]> git.immae.eu Git - perso/Immae/Projets/Python/MusicSampler.git/blobdiff - music_sampler/key.py
Merge branch 'load_action'
[perso/Immae/Projets/Python/MusicSampler.git] / music_sampler / key.py
index ce2f45bafd8bf9ca9cbdf47c48070eb99615e4cb..e05bb169354a7e6afc395cdb655a27a306f0ac4b 100644 (file)
@@ -9,7 +9,11 @@ import time
 import threading
 from transitions.extensions import HierarchicalMachine as Machine
 
-class KeyMachine(Widget):
+# All drawing operations should happen in the main thread
+# https://github.com/kivy/kivy/wiki/Working-with-Python-threads-inside-a-Kivy-application
+from kivy.clock import mainthread
+
+class KeyMachine():
     STATES = [
         'initial',
         'configuring',
@@ -97,11 +101,15 @@ class KeyMachine(Widget):
         {
             'trigger': 'repeat_protection_finished',
             'source': 'loaded_protecting_repeat',
-            'dest': 'loaded'
+            'dest': 'loaded',
+            'after': 'callback_action_state_changed'
         },
     ]
 
-    state = StringProperty("")
+    def __setattr__(self, name, value):
+        if hasattr(self, 'initialized') and name == 'state':
+            self.key.update_state(value)
+        super().__setattr__(name, value)
 
     def __init__(self, key, **kwargs):
         self.key = key
@@ -109,7 +117,8 @@ class KeyMachine(Widget):
         Machine(model=self, states=self.STATES,
                 transitions=self.TRANSITIONS, initial='initial',
                 ignore_invalid_triggers=True, queued=True)
-        super(KeyMachine, self).__init__(**kwargs)
+
+        self.initialized = True
 
     # Machine states / events
     def is_loaded_or_failed(self):
@@ -118,22 +127,22 @@ class KeyMachine(Widget):
     def is_loaded_inactive(self):
         return self.is_loaded_no_config() or self.is_loaded_no_actions()
 
+    @mainthread
     def on_enter_configuring(self):
+        self.destroy_actions()
+        self.key.unset_description()
+        self.key.unset_color()
+
         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()
@@ -145,6 +154,11 @@ class KeyMachine(Widget):
         else:
             self.no_actions()
 
+    def destroy_actions(self):
+        for action in self.key.actions:
+            action.destroy()
+        self.key.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))
@@ -168,9 +182,21 @@ class KeyMachine(Widget):
             self.key.repeat_protection_finished()
 
     # Callbacks
+    @mainthread
     def key_loaded_callback(self):
         self.key.parent.key_loaded_callback()
 
+    def callback_action_state_changed(self):
+        if self.state not in ['failed', 'loading', 'loaded']:
+            return
+
+        if any(action.is_failed() for action in self.key.actions):
+            self.to_failed()
+        elif any(action.is_loading() for action in self.key.actions):
+            self.to_loading()
+        else:
+            self.to_loaded()
+        self.key_loaded_callback()
 
 class Key(ButtonBehavior, Widget):
 
@@ -234,18 +260,18 @@ class Key(ButtonBehavior, Widget):
         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)
 
         super(Key, self).__init__(**kwargs)
 
     # Kivy events
+    @mainthread
+    def update_state(self, value):
+        self.machine_state = value
+
     def on_key_sym(self, key, key_sym):
         if key_sym != "":
             self.configure()
@@ -258,13 +284,6 @@ class Key(ButtonBehavior, Widget):
     def interrupt(self):
         self.current_action.interrupt()
 
-    # Callbacks
-    def callback_action_ready(self, action, success):
-        if not success:
-            self.fail()
-        elif all(action.is_loaded_or_failed() for action in self.actions):
-            self.success()
-
     # Setters
     def set_description(self, description):
         if description[0] is not None: