KendoSortable placeholder does not appear when item is dragged diagonally upwards - kendo-ui

I've got two kendo sortable list wherein I can drag the multi-selected items left to right. All looks good but I experienced this weird behavior. The second time I drag diagonally upwards (north east), the placeholder "Drop here" will not appear until you move the mouse downward a little.
Start dragging "Strawberries" then "Pinapples" to the right list. Remember that your cursor should move north east until you reach the below of "Strawberries"
Is this a limitation of kendo drag and drop?
Here is the Dojo that I am using.

So, I looked the the kendo source code and used your code in a local project with a bunch of console.log()'s and here's what I found:
(The methods of interest are _drag() and _movePlaceholder() of the Sortable class)
This is how kendo is deciding whether or not to show the placeholder(call _movePlaceholder()) inside _drag():
if (axisDelta.y < 0 && (moveOnDragEnter || offsetDelta.top < 0)) {
direction = 'prev';
} else if (axisDelta.y > 0 && (moveOnDragEnter || offsetDelta.top > 0)) {
direction = 'next';
}
While you are moving the cursor upwards over the right-side dropzone:
axisDelta.y is -1(moving up) AND offsetDelta.top > 0(you are below the top of the drop area)
So neither case is true.
The instant you drag 1 pixel down:
axisDelta.y is 1(you are moving down) AND offsetDelta.top > 0(still below the top of the drop area)
So you fall into the direction = 'next'; and _movePlaceholder() will get called since direction is set and the "Drop Here" appears in the "next" spot(below the last item).
If you drag from the top of the drop area, you would hit the direction = 'prev'; case and the "Drop Here" appears in the "prev" spot(above the first item).
The moveOnDragEnter variable seems to be an undocumented option that you can set to true on your sortable init to override the offsetDelta check BUT if you set it, it will cause the "Drop Here" to appear immediately upon entering the drop area BUT it will appear on the top of the list if you enter dragging up and it will appear on the bottom of the list if you enter dragging down...which is not what you want.
Whew!
So....no, with the current logic there is no way to be dragging upwards AND get the "Drop Here" to appear on the bottom of the list and it is a limitation of the sortable.
Now, if you like, you could probably edit the source code to add more cases to the logic to check for more condition combinations, i.e:
if (I'm anywhere in the drop area) {
figure out if the cursor position is above the first item or below the last item and set direction accordingly so that _movePlaceholder() will get called
}
...or just accept the limitation.

Related

Create PySimpleGUI list with a key

I wish to have a list of text items in a PySimpleGUI that I can update later. That is, I want to have a key for the list. This might be vertical or horizontal, and I do not know how many items there will be.
I end up with different use cases, but the current one is to make a single line of text items with different colors. Other times, I need to write and update a customized table, just different enough that the table widget does not work.
Conceptually, I want to do something like this:
layout = [ [sg.T('Titles and Things')], sg.ListThing(key='-data-', [[]]) ]
so that I can:
window['-data-'].update(values=[ [sg.T(v, color=c)] for (v,c) in my_data ])
Another, invalid syntax, way of saying what I want is to use [key="-data-", sg.T('Item1'), sg.T('Item2')].
Is this possible?
You can update individual layout elements but you cannot dynamically change the layout itself.
It is possible to create 2 or more elements, whereby only one of them is visible, and switch them later as needed. Or you can close and re-create the window with another layout. Or combine both approaches.
An example of switching layouts:
def change_layout():
left_col_1 = sg.Column([[sg.Text(f'Text {i}') for i in range(4)]], visible=True, key='col_1')
left_col_2 = sg.Column([[sg.Text(f'Text {i}')] for i in range(6)], visible=False, key='col_2')
visible_1 = True
layout = [[sg.Column([[left_col_1, left_col_2]]), sg.Button('Change layout', key='change')]]
window = sg.Window('window', layout=layout, finalize=True)
while True:
event, values = window.read()
print(event)
print(values)
print(visible_1)
if event in ('Exit', sg.WIN_CLOSED):
break
if event == 'change':
window['col_1'].update(visible=not visible_1)
window['col_2'].update(visible=visible_1)
visible_1 = not visible_1
Please notice that the alternative layouts for the left part (left_col_1, left_col_2) need to be enclosed in a container (column, frame) to keep their position in the window in the moment they are invisible.

Xcode UITest scrolling to the bottom of an UITableView

