commit
cec3533a3a
6 changed files with 106 additions and 21 deletions
31
build.py
31
build.py
|
|
@ -1,7 +1,19 @@
|
|||
import os
|
||||
import time
|
||||
import zipfile
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import requests
|
||||
|
||||
LEARN_PROJECT_URLS = [
|
||||
"https://cdn-learn.adafruit.com/downloads/zip/3194974/Metro/Metro_RP2350_Snake.zip?timestamp={}",
|
||||
"https://cdn-learn.adafruit.com/downloads/zip/3195762/Metro/Metro_RP2350_Memory/memory_game.zip?timestamp={}",
|
||||
"https://cdn-learn.adafruit.com/downloads/zip/3195805/Metro/Metro_RP2350_CircuitPython_Matrix.zip?timestamp={}",
|
||||
"https://cdn-learn.adafruit.com/downloads/zip/3194658/Metro/Metro_RP2350_FlappyNyanCat.zip?timestamp={}",
|
||||
"https://cdn-learn.adafruit.com/downloads/zip/3196927/Metro/Metro_RP2350_Match3/match3_game.zip?timestamp={}",
|
||||
"https://cdn-learn.adafruit.com/downloads/zip/3194422/Metro/Metro_RP2350_Breakout.zip?timestamp={}",
|
||||
# "",
|
||||
]
|
||||
|
||||
def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir: Path, output_dir: Path):
|
||||
# Get font name without extension
|
||||
|
|
@ -53,6 +65,10 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
|
|||
# Skip the lib directory as we'll handle it separately
|
||||
if 'lib/' in path:
|
||||
continue
|
||||
if path.endswith("/"):
|
||||
# skip directories, they will get created by
|
||||
# mkdir(parents=True) below
|
||||
continue
|
||||
|
||||
# Get the relative path from code_dir
|
||||
rel_path = path[len(code_dir):]
|
||||
|
|
@ -97,7 +113,22 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
|
|||
# Clean up temporary directory
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def download_learn_projects():
|
||||
for url in LEARN_PROJECT_URLS:
|
||||
response = requests.get(url.format(int(time.time())), allow_redirects=True)
|
||||
resp_url = response.url
|
||||
#print(resp_url)
|
||||
filename = resp_url.split("/")[-1].split("?")[0]
|
||||
with open(f"learn-projects/{filename}", 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# download all learn project zips
|
||||
download_learn_projects()
|
||||
|
||||
# Get the project root directory
|
||||
root_dir = Path(__file__).parent
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
96
src/code.py
96
src/code.py
|
|
@ -6,12 +6,15 @@ This example uses adafruit_display_text.label to display text using a custom fon
|
|||
loaded by adafruit_bitmap_font
|
||||
"""
|
||||
import array
|
||||
import atexit
|
||||
import json
|
||||
|
||||
import displayio
|
||||
import pathlib
|
||||
|
||||
import supervisor
|
||||
import sys
|
||||
import usb
|
||||
import adafruit_pathlib as pathlib
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
from adafruit_display_text.text_box import TextBox
|
||||
from adafruit_display_text.bitmap_label import Label
|
||||
|
|
@ -22,9 +25,14 @@ import adafruit_usb_host_descriptors
|
|||
from adafruit_anchored_group import AnchoredGroup
|
||||
|
||||
display = supervisor.runtime.display
|
||||
|
||||
scale = 1
|
||||
if display.width > 360:
|
||||
scale = 2
|
||||
|
||||
font_file = "/fonts/terminal.lvfontbin"
|
||||
font = bitmap_font.load_font(font_file)
|
||||
main_group = displayio.Group()
|
||||
main_group = displayio.Group(scale=scale)
|
||||
display.root_group = main_group
|
||||
|
||||
background_bmp = displayio.Bitmap(display.width, display.height, 1)
|
||||
|
|
@ -43,8 +51,8 @@ mouse_bmp.pixel_shader.make_transparent(0)
|
|||
mouse_tg = displayio.TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader)
|
||||
|
||||
# move it to the center of the display
|
||||
mouse_tg.x = display.width // 2
|
||||
mouse_tg.y = display.height // 2
|
||||
mouse_tg.x = display.width // (2 * scale)
|
||||
mouse_tg.y = display.height // (2 * scale)
|
||||
# 046d:c52f
|
||||
|
||||
|
||||
|
|
@ -98,17 +106,21 @@ for device in usb.core.find(find_all=True):
|
|||
mouse = device
|
||||
print(f"mouse interface: {mouse_interface_index} endpoint_address: {hex(mouse_endpoint_address)}")
|
||||
|
||||
mouse_was_attached = None
|
||||
if mouse is not None:
|
||||
# detach the kernel driver if needed
|
||||
if mouse.is_kernel_driver_active(0):
|
||||
mouse_was_attached = True
|
||||
mouse.detach_kernel_driver(0)
|
||||
else:
|
||||
mouse_was_attached = False
|
||||
|
||||
# set configuration on the mouse so we can use it
|
||||
mouse.set_configuration()
|
||||
|
||||
mouse_buf = array.array("b", [0] * 8)
|
||||
WIDTH = 300
|
||||
HEIGHT = 192
|
||||
WIDTH = 280
|
||||
HEIGHT = 182
|
||||
|
||||
config = {
|
||||
"menu_title": "Launcher Menu",
|
||||
|
|
@ -152,31 +164,56 @@ cell_width = WIDTH // config["width"]
|
|||
|
||||
default_icon_bmp, default_icon_palette = adafruit_imageload.load("launcher_assets/default_icon.bmp")
|
||||
default_icon_palette.make_transparent(0)
|
||||
menu_grid = GridLayout(x=10, y=26, width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
|
||||
menu_grid = GridLayout(x=40, y=16, width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
|
||||
divider_lines=False)
|
||||
main_group.append(menu_grid)
|
||||
|
||||
menu_title_txt = Label(font, text=config["menu_title"])
|
||||
menu_title_txt.anchor_point = (0.5, 0.5)
|
||||
menu_title_txt.anchored_position = (display.width // 2, 2)
|
||||
menu_title_txt.anchored_position = (display.width // (2 * scale), 2)
|
||||
main_group.append(menu_title_txt)
|
||||
|
||||
app_titles = []
|
||||
apps = []
|
||||
app_path = pathlib.Path("/apps")
|
||||
i = 0
|
||||
|
||||
pages = [{}]
|
||||
|
||||
cur_file_index = 0
|
||||
cur_page = 0
|
||||
for path in app_path.iterdir():
|
||||
print(path)
|
||||
cell_group = AnchoredGroup()
|
||||
|
||||
code_file = path / "code.py"
|
||||
if not code_file.exists():
|
||||
continue
|
||||
cell_group = AnchoredGroup()
|
||||
icon_file = path / "icon.bmp"
|
||||
|
||||
metadata_file = path / "metadata.json"
|
||||
if not metadata_file.exists():
|
||||
metadata_file = None
|
||||
metadata = None
|
||||
if metadata_file is not None:
|
||||
with open(metadata_file.absolute(), "r") as f:
|
||||
metadata = json.load(f)
|
||||
|
||||
if metadata is not None and "icon" in metadata:
|
||||
icon_file = path / metadata["icon"]
|
||||
else:
|
||||
icon_file = path / "icon.bmp"
|
||||
|
||||
if not icon_file.exists():
|
||||
icon_file = None
|
||||
|
||||
if metadata is not None and "title" in metadata:
|
||||
title = metadata["title"]
|
||||
else:
|
||||
title = path.name
|
||||
|
||||
apps.append({
|
||||
"title": path.name,
|
||||
"icon": str(icon_file.absolute()),
|
||||
"title": title,
|
||||
"icon": str(icon_file.absolute()) if icon_file is not None else None,
|
||||
"file": str(code_file.absolute())
|
||||
})
|
||||
if apps[-1]["icon"] is None:
|
||||
|
|
@ -203,12 +240,12 @@ right_bmp, right_palette = adafruit_imageload.load("launcher_assets/arrow_right.
|
|||
right_palette.make_transparent(0)
|
||||
|
||||
left_tg = AnchoredTileGrid(bitmap=left_bmp, pixel_shader=left_palette)
|
||||
left_tg.anchor_point = (0, 1.0)
|
||||
left_tg.anchored_position = (10, display.height - 2)
|
||||
left_tg.anchor_point = (0, 0.5)
|
||||
left_tg.anchored_position = (4, (display.height // 2 // scale) - 2)
|
||||
|
||||
right_tg = AnchoredTileGrid(bitmap=right_bmp, pixel_shader=right_palette)
|
||||
right_tg.anchor_point = (1.0, 1.0)
|
||||
right_tg.anchored_position = (display.width - 10, display.height - 2)
|
||||
right_tg.anchor_point = (1.0, 0.5)
|
||||
right_tg.anchored_position = ((display.width // scale) - 4, (display.height // 2 // scale) - 2)
|
||||
|
||||
main_group.append(left_tg)
|
||||
main_group.append(right_tg)
|
||||
|
|
@ -217,6 +254,20 @@ if mouse:
|
|||
main_group.append(mouse_tg)
|
||||
|
||||
selected = 0
|
||||
|
||||
|
||||
def atexit_callback():
|
||||
"""
|
||||
re-attach USB devices to kernel if needed.
|
||||
:return:
|
||||
"""
|
||||
print("inside atexit callback")
|
||||
if mouse_was_attached and not mouse.is_kernel_driver_active(0):
|
||||
mouse.attach_kernel_driver(0)
|
||||
|
||||
atexit.register(atexit_callback)
|
||||
|
||||
# print(f"apps: {apps}")
|
||||
while True:
|
||||
index = None
|
||||
|
||||
|
|
@ -241,7 +292,7 @@ while True:
|
|||
# attempt to read data from the mouse
|
||||
# 10ms timeout, so we don't block long if there
|
||||
# is no data
|
||||
count = mouse.read(mouse_endpoint_address, mouse_buf, timeout=10)
|
||||
count = mouse.read(mouse_endpoint_address, mouse_buf, timeout=20)
|
||||
except usb.core.USBTimeoutError:
|
||||
# skip the rest of the loop if there is no data
|
||||
count = 0
|
||||
|
|
@ -249,8 +300,8 @@ while True:
|
|||
# update the mouse tilegrid x and y coordinates
|
||||
# based on the delta values read from the mouse
|
||||
if count > 0:
|
||||
mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + mouse_buf[1]))
|
||||
mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + mouse_buf[2]))
|
||||
mouse_tg.x = max(0, min((display.width // scale) - 1, mouse_tg.x + mouse_buf[1]))
|
||||
mouse_tg.y = max(0, min((display.height // scale) - 1, mouse_tg.y + mouse_buf[2]))
|
||||
|
||||
if mouse_buf[0] & (1 << 0) != 0:
|
||||
clicked_cell = menu_grid.which_cell_contains((mouse_tg.x, mouse_tg.y))
|
||||
|
|
@ -258,8 +309,11 @@ while True:
|
|||
index = clicked_cell[1] * config["width"] + clicked_cell[0]
|
||||
|
||||
if index is not None:
|
||||
supervisor.set_next_code_file(config["apps"][index]["file"], sticky_on_reload=True, reload_on_error=True,
|
||||
working_directory="/apps/matrix")
|
||||
# print("index", index)
|
||||
# print(f"selected: {apps[index]}")
|
||||
launch_file = apps[index]["file"]
|
||||
supervisor.set_next_code_file(launch_file, sticky_on_reload=True, reload_on_error=True,
|
||||
working_directory="/".join(launch_file.split("/")[:-1]))
|
||||
|
||||
if mouse and not mouse.is_kernel_driver_active(0):
|
||||
mouse.attach_kernel_driver(0)
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 918 B |
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 918 B |
Loading…
Reference in a new issue