import threading
from transitions.extensions import HierarchicalMachine as Machine
-class Key(ButtonBehavior, Widget):
+class KeyMachine(Widget):
STATES = [
'initial',
'configuring',
},
]
+ state = StringProperty("")
+
+ def __init__(self, key, **kwargs):
+ self.key = key
+
+ Machine(model=self, states=self.STATES,
+ transitions=self.TRANSITIONS, initial='initial',
+ ignore_invalid_triggers=True, queued=True)
+ super(KeyMachine, self).__init__(**kwargs)
+
+ # Machine states / events
+ def is_loaded_or_failed(self):
+ return self.is_loaded(allow_substates=True) or self.is_failed()
+
+ def is_loaded_inactive(self):
+ return self.is_loaded_no_config() or self.is_loaded_no_actions()
+
+ def on_enter_configuring(self):
+ if self.key.key_sym in self.key.parent.key_config:
+ self.key.config = self.key.parent.key_config[self.key.key_sym]
+
+ self.key.actions = []
+ for key_action in self.key.config['actions']:
+ self.key.add_action(key_action[0], **key_action[1])
+
+ if 'description' in self.key.config['properties']:
+ self.key.set_description(self.key.config['properties']['description'])
+ else:
+ self.key.unset_description()
+ if 'color' in self.key.config['properties']:
+ self.key.set_color(self.key.config['properties']['color'])
+ else:
+ self.key.unset_color()
+ self.success()
+ else:
+ self.no_config()
+
+ def on_enter_loading(self):
+ if len(self.key.actions) > 0:
+ for action in self.key.actions:
+ action.load()
+ else:
+ self.no_actions()
+
+ def run_actions(self, modifiers):
+ self.key.parent.parent.ids['KeyList'].append(self.key.key_sym)
+ debug_print("running actions for {}".format(self.key.key_sym))
+ start_time = time.time()
+ self.key.parent.start_running(self, start_time)
+ for self.key.current_action in self.key.actions:
+ if self.key.parent.keep_running(self, start_time):
+ self.key.list_actions()
+ self.key.current_action.run(start_time)
+ self.key.list_actions(last_action_finished=True)
+
+ self.key.parent.finished_running(self, start_time)
+
+ def on_enter_loaded_protecting_repeat(self, modifiers):
+ if 'repeat_delay' in self.key.config['properties']:
+ self.key.protecting_repeat_timer = threading.Timer(
+ self.key.config['properties']['repeat_delay'],
+ self.key.repeat_protection_finished)
+ self.key.protecting_repeat_timer.start()
+ else:
+ self.key.repeat_protection_finished()
+
+ # Callbacks
+ def key_loaded_callback(self):
+ self.key.parent.key_loaded_callback()
+
+
+class Key(ButtonBehavior, Widget):
+
key_sym = StringProperty(None)
custom_color = ListProperty([0, 1, 0])
description_title = StringProperty("")
description = ListProperty([])
- state = StringProperty("")
+ machine_state = StringProperty("")
def get_alias_line_cross_color(self):
if not self.is_failed() and (
line_cross_color = AliasProperty(
get_alias_line_cross_color,
set_alias_line_cross_color,
- bind=['state'])
+ bind=['machine_state'])
def get_alias_line_color(self):
if self.is_loaded_running():
pass
line_color = AliasProperty(get_alias_line_color, set_alias_line_color,
- bind=['state'])
+ bind=['machine_state'])
def get_alias_color(self):
if self.is_loaded_inactive():
pass
color = AliasProperty(get_alias_color, set_alias_color,
- bind=['state', 'custom_color'])
+ bind=['machine_state', 'custom_color'])
+
+ def __getattr__(self, name):
+ if hasattr(self.machine, name):
+ return getattr(self.machine, name)
+ else:
+ raise AttributeError
+
+ def machine_state_changed(self, instance, machine_state):
+ self.machine_state = self.machine.state
def __init__(self, **kwargs):
self.actions = []
self.current_action = None
+ self.machine = KeyMachine(self)
+ self.machine.bind(state=self.machine_state_changed)
- Machine(model=self, states=self.STATES,
- transitions=self.TRANSITIONS, initial='initial',
- ignore_invalid_triggers=True, queued=True)
super(Key, self).__init__(**kwargs)
# Kivy events
def on_press(self):
self.list_actions()
- # Machine states / events
- def is_loaded_or_failed(self):
- return self.is_loaded(allow_substates=True) or self.is_failed()
-
- def is_loaded_inactive(self):
- return self.is_loaded_no_config() or self.is_loaded_no_actions()
-
- def on_enter_configuring(self):
- if self.key_sym in self.parent.key_config:
- self.config = self.parent.key_config[self.key_sym]
-
- self.actions = []
- for key_action in self.config['actions']:
- self.add_action(key_action[0], **key_action[1])
-
- if 'description' in self.config['properties']:
- self.set_description(self.config['properties']['description'])
- else:
- self.unset_description()
- if 'color' in self.config['properties']:
- self.set_color(self.config['properties']['color'])
- else:
- self.unset_color()
- self.success()
- else:
- self.no_config()
-
- def on_enter_loading(self):
- if len(self.actions) > 0:
- for action in self.actions:
- action.load()
- else:
- self.no_actions()
-
- def run_actions(self, modifiers):
- self.parent.parent.ids['KeyList'].append(self.key_sym)
- debug_print("running actions for {}".format(self.key_sym))
- start_time = time.time()
- self.parent.start_running(self, start_time)
- for self.current_action in self.actions:
- if self.parent.keep_running(self, start_time):
- self.list_actions()
- self.current_action.run(start_time)
- self.list_actions(last_action_finished=True)
-
- self.parent.finished_running(self, start_time)
-
- def on_enter_loaded_protecting_repeat(self, modifiers):
- if 'repeat_delay' in self.config['properties']:
- self.protecting_repeat_timer = threading.Timer(
- self.config['properties']['repeat_delay'],
- self.repeat_protection_finished)
- self.protecting_repeat_timer.start()
- else:
- self.repeat_protection_finished()
-
# This one cannot be in the Machine state since it would be queued to run
# *after* the loop is ended...
def interrupt(self):
self.current_action.interrupt()
# Callbacks
- def key_loaded_callback(self):
- self.parent.key_loaded_callback()
-
def callback_action_ready(self, action, success):
if not success:
self.fail()