diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2016-09-22 21:47:25 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2016-09-22 21:47:25 +0200 |
commit | d028768179d4fd1555831e26daaa9aae9ac94e85 (patch) | |
tree | c7dc2e8b589c87d50961b60ddfa17b739ef4e9fb /music_sampler/key.py | |
parent | d4217fda2ff3991eb1ee9a9bec6acff751798507 (diff) | |
parent | f9aeecf1a00e0e632546db00cb0cfa31b078dbe9 (diff) | |
download | MusicSampler-d028768179d4fd1555831e26daaa9aae9ac94e85.tar.gz MusicSampler-d028768179d4fd1555831e26daaa9aae9ac94e85.tar.zst MusicSampler-d028768179d4fd1555831e26daaa9aae9ac94e85.zip |
Merge branch 'load_action'1.3.0
Diffstat (limited to 'music_sampler/key.py')
-rw-r--r-- | music_sampler/key.py | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/music_sampler/key.py b/music_sampler/key.py index ce2f45b..e05bb16 100644 --- a/music_sampler/key.py +++ b/music_sampler/key.py | |||
@@ -9,7 +9,11 @@ import time | |||
9 | import threading | 9 | import threading |
10 | from transitions.extensions import HierarchicalMachine as Machine | 10 | from transitions.extensions import HierarchicalMachine as Machine |
11 | 11 | ||
12 | class KeyMachine(Widget): | 12 | # All drawing operations should happen in the main thread |
13 | # https://github.com/kivy/kivy/wiki/Working-with-Python-threads-inside-a-Kivy-application | ||
14 | from kivy.clock import mainthread | ||
15 | |||
16 | class KeyMachine(): | ||
13 | STATES = [ | 17 | STATES = [ |
14 | 'initial', | 18 | 'initial', |
15 | 'configuring', | 19 | 'configuring', |
@@ -97,11 +101,15 @@ class KeyMachine(Widget): | |||
97 | { | 101 | { |
98 | 'trigger': 'repeat_protection_finished', | 102 | 'trigger': 'repeat_protection_finished', |
99 | 'source': 'loaded_protecting_repeat', | 103 | 'source': 'loaded_protecting_repeat', |
100 | 'dest': 'loaded' | 104 | 'dest': 'loaded', |
105 | 'after': 'callback_action_state_changed' | ||
101 | }, | 106 | }, |
102 | ] | 107 | ] |
103 | 108 | ||
104 | state = StringProperty("") | 109 | def __setattr__(self, name, value): |
110 | if hasattr(self, 'initialized') and name == 'state': | ||
111 | self.key.update_state(value) | ||
112 | super().__setattr__(name, value) | ||
105 | 113 | ||
106 | def __init__(self, key, **kwargs): | 114 | def __init__(self, key, **kwargs): |
107 | self.key = key | 115 | self.key = key |
@@ -109,7 +117,8 @@ class KeyMachine(Widget): | |||
109 | Machine(model=self, states=self.STATES, | 117 | Machine(model=self, states=self.STATES, |
110 | transitions=self.TRANSITIONS, initial='initial', | 118 | transitions=self.TRANSITIONS, initial='initial', |
111 | ignore_invalid_triggers=True, queued=True) | 119 | ignore_invalid_triggers=True, queued=True) |
112 | super(KeyMachine, self).__init__(**kwargs) | 120 | |
121 | self.initialized = True | ||
113 | 122 | ||
114 | # Machine states / events | 123 | # Machine states / events |
115 | def is_loaded_or_failed(self): | 124 | def is_loaded_or_failed(self): |
@@ -118,22 +127,22 @@ class KeyMachine(Widget): | |||
118 | def is_loaded_inactive(self): | 127 | def is_loaded_inactive(self): |
119 | return self.is_loaded_no_config() or self.is_loaded_no_actions() | 128 | return self.is_loaded_no_config() or self.is_loaded_no_actions() |
120 | 129 | ||
130 | @mainthread | ||
121 | def on_enter_configuring(self): | 131 | def on_enter_configuring(self): |
132 | self.destroy_actions() | ||
133 | self.key.unset_description() | ||
134 | self.key.unset_color() | ||
135 | |||
122 | if self.key.key_sym in self.key.parent.key_config: | 136 | if self.key.key_sym in self.key.parent.key_config: |
123 | self.key.config = self.key.parent.key_config[self.key.key_sym] | 137 | self.key.config = self.key.parent.key_config[self.key.key_sym] |
124 | 138 | ||
125 | self.key.actions = [] | ||
126 | for key_action in self.key.config['actions']: | 139 | for key_action in self.key.config['actions']: |
127 | self.key.add_action(key_action[0], **key_action[1]) | 140 | self.key.add_action(key_action[0], **key_action[1]) |
128 | 141 | ||
129 | if 'description' in self.key.config['properties']: | 142 | if 'description' in self.key.config['properties']: |
130 | self.key.set_description(self.key.config['properties']['description']) | 143 | self.key.set_description(self.key.config['properties']['description']) |
131 | else: | ||
132 | self.key.unset_description() | ||
133 | if 'color' in self.key.config['properties']: | 144 | if 'color' in self.key.config['properties']: |
134 | self.key.set_color(self.key.config['properties']['color']) | 145 | self.key.set_color(self.key.config['properties']['color']) |
135 | else: | ||
136 | self.key.unset_color() | ||
137 | self.success() | 146 | self.success() |
138 | else: | 147 | else: |
139 | self.no_config() | 148 | self.no_config() |
@@ -145,6 +154,11 @@ class KeyMachine(Widget): | |||
145 | else: | 154 | else: |
146 | self.no_actions() | 155 | self.no_actions() |
147 | 156 | ||
157 | def destroy_actions(self): | ||
158 | for action in self.key.actions: | ||
159 | action.destroy() | ||
160 | self.key.actions = [] | ||
161 | |||
148 | def run_actions(self, modifiers): | 162 | def run_actions(self, modifiers): |
149 | self.key.parent.parent.ids['KeyList'].append(self.key.key_sym) | 163 | self.key.parent.parent.ids['KeyList'].append(self.key.key_sym) |
150 | debug_print("running actions for {}".format(self.key.key_sym)) | 164 | debug_print("running actions for {}".format(self.key.key_sym)) |
@@ -168,9 +182,21 @@ class KeyMachine(Widget): | |||
168 | self.key.repeat_protection_finished() | 182 | self.key.repeat_protection_finished() |
169 | 183 | ||
170 | # Callbacks | 184 | # Callbacks |
185 | @mainthread | ||
171 | def key_loaded_callback(self): | 186 | def key_loaded_callback(self): |
172 | self.key.parent.key_loaded_callback() | 187 | self.key.parent.key_loaded_callback() |
173 | 188 | ||
189 | def callback_action_state_changed(self): | ||
190 | if self.state not in ['failed', 'loading', 'loaded']: | ||
191 | return | ||
192 | |||
193 | if any(action.is_failed() for action in self.key.actions): | ||
194 | self.to_failed() | ||
195 | elif any(action.is_loading() for action in self.key.actions): | ||
196 | self.to_loading() | ||
197 | else: | ||
198 | self.to_loaded() | ||
199 | self.key_loaded_callback() | ||
174 | 200 | ||
175 | class Key(ButtonBehavior, Widget): | 201 | class Key(ButtonBehavior, Widget): |
176 | 202 | ||
@@ -234,18 +260,18 @@ class Key(ButtonBehavior, Widget): | |||
234 | else: | 260 | else: |
235 | raise AttributeError | 261 | raise AttributeError |
236 | 262 | ||
237 | def machine_state_changed(self, instance, machine_state): | ||
238 | self.machine_state = self.machine.state | ||
239 | |||
240 | def __init__(self, **kwargs): | 263 | def __init__(self, **kwargs): |
241 | self.actions = [] | 264 | self.actions = [] |
242 | self.current_action = None | 265 | self.current_action = None |
243 | self.machine = KeyMachine(self) | 266 | self.machine = KeyMachine(self) |
244 | self.machine.bind(state=self.machine_state_changed) | ||
245 | 267 | ||
246 | super(Key, self).__init__(**kwargs) | 268 | super(Key, self).__init__(**kwargs) |
247 | 269 | ||
248 | # Kivy events | 270 | # Kivy events |
271 | @mainthread | ||
272 | def update_state(self, value): | ||
273 | self.machine_state = value | ||
274 | |||
249 | def on_key_sym(self, key, key_sym): | 275 | def on_key_sym(self, key, key_sym): |
250 | if key_sym != "": | 276 | if key_sym != "": |
251 | self.configure() | 277 | self.configure() |
@@ -258,13 +284,6 @@ class Key(ButtonBehavior, Widget): | |||
258 | def interrupt(self): | 284 | def interrupt(self): |
259 | self.current_action.interrupt() | 285 | self.current_action.interrupt() |
260 | 286 | ||
261 | # Callbacks | ||
262 | def callback_action_ready(self, action, success): | ||
263 | if not success: | ||
264 | self.fail() | ||
265 | elif all(action.is_loaded_or_failed() for action in self.actions): | ||
266 | self.success() | ||
267 | |||
268 | # Setters | 287 | # Setters |
269 | def set_description(self, description): | 288 | def set_description(self, description): |
270 | if description[0] is not None: | 289 | if description[0] is not None: |