Files
wadamesh/test/constellation_render/render.cpp
T
Kaj SchittecatandClaude Opus 5.5 662665e6de touch: beta_89, the UI overhaul
Every screen redesigned to the Oct 2026 mockups, on one design system:
palette, type roles (generated Montserrat faces with Lucide line icons on the
LV_SYMBOL codepoints), a theme apply-cb that styles every LVGL widget, button
kinds, list rows, sheets as action lists, toasts and key-glyph avatars.

Rebuilt: status bar, Chats (filters, + and menu), conversation (route header,
hop meta, "Heard by N repeaters", delivery states, pill composer), lock screen
(mark, clock, 24 h activity, unread cards), Constellation screensaver, Home
launcher and launcher sheet, Status page, grouped Settings home, animated boot
splash, and the message glance as a notification card.

New: optional PIN lock (salted SHA-256, keyboard / touch pad / number pad per
board, backoff that survives reboot), screensaver on battery with its own
duration, T-Deck text sizes, trackball hold to switch Scroll and Cursor (Scroll
default, prefs v69/v70), hold Settings tab for the control panel. M9 bottom
notices removed. Every screen measured for the Large and Huge text sizes.

Fix: adverts over 2/3-byte path hashes never reached the recently heard table
(packed path_len compared as a byte count); ADVERT_PATH replies now carry the
whole multi-byte path.

English placeholders for the 204 untranslated keys in every .lang file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 23:26:41 +02:00

