implemented top level menu
This commit is contained in:
parent
fbac02d6f9
commit
a74caf0f0a
|
@ -0,0 +1 @@
|
||||||
|
A menu-driven application launcher for a Raspberry Pi Zero with an Adafruit OLED bonnet.
|
|
@ -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)
|
||||||
|
|
Binary file not shown.
|
@ -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
26
main.py
|
@ -1,4 +1,24 @@
|
||||||
from menu import Menu
|
import os
|
||||||
from icecream import ic
|
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
46
menu.py
|
@ -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 enum import Enum, auto
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from cinput import ControlInput, Button
|
||||||
|
from graphics import Graphics
|
||||||
|
|
||||||
class MenuType(Enum):
|
class MenuType(Enum):
|
||||||
SUB_MENU = auto()
|
SUB_MENU = auto()
|
||||||
|
@ -11,12 +16,35 @@ class MenuItem:
|
||||||
display: str
|
display: str
|
||||||
menu_type: MenuType
|
menu_type: MenuType
|
||||||
|
|
||||||
Menu = [
|
class Menu:
|
||||||
MenuItem("df -h",
|
def __init__(
|
||||||
MenuType.EXEC_CMD),
|
self, config: list[MenuItem], cinput: ControlInput, graphics: Graphics):
|
||||||
MenuItem("Chess",
|
self._selected_index = 0
|
||||||
MenuType.EXEC_PLUGIN),
|
self._menu = config
|
||||||
MenuItem("Reboot",
|
self._input = cinput
|
||||||
MenuType.EXEC_CMD),
|
self._graphics = graphics
|
||||||
MenuItem("Shutdown",
|
|
||||||
MenuType.EXEC_CMD)]
|
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
|
||||||
|
|
Reference in New Issue