I am writing an UI test case, in which I need to perform an action, and then on the current page, scroll the only UITableView to the bottom to check if specific text shows up inside the last cell in the UITableView.
Right now the only way I can think of is to scroll it using app.tables.cells.element(boundBy: 0).swipeUp(), but if there are too many cells, it doesn't scroll all the way to the bottom. And the number of cells in the UITableView is not always the same, I cannot swipe up more than once because there might be only one cell in the table.
One way you could go about this is by getting the last cell from the tableView. Then, run a while loop that scrolls and checks to see if the cell isHittable between each scroll. Once it's determined that isHittable == true, the element can then be asserted against.
https://developer.apple.com/documentation/xctest/xcuielement/1500561-ishittable
It would look something like this (Swift answer):
In your XCTestCase file, write a query to identify the table. Then, a subsequent query to identify the last cell.
let tableView = app.descendants(matching: .table).firstMatch
guard let lastCell = tableView.cells.allElementsBoundByIndex.last else { return }
Use a while loop to determine whether or not the cell isHittable/is on screen. Note: isHittable relies on the cell's userInteractionEnabled property being set to true
//Add in a count, so that the loop can escape if it's scrolled too many times
let MAX_SCROLLS = 10
var count = 0
while lastCell.isHittable == false && count < MAX_SCROLLS {
apps.swipeUp()
count += 1
}
Check the cell's text using the label property, and compare it against the expected text.
//If there is only one label within the cell
let textInLastCell = lastCell.descendants(matching: .staticText).firstMatch
XCTAssertTrue(textInLastCell.label == "Expected Text" && textInLastCell.isHittable)
Blaines answer lead me to dig a little bit more into this topic and I found a different solution that worked for me:
func testTheTest() {
let app = XCUIApplication()
app.launch()
// Opens a menu in my app which contains the table view
app.buttons["openMenu"].tap()
// Get a handle for the tableView
let listpagetableviewTable = app.tables["myTableView"]
// Get a handle for the not yet existing cell by its content text
let cell = listpagetableviewTable.staticTexts["This text is from the cell"]
// Swipe down until it is visible
while !cell.exists {
app.swipeUp()
}
// Interact with it when visible
cell.tap()
}
One thing I had to do for this in order to work is set isAccessibilityElement to true and also assign accessibilityLabel as a String to the table view so it can be queried by it within the test code.
This might not be best practice but for what I could see in my test it works very well. I don't know how it would work when the cell has no text, one might be able to reference the cell(which is not really directly referenced here) by an image view or something else. It's obviously missing the counter from Blaines answer but I left it out for simplicity reasons.

SAPUI5 Panels - Controlling position of content

