The main objective is to implement code that transforms gestures or strokes into events. The approach is as follows: event handlers for touch_down, touch_move and touch_up record the positions of these touch events. On touch_up, the recorded positions or gesture is decoded / looked up in a GestureDatabase, a gesture event is fired and the name of the gesture is passed as a parameter. This all works are expected.
Next, I want to bubble the gesture event to all other (active) widgets, so that only one widget has the code to record the touch events and the lookup in the GestureDatabase, and all connected widgets can respond to the gesture event. The code to record the touch events is implemented in a MDScreenManager and I want the child MDScreens to respond to the gesture events.
The code for the MyScreenManager class implements a touch event handler as below. The on_gesture method in the MyScreenManager class fires as expected. However, the on_gesture in the BatchesScreen class is never called.
class BatchesScreen(MDScreen):
def __init__(self, name):
super().__init__(name=name)
self.add_widget(self.build())
def build(self):
print(self.__class__)
return Builder.load_file('uix/batches.kv')
def on_gesture(self, *args):
print('Gesture dispacthed for Batches Screen: {}'.format(args[0]))
class TopLayout(MDBoxLayout):
pass
class MyScreenManager(MDScreenManager, EventDispatcher):
_strokes = {
'right' : 13,
'left' : 31,
'down' : 14,
'up' : 41
}
def __init__(self, **kwargs):
self._gestureDb = GestureDatabase()
for name, points in self._strokes.items():
self._gestureDb.add_gesture(Gesture(name=name, point_list=points))
self.register_event_type('on_gesture')
super(MyScreenManager, self).__init__(**kwargs)
def on_touch_down(self, touch):
touch.ud['line'] = list()
touch.ud['line'].append(touch.pos)
return MDScreenManager.on_touch_down(self, touch)
def on_touch_move(self, touch):
touch.ud['line'].append(touch.pos)
return MDScreenManager.on_touch_move(self, touch)
def on_touch_up(self, touch):
touch.ud['line'].append(touch.pos)
stroke = self._gestureDb.find(Gesture(point_list=touch.ud['line']), 0.5, False)
if stroke is not None:
self.dispatch('on_gesture', stroke[1].name)
MDScreenManager.on_touch_up(self, touch)
def on_gesture(self, *args):
print('Gesture dispacthed: {}'.format(args[0]))
class MyApp(MDApp):
def build(self):
root_widget = TopLayout()
root_widget.ids['batchesListScreen'].add_widget(BatchesScreen().build(), 1000)
root_widget.ids['recipesListScreen'].add_widget(RecipesScreen().build(), 1000)
root_widget.ids['manager'].current = 'RecipesScreen'
return root_widget
MyApp().run()
The widget hierarchy is defined in a KV-file:
<BatchesScreen@MDScreen>:
name: 'BatchesScreen'
MDBoxLayout:
<RecipesScreen@MDScreen>:
name: 'RecipesScreen'
MDBoxLayout:
<MyScreenManager@MDScreenManager>:
transition: MDSlideTransition()
direction: 'left'
<TopLayout@MDBoxLayout>:
orientation: 'vertical'
MDTopAppBar:
pos_hint: {"top": 1}
size_hint: (1, 0.1)
elevation: 4
title: "My Toolbar"
left_action_items: [["menu", lambda x: app.root.ids['nav_drawer'].set_state("open")]]
MDNavigationLayout:
id: top
size_hint: (1, 0.9)
pos_hint: {"top": 0.9}
MyScreenManager:
id: manager
BatchesScreen:
id: batchesListSscreen
RecipesScreen:
id: recipesListScreen
MDNavigationDrawer:
id: nav_drawer
anchor: "left"
radius: (0, 16, 16, 0)
MDNavigationDrawerMenu:
MDNavigationDrawerHeader:
title: "My App"
text: "Header text"
DrawerClickableItem:
text: "Batches"
on_press:
root.ids['manager'].current = 'BatchesScreen'
root.ids['nav_drawer'].set_state("closed")
DrawerClickableItem:
text: "Recipes"
on_press:
root.ids['manager'].current = 'RecipesScreen'
root.ids['nav_drawer'].set_state("closed")