Creating kivy behavior that dispatches event bubbling same way as on_touch_down
<p>Let's start with basic example:</p>

<pre><code>class OuterWidget(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            print('on_touch_down', self)
            return True  # doesn't dispatch to InnerWidget
        return super().on_touch_down(touch)


class InnerWidget(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            print('on_touch_down', self)
        return super().on_touch_down(touch)
</code></pre>

<p>Event dispatches to <code>OuterWidget</code> first, if it calls <code>super().on_touch_down(touch)</code> event dispatches to child widgets, else event doesn't dispatch next. That's clear.</p>

<p>I want to create some behavior that happens with <code>on_touch_down</code> and acts same way. Let's try:</p>

<pre><code>class TestBehavior(Widget):
    def __init__(self, **kwargs):
        self.register_event_type('on_test_event')
        super().__init__(**kwargs)

    def on_test_event(self, touch):
        pass

    def on_touch_down(self, touch):
        self.dispatch('on_test_event', touch)  # Some event that happens with on_touch_down
        return super().on_touch_down(touch)


class OuterWidget(TestBehavior, Widget):
    def on_test_event(self, touch):
        if self.collide_point(*touch.pos):
            print('on_test_event', self)
            return True  # doesn't affect anything, both widgets would recieve on_test_event
        return super().on_test_event(touch)


class InnerWidget(TestBehavior, Widget):
    def on_test_event(self, touch):
        if self.collide_point(*touch.pos):
            print('on_test_event', self)
            return True
        return super().on_test_event(touch)
</code></pre>

<p><code>on_test_event</code> bubbling wouldn't work same way as <code>on_touch_down</code>. Regardless of what <code>OuterWidget</code> returns event would be dispatched to <code>InnerWidget</code>. It happens because both widgets would receive <code>on_touch_down</code> event that fires <code>on_test_event</code>.</p>

<p>Looks like if I use <code>on_touch_down</code> to dispatch some event in behavior this event will be always dispatched to all children, regardless of what any of them returned. But I want not to dispatch <code>on_test_event</code> next if some widget didn't call <code>super().on_test_event(touch)</code>.</p>

<p>How can I do it? Any ideas?</p>

<p>The Widget class handles its events to all its children like this:</p>

<p>(copied from widget.py)</p>

<pre><code>def on_touch_down(self, touch):
    '''Receive a touch down event.
    :Parameters:
        `touch`: :class:`~kivy.input.motionevent.MotionEvent` class
            Touch received. The touch is in parent coordinates. See
            :mod:`~kivy.uix.relativelayout` for a discussion on
            coordinate systems.
    :Returns: bool
        If True, the dispatching of the touch event will stop.
        If False, the event will continue to be dispatched to the rest
        of the widget tree.
    '''
    if self.disabled and self.collide_point(*touch.pos):
        return True
    for child in self.children[:]:
        if child.dispatch('on_touch_down', touch):
            return True
</code></pre>

<p>As you can see it iterates over its childern and dispatch the event until <em>True</em> is returned.</p>

<p>To create a similar behavior you may create your own <strong>mix-in class and make all you class inherent from it</strong> or to **monkey patch Widget **</p>

<p>IMHO that will be a bit messy, what I would do is to create a function:</p>

<pre><code>def fire_my_event(widget):
    if hasattr(widget, 'on_test_event'):
       if widget.on_test_event():
          return True
    for c in widget.children[:]:
        if fire_my_event(c):
            return True

#in your code somewhere
class SomeWidget(Image): #or anything else ...
    def on_touch_down(self, touch):
       fire_my_event(self)
</code></pre>

<p>Have fun!</p>

python kivy