From 597b007333d8ec0d9cfd29e6941fcbe57379108a Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Mon, 22 May 2023 08:40:47 +0200 Subject: Initial commit --- src/skeleton.py | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 src/skeleton.py (limited to 'src/skeleton.py') diff --git a/src/skeleton.py b/src/skeleton.py new file mode 100644 index 0000000..8497d34 --- /dev/null +++ b/src/skeleton.py @@ -0,0 +1,199 @@ +import displayio +import terminalio +from adafruit_display_shapes.rect import Rect +from adafruit_display_text import label + +from collections import namedtuple +from supervisor import ticks_ms +from actions import Action +import ticks + +class Group(object): + def __init__(self, color, actions): + + # The color of the LED for the selected element + self.color = color + + self.actions = actions + + self._selected = actions[0][0] + + @property + def selected(self): + return self._selected + + @selected.setter + def selected(self, value): + """Set the value, and switch the LED accordingly""" + + keys = [action[0] for action in self.actions] + + if value not in keys: + return + + for keyId in keys: + Action().macropad.pixels[keyId] = 0 + Action().macropad.pixels[value] = int(self.color) + self._selected = value + +class Configuration(object): + + def __init__(self, title): + + # Set the application available in the menu by default + self.visible = True + self.Action = namedtuple("Action", ("name", "callback", "color")) + self.title = title + self.keys = { + 0 : None, 1 : None, 2 : None, + 3 : None, 4 : None, 5 : None, + 6 : None, 7 : None, 8 : None, + 9 : None, 10 : None, 11 : None, + 12 : None, + 13 : None, + } + self.group = [] + self.tick = None + + def registerKey(self, keyId, name, callback, color): + if keyId > 13: + return + self.keys[keyId] = self.Action(name, callback, color) + + def registerGroup(self, group): + self.group.append(group) + + def setTick(self, duration, callback): + self.tick = (duration, callback) + +class Handler(object): + + def __init__(self, macropad, configuration): + self.macropad = macropad + self.group = displayio.Group() + + self.keys = { + 0 : None, 1 : None, 2 : None, + 3 : None, 4 : None, 5 : None, + 6 : None, 7 : None, 8 : None, + 9 : None, 10 : None, 11 : None, + 12 : None, + 13 : None, + } + + self.colors = { + 0 : None, 1 : None, 2 : None, + 3 : None, 4 : None, 5 : None, + 6 : None, 7 : None, 8 : None, + 9 : None, 10 : None, 11 : None, + } + + self.options = configuration.group + + self.name = configuration.title + + for index, value in configuration.keys.items(): + if value is None: + continue + self.keys[index] = value.name, value.callback + self.colors[index] = value.color + + for option in self.options: + for action in option.actions: + keyId = action[0] + self.keys[keyId] = action[1], lambda macropad, key, pressed: None + self.macropad.pixels[option.selected] = int(option.color) + + self.periodic_callback = None + self.next_tick = None + + if configuration.tick is not None: + self.periodic_callback = configuration.tick + self._update_tick() + self.macropad.pixels.show() + + def _update_tick(self): + self.next_tick = ticks.add( + ticks_ms(), + self.periodic_callback[0] + ) + + def _set_color(self, key, pressed): + if pressed: + self.macropad.pixels[key] = int(0x010101) + else: + color = self.colors[key] + self.macropad.pixels[key] = int( self.colors[key] or 0 ) + for option in self.options: + self.macropad.pixels[option.selected] = int(option.color) + + def tick(self): + "Execute asyncronous events" + + Action().collect_tasks() + if self.next_tick is None or ticks.less(self.next_tick): + return + + self.periodic_callback[1](self.macropad) + self._update_tick() + + def start(self): + self.position = self.macropad.encoder + + for key_index in range(12): + x = key_index % 3 + y = key_index // 3 + self.group.append(label.Label(terminalio.FONT, text='', color=0xFFFFFF, + anchored_position=((self.macropad.display.width - 1) * x / 2, + self.macropad.display.height - 1 - + (3 - y) * 12), + anchor_point=(x / 2, 1.0))) + self.group.append(Rect(0, 0, self.macropad.display.width, 12, fill=0xFFFFFF)) + self.group.append(label.Label(terminalio.FONT, text='', color=0x000000, + anchored_position=(self.macropad.display.width//2, -2), + anchor_point=(0.5, 0.0))) + self.macropad.display.show(self.group) + + self.group[13].text = self.name # Application name + for i in range(12): + if self.keys[i] is not None: + self.group[i].text = self.keys[i][0] + self.macropad.keyboard.release_all() + self.macropad.consumer_control.release() + self.macropad.mouse.release_all() + self.macropad.stop_tone() + for key in range(12): + self._set_color(key, False) + self.macropad.pixels.show() + self.macropad.display.refresh() + + def execute_action(self, key, pressed): + + for option in self.options: + option.selected = key + + action = self.keys[key] + + # Do nothing if there is no action for this key + if action is None: + return + + # Update the leds + if key < 12: + if pressed: Action().flash(key, 0x010101) + else: self._set_color(key, pressed) + else: + for key_idx in range(12): + self._set_color(key_idx, pressed) + self.macropad.pixels.show() + + result = action[1](self.macropad, key, pressed) + + # If we use the rotary encoder, mark all the actions as resolved. + if key >= 12: + action[1](self.macropad, key, False) + for key_idx in range(12): + self._set_color(key_idx, False) + self.macropad.pixels.show() + + return result -- cgit v1.2.3