Cut shell/panel comment bloat ~47% (comments only, zero code change)

This commit is contained in:
2026-07-29 20:48:56 -04:00
parent 1f24c4b095
commit cc36dd59c7
15 changed files with 627 additions and 1320 deletions
+51 -93
View File
@@ -1,37 +1,29 @@
#pragma once
// draw_kit — the LICE-facing SHELL half of the shared drawing kit (Phase L, L1). This is
// the ONE source of drawing for the whole system: every surface (bank_panel now; the VST
// editor + embed strip at L3) fills, buttons, rows, sliders, waveforms, and — above all —
// draws TEXT through this kit, so a control looks identical everywhere because it is the
// same kit function. It replaces the flat LICE_FillRect blocks and raw-GDI DrawTextA with
// gradient/AA surfaces (the vwnd micro-gradient + inner highlight/shadow trick) and cached
// anti-aliased text (LICE_CachedFont), honoring the interaction-state model.
// draw_kit — the LICE-facing SHELL half of the shared drawing kit: the ONE source of
// drawing for the whole system (bank_panel, the VST editor, and the embed strip all fill,
// button, row, slider, waveform, and draw TEXT through this same kit, so a control looks
// identical everywhere).
//
// PURE/SHELL SPLIT (CLAUDE.md §load-bearing): this file is SHELL — it touches LICE and
// SWELL (HFONT). All palette decisions come from the pure `theme` module (role -> KitColor);
// all layout/hit-test from the pure `component_geometry` / mode_switch / etc. modules. This
// file only turns those pure answers into LICE calls. It is DAW-verified, not unit-tested.
// SHELL: touches LICE and SWELL (HFONT). Palette decisions come from the pure `theme`
// module (role -> KitColor); layout/hit-test from the pure `component_geometry` /
// mode_switch / etc. modules. This file only turns those pure answers into LICE calls.
// DAW-verified, not unit-tested.
//
// FONT LIFECYCLE (owned here): the kit holds a small set of LICE_CachedFonts (title / label
// / value-mono / micro). kitFontsInit() creates them once (from HFONTs handed off with
// LICE_FONT_FLAG_OWNS_HFONT, so the cached font frees the HFONT itself — verified in
// lice_text.h §SetFromHFont doc: "OWNS means LICE_IFont will clean up hfont on font change
// or exit"). kitFontsShutdown() deletes the cached fonts. The consumer calls init on panel
// open and shutdown on close/teardown. text() no-ops safely before init (defensive), so a
// draw that races construction never crashes.
// Fonts: kitFontsInit() hands each LICE_CachedFont an HFONT with
// LICE_FONT_FLAG_OWNS_HFONT, so the cached font frees the HFONT itself on shutdown/
// reassignment. text() no-ops safely before init, so a draw that races construction
// never crashes.
//
// DOUBLE-BUFFER DISCIPLINE (§3.5 "zero-jank"): every function here draws into the caller's
// offscreen LICE_IBitmap; the caller BitBlt's once. Nothing here draws direct-to-DC.
// Every function draws into the caller's offscreen LICE_IBitmap; the caller BitBlt's
// once. Nothing here draws direct-to-DC.
#include "core/ui/component_geometry.h" // KitBox / SliderGeometry — the pure geometry the shell draws
#include "core/audio/peaks.h" // Envelope — the waveform primitive's input
#include "core/ui/component_geometry.h" // KitBox / SliderGeometry
#include "core/audio/peaks.h" // Envelope
#include "core/ui/theme.h" // Role / InteractionState / KitColor / TextClass
// LICE types at the boundary (this is the shell half). LICE_IBitmap is forward-declared
// to keep the header light. LICE_pixel is a typedef (unsigned int) — not forward-declarable
// — so the full lice.h is included only for the toLice() declaration; on Windows lice.h
// pulls in <windows.h>, which is fine since draw_kit.h is shell-only and never included by
// a pure module.
// LICE_pixel is a typedef (unsigned int), not forward-declarable, so the full lice.h is
// included for the toLice() declaration; lice.h pulls in <windows.h> on Windows, which is
// fine since this header is shell-only and never included by a pure module.
#ifdef _WIN32
#include <windows.h>
#endif
@@ -40,10 +32,7 @@ class LICE_IBitmap;
namespace reasampler {
// Real-namespace-home using-declarations (Q-W6: the interim core/namespaces.h shim
// is retired; the kit's pure vocabulary names its Q-W1 homes explicitly). These are
// deliberate re-exports: every draw_kit consumer speaks these types at the call
// boundary, so they surface here exactly as panel_state.h surfaces the panel's.
// Re-exports: every draw_kit consumer speaks these types at the call boundary.
using audio::Envelope;
using ui::InteractionState;
using ui::KitBox;
@@ -53,8 +42,8 @@ using ui::ListRowBox;
using ui::Role;
using ui::SliderGeometry;
// The kit's four cached fonts (§3.1 type scale). Consumers pass a Font to text() to pick
// the size/weight; the kit maps it to the matching LICE_CachedFont.
// The kit's four cached fonts. Consumers pass a Font to text() to pick the size/weight;
// the kit maps it to the matching LICE_CachedFont.
enum class Font {
Title, // ~15px semibold — region titles, headings
Label, // ~12px regular — labels, body
@@ -66,90 +55,59 @@ enum class Font {
// single-line convention); a caller wanting multi-line composes rows itself.
enum class Align { Left, Center, Right };
// --- KitColor LICE_pixel conversion ----------------------------------------
// The one place a pure KitColor becomes a LICE_pixel. Declared here so any shell
// translation unit that already includes draw_kit.h can use it without duplicating
// the LICE_RGBA packing. Defined in draw_kit.cpp.
// The one place a pure KitColor becomes a LICE_pixel. Defined in draw_kit.cpp.
LICE_pixel toLice(const KitColor& c);
// --- Font lifecycle (owned by the kit) ---------------------------------------
// Creates the four cached fonts once. Idempotent: a second call before shutdown is a no-op
// (the kit already holds live fonts). Safe to call on every panel open. Uses the platform
// UI sans (Segoe UI) for title/label/micro and a tabular mono (Consolas) for value-mono;
// the exact HFONT is created here, so a face change is a one-line edit. NO-OP-SAFE: if font
// creation fails, text() degrades to drawing nothing rather than crashing.
// Creates the four cached fonts once; idempotent. Segoe UI for title/label/micro,
// Consolas (tabular) for value-mono. No-op-safe: if font creation fails, text()
// draws nothing rather than crashing.
void kitFontsInit();
// Deletes the cached fonts (which free their owned HFONTs — LICE_FONT_FLAG_OWNS_HFONT).
// Idempotent. The consumer calls this on panel close / extension shutdown.
// Frees the owned HFONTs. Idempotent. Call on panel close / extension shutdown.
void kitFontsShutdown();
// --- Text (the single biggest "temple os -> modern" lever) -------------------
// Draws a single line of AA cached-font text in `color` inside `box`, horizontally aligned
// per `align` and vertically centered, clipped with an end-ellipsis. This REPLACES the
// GDI SetTextColor + DrawText path. No-op (safe) before kitFontsInit() or on a null bitmap.
// Draws a single line of AA cached-font text in `color` inside `box`, horizontally
// aligned per `align` and vertically centered, clipped with an end-ellipsis. No-op
// before kitFontsInit() or on a null bitmap.
void text(LICE_IBitmap* bmp, const KitBox& box, const char* str,
Font font, const KitColor& color, Align align);
// Convenience overload: text in a palette ROLE's color (the common case — the shell almost
// always wants text/primary or text/dim, not a raw color).
// Convenience overload: text in a palette ROLE's color.
void text(LICE_IBitmap* bmp, const KitBox& box, const char* str,
Font font, Role role, Align align);
// --- Surfaces + components ----------------------------------------------------
// The kit's foundational fill: a micro-gradient (a few percent lighter at the top, via
// LICE_GradRect) plus a 1px inner top-highlight and bottom-shadow — the vwnd trick that
// kills the flat look (§2.2). Every button/row/cell fills through this so elevation reads
// without a border. `role` picks the surface color; `state` transforms it per the
// interaction model (hover lightens, pressed darkens, disabled desaturates, etc.).
// The kit's foundational fill: a micro-gradient plus a 1px inner top-highlight/
// bottom-shadow, so elevation reads without a border. `state` transforms the role
// color (hover lightens, pressed darkens, disabled desaturates).
void fillSurface(LICE_IBitmap* bmp, const KitBox& box, Role role, InteractionState state);
// A rounded, gradient-filled button with the inner highlight/shadow and a centered label,
// honoring the interaction state. `warn == true` swaps the surface to the warn role (for
// byte-deleting verbs like prune/delete) — the only place warn is drawn. A degenerate box
// is a no-op.
// A rounded, gradient-filled button with a centered label. `warn == true` swaps the
// surface to the warn role — the only place warn is drawn. Degenerate box is a no-op.
void drawButton(LICE_IBitmap* bmp, const KitButtonBox& button, const char* label,
InteractionState state, bool warn);
// A horizontal slider: the track groove, the accent-filled portion up to the handle, and
// the handle (a raised knob honoring state — hover/dragging brighten it). `geom` is the
// pure SliderGeometry the caller computed; the kit only draws it. Degenerate geom is a no-op.
// A horizontal slider: track groove, accent-filled portion up to the handle, and the
// handle itself. `geom` is the pure SliderGeometry the caller computed.
void drawSlider(LICE_IBitmap* bmp, const SliderGeometry& geom, InteractionState state);
// A selectable list row: the row surface (rest/hover/active/focus via state), an optional
// leading thumbnail area reserved at `thumbWidth` px (0 for none — the caller draws the
// thumbnail into the returned-by-convention left inset), and a left-aligned label in the
// remaining width. Focus draws a 1px text/primary ring distinct from the accent selection
// fill. A degenerate row is a no-op.
// A selectable list row: row surface, an optional leading thumbnail inset
// (`thumbWidth`, 0 for none), and a left-aligned label. Focus draws a 1px ring
// distinct from the accent selection fill.
void drawListRow(LICE_IBitmap* bmp, const ListRowBox& row, const char* label,
int thumbWidth, InteractionState state);
// waveformColumnCount — declared in component_geometry.h (already included above). Returns
// the drawable column count inside `box` (box.width minus the fixed 2px insets each side).
// Callers pass this value directly as the `binCount` argument to peaks::computeEnvelope;
// overbinning (more bins than columns) costs memory and CPU without changing a rendered
// pixel — peaks::columnMinMax's exact partition already makes the draw gap-free.
// Multiplier kept at 1 (no oversampling). kWaveformOversample is present only so existing
// call sites `kWaveformOversample * waveformColumnCount(box)` compile unchanged; a value of
// 1 means they request exactly one bin per column, which is correct. The gap-free render
// comes from peaks::columnMinMax's exact partition, NOT from extra bins.
// Callers pass waveformColumnCount(box) as computeEnvelope's `binCount` — overbinning
// costs memory/CPU without changing a rendered pixel, since columnMinMax's exact
// partition already makes the draw gap-free at any bins-to-pixels ratio. Kept at 1 (no
// oversampling); present so existing call sites `kWaveformOversample *
// waveformColumnCount(box)` compile unchanged.
inline constexpr int kWaveformOversample = 1;
// A waveform envelope drawn as a min/max plot over the bg/panel surface: a midline per
// channel and one accent vertical span PER PIXEL COLUMN, each column covering the true
// extremes of every bin that projects to it (peaks::columnMinMax — gap-free at any
// bins-to-pixels ratio because columnMinMax partitions bins exactly as computeEnvelope
// does, so every pixel column is always covered). The ONE waveform shape in the system:
// the dock-panel thumbnail, the browser cards, and the editor hero all render through
// this. `box` is the draw region; `env` is the per-channel min/max envelope from
// peaks::computeEnvelope, sized to waveformColumnCount(box) bins (clamped to frame count).
// An empty env draws just the midline. The caller fills the surface first (or passes a
// box already filled); this draws only the wave + midline.
// A waveform drawn as a min/max plot: a midline per channel and one accent vertical
// span per pixel column (peaks::columnMinMax — gap-free at any bins-to-pixels ratio).
// The ONE waveform shape in the system: dock-panel thumbnail, browser cards, and
// editor hero all render through this. `env` is sized to waveformColumnCount(box)
// bins (clamped to frame count); an empty env draws just the midline.
void drawWaveform(LICE_IBitmap* bmp, const KitBox& box, const Envelope& env);
} // namespace reasampler