Skip to content

Commit cec3533

Browse files
authored
Merge pull request #4 from adafruit/working_on_stuff
Several updates
2 parents 6541575 + d2d5255 commit cec3533

File tree

6 files changed

+106
-21
lines changed

6 files changed

+106
-21
lines changed

build.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
import os
2+
import time
23
import zipfile
34
import shutil
45
from pathlib import Path
6+
import requests
7+
8+
LEARN_PROJECT_URLS = [
9+
"https://cdn-learn.adafruit.com/downloads/zip/3194974/Metro/Metro_RP2350_Snake.zip?timestamp={}",
10+
"https://cdn-learn.adafruit.com/downloads/zip/3195762/Metro/Metro_RP2350_Memory/memory_game.zip?timestamp={}",
11+
"https://cdn-learn.adafruit.com/downloads/zip/3195805/Metro/Metro_RP2350_CircuitPython_Matrix.zip?timestamp={}",
12+
"https://cdn-learn.adafruit.com/downloads/zip/3194658/Metro/Metro_RP2350_FlappyNyanCat.zip?timestamp={}",
13+
"https://cdn-learn.adafruit.com/downloads/zip/3196927/Metro/Metro_RP2350_Match3/match3_game.zip?timestamp={}",
14+
"https://cdn-learn.adafruit.com/downloads/zip/3194422/Metro/Metro_RP2350_Breakout.zip?timestamp={}",
15+
# "",
16+
]
517

618
def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir: Path, output_dir: Path):
719
# Get font name without extension
@@ -53,6 +65,10 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
5365
# Skip the lib directory as we'll handle it separately
5466
if 'lib/' in path:
5567
continue
68+
if path.endswith("/"):
69+
# skip directories, they will get created by
70+
# mkdir(parents=True) below
71+
continue
5672

5773
# Get the relative path from code_dir
5874
rel_path = path[len(code_dir):]
@@ -97,7 +113,22 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
97113
# Clean up temporary directory
98114
shutil.rmtree(temp_dir, ignore_errors=True)
99115

116+
117+
def download_learn_projects():
118+
for url in LEARN_PROJECT_URLS:
119+
response = requests.get(url.format(int(time.time())), allow_redirects=True)
120+
resp_url = response.url
121+
#print(resp_url)
122+
filename = resp_url.split("/")[-1].split("?")[0]
123+
with open(f"learn-projects/{filename}", 'wb') as f:
124+
f.write(response.content)
125+
126+
100127
def main():
128+
129+
# download all learn project zips
130+
download_learn_projects()
131+
101132
# Get the project root directory
102133
root_dir = Path(__file__).parent
103134

-25.8 KB
Binary file not shown.
-58.1 KB
Binary file not shown.

