181 lines
6.1 KiB
Python
181 lines
6.1 KiB
Python
__all__ = ('GestureDatabase', 'GestureDatabaseItem')
|
|
|
|
from kivy.clock import Clock
|
|
from kivy.lang import Builder
|
|
from kivy.properties import NumericProperty, StringProperty
|
|
from kivy.properties import ListProperty, ObjectProperty
|
|
from kivy.uix.gridlayout import GridLayout
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.uix.popup import Popup
|
|
from kivy.graphics import Rectangle, Color
|
|
from kivy.multistroke import Recognizer
|
|
|
|
# local libraries
|
|
from helpers import InformationPopup
|
|
|
|
|
|
Builder.load_file('gesturedatabase.kv')
|
|
|
|
|
|
class GestureExportPopup(Popup):
|
|
pass
|
|
|
|
|
|
class GestureImportPopup(Popup):
|
|
pass
|
|
|
|
|
|
class GestureDatabaseItem(FloatLayout):
|
|
name = StringProperty('(no name)')
|
|
template_count = NumericProperty(0)
|
|
gesture_list = ListProperty([])
|
|
|
|
def __init__(self, **kwargs):
|
|
super(GestureDatabaseItem, self).__init__(**kwargs)
|
|
self.rect = None
|
|
self._draw_trigger = Clock.create_trigger(self.draw_item, 0)
|
|
self.update_template_count()
|
|
self.bind(gesture_list=self.update_template_count)
|
|
self.register_event_type('on_select')
|
|
self.register_event_type('on_deselect')
|
|
|
|
def toggle_selected(self, *l):
|
|
self._draw_rect(clear=True)
|
|
if self.ids.select.state == 'down':
|
|
self.dispatch('on_select')
|
|
self.ids.select.text = 'Deselect'
|
|
else:
|
|
self.dispatch('on_deselect')
|
|
self.ids.select.text = 'Select'
|
|
|
|
def update_template_count(self, *l):
|
|
tpl_count = 0
|
|
for g in self.gesture_list:
|
|
tpl_count += len(g.templates)
|
|
self.template_count = tpl_count
|
|
|
|
def draw_item(self, *l):
|
|
self.ids.namelbl.pos = self.pos
|
|
self.ids.namelbl.y += 90
|
|
self.ids.stats.pos = self.pos
|
|
self.ids.stats.y += 40
|
|
self.ids.select.pos = self.pos
|
|
self._draw_rect()
|
|
|
|
def _draw_rect(self, clear=False, *l):
|
|
col = self.ids.select.state == 'down' and 1 or .2
|
|
with self.canvas:
|
|
Color(col, 0, 0, .15)
|
|
if self.rect or clear:
|
|
self.canvas.remove(self.rect)
|
|
self.rect = Rectangle(size=self.size, pos=self.pos)
|
|
|
|
def on_select(*l):
|
|
pass
|
|
|
|
def on_deselect(*l):
|
|
pass
|
|
|
|
|
|
class GestureDatabase(GridLayout):
|
|
selected_count = NumericProperty(0)
|
|
recognizer = ObjectProperty(None)
|
|
export_popup = ObjectProperty(GestureExportPopup())
|
|
import_popup = ObjectProperty(GestureImportPopup())
|
|
info_popup = ObjectProperty(InformationPopup())
|
|
|
|
def __init__(self, **kwargs):
|
|
super(GestureDatabase, self).__init__(**kwargs)
|
|
self.redraw_all = Clock.create_trigger(self._redraw_gesture_list, 0)
|
|
self.export_popup.ids.save_btn.bind(on_press=self.perform_export)
|
|
self.import_popup.ids.filechooser.bind(on_submit=self.perform_import)
|
|
|
|
def import_gdb(self):
|
|
self.gdict = {}
|
|
for gesture in self.recognizer.db:
|
|
if gesture.name not in self.gdict:
|
|
self.gdict[gesture.name] = []
|
|
self.gdict[gesture.name].append(gesture)
|
|
|
|
self.selected_count = 0
|
|
self.ids.gesture_list.clear_widgets()
|
|
for k in sorted(self.gdict, key=lambda n: n.lower()):
|
|
gitem = GestureDatabaseItem(name=k, gesture_list=self.gdict[k])
|
|
gitem.bind(on_select=self.select_item)
|
|
gitem.bind(on_deselect=self.deselect_item)
|
|
self.ids.gesture_list.add_widget(gitem)
|
|
|
|
def select_item(self, *l):
|
|
self.selected_count += 1
|
|
|
|
def deselect_item(self, *l):
|
|
self.selected_count -= 1
|
|
|
|
def mass_select(self, *l):
|
|
if self.selected_count:
|
|
for i in self.ids.gesture_list.children:
|
|
if i.ids.select.state == 'down':
|
|
i.ids.select.state = 'normal'
|
|
i.draw_item()
|
|
else:
|
|
for i in self.ids.gesture_list.children:
|
|
if i.ids.select.state == 'normal':
|
|
i.ids.select.state = 'down'
|
|
i.draw_item()
|
|
|
|
def unload_gestures(self, *l):
|
|
if not self.selected_count:
|
|
self.recognizer.db = []
|
|
self.ids.gesture_list.clear_widgets()
|
|
self.selected_count = 0
|
|
return
|
|
|
|
for i in self.ids.gesture_list.children[:]:
|
|
if i.ids.select.state == 'down':
|
|
self.selected_count -= 1
|
|
for g in i.gesture_list:
|
|
# if g in self.recognizer.db: # not needed, for testing
|
|
self.recognizer.db.remove(g)
|
|
self.ids.gesture_list.remove_widget(i)
|
|
|
|
def perform_export(self, *l):
|
|
path = self.export_popup.ids.filename.text
|
|
if not path:
|
|
self.export_popup.dismiss()
|
|
self.info_popup.text = 'Missing filename'
|
|
self.info_popup.open()
|
|
return
|
|
elif not path.lower().endswith('.kg'):
|
|
path += '.kg'
|
|
|
|
self.save_selection_to_file(path)
|
|
|
|
self.export_popup.dismiss()
|
|
self.info_popup.text = 'Gestures exported!'
|
|
self.info_popup.open()
|
|
|
|
def perform_import(self, filechooser, *l):
|
|
count = len(self.recognizer.db)
|
|
for f in filechooser.selection:
|
|
self.recognizer.import_gesture(filename=f)
|
|
self.import_gdb()
|
|
self.info_popup.text = ("Imported %d gestures.\n" %
|
|
(len(self.recognizer.db) - count))
|
|
self.import_popup.dismiss()
|
|
self.info_popup.open()
|
|
|
|
def save_selection_to_file(self, filename, *l):
|
|
if not self.selected_count:
|
|
self.recognizer.export_gesture(filename=filename)
|
|
else:
|
|
tmpgdb = Recognizer()
|
|
for i in self.ids.gesture_list.children:
|
|
if i.ids.select.state == 'down':
|
|
for g in i.gesture_list:
|
|
tmpgdb.db.append(g)
|
|
tmpgdb.export_gesture(filename=filename)
|
|
|
|
def _redraw_gesture_list(self, *l):
|
|
for child in self.ids.gesture_list.children:
|
|
child._draw_trigger()
|