How in OpenEdge ABL / Progress 4GL do I get the RIGHT-MOUSE-CLICK trigger to perform the default left click to reposition the focus - right-click

I'm using OpenEdge ABL / Progress 4GL. I have a browser widget populated with rows. When I left click a row the row is highlighted and that row is now in focus. I want when I right click on a different row for progress to perform a "left click" (to move the focus to the row that was right clicked on) then do the right click.

Check the ABL Reference for mouse events (page 1834 of the 10.2B ABL Reference Guide).
The usual method is to capture the event in question with an "ON event-name OF widget-name" then apply a different event to the widget (APPLY "mouse-select-click" TO b-name) then tell the AVM to ignore the original event with "RETURN NO-APPLY."
It would look something like this:
ON MOUSE-MENU-CLICK OF b-name
DO:
APPLY "mouse-select-click" TO SELF.
RETURN NO-APPLY.
END.
Caveat: I'm not sure what event a right-click triggers, so you'll need to adapt this code to suit.

I already answered this question here : How in OpenEdge ABL / Progress 4GL do I find the row id of a row that is right clicked in a browser.
I'm not sure what the policy is with this duplicate question, but I'm repeating my answer here, I hope it's OK.
I had a similar situation; I wanted to respond to the mouse's Right-click in a browse. Right-clicking does not select the row you're clicking on, so I had to programmatically figure out which row it was. The coding below determines which row you clicked on and selects it. I am afraid it really is this complicated.
This goes in the MOUSE-MENU-DOWN event of the browse:
DEFINE VARIABLE iRowHeight AS INTEGER NO-UNDO.
DEFINE VARIABLE iLastY AS INTEGER NO-UNDO.
DEFINE VARIABLE iRow AS INTEGER NO-UNDO.
DEFINE VARIABLE hCell AS HANDLE NO-UNDO.
DEFINE VARIABLE iTopRowY AS INTEGER NO-UNDO.
/* See if there are ANY rows in view... */
IF SELF:NUM-ITERATIONS = 0 THEN
DO:
/* No rows, the user clicked on an empty browse widget */
RETURN NO-APPLY.
END.
/* We don't know which row was clicked on, we have to calculate it from the mouse coordinates and the row heights. No really. */
SELF:SELECT-ROW(1). /* Select the first row so we can get the first cell. */
hCell = SELF:FIRST-COLUMN. /* Get the first cell so we can get the Y coord of the first row, and the height of cells. */
iTopRowY = hCell:Y - 1. /* The Y coord of the top of the top row relative to the browse widget. Had to subtract 1 pixel to get it accurate. */
iRowHeight = hCell:HEIGHT-PIXELS. /* SELF:ROW-HEIGHT-PIXELS is not the same as hCell:HEIGHT-PIXELS for some reason */
iLastY = LAST-EVENT:Y. /* The Y position of the mouse event (relative to the browse widget) */
/* calculate which row was clicked. Truncate so that it doesn't round clicks past the middle of the row up to the next row. */
iRow = 1 + TRUNCATE((iLastY - iTopRowY) / iRowHeight, 0).
IF iRow > 0 AND iRow <= SELF:NUM-ITERATIONS THEN
DO:
/* The user clicked on a populated row */
Your coding here, for example:
SELF:SELECT-ROW(iRow).
END.
ELSE DO:
/* The click was on an empty row. */
SELF:DESELECT-ROWS().
RETURN NO-APPLY.
END.
I hope this helps.

Basically, you would have to define a trigger like this:
ON RIGHT-MOUSE-CLICK OF myBrowseRow DO:
APPLY "ENTRY" TO myBrowse IN FRAME myFrame.
/* Code to focus a particular row in the browse. */
APPLY "ENTRY" TO SELF IN BROWSE myBrowse.
END.
The problem might be that you'll have to add that trigger to every row in the browse, because it's AFAIK impossible to figure out which row has been right-clicked if you set the trigger just for the browse itself...

To expand on the main answer, here are some additional notes and sample code.
1. You need to be aware of the height of the headers and title.
2. You could dynamically attach a menu if you had standard browse functions.
3. Multi-select browsers act slightly differently.
ON 'right-mouse-down':U ANYWHERE DO:
RUN set_focus (SELF).
IF SELF:TYPE = 'BROWSE' THEN DO:
RETURN NO-APPLY.
END.
ELSE DO:
APPLY 'menu-drop' TO SELF.
END.
END.
PROCEDURE set_focus.
DEF INPUT PARAM i_object AS HANDLE NO-UNDO.
DEF VAR l_was_row_one_selected AS LOG NO-UNDO.
DEF VAR l_header_y AS DEC NO-UNDO.
DEF VAR w_browse_title_bar_height AS DEC NO-UNDO INITIAL 19. /* determine this for your UI */
DEF VAR o_labels AS CHAR NO-UNDO.
DEF VAR o_procedures AS CHAR NO-UNDO.
DEF VAR h_menu AS HANDLE NO-UNDO.
DEF VAR h_menu_item AS HANDLE NO-UNDO.
DEF VAR l_count AS INT NO-UNDO.
/* given an object ... */
IF i_object:TYPE = 'browse' THEN DO:
IF i_object:NUM-SELECTED-ROWS = 0
THEN ASSIGN l_was_row_one_selected = FALSE.
ELSE ASSIGN l_was_row_one_selected = i_object:IS-ROW-SELECTED(1) NO-ERROR.
i_object:SELECT-ROW(1) NO-ERROR.
IF ERROR-STATUS:ERROR THEN RETURN.
l_header_y = MAX(1,i_object:FIRST-COLUMN:Y). /* in case there are no column headers */
IF i_object:TITLE <> ? THEN l_header_y = l_header_y - w_browse_title_bar_height.
IF l_was_row_one_selected = FALSE THEN i_object:DESELECT-SELECTED-ROW(1) NO-ERROR.
/* this section selects the correct row, based on where it was clicked, minus the height of the headers divided by row height */
i_object:SELECT-ROW(
INT(
1 +
TRUNC(
(LAST-EVENT:Y - l_header_y) / i_object:FIRST-COLUMN:HEIGHT-PIXELS
,0)
)
)
NO-ERROR.
APPLY 'ENTRY':u TO i_object. /* to get focus properly */
APPLY 'VALUE-CHANGED':u TO i_object.
/* use some rule to find associated dynamic menu items, e.g. maintenance options, finding related data*/
RUN find_menu_stuff (i_object:NAME, OUTPUT o_labels, OUTPUT o_procedures).
IF o_labels = '' THEN RETURN.
/* this finds a popup menu, if any */
h_menu = i_object:POPUP-MENU NO-ERROR.
IF VALID-HANDLE(h_menu) THEN RETURN. /* already created previously */
/* create a popup menu */
CREATE MENU h_menu.
ASSIGN
h_menu:POPUP-ONLY = TRUE
i_object:POPUP-MENU = h_menu
.
/* add the standard maintenance options (they still may not be supported though) */
DO l_count = 1 TO NUM-ENTRIES (o_labels):
IF ENTRY(l_count,o_labels) = 'Rule' THEN DO:
CREATE MENU-ITEM h_menu_item
ASSIGN
SUBTYPE = 'RULE'
PARENT = h_menu
.
END.
ELSE DO:
CREATE MENU-ITEM h_menu_item
ASSIGN
PARENT = h_menu
LABEL = ENTRY(l_count,o_labels)
SENSITIVE = TRUE
TRIGGERS:
ON CHOOSE PERSISTENT RUN pp_apply_maint_action IN THIS-PROCEDURE (SELF, ENTRY(l_count,o_procedures)).
END TRIGGERS.
END.
END.
END.
IF VALID-HANDLE(h_menu)
THEN APPLY 'menu-drop' TO h_menu.
/* MENU-DROP - Supported only when the POPUP-ONLY attribute is set to TRUE and the
menu is set as a popup for some other widget */
END PROCEDURE.
PROCEDURE find_menu_stuff.
/* do lookups or other general or specific things here */
END.

