implemented top level menu

This commit is contained in:
Rudis Muiznieks 2022-04-23 13:37:54 -05:00
parent fbac02d6f9
commit a74caf0f0a
Signed by: rudism
GPG key ID: CABF2F86EF7884F9
6 changed files with 126 additions and 12 deletions

1
README.md Normal file
View file

@ -0,0 +1 @@
A menu-driven application launcher for a Raspberry Pi Zero with an Adafruit OLED bonnet.

41
cinput.py Normal file
View file

@ -0,0 +1,41 @@
import board
from digitalio import DigitalInOut, Direction, Pull
from enum import Enum, auto
from time import sleep
class Button(Enum):
BTN_A = auto()
BTN_B = auto()
BTN_C = auto()
DIR_U = auto()
DIR_R = auto()
DIR_D = auto()
DIR_L = auto()
class ControlInput:
_buttons = {
Button.BTN_A: DigitalInOut(board.D5),
Button.BTN_B: DigitalInOut(board.D6),
Button.BTN_C: DigitalInOut(board.D4),
Button.DIR_U: DigitalInOut(board.D17),
Button.DIR_R: DigitalInOut(board.D23),
Button.DIR_L: DigitalInOut(board.D27),
Button.DIR_D: DigitalInOut(board.D22),
}
_pressed = set()
def __init__(self):
for button in self._buttons:
self._buttons[button].direction = Direction.INPUT
self._buttons[button].pull = Pull.UP
def get_one_shot(self):
while True:
for button in self._buttons:
if not self._buttons[button].value and not button in self._pressed:
self._pressed.add(button)
return button
elif self._buttons[button].value:
self._pressed.discard(button)

BIN
font5x8.bin Normal file

Binary file not shown.

24
graphics.py Normal file
View file

@ -0,0 +1,24 @@
from board import SCL, SDA
from busio import I2C
from adafruit_ssd1306 import SSD1306_I2C
class Graphics:
OLED_WIDTH = 128
OLED_HEIGHT = 64
OLED_ADDR = 0x3C
LINE_HEIGHT = 9
MAX_LINES = 7
def __init__(self):
i2c = I2C(SCL, SDA)
self._display = SSD1306_I2C(
self.OLED_WIDTH, self.OLED_HEIGHT, i2c, addr = self.OLED_ADDR)
def clear(self):
self._display.fill(0)
def text(self, text, x, y, c):
self._display.text(text, x, y, c)
def show(self):
self._display.show()

26
main.py
View file

@ -1,4 +1,24 @@
from menu import Menu
from icecream import ic
import os
from menu import Menu, MenuItem, MenuType
from cinput import ControlInput
from graphics import Graphics
ic(Menu)
menu_config = [
MenuItem("Information",
MenuType.EXEC_PLUGIN),
MenuItem("Apps",
MenuType.SUB_MENU),
MenuItem("Reboot",
MenuType.EXEC_CMD),
MenuItem("Shutdown",
MenuType.EXEC_CMD)]
cinput = ControlInput()
graphics = Graphics()
menu = Menu(menu_config, cinput, graphics)
try:
menu.get_selection()
except KeyboardInterrupt:
graphics.clear()
graphics.show()
os._exit(0)

46
menu.py
View file

@ -1,5 +1,10 @@
from board import SCL, SDA
from busio import I2C
from adafruit_ssd1306 import SSD1306_I2C
from enum import Enum, auto
from dataclasses import dataclass
from cinput import ControlInput, Button
from graphics import Graphics
class MenuType(Enum):
SUB_MENU = auto()
@ -11,12 +16,35 @@ class MenuItem:
display: str
menu_type: MenuType
Menu = [
MenuItem("df -h",
MenuType.EXEC_CMD),
MenuItem("Chess",
MenuType.EXEC_PLUGIN),
MenuItem("Reboot",
MenuType.EXEC_CMD),
MenuItem("Shutdown",
MenuType.EXEC_CMD)]
class Menu:
def __init__(
self, config: list[MenuItem], cinput: ControlInput, graphics: Graphics):
self._selected_index = 0
self._menu = config
self._input = cinput
self._graphics = graphics
def _print(self, items: list[MenuItem]):
self._graphics.clear()
top_index = 0 if self._selected_index < Graphics.MAX_LINES else Graphics.MAX_LINES - self._selected_index + 1
for idx in range(top_index, 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 - top_index) * Graphics.LINE_HEIGHT, 1)
self._graphics.show()
def get_selection(self):
while True:
self._print(self._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