src/code.py

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66
loaded by adafruit_bitmap_font
77
"""
88
import array
9+
import atexit
10+
import json
911

1012
import displayio
11-
import pathlib
13+
1214
import supervisor
1315
import sys
1416
import usb
17+
import adafruit_pathlib as pathlib
1518
from adafruit_bitmap_font import bitmap_font
1619
from adafruit_display_text.text_box import TextBox
1720
from adafruit_display_text.bitmap_label import Label
@@ -22,9 +25,14 @@
2225
from adafruit_anchored_group import AnchoredGroup
2326

2427
display = supervisor.runtime.display
28+
29+
scale = 1
30+
if display.width > 360:
31+
scale = 2
32+
2533
font_file = "/fonts/terminal.lvfontbin"
2634
font = bitmap_font.load_font(font_file)
27-
main_group = displayio.Group()
35+
main_group = displayio.Group(scale=scale)
2836
display.root_group = main_group
2937

3038
background_bmp = displayio.Bitmap(display.width, display.height, 1)
@@ -43,8 +51,8 @@
4351
mouse_tg = displayio.TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader)
4452

4553
# move it to the center of the display
46-
mouse_tg.x = display.width // 2
47-
mouse_tg.y = display.height // 2
54+
mouse_tg.x = display.width // (2 * scale)
55+
mouse_tg.y = display.height // (2 * scale)
4856
# 046d:c52f
4957

5058

@@ -98,17 +106,21 @@
98106
mouse = device
99107
print(f"mouse interface: {mouse_interface_index} endpoint_address: {hex(mouse_endpoint_address)}")
100108

109+
mouse_was_attached = None
101110
if mouse is not None:
102111
# detach the kernel driver if needed
103112
if mouse.is_kernel_driver_active(0):
113+
mouse_was_attached = True
104114
mouse.detach_kernel_driver(0)
115+
else:
116+
mouse_was_attached = False
105117

106118
# set configuration on the mouse so we can use it
107119
mouse.set_configuration()
108120

109121
mouse_buf = array.array("b", [0] * 8)
110-
WIDTH = 300
111-
HEIGHT = 192
122+
WIDTH = 280
123+
HEIGHT = 182
112124

113125
config = {
114126
"menu_title": "Launcher Menu",
@@ -152,31 +164,56 @@
152164

153165
default_icon_bmp, default_icon_palette = adafruit_imageload.load("launcher_assets/default_icon.bmp")
154166
default_icon_palette.make_transparent(0)
155-
menu_grid = GridLayout(x=10, y=26, width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
167+
menu_grid = GridLayout(x=40, y=16, width=WIDTH, height=HEIGHT, grid_size=(config["width"], config["height"]),
156168
divider_lines=False)
157169
main_group.append(menu_grid)
158170

159171
menu_title_txt = Label(font, text=config["menu_title"])
160172
menu_title_txt.anchor_point = (0.5, 0.5)
161-
menu_title_txt.anchored_position = (display.width // 2, 2)
173+
menu_title_txt.anchored_position = (display.width // (2 * scale), 2)
162174
main_group.append(menu_title_txt)
163175

164176
app_titles = []
165177
apps = []
166178
app_path = pathlib.Path("/apps")
167179
i = 0
180+
181+
pages = [{}]
182+
183+
cur_file_index = 0
184+
cur_page = 0
168185
for path in app_path.iterdir():
169186
print(path)
187+
cell_group = AnchoredGroup()
188+
170189
code_file = path / "code.py"
171190
if not code_file.exists():
172191
continue
173-
cell_group = AnchoredGroup()
174-
icon_file = path / "icon.bmp"
192+
193+
metadata_file = path / "metadata.json"
194+
if not metadata_file.exists():
195+
metadata_file = None
196+
metadata = None
197+
if metadata_file is not None:
198+
with open(metadata_file.absolute(), "r") as f:
199+
metadata = json.load(f)
200+
201+
if metadata is not None and "icon" in metadata:
202+
icon_file = path / metadata["icon"]
203+
else:
204+
icon_file = path / "icon.bmp"
205+
175206
if not icon_file.exists():
176207
icon_file = None
208+
209+
if metadata is not None and "title" in metadata:
210+
title = metadata["title"]
211+
else:
212+
title = path.name
213+
177214
apps.append({
178-
"title": path.name,
179-
"icon": str(icon_file.absolute()),
215+
"title": title,
216+
"icon": str(icon_file.absolute()) if icon_file is not None else None,
180217
"file": str(code_file.absolute())
181218
})
182219
if apps[-1]["icon"] is None:
@@ -203,12 +240,12 @@
203240
right_palette.make_transparent(0)
204241

205242
left_tg = AnchoredTileGrid(bitmap=left_bmp, pixel_shader=left_palette)
206-
left_tg.anchor_point = (0, 1.0)
207-
left_tg.anchored_position = (10, display.height - 2)
243+
left_tg.anchor_point = (0, 0.5)
244+
left_tg.anchored_position = (4, (display.height // 2 // scale) - 2)
208245

209246
right_tg = AnchoredTileGrid(bitmap=right_bmp, pixel_shader=right_palette)
210-
right_tg.anchor_point = (1.0, 1.0)
211-
right_tg.anchored_position = (display.width - 10, display.height - 2)
247+
right_tg.anchor_point = (1.0, 0.5)
248+
right_tg.anchored_position = ((display.width // scale) - 4, (display.height // 2 // scale) - 2)
212249

213250
main_group.append(left_tg)
214251
main_group.append(right_tg)
@@ -217,6 +254,20 @@
217254
main_group.append(mouse_tg)
218255

219256
selected = 0
257+
258+
259+
def atexit_callback():
260+
"""
261+
re-attach USB devices to kernel if needed.
262+
:return:
263+
"""
264+
print("inside atexit callback")
265+
if mouse_was_attached and not mouse.is_kernel_driver_active(0):
266+
mouse.attach_kernel_driver(0)
267+
268+
atexit.register(atexit_callback)
269+
270+
# print(f"apps: {apps}")
220271
while True:
221272
index = None
222273

@@ -241,25 +292,28 @@
241292
# attempt to read data from the mouse
242293
# 10ms timeout, so we don't block long if there
243294
# is no data
244-
count = mouse.read(mouse_endpoint_address, mouse_buf, timeout=10)
295+
count = mouse.read(mouse_endpoint_address, mouse_buf, timeout=20)
245296
except usb.core.USBTimeoutError:
246297
# skip the rest of the loop if there is no data
247298
count = 0
248299

249300
# update the mouse tilegrid x and y coordinates
250301
# based on the delta values read from the mouse
251302
if count > 0:
252-
mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + mouse_buf[1]))
253-
mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + mouse_buf[2]))
303+
mouse_tg.x = max(0, min((display.width // scale) - 1, mouse_tg.x + mouse_buf[1]))
304+
mouse_tg.y = max(0, min((display.height // scale) - 1, mouse_tg.y + mouse_buf[2]))
254305

255306
if mouse_buf[0] & (1 << 0) != 0:
256307
clicked_cell = menu_grid.which_cell_contains((mouse_tg.x, mouse_tg.y))
257308
if clicked_cell is not None:
258309
index = clicked_cell[1] * config["width"] + clicked_cell[0]
259310

260311
if index is not None:
261-
supervisor.set_next_code_file(config["apps"][index]["file"], sticky_on_reload=True, reload_on_error=True,
262-
working_directory="/apps/matrix")
312+
# print("index", index)
313+
# print(f"selected: {apps[index]}")
314+
launch_file = apps[index]["file"]
315+
supervisor.set_next_code_file(launch_file, sticky_on_reload=True, reload_on_error=True,
316+
working_directory="/".join(launch_file.split("/")[:-1]))
263317

264318
if mouse and not mouse.is_kernel_driver_active(0):
265319
mouse.attach_kernel_driver(0)

src/launcher_assets/arrow_left.bmp

-1.45 KB
Binary file not shown.
-1.45 KB
Binary file not shown.

0 commit comments

Comments
 (0)