From ba21932596c3b6d1a2ce1e1a22b6417e1c509865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Thu, 11 Aug 2016 18:22:19 +0200 Subject: Avoid name clash for "state" There is a clash of variable between ButtonBehavior and HierarchicalMachine, we create a new class KeyMachine to avoid that. This should fix issue https://git.immae.eu/mantisbt/view.php?id=15 --- music_sampler/key.py | 156 +++++++++++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 67 deletions(-) diff --git a/music_sampler/key.py b/music_sampler/key.py index bdae5bd..534a3db 100644 --- a/music_sampler/key.py +++ b/music_sampler/key.py @@ -9,7 +9,7 @@ import time import threading from transitions.extensions import HierarchicalMachine as Machine -class Key(ButtonBehavior, Widget): +class KeyMachine(Widget): STATES = [ 'initial', 'configuring', @@ -101,11 +101,84 @@ class Key(ButtonBehavior, Widget): }, ] + 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 ( @@ -122,7 +195,7 @@ class Key(ButtonBehavior, Widget): 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(): @@ -134,7 +207,7 @@ class Key(ButtonBehavior, Widget): 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(): @@ -153,15 +226,23 @@ class Key(ButtonBehavior, Widget): 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 @@ -172,71 +253,12 @@ class Key(ButtonBehavior, Widget): 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() -- cgit v1.2.3