Page template renderer: HERO1 and GRID6, Phase 1b (#59) #120
No reviewers
Labels
No labels
area:companion
area:docs
area:shared
area:tooling
area:watchapp
blocker
kind:chore
kind:feature
kind:spike
kind:test
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
robert/PedalPebble!120
Loading…
Reference in a new issue
No description provided.
Delete branch "area/page-template-hero1-grid6"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Completes the part of #59 that PR #87 deliberately deferred, per that issue's own 2026-09-01 update (D32):
HERO1andGRID6, on top of theemery/HERO2/QUADPhase 1 renderer #87 already shipped. Read the issue's full body (including the 2026-09-01 drawn-digits/emphasised-slot/narrowing update and the 2026-09-02 stale-vs-unavailable update) and PR #87's own description before starting — this PR reuses everything #87 built and does not touch it.What this ships
page_render_geometry.h/.c— same bounds-in/rects-out contract as #87 (zero<pebble.h>, zero SDK calls, D34):page_render_hero1_hero_rect(content)— one field, the whole content area (DESIGN.md section 3: "full 200x208" on emery). Named to match the establishedpage_render_hero2_hero_rect()/page_render_quad_cell_rect()convention. Returnscontentunchanged, but exists as a real, host-testable function anyway so a future round variant (#62) has a call site to grow aPBL_IF_ROUND_ELSEbranch into.page_render_grid6_cell_rect(content, slot)— 2x3 grid, same last-row/last-column-absorbs-the-remainder tiling rule aspage_render_quad_cell_rect().page_render_digit_height()extended:HERO1slot 0 = 140px, DESIGN.md's own "~140px digits" figure, used exactly.GRID6ordinary slots (1-5) = 40px, DESIGN.md's own figure (also D29/D24's stated 5.0mm floor).GRID6slot 0 (PAGE_EMPHASISED_SLOT, D29) = 46px — a reasoned choice mirroring QUAD's 56/76 pattern (a size lookup keyed on slot index, not a separate layout path), but with much less headroom: GRID6's cell (100x69) leaves only 69-20=49px of value area versus QUAD's 84px, so the margin above the ordinary height is smaller (3px clearance vs QUAD's 8px). Verified in the emulator screenshot below, same as QUAD's own 76 was.page_render_resolve_template(requested, content)— new function. GRID6 falls back to QUAD whencontent, divided into a 2x3 grid, produces a cell smaller than GRID6's own DESIGN.md reference cell (100x69) in either dimension. This is a pixel comparison against DESIGN.md's own numbers, not aPBL_PLATFORM_*check — it stays platform-blind by construction (this file takes no SDK dependency, same as everything else in it) and correctly falls back on basalt's real content (144x148 → 72x49 cell) while leaving GRID6 untouched on emery (200x208 → 100x69, exactly at the reference size).Deliberately does not special-case gabbro. A round screen's usable area is smaller than its rectangular bounding box (a 260x260 circle only inscribes ~184x184, D24), but nothing in this file — Phase 1 or 1b — has taught
page_render_content_rect()that a screen can be round; it still returns a plain rectangle. Called with gabbro's raw rectangular content (260x240), this function reports GRID6 "fits" (cell 130x80), which is wrong for the physical screen. That gap is real, confirmed by an actual gabbro screenshot below, and is explicitly not fixed here — building the round-aware content rect that would make this call correct is #62's job, a separate open issue, not a side effect of this one.page_render.c/.h—prv_draw_hero1()/prv_draw_grid6()added, following the exact same one-cell-at-a-time pattern asprv_draw_hero2()/prv_draw_quad().page_render_draw()now resolves the template throughpage_render_resolve_template()before its dispatch switch; a GRID6 that resolves to QUAD draws through the existing, unchangedprv_draw_quad(), which means it only showsdesc->fields[0..3]— silently dropping fields 4 and 5 is the expected degrade the issue's own acceptance criterion ("GRID6 may fall back to QUAD") asks for, documented at the call site.Stale-vs-unavailable (D44) and label overflow handling (
GTextOverflowModeTrailingEllipsis) are entirely unchanged, reused as-is —prv_draw_cell()doesn't know or care which template called it, so HERO1/GRID6 get D44's hollow+strike-vs-solid-dashes distinction and #87's ellipsis-based overflow protection for free, with no new code.watchapp/tests/test_page_render_geometry.c— 10 new tests (38 total, up from 28):HERO1's hero rect,GRID6's cell rects (DESIGN.md numbers + exact tiling/no-gap/no-overlap, at emery's real 200x228),GRID6's emphasised-slot lookup,HERO1's digit height, andpage_render_resolve_template()at both emery's and basalt's real dimensions (144x168 — DESIGN.md's own basalt figure). Hand-compiled and run directly, no cmake binary in this environment:Also re-ran all four other existing host suites (
fields,page,state,backlight) the same way — 126 tests, zero regressions, 164 total across the whole suite.Two real findings, flagged in code rather than silently patched
Both surfaced by this PR's own emulator verification (not assumed), and both are pre-existing, cross-cutting limitations of the fixed-digit-height mechanism (
page_render_digit_height(template, slot)doesn't knowcontent's actual size) rather than something a two-template Phase 1b PR should fix as a side effect:FIELD_SPEED's "28.4" (3 digits + 1 dot) — needs ~322px of run width at 140px digit height (the fixed 0.6x-height-per-digit ratio every template uses). Emery's content is only 200px wide; basalt's is 144. Confirmed via real screenshots on both (below) — the last digit is visibly sliced off-screen on emery, and HERO1 is nearly unusable on basalt. The largest height that keeps that same value on-screen on emery is ~88px — smaller than HERO2's own 96px hero, which would make HERO1 the smaller of the two "one dominant number" shapes, contradicting the physical-size table the 140 figure came from. Fixing this properly means making digit height content-width-aware, which is a mechanism change touching every template, not a HERO1-specific number swap — flagged inpage_render_geometry.cand left at the literal DESIGN.md figure rather than quietly substituting a smaller number that buries the conflict.Both are documented in code comments at the relevant constant/function, and reported here for a decision rather than resolved unilaterally (D48: a checked fact, not a better argument).
Render cost — measured, not assumed
Same
carousel.ctiming wrapper #87 used (time_ms()bracketingpage_render_draw()), same emery emulator. Real log lines:All comfortably inside the 1Hz (1000ms) budget — GRID6's worst case is 6.9% of it.
heap_bytes_free()stayed flat across every transition in the same log (99784 -> 99784) — no allocation anywhere in the new code, digit drawing included.Also measured on basalt and gabbro, since this PR is the first to actually look at either for these templates:
Verification
Host tests: see above — 38/38 in this suite, 164/164 across the whole host suite, hand-compiled with
gcc -std=c11 -Wall -Wextra -Werror.Builds:
pebble buildclean for all three platforms (emery,gabbro,basalt) — zero warnings from any changed file, both before and after the emulator-verification temp seeding was reverted. Finalemery/basaltmemory-usage reports are byte-for-byte identical to the pre-change build (14384 bytes RAM footprint) — nothing here costs any static RAM.Emulator, live, real screenshots — temporarily seeded
fields.c's store and swapped two default pages' templates to HERO1/GRID6 inmain.c/page.c(same technique #87 used, marked_TEMP, fully reverted —git diffon both files is empty in this PR) purely to have real digit values and reachable pages to screenshot:FIELD_SPEED, "28.4"): renders at 140px, confirms finding (1) above — last digit clipped off the right edge.AVG SPEEDtemporarily replaced withDURCHSCHNITTSGESCHWINDIGKEIT, reverted): truncates cleanly via the existing ellipsis mechanism, no clipping, digit rendering completely unaffected — confirms the same #87 mechanism covers HERO1/GRID6 with no new code needed.page_render_resolve_template()works, but also visibly shows finding (2): the QUAD cells themselves overlap.Not in this PR
gabbro) geometry variants — #62, still open. Nothing round-specific is built here;page_render_resolve_template()explicitly does not special-case gabbro (see its own comment) rather than half-building #62 as a side effect.https://claude.ai/code/session_01DAoXbRmJUf2uxNYBfdAXPt