I ran XQueryTree on all my windows and I got them in z-order from topmost at top of the array to bottom-most at bottom of array.
I then filtered out only what is visible by doing XGetWindowAttributes on each and removing it if it is not map_state of IsVisible
For each visible window, I check and get the _NET_WM_PID, _NET_WM_NAME, x, y, height (as height + border_width), and width (as width + border_width).
My data is at this gist and also at bottom: https://gist.github.com/Noitidart/94562d08f243cd7ca7ec
My setup is of two monitors. And this is a fullscreenshot of them both:
There is one transparent window over each monitor, that is the height and width of the monitor, their titles are "nativeshot_canvas".
So looking through the data I see that windows are broken up into multiple entries by XQueryTree. My manual analysis tells me this:
"nativeshot_canvas" on left monitor
"nativeshot_canvas" on right monitor
UNKNOWN WINDOW 1
UNKNOWN WINDOW 2
horizontal menu bar on right monitor
horizontal menu bar on left monitor
vertical dock on right monitor
vertical dock on left monitor
UNKNOWN WINDOW 3
"Javascript Application" window
"Browser Console" window
"Mozilla Firefox" window with two tabs
"Desktop"
A graphic of the data and my manual analysis is below.
THE QUESTION
Is there a way to programmatically identify which entries correlate to a single window? In my manual analysis I used some patterns I came up with in that each window group starts with either a _NET_WM_PID (pid key in data below) or a _NET_WM_NAME (title key in data below). I don't think this is a good pattern because we see at top things have a PID but their width and height are 1.
edit: still stuck on how finding a gurantteed way to correlate these divisions into groups of windows. i basically need to get all x, y, width, and height of all the windows out there, if anyone has any input i would be very greatful
My code to list out the XQueryTree data:
var xqRoot = ostypes.TYPE.Window();
var xqParent = ostypes.TYPE.Window();
var xqChildArr = ostypes.TYPE.Window.ptr();
var nChilds = ostypes.TYPE.unsigned_int();
var gpTypeReturned = ostypes.TYPE.Atom();
var gpFormatReturned = ostypes.TYPE.int();
var gpNItemsReturned = ostypes.TYPE.unsigned_long();
var gpBytesAfterReturn = ostypes.TYPE.unsigned_long();
var gpItemsArr = ostypes.TYPE.unsigned_char.ptr();
var geoRoot = ostypes.TYPE.Window();
var geoX = ostypes.TYPE.int();
var geoY = ostypes.TYPE.int();
var geoW = ostypes.TYPE.unsigned_int();
var geoH = ostypes.TYPE.unsigned_int();
var geoBorderWidth = ostypes.TYPE.unsigned_int();
var geoDepth = ostypes.TYPE.unsigned_int();
var wAttr = ostypes.TYPE.XWindowAttributes();
var processWin = function(w) {
if (aOptions.filterVisible) {
var rez_WA = ostypes.API('XGetWindowAttributes')(ostypes.HELPER.cachedXOpenDisplay(), w, wAttr.address());
console.info('wAttr.map_state:', wAttr.map_state.toString());
if (!cutils.jscEqual(wAttr.map_state, ostypes.CONST.IsViewable)) {
return; // continue as this is a hidden window, do not list features, do not dig this window
}
}
var thisWin = {};
// fetch props on thisWin
thisWin.hwndXid = parseInt(cutils.jscGetDeepest(w));
if (aOptions.getPid) {
var rez_pid = ostypes.API('XGetWindowProperty')(ostypes.HELPER.cachedXOpenDisplay(), w, ostypes.HELPER.cachedAtom('_NET_WM_PID'), 0, 1, ostypes.CONST.False, ostypes.CONST.XA_CARDINAL, gpTypeReturned.address(), gpFormatReturned.address(), gpNItemsReturned.address(), gpBytesAfterReturn.address(), gpItemsArr.address());
if (ostypes.HELPER.getWinProp_ReturnStatus(ostypes.CONST.XA_CARDINAL, gpTypeReturned, gpFormatReturned, gpBytesAfterReturn) == 1) {
var jsN = parseInt(cutils.jscGetDeepest(gpNItemsReturned));
if (jsN == 0) {
thisWin.pid = null; // set to null as this window did not have a pid, but i add the key indicating i tested for it and the window had the proerty
} else {
//console.info('gpItemsArr:', gpItemsArr.toString(), 'casted:', ctypes.cast(gpItemsArr, ostypes.TYPE.CARD32).toString(), 'casted to single el:', ctypes.cast(gpItemsArr, ostypes.TYPE.CARD32.array(1).ptr).contents.toString()); // "gpItemsArr:" "ctypes.unsigned_char.ptr(ctypes.UInt64("0x7f229409d710"))" "casted:" "ctypes.unsigned_int(2483672848)" "casted to single el:" "ctypes.unsigned_int.array(1)([2212])" // showing that it must be cast and not just to type cuz its single element, but to array of 1 element
thisWin.pid = parseInt(cutils.jscGetDeepest(ctypes.cast(gpItemsArr, ostypes.TYPE.CARD32.array(1).ptr).contents[0]));
}
ostypes.API('XFree')(gpItemsArr);
} else {
thisWin.pid = undefined; // window didnt even have property
}
}
if (aOptions.getTitle) {
var rez_title = ostypes.API('XGetWindowProperty')(ostypes.HELPER.cachedXOpenDisplay(), w, ostypes.HELPER.cachedAtom('_NET_WM_NAME'), 0, 256 /* this number times 4 is maximum ctypes.char that can be returned*/, ostypes.CONST.False, ostypes.HELPER.cachedAtom('UTF8_STRING'), gpTypeReturned.address(), gpFormatReturned.address(), gpNItemsReturned.address(), gpBytesAfterReturn.address(), gpItemsArr.address());
if (ostypes.HELPER.getWinProp_ReturnStatus(ostypes.HELPER.cachedAtom('UTF8_STRING'), gpTypeReturned, gpFormatReturned, gpBytesAfterReturn) == 1) {
var jsN = parseInt(cutils.jscGetDeepest(gpNItemsReturned));
if (jsN == 0) {
thisWin.title = ''; // window had property but not title
} else {
thisWin.title = ctypes.cast(gpItemsArr, ostypes.TYPE.char.array(jsN).ptr).contents.readString();
}
ostypes.API('XFree')(gpItemsArr);
} else {
thisWin.title = undefined; // window didnt even have property
}
}
if (aOptions.getBounds) {
if (aOptions.filterVisible) {
// then get the info from wAttr as its already available
thisWin.left = parseInt(cutils.jscGetDeepest(wAttr.x));
thisWin.top = parseInt(cutils.jscGetDeepest(wAttr.y));
var borderWidth = parseInt(cutils.jscGetDeepest(wAttr.border_width));
thisWin.borderWidth = borderWidth;
thisWin.width = parseInt(cutils.jscGetDeepest(wAttr.width))/* + borderWidth*/;
thisWin.height = parseInt(cutils.jscGetDeepest(wAttr.height))/* + borderWidth*/;
thisWin.right = thisWin.left + thisWin.width;
thisWin.bottom = thisWin.top + thisWin.height;
} else {
var rez_bounds = ostypes.API('XGetGeometry')(ostypes.HELPER.cachedXOpenDisplay(), w, geoRoot.address(), geoX.address(), geoY.address(), geoW.address(), geoH.address(), geoBorderWidth.address(), geoDepth.address());
thisWin.left = parseInt(cutils.jscGetDeepest(geoX));
thisWin.top = parseInt(cutils.jscGetDeepest(geoY));
var borderWidth = parseInt(cutils.jscGetDeepest(wAttr.border_width));
thisWin.borderWidth = borderWidth;
thisWin.width = parseInt(cutils.jscGetDeepest(wAttr.width))/* + borderWidth*/;
thisWin.height = parseInt(cutils.jscGetDeepest(wAttr.height))/* + borderWidth*/;
thisWin.right = thisWin.left + thisWin.width;
thisWin.bottom = thisWin.top + thisWin.height;
}
}
rezWinArr.splice(0, 0, thisWin);
// dig the win even if it doesnt qualify
var rez_XQ = ostypes.API('XQueryTree')(ostypes.HELPER.cachedXOpenDisplay(), w, xqRoot.address(), xqParent.address(), xqChildArr.address(), nChilds.address()); // interesting note about XQueryTree and workspaces: "The problem with this approach is that it will only return windows on the same virtual desktop. In the case of multiple virtual desktops, windows on other virtual desktops will be ignored." source: http://www.experts-exchange.com/Programming/System/Q_21443252.html
var jsNC = parseInt(cutils.jscGetDeepest(nChilds));
if (jsNC > 0) {
var jsChildArr = ctypes.cast(xqChildArr, ostypes.TYPE.Window.array(jsNC).ptr).contents;
// for (var i=jsNC-1; i>-1; i--) {
for (var i=0; i<jsNC; i++) {
var wChild = jsChildArr[i];
processWin(wChild);
}
ostypes.API('XFree')(xqChildArr);
}
}
processWin(ostypes.HELPER.cachedDefaultRootWindow());
Related
I was trying to maintain the object size while zooming, i tried to get inspired by this answer in which the guy who wrote it didn't solve the controls issue in such as case, as a consequence you can see them not sticking to the object while zooming as in this screenshot.
But i came with this solution to maintain the object position and controls by updating its left and top after calculating them based on the inverted viewportTransform by calculating a new fabric.Point using the fabric.util.transformPoint function
fabric.Object.prototype.transform = function(ctx) {
const obj = this;
const {
ignoreZoom,
group,
canvas,
left,
top
} = obj;
const {
contextTop,
viewportTransform,
getZoom,
requestRenderAll,
} = canvas;
var needFullTransform = (group && !group._transformDone) || (group && canvas && ctx === contextTop);
if (ignoreZoom) {
const oldP = new fabric.Point(left, top);
const newP = fabric.util.transformPoint(oldP, fabric.util.invertTransform(viewportTransform));
var zoom = 1 / getZoom();
/* // here i tried to refresh the whole canvas with requestRenderAll()
this.set({
left: newP.x,
top: newP.y,
scaleX: zoom,
scaleY: zoom,
});
this.setCoords();
requestRenderAll();
*/
// but here i try refresh the object only which is better i think
this.left = newP.x;
this.top = newP.y;
this.scaleX = zoom;
this.scaleY = zoom;
this.drawObject(ctx);
}
var m = this.calcTransformMatrix(!needFullTransform);
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}
I have made this codesandbox as a demo for my code. As you can see in this screenshot, controls stick around the object but the whole of them doesn't maintain their position relatively to the background and sometimes they disappear completely.
I need the object to keep its position relatively to the background.
How to make it better ?
// EDIT
I tried to understand better what happens while zooming, i found the fabric.Canvas.zoomToPoint() which is used for zooming (as in their tutorial)
zoomToPoint: function (point, value) {
// TODO: just change the scale, preserve other transformations
var before = point, vpt = this.viewportTransform.slice(0);
point = transformPoint(point, invertTransform(this.viewportTransform));
vpt[0] = value;
vpt[3] = value;
var after = transformPoint(point, vpt);
vpt[4] += before.x - after.x;
vpt[5] += before.y - after.y;
return this.setViewportTransform(vpt);
},
i guess the best way to fix the object position relatively to the background will be to apply the inverse transformation of the one applied to the canvas for the zoom to the object.
So i wrote this function
function getNewVpt(point, value) {
var before = point,
vpt = canvas.viewportTransform.slice(0);
point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));
vpt[0] = value;
vpt[3] = value;
var after = fabric.util.transformPoint(point, vpt);
vpt[4] += before.x - after.x;
vpt[5] += before.y - after.y;
return vpt;
}
and i used it to rewrite the fabric.Object.prototype.transform
fabric.Object.prototype.transform = function (ctx) {
const obj = this;
const { ignoreZoom, group, canvas: objCanvas, left, top } = obj;
const {
contextTop,
viewportTransform,
} = objCanvas;
var needFullTransform =
(group && !group._transformDone) ||
(group && objCanvas && ctx === contextTop);
if (ignoreZoom && zoomingIsOn) {
zoomingIsOn = false;
var zoom = 1 / objCanvas.getZoom();
const oldP = new fabric.Point(left, top);
console.log('transform : oldP : ', oldP);
const newVpt = getNewVpt(oldP, zoom)
const newP = fabric.util.transformPoint(oldP, newVpt);
console.log('transform : newP : ', newP);
// here i tried to refresh the whole canvas with requestRenderAll()
this.set({
left: newP.x,
top: newP.y,
scaleX: zoom,
scaleY: zoom
});
this.setCoords();
console.log('transform : CALLING objCanvas.requestRenderAll() ');
objCanvas.requestRenderAll();
// but here i try refresh the object only which is better i think
// this.left = newP.x;
// this.top = newP.y;
// this.scaleX = zoom;
// this.scaleY = zoom;
// this.drawObject(ctx);
}
var m = this.calcTransformMatrix(!needFullTransform);
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
};
And here i forked this new codesandbox for this second solution , the result seems to be better than the former solution but it still not perfect. What i may still be doing wrong ?!
// EDIT 2
I tried to pass objCanvas.getZoom() instead of zoom as second parameter to the getNewVpt() function. It seems there is some more improovement but still not perfect again
// Edit 3
In This codesandbox probably i got the best result i could get using another function which returns directly the new point:
function getNewPt(point, value) {
// TODO: just change the scale, preserve other transformations
var vpt = canvas.viewportTransform.slice(0);
point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));
vpt[0] = value;
vpt[3] = value;
return fabric.util.transformPoint(point, vpt);;
}
I still wish anybody who can tell me if there is a way to improove it more. As you can see the triangle returns back to its initial position after zooming/ dezooming and getting back to the same initial zoom value which is good but between those initial and final states , it still seems not to be in the right spot..
You just have to call zoomToPoint where it zooms and the objects will keep their position and scale relative to the background.
Try the following
canvas.on('mouse:wheel', function(opt) {
// console.log(opt.e.deltaY)
let zoomLevel = canvas.getZoom();
// console.log('zoom Level: ', (zoomLevel * 100).toFixed(0), '%');
zoomLevel += opt.e.deltaY * -0.01;
// Restrict scale
zoomLevel = Math.min(Math.max(.125, zoomLevel), 20);
canvas.zoomToPoint(
new fabric.Point(opt.e.offsetX, opt.e.offsetY),
zoomLevel,
);
canvas.renderAll();
})
I want to drag and resize a rectangle in paperjs, I also want to rotate the rectangle and resize it while maintaining its relative dimensions.
Ideally I'd like to do so with my mouse by dragging one of its corners (anchors). What mathematics or feature is helpful in doing this in paperjs?
I have tried this by using scaling and modifying the corners but it doesn't work as I want it to. Could someone point me to a solution?
Thanks in advance.
Here's a simple solution that should get you started. It doesn't handle rotation because I'm not sure how you envision the UI working, but by modifying the bounding box to resize the rectangle you should be able to rotate it without problems.
paperjs sketch
I decided to make up my own UI and go ahead and make the example more complicated to address as much of you question as I can without more information. Here's the new sketch:
new sketch
The UI is
click in rectangle to move it by dragging
click on a corner and drag to resize it
control-click on a corner to rotate it
It's a bit tricky to click the corners, but that's an exercise left to the reader. They are colored circles just to emphasize where each segment point of the Path is located.
Key points of the code:
Use the rectangle's bounds to scale. Path.Rectangle is not a rectangle as far as paper is concerned. It is four curves (which happen to be straight) connecting four segment points. When you need to work with a rectangle to get its center, top left, etc., you need a Rectangle. Scale the visible rectangle by using the rectangle's bounds (Path.Rectangle.bounds). The code illustrates the bounds with an additional aqua rectangle so it's visible (it's easiest to see when rotating).
onMouseDown() sets the state for onMouseDrag() and sets up data needed for each state, e.g., saving the scale base for resizing.
onMouseDrag() implements moving, resizing, and rotating.
tool.onMouseDrag = function(e) {
if (rect.data.state === 'moving') {
rect.position = rect.position + e.point - e.lastPoint;
adjustRect(rect);
} else if (rect.data.state === 'resizing') {
// scale by distance from down point
var bounds = rect.data.bounds;
var scale = e.point.subtract(bounds.center).length /
rect.data.scaleBase.length;
var tlVec = bounds.topLeft.subtract(bounds.center).multiply(scale);
var brVec = bounds.bottomRight.subtract(bounds.center).multiply(scale);
var newBounds = new Rectangle(tlVec + bounds.center, brVec + bounds.center);
rect.bounds = newBounds;
adjustRect(rect);
} else if (rect.data.state === 'rotating') {
// rotate by difference of angles, relative to center, of
// the last two points.
var center = rect.bounds.center;
var baseVec = center - e.lastPoint;
var nowVec = center - e.point;
var angle = nowVec.angle - baseVec.angle;
rect.rotate(angle);
adjustRect(rect);
}
}
Moving is pretty easy - just calculate the difference between the current and last points from the event and change the position of the rectangle by that much.
Resizing is not as obvious. The strategy is to adjust the x and y bounds based on the original distance (scaleBase.length) between the mousedown point and the center of the rectangle. Note that while paper-full.js allows using operators ("+", "-", "*", "/") with points, I used the raw subtract() and multiply() methods a few times - I find it natural to chain the calculations that way.
Rotating uses the very nice paper concept that a point also defines a vector and a vector has an angle. It just notes the difference in the angles between the event lastPoint and point relative to the rectangle's center and rotates the rectangle by that difference.
moveCircles() and adjustRect() are just bookkeeping functions to update the corner circles and aqua rectangle.
Consider the following. I just went through the process of figuring this out, based on lots of examples.
My Goals:
use my own bounding box when selecting an item
Move, Resize, and Rotate (with snap to rotation [45 degrees]) the selected item
Show a title / name of the item
Example Sketch
Paper.js Code
var hitOptions = {
segments: true,
stroke: true,
fill: true,
tolerance: 5
};
function drawHex(w, c, n){
var h = new Path.RegularPolygon(new Point(100, 100), 6, w / 2);
h.selectedColor = 'transparent';
c = c != undefined ? c : "#e9e9ff";
n = n != undefined ? n : "Hexayurt";
h.name = n;
h.fillColor = c;
h.data.highlight = new Group({
children: [makeBounds(h), makeCorners(h), makeTitle(h)],
strokeColor: '#a2a2ff',
visible: false
});
return h;
}
function makeCorners(o, s){
s = s != undefined ? s : 5;
var g = new Group();
var corners = [
o.bounds.topLeft,
o.bounds.topRight,
o.bounds.bottomLeft,
o.bounds.bottomRight
];
corners.forEach(function(corner, i) {
var h = new Path.Rectangle({
center: corner,
size: s
});
g.addChild(h);
});
return g;
}
function makeBounds(o){
return new Path.Rectangle({
rectangle: o.bounds
});
}
function makeTitle(o, n, c){
c = c != undefined ? c : 'black';
var t = new PointText({
fillColor: c,
content: n != undefined ? n : o.name,
strokeWidth: 0
});
t.bounds.center = o.bounds.center;
return t;
}
function selectItem(o){
console.log("Select Item", o.name);
o.selected = true;
o.data.highlight.visible = true;
o.data.highlight.bringToFront();
}
function clearSelected(){
project.selectedItems.forEach(function(o, i){
console.log("Unselect Item", o.name);
o.data.highlight.visible = false;
});
project.activeLayer.selected = false;
}
function moveBoxes(o){
var boxes = o.data.highlight.children[1].children;
boxes[0].position = o.bounds.topLeft;
boxes[1].position = o.bounds.topRight;
boxes[2].position = o.bounds.bottomLeft;
boxes[3].position = o.bounds.bottomRight;
}
function moveTitle(o){
var t = o.data.highlight.children[2];
t.bounds.center = o.bounds.center;
}
function adjustBounds(o){
if(o.data.state == "moving"){
o.data.highlight.position = o.position;
} else {
o.data.highlight.children[0].bounds = o.bounds;
moveBoxes(o);
}
}
var hex1 = drawHex(200);
console.log(hex1.data, hex1.data.highlight);
var segment, path;
var movePath = false;
var tool = new Tool();
tool.minDistance = 10;
tool.onMouseDown = function(event) {
segment = path = null;
var hitResult = project.hitTest(event.point, hitOptions);
if (!hitResult){
clearSelected();
return;
}
if(hitResult && hitResult.type == "fill"){
path = hitResult.item;
}
if (hitResult && hitResult.type == "segment") {
path = project.selectedItems[0];
segment = hitResult.segment;
if(event.modifiers.control){
path.data.state = "rotating";
} else {
path.data.state = "resizing";
path.data.bounds = path.bounds.clone();
path.data.scaleBase = event.point - path.bounds.center;
}
console.log(path.data);
}
movePath = hitResult.type == 'fill';
if (movePath){
project.activeLayer.addChild(hitResult.item);
path.data.state = "moving";
selectItem(path);
console.log("Init Event", path.data.state);
}
};
tool.onMouseDrag = function(event) {
console.log(path, segment, path.data.state);
if (segment && path.data.state == "resizing") {
var bounds = path.data.bounds;
var scale = event.point.subtract(bounds.center).length / path.data.scaleBase.length;
var tlVec = bounds.topLeft.subtract(bounds.center).multiply(scale);
var brVec = bounds.bottomRight.subtract(bounds.center).multiply(scale);
var newBounds = new Rectangle(tlVec + bounds.center, brVec + bounds.center);
path.bounds = newBounds;
adjustBounds(path);
} else if(segment && path.data.state == "rotating") {
var center = path.bounds.center;
var baseVec = center - event.lastPoint;
var nowVec = center - event.point;
var angle = nowVec.angle - baseVec.angle;
if(angle < 0){
path.rotate(-45);
} else {
path.rotate(45);
}
adjustBounds(path);
} else if (path && path.data.state == "moving") {
path.position += event.delta;
adjustBounds(path);
}
};
This makes use of .data to store references of the bounding box, handles, and title as a Group. This way, they are always there, they can just visible true or false. This makes it easy to show and hide them as needed.
drawHex( width , color, name )
Width - Required, number of pixels wide
Color - Optional, string that defines the Fill Color. Default: #e9e9ff
Name - Optional, string to be used as the Name and Title. Default: "Hexayurt"
Interactions
click - Select item (show bounding box & Handles)
click + drag - Move item
click + drag handle - Resize item
Ctrl + click + drag handle - Rotate item
This is my first pass at it and I may cleanup a lot of the code. For example, I could bind events to the handles specifically instead of looking at more global events.
I'm developing an taxi caller app. And I used Bing map
This is my flow:
Get my position
Get 3 near taxis
When I tap 1 in 3 taxis, all in formation of taxis will sent to a new
Variable to used with another function.
This is my code
And how to send a obj from Foreach to taxiIcon_Tap?
Thanks and best regards!
//------ BEGIN get near Driver ------//
private async void GetNearDriver()
{
var uid = userData.content.uid;
var lat = pickupLat;
var lng = pickupLng;
var clvl = taxiType;
var input = string.Format("{{\"uid\":\"{0}\",\"lat\":{1},\"lng\":{2},\"cLvl\":\"{3}\"}}", uid, lat.ToString().Replace(',', '.'), lng.ToString().Replace(',', '.'), clvl);
var output = await GetJsonFromPOSTMethod.GetJsonString(ConstantVariable.tNetRiderGetNerDriverAddress, input);
var nearDriver = JsonConvert.DeserializeObject<RiderGetNearDriver>(output);
if (nearDriver.content.listDriverDTO.Count > 0)
{
foreach (var taxi in nearDriver.content.listDriverDTO)
{
ShowNearDrivers(taxi.lat, taxi.lng, taxi.cName);
}
}
}
//------ END get near Driver ------//
//------ BEGIN show and Design UI 3 taxi near current position ------//
private void ShowNearDrivers(double lat, double lng, string tName)
{
GeoCoordinate TaxiCoordinate = new GeoCoordinate(lat, lng);
//Create taxi icon on map
Image taxiIcon = new Image();
taxiIcon.Source = new BitmapImage(new Uri("/Images/Taxis/img_CarIcon.png", UriKind.Relative));
//Add a tapped event
taxiIcon.Tap += taxiIcon_Tap;
//Create Taxi Name
TextBlock taxiName = new TextBlock();
taxiName.HorizontalAlignment = HorizontalAlignment.Center;
taxiName.Text = tName;
taxiName.FontSize = 12;
taxiName.Foreground = new SolidColorBrush(Color.FromArgb(255, (byte)46, (byte)159, (byte)255)); //RBG color for #2e9fff
//Create Stack Panel to group icon, taxi name, ...
Rectangle taxiNameBackground = new Rectangle();
taxiNameBackground.Height = 18;
taxiNameBackground.Width = taxiName.ToString().Length + 20;
taxiNameBackground.RadiusX = 9;
taxiNameBackground.RadiusY = 7;
//taxiNameBackground.Stroke = new SolidColorBrush(Color.FromArgb(255, (byte)171, (byte)171, (byte)171)); //RBG color for #ababab
taxiNameBackground.Fill = new SolidColorBrush(Color.FromArgb(255, (byte)213, (byte)235, (byte)255)); //RBG color for #d5ebff
Grid taxiNameGrid = new Grid();
taxiNameGrid.Margin = new Thickness(0, 4, 0, 4); //Margin Top and Bottom 4px
taxiNameGrid.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
taxiNameGrid.VerticalAlignment = System.Windows.VerticalAlignment.Center;
taxiNameGrid.Children.Add(taxiNameBackground);
taxiNameGrid.Children.Add(taxiName);
StackPanel taxiStackPanel = new StackPanel();
//taxiStackPanel.Margin = new Thickness(5, 0, 5, 0);
taxiStackPanel.Children.Add(taxiIcon);
taxiStackPanel.Children.Add(taxiNameGrid);
// Create a MapOverlay to contain the circle.
MapOverlay myTaxiOvelay = new MapOverlay();
//myTaxiOvelay.Content = myCircle;
myTaxiOvelay.Content = taxiStackPanel;
myTaxiOvelay.PositionOrigin = new Point(0.5, 0.5);
myTaxiOvelay.GeoCoordinate = TaxiCoordinate;
//Add to Map's Layer
riderMapLayer = new MapLayer();
riderMapLayer.Add(myTaxiOvelay);
map_RiderMap.Layers.Add(riderMapLayer);
}
//Tapped event
private void taxiIcon_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
//Hide Step 01
this.grv_Step01.Visibility = Visibility.Collapsed;
//Show Step 02
this.grv_Step02.Visibility = Visibility.Visible;
this.grv_Picker.Visibility = Visibility.Collapsed;
//Step 2 info
LoadStep2Info();
}
//------ END show and Design UI 3 taxi near current position ------//
You can use the Tag property to pass such miscellaneous objects around when using events which don't expose the ability to add an additional payload.
My understanding is that in the taxiIcon_Tap event you want to be able to access your own object that is related to whatever was tapped.
To do this set you object to the Tag property of the item being tapped.
i.e. If you want to pass the coordinates do:
taxiIcon.Tag = TaxiCoordinate;
(You could pass anything.)
Then, in the tapped event handler you can get at this object by casting from the sender to get the Tag and then casting that back to your type.
var coords = ((FrameworkElement)sender).Tag as GeoCoordinate;
I am developing an Bootstrapper application. When we move to the installation location selection wizard, we can have a browse option to change the location of our setup installation.
When we clock that browse option, i need to show only the drives( 'C', 'D' and 'F') available in a system. When we select the drive, it will not expand. i need that drive alone (Ex: C:) in the installation location text in the installation wizard.
Can anyone please guide me that how to achieve my requirement?
My code:
private void btn_Browse_Click(object sender, EventArgs e)
{
txt_InstallLocation.Focus();
FBD_Source.RootFolder = Environment.SpecialFolder.Desktop;
if (FBD_Source.ShowDialog() == DialogResult.OK)
{
txt_InstallLocation.TextBox.Text = FBD_Source.SelectedPath;
BA.Model.Bootstrapper.Engine.StringVariables["APPDIR"] = FBD_Source.SelectedPath + "\\";
}
}
I need to modify the below line of code.
FBD_Source.RootFolder = Environment.SpecialFolder.Desktop;
Can anyone please assist me to proceed further or direct me in right path?
Your can find the available drives like this.
var drives = System.Environment.GetLogicalDrives();
foreach (string d in drives)
Console.WriteLine(d);
Don't use the FolderBrowserDialog.
Create a form with a dynamically created radiobutton/list and make the user select one of those options
Something like this
var drives = System.Environment.GetLogicalDrives();
Form selectionForm = new Form() { MaximizeBox = false, FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog, StartPosition = FormStartPosition.CenterScreen };
ListBox lb = new ListBox() { Dock = DockStyle.Fill };
foreach (var item in drives)
lb.Items.Add(item);
selectionForm.Controls.Add(lb);
Button btnOk = new Button() { Dock = DockStyle.Left, Width = selectionForm.Width / 2 };
btnOk.Text = "OK";
Button btnCancel = new Button() { Dock = DockStyle.Right, Width = selectionForm.Width / 2 };
btnCancel.Text = "Cancel";
Panel bottomPanel = new Panel() { Dock = DockStyle.Bottom, Height = 50 };
bottomPanel.Controls.Add(btnOk);
bottomPanel.Controls.Add(btnCancel);
selectionForm.Controls.Add(bottomPanel);
selectionForm.ShowDialog();
MessageBox.Show(lb.SelectedItem.ToString());
I know that I can easily allow a user to select multiple Features/Geometries in OpenLayers but I then want enable the user to easily drag/move all of the selected features at the same time.
With the ModifyFeature control it only moves one feature at a time ... is there a way to easily extend this control (or whatever works) to move all of the selected features on that layer?
Okay, skip the ModifyFeature control and just hook into the SelectFeature control to keep track of the selected features and then use the DragControl to manipulate the selected points at the same time.
Example of the control instantiation:
var drag = new OpenLayers.Control.DragFeature(vectors, {
onStart: startDrag,
onDrag: doDrag,
onComplete: endDrag
});
var select = new OpenLayers.Control.SelectFeature(vectors, {
box: true,
multiple: true,
onSelect: addSelected,
onUnselect: clearSelected
});
Example of the event handling functions:
/* Keep track of the selected features */
function addSelected(feature) {
selectedFeatures.push(feature);
}
/* Clear the list of selected features */
function clearSelected(feature) {
selectedFeatures = [];
}
/* Feature starting to move */
function startDrag(feature, pixel) {
lastPixel = pixel;
}
/* Feature moving */
function doDrag(feature, pixel) {
for (f in selectedFeatures) {
if (feature != selectedFeatures[f]) {
var res = map.getResolution();
selectedFeatures[f].geometry.move(res * (pixel.x - lastPixel.x), res * (lastPixel.y - pixel.y));
vectors.drawFeature(selectedFeatures[f]);
}
}
lastPixel = pixel;
}
/* Featrue stopped moving */
function endDrag(feature, pixel) {
for (f in selectedFeatures) {
f.state = OpenLayers.State.UPDATE;
}
}
Hmm...
I tried the code above, and couldn't make it work. Two issues:
1) To move each feature, you need to use the original position of that feature, and add the "drag vector" from whatever feature the DragControl is moving around by itself (i.e. the feature-parameter to doDrag).
2) Since DragFeatures own code sets lastPixel=pixel before calling onDrag, the line calling move() will move the feature to (0,0).
My code looks something like this:
var lastPixels;
function startDrag(feature, pixel) {
// save hash with selected features start position
lastPixels = [];
for( var f=0; f<wfs.selectedFeatures.length; f++){
lastPixels.push({ fid: layer.selectedFeatures[f].fid,
lastPixel: map.getPixelFromLonLat( layer.selectedFeatures[f].geometry.getBounds().getCenterLonLat() )
});
}
}
function doDrag(feature, pixel) {
/* because DragFeatures own handler overwrites dragSelected.lastPixel with pixel before this is called, calculate drag vector from movement of "feature" */
var g = 0;
while( lastPixels[g].fid != feature.fid ){ g++; }
var lastPixel = lastPixels[g].lastPixel;
var currentCenter = map.getPixelFromLonLat( feature.geometry.getBounds().getCenterLonLat() );
var dragVector = { dx: currentCenter.x - lastPixel.x, dy: lastPixel.y - currentCenter.y };
for( var f=0; f<layer.selectedFeatures.length; f++){
if (feature != layer.selectedFeatures[f]) {
// get lastpixel of this feature
lastPixel = null;
var h = 0;
while( lastPixels[h].fid != layer.selectedFeatures[f].fid ){ h++; }
lastPixel = lastPixels[h].lastPixel;
var newPixel = new OpenLayers.Pixel( lastPixel.x + dragVector.dx, lastPixel.y - dragVector.dy );
// move() moves polygon feature so that centre is at location given as parameter
layer.selectedFeatures[f].move(newPixel);
}
}
}
I had a similar problem and solved it by overriding DragFeature's moveFeature function and putting this.lastPixel = pixel inside the for loop that applies the move to all features within my layer vector. Until I moved this.lastPixel = pixel inside the loop, all features except the one being dragged got crazily distorted.
`OpenLayers.Control.DragFeature.prototype.moveFeature = function (pixel) {
var res = this.map.getResolution();
for (var i = 0; i < vector.features.length; i++) {
var feature = vector.features[i];
feature .geometry.move(res * (pixel.x - this.lastPixel.x),
res * (this.lastPixel.y - pixel.y));
this.layer.drawFeature(feature );
this.lastPixel = pixel;
}
this.onDrag(this.feature, pixel);
};
`