Skip to content

Commit

Permalink
Add information option to Menu widget
Browse files Browse the repository at this point in the history
  • Loading branch information
npentrel committed Jun 23, 2024
1 parent 73c0310 commit 71a4e73
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 71 deletions.
182 changes: 111 additions & 71 deletions modules/app_components/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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"
Expand Down Expand 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":
Expand Down
4 changes: 4 additions & 0 deletions modules/firmware_apps/app_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 71a4e73

Please sign in to comment.