I have a number of Panels which, when expanded, show the corresponding questions for that particular 'Category'
The issue I have is, say for example I answer the questions for the 1st panel, the content will scroll down, eventually hiding the panel... fair enough.
However, when I click on the Next Category (Production Area), I need to the page to scroll back up to the first question in the Category, or maybe even just display the selected category at the top of the page.
Is this possible?
Currently, the user has to continually scroll back if when they select the next Category.
You can achieve it using scrollToElement()
var oPage = sap.ui.getCore().byId("pageId"); // you page ID
var oList = sap.ui.getCore().byId("ListId"); // element ID to which it has to scroll
if (oPage && oList) oPage.scrollToElement(oList, 1000);
Execute the above code inside the panel event expand.
you can try to use this control instead which suits your needs
https://sapui5.hana.ondemand.com/#/entity/sap.uxap.ObjectPageLayout
After trying everything, this is what worked for me.
onExpand: function (oEvent) {
if (oEvent.getParameters().expand) {
var focusID = oEvent.getParameter("id");
var elmnt = sap.ui.getCore().byId(focusID);
elmnt.getDomRef().scrollIntoView(true);

E4 RCP How to set selection of ToolBarItem that contains Radio Buttons

In Eclipse E4 (Luna), using the application model to create parts, handlers, commands, handled menu items etc, (these are not created programatically). I have a toolbar. This contains a sub-Menu item called "Filter" that contains another sub-menu of two filters. The two filters are two Handled Menu Items which are set up as "Radio" Buttons.
When I select the appropriate in the UI of my running app from the selection, the Radio button switches just fine to the selected Item. However I would like this selection to update (deselecting one Radio button and selecting the appropriate radio button of the handled menu item) when my ViewPart changes through other UI selection. Currently my ViewPart updates, but the Radio buttons are on the same previous selection through the UI.
Is there a way in which I get access both Handled Menu Item's IDs and set the selection (one to false, the other to true) when the viewer is updated.
Image of design is attached below:
Hierarchy of the application model is as follows:
Thanks in advance,
Marv
You can use the model service to find menu items. Use something like:
#Inject
EModelService modelService;
#Inject
MApplication app;
List<MMenuItem> items = modelService.findElements(app, "menu item id", MMenuItem.class, Collections.emptyList(), EModelService.IN_MAIN_MENU);
Once you have the MMenuItem you can call the setSelected(boolean) method to change the selection.
To find a menu item which is in a Part menu use:
modelService.findElements(app, "menu item id", MMenuItem.class, Collections.emptyList(), EModelService.IN_PART);
(IN_PART argument instead of IN_MAIN_MENU).
You could also specify the MPart rather than the Application as the first argument to findElements which may speed up the search.
For menus as a child of a Tool Bar Item it appears that the model services cannot find these directly. However you can find the Tool Bar Item and look at the menu yourself:
List<MToolItem> items = modelService.findElements(app, "tool bar item id", MToolItem.class, Collections.emptyList(), EModelService.IN_PART);
MToolItem item = items.get(0);
MMenu menu = item.getMenu();
List<MMenuElement> children = menu.getChildren();
... search menu elements
I solved this by starting with MPart PartID and drilling down to the HandledMenuItems on which I wanted to set the Radio Button selections, then setting the selection property for each individual HandledMenuItem.
This can probably be refactored to be more concise, but I've left the code with each step to have the solution easier to read.
BTW, in every instance / combination of the EModelService methods, the list returned a size of 0. So I'm not certain if that will work for what I'm trying to achieve. The following does work, although I'm not certain it is the most efficient means.
I hope this helps others.
// Get view part
MPart viewPart = _partService.findPart("part_id");
// get list of all menu items from the Part
List<MMenu> viewPartMenu = viewPart.getMenus();
// Get list of ViewMenus from viewPartMenu there is only one View Menu so it will be index 0
MMenu viewMenu = viewPartMenu .get(0);
// Get list of MMenuElements from the viewMenu - the children in the view menu
List<MMenuElement> viewMenuElements = viewMenu.getChildren();
// This gets me to the 2 HandledMenuItems
// Upper Most HandledMenuItem Radio Button is at viewMenuElements index 0. This is cast to MHandledMenuItem
MHandledMenuItem upperHandledMenuItem = (MHandledMenuItem) viewMenuElements.get(0);
// Set Selection
upperHandledMenuItem.setSelected(false);
// Lower Most HandledMenuItem Radio Button is at viewMenuElements index 1. This is cast to MHandledMenuItem
MHandledMenuItem lowerHandledMenuItem = (MHandledMenuItem) viewMenuElements.get(1);
// Set selection
lowerHandledMenuItem.setSelected(true);

DataGridView: how to make scrollbar in sync with current cell selection?

I have a windows application with DataGridView as data presentation. Every 2 minutes, the grid will be refreshed with new data. In order to keep the scroll bar in sync with the new data added, I have to reset its ScrollBars:
dbv.Rows.Clear(); // clear rows
SCrollBars sc = dbv.ScrollBars;
dbv.ScrollBars = ScrollBars.None;
// continue to populate rows such as dbv.Rows.Add(obj);
dbv.ScrollBars = sc; // restore the scroll bar setting back
With above codes, the scroll bar reappears fine after data refresh. The problem is that the application requires to set certain cell as selected after the refresh:
dbv.CurrentCell = dbv[0, selectedRowIndex];
With above code, the cell is selected; however, the scroll bar's position does not reflect the position of the selected cell's row position. When I try to move the scroll bar after the refresh, the grid will jump to the first row.
It seems that the scroll bar position is set back to 0 after the reset. The code to set grid's CurrentCell does not cause the scroll bar to reposition to the correct place. There is no property or method to get or set scroll bar's value in DataGriadView, as far as I know.
I also tried to set the selected row to the top:
dbv.CurrentCell = dbv[0, selectedRowIndex];
dbv.FirstDisplayedScrollingRowIndex = selectedRowIndex;
The row will be set to the top, but the scroll bar's position is still out of sync. Not sure if there is any way to make scroll bar's position in sync with the selected row which is set in code?
I found an answer to resolve issue. As I mentioned that the control does not have methods or properties to set the correct scroll bar value. However, the scroll bar and the DatagridView content will display correct if there is an interaction directly towards to the UI such as touch the scroll bar or grid cell. It looks like that the control needs to be refocused and a repaint.
Simply use the following codes does not cause the scroll bar reset:
dgv.Select();
// or dbv.Focuse();
The way I found is that I have to make the DatagridView control disappear to back again. Fortunately, I have a tab control with several tabs. Then I switch the tab to get scroll bar reset:
int index = myTabCtrl.SelectedIndex;
if (index == (myTabCtrl.TabCount)) {
dgv.SeletecedIndex = 0;
}
else {
dgv.SelectedIndex = index + 1;
}
myTabCtrl.SelectedIndex = index;
If you don't have any way to hide the DatagridView on your form, you could simply minimize the form and then restore it back.
The problem is that there will be a fresh on the UI.
It seems, TAB, SHIFT+TAB, END keys don't always bring last column into the visible view.
The following code inside the CurrentCellChanged event handler seems to fix this issue (vb.net):
If Me.MyDataGridView.CurrentCell IsNot Nothing Then
Dim currentColumnIndex As Integer = e.MyDataGridView.CurrentCell.ColumnIndex
Dim entireRect As Rectangle = _
Me.MyDataGridView.GetColumnDisplayRectangle(currentColumnIndex, False)
Dim visiblePart As Rectangle = _
Me.MyDataGridView.GetColumnDisplayRectangle(currentColumnIndex, True)
If (visiblePart.Width < entireRect.Width) Or (entireRect.Width = 0) Then
Me.MyDataGridView.FirstDisplayedCell = Me.MyDataGridView.CurrentCell
'OR Me.MyDataGridView.FirstDisplayedScrollingColumnIndex = currentColumnIndex
End If
End If

Resources