aboutsummaryrefslogtreecommitdiff
path: root/helpers
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2016-06-25 23:37:49 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2016-06-25 23:40:51 +0200
commit4b2d79ca27dcbb85465829595ad81cec5fc63983 (patch)
tree683b3a9b19aa01de53b0dccc3ac143d876dcf088 /helpers
parent8612c5f8bb0fc9529bc489a6719654d4474db6d5 (diff)
downloadMusicSampler-4b2d79ca27dcbb85465829595ad81cec5fc63983.tar.gz
MusicSampler-4b2d79ca27dcbb85465829595ad81cec5fc63983.tar.zst
MusicSampler-4b2d79ca27dcbb85465829595ad81cec5fc63983.zip
Migrate to kivy
Diffstat (limited to 'helpers')
-rw-r--r--helpers/__init__.py149
-rw-r--r--helpers/font.py10
-rw-r--r--helpers/key.py202
-rw-r--r--helpers/mapping.py281
-rw-r--r--helpers/rounded_rect.py62
5 files changed, 183 insertions, 521 deletions
diff --git a/helpers/__init__.py b/helpers/__init__.py
index eb948f2..40a96af 100644
--- a/helpers/__init__.py
+++ b/helpers/__init__.py
@@ -1,150 +1 @@
1# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
2from .music_file import *
3from .mapping import *
4from .lock import *
5from .font import *
6import yaml
7
8def parse_config2():
9 stream = open("config.yml", "r")
10 config = yaml.load(stream)
11 stream.close()
12
13 aliases = config['aliases']
14 seen_files = {}
15
16 file_lock = Lock("file")
17
18 channel_id = 0
19
20 key_properties = {}
21
22 for key in config['key_properties']:
23 if key not in key_properties:
24 key_properties[key] = {
25 "actions": [],
26 "properties": config['key_properties'][key],
27 "files": []
28 }
29
30 for mapped_key in config['keys']:
31 if mapped_key not in key_properties:
32 key_properties[mapped_key] = {
33 "actions": [],
34 "properties": {},
35 "files": []
36 }
37 for action in config['keys'][mapped_key]:
38 action_name = list(action)[0]
39 action_args = {}
40 if action[action_name] is None:
41 action[action_name] = []
42
43 if 'include' in action[action_name]:
44 included = action[action_name]['include']
45 del(action[action_name]['include'])
46
47 if isinstance(included, str):
48 action[action_name].update(aliases[included], **action[action_name])
49 else:
50 for included_ in included:
51 action[action_name].update(aliases[included_], **action[action_name])
52
53 for argument in action[action_name]:
54 if argument == 'file':
55 filename = action[action_name]['file']
56 if filename not in seen_files:
57 if filename in config['music_properties']:
58 seen_files[filename] = MusicFile(
59 filename,
60 file_lock,
61 channel_id,
62 **config['music_properties'][filename])
63 else:
64 seen_files[filename] = MusicFile(
65 filename,
66 file_lock,
67 channel_id)
68 channel_id = channel_id + 1
69
70 if filename not in key_properties[mapped_key]['files']:
71 key_properties[mapped_key]['files'].append(seen_files[filename])
72
73 action_args['music'] = seen_files[filename]
74
75 else:
76 action_args[argument] = action[action_name][argument]
77
78 key_properties[mapped_key]['actions'].append([action_name, action_args])
79
80 return (key_properties, channel_id + 1, seen_files)
81
82def parse_config(mapping):
83 stream = open("config.yml", "r")
84 config = yaml.load(stream)
85 stream.close()
86
87 aliases = config['aliases']
88 seen_files = {}
89
90 file_lock = Lock("file")
91
92 channel_id = 0
93
94 for mapped_key in config['keys']:
95 key = mapping.find_by_unicode(mapped_key)
96 if key is None:
97 continue
98
99 for action in config['keys'][mapped_key]:
100 action_name = list(action)[0]
101 action_args = {}
102 if action[action_name] is None:
103 action[action_name] = []
104
105 if 'include' in action[action_name]:
106 included = action[action_name]['include']
107 del(action[action_name]['include'])
108
109 if isinstance(included, str):
110 action[action_name].update(aliases[included], **action[action_name])
111 else:
112 for included_ in included:
113 action[action_name].update(aliases[included_], **action[action_name])
114
115 for argument in action[action_name]:
116 if argument == 'file':
117 filename = action[action_name]['file']
118 if filename not in seen_files:
119 if filename in config['music_properties']:
120 seen_files[filename] = MusicFile(
121 filename,
122 file_lock,
123 channel_id,
124 **config['music_properties'][filename])
125 else:
126 seen_files[filename] = MusicFile(
127 filename,
128 file_lock,
129 channel_id)
130 channel_id = channel_id + 1
131
132 action_args['music'] = seen_files[filename]
133
134 else:
135 action_args[argument] = action[action_name][argument]
136
137 key.add_action(action_name, **action_args)
138
139 for key_property in config['key_properties']:
140 key = mapping.find_by_unicode(key_property)
141 if key is None:
142 continue
143
144 if 'description' in config['key_properties'][key_property]:
145 key.set_description(config['key_properties'][key_property]['description'])
146 if 'color' in config['key_properties'][key_property]:
147 key.set_color(config['key_properties'][key_property]['color'])
148
149 # Return the number of channels reserved
150 return (channel_id + 1, seen_files)
diff --git a/helpers/font.py b/helpers/font.py
deleted file mode 100644
index 83999ef..0000000
--- a/helpers/font.py
+++ /dev/null
@@ -1,10 +0,0 @@
1import os
2import pygame
3import sys
4
5def font(size, font = "Ubuntu-Regular"):
6 if getattr(sys, 'frozen', False):
7 return pygame.font.Font(sys._MEIPASS + "/fonts/" + font + ".ttf", size)
8 else:
9 path = os.path.dirname(os.path.realpath(__file__))
10 return pygame.font.Font(path + "/../fonts/" + font + ".ttf", size)
diff --git a/helpers/key.py b/helpers/key.py
index d923b1d..658c17f 100644
--- a/helpers/key.py
+++ b/helpers/key.py
@@ -1,169 +1,101 @@
1from .rounded_rect import * 1from kivy.uix.widget import Widget
2from kivy.properties import AliasProperty, BooleanProperty, ListProperty, StringProperty
3from kivy.clock import Clock
4from kivy.uix.behaviors import ButtonBehavior
5
2from .action import * 6from .action import *
3from .font import font
4import time 7import time
5import sys 8
6import pygame 9class Key(ButtonBehavior, Widget):
7 10 key_sym = StringProperty(None)
8class Key: 11 custom_color = ListProperty([0, 1, 0, 1])
9 default_outer_color = (120, 120, 120) 12 custom_unready_color = ListProperty([0, 1, 0, 100/255])
10 lighter_outer_color = (200, 200, 200) 13 description_title = StringProperty("")
11 default_inner_color = (255, 255, 255) 14 description = ListProperty([])
12 mapped_inner_color = ( 0, 255, 0) 15 is_key_ready = BooleanProperty(True)
13 mapped_unready_inner_color = ( 0, 255, 0, 100) 16
14 17 def get_color(self):
15 def __init__(self, mapping, draw_lock, key_name, key_sym, top, left, width = 48, height = 48, disabled = False): 18 if not self.has_actions:
16 self.draw_lock = draw_lock 19 return [1, 1, 1, 1]
17 self.mapping = mapping 20 elif self.all_actions_ready:
18 self.key_name = key_name 21 return self.custom_color
19 self.key_sym = key_sym
20
21 self.top = top
22 self.left = left
23 self.width = width
24 self.height = height
25
26 self.bottom = self.top + self.height
27 self.right = self.left + self.width
28
29 self.rect = (self.left, self.top, self.right, self.bottom)
30 self.position = (self.left, self.top)
31 self.disabled = disabled
32
33 if disabled:
34 self.outer_color = self.lighter_outer_color
35 self.linewidth = 1
36 else: 22 else:
37 self.outer_color = self.default_outer_color 23 return self.custom_unready_color
38 self.linewidth = 3 24 def set_color(self):
25 pass
26
27 color = AliasProperty(get_color, set_color, bind=['is_key_ready'])
39 28
40 self.inner_color = self.default_inner_color 29 def __init__(self, **kwargs):
30 super(Key, self).__init__(**kwargs)
41 self.actions = [] 31 self.actions = []
42 self.description = []
43 self.custom_color = self.mapped_inner_color
44 self.custom_unready_color = self.mapped_unready_inner_color
45
46 def square(self, all_actions_ready):
47 if self.has_actions():
48 if all_actions_ready:
49 self.inner_color = self.custom_color
50 else:
51 self.inner_color = self.custom_unready_color
52 32
53 return RoundedRect((0, 0, self.width, self.height), 33 def on_key_sym(self, key, key_sym):
54 self.outer_color, self.inner_color, self.linewidth) 34 if key_sym in self.parent.key_config:
35 self.is_key_ready = False
36
37 self.config = self.parent.key_config[key_sym]
55 38
56 def collidepoint(self, position): 39 self.actions = []
57 return self.surface.get_rect().collidepoint( 40 for key_action in self.config['actions']:
58 position[0] - self.position[0], 41 self.add_action(key_action[0], **key_action[1])
59 position[1] - self.position[1] 42
60 ) 43 if 'description' in self.config['properties']:
44 key.set_description(self.config['properties']['description'])
45 if 'color' in self.config['properties']:
46 key.set_color(self.config['properties']['color'])
47
48 Clock.schedule_interval(self.check_all_active, 1)
49
50 def check_all_active(self, dt):
51 if self.all_actions_ready:
52 self.is_key_ready = True
53 return False
61 54
62 def set_description(self, description): 55 def set_description(self, description):
63 for desc in description: 56 if description[0] is not None:
57 self.description_title = str(description[0])
58 for desc in description[1:]:
64 if desc is None: 59 if desc is None:
65 self.description.append("") 60 self.description.append("")
66 else: 61 else:
67 self.description.append(str(desc)) 62 self.description.append(str(desc).replace(" ", " "))
68 63
69 def set_color(self, color): 64 def set_color(self, color):
70 self.custom_color = tuple(color) 65 color = [x / 255 for x in color]
71 color.append(100) 66 color.append(1)
67 self.custom_color = color
68 color[3] = 100 / 255
72 self.custom_unready_color = tuple(color) 69 self.custom_unready_color = tuple(color)
73 70
74 def draw(self, background_surface): 71 @property
75 self.draw_lock.acquire()
76 all_actions_ready = self.all_actions_ready()
77
78 self.surface = self.square(all_actions_ready).surface()
79
80 police = font(14)
81 text_police = font(10)
82
83 police.set_bold(True)
84 text = police.render(self.key_sym, True, (0,0,0))
85 self.surface.blit(text, (5,5))
86
87 is_first_line = True
88 offset = 11 + text_police.get_linesize() - 4
89 first_line_offset = 18
90 for description in self.description:
91 text = text_police.render(description, True, (0,0,0))
92 if is_first_line:
93 self.surface.blit(text, (first_line_offset, 9))
94 is_first_line = False
95 else:
96 self.surface.blit(text, (3, offset))
97 offset += text_police.get_linesize() - 4
98
99 background_surface.blit(self.surface, self.position)
100 self.draw_lock.release()
101
102 return not all_actions_ready
103
104 def poll_redraw(self, background):
105 while True:
106 time.sleep(1)
107 if self.all_actions_ready():
108 self.draw(background)
109 self.mapping.blit()
110 break
111
112 def has_actions(self): 72 def has_actions(self):
113 return len(self.actions) > 0 73 return len(self.actions) > 0
114 74
75 @property
115 def all_actions_ready(self): 76 def all_actions_ready(self):
116 return all(action.ready() for action in self.actions) 77 return all(action.ready() for action in self.actions)
117 78
118 def add_action(self, action_name, **arguments): 79 def add_action(self, action_name, **arguments):
119 self.actions.append(Action(action_name, self, **arguments)) 80 self.actions.append(Action(action_name, self, **arguments))
120 81
121 def do_actions(self, screen): 82 def do_actions(self):
122 print("running actions for {}".format(self.key_sym)) 83 print("running actions for {}".format(self.key_sym))
123 start_time = time.time() 84 start_time = time.time()
124 self.mapping.start_running(self, start_time) 85 self.parent.start_running(self, start_time)
125 action_number = 0 86 action_number = 0
126 for action in self.actions: 87 for action in self.actions:
127 if self.mapping.keep_running(self, start_time): 88 if self.parent.keep_running(self, start_time):
128 self.list_actions(screen, action_number = action_number + 0.5) 89 self.list_actions(action_number = action_number + 0.5)
129 action.run() 90 action.run()
130 action_number += 1 91 action_number += 1
131 self.list_actions(screen, action_number = action_number) 92 self.list_actions(action_number = action_number)
132
133 self.mapping.finished_running(self, start_time)
134
135 def list_actions(self, screen, action_number = 0):
136 action_descriptions = [action.description() for action in self.actions]
137 #print("actions linked to key {}:".format(self.key_sym))
138 #print("\t" + "\n\t".join(action_descriptions))
139 self.draw_lock.acquire()
140 surface = pygame.Surface((690, 250)).convert()
141 surface.fill((250, 250, 250))
142 police = font(14)
143
144 offset = 0
145 police.set_bold(True)
146 text = police.render("actions linked to key {}:".format(self.key_sym), True, (0,0,0))
147 surface.blit(text, (0, offset))
148 offset += police.get_linesize()
149
150 police.set_bold(False)
151 icon_police = font(14, font = "Symbola")
152 for index, description in enumerate(action_descriptions):
153 if index < int(action_number):
154 icon = icon_police.render("✓", True, (0,0,0))
155 elif index + 0.5 == action_number:
156 icon = icon_police.render("✅", True, (0,0,0))
157 else:
158 icon = icon_police.render(" ", True, (0,0,0))
159
160 text = police.render(description, True, (0,0,0))
161 surface.blit(icon, (0, offset))
162 surface.blit(text, (10, offset))
163 offset += police.get_linesize()
164 93
165 screen.blit(surface, (5, 308)) 94 self.parent.finished_running(self, start_time)
166 pygame.display.flip()
167 self.draw_lock.release()
168 95
96 def list_actions(self, action_number = 0):
97 self.parent.parent.ids['ActionList'].update_list(self, action_number)
169 98
99 def on_press(self):
100 self.list_actions()
101 pass
diff --git a/helpers/mapping.py b/helpers/mapping.py
index 58aaf3d..4a1cd98 100644
--- a/helpers/mapping.py
+++ b/helpers/mapping.py
@@ -1,175 +1,51 @@
1from kivy.uix.relativelayout import RelativeLayout
2from kivy.properties import NumericProperty
3from kivy.core.window import Window
4
1import threading 5import threading
2import pygame 6import pygame
3from .key import * 7import yaml
4 8
5class Mapping: 9from .lock import *
6 WIDTH = 903 10from .music_file import *
7 HEIGHT = 298 11
8 SIZE = WIDTH, HEIGHT 12class Mapping(RelativeLayout):
9 13 expected_keys = NumericProperty(0)
10 ROW_POSITIONS = { 14
11 'first': 0, 15 def __init__(self, **kwargs):
12 'second': 50, 16 self.key_config, self.channel_number, self.open_files = self.parse_config()
13 'third': 100, 17 super(Mapping, self).__init__(**kwargs)
14 'fourth': 150, 18 self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
15 'fifth': 200, 19 self._keyboard.bind(on_key_down=self._on_keyboard_down)
16 'sixth': 250,
17 }
18
19 KEYS = [
20 (pygame.K_ESCAPE, 'ESC', 'first', 0, {}),
21
22 (pygame.K_F1, 'F1', 'first', 100, {}),
23 (pygame.K_F2, 'F2', 'first', 150, {}),
24 (pygame.K_F3, 'F3', 'first', 200, {}),
25 (pygame.K_F4, 'F4', 'first', 250, {}),
26
27 (pygame.K_F5, 'F5', 'first', 325, {}),
28 (pygame.K_F6, 'F6', 'first', 375, {}),
29 (pygame.K_F7, 'F7', 'first', 425, {}),
30 (pygame.K_F8, 'F8', 'first', 475, {}),
31
32 (pygame.K_F9, 'F9', 'first', 550, {}),
33 (pygame.K_F10, 'F10', 'first', 600, {}),
34 (pygame.K_F11, 'F11', 'first', 650, {}),
35 (pygame.K_F12, 'F12', 'first', 700, {}),
36
37
38 (178, '²', 'second', 0, {}),
39 (pygame.K_AMPERSAND, '&', 'second', 50, {}),
40 (233, 'é', 'second', 100, {}),
41 (pygame.K_QUOTEDBL, '"', 'second', 150, {}),
42 (pygame.K_QUOTE, "'", 'second', 200, {}),
43 (pygame.K_LEFTPAREN, '(', 'second', 250, {}),
44 (pygame.K_MINUS, '-', 'second', 300, {}),
45 (232, 'è', 'second', 350, {}),
46 (pygame.K_UNDERSCORE, '_', 'second', 400, {}),
47 (231, 'ç', 'second', 450, {}),
48 (224, 'à', 'second', 500, {}),
49 (pygame.K_RIGHTPAREN, ')', 'second', 550, {}),
50 (pygame.K_EQUALS, '=', 'second', 600, {}),
51
52 (pygame.K_BACKSPACE, '<-', 'second', 650, { 'width': 98 }),
53
54
55 (pygame.K_TAB, 'tab', 'third', 0, { 'width' : 73 }),
56 (pygame.K_a, 'a', 'third', 75, {}),
57 (pygame.K_z, 'z', 'third', 125, {}),
58 (pygame.K_e, 'e', 'third', 175, {}),
59 (pygame.K_r, 'r', 'third', 225, {}),
60 (pygame.K_t, 't', 'third', 275, {}),
61 (pygame.K_y, 'y', 'third', 325, {}),
62 (pygame.K_u, 'u', 'third', 375, {}),
63 (pygame.K_i, 'i', 'third', 425, {}),
64 (pygame.K_o, 'o', 'third', 475, {}),
65 (pygame.K_p, 'p', 'third', 525, {}),
66 (pygame.K_CARET, '^', 'third', 575, {}),
67 (pygame.K_DOLLAR, '$', 'third', 625, {}),
68
69 (pygame.K_RETURN, 'Enter', 'third', 692, { 'width': 56, 'height': 98 }),
70
71 (pygame.K_CAPSLOCK, 'CAPS', 'fourth', 0, { 'width': 88, 'disabled': True }),
72
73 (pygame.K_q, 'q', 'fourth', 90, {}),
74 (pygame.K_s, 's', 'fourth', 140, {}),
75 (pygame.K_d, 'd', 'fourth', 190, {}),
76 (pygame.K_f, 'f', 'fourth', 240, {}),
77 (pygame.K_g, 'g', 'fourth', 290, {}),
78 (pygame.K_h, 'h', 'fourth', 340, {}),
79 (pygame.K_j, 'j', 'fourth', 390, {}),
80 (pygame.K_k, 'k', 'fourth', 440, {}),
81 (pygame.K_l, 'l', 'fourth', 490, {}),
82 (pygame.K_m, 'm', 'fourth', 540, {}),
83 (249, 'ù', 'fourth', 590, {}),
84 (pygame.K_ASTERISK, '*', 'fourth', 640, {}),
85
86
87 (pygame.K_LSHIFT, 'LShift', 'fifth', 0, { 'width': 63, 'disabled': True }),
88
89 (pygame.K_LESS, '<', 'fifth', 65, {}),
90 (pygame.K_w, 'w', 'fifth', 115, {}),
91 (pygame.K_x, 'x', 'fifth', 165, {}),
92 (pygame.K_c, 'c', 'fifth', 215, {}),
93 (pygame.K_v, 'v', 'fifth', 265, {}),
94 (pygame.K_b, 'b', 'fifth', 315, {}),
95 (pygame.K_n, 'n', 'fifth', 365, {}),
96 (pygame.K_COMMA, ',', 'fifth', 415, {}),
97 (pygame.K_SEMICOLON, ';', 'fifth', 465, {}),
98 (pygame.K_COLON, ':', 'fifth', 515, {}),
99 (pygame.K_EXCLAIM, '!', 'fifth', 565, {}),
100
101 (pygame.K_RSHIFT, 'RShift', 'fifth', 615, { 'width': 133, 'disabled': True }),
102
103 (pygame.K_LCTRL, 'LCtrl', 'sixth', 0, { 'width': 63, 'disabled': True }),
104 (pygame.K_LSUPER, 'LSuper', 'sixth', 115, { 'disabled': True }),
105 (pygame.K_LALT, 'LAlt', 'sixth', 165, { 'disabled': True }),
106 (pygame.K_SPACE, 'Espace', 'sixth', 215, { 'width': 248 }),
107 (pygame.K_MODE, 'AltGr', 'sixth', 465, { 'disabled': True }),
108 (314, 'Compose', 'sixth', 515, { 'disabled': True }),
109 (pygame.K_RCTRL, 'RCtrl', 'sixth', 565, { 'width': 63, 'disabled': True }),
110
111
112 (pygame.K_INSERT, 'ins', 'second', 755, {}),
113 (pygame.K_HOME, 'home', 'second', 805, {}),
114 (pygame.K_PAGEUP, 'pg_u', 'second', 855, {}),
115 (pygame.K_DELETE, 'del', 'third', 755, {}),
116 (pygame.K_END, 'end', 'third', 805, {}),
117 (pygame.K_PAGEDOWN, 'pg_d', 'third', 855, {}),
118
119
120 (pygame.K_UP, 'up', 'fifth', 805, {}),
121 (pygame.K_DOWN, 'down', 'sixth', 805, {}),
122 (pygame.K_LEFT, 'left', 'sixth', 755, {}),
123 (pygame.K_RIGHT, 'right', 'sixth', 855, {}),
124 ]
125
126 def __init__(self, screen, draw_lock):
127 self.draw_lock = draw_lock
128 self.screen = screen
129 self.background = pygame.Surface(self.SIZE).convert()
130 self.background.fill((250, 250, 250))
131 self.keys = {}
132 self.running = [] 20 self.running = []
133 for key in self.KEYS:
134 if key[2] in self.ROW_POSITIONS:
135 position = self.ROW_POSITIONS[key[2]]
136 else:
137 position = key[2]
138 self.keys[key[0]] = Key(self,
139 self.draw_lock,
140 key[0], key[1], position, key[3],
141 **key[4])
142
143 def draw(self):
144 for key_name in self.keys:
145 key = self.keys[key_name]
146 should_redraw_key = key.draw(self.background)
147
148 if should_redraw_key:
149 threading.Thread(name = "MSPollRedraw", target = key.poll_redraw, args = [self.background]).start()
150 self.blit()
151
152 def blit(self):
153 self.draw_lock.acquire()
154 self.screen.blit(self.background, (5, 5))
155 pygame.display.flip()
156 self.draw_lock.release()
157
158 def find_by_key_num(self, key_num):
159 if key_num in self.keys:
160 return self.keys[key_num]
161 return None
162 21
163 def find_by_collidepoint(self, position): 22
164 for key in self.keys: 23 pygame.mixer.init(frequency = 44100)
165 if self.keys[key].collidepoint(position): 24 pygame.mixer.set_num_channels(self.channel_number)
166 return self.keys[key] 25
26 def _keyboard_closed(self):
27 self._keyboard.unbind(on_key_down=self._on_keyboard_down)
28 self._keyboard = None
29
30 def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
31 key = self.find_by_key_code(keycode)
32 if key is not None:
33 threading.Thread(name = "MSKeyAction", target=key.do_actions).start()
34 return True
35
36 def find_by_key_code(self, key_code):
37 if "Key_" + str(key_code[0]) in self.ids:
38 return self.ids["Key_" + str(key_code[0])]
167 return None 39 return None
168 40
169 def find_by_unicode(self, key_sym): 41 def find_by_unicode(self, key_sym):
170 for key in self.keys: 42 for key in self.children:
171 if self.keys[key].key_sym == key_sym: 43 if not type(key).__name__ == "Key":
172 return self.keys[key] 44 continue
45 print(key.key_sym, key_sym)
46 if key.key_sym == key_sym:
47 print("found")
48 return key
173 return None 49 return None
174 50
175 def stop_all_running(self): 51 def stop_all_running(self):
@@ -185,3 +61,78 @@ class Mapping:
185 if (key, start_time) in self.running: 61 if (key, start_time) in self.running:
186 self.running.remove((key, start_time)) 62 self.running.remove((key, start_time))
187 63
64 def parse_config(self):
65 stream = open("config.yml", "r")
66 config = yaml.load(stream)
67 stream.close()
68
69 aliases = config['aliases']
70 seen_files = {}
71
72 file_lock = Lock("file")
73
74 channel_id = 0
75
76 key_properties = {}
77
78 for key in config['key_properties']:
79 if key not in key_properties:
80 key_properties[key] = {
81 "actions": [],
82 "properties": config['key_properties'][key],
83 "files": []
84 }
85
86 for mapped_key in config['keys']:
87 if mapped_key not in key_properties:
88 key_properties[mapped_key] = {
89 "actions": [],
90 "properties": {},
91 "files": []
92 }
93 for action in config['keys'][mapped_key]:
94 action_name = list(action)[0]
95 action_args = {}
96 if action[action_name] is None:
97 action[action_name] = []
98
99 if 'include' in action[action_name]:
100 included = action[action_name]['include']
101 del(action[action_name]['include'])
102
103 if isinstance(included, str):
104 action[action_name].update(aliases[included], **action[action_name])
105 else:
106 for included_ in included:
107 action[action_name].update(aliases[included_], **action[action_name])
108
109 for argument in action[action_name]:
110 if argument == 'file':
111 filename = action[action_name]['file']
112 if filename not in seen_files:
113 if filename in config['music_properties']:
114 seen_files[filename] = MusicFile(
115 filename,
116 file_lock,
117 channel_id,
118 **config['music_properties'][filename])
119 else:
120 seen_files[filename] = MusicFile(
121 filename,
122 file_lock,
123 channel_id)
124 channel_id = channel_id + 1
125
126 if filename not in key_properties[mapped_key]['files']:
127 key_properties[mapped_key]['files'].append(seen_files[filename])
128
129 action_args['music'] = seen_files[filename]
130
131 else:
132 action_args[argument] = action[action_name][argument]
133
134 key_properties[mapped_key]['actions'].append([action_name, action_args])
135
136 return (key_properties, channel_id + 1, seen_files)
137
138
diff --git a/helpers/rounded_rect.py b/helpers/rounded_rect.py
deleted file mode 100644
index f168e0e..0000000
--- a/helpers/rounded_rect.py
+++ /dev/null
@@ -1,62 +0,0 @@
1import pygame
2
3class RoundedRect:
4 def __init__(self, rect, outer_color, inner_color, linewidth = 2, radius = 0.4):
5 self.rect = pygame.Rect(rect)
6 self.outer_color = pygame.Color(*outer_color)
7 self.inner_color = pygame.Color(*inner_color)
8 self.linewidth = linewidth
9 self.radius = radius
10
11 def surface(self):
12 rectangle = self.filledRoundedRect(self.rect, self.outer_color, self.radius)
13
14 inner_rect = pygame.Rect((
15 self.rect.left + 2 * self.linewidth,
16 self.rect.top + 2 * self.linewidth,
17 self.rect.right - 2 * self.linewidth,
18 self.rect.bottom - 2 * self.linewidth
19 ))
20
21 inner_rectangle = self.filledRoundedRect(inner_rect, self.inner_color, self.radius)
22
23 rectangle.blit(inner_rectangle, (self.linewidth, self.linewidth))
24
25 return rectangle
26
27 def filledRoundedRect(self, rect, color, radius=0.4):
28 """
29 filledRoundedRect(rect,color,radius=0.4)
30
31 rect : rectangle
32 color : rgb or rgba
33 radius : 0 <= radius <= 1
34 """
35
36 alpha = color.a
37 color.a = 0
38 pos = rect.topleft
39 rect.topleft = 0,0
40 rectangle = pygame.Surface(rect.size,pygame.SRCALPHA)
41
42 circle = pygame.Surface([min(rect.size)*3]*2,pygame.SRCALPHA)
43 pygame.draw.ellipse(circle,(0,0,0),circle.get_rect(),0)
44 circle = pygame.transform.smoothscale(circle,[int(min(rect.size)*radius)]*2)
45
46 radius = rectangle.blit(circle,(0,0))
47 radius.bottomright = rect.bottomright
48 rectangle.blit(circle,radius)
49 radius.topright = rect.topright
50 rectangle.blit(circle,radius)
51 radius.bottomleft = rect.bottomleft
52 rectangle.blit(circle,radius)
53
54 rectangle.fill((0,0,0),rect.inflate(-radius.w,0))
55 rectangle.fill((0,0,0),rect.inflate(0,-radius.h))
56
57 rectangle.fill(color,special_flags=pygame.BLEND_RGBA_MAX)
58 rectangle.fill((255,255,255,alpha),special_flags=pygame.BLEND_RGBA_MIN)
59
60 return rectangle
61
62