CodenameOne icon indicating copy to clipboard operation
CodenameOne copied to clipboard

dragListener events are duplicated and arrive in wrong order

Open ThomasH99 opened this issue 4 years ago • 0 comments

Describe the bug I've spend a few days to get to the bottom of this issue. My code implements a dragListener that didn't behave correctly but jumped back and forth. I long thought it was a problem in my own code, but in the end I discovered it is due to Component. pointerDragged(final Component lead, final int x, final int y, final Object currentPointerPress) duplicating events, which then arrive out of order, probably due to the order in which callSerially executes the submitted Runnables.

It seems the error is linked to the additional calls here

private void pointerDragged(final Component lead, final int x, final int y, final Object currentPointerPress)
...
        if (dragCallbacks < 2) {
                dragCallbacks++;
                Display.getInstance().callSerially(new Runnable() {
                    public void run() {
                        if (dragActivated) {
                            lead.pointerDragged(x, y, currentPointerPress);
                        }
                        dragCallbacks--;
                    }
                });
            }

To Reproduce Run the below example code. Drag "DRAG ME" consistently upwards and you can see that many events arrive with a wrong y value, indicating (wrongly) that the drag direction has changed and that the received drag position has suddenly moved back to an earlier position like if the user's finger was jittering up and down.

int lastY = -1;
int dragDirection = 0; //0: init; -1=up; 1=down
int lastDragDirection = 0;
Form hi = new Form("Welcome", BoxLayout.y());

Label dragMe = new Label("DRAG ME");
dragMe.setDraggable(true);
dragMe.addDragOverListener((evt) -> {
    int y = evt.getY();
    lastDragDirection = dragDirection;
    if (lastY == -1 || y == lastY) { //ignore same y value
    } else if (y < lastY) {
        dragDirection = -1;
    } else if (y > lastY) {
        dragDirection = 1;
    }
    if (lastDragDirection != dragDirection) {
        Label dropTarget = evt.getDropTarget() instanceof Label ? (Label) evt.getDropTarget() : null;
        Log.p("Dragging " + (dragDirection == -1 ? "UP  " : dragDirection == 1 ? "DOWN" : "INIT") + " y= " + y + " d= " + (lastY - y)
                + (dropTarget != null ? " over " + dropTarget.getText() : ""));
    }
    lastY = y;
});
for (int i = 0; i < 20; i++) {
    if (i == 10) {
        hi.add(dragMe);
    }
    Label l = new Label("DropTarget " + i);
    l.setDropTarget(true);
    hi.add(l);
}
hi.show();

Expected behavior The drag events should not duplicated, or if there is an important reason for doing it, it should be ensured they don't arrive out of order.

Desktop (please complete the following information):

  • OS: MacOS, Simulator

ThomasH99 avatar Sep 24 '21 18:09 ThomasH99