Skin template system, separate prev sprite, reorganize device scripts
Add tools/gen_skin_template.py to generate a labeled 642x420 PNG template for creating custom spritesheets. Move rg35xx device scripts from tools/ to device/rg35xx/. Point prev_sprite at its own cell (bottom-center) so Prev and Next can have distinct icons. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
02ab142d96
commit
8a638acdd8
@ -34,7 +34,7 @@ No test suite, no linter.
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Single-file C program: `src/sdlamp2.c` (~650 lines). One generated header: `src/controls_png.h` (embedded PNG byte array — regenerate with `./tools/embed_png.py assets/controls.png src/controls_png.h` if the spritesheet changes).
|
Single-file C program: `src/sdlamp2.c` (~650 lines). One generated header: `src/controls_png.h` (embedded PNG byte array — regenerate with `python3 tools/embed_png.py assets/controls.png src/controls_png.h` if the spritesheet changes). Skin template: `python3 tools/gen_skin_template.py [output.png]` generates a labeled grid template for creating custom spritesheets (requires Pillow). Device-specific scripts live in `device/rg35xx/`.
|
||||||
|
|
||||||
Key sections in order:
|
Key sections in order:
|
||||||
- **Decoder struct** — holds all FFmpeg state (format/codec contexts, swr resampler, album art texture)
|
- **Decoder struct** — holds all FFmpeg state (format/codec contexts, swr resampler, album art texture)
|
||||||
|
|||||||
BIN
assets/skin_template.png
Normal file
BIN
assets/skin_template.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
@ -143,8 +143,8 @@ The `dmenu_ln` script already supports switching the startup binary via config f
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
scp build/sdlamp2 root@rg35xx:/mnt/vendor/bin/sdlamp2
|
scp build/sdlamp2 root@rg35xx:/mnt/vendor/bin/sdlamp2
|
||||||
scp tools/rg35xx-wrapper.sh root@rg35xx:/mnt/vendor/bin/rg35xx-wrapper.sh
|
scp device/rg35xx/rg35xx-wrapper.sh root@rg35xx:/mnt/vendor/bin/rg35xx-wrapper.sh
|
||||||
scp tools/rg35xx-screen-monitor.py root@rg35xx:/mnt/vendor/bin/rg35xx-screen-monitor.py
|
scp device/rg35xx/rg35xx-screen-monitor.py root@rg35xx:/mnt/vendor/bin/rg35xx-screen-monitor.py
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Add the config check** to `/mnt/vendor/ctrl/dmenu_ln`. In the section where `CMD` overrides are checked (after the existing `muos.ini` / `vpRun.ini` checks, before the `app_scheduling` call), add:
|
2. **Add the config check** to `/mnt/vendor/ctrl/dmenu_ln`. In the section where `CMD` overrides are checked (after the existing `muos.ini` / `vpRun.ini` checks, before the `app_scheduling` call), add:
|
||||||
@ -155,7 +155,7 @@ The `dmenu_ln` script already supports switching the startup binary via config f
|
|||||||
fi
|
fi
|
||||||
```
|
```
|
||||||
|
|
||||||
The wrapper script handles device-specific concerns (WiFi hotspot, power button monitoring) and launches sdlamp2 as its main foreground process. See `tools/rg35xx-wrapper.sh` for details.
|
The wrapper script handles device-specific concerns (WiFi hotspot, power button monitoring) and launches sdlamp2 as its main foreground process. See `device/rg35xx/rg35xx-wrapper.sh` for details.
|
||||||
|
|
||||||
3. **Enable sdlamp2 on boot:**
|
3. **Enable sdlamp2 on boot:**
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,12 @@ This document specifies the functional requirements for an SDL2 based media play
|
|||||||
|
|
||||||
## 6. Changelog
|
## 6. Changelog
|
||||||
|
|
||||||
|
### 2026-02-14 — Skin template system and device script reorganization
|
||||||
|
|
||||||
|
- **Skin template generator**: New `tools/gen_skin_template.py` (requires Pillow) generates a 642x420 PNG template showing the sprite grid layout with labeled gutters. Skin creators can draw over the white 200x200 cells; the 20px gray gutters (never rendered by the app) identify each cell's purpose.
|
||||||
|
- **Separate Prev sprite**: `prev_sprite` now uses the bottom-center cell `{220, 220}` instead of sharing the bottom-right cell with `next_sprite`. This gives Prev and Next distinct sprites in the spritesheet.
|
||||||
|
- **Device scripts moved**: `rg35xx-wrapper.sh` and `rg35xx-screen-monitor.py` moved from `tools/` to `device/rg35xx/`, separating device-specific scripts from dev tools.
|
||||||
|
|
||||||
### 2026-02-14 — Softer background, remove panel divider
|
### 2026-02-14 — Softer background, remove panel divider
|
||||||
|
|
||||||
- **Background color**: Changed from white (`#FFFFFF`) to a medium gray (`#979797`) for a gentler appearance.
|
- **Background color**: Changed from white (`#FFFFFF`) to a medium gray (`#979797`) for a gentler appearance.
|
||||||
|
|||||||
@ -612,7 +612,7 @@ int main(int argc, char** argv) {
|
|||||||
const SDL_Rect play_sprite = {220, 0, 200, 200};
|
const SDL_Rect play_sprite = {220, 0, 200, 200};
|
||||||
const SDL_Rect ff_sprite = {440, 0, 200, 200};
|
const SDL_Rect ff_sprite = {440, 0, 200, 200};
|
||||||
const SDL_Rect stop_sprite = {0, 220, 200, 200};
|
const SDL_Rect stop_sprite = {0, 220, 200, 200};
|
||||||
const SDL_Rect prev_sprite = {440, 220, 200, 200};
|
const SDL_Rect prev_sprite = {220, 220, 200, 200};
|
||||||
const SDL_Rect next_sprite = {440, 220, 200, 200};
|
const SDL_Rect next_sprite = {440, 220, 200, 200};
|
||||||
const SDL_Rect circle_sprite = {440, 220, 200, 200}; /* placeholder for no-art */
|
const SDL_Rect circle_sprite = {440, 220, 200, 200}; /* placeholder for no-art */
|
||||||
|
|
||||||
|
|||||||
96
tools/gen_skin_template.py
Normal file
96
tools/gen_skin_template.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
gen_skin_template.py — Generate a skin template PNG for sdlamp2.
|
||||||
|
|
||||||
|
Creates a 642x420 PNG showing the sprite grid layout with labeled gutters.
|
||||||
|
Each 200x200 cell is blank white (ready to draw on). The 20px gutters between
|
||||||
|
cells are gray with small text labels identifying adjacent cells.
|
||||||
|
|
||||||
|
Grid layout:
|
||||||
|
Col 0 (0-199) Col 1 (220-419) Col 2 (440-639)
|
||||||
|
Row 0: REWIND PLAY FF
|
||||||
|
----gutter y=200-219 with labels----
|
||||||
|
Row 1: STOP PREV NEXT
|
||||||
|
|
||||||
|
Two extra pixels on the right (640-641) are gutter fill to reach 642px width,
|
||||||
|
matching the spritesheet dimensions.
|
||||||
|
|
||||||
|
Usage: python3 tools/gen_skin_template.py [output.png]
|
||||||
|
|
||||||
|
Requires Pillow.
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
CELL = 200
|
||||||
|
GAP = 20
|
||||||
|
COLS = 3
|
||||||
|
ROWS = 2
|
||||||
|
WIDTH = COLS * CELL + (COLS - 1) * GAP + 2 # 642
|
||||||
|
HEIGHT = ROWS * CELL + (ROWS - 1) * GAP # 420
|
||||||
|
|
||||||
|
CELL_COLOR = (255, 255, 255)
|
||||||
|
GUTTER_COLOR = (180, 180, 180)
|
||||||
|
TEXT_COLOR = (80, 80, 80)
|
||||||
|
|
||||||
|
LABELS = [
|
||||||
|
["REWIND", "PLAY", "FF"],
|
||||||
|
["STOP", "PREV", "NEXT"],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def cell_x(col):
|
||||||
|
return col * (CELL + GAP)
|
||||||
|
|
||||||
|
|
||||||
|
def cell_y(row):
|
||||||
|
return row * (CELL + GAP)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
output_path = sys.argv[1] if len(sys.argv) > 1 else "skin_template.png"
|
||||||
|
|
||||||
|
img = Image.new("RGB", (WIDTH, HEIGHT), GUTTER_COLOR)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
# Try to load a small font for labels
|
||||||
|
try:
|
||||||
|
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11)
|
||||||
|
except OSError:
|
||||||
|
try:
|
||||||
|
font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 11)
|
||||||
|
except OSError:
|
||||||
|
font = ImageFont.load_default()
|
||||||
|
|
||||||
|
# Draw white cells
|
||||||
|
for row in range(ROWS):
|
||||||
|
for col in range(COLS):
|
||||||
|
x = cell_x(col)
|
||||||
|
y = cell_y(row)
|
||||||
|
draw.rectangle([x, y, x + CELL - 1, y + CELL - 1], fill=CELL_COLOR)
|
||||||
|
|
||||||
|
# Label the horizontal gutter (y = 200..219)
|
||||||
|
gutter_y = CELL # 200
|
||||||
|
for col in range(COLS):
|
||||||
|
cx = cell_x(col) + CELL // 2
|
||||||
|
|
||||||
|
# Row 0 label above center of gutter
|
||||||
|
label_0 = LABELS[0][col]
|
||||||
|
bbox = draw.textbbox((0, 0), label_0, font=font)
|
||||||
|
tw = bbox[2] - bbox[0]
|
||||||
|
draw.text((cx - tw // 2, gutter_y + 1), label_0, fill=TEXT_COLOR, font=font)
|
||||||
|
|
||||||
|
# Row 1 label below center of gutter
|
||||||
|
label_1 = LABELS[1][col]
|
||||||
|
bbox = draw.textbbox((0, 0), label_1, font=font)
|
||||||
|
tw = bbox[2] - bbox[0]
|
||||||
|
th = bbox[3] - bbox[1]
|
||||||
|
draw.text((cx - tw // 2, gutter_y + GAP - th - 2), label_1, fill=TEXT_COLOR, font=font)
|
||||||
|
|
||||||
|
img.save(output_path)
|
||||||
|
print(f"Skin template saved to {output_path} ({WIDTH}x{HEIGHT})")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
x
Reference in New Issue
Block a user