129 lines
5.0 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
// Renders the Constellation screensaver (src/ui-touch/Constellation.cpp) on the
// host at one logical screen size and writes it as a 24-bit BMP, so its layout
// can be checked for every board without the board. run.sh calls this once per
// size. The scene is a fixed, plausible mesh: repeaters with nodes behind them,
// direct neighbours, a room, stale ghosts, names with emoji in them.
//
// render <width> <height> <out.bmp> [ping]
#include "lvgl.h"
#include "../../src/ui-touch/Constellation.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C" const lv_font_t ui_semibold_12; // the counts in the status lines
static int s_w = 0, s_h = 0;
static uint8_t* s_rgb = nullptr;
static void flush(lv_disp_drv_t* drv, const lv_area_t* a, lv_color_t* px) {
for (int y = a->y1; y <= a->y2; ++y) {
for (int x = a->x1; x <= a->x2; ++x) {
const uint32_t c = lv_color_to32(*px++);
uint8_t* o = s_rgb + ((size_t)y * s_w + x) * 3;
o[0] = (c >> 16) & 0xFF; o[1] = (c >> 8) & 0xFF; o[2] = c & 0xFF;
}
}
lv_disp_flush_ready(drv);
}
static void run(uint32_t ms) {
for (uint32_t t = 0; t < ms; t += 10) { lv_tick_inc(10); lv_timer_handler(); }
}
static bool writeBmp(const char* path) {
FILE* f = fopen(path, "wb");
if (!f) return false;
const uint32_t row = (uint32_t)((s_w * 3 + 3) & ~3), img = row * (uint32_t)s_h;
uint8_t h[54] = {'B', 'M'};
auto p32 = [&](int o, uint32_t v) { h[o] = v; h[o + 1] = v >> 8; h[o + 2] = v >> 16; h[o + 3] = v >> 24; };
p32(2, 54 + img); p32(10, 54); p32(14, 40); p32(18, (uint32_t)s_w); p32(22, (uint32_t)s_h);
h[26] = 1; h[28] = 24; p32(34, img);
fwrite(h, 1, sizeof h, f);
uint8_t pad[3] = {0, 0, 0};
for (int y = s_h - 1; y >= 0; --y) {
for (int x = 0; x < s_w; ++x) {
const uint8_t* c = s_rgb + ((size_t)y * s_w + x) * 3;
const uint8_t bgr[3] = {c[2], c[1], c[0]};
fwrite(bgr, 1, 3, f);
}
fwrite(pad, 1, row - (uint32_t)s_w * 3, f);
}
fclose(f);
return true;
}
static CstNode node(uint32_t key, int bearing, int dist, CstKind kind, int level, int via, const char* label) {
CstNode n = {};
n.key = key; n.bearing = (int16_t)bearing; n.dist = (uint16_t)dist;
n.kind = (uint8_t)kind; n.level = (uint8_t)level; n.via = (int16_t)via;
if (label) snprintf(n.label, sizeof n.label, "%s", label);
return n;
}
int main(int argc, char** argv) {
if (argc < 4) { fprintf(stderr, "usage: render <w> <h> <out.bmp> [ping]\n"); return 2; }
s_w = atoi(argv[1]); s_h = atoi(argv[2]);
const bool ping = argc > 4 && strcmp(argv[4], "ping") == 0;
s_rgb = (uint8_t*)calloc((size_t)s_w * s_h, 3);
lv_init();
static lv_disp_draw_buf_t db;
lv_color_t* buf = (lv_color_t*)malloc(sizeof(lv_color_t) * (size_t)s_w * s_h);
lv_disp_draw_buf_init(&db, buf, nullptr, (uint32_t)(s_w * s_h));
static lv_disp_drv_t dd;
lv_disp_drv_init(&dd);
dd.hor_res = (lv_coord_t)s_w; dd.ver_res = (lv_coord_t)s_h;
dd.flush_cb = flush; dd.draw_buf = &db; dd.full_refresh = 1;
lv_disp_drv_register(&dd);
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x202428), 0); // what it covers
CstTheme th = {0x000000, 0x15B6A6, 0x19D6C2, 0xE6EBED, 0x8A969C, 0x5C686E,
&lv_font_montserrat_12, &ui_semibold_12};
cstShow(lv_layer_top(), th);
// Index: 0 repeater (direct) 1 repeater (via 0)
CstNode n[24];
int c = 0;
n[c++] = node(0xA1000001, 40, 330, CST_REPEATER, 3, -1, "BE-3001 RPT01");
n[c++] = node(0xA1000002, 75, 620, CST_REPEATER, 3, 0, "GNK \xF0\x9F\x93\xA1 Hill");
n[c++] = node(0xA1000003, 210, 420, CST_REPEATER, 2, -1, nullptr);
n[c++] = node(0xA1000004, 300, 700, CST_REPEATER, 1, 2, nullptr);
n[c++] = node(0xB2000001, 95, 820, CST_COMPANION, 3, 1, "Jade \xE2\x9C\xA8");
n[c++] = node(0xB2000002, 20, 560, CST_COMPANION, 3, 0, "pisti87");
n[c++] = node(0xB2000003, 160, 260, CST_COMPANION, 2, -1, "Kaj T-Deck");
n[c++] = node(0xB2000004, 230, 760, CST_COMPANION, 2, 2, nullptr);
n[c++] = node(0xB2000005, 330, 900, CST_COMPANION, 1, 3, nullptr);
n[c++] = node(0xC3000001, 120, 680, CST_ROOM, 2, 1, "Room \xC3\xA9t\xC3\xA9");
for (int g = 0; c < 24; ++g) {
n[c++] = node(0xD4000000u + (uint32_t)g, (g * 47 + 13) % 360, 500 + (g * 97) % 480,
g % 3 == 0 ? CST_REPEATER : CST_COMPANION, g % 2, -2, nullptr);
}
cstSetNodes(n, c);
CstStatus st = {};
snprintf(st.clock, sizeof st.clock, "21:47");
st.clock_ok = true;
snprintf(st.date, sizeof st.date, "TUE 6 OCT");
st.unread = 3;
snprintf(st.unread_word, sizeof st.unread_word, "new");
st.heard = 14;
snprintf(st.info, sizeof st.info, "nodes \xC2\xB7 heard 12 s ago");
st.batt = 86;
st.charging = false;
st.north_up = true;
cstSetStatus(st);
run(1200);
if (ping) {
cstPing(0xB2000001); // two hops in, through both repeaters
cstPingSelf();
run(420);
}
lv_refr_now(nullptr);
if (!writeBmp(argv[3])) { fprintf(stderr, "cannot write %s\n", argv[3]); return 1; }
printf("ok: %dx%d -> %s\n", s_w, s_h, argv[3]);
return 0;
}