As of v0.8.0
scrolling appears to be broken when nesting lists (on
Android). Attempting to scroll the list on android just does nothing. This
is in comparison to old functionality in v0.7.0
wherein scrolling down on
a nested list properly scrolled the list (e.g. if the cursor was within
the nested list only). Note other platforms tested (such as Linux this
bug does not effect).
Example: https://paste.sr.ht/~mil/df2af99291cd4bf2cda30d3184b3ca96220db5e5
Build the above example with gogio -target android .
; and then compare
the results swapping v0.7.0
and v0.8.0
in go.mod):
Looking into this further, I ran a git bisect
and the breaking commit is:
https://git.sr.ht/~eliasnaur/gio/commit/8fb6d3da2b015008ae9debb44241bef13b5c56fb
Prior to this commit nested list scrolling worked fine on Android and after, attempting scroll a nested list just nops.
Just to clarify as I can't edit the ticket - scrolling does work on the top-level list in either case..
But attempting to scroll within the nested listed is broken and has different / no functionality on v0.8.0
Thank you very much for the bisection! I think we need ~eliasnaur's input on this one.
Elias Naur referenced this ticket in commit efd31ad.
Thank you for the detailed report, and in particular the bisection. I've pushed a change that alleviates the problem a bit. Your example now scrolls, but not the inner list.
The diagnosis is that with the bisected change, both scrollable Lists receive the drag events, and both would execute a grab of the pointer. Before, the grabs would cancel each other out, but with the change the first grabber wins.
This is not a complete fix, because the outer List processes events before the nested List and thus wins the grab.
I'm not sure what the right fix is.
An option is to rework the List to process events last, but that complicates the List implementation and requires it to lay out children both before and and after scroll events.
Another option is to defer pointer grabs, and resolve multiple grabs by granting the top-most handler the grab, not just the first. This change seems right, and I started working on it. However, I ran into complexities during which I realized that not even top-most grabs will completely fix the issue: what is lacking is ability for the inner/top-most List to scroll until it reaches one of its extremes and then allow the outer List to continue scrolling. This is the behaviour of scroll (z-axis) events, and I'd like to have that for touch-based scrolling as well.
Scroll events are filtered by scroll distance, so perhaps something similar can be done here. Say, a pointer handler can declare its maximum drag distance in each direction, and then the Gio event machinery can route drag events to the handler that have remaining drag distance, prioritized by top-most-ness. That is, the inner List will be dragged until its extreme, and then the outer List and so on.
Since this is a bigger change, I won't be able to work on it right now, but I'd be happy to review any attempts at implementing it.
I see - so I'm understanding this new behavior is inherent to the way event handling was refactored. Prior to the commit & in v0.7.0 scrolling in nested lists worked perfectly (scrolling the nested list when the cursor was there and the outer list when not focused on the nested list itself). But I suppose reverting the event handling logic refactor is infeasible / unrealistic
Scroll events are filtered by scroll distance, so perhaps something similar can be done here. Say, a pointer handler can declare its maximum drag distance in each direction, and then the Gio event machinery can route drag events to the handler that have remaining drag distance, prioritized by top-most-ness. That is, the inner List will be dragged until its extreme, and then the outer List and so on.
That sounds logical to me - however I'm not entirely too familiar with gio's underlying logic to be able to make the change myself.
I built & maintain an app based on gio which makes heavy use of nested lists as a UX pattern (unfortunately) so I'm currently blocked on app releases since gio v0.8.0 (and downgrading gio to v0.7.0 also isn't an option due to some go tooling version mismatch in the target builds I distribute on too).
I shall try to find some time to work on this, but it won't be before end of this month.
In the meantime, I encourage you look into adding
DragX
andDragY
fields topointer.Filter
. They likely work similar to the existingScrollX
/ScrollY
fields declared on line 68-69 in pointer.go. In fact, you may even get away with using the existing scroll limit values for drag limits for a prototype.