78 lines
2.6 KiB
Python
78 lines
2.6 KiB
Python
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"]
|