from enum import Enum, auto from dataclasses import dataclass from cinput import ControlInput, Button from graphics import Graphics class MenuType(Enum): SUB_MENU = auto() CMD = auto() EXIT_CMD = auto() PLUGIN = auto() BACK = auto() @dataclass class MenuItem: display: str menu_type: MenuType data: dict class Menu: STR_BACK = "BACK" def __init__( self, config: list[MenuItem], cinput: ControlInput, graphics: Graphics): self._top_index = 0 self._selected_index = 0 self._menu_path = list() self._menu = config self._cur_menu = self._menu self._input = cinput self._graphics = graphics def _print(self, items: list[MenuItem]): self._graphics.clear() selected_diff = self._selected_index - self._top_index if selected_diff < 0: self._top_index = self._selected_index if selected_diff >= Graphics.MAX_LINES: self._top_index = self._selected_index - Graphics.MAX_LINES + 1 for idx in range(self._top_index, self._top_index + Graphics.MAX_LINES): if idx >= len(items): break marker = "> " if idx == self._selected_index else " " self._graphics.text(marker + items[idx].display, 0, (idx - self._top_index), 1) self._graphics.show() def get_selection(self): while True: self._print(self._cur_menu) pressed = self._input.get_one_shot() if pressed == Button.DIR_U: self._selected_index -= 1 if self._selected_index < 0: self._selected_index = len(self._menu) - 1 elif pressed == Button.DIR_D: self._selected_index += 1 if self._selected_index >= len(self._menu): self._selected_index = 0 elif pressed == Button.BTN_B or pressed == Button.DIR_R: item = self._cur_menu[self._selected_index] if item.menu_type == MenuType.SUB_MENU: self._menu_path.append(self._selected_index) self._selected_index = 0 else: return item elif pressed == Button.BTN_A or pressed == Button.DIR_L: if len(self._menu_path) > 0: self._selected_index = self._menu_path.pop() else: return MenuItem(self.STR_BACK, MenuType.BACK, {}) self._cur_menu = self._menu for i in range(0, len(self._menu_path)): self._cur_menu = self._cur_menu[self._menu_path[i]].data["sub_menu"]