From 3bd77c9e826316fb51fe7d56e75d8d6ac72e66c9 Mon Sep 17 00:00:00 2001 From: Serge Bazanski <q3k@q3k.org> Date: Thu, 3 Aug 2023 19:02:08 +0200 Subject: [PATCH] py: remove st3m --- python_payload/st3m/__init__.py | 0 python_payload/st3m/application.py | 169 ------------ python_payload/st3m/control.py | 146 ----------- python_payload/st3m/event.py | 369 -------------------------- python_payload/st3m/menu.py | 400 ----------------------------- python_payload/st3m/ui.py | 296 --------------------- python_payload/st3m/utils.py | 47 ---- 7 files changed, 1427 deletions(-) delete mode 100644 python_payload/st3m/__init__.py delete mode 100644 python_payload/st3m/application.py delete mode 100644 python_payload/st3m/control.py delete mode 100644 python_payload/st3m/event.py delete mode 100644 python_payload/st3m/menu.py delete mode 100644 python_payload/st3m/ui.py delete mode 100644 python_payload/st3m/utils.py diff --git a/python_payload/st3m/__init__.py b/python_payload/st3m/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/python_payload/st3m/application.py b/python_payload/st3m/application.py deleted file mode 100644 index 1cf755c804..0000000000 --- a/python_payload/st3m/application.py +++ /dev/null @@ -1,169 +0,0 @@ -from st3m import logging - -log = logging.Log(__name__, level=logging.INFO) -log.info("import") -from . import ui, event, menu - -STATE_OFF = 0 -STATE_INIT = 10 -STATE_BACKGROUND = 200 -STATE_FOREGROUND = 300 -STATE_ERROR = 500 - -log.info("setting up application") - - -class Application: - def __init__( - self, title="badge23 app", author="someone@earth", exit_on_menu_enter=True - ): - log.info(f"__init__ app '{title}'") - self.title = title - self.author = author - self.state = STATE_OFF - self.has_background = False - self.has_foreground = True - self._events_background = [] - self._events_foreground = [] - self.ui = ui.Viewport() - self.icon = ui.Icon(label=self.title, size=100) - self.engine = event.the_engine - self.menu = None - if exit_on_menu_enter: - self.add_event( - event.Event( - name="exit", - action=self.exit, - condition=lambda e: e["type"] == "button" - and e["index"] == 1 - and e.get("from") == 2 - and e["change"], - ) - ) - - def __repr__(self): - return "App " + self.title - - def init(self): - log.info(f"init app '{self.title}'") - self.state = STATE_INIT - self.on_init() - if self.has_background: - if self._events_background: - self._set_events(self._events_background, True) - engine.register_service_loop(self.main_always, True) - - def run(self): - log.info(f"run app '{self.title}' from state {self.state}") - if self.state == STATE_OFF: - log.info("from STATE_OFF, doing init()") - self.init() - if self.has_foreground: - self._to_foreground() - elif self.has_background: - self._to_background() - else: - log.warning( - f"App {self.title} has neither foreground nor background, not doing anything" - ) - - # start the eventloop if it is not already running - if not event.the_engine.is_running: - log.info("eventloop not yet running, starting") - event.the_engine.eventloop() - - def exit(self, data={}): - log.info(f"exit app '{self.title}' from state {self.state}") - self.on_exit() - if self.state == STATE_FOREGROUND: - self._to_background() - - def kill(self): - # disable all events - log.info(f"kill app '{self.title}' from state {self.state}") - engine.register_service_loop(self.main_always, False) - - engine.foreground_app = None - self._set_events(self._events_background, False) - self._set_events(self._events_forground, False) - self.state = STATE_OFF - - def draw(self, ctx): - self.ui.draw(ctx) - self.on_draw(ctx) - - def tick(self): - self.main_foreground() - - def add_event(self, event, is_background=False): - if not is_background: - self._events_foreground.append(event) - else: - self._events_background.append(event) - - def is_foreground(self): - return self.state == STATE_FOREGROUND - - def _to_foreground(self): - log.info(f"to_foreground app '{self.title}' from state {self.state}") - if not self.has_foreground: - log.error(f"app has no foreground!") - return - - if self._events_background: - self._set_events(self_events_background, False) - self.state = STATE_FOREGROUND - - if self._events_foreground: - self._set_events(self._events_foreground, True) - - # TODO(q3k): make this pending - # self.ui.ctx.rgb(*ui.BLACK).rectangle(-120,-120,240,240).fill() - # self.icon.draw() - - self.on_foreground() - - self.engine.foreground_app = self - - def _to_background(self): - log.info(f"to_background app '{self.title}' from state {self.state}") - self.state = STATE_BACKGROUND - if self._events_foreground: - self._set_events(self._events_foreground, False) - - self.engine.foreground_app = None - menu.menu_back() - if self.has_background: - self.state = STATE_BACKGROUND - self.on_background() - - def _set_events(self, events, enabled=True): - for e in events: - e.set_enabled(enabled) - - def on_init(self): - log.info(f"app {self.title}: on_init()") - - def on_foreground(self): - log.info(f"app {self.title}: on_foreground()") - - def on_background(self): - log.info(f"app {self.title}: on_background()") - - def on_exit(self): - log.info(f"app {self.title}: on_exit()") - - def on_kill(self): - log.info(f"app {self.title}: on_kill()") - - def on_draw(self, ctx): - log.debug(f"app {self.title}: on_draw()") - - def main_foreground(self): - pass - - def main_always(self): - pass - - def main(self): - self.main_foreground() diff --git a/python_payload/st3m/control.py b/python_payload/st3m/control.py deleted file mode 100644 index 1fcc2b1273..0000000000 --- a/python_payload/st3m/control.py +++ /dev/null @@ -1,146 +0,0 @@ -from st3m import logging, menu - -log = logging.Log(__name__, level=logging.INFO) -log.info("import") - -from . import ui - - -class Control: - def __init__(self, name, default=0, on_set=None, on_get=None, on_mod=None): - # TODO inheritance from Control() - self.name = name - self.on_set = on_set - self.on_get = on_get - self.on_mod = on_mod - - if not self.on_get: - self._value = default - self.ui = ui.IconValue(label=self.name, size=60, value=self.get_value()) - self.ui.get_value = self.get_normal_value - - self.menu = menu.MenuControl(self) - - def draw(self, ctx): - self.ui.value = self.get_value() - self.ui.draw(ctx) - - def get_normal_value(self): - v = self.get_value() - n = min(1, max(0, v)) - return n - - def get_value(self, update=True): - if update and self.on_get: - self._value = self.on_get() - return self._value - - def set_value(self, value, do_trigger=True): - self._value = value - if do_trigger: - if self.on_set: - self.on_set(value) - - def mod_value(self, delta): - self._value = self.on_mod(delta) - - def enter_menu(self): - menu.submenu_push(self.menu) - - def scroll(self, delta): - pass - - def touch_1d(self, x, z): - pass - - -class ControlSwitch(Control): - def enter(self): - self.set_value(not self.get_value()) - - def scroll(self, delta): - self.enter() - - def touch_1d(self, x, z): - if z < 0: # Release - self.enter() - - -class ControlFloat(Control): - def __init__(self, min=0.0, max=1.0, step=0.1, *args, **kwargs): - self.min = min - self.max = max - self.step = step - super().__init__(*args, **kwargs) - - def get_normal_value(self): - v = self.get_value() - n = (v - self.min) / (self.max - self.min) - return n - - -class ControlKnob(ControlFloat): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._x_init = 0 - self._touch_started_here = False - - def enter(self): - # repeat action with current value - self.set_value(self.get_value()) - - def scroll(self, delta): - if self.on_mod: - # print("control: on mod") - self.on_mod(delta) - - elif self.on_set: - v = self.get_value() - v_new = max(self.min, min(self.max, v + delta * self.step)) - self.set_value(v_new) - - def touch_1d(self, x, z): - if z > 0: # Inital Contact - self._x_init = x - self._touch_started_here = True - - if z == 0: # Continous contact - if not self._touch_started_here: - return - diff = self._x_init - x - self.scroll(5 * diff) - - if z < 0: # Release - self._touch_started_here = False - - -class ControlSlide(ControlFloat): - def __init__(self, do_reset=True, *args, **kwargs): - self.do_reset = do_reset - self._saved_value = None - super().__init__(*args, **kwargs) - - def touch_1d(self, x, z): - if z > 0: # Inital Contact - self._saved_value = self.get_value() - - if self._saved_value is None: - return - - if z == 0: # Continous contact - v = (self.max - self.min) * x + self.min - self.set_value(v) - # print("c",x,v,self.max,self.min) - - if z < 0: # Release - if self.do_reset: - self.set_value(self._saved_value) - self._saved_value = None - - -class ControlString(Control): - pass - - -class ControlTextField: - pass diff --git a/python_payload/st3m/event.py b/python_payload/st3m/event.py deleted file mode 100644 index e48505e3a6..0000000000 --- a/python_payload/st3m/event.py +++ /dev/null @@ -1,369 +0,0 @@ -from st3m import logging - -log = logging.Log(__name__, level=logging.INFO) -log.info("import") - -from st3m.system import hardware, captouch - -import kernel -import time -import math -import random - - -EVENTTYPE_TIMED = 1 -EVENTTYPE_INPUT = 2 -# EVENTTYPE_BUTTON = 2 -# EVENTTYPE_CAPTOUCH = 3 -# EVENTTYPE_CAPCROSS = 4 - - -class Engine: - def __init__(self): - self.events_timed = [] - self.events_input = [] - self.next_timed = None - self.last_input_state = None - self.userloop = None - self.is_running = False - self.foreground_app = None - self.active_menu = None - self.overlay = None - - self._draw_started = None - self._draw_ended = None - - self._think_started = None - self._think_ended = None - - self._last_report = None - - def _report_heap(self): - st = kernel.heap_stats() - g = st.general - d = st.dma - log.info( - f"Heap: General: {g.total_free_bytes:d}B free, {g.total_allocated_bytes:d}B allocated, {g.largest_free_block:d}B largest free block" - ) - log.info( - f"Heap: DMA: {d.total_free_bytes:d}B free, {d.total_allocated_bytes:d}B allocated, {d.largest_free_block:d}B largest free block" - ) - - def _report(self): - now = time.ticks_ms() - if self._last_report is not None and (now - self._last_report) < 1000: - return - - if self._draw_started is not None and self._draw_ended is not None: - draw_time = self._draw_ended - self._draw_started - log.info(f"EventLoop Draw time: {draw_time:.3f}ms") - - if self._think_started is not None and self._think_ended is not None: - think_time = self._think_ended - self._think_started - log.info(f"EventLoop Think time: {think_time:.3f}ms") - - self._report_heap() - self._last_report = now - - def add(self, event): - if isinstance(event, EventTimed): - self.add_timed(event) - elif isinstance(event, Event): - self.add_input(event) - - def add_timed(self, event): - self.events_timed.append(event) - self._sort_timed() - - def add_input(self, event): - self.events_input.append(event) - - def remove(self, group_id): - self.remove_input(group_id) - self.remove_timed(group_id) - - def remove_timed(self, group_id): - # print("before:",len(self.events_timed)) - self.events_timed = [ - event for event in self.events_timed if event.group_id != group_id - ] - self._sort_timed() - # print("after",len(self.events_timed)) - - def remove_input(self, group_id): - self.events_input = [ - event for event in self.events_input if event.group_id != group_id - ] - - def _sort_timed(self): - self.events_timed = sorted(self.events_timed, key=lambda event: event.deadline) - - def _handle_timed(self): - if not self.next_timed and self.events_timed: - self.next_timed = self.events_timed.pop(0) - - now = time.ticks_ms() - - if self.next_timed: - diff = time.ticks_diff(self.next_timed.deadline, now) - if diff <= 0: - self.next_timed.trigger({"ticks_ms": now, "ticks_delay": -diff}) - self.next_timed = None - - def _handle_input(self, delta): - # log.info("input {delta}") - input_state = [] - - # buttons - input_state.append( - {"type": "button", "index": 0, "value": hardware.menu_button_get()} - ) - - input_state.append( - {"type": "button", "index": 1, "value": hardware.application_button_get()} - ) - - # captouch - cps = captouch.read() - for i in range(0, 10): - petal = cps.petals[i] - (radius, angle) = petal.position - input_state.append( - { - "type": "captouch", - "index": i, - "value": petal.pressed, - "radius": radius, - "angle": angle, - } - ) - - if not self.last_input_state: - self.last_input_state = input_state - return - - for i in range(len(input_state)): - entry = input_state[i] - last_entry = self.last_input_state[i] - - # update for all - entry["ticks_ms"] = time.ticks_ms() - entry["delta"] = delta - - if entry["value"] != last_entry["value"]: - # update only when value changed - entry["change"] = True - entry["from"] = last_entry["value"] - else: - # update only when value did not change - entry["change"] = False - - # find and trigger the events q - triggered_events = list( - filter(lambda e: e.enabled and e.condition(entry), self.events_input) - ) - # log.info(triggered_events) - # map(lambda e: e.trigger(d), triggered_events) - for e in triggered_events: - e.trigger(entry) - - self.last_input_state = input_state - - def _handle_userloop(self): - if self.foreground_app: - self.foreground_app.tick() - - def _handle_draw(self, ctx): - self._draw_started = time.ticks_ms() - - if self.foreground_app: - self.foreground_app.draw(ctx) - if self.active_menu: - self.active_menu.draw(ctx) - if self.overlay: - self.overlay.draw(ctx) - - self._draw_ended = time.ticks_ms() - - def _eventloop_single(self, delta): - self._think_started = time.ticks_ms() - - self._handle_timed() - self._handle_input(delta) - self._handle_userloop() - - self._think_ended = time.ticks_ms() - - def eventloop(self): - log.info("starting eventloop") - if self.is_running: - log.warning("eventloop already running, doing nothing") - return - self.is_running = True - - last_eventloop = None - - ctx = None - while self.is_running: - start = time.ticks_ms() - deadline = start + 20 - self._report() - - if last_eventloop is not None: - delta = (start - last_eventloop) / 1000.0 - if delta >= 0.01: - last_eventloop = start - self._eventloop_single(delta) - else: - last_eventloop = start - - post_think = time.ticks_ms() - - if ctx is None: - ctx = hardware.get_ctx() - if ctx is not None: - self._handle_draw(ctx) - - post_draw = time.ticks_ms() - - if ctx is not None and not hardware.display_pipe_full(): - hardware.display_update(ctx) - # log.info("update") - ctx = None - - post_submit = time.ticks_ms() - - wait = deadline - time.ticks_ms() - if wait > 0: - hardware.freertos_sleep(wait) - else: - log.warning(f"Application took too long too process! Slack {wait}ms.") - log.warning( - f"Think: {post_think-start}ms, Draw: {post_draw-post_think}ms, Submit: {post_submit-post_draw}ms" - ) - hardware.freertos_sleep(1) - - -class Event: - def __init__( - self, - name="unknown", - data={}, - action=None, - condition=None, - group_id=None, - enabled=False, - ): - # print (action) - self.name = name - self.eventtype = None - self.data = data - self.action = action - self.condition = condition - self.enabled = enabled - if not condition: - self.condition = lambda x: True - self.group_id = group_id - - if enabled: - self.set_enabled() - - def trigger(self, triggerdata={}): - log.debug("triggered {} (with {})".format(self.name, triggerdata)) - if not self.action is None: - triggerdata.update(self.data) - self.action(triggerdata) - - def set_enabled(self, enabled=True): - self.enabled = enabled - if enabled: - the_engine.add(self) - else: - self.remove() - - def remove(self): - log.info(f"remove {self}") - while self in the_engine.events_input: - # print ("from input") - the_engine.events_input.remove(self) - while self in the_engine.events_timed: - # print("from timed") - the_engine.events_timed.remove(self) - the_engine._sort_timed() - - -class EventTimed(Event): - def __init__(self, ms, name="timer", *args, **kwargs): - # super().__init__(name,data,action) - self.deadline = time.ticks_add(time.ticks_ms(), ms) - - super().__init__(*args, **kwargs) - self.name = name - self.type = EVENTTYPE_TIMED - - def __repr__(self): - return "event on tick {} ({})".format(self.deadline, self.name) - - -# hack, make this oo -def on_restart(data): - print("loop sequence") - obj = data["object"] - if obj.is_running: - obj.start() - - -class Sequence: - def __init__(self, bpm=60, loop=True, steps=16, action=None): - self.group_id = random.randint(0, 100000000) - self.bpm = bpm - self.steps = steps - self.repeat_event = None - self.loop = loop - self.events = [] - self.is_running = False - - if not action: - self.action = lambda data: log.info("step {}".format(data.get("step"))) - else: - self.action = action - - def start(self): - if self.is_running: - self.stop() - stepsize_ms = int(60 * 1000 / self.bpm) - for i in range(self.steps): - log.debug(f"adding sequence event {i}") - self.events.append( - EventTimed( - stepsize_ms * i, - name="seq{}".format(i), - action=self.action, - data={"step": i}, - group_id=self.group_id, - enabled=True, - ) - ) - if self.loop: - self.repeat_event = EventTimed( - stepsize_ms * self.steps, - name="loop", - group_id=self.group_id, - enabled=True, - action=on_restart, - data={"object": self}, - ) - self.is_running = True - - def stop(self): - # for e in self.events: e.remove() - log.info("sequence stop") - the_engine.remove_timed(group_id=self.group_id) - self.events = [] - if self.repeat_event: - self.repeat_event.remove() - self.is_running = False - - -global the_engine -the_engine = Engine() diff --git a/python_payload/st3m/menu.py b/python_payload/st3m/menu.py deleted file mode 100644 index d9f3db7209..0000000000 --- a/python_payload/st3m/menu.py +++ /dev/null @@ -1,400 +0,0 @@ -from st3m import logging -import math - -log = logging.Log(__name__, level=logging.INFO) -log.info("import") - -from . import ui, event - - -import time -import math - -menu_stack = [] - - -class Menu: - def __init__(self, name="menu", has_back=True): - self.name = name - self.items = [] - self.items_petal = [None for i in range(10)] - self.__index = 0 - self.ui = ui.GroupRing(r=80) - self.ui2 = ui.GroupPetals( - r=100 - ) # TODO(iggy) hack, this should be composed together in ui - self.icon = ui.IconFlower(label=name, size=80) - self.ui.element_center = self.icon - - self.angle = 0 - self.angle_step = 0.2 - - if has_back: - self.add(MenuItemBack()) - - def __repr__(self): - return "{} ({}): {}".format(self.name, self.__index, self.items) - - def add(self, item): - self.items.append(item) - self.ui.add(item.ui) - - def add_petal(self, item, petal_index): - self.items_petal[petal_index] = item - self.ui2.children[petal_index] = item.ui - - def pop(self): - self.items.pop() - self.ui.children.pop() - - def start(self): - log.info(f"starting menu {self.name}") - set_active_menu(self) - - # def scroll(self, n=0): - # self.__index= (self.__index+n)%len(self.items) - # return self.items[self.__index] - - def scroll_app(self, delta): - hovered = self.get_hovered_item() - if hasattr(hovered, "scroll"): - hovered.scroll(delta) - - def scroll_menu(self, delta): - if self.angle_step < 0.5: - self.angle_step += 0.025 - self.rotate_steps(delta) - - def enter_menu(self, data={}): - hovered = self.get_hovered_item() - if hasattr(hovered, "enter_menu"): - hovered.enter_menu() - else: - hovered.enter() - - def enter_app(self, data={}): - hovered = self.get_hovered_item() - if hasattr(hovered, "enter_app"): - hovered.enter_app() - else: - hovered.enter() - - def rotate_by(self, angle): - self.rotate_to(self.angle + angle) - - def rotate_to(self, angle): - self.angle = angle % (math.pi * 2) - self.ui.angle_offset = self.angle - # for child in self.ui.children: - # child.angle_offset = self.angle*2 - - self.icon.phi_offset = self.angle - - def rotate_steps(self, steps=1): - self.rotate_by(-self.angle_step * steps) - - def _get_hovered_index(self): - index = round(-self.angle / (math.pi * 2) * len(self.items)) - i = index % len(self.items) - return i - - def get_hovered_item(self): - return self.items[self._get_hovered_index()] - - def _get_angle_for_index(self, index): - return (math.pi * 2 / len(self.items) * (index) + self.angle) % (math.pi * 2) - - def _get_topness_for_index(self, index): - angle = self._get_angle_for_index(index) - dist = min(angle, math.pi * 2 - angle) - topness = 1 - (dist / math.pi) - return topness - - def draw(self, ctx): - # TODO this is more like a hack... - # if not self==active_menu: - # active_menu.draw() - # return - # print("draw",self.name) - hovered_index = self._get_hovered_index() - for i in range(len(self.items)): - item = self.items[i] - my_extra = abs(self._get_topness_for_index(i)) * 40 - - if i == hovered_index: - item.ui.has_highlight = True - my_extra += 20 - else: - item.ui.has_highlight = False - item.ui.size = 30 + my_extra - - # black background - # TODO transparent menu with compositing - ctx.rectangle(-120, -120, 240, 240).rgb(*ui.BLACK).fill() - - self.ui2.draw(ctx) - self.ui.draw(ctx) - - -class MenuControl(Menu): - def __init__(self, control, *args, **kwargs): - super().__init__(*args, **kwargs) - self.control = control - self.ui.element_center = self.control.ui - - def scroll_app(self, delta): - hovered = self.get_hovered_item() - if hasattr(hovered, "scroll"): - hovered.scroll(delta) - else: - self.control.scroll(delta) - - def enter_app(self, data={}): - hovered = self.get_hovered_item() - if hasattr(hovered, "enter_app"): - hovered.enter_app() - else: - self.control.enter() - - -class MenuItem: - def __init__(self, name="item", action=None): - self.name = name - self.action = action - self.ui = ui.IconFlower(label=name) - - def __repr__(self): - return "item: {} (action: {})".format(self.name, "?") - - def enter(self, data={}): - log.info("enter MenuItem {}".format(self.name)) - if self.action: - self.action(data) - - -class MenuItemApp(MenuItem): - def __init__(self, app): - super().__init__(name=app.title) - self.target = app - - def enter(self, data={}): - if self.target: - submenu_push(None) - self.target.run() - - -class MenuItemSubmenu(MenuItem): - def __init__(self, submenu): - super().__init__(name=submenu.name) - self.ui = submenu.icon - self.target = submenu - - def enter_menu(self, data={}): - log.info("item submenu enter") - submenu_push(self.target) - - -class MenuItemBack(MenuItem): - def __init__(self): - super().__init__(name="") - self.ui = ui.IconLabel(label="back") - - def enter_menu(self, data={}): - log.info(f"item back selected") - menu_back() - - -class MenuItemControl(MenuItem): - def __init__(self, name, control): - super().__init__(name=name) - self.control = control - self.ui = control.ui - - def enter_menu(self): - log.info(f"item {self.name} (MenuItemControl): enter_menu->enter") - self.control.enter() - - def enter_app(self): - log.info(f"item {self.name} (MenuItemControl): enter->enter menu") - self.control.enter_menu() - - def scroll(self, delta): - self.control.scroll(delta) - - def touch_1d(self, x, z): - self.control.touch_1d(x, z) - - -def on_scroll(d): - active_menu = get_active_menu() - if active_menu is None: - return - - if d["index"] == 0: # right button - active_menu.scroll_app(d["value"] * 10.0 * d["delta"]) - - else: # index=1, #left button - active_menu.scroll_menu(d["value"] * 10.0 * d["delta"]) - - -menu_offset = None -last = time.ticks_ms() - - -def on_scroll_captouch(d): - active_menu = get_active_menu() - if active_menu is None: - return - global menu_offset - global last - # if abs(d["radius"]) < 10000: - # return - - a = math.atan2(-d["radius"] / 600, d["angle"] / 600) - - z = 0 - if d["change"]: - if d["value"] == 1: - z = 1 - else: - z = -1 - - if z == 1: - menu_offset = active_menu.angle - a - last = time.ticks_ms() - if z == 0: - active_menu.rotate_to(menu_offset + a) - - if z == -1: - diff = time.ticks_diff(time.ticks_ms(), last) - if diff < 300: - active_menu.enter_menu() - - # active_menu.rotate_to(a) - - -def on_release(d): - active_menu = get_active_menu() - - if active_menu is None: - return - - active_menu.angle_step = 0.2 - - -def on_touch_1d(d): - active_menu = get_active_menu() - - if active_menu is None: - return - - v = min(1.0, max(0.0, ((d["radius"] + 25000.0) / 50000.0))) - z = 0 - if d["change"]: - if d["value"] == 1: - z = 1 - else: - z = -1 - - log.debug(f"menu: touch_1d ({v},{z})") - - petal_idx = d["index"] - petal_item = active_menu.items_petal[petal_idx] - if petal_item: - petal_item.touch_1d(v, z) - - if d["index"] == 8: - hovered = active_menu.get_hovered_item() - if hasattr(hovered, "touch_1d"): - hovered.touch_1d(v, z) - - -def on_enter(d): - active_menu = get_active_menu() - - # if active_menu is None: - # log.info("menu enter without active menu, opening last menu") - # menu_back() - # return - if active_menu: - if d["index"] == 0: # right button - log.info("menu enter_app") - active_menu.enter_app() - - else: - log.info("menu enter_menu") - active_menu.enter_menu() - - -event.Event( - name="menu rotation button", - group_id="menu", - condition=lambda e: e["type"] == "button" - and not e["change"] - and abs(e["value"]) == 1, - action=on_scroll, - enabled=True, -) - -event.Event( - name="menu rotation captouch", - group_id="menu", - condition=lambda e: e["type"] == "captouch" - and (e["value"] == 1 or e["change"]) - and e["index"] == 2, - action=on_scroll_captouch, - enabled=True, -) - - -event.Event( - name="menu rotation button release", - group_id="menu", - condition=lambda e: e["type"] == "button" and e["change"] and e["value"] == 0, - action=on_release, - enabled=True, -) - -event.Event( - name="menu 1d captouch", - group_id="menu", - condition=lambda e: e["type"] == "captouch" and (e["value"] == 1 or e["change"]), - action=on_touch_1d, - enabled=True, -) - -event.Event( - name="menu button enter", - group_id="menu", - condition=lambda e: e["type"] == "button" and e["change"] and e["from"] == 2, - action=on_enter, - enabled=True, -) - - -def set_active_menu(menu): - event.the_engine.active_menu = menu - - -def get_active_menu(): - return event.the_engine.active_menu - - -def menu_back(): - previous = menu_stack.pop() - log.info(f"back to previous menu {previous.name} (Stack: {len(menu_stack)})") - - set_active_menu(previous) - - -def submenu_push(new_menu): - active = get_active_menu() - menu_stack.append(active) - active.rotate_to(0) - if new_menu: - log.info( - f"enter submenu {new_menu.name} from {active.name} (Stack: {len(menu_stack)})" - ) - else: - log.info(f"leaving menu from {active.name}") - set_active_menu(new_menu) diff --git a/python_payload/st3m/ui.py b/python_payload/st3m/ui.py deleted file mode 100644 index 380d9f0e0d..0000000000 --- a/python_payload/st3m/ui.py +++ /dev/null @@ -1,296 +0,0 @@ -from st3m import logging - -log = logging.Log(__name__, level=logging.INFO) -log.info("import") - -import random -import math -import time -from math import sin, cos, pi - -import gc - -WIDTH = 240 -HEIGHT = 240 - -# Define a few RGB (0.0 to 1.0) colors -BLACK = (0, 0, 0) -RED = (1, 0, 0) -GREEN = (0, 1, 0) -BLUE = (0, 0, 1) -WHITE = (1, 1, 1) -GREY = (0.5, 0.5, 0.5) -GO_GREEN = (63 / 255, 255 / 255, 33 / 53) -PUSH_RED = (251 / 255, 72 / 255, 196 / 255) - - -# Utility functions -def xy_from_polar(r, phi): - return (r * math.sin(phi), r * math.cos(phi)) # x # y - - -# def ctx_circle(self, x,y, radius, arc_from = -math.pi, arc_to = math.pi): -# return self.arc(x,y,radius,arc_from,arc_to,True) - -# the_ctx.circle = ctx_circle - - -def randrgb(): - return (random.random(), random.random(), random.random()) - - -class UIElement: - def __init__(self, origin=(0, 0)): - self.children = [] - self.origin = origin - - def draw(self, ctx, offset=(0, 0)): - pos = (self.origin[0] + offset[0], self.origin[1] + offset[1]) - - self._draw(ctx, pos) - for child in self.children: - child.draw(ctx, pos) - - def _draw(self, ctx, pos): - pass - - def add(self, child): - self.children.append(child) - - -class Viewport(UIElement): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.background = False - - def _draw(self, ctx, pos): - if self.background: - ctx.rgb(*BLACK).rectangle(-120, -120, 240, 240).fill() - - -class Circle(UIElement): - def __init__( - self, radius, color=PUSH_RED, arc_from=-math.pi, arc_to=math.pi, *args, **kwargs - ): - self.radius = radius - self.color = color - self.arc_from = arc_from - self.arc_to = arc_to - super().__init__() - - def _draw(self, ctx, pos): - (x, y) = pos - ctx.move_to(x, y).rgb(*self.color).arc( - x, y, self.radius, self.arc_from, self.arc_to, True - ).fill() - - -class Text(UIElement): - def __init__(self, s="foo"): - self.s = s - super().__init__() - - def _draw(self, ctx, pos): - ctx.text_align = ctx.CENTER - ctx.text_baseline = ctx.MIDDLE - ctx.font_size = 30 - ctx.rgb(1, 1, 1).move_to(pos[0], pos[1]).text(self.s) - - -class Icon(UIElement): - def __init__(self, label="?", size=60): - self.bg = (random.random(), random.random(), random.random()) - self.fg = 0 - self.label = label - self.size = size - self.has_highlight = False - super().__init__() - - def _draw(self, ctx, pos): - ctx.text_align = ctx.CENTER - ctx.text_baseline = ctx.MIDDLE - ctx.font_size = self.size / 3 - - (x, y) = pos - hs = 5 - - if self.has_highlight: - ctx.rgb(*GO_GREEN).arc( - x, y, self.size / 2 + hs, -math.pi, math.pi, True - ).fill() - ctx.move_to(x, y).rgb(*self.bg).arc( - x, y, self.size / 2, -math.pi, math.pi, True - ).fill() - - y += self.size / 3 - width = max(self.size - 10, ctx.text_width(self.label)) + 10 - height = self.size / 3 + 8 - if self.has_highlight: - ctx.rgb(*BLACK).move_to(x, y - height / 2).round_rectangle( - x - width / 2, y - height / 2, width, height, width // 2 - ).fill() - ctx.rgb(*GO_GREEN).move_to(x, y).text(self.label) - else: - ctx.rgb(*PUSH_RED).move_to(x, y - height / 2).round_rectangle( - x - width / 2, y - height / 2, width, height, width // 2 - ).fill() - ctx.rgb(*BLACK).move_to(x, y).text(self.label) - - -class IconLabel(Icon): - def _draw(self, ctx, pos): - ctx.text_align = ctx.CENTER - ctx.text_baseline = ctx.MIDDLE - ctx.font_size = self.size / 2 - - (x, y) = pos - hs = 5 - width = ctx.text_width(self.label) + 10 - height = self.size / 2 - if self.has_highlight: - ctx.rgb(*GO_GREEN).move_to(x, y - height / 2).round_rectangle( - x - width / 2, y - height / 2, width, height, width // 2 - ).fill() - ctx.rgb(*BLACK).move_to(x, y).text(self.label) - else: - ctx.rgb(*PUSH_RED).move_to(x, y - height / 2).round_rectangle( - x - width / 2, y - height / 2, width, height, width // 2 - ).fill() - ctx.rgb(*BLACK).move_to(x, y).text(self.label) - - -class IconFlower(Icon): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.petal_count = random.randint(3, 5) - # self.petal_count = 0 - self.petal_color = (random.random(), random.random(), random.random()) - self.phi_offset = random.random() - self.size_offset = random.randint(0, 20) - # self.bg=PUSH_RED - - def _draw(self, ctx, pos): - ctx.text_align = ctx.CENTER - ctx.text_baseline = ctx.MIDDLE - ctx.font_size = self.size / 3 - - (x, y) = pos - petal_size = 0 - if self.petal_count: - petal_size = 2.3 * self.size / self.petal_count + self.size_offset - - hs = 5 - - for i in range(self.petal_count): - phi = math.pi * 2 / self.petal_count * i + self.phi_offset - r = self.size / 2 - (x_, y_) = xy_from_polar(r, phi) - size_rnd = random.randint(-1, 1) - if self.has_highlight: - ctx.move_to(x + x_, y + y_).rgb(*GO_GREEN).arc( - x + x_, - y + y_, - petal_size / 2 + hs + size_rnd, - -math.pi, - math.pi, - True, - ).fill() - ctx.move_to(x + x_, y + y_).rgb(*self.petal_color).arc( - x + x_, y + y_, petal_size / 2 + size_rnd, -math.pi, math.pi, True - ).fill() - - if self.has_highlight: - ctx.rgb(*GO_GREEN).arc( - x, y, self.size / 2 + hs, -math.pi, math.pi, True - ).fill() - ctx.move_to(x, y).rgb(*self.bg).arc( - x, y, self.size / 2, -math.pi, math.pi, True - ).fill() - - y += self.size / 3 - width = max(self.size, ctx.text_width(self.label) + 10) - height = self.size / 3 + 8 - if self.has_highlight: - ctx.rgb(*BLACK).move_to(x, y - height / 2).round_rectangle( - x - width / 2, y - height / 2, width, height, width // 2 - ).fill() - ctx.rgb(*GO_GREEN).move_to(x, y).text(self.label) - else: - ctx.rgb(*PUSH_RED).move_to(x, y - height / 2).round_rectangle( - x - width / 2, y - height / 2, width, height, width // 2 - ).fill() - ctx.rgb(*BLACK).move_to(x, y).text(self.label) - - -class IconValue(Icon): - def __init__(self, value=0, *args, **kwargs): - super().__init__(*args, **kwargs) - self.value = value - self.get_value = None - - def _draw(self, ctx, pos): - (x, y) = pos - - v = self.value - if self.get_value: - v = self.get_value() - self.value = v - - ctx.text_align = ctx.CENTER - ctx.text_baseline = ctx.MIDDLE - ctx.font_size = self.size / 3 - - if self.has_highlight: - ctx.move_to(x, y).rgb(*WHITE).arc( - x, y, self.size / 2 + 5, -pi, pi, True - ).fill() - - ctx.move_to(x, y).rgb(*PUSH_RED).arc(x, y, self.size / 2, -pi, pi, True).fill() - ctx.move_to(x, y).rgb(*GO_GREEN).arc( - x, y, self.size / 2 - 5, v * 2 * pi, 0, 1 - ).fill() - ctx.rgb(0, 0, 0).move_to(x, y).text(self.label) - - ctx.move_to(x, y).rgb(*PUSH_RED).arc(x, y, self.size / 2, -pi, pi, True).fill() - ctx.move_to(x, y).rgb(*GO_GREEN).arc( - x, y, self.size / 2 - 5, v * 2 * pi, 0, 1 - ).fill() - ctx.rgb(0, 0, 0).move_to(x, y).text(self.label) - - -class GroupStackedVertical(UIElement): - pass - - -class GroupRing(UIElement): - def __init__(self, r=100, origin=(0, 0), element_center=None): - self.r = r - self.angle_offset = 0 - self.element_center = element_center - super().__init__(origin) - - def draw(self, ctx, offset=(0, 0)): - pos = (self.origin[0] + offset[0], self.origin[1] + offset[1]) - self._draw(ctx, pos) - for index in range(len(self.children)): - # print("child",index) - child = self.children[index] - if not child: - continue - angle = 2 * math.pi / len(self.children) * index + self.angle_offset - # print(angle,self.r,pos[0]) - x = -math.sin(angle) * self.r + pos[0] - y = -math.cos(angle) * self.r + pos[1] - # print("pos",(x,y)) - child.draw(ctx, offset=(x, y)) - - def _draw(self, ctx, pos): - if self.element_center: - self.element_center.has_highlight = False - self.element_center._draw(ctx, pos) - - -class GroupPetals(GroupRing): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.children = [None for i in range(10)] diff --git a/python_payload/st3m/utils.py b/python_payload/st3m/utils.py deleted file mode 100644 index 6ba9eb4817..0000000000 --- a/python_payload/st3m/utils.py +++ /dev/null @@ -1,47 +0,0 @@ -from st3m import logging - -log = logging.Log(__name__, level=logging.INFO) -log.info("import") - -import time -from hardware import * -from st3m.system import audio - -RED = 0b1111100000000000 -GREEN = 0b0000011111100000 -BLUE = 0b0000000000011111 - - -def clear_all_leds(): - for i in range(40): - set_led_rgb(i, 0, 0, 0) - update_leds() - - -def highlight_bottom_petal(num, RED, GREEN, BLUE): - start = 4 + 8 * num - for i in range(7): - set_led_rgb(((i + start) % 40), RED, GREEN, BLUE) - update_leds() - - -def long_bottom_petal_captouch_blocking(num, ms): - if get_captouch((num * 2) + 1) == 1: - time.sleep_ms(ms) - if get_captouch((num * 2) + 1) == 1: - return True - return False - - -def draw_volume_slider(ctx, volume): - length = int(96 * volume) - - ctx.rgb(0, 0, 0) # dummy - ctx.round_rectangle(-49, 41, 98, 8, 3).fill() # dummy idk - - ctx.rgb(0, 255, 0) - ctx.round_rectangle(-51, 49, 102, 12, 3).fill() - ctx.rgb(0, 0, 0) - ctx.round_rectangle(-50, 50, 100, 10, 3).fill() - ctx.rgb(0, 255, 0) - ctx.round_rectangle(-48, 52, length, 6, 3).fill() -- GitLab