diff --git a/modules/app_components/menu.py b/modules/app_components/menu.py index 05ccefa..9c468e0 100644 --- a/modules/app_components/menu.py +++ b/modules/app_components/menu.py @@ -4,7 +4,14 @@ from events.input import BUTTON_TYPES, ButtonDownEvent from system.eventbus import eventbus -from .tokens import heading_font_size, label_font_size, line_height, set_color +from .tokens import ( + heading_font_size, + label_font_size, + line_height, + set_color, + clear_background, +) +from .layout import TextDisplay, LinearLayout def ease_out_quart(x): @@ -16,6 +23,7 @@ def __init__( self, app: App, menu_items: list[str] = [], + info_items: list[str] = [], position=0, select_handler: Union[Callable[[str, int], Any], None] = None, change_handler: Union[Callable[[str], Any], None] = None, @@ -28,6 +36,7 @@ def __init__( ): self.app = app self.menu_items = menu_items + self.info_items = info_items self.position = position self.select_handler = select_handler self.change_handler = change_handler @@ -38,38 +47,58 @@ def __init__( self.focused_item_font_size = focused_item_font_size self.focused_item_margin = focused_item_margin self.focused_item_font_size_arr = [] + self.layout = LinearLayout(items=[]) + self.show_info = False self.animation_time_ms = 0 # self.is_animating: Literal["up", "down", "none"] = "none" self.is_animating: Literal["up", "down", "none"] = "up" - eventbus.on(ButtonDownEvent, self._handle_buttondown, app) + eventbus.on_async(ButtonDownEvent, self._handle_buttondown, app) def _cleanup(self): eventbus.remove(ButtonDownEvent, self._handle_buttondown, self.app) - def _handle_buttondown(self, event: ButtonDownEvent): + async def _handle_buttondown(self, event: ButtonDownEvent): if BUTTON_TYPES["UP"] in event.button: - self.up_handler() - if self.change_handler is not None: - self.change_handler( - self.menu_items[self.position % len(self.menu_items)] - ) + if self.show_info: + await self.layout.button_event(event) + else: + self.up_handler() + if self.change_handler is not None: + self.change_handler( + self.menu_items[self.position % len(self.menu_items)] + ) if BUTTON_TYPES["DOWN"] in event.button: - self.down_handler() - if self.change_handler is not None: - self.change_handler( - self.menu_items[self.position % len(self.menu_items)] - ) + if self.show_info: + await self.layout.button_event(event) + else: + self.down_handler() + if self.change_handler is not None: + self.change_handler( + self.menu_items[self.position % len(self.menu_items)] + ) if BUTTON_TYPES["CANCEL"] in event.button: - if self.back_handler is not None: - self.back_handler() + if self.show_info: + self.show_info = False + else: + if self.back_handler is not None: + self.back_handler() if BUTTON_TYPES["CONFIRM"] in event.button: + self.show_info = False if self.select_handler is not None: self.select_handler( self.menu_items[self.position % len(self.menu_items)], self.position % len(self.menu_items), ) + if BUTTON_TYPES["RIGHT"] in event.button: + self.layout.items = [] + entry = TextDisplay(self.info_items[self.position % len(self.menu_items)]) + self.layout.items.append(entry) + self.show_info = True + if BUTTON_TYPES["LEFT"] in event.button: + self.layout.items = [] + self.show_info = False def up_handler(self): self.is_animating = "up" @@ -100,62 +129,73 @@ def _calculate_max_focussed_font_size(self, item, ctx): return proposed_font_size def draw(self, ctx): - # calculate biggest font size a menu item should grow to - if not self.focused_item_font_size_arr: - for item in self.menu_items: - fs = self._calculate_max_focussed_font_size(item, ctx) - self.focused_item_font_size_arr = self.focused_item_font_size_arr + [fs] - - animation_progress = ease_out_quart(self.animation_time_ms / self.speed_ms) - animation_direction = 1 if self.is_animating == "up" else -1 - - ctx.text_align = ctx.CENTER - ctx.text_baseline = ctx.MIDDLE - - set_color(ctx, "label") - num_menu_items = len(self.menu_items) - - # Current menu item - ctx.font_size = self.item_font_size + animation_progress * ( - self.focused_item_font_size_arr[ - self.position % num_menu_items if num_menu_items > 0 else 1 - ] - - self.item_font_size - ) - - label = "" - try: - label = self.menu_items[ - self.position % num_menu_items if num_menu_items > 0 else 1 - ] - except IndexError: - label = "Empty Menu" - ctx.move_to( - 0, animation_direction * -30 + animation_progress * animation_direction * 30 - ).text(label) - - # Previous menu items - ctx.font_size = self.item_font_size - for i in range(1, 4): - if (self.position - i) >= 0 and len(self.menu_items): - ctx.move_to( - 0, - -self.focused_item_margin - + -i * self.item_line_height - - animation_direction * 30 - + animation_progress * animation_direction * 30, - ).text(self.menu_items[self.position - i]) - - # Next menu items - for i in range(1, 4): - if (self.position + i) < len(self.menu_items): - ctx.move_to( - 0, - self.focused_item_margin - + i * self.item_line_height - - animation_direction * 30 - + animation_progress * animation_direction * 30, - ).text(self.menu_items[self.position + i]) + if self.show_info and self.info_items: + # show info for item + ctx.save() + clear_background(ctx) + self.layout.draw(ctx) + ctx.restore() + else: + # calculate biggest font size a menu item should grow to + if not self.focused_item_font_size_arr: + for item in self.menu_items: + fs = self._calculate_max_focussed_font_size(item, ctx) + self.focused_item_font_size_arr = ( + self.focused_item_font_size_arr + [fs] + ) + + animation_progress = ease_out_quart(self.animation_time_ms / self.speed_ms) + animation_direction = 1 if self.is_animating == "up" else -1 + + ctx.text_align = ctx.CENTER + ctx.text_baseline = ctx.MIDDLE + + set_color(ctx, "label") + num_menu_items = len(self.menu_items) + + # Current menu item + ctx.font_size = self.item_font_size + animation_progress * ( + self.focused_item_font_size_arr[ + self.position % num_menu_items if num_menu_items > 0 else 1 + ] + - self.item_font_size + ) + + label = "" + try: + label = self.menu_items[ + self.position % num_menu_items if num_menu_items > 0 else 1 + ] + except IndexError: + label = "Empty Menu" + ctx.move_to( + 0, + animation_direction * -30 + + animation_progress * animation_direction * 30, + ).text(label) + + # Previous menu items + ctx.font_size = self.item_font_size + for i in range(1, 4): + if (self.position - i) >= 0 and len(self.menu_items): + ctx.move_to( + 0, + -self.focused_item_margin + + -i * self.item_line_height + - animation_direction * 30 + + animation_progress * animation_direction * 30, + ).text(self.menu_items[self.position - i]) + + # Next menu items + for i in range(1, 4): + if (self.position + i) < len(self.menu_items): + ctx.move_to( + 0, + self.focused_item_margin + + i * self.item_line_height + - animation_direction * 30 + + animation_progress * animation_direction * 30, + ).text(self.menu_items[self.position + i]) def update(self, delta): if self.is_animating != "none": diff --git a/modules/firmware_apps/app_store.py b/modules/firmware_apps/app_store.py index 70e083f..158ce63 100644 --- a/modules/firmware_apps/app_store.py +++ b/modules/firmware_apps/app_store.py @@ -144,6 +144,10 @@ def exit_available_menu(): self.available_menu = Menu( self, menu_items=[app["manifest"]["app"]["name"] for app in self.app_store_index], + info_items=[ + app["manifest"]["metadata"]["description"] + for app in self.app_store_index + ], select_handler=on_select, back_handler=exit_available_menu, focused_item_font_size=fourteen_pt,