Buttons inside a carousel disables swiping/paging, buttons 'steal' touch events #737

Closed
ricosuave73 opened this Issue Oct 12, 2012 · 10 comments

Projects

None yet

5 participants

@ricosuave73

Issue:
When placing a grid of buttons inside a Carousel, swiping the Carousel to go the the next or previous page no longer works, instead, the buttons inside the Carousel get triggered.

Expected behavior:
Buttons inside a Carousel mimic the interface of a smartphone or tablet, where a user can page through his/her apps by swiping, and open an application by tapping on an icon.
So the expected behaviour would be that a swipe will page through the Carousel, and a tap will operate the element(s) inside.

Possible solution:
In the scrollview element, the same issue would occur, but there it is solved. It should be possible to port the swipe/tap code from the ScrollView to the Carousel, but I was unable to do so myself.

@hansent
@revolunet

+1 on this, the widgets should detect swipe movement and "bubble" it to the parent carousel if any

@tshirtman
Kivy member
@revolunet

For me, if swipe is detected, then on_release shouldnt be fired

@hansent
@tito
Kivy member

I don't think adding on_touch_cancel in base widget make sense: traversing the whole widget tree for informing only one or two widget about a touch is cancelled is meaningless. Plus, cancel a touch indicate that the touch is not gonna to work right ? But here, we want to stop the touch working for the button, and continue to work for the scrollview.

So my idea is to continue on the "grab" state. First, everyone agreed that even if we receive on_touch_down, we might not receive on_touch_up for tons of reason. BUT, if you grab the touch, you're ensured that the on_touch_up will be called. Button use the grab state for the up, as many others widgets.

Now, in the MotionEvent.grab() method, we have an exclusive= parameter: If somebody grab exclusively the touch, other tentative of grab will failed (currently implemented as an exception, but actually, we never try/catch in our code.)

My proposal would be (i assume that Button is somewhere inside the ScrollView tree):
1. ScrollView is the first to receive the event, and start to grab() without exclusive, as usual.
2. Button got the event, and do the same
3. ScrollView detect a swipe, he's redoing the grab() with exclusive=True.
4. In the grab() method, we fire manually a touch_up event for all the classes in grab mode, except the exclusive one
5. Button receive an on_touch_up in grab mode:
5.1. on_release is fired, as usual
5.2 OR we add a touch.grab_cancel or something like that, and use it to see if we should continue or not.
6. ScrollView is now the only one to receive touch move/up

If 5.2 is not acceptable for some reason, then we could do at first: touch.grab(self, self.on_grab_cancel).
Or on_touch_cancel, but not in the base widget (no tree dispatching). If grab() detect a on_touch_cancel method, it will just use it.

What do you think ?

@hansent

5.1. on_release is fired, as usual
dont work..becasue button should not fire on_release in this case right?!

OR we add a touch.grab_cancel or something like that, and use it to see if we should continue or not.
this can work, but it will make every touch handler function who uses grab more complicated

If 5.2 is not acceptable for some reason, then we could do at first: touch.grab(self, self.on_grab_cancel).
Or on_touch_cancel, but not in the base widget (no tree dispatching). If grab() detect a on_touch_cancel
method, it will just use it.

I really like your last suggestion, let me see if I understand right:

def grab(self, widget, on_cancel=None, exclusive=False):
    ...

touch.grab(self, self.on_grab_cancel) : will use on self.on_grab_cancel if touch is later grabbed exclusively

or if I call just touch.grab(self) and self is a widget with on_touch_cancel (or on _grab_cancel ?) it will use that...if its None, and widget dont have this method...just dont do anything...

@tito
Kivy member

I prefered on_grab_cancel when i wrote the answer, but i've fallback on your proposal. Seem that the on_grab_cancel is better.

But yes, that's the proposal. I'm in favor of the second (= not changing the grab() signature). All the changes would be in grab(), and then adapt the widgets we need.

The signature would on_grab_cancel(self, touch).

@tito tito was assigned Oct 15, 2012
@tito
Kivy member

Ok, i'm trying to implement the 5.2 solution

@tito
Kivy member

Ok, no 5.2 solution, but implementing a gesture detector same as scrollview works. Done!

@tito tito closed this Nov 8, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment