feat: menu demo
This commit is contained in:
@@ -5,6 +5,7 @@ from time import sleep, time_ns
|
|||||||
|
|
||||||
from machine import SPI, Pin
|
from machine import SPI, Pin
|
||||||
|
|
||||||
|
from encoder import Encoder
|
||||||
from ili9341 import Display, color565
|
from ili9341 import Display, color565
|
||||||
|
|
||||||
colors = {
|
colors = {
|
||||||
@@ -18,6 +19,12 @@ colors = {
|
|||||||
"NAVY": (0, 0, 128),
|
"NAVY": (0, 0, 128),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu = [
|
||||||
|
"Option 1",
|
||||||
|
"Option 2",
|
||||||
|
"Option 3",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def display():
|
def display():
|
||||||
bg = Pin(33, Pin.OUT)
|
bg = Pin(33, Pin.OUT)
|
||||||
@@ -26,70 +33,80 @@ def display():
|
|||||||
|
|
||||||
bg.on()
|
bg.on()
|
||||||
|
|
||||||
while True:
|
encoder_a = Pin(2, Pin.IN, Pin.PULL_UP)
|
||||||
|
encoder_b = Pin(4, Pin.IN, Pin.PULL_UP)
|
||||||
|
|
||||||
|
def draw_debug_text(text: str, y: int):
|
||||||
display.draw_text8x8(
|
display.draw_text8x8(
|
||||||
10,
|
10,
|
||||||
10,
|
y,
|
||||||
"ILI9341 Display Test",
|
text,
|
||||||
color565(255, 255, 255),
|
color565(255, 255, 255),
|
||||||
color565(0, 0, 0),
|
color565(0, 0, 0),
|
||||||
270,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
last_registered: int = time_ns()
|
||||||
|
|
||||||
|
menu_index = 0
|
||||||
|
|
||||||
|
def handle_button_pres(dir: str):
|
||||||
|
nonlocal last_registered
|
||||||
|
nonlocal menu_index
|
||||||
|
|
||||||
|
if (time_ns() - last_registered) < 100000000:
|
||||||
|
return
|
||||||
|
|
||||||
|
last_registered = time_ns()
|
||||||
|
|
||||||
|
if dir == "Left":
|
||||||
|
menu_index = (menu_index - 1) % 3
|
||||||
|
elif dir == "Right":
|
||||||
|
menu_index = (menu_index + 1) % 3
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
refresh_display()
|
||||||
|
|
||||||
|
encoder = Encoder(
|
||||||
|
encoder_a,
|
||||||
|
encoder_b,
|
||||||
|
on_left=lambda x: handle_button_pres("Left"),
|
||||||
|
on_right=lambda x: handle_button_pres("Right"),
|
||||||
|
)
|
||||||
|
|
||||||
|
display.clear(color=color565(*colors["BLUE"]))
|
||||||
|
|
||||||
display.draw_text8x8(
|
display.draw_text8x8(
|
||||||
10,
|
10,
|
||||||
280,
|
10,
|
||||||
|
"Menu:",
|
||||||
|
color565(255, 255, 255),
|
||||||
|
color565(0, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
display.draw_text8x8(
|
||||||
|
230 - (8 * 4),
|
||||||
|
10,
|
||||||
"PPAP",
|
"PPAP",
|
||||||
color565(255, 255, 255),
|
color565(255, 255, 255),
|
||||||
color565(0, 0, 0),
|
color565(0, 0, 0),
|
||||||
270,
|
|
||||||
)
|
)
|
||||||
sleep(1)
|
|
||||||
# Calculate valid hlines parameters for display clear method
|
|
||||||
valid_hlines = []
|
|
||||||
for i in range(1, display.height):
|
|
||||||
if display.height % i == 0:
|
|
||||||
valid_hlines.append(i)
|
|
||||||
# Ensure only 13 entries, truncate or repeat the last one
|
|
||||||
valid_hlines = valid_hlines[:8]
|
|
||||||
if len(valid_hlines) < 8:
|
|
||||||
valid_hlines += [valid_hlines[-1]] * (8 - len(valid_hlines))
|
|
||||||
# Ensure only 13 entries, truncate or repeat the last one
|
|
||||||
valid_hlines = valid_hlines[:8]
|
|
||||||
if len(valid_hlines) < 8:
|
|
||||||
valid_hlines += [valid_hlines[-1]] * (8 - len(valid_hlines))
|
|
||||||
|
|
||||||
print("Clearing to black...")
|
def get_cursor(line: int):
|
||||||
start = time_ns()
|
nonlocal menu_index
|
||||||
display.clear()
|
if line == menu_index:
|
||||||
end = time_ns()
|
return "> "
|
||||||
print(f"Display cleared in {end - start} ms.")
|
else:
|
||||||
sleep(2)
|
return " "
|
||||||
|
|
||||||
print("Clearing to white...")
|
def refresh_display():
|
||||||
start = time_ns()
|
for i, line in enumerate(menu):
|
||||||
display.clear(color565(255, 255, 255))
|
|
||||||
end = time_ns()
|
|
||||||
print(f"Display cleared in {end - start} ms.")
|
|
||||||
sleep(2)
|
|
||||||
|
|
||||||
for hlines, (color, rgb) in zip(valid_hlines, colors.items()):
|
|
||||||
display.draw_text8x8(
|
display.draw_text8x8(
|
||||||
10,
|
10,
|
||||||
10,
|
18 + (i + 1) * 8,
|
||||||
f"Next color: {color}",
|
get_cursor(i) + line,
|
||||||
color565(255, 255, 255),
|
color565(255, 255, 255),
|
||||||
color565(0, 0, 0),
|
color565(0, 0, 0),
|
||||||
270,
|
|
||||||
)
|
)
|
||||||
sleep(1)
|
|
||||||
print(f"Clearing display to {color}, hlines={hlines}...")
|
|
||||||
try:
|
|
||||||
start = time_ns()
|
|
||||||
display.clear(hlines=hlines, color=color565(*rgb))
|
|
||||||
end = time_ns()
|
|
||||||
print(f"Display cleared in {end - start} ms.")
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
sleep(1)
|
|
||||||
|
|
||||||
sleep(5)
|
refresh_display()
|
||||||
|
|||||||
10
encoder.py
Normal file
10
encoder.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from machine import Pin
|
||||||
|
|
||||||
|
|
||||||
|
class Encoder:
|
||||||
|
def __init__(self, pin_a: Pin, pin_b: Pin, on_left, on_right) -> None:
|
||||||
|
self.pin_a = pin_a
|
||||||
|
self.pin_b = pin_b
|
||||||
|
pin_a.irq(trigger=Pin.IRQ_RISING, handler=on_left)
|
||||||
|
pin_b.irq(trigger=Pin.IRQ_RISING, handler=on_right)
|
||||||
|
pass
|
||||||
4
main.py
4
main.py
@@ -13,5 +13,5 @@ import led_program
|
|||||||
import motor
|
import motor
|
||||||
|
|
||||||
# _thread.start_new_thread(led_program.boostrap, ())
|
# _thread.start_new_thread(led_program.boostrap, ())
|
||||||
# _thread.start_new_thread(display_program.display, ())
|
_thread.start_new_thread(display_program.display, ())
|
||||||
_thread.start_new_thread(motor.motor_run, ())
|
# _thread.start_new_thread(motor.motor_run, ())
|
||||||
|
|||||||
76
menu.py
Normal file
76
menu.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
from this import d
|
||||||
|
|
||||||
|
from ili9341 import Display, color565
|
||||||
|
|
||||||
|
|
||||||
|
class MenuItem:
|
||||||
|
def __init__(self, name: str, navigate: str):
|
||||||
|
self.name = name
|
||||||
|
self.navigate = navigate
|
||||||
|
|
||||||
|
|
||||||
|
class MenuPage:
|
||||||
|
UP = 0
|
||||||
|
DOWN = 1
|
||||||
|
|
||||||
|
def __init__(self, title: str, item: list[MenuItem]):
|
||||||
|
self.title = title
|
||||||
|
self.items = item
|
||||||
|
self.items.append(MenuItem("Back", "Root"))
|
||||||
|
self.cursor = 0
|
||||||
|
|
||||||
|
def size(self) -> int:
|
||||||
|
return len(self.items)
|
||||||
|
|
||||||
|
def move(self, direction: int):
|
||||||
|
match direction:
|
||||||
|
case self.UP:
|
||||||
|
self.cursor = (self.cursor + 1) % self.size()
|
||||||
|
case self.DOWN:
|
||||||
|
self.cursor = (self.cursor - 1) % self.size()
|
||||||
|
|
||||||
|
def draw(self) -> str:
|
||||||
|
|
||||||
|
lines: list[str] = []
|
||||||
|
|
||||||
|
for i, item in enumerate(self.items):
|
||||||
|
if i == self.cursor:
|
||||||
|
lines.append("> {item.name}\n")
|
||||||
|
else:
|
||||||
|
lines.append(" {item.name}\n")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def current_at_cursor(self, cursor: int) -> MenuItem:
|
||||||
|
return self.items[cursor]
|
||||||
|
|
||||||
|
|
||||||
|
class DisplayMenu:
|
||||||
|
def __init__(self, display: Display, pages: list[MenuPage]):
|
||||||
|
self.display = display
|
||||||
|
self.pages = pages
|
||||||
|
self.cursor = 0
|
||||||
|
self.current_page = self.pages[0]
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def __draw_display_line(self, line: str, offset: int):
|
||||||
|
self.display.draw_text8x8(
|
||||||
|
10,
|
||||||
|
10 + (offset * 8),
|
||||||
|
line,
|
||||||
|
color565(255, 255, 255),
|
||||||
|
color565(0, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
def move_up(self):
|
||||||
|
self.current_page.move(MenuPage.UP)
|
||||||
|
|
||||||
|
def move_down(self):
|
||||||
|
self.current_page.move(MenuPage.DOWN)
|
||||||
|
|
||||||
|
def select(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.__draw_display_line(self.current_page.title, 0)
|
||||||
|
self.__draw_display_line(self.current_page.draw(), 2)
|
||||||
Reference in New Issue
Block a user