]>
Commit | Line | Data |
---|---|---|
b7ca3fc2 | 1 | from transitions.extensions import HierarchicalMachine as Machine |
6ebe6247 | 2 | from .helpers import debug_print, error_print |
c4f4f2a1 | 3 | from . import actions |
a24c34bc | 4 | |
be27763f | 5 | class Action: |
b7ca3fc2 IB |
6 | STATES = [ |
7 | 'initial', | |
8 | 'loading', | |
9 | 'failed', | |
10 | { | |
11 | 'name': 'loaded', | |
93a3e51e IB |
12 | 'children': ['stopped', 'running'] |
13 | }, | |
14 | 'destroyed' | |
b7ca3fc2 IB |
15 | ] |
16 | ||
17 | TRANSITIONS = [ | |
18 | { | |
19 | 'trigger': 'load', | |
20 | 'source': 'initial', | |
21 | 'dest': 'loading' | |
22 | }, | |
23 | { | |
24 | 'trigger': 'fail', | |
93a3e51e | 25 | 'source': ['loading', 'loaded'], |
e55b29bb | 26 | 'dest': 'failed', |
b7ca3fc2 IB |
27 | }, |
28 | { | |
29 | 'trigger': 'success', | |
30 | 'source': 'loading', | |
93a3e51e | 31 | 'dest': 'loaded_stopped', |
b7ca3fc2 IB |
32 | }, |
33 | { | |
93a3e51e | 34 | 'trigger': 'reload', |
b7ca3fc2 | 35 | 'source': 'loaded', |
93a3e51e IB |
36 | 'dest': 'loading', |
37 | }, | |
38 | { | |
39 | 'trigger': 'run', | |
40 | 'source': 'loaded_stopped', | |
b7ca3fc2 | 41 | 'dest': 'loaded_running', |
e55b29bb | 42 | 'after': 'finish_action', |
b7ca3fc2 IB |
43 | }, |
44 | { | |
45 | 'trigger': 'finish_action', | |
46 | 'source': 'loaded_running', | |
93a3e51e IB |
47 | 'dest': 'loaded_stopped' |
48 | }, | |
49 | { | |
50 | 'trigger': 'destroy', | |
51 | 'source': '*', | |
52 | 'dest': 'destroyed' | |
b7ca3fc2 IB |
53 | } |
54 | ] | |
55 | ||
be27763f | 56 | def __init__(self, action, key, **kwargs): |
b7ca3fc2 IB |
57 | Machine(model=self, states=self.STATES, |
58 | transitions=self.TRANSITIONS, initial='initial', | |
93a3e51e IB |
59 | ignore_invalid_triggers=True, queued=True, |
60 | after_state_change=self.notify_state_change) | |
be27763f | 61 | |
b7ca3fc2 | 62 | self.action = action |
be27763f | 63 | self.key = key |
1b4b78f5 | 64 | self.mapping = key.parent |
be27763f | 65 | self.arguments = kwargs |
0deb82a5 | 66 | self.sleep_event = None |
b7ca3fc2 | 67 | self.waiting_music = None |
be27763f | 68 | |
e55b29bb IB |
69 | def is_loaded_or_failed(self): |
70 | return self.is_loaded(allow_substates=True) or self.is_failed() | |
b7ca3fc2 | 71 | |
93a3e51e IB |
72 | def callback_music_state(self, new_state): |
73 | # If a music gets unloaded while the action is loaded_running and | |
74 | # depending on the music, it won't be able to do the finish_action. | |
75 | # Can that happen? | |
76 | # a: play 'mp3'; | |
77 | # z: wait 'mp3'; | |
78 | # e: pause 'mp3'; | |
79 | # r: stop 'mp3'; unload_music 'mp3' | |
80 | if new_state == 'failed': | |
b7ca3fc2 | 81 | self.fail() |
93a3e51e IB |
82 | elif self.is_loaded(allow_substates=True) and\ |
83 | new_state in ['initial', 'loading']: | |
84 | self.reload(reloading=True) | |
85 | elif self.is_loading() and new_state.startswith('loaded_'): | |
86 | self.success() | |
b7ca3fc2 IB |
87 | |
88 | # Machine states / events | |
93a3e51e IB |
89 | def on_enter_loading(self, reloading=False): |
90 | if reloading: | |
91 | return | |
c4f4f2a1 | 92 | if hasattr(actions, self.action): |
93a3e51e IB |
93 | if 'music' in self.arguments and\ |
94 | self.action not in ['unload_music', 'load_music']: | |
95 | self.arguments['music'].subscribe_state_change( | |
96 | self.callback_music_state) | |
b7ca3fc2 IB |
97 | else: |
98 | self.success() | |
be27763f | 99 | else: |
b7ca3fc2 IB |
100 | error_print("Unknown action {}".format(self.action)) |
101 | self.fail() | |
102 | ||
62a8b07a | 103 | def on_enter_loaded_running(self, key_start_time): |
a24c34bc | 104 | debug_print(self.description()) |
c4f4f2a1 | 105 | if hasattr(actions, self.action): |
62a8b07a IB |
106 | getattr(actions, self.action).run(self, |
107 | key_start_time=key_start_time, **self.arguments) | |
be27763f | 108 | |
93a3e51e IB |
109 | def on_enter_destroyed(self): |
110 | if 'music' in self.arguments: | |
111 | self.arguments['music'].unsubscribe_state_change( | |
112 | self.callback_music_state) | |
113 | ||
114 | def notify_state_change(self, *args, **kwargs): | |
115 | self.key.callback_action_state_changed() | |
e55b29bb IB |
116 | |
117 | # This one cannot be in the Machine state since it would be queued to run | |
118 | # *after* the wait is ended... | |
119 | def interrupt(self): | |
c4f4f2a1 IB |
120 | if getattr(actions, self.action, None) and\ |
121 | hasattr(getattr(actions, self.action), 'interrupt'): | |
122 | return getattr(getattr(actions, self.action), 'interrupt')( | |
123 | self, **self.arguments) | |
0deb82a5 | 124 | |
d4217fda IB |
125 | def pause(self): |
126 | if getattr(actions, self.action, None) and\ | |
127 | hasattr(getattr(actions, self.action), 'pause'): | |
128 | return getattr(getattr(actions, self.action), 'pause')( | |
129 | self, **self.arguments) | |
130 | ||
131 | def unpause(self): | |
132 | if getattr(actions, self.action, None) and\ | |
133 | hasattr(getattr(actions, self.action), 'unpause'): | |
134 | return getattr(getattr(actions, self.action), 'unpause')( | |
135 | self, **self.arguments) | |
136 | ||
137 | def reset(self): | |
138 | if getattr(actions, self.action, None) and\ | |
139 | hasattr(getattr(actions, self.action), 'reset'): | |
140 | return getattr(getattr(actions, self.action), 'reset')( | |
141 | self, **self.arguments) | |
142 | ||
b7ca3fc2 | 143 | # Helpers |
29597680 | 144 | def music_list(self, music): |
be27763f | 145 | if music is not None: |
29597680 | 146 | return [music] |
be27763f | 147 | else: |
1b4b78f5 | 148 | return self.mapping.open_files.values() |
29597680 | 149 | |
b7ca3fc2 | 150 | def description(self): |
c4f4f2a1 IB |
151 | if hasattr(actions, self.action): |
152 | return getattr(actions, self.action)\ | |
153 | .description(self, **self.arguments) | |
b7ca3fc2 | 154 | else: |
6a327173 | 155 | return _("unknown action {}").format(self.action) |