]> git.immae.eu Git - perso/Immae/Projets/Python/MusicSampler.git/blob - helpers/__init__.py
Allow to find files in pyinstaller
[perso/Immae/Projets/Python/MusicSampler.git] / helpers / __init__.py
1 # -*- coding: utf-8 -*-
2 from pygame import *
3 import sys
4
5 class Action:
6 action_types = [
7 'command',
8 'pause',
9 'play',
10 'stop',
11 'volume',
12 'wait',
13 ]
14
15 def __init__(self, action, **kwargs):
16 if action in self.action_types:
17 self.action = action
18 else:
19 raise Exception("Unknown action {}".format(action))
20
21 self.arguments = kwargs
22
23 def run(self, callback):
24 getattr(self, self.action)(callback, **self.arguments)
25
26 def command(self, callback, command = "", **kwargs):
27 pass
28
29 def pause(self, callback, music = None, **kwargs):
30 pass
31
32 def play(self, callback,
33 music = None,
34 fade_in = 0,
35 restart_if_running = False,
36 volume = 100,
37 **kwargs):
38 pass
39
40 def stop(self, callback, music = None, fade_out = 0, **kwargs):
41 print('stopping')
42 return callback()
43
44 def volume(self, callback, music = None, value = 100, **kwargs):
45 pass
46
47 def wait(self, callback, time = 0, **kwargs):
48 pass
49
50 class Key:
51 row_positions = {
52 'first': 5,
53 'second': 55,
54 'third': 105,
55 'fourth': 155,
56 'fifth': 205,
57 'sixth': 255,
58 }
59
60 default_outer_color = (120, 120, 120)
61 lighter_outer_color = (200, 200, 200)
62 default_inner_color = (255, 255, 255)
63 mapped_inner_color = ( 0, 255, 0)
64
65 def __init__(self, key_name, key_sym, top, left, width = 48, height = 48, disabled = False):
66 self.key_name = key_name
67 self.key_sym = key_sym
68
69 if isinstance(top, str):
70 self.top = self.row_positions[top]
71 else:
72 self.top = top
73
74 self.left = left
75 self.width = width
76 self.height = height
77
78 self.bottom = self.top + self.height
79 self.right = self.left + self.width
80
81 self.rect = (self.left, self.top, self.right, self.bottom)
82 self.position = (self.left, self.top)
83
84 if disabled:
85 self.outer_color = self.lighter_outer_color
86 self.linewidth = 1
87 else:
88 self.outer_color = self.default_outer_color
89 self.linewidth = 3
90
91 self.inner_color = self.default_inner_color
92 self.actions = []
93
94 def square(self):
95 if self.has_action():
96 self.inner_color = self.mapped_inner_color
97
98 return RoundedRect((0, 0, self.width, self.height),
99 self.outer_color, self.inner_color, self.linewidth)
100
101 def collidepoint(self, position):
102 return self.surface.get_rect().collidepoint(
103 position[0] - self.position[0],
104 position[1] - self.position[1]
105 )
106
107 def draw(self, background_surface):
108 self.surface = self.square().surface()
109
110 if getattr(sys, 'frozen', False):
111 police = font.Font(sys._MEIPASS + "/Ubuntu-Regular.ttf", 14)
112 else:
113 police = font.Font("Ubuntu-Regular.ttf", 14)
114
115 text = police.render(self.key_sym, True, (0,0,0))
116 self.surface.blit(text, (5,5))
117 background_surface.blit(self.surface, self.position)
118
119 def has_action(self):
120 return len(self.actions) > 0
121
122 def add_action(self, action_name, **arguments):
123 self.actions.append(Action(action_name, **arguments))
124
125 def next_action(self):
126 print("running next action")
127
128 def do_actions(self):
129 self.current_action = 0
130 print("running actions for {}".format(self.key_sym))
131 if len(self.actions) > 0:
132 self.actions[0].run(self.next_action)
133
134 def list_actions(self, surface):
135 print("bouh", self.key_sym)
136 surface.fill((255, 0, 0))
137
138 def find_by_key_num(key_num):
139 if key_num in Mapping.KEYS:
140 return Mapping.KEYS[key_num]
141 return None
142
143 def find_by_collidepoint(position):
144 for key in Mapping.KEYS:
145 if Mapping.KEYS[key].collidepoint(position):
146 return Mapping.KEYS[key]
147 return None
148
149 def find_by_unicode(key_sym):
150 for key in Mapping.KEYS:
151 if Mapping.KEYS[key].key_sym == key_sym:
152 return Mapping.KEYS[key]
153 return None
154
155 class Mapping:
156 KEYS = {
157 K_ESCAPE: Key(K_ESCAPE, 'ESC', 'first', 0),
158
159 K_F1: Key(K_F1, 'F1', 'first', 100),
160 K_F2: Key(K_F2, 'F2', 'first', 150),
161 K_F3: Key(K_F3, 'F3', 'first', 200),
162 K_F4: Key(K_F4, 'F4', 'first', 250),
163
164 K_F5: Key(K_F5, 'F5', 'first', 325),
165 K_F6: Key(K_F6, 'F6', 'first', 375),
166 K_F7: Key(K_F7, 'F7', 'first', 425),
167 K_F8: Key(K_F8, 'F8', 'first', 475),
168
169 K_F9: Key(K_F9, 'F9', 'first', 550),
170 K_F10: Key(K_F10, 'F10', 'first', 600),
171 K_F11: Key(K_F11, 'F11', 'first', 650),
172 K_F12: Key(K_F12, 'F12', 'first', 700),
173
174
175 178: Key(178, '²', 'second', 0),
176 K_AMPERSAND: Key(K_AMPERSAND, '&', 'second', 50),
177 233: Key(233, 'é', 'second', 100),
178 K_QUOTEDBL: Key(K_QUOTEDBL, '"', 'second', 150),
179 K_QUOTE: Key(K_QUOTE, "'", 'second', 200),
180 K_LEFTPAREN: Key(K_LEFTPAREN, '(', 'second', 250),
181 K_MINUS: Key(K_MINUS, '-', 'second', 300),
182 232: Key(232, 'è', 'second', 350),
183 K_UNDERSCORE: Key(K_UNDERSCORE, '_', 'second', 400),
184 231: Key(231, 'ç', 'second', 450),
185 224: Key(224, 'à', 'second', 500),
186 K_RIGHTPAREN: Key(K_RIGHTPAREN, ')', 'second', 550),
187 K_EQUALS: Key(K_EQUALS, '=', 'second', 600),
188
189 K_BACKSPACE: Key(K_BACKSPACE, '<-', 'second', 650, width = 98),
190
191
192 K_TAB: Key(K_TAB, 'tab', 'third', 0, width = 73),
193 K_a: Key(K_a, 'a', 'third', 75),
194 K_z: Key(K_z, 'z', 'third', 125),
195 K_e: Key(K_e, 'e', 'third', 175),
196 K_r: Key(K_r, 'r', 'third', 225),
197 K_t: Key(K_t, 't', 'third', 275),
198 K_y: Key(K_y, 'y', 'third', 325),
199 K_u: Key(K_u, 'u', 'third', 375),
200 K_i: Key(K_i, 'i', 'third', 425),
201 K_o: Key(K_o, 'o', 'third', 475),
202 K_p: Key(K_p, 'p', 'third', 525),
203 K_CARET: Key(K_CARET, '^', 'third', 575),
204 K_DOLLAR: Key(K_DOLLAR, '$', 'third', 625),
205
206 K_RETURN: Key(K_RETURN, 'Enter', 'third', 692, width = 56, height = 98),
207
208 K_CAPSLOCK: Key(K_CAPSLOCK, 'CAPS', 'fourth', 0, width = 88, disabled = True),
209
210 K_q: Key(K_q, 'q', 'fourth', 90),
211 K_s: Key(K_s, 's', 'fourth', 140),
212 K_d: Key(K_d, 'd', 'fourth', 190),
213 K_f: Key(K_f, 'f', 'fourth', 240),
214 K_g: Key(K_g, 'g', 'fourth', 290),
215 K_h: Key(K_h, 'h', 'fourth', 340),
216 K_j: Key(K_j, 'j', 'fourth', 390),
217 K_k: Key(K_k, 'k', 'fourth', 440),
218 K_l: Key(K_l, 'l', 'fourth', 490),
219 K_m: Key(K_m, 'm', 'fourth', 540),
220 249: Key(249, 'ù', 'fourth', 590),
221 K_ASTERISK: Key(K_ASTERISK, '*', 'fourth', 640),
222
223
224 K_LSHIFT: Key(K_LSHIFT, 'LShift', 'fifth', 0, width = 63, disabled = True),
225
226 K_LESS: Key(K_LESS, '<', 'fifth', 65),
227 K_w: Key(K_w, 'w', 'fifth', 115),
228 K_x: Key(K_x, 'x', 'fifth', 165),
229 K_c: Key(K_c, 'c', 'fifth', 215),
230 K_v: Key(K_v, 'v', 'fifth', 265),
231 K_b: Key(K_b, 'b', 'fifth', 315),
232 K_n: Key(K_n, 'n', 'fifth', 365),
233 K_COMMA: Key(K_COMMA, ',', 'fifth', 415),
234 K_SEMICOLON: Key(K_SEMICOLON, ';', 'fifth', 465),
235 K_COLON: Key(K_COLON, ':', 'fifth', 515),
236 K_EXCLAIM: Key(K_EXCLAIM, '!', 'fifth', 565),
237
238 K_RSHIFT: Key(K_RSHIFT, 'RShift', 'fifth', 615, width = 133, disabled = True),
239
240 K_LCTRL: Key(K_LCTRL, 'LCtrl', 'sixth', 0, width = 63, disabled = True),
241 K_LSUPER: Key(K_LSUPER, 'LSuper', 'sixth', 115, disabled = True),
242 K_LALT: Key(K_LALT, 'LAlt', 'sixth', 165, disabled = True),
243 K_SPACE: Key(K_SPACE, 'Espace', 'sixth', 215, width = 248),
244 K_MODE: Key(K_MODE, 'AltGr', 'sixth', 465, disabled = True),
245 314: Key(314, 'Compose', 'sixth', 515, disabled = True),
246 K_RCTRL: Key(K_RCTRL, 'RCtrl', 'sixth', 565, width = 63, disabled = True),
247
248
249 K_INSERT: Key(K_INSERT, 'ins', 'second', 755),
250 K_HOME: Key(K_HOME, 'home', 'second', 805),
251 K_PAGEUP: Key(K_PAGEUP, 'pg_u', 'second', 855),
252 K_DELETE: Key(K_DELETE, 'del', 'third', 755),
253 K_END: Key(K_END, 'end', 'third', 805),
254 K_PAGEDOWN: Key(K_PAGEDOWN, 'pg_d', 'third', 855),
255
256
257 K_UP: Key(K_UP, 'up', 'fifth', 805),
258 K_DOWN: Key(K_DOWN, 'down', 'sixth', 805),
259 K_LEFT: Key(K_LEFT, 'left', 'sixth', 755),
260 K_RIGHT: Key(K_RIGHT, 'right', 'sixth', 855),
261 }
262
263 class MusicFile:
264 def __init__(self, filename):
265 self.filename = filename
266
267 class RoundedRect:
268 def __init__(self, rect, outer_color, inner_color, linewidth = 2, radius = 0.4):
269 self.rect = Rect(rect)
270 self.outer_color = Color(*outer_color)
271 self.inner_color = Color(*inner_color)
272 self.linewidth = linewidth
273 self.radius = radius
274
275 def surface(self):
276 rectangle = self.filledRoundedRect(self.rect, self.outer_color, self.radius)
277
278 inner_rect = Rect((
279 self.rect.left + 2 * self.linewidth,
280 self.rect.top + 2 * self.linewidth,
281 self.rect.right - 2 * self.linewidth,
282 self.rect.bottom - 2 * self.linewidth
283 ))
284
285 inner_rectangle = self.filledRoundedRect(inner_rect, self.inner_color, self.radius)
286
287 rectangle.blit(inner_rectangle, (self.linewidth, self.linewidth))
288
289 return rectangle
290
291 def filledRoundedRect(self, rect, color, radius=0.4):
292 """
293 filledRoundedRect(rect,color,radius=0.4)
294
295 rect : rectangle
296 color : rgb or rgba
297 radius : 0 <= radius <= 1
298 """
299
300 alpha = color.a
301 color.a = 0
302 pos = rect.topleft
303 rect.topleft = 0,0
304 rectangle = Surface(rect.size,SRCALPHA)
305
306 circle = Surface([min(rect.size)*3]*2,SRCALPHA)
307 draw.ellipse(circle,(0,0,0),circle.get_rect(),0)
308 circle = transform.smoothscale(circle,[int(min(rect.size)*radius)]*2)
309
310 radius = rectangle.blit(circle,(0,0))
311 radius.bottomright = rect.bottomright
312 rectangle.blit(circle,radius)
313 radius.topright = rect.topright
314 rectangle.blit(circle,radius)
315 radius.bottomleft = rect.bottomleft
316 rectangle.blit(circle,radius)
317
318 rectangle.fill((0,0,0),rect.inflate(-radius.w,0))
319 rectangle.fill((0,0,0),rect.inflate(0,-radius.h))
320
321 rectangle.fill(color,special_flags=BLEND_RGBA_MAX)
322 rectangle.fill((255,255,255,alpha),special_flags=BLEND_RGBA_MIN)
323
324 return rectangle
325
326
327 def parse_config():
328 import yaml
329 stream = open("config.yml", "r")
330 config = yaml.load(stream)
331 stream.close()
332
333 aliases = config['aliases']
334 seen_files = {}
335
336 for mapped_key in config['keys']:
337 key = Key.find_by_unicode(mapped_key)
338 if key is None:
339 continue
340
341 for action in config['keys'][mapped_key]:
342 action_name = list(action)[0]
343 action_args = {}
344 if action[action_name] is None:
345 action[action_name] = []
346
347 for argument in action[action_name]:
348 if argument == 'include':
349 included = action[action_name]['include']
350 if isinstance(included, str):
351 action_args.update(aliases[included])
352 else:
353 for included_ in included:
354 action_args.update(aliases[included_])
355 elif argument == 'file':
356 filename = action[action_name]['file']
357 if filename not in seen_files:
358 seen_files[filename] = MusicFile.new(filename)
359
360 action_args['music'] = seen_files[filename]
361
362 else:
363 action_args[argument] = action[action_name][argument]
364
365 key.add_action(action_name, **action_args)