Compare commits

...

8 commits
1.0.9 ... main

Author SHA1 Message Date
foamyguy
508a0f5b87
Merge pull request #66 from FoamyGuy/order_app_icons
Some checks failed
Validate Build / validate-build (push) Has been cancelled
sort app icons by title. Remove unused iterator var
2025-08-22 11:46:37 -05:00
foamyguy
c24e40fd3f sort app icons by title. Remove unused iterator var 2025-08-22 11:42:23 -05:00
foamyguy
d96ee58a58
Merge pull request #64 from FoamyGuy/launcher_layout
Some checks failed
Validate Build / validate-build (push) Has been cancelled
Launcher layout improvements
2025-08-21 11:18:04 -05:00
foamyguy
a2253d6d5c
Merge pull request #63 from RetiredWizard/fruitjamaddminesw
Add PyPaint to included apps
2025-08-21 11:16:30 -05:00
foamyguy
13f6751504 more narrow arrow buttons. more room for app icon grid. move help text to single row at bottom. remove leftover hardcoded apps list. 2025-08-21 11:07:29 -05:00
RetiredWizard
bbbe417f6f Add PyPaint to included apps 2025-08-21 10:52:21 -04:00
foamyguy
f9ce279198
Merge pull request #53 from FoamyGuy/use_learn_repo
Some checks failed
Validate Build / validate-build (push) Has been cancelled
use learn repo instead of bundle zip URLs.
2025-08-19 13:40:49 -05:00
foamyguy
28cdd13f5c use learn repo instead of bundle zip URLs. 2025-08-14 12:11:02 -05:00
5 changed files with 37 additions and 127 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
dist
latest_dl
Adafruit_Learning_System_Guides

114
build.py
View file

@ -1,26 +1,25 @@
from datetime import datetime
import os
import time
import zipfile
import shutil
from pathlib import Path
import requests
from circup.commands import main as circup_cli
# TODO: maybe change these to use the first URLs i.e. https://learn.adafruit.com/elements/3198279/download?type=zip
# instead of the redirect URLs that are direct to the CDN. That will make easier for users to add apps here.
# The code will need to follow the redirect and get the filename from the next URL.
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={}",
"https://cdn-learn.adafruit.com/downloads/zip/3196755/Metro/Metro_RP2350_Chips_Challenge.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3198116/Metro/Metro_RP2350_Minesweeper.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3198279/Fruit_Jam/Larsio_Paint_Music.zip?timestamp={}",
"https://cdn-learn.adafruit.com/downloads/zip/3203853/Fruit_Jam/Fruit_Jam_IRC_Client.zip?timestamp={}",
# each path is a tuple that contains:
# (path within learn repo, directory name to use inside of apps/)
LEARN_PROJECT_PATHS = [
("Metro/Metro_RP2350_Snake/","Metro_RP2350_Snake"),
("Metro/Metro_RP2350_Memory/memory_game/", "Metro_RP2350_Memory"),
("Metro/Metro_RP2350_CircuitPython_Matrix/", "Metro_RP2350_CircuitPython_Matrix"),
("Metro/Metro_RP2350_FlappyNyanCat/", "Metro_RP2350_FlappyNyanCat"),
("Metro/Metro_RP2350_Match3/match3_game/", "Metro_RP2350_Match3"),
("Metro/Metro_RP2350_Breakout/", "Metro_RP2350_Breakout"),
("Metro/Metro_RP2350_Chips_Challenge/", "Metro_RP2350_Chips_Challenge"),
("Metro/Metro_RP2350_Minesweeper/", "Metro_RP2350_Minesweeper"),
("Fruit_Jam/Larsio_Paint_Music/", "Larsio_Paint_Music"),
("Fruit_Jam/Fruit_Jam_IRC_Client/", "Fruit_Jam_IRC_Client"),
("Fruit_Jam/Fruit_Jam_PyPaint/", "Fruit_Jam_PyPaint"),
]
def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir: Path, output_dir: Path):
@ -39,6 +38,8 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
try:
# Copy src contents
shutil.copytree(src_dir, temp_dir, dirs_exist_ok=True)
# remove empty __init__.py file
os.remove(temp_dir / "__init__.py")
# Create fonts directory and copy the specific font
fonts_dir = temp_dir / "fonts"
@ -48,65 +49,9 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
# Extract learn-projects contents into apps directory
apps_dir = temp_dir / "apps"
apps_dir.mkdir(parents=True, exist_ok=True)
for zip_path in learn_projects_dir.glob("*.zip"):
# Create app-specific directory using zip name without extension
app_name = zip_path.stem
app_dir = apps_dir / app_name
app_dir.mkdir(parents=True, exist_ok=True)
# Extract zip contents and process them
with zipfile.ZipFile(zip_path, 'r') as zf:
# Find the directory containing code.py
code_dir = None
for path in zf.namelist():
if path.endswith('/code.py'):
code_dir = str(Path(path).parent) + '/'
break
if not code_dir:
print(f"Warning: No code.py found in {zip_path}")
continue
# Extract files from the code.py directory to app directory
for path in zf.namelist():
if path.startswith(code_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):]
if rel_path:
# Extract the file
source = zf.open(path)
target = app_dir / rel_path
target.parent.mkdir(parents=True, exist_ok=True)
with open(target, 'wb') as f:
f.write(source.read())
# Handle lib directory specially - move to root
for path in zf.namelist():
if '/lib/' in path:
# Get the part of the path after 'lib/'
lib_index = path.index('/lib/') + 5 # skip past '/lib/'
rel_path = path[lib_index:]
# Skip directory entries
if not rel_path or path.endswith('/'):
continue
# Extract the file to root lib directory
source = zf.open(path)
target = temp_dir / 'lib' / rel_path
# Ensure parent directory exists
target.parent.mkdir(parents=True, exist_ok=True)
# Write the file
with open(target, 'wb') as f:
f.write(source.read())
# copy learn apps
for learn_app_path, dir_name in LEARN_PROJECT_PATHS:
shutil.copytree(f"Adafruit_Learning_System_Guides/{learn_app_path}", apps_dir / dir_name, dirs_exist_ok=True)
# copy builtin apps
shutil.copytree("builtin_apps", apps_dir, dirs_exist_ok=True)
@ -116,9 +61,9 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
circup_cli(["--path", temp_dir, "install", "--auto"],
standalone_mode=False)
# install builtin apps required libs
for builtin_app_dir in os.listdir("builtin_apps"):
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"apps/{builtin_app_dir}/code.py"],
# install apps required libs
for app_dir in os.listdir(apps_dir):
circup_cli(["--path", temp_dir, "install", "--auto", "--auto-file", f"apps/{app_dir}/code.py"],
standalone_mode=False)
os.remove(temp_dir / "boot_out.txt")
# Create the final zip file
@ -139,13 +84,12 @@ def create_font_specific_zip(font_path: Path, src_dir: Path, learn_projects_dir:
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)
try:
shutil.rmtree("Adafruit_Learning_System_Guides/")
except FileNotFoundError:
pass
os.system("git clone https://github.com/adafruit/Adafruit_Learning_System_Guides.git")
def main():

