From 0deb82a57ae3abefd44509dc88c546f6e5a94d1b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Thu, 14 Jul 2016 15:39:54 +0200 Subject: [PATCH] Make 'wait' action interruptible --- helpers/action.py | 38 +++++++++++++++++++++++++++++--------- helpers/key.py | 7 +++++-- helpers/mapping.py | 3 +++ helpers/music_file.py | 9 ++++++--- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/helpers/action.py b/helpers/action.py index 69ae96f..9145629 100644 --- a/helpers/action.py +++ b/helpers/action.py @@ -1,4 +1,4 @@ -import pygame +import threading import time class Action: @@ -21,6 +21,7 @@ class Action: self.key = key self.arguments = kwargs + self.sleep_event = None def ready(self): if 'music' in self.arguments: @@ -35,7 +36,13 @@ class Action: def description(self): return getattr(self, self.action + "_print")(**self.arguments) + def interrupt(self): + if getattr(self, self.action + "_interrupt", None): + return getattr(self, self.action + "_interrupt")(**self.arguments) + + # Actions def command(self, command = "", **kwargs): + # FIXME: todo pass def music_list(self, music): @@ -81,14 +88,15 @@ class Action: pass def wait(self, duration = 0, music = None, **kwargs): - # FIXME: Make it stoppable - # http://stackoverflow.com/questions/29082268/python-time-sleep-vs-event-wait - if music is None: - time.sleep(duration) - else: - # TODO + self.sleep_event = threading.Event() + + if music is not None: music.wait_end() + threading.Timer(duration, self.sleep_event.set).start() + self.sleep_event.wait() + + # Action messages def command_print(self, command = "", **kwargs): return "running command {}".format(command) @@ -146,7 +154,19 @@ class Action: else: return "setting volume to {}%".format(value) - def wait_print(self, duration, **kwargs): - return "waiting {}s".format(duration) + def wait_print(self, duration = 0, music = None, **kwargs): + if music is None: + return "waiting {}s".format(duration) + elif duration == 0: + return "waiting the end of « {} »".format(music.name) + else: + return "waiting the end of « {} » + {}s".format(music.name, duration) + # Interruptions + def wait_interrupt(self, duration = 0, music = None, **kwargs): + if self.sleep_event is not None: + self.sleep_event.set() + if music is not None: + music.wait_event.set() + diff --git a/helpers/key.py b/helpers/key.py index ca73b87..5eaf481 100644 --- a/helpers/key.py +++ b/helpers/key.py @@ -79,6 +79,9 @@ class Key(ButtonBehavior, Widget): def add_action(self, action_name, **arguments): self.actions.append(Action(action_name, self, **arguments)) + def interrupt_action(self): + self.current_action.interrupt() + def do_actions(self): if not self.enabled: return None @@ -88,10 +91,10 @@ class Key(ButtonBehavior, Widget): start_time = time.time() self.parent.start_running(self, start_time) action_number = 0 - for action in self.actions: + for self.current_action in self.actions: if self.parent.keep_running(self, start_time): self.list_actions(action_number = action_number + 0.5) - action.run() + self.current_action.run() action_number += 1 self.list_actions(action_number = action_number) diff --git a/helpers/mapping.py b/helpers/mapping.py index 95c9d67..ea9d075 100644 --- a/helpers/mapping.py +++ b/helpers/mapping.py @@ -65,7 +65,10 @@ class Mapping(RelativeLayout): return False def stop_all_running(self): + running = self.running self.running = [] + for (key, start_time) in running: + key.interrupt_action() def start_running(self, key, start_time): self.running.append((key, start_time)) diff --git a/helpers/music_file.py b/helpers/music_file.py index b40de1a..e6a340d 100644 --- a/helpers/music_file.py +++ b/helpers/music_file.py @@ -40,8 +40,8 @@ class MusicFile(Machine): self.audio_segment = None self.gain = gain self.music_lock = Lock("music__" + filename) + self.wait_event = threading.Event() - self.flag_paused = False threading.Thread(name = "MSMusicLoad", target = self.load).start() def on_enter_loading(self): @@ -109,6 +109,9 @@ class MusicFile(Machine): if self.is_loaded_stopping(): self.stopped() + def on_enter_loaded_stopped(self): + self.wait_event.set() + def play_callback(self, out_data, frame_count, time_info, status_flags): with self.music_lock: audio_segment = self.current_audio_segment.get_sample_slice_data( @@ -147,8 +150,8 @@ class MusicFile(Machine): return 20 * math.log10(max(volume, 0.0001) / 100) def wait_end(self): - # FIXME: todo - pass + self.wait_event.clear() + self.wait_event.wait() # Add some more functions to AudioSegments def get_sample_slice_data(self, start_sample=0, end_sample=float('inf')): -- 2.41.0