test-kivy-app/kivy_venv/share/kivy-examples/demo/multistroke/main.py

145 lines
5.7 KiB
Python
Raw Normal View History

2024-09-15 12:12:16 +00:00
'''
Multistroke Recognition Database Demonstration
==============================================
This application records gestures and attempts to match them. You should
see a black drawing surface with some buttons across the bottom. As you
make a gesture on the drawing surface, the gesture will be added to
the history and a match will be attempted. If you go to the history tab,
name the gesture, and add it to the database, then similar gestures in the
future will be recognized. You can load and save databases of gestures
in .kg files.
This demonstration code spans many files, with this being the primary file.
The information pop-up ('No match') comes from the file helpers.py.
The history pane is managed in the file historymanager.py and described
in the file historymanager.kv. The database pane and storage is managed in
the file gesturedatabase.py and the described in the file gesturedatabase.kv.
The general logic of the sliders and buttons are in the file
settings.py and described in settings.kv. but the actual settings pane is
described in the file multistroke.kv and managed from this file.
'''
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.gesturesurface import GestureSurface
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.label import Label
from kivy.multistroke import Recognizer
# Local libraries
from historymanager import GestureHistoryManager
from gesturedatabase import GestureDatabase
from settings import MultistrokeSettingsContainer
class MainMenu(GridLayout):
pass
class MultistrokeAppSettings(MultistrokeSettingsContainer):
pass
class MultistrokeApp(App):
def goto_database_screen(self, *l):
self.database.import_gdb()
self.manager.current = 'database'
def handle_gesture_cleanup(self, surface, g, *l):
if hasattr(g, '_result_label'):
surface.remove_widget(g._result_label)
def handle_gesture_discard(self, surface, g, *l):
# Don't bother creating Label if it's not going to be drawn
if surface.draw_timeout == 0:
return
text = '[b]Discarded:[/b] Not enough input'
g._result_label = Label(text=text, markup=True, size_hint=(None, None),
center=(g.bbox['minx'], g.bbox['miny']))
self.surface.add_widget(g._result_label)
def handle_gesture_complete(self, surface, g, *l):
result = self.recognizer.recognize(g.get_vectors())
result._gesture_obj = g
result.bind(on_complete=self.handle_recognize_complete)
def handle_recognize_complete(self, result, *l):
self.history.add_recognizer_result(result)
# Don't bother creating Label if it's not going to be drawn
if self.surface.draw_timeout == 0:
return
best = result.best
if best['name'] is None:
text = '[b]No match[/b]'
else:
text = 'Name: [b]%s[/b]\nScore: [b]%f[/b]\nDistance: [b]%f[/b]' % (
best['name'], best['score'], best['dist'])
g = result._gesture_obj
g._result_label = Label(text=text, markup=True, size_hint=(None, None),
center=(g.bbox['minx'], g.bbox['miny']))
self.surface.add_widget(g._result_label)
def build(self):
# Setting NoTransition breaks the "history" screen! Possibly related
# to some inexplicable rendering bugs on my particular system
self.manager = ScreenManager(transition=SlideTransition(
duration=.15))
self.recognizer = Recognizer()
# Setup the GestureSurface and bindings to our Recognizer
surface = GestureSurface(line_width=2, draw_bbox=True,
use_random_color=True)
surface_screen = Screen(name='surface')
surface_screen.add_widget(surface)
self.manager.add_widget(surface_screen)
surface.bind(on_gesture_discard=self.handle_gesture_discard)
surface.bind(on_gesture_complete=self.handle_gesture_complete)
surface.bind(on_gesture_cleanup=self.handle_gesture_cleanup)
self.surface = surface
# History is the list of gestures drawn on the surface
history = GestureHistoryManager()
history_screen = Screen(name='history')
history_screen.add_widget(history)
self.history = history
self.manager.add_widget(history_screen)
# Database is the list of gesture templates in Recognizer
database = GestureDatabase(recognizer=self.recognizer)
database_screen = Screen(name='database')
database_screen.add_widget(database)
self.database = database
self.manager.add_widget(database_screen)
# Settings screen
app_settings = MultistrokeAppSettings()
ids = app_settings.ids
ids.max_strokes.bind(value=surface.setter('max_strokes'))
ids.temporal_win.bind(value=surface.setter('temporal_window'))
ids.timeout.bind(value=surface.setter('draw_timeout'))
ids.line_width.bind(value=surface.setter('line_width'))
ids.draw_bbox.bind(value=surface.setter('draw_bbox'))
ids.use_random_color.bind(value=surface.setter('use_random_color'))
settings_screen = Screen(name='settings')
settings_screen.add_widget(app_settings)
self.manager.add_widget(settings_screen)
# Wrap in a gridlayout so the main menu is always visible
layout = GridLayout(cols=1)
layout.add_widget(self.manager)
layout.add_widget(MainMenu())
return layout
if __name__ in ('__main__', '__android__'):
MultistrokeApp().run()