View file

@ -146,45 +146,13 @@ if "use_mouse" in launcher_config and launcher_config["use_mouse"]:
mouse_buf = array.array("b", [0] * 8)
WIDTH = int(280 / 360 * display.width // scale)
WIDTH = int(298 / 360 * display.width // scale)
HEIGHT = int(182 / 200 * display.height // scale)
config = {
"menu_title": "Launcher Menu",
"width": 3,
"height": 2,
"apps": [
{
"title": "🐍Snake🐍",
"icon": "icon_snake.bmp",
"file": "code_snake_game.py"
},
{
"title": "Nyan😺Flap",
"icon": "icon_flappynyan.bmp",
"file": "code_flappy_nyan.py"
},
{
"title": "Memory🧠",
"icon": "icon_memory.bmp",
"file": "code_memory.py"
},
{
"title": "Matrix",
"icon": "/apps/matrix/icon.bmp",
"file": "/apps/matrix/code.py"
},
{
"title": "Breakout",
"icon": "icon_breakout.bmp",
"file": "code_breakout.py"
},
{
"title": "Paint🖌",
"icon": "icon_paint.bmp",
}
]
}
cell_width = WIDTH // config["width"]
@ -207,7 +175,6 @@ scaled_group.append(menu_title_txt)
app_titles = []
apps = []
app_path = pathlib.Path("/apps")
i = 0
pages = [{}]
@ -248,7 +215,7 @@ for path in app_path.iterdir():
"dir": path
})
i += 1
apps = sorted(apps, key=lambda app: app["title"].lower())
print("launcher config", launcher_config)
if "favorites" in launcher_config:
@ -371,11 +338,11 @@ if "arrow" in launcher_config["palette"]:
left_tg = AnchoredTileGrid(bitmap=left_bmp, pixel_shader=left_palette)
left_tg.anchor_point = (0, 0.5)
left_tg.anchored_position = (4, (display.height // 2 // scale) - 2)
left_tg.anchored_position = (0, (display.height // 2 // scale) - 2)
right_tg = AnchoredTileGrid(bitmap=right_bmp, pixel_shader=right_palette)
right_tg.anchor_point = (1.0, 0.5)
right_tg.anchored_position = ((display.width // scale) - 4, (display.height // 2 // scale) - 2)
right_tg.anchored_position = ((display.width // scale), (display.height // 2 // scale) - 2)
original_arrow_btn_color = left_palette[2]
scaled_group.append(left_tg)
@ -389,13 +356,11 @@ if mouse:
scaled_group.append(mouse_tg)
help_txt = Label(terminalio.FONT, text="[Arrow]: Move\n[E]: Edit\n[Enter]: Run\n[1-9]: Page",
help_txt = Label(terminalio.FONT, text="[Arrow]: Move [E]: Edit [Enter]: Run [1-9]: Page",
color=int(launcher_config["palette"].get("fg", "0xffffff"), 16))
# help_txt = TextBox(terminalio.FONT, width=88, height=30, align=TextBox.ALIGN_RIGHT, background_color=int(launcher_config["palette"].get("accent", "0x008800"), 16), text="[E]: Edit\n[Enter]: Run")
help_txt.anchor_point = (0, 0)
help_txt.anchored_position = (2, 2)
# help_txt.anchored_position = (display.width - 89, 1)
help_txt.anchor_point = (0.0, 1.0)
help_txt.anchored_position = (2, display.height-2)
print(help_txt.bounding_box)
main_group.append(help_txt)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 918 B