Related

Godot Inversing selected rectangle area made up of two Vector2 objects

This seems like a really simple question but I've been at this for a couple of hours and need an outsiders perspective.
I'm migrating a start of a game to Godot from Unity.
I'm selecting an area of tiles (startDragPosition, endDragPosition, both Vector2 objects) from a TileMap and setting them to a certain tile. Currently the dragging only works if the direction is top->bottom and left->right, so if the ending x and y are larger than the starting x and y
In Unity(C#) I had a few simple lines to flip the rectangle values if it was dragged in reverse.
if (end_x < start_x) {
int tmp = end_x;
end_x = start_x;
start_x = tmp;
}
if (end_y < start_y) {
int tmp = end_y;
end_y = start_y;
start_y = tmp;
}
However in when I try a similar approach in Godot it is not working for some reason. I'm thinking that I'm messing up somewhere earlier and any help would be appreciated. If there is an easier way of doing this please tell me I'm fairly new to Godot itself.
Here is the function responsible for dragging in my Godot script(GD)
func Drag():
if(Input.is_action_just_pressed("click")):
startDragPosition=get_global_mouse_position()
if(Input.is_action_pressed("click")):
endDragPosition=get_global_mouse_position()
print("01 START: "+String(stepify(startDragPosition.x-8,16)/16)+"_"+String(stepify(startDragPosition.y-8,16)/16))
print("01 END: "+String(stepify(endDragPosition.x-8,16)/16)+"_"+String(stepify(endDragPosition.y-8,16)/16))
if(endDragPosition.x<startDragPosition.x):
var temp = endDragPosition.x
endDragPosition.x=startDragPosition.x
startDragPosition.x=temp
if(endDragPosition.y<startDragPosition.y):
var temp = endDragPosition.y
endDragPosition.y=startDragPosition.y
startDragPosition.y=temp
for x in range(startDragPosition.x,endDragPosition.x):
for y in range(startDragPosition.y,endDragPosition.y):
get_node("../DragPreview").set_cell((stepify(x-8,16))/16,(stepify(y-8,16))/16,0)
#get_node("../DragPreview").update_bitmask_area(Vector2((stepify(x-8,16))/16,(stepify(y-8,16))/16))
if(Input.is_action_just_released("click")):
print("START: "+String(stepify(startDragPosition.x-8,16)/16)+"_"+String(stepify(startDragPosition.y-8,16)/16))
print("END: "+String(stepify(endDragPosition.x-8,16)/16)+"_"+String(stepify(endDragPosition.y-8,16)/16))
startDragPosition=null
endDragPosition=null
When you drag, you always write to endDragPosition.
When you drag to the left or drag up, and you update endDragPosition, it will have smaller coordinates than it had before. Because of that you swap the coordinates with startDragPosition… And then you keep dragging left or up, and that updates endDragPosition again. The original startDragPosition is lost.
Either you work with a copy when you are deciding the start and end:
var start = startDragPosition
var end = endDragPosition
if(end.x<start.x):
var temp = end.x
end.x=start.x
start.x=temp
if(end.y<start.y):
var temp = end.y
end.y=start.y
start.y=temp
for x in range(start.x,end.x):
for y in range(start.y,end.y):
# whatever
pass
Or you forget this swapping shenanigans, and give the loops a step:
var start = startDragPosition
var end = endDragPosition
for x in range(start.x,end.x,sign(end.x-start.x)):
for y in range(start.y,end.y,sign(end.y-start.y)):
# whatever
pass

Reading in multiple STEM signals into multiple datacubes

I've written a through focus STEM acquisition script that reads in an image using the DSAcquire function, where I specify the signal to be read in with DSAcquireData(img, signalindex, etc.).
The nice thing about the above is that I can read in the image without it appearing on screen, copy it into a datacube, and then acquire the next one in the series, etc.
If I want to use two signals instead of one (eg HAADF and BF), it looks like the only way to do this is to use DSStartAcquisition after setting the digiscan parameters?
How should I go about copying signals into two preallocated image stacks (stack1, stack2)? Preferably without tens of images cluttering the screen (but ideally with some measure of progress?)
One way of doing this - by iterating over x individual acquisitions is a straight forward expansion of the F1 help examples:
// Acquire 2 signals simultaneously, e.g. HAADF and BF detector
number paramID
number width = 512 // pixel
number height = 512 // pixel
number rotation = 0 // degree
number pixelTime= 2 // microseconds
number lSynch = 1 // activated
paramID = DSCreateParameters( width, height, rotation, pixelTime, lSynch )
number signalIndex, dataType, selected, imageID
signalIndex = 0
dataType = 2 // 2 byte data
selected = 1 // acquire this signal
image img1 := IntegerImage( "Signal 1", dataType, 0, width, height )
img1.ShowImage()
imageID = img1.ImageGetID() // use displayed image
DSSetParametersSignal( paramID, signalIndex, dataType, selected, imageID )
signalIndex = 1
dataType = 2 // 2 byte data
selected = 1 // acquire this signal
image img2 := IntegerImage( "Signal 1", dataType, 0, width, height )
img2.Showimage()
imageID = img2.ImageGetID() // use displayed image
DSSetParametersSignal( paramID, signalIndex, dataType, selected, imageID )
number continuous = 0 // 0 = single frame, 1 = continuous
number synchronous = 1 // 0 = return immediately, 1 = return when finished
// Create stack to copy data to
number nplanes = 10
image stack1 := img1.ImageClone()
stack1.ImageResize(3,width,height,nplanes)
stack1.SetName("Signal 1 (stack)")
stack1.ShowImage()
image stack2 := img2.ImageClone()
stack2.ImageResize(3,width,height,nplanes)
stack2.SetName("Signal 2 (stack)")
stack2.ShowImage()
//Quickly arrange image
EGUPerformActionWithAllShownImages("arrange")
// Iterated acquisition
for( number i=0; i<nPlanes; i++ )
{
DSStartAcquisition( paramID, continuous, synchronous )
// Copy data
stack1.slice2(0,0,i, 0,width,1, 1,height,1) = img1
stack2.slice2(0,0,i, 0,width,1, 1,height,1) = img2
}
DSDeleteParameters( paramID ) // remove parameters from memory
However, this will restart a new Digiscan acquisition at each frame. You might want to prefer doing this with a continuous acquisition and an image listener instead.
For this, you would most likely hook up an image-listener as described in the F1 help here:
The Digiscan acquisition - depending on the speed - will update the image several times per frame, so you will need some check if it's end-of-frame.
One way to do this would be to use a data_value_changed event and then check if the last pixel in the image has changed value. Another option would be to use the tags_changed event, as apparently the tags of the acquisition image are update once per frame. Both options have some potential issues, though.
See also this very relevant recent question on this topic: Fastest way to see which pixel has changed when using a listener

Specman/e list of lists (multidimensional array)

How can I create a fixed multidimensional array in Specman/e using varibles?
And then access individual elements or whole rows?
For example in SystemVerilog I would have:
module top;
function automatic my_func();
bit [7:0] arr [4][8]; // matrix: 4 rows, 8 columns of bytes
bit [7:0] row [8]; // array : 8 elements of bytes
row = '{1, 2, 3, 4, 5, 6, 7, 8};
$display("Array:");
foreach (arr[i]) begin
arr[i] = row;
$display("row[%0d] = %p", i, row);
end
$display("\narr[2][3] = %0d", arr[2][3]);
endfunction : my_func
initial begin
my_func();
end
endmodule : top
This will produce this output:
Array:
row[0] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[1] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[2] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[3] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
arr[2][3] = 4
Can someone rewrite my_func() in Specman/e?
There are no fixed arrays in e. But you can define a variable of a list type, including a multi-dimensional list, such as:
var my_md_list: list of list of my_type;
It is not the same as a multi-dimensional array in other languages, in the sense that in general each inner list (being an element of the outer list) may be of a different size. But you still can achieve your purpose using it. For example, your code might be rewritten in e more or less like this:
var arr: list of list of byte;
var row: list of byte = {1;2;3;4;5;6;7;8};
for i from 0 to 3 do {
arr.add(row.copy());
print arr[i];
};
print arr[2][3];
Notice the usage of row.copy() - it ensures that each outer list element will be a copy of the original list.
If we don't use copy(), we will get a list of many pointers to the same list. This may also be legitimate, depending on the purpose of your code.
In case of a field (as opposed to a local variable), it is also possible to declare it with a given size. This size is, again, not "fixed" and can be modified at run time (by adding or removing items), but it determines the original size of the list upon creation, for example:
struct foo {
my_list[4][8]: list of list of int;
};

how to find out x and y offset when trying to drag/move an element in Selenium?

I am using
builder.moveToElement(element).moveByOffset(x,y).click().build().perform();
In above function I am not sure of values of X and Y, so I have to run test several times to find out the correct values of X and Y.
Example: first I will try with 5, 5 then if I see its little more towards right than 5, 10 and so on.
Is their a way to find it one go?
Try the below code to get exact x & y coordinate & then try your code
WebElement ele= driver.findElement(By.xpath("x-path"));
Point point = ele.getLocation();
int xcord = point.getX();
int ycord = point.getY();
Please try to follow the below details.
If you are using Chrome Browser (use plug in "Cordinates") or Firefox browser (use plug in "Web Developer -> Display Ruler").
After fetching the cordinates from these plug ins, you can use them in your action class for drag and drop.
Please be mindful that, once the action is done, you should put offset to ZERO.
e.g: if in first attempt I have tried to click any element preset at (60,20), then before making the second attempt to click anywhere else, I should set the offset as (-60, -20).
Else you can find the second coordinates and perform the plus minus calculations before attempting to click on that.
Try this code to get coordinates by program itself
//set x and y limits to your webelement size
WebElement element = //your element;
actions = new Actions(remoteDriver);
for (int x = 0; x < element.getSize().getWidth(); x++) {
for (int y = 0; y < getSize().getHeight(); y++) {
actions.moveToElement(element).moveByOffset(x, y).click().build().perform();
if ( //your condition ) {
System.out.println("X and Y when condition satisified are" + x " and " + y);
break;
}
}
}
In my experience , the offset values are nearly equal or in range to half of pixel values of particular point to click in webelement
ie for my full screen close button for video of 1300*700 playing browser , offset value to full screen close button was x=550 and y=320. Try limiting in that range. Smaller Web Elements means it is much easier to find.

Objective-C: Adding to variable before assignment

I have the following code:
NSInteger variableScene = 10;
NSInteger numberOfRowsXX = //an Integer value; <-- I would like replace XX with the value of 'variableScene'
So it'll look like this:
NSInteger numberOfRows10 == //an Integer value;
How can I replace XX with the value of variableScene?
*Update*
Why I'm trying accomplish this?
It's a bit complicated. I'm using Core Data with remote Database. In a nutshell: I have 10 Scenes that'll be presented based on the User selection order. For each Scene I need to assign the numberOfRows to present at the end of all the Scenes with a UITableViewController.
I have a variableScene that I pass around from Scene to Scene.
I need to assign numberOfRowsSceneXX = //an integer
XX will come from variableScene, which could be any number from 1 - 10.
So when we get to the last scene, we'll have a value for each Section (numberOfRowInSection) which will be represented by each Scene: numberOfRowScene1, numberOfRowsScene2, etc.
I tried to simplify the question. Hope it makes sense.
Use arrays.
set it up as:
#define MAX_SCENES 10
NSInteger numberOfRows[MAX_SCENES];
then when you want to set the value:
if (variableScene < MAX_SCENES) {
numberOfRows[variableScene] = variable;
}