L1: shared LICE drawing kit — theme/palette + component geometry + draw kit; retire GDI text in bank_panel

This commit is contained in:
2026-07-26 20:04:04 -04:00
parent ec05af35ef
commit beca6487c7
10 changed files with 1394 additions and 42 deletions
+46 -36
View File
@@ -55,6 +55,8 @@
#include "bank_grid.h"
#include "bank_model.h"
#include "capture_paths.h"
#include "component_geometry.h" // KitBox — the kit text()'s draw box (L1)
#include "draw_kit.h" // kit text() over cached AA fonts — retires GDI DrawText (L1)
#include "guid_diff.h" // GuidBaseline — new-content detection (D2 Wave 2)
#include "item_read.h" // itemGuid / itemLaneName — shared item-read seam (D2 W3-B)
#include "lane_keys.h" // managed/manual lane heuristic (D2 Wave 2)
@@ -482,15 +484,38 @@ void drawThumbnail(LICE_IBitmap* bmp, const CellRect& rect, const Envelope& env,
}
}
// Draws a centered single-line label into a rect (COLORREF text).
void drawCenteredText(LICE_IBitmap* bmp, const RECT& rc, const char* text,
// --- GDI-text retirement (Phase L, L1) ----------------------------------------
//
// All panel text now draws through the kit's cached AA font (draw_kit::text), NOT raw GDI
// DrawText — the single biggest "temple os -> modern" lever. These thin adapters bridge the
// panel's existing RECT + COLORREF + DT_* call sites to the kit's KitBox + KitColor + Align
// so the retirement is mechanical and preserves each site's current color/alignment (L1 is
// the text-engine swap; the palette re-role is L2). The kit owns the font lifecycle
// (kitFontsInit/Shutdown, wired at panel open/close below).
KitBox toKitBox(const RECT& r) {
return KitBox{r.left, r.top, r.right - r.left, r.bottom - r.top};
}
KitColor toKitColor(COLORREF c) {
return KitColor{static_cast<std::uint8_t>(GetRValue(c)),
static_cast<std::uint8_t>(GetGValue(c)),
static_cast<std::uint8_t>(GetBValue(c)), 255};
}
// Maps the panel's DT_* horizontal flag to the kit's Align (the only three the panel uses).
Align toKitAlign(UINT fmt) {
if (fmt & DT_CENTER) return Align::Center;
if (fmt & DT_RIGHT) return Align::Right;
return Align::Left;
}
// Draws a single-line label into a rect through the kit's cached AA font (was GDI DrawText).
// `fmt` carries only the horizontal alignment (the kit always v-centers + single-lines +
// end-ellipsis, matching the retired DrawText flags). Font::Label is the panel's body face.
void drawCenteredText(LICE_IBitmap* bmp, const RECT& rc, const char* txt,
COLORREF color, UINT fmt) {
HDC dc = bmp->getDC();
if (!dc) return;
RECT r = rc;
SetTextColor(dc, color);
SetBkMode(dc, TRANSPARENT);
DrawText(dc, text, -1, &r, fmt | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
text(bmp, toKitBox(rc), txt, Font::Label, toKitColor(color), toKitAlign(fmt));
}
// --- Mode-switch header (D5, unchanged) ---------------------------------------
@@ -516,7 +541,6 @@ void drawModeSwitch(LICE_IBitmap* bmp, int w) {
if (segs.empty()) return;
const std::string& activeId = view.activeModeId();
HDC dc = bmp->getDC();
for (int i = 0; i < n; ++i) {
const SegmentRect& s = segs[static_cast<std::size_t>(i)];
@@ -527,12 +551,9 @@ void drawModeSwitch(LICE_IBitmap* bmp, int w) {
active ? kColSegActiveBg : kColSegBg, 1.0f, 0);
LICE_DrawRect(bmp, s.x, s.y, s.width, s.height, kColSegBorder, 1.0f, 0);
if (!dc) continue;
RECT rc{s.x, s.y, s.x + s.width, s.y + s.height};
SetTextColor(dc, active ? kRgbSegActiveText : kRgbSegText);
SetBkMode(dc, TRANSPARENT);
DrawText(dc, mode.displayName.c_str(), -1, &rc,
DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
drawCenteredText(bmp, rc, mode.displayName.c_str(),
active ? kRgbSegActiveText : kRgbSegText, DT_CENTER);
}
}
@@ -564,17 +585,11 @@ void drawTailFooter(LICE_IBitmap* bmp, int w, int h) {
LICE_FillRect(bmp, f.left, f.top, w, kFooterHeight, kColFooterBg, 1.0f, 0);
LICE_Line(bmp, f.left, f.top, f.right, f.top, kColFooterBorder, 1.0f, 0, false);
HDC dc = bmp->getDC();
if (!dc) return;
SetBkMode(dc, TRANSPARENT);
// Tail-mode toggle, left-aligned (the interactive control — footer clicks cycle it).
const std::string label = tailToggleLabel(currentTail());
RECT rc = f;
rc.left += 8;
SetTextColor(dc, kRgbFooterText);
DrawText(dc, label.c_str(), -1, &rc,
DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
drawCenteredText(bmp, rc, label.c_str(), kRgbFooterText, DT_LEFT);
// Version/channel readout (Phase V, V3/V4), right-aligned in the same footer strip so
// it is always visible but unobtrusive. appVersion() renders "0.9.01" on stable and
@@ -587,9 +602,8 @@ void drawTailFooter(LICE_IBitmap* bmp, int w, int h) {
// readout's right margin. If this inset (currently 8) changes, update rightInset there.
RECT vrc = f;
vrc.right -= 8; // COUPLED: PruneButtonSpec::rightInset in prune_button.h is 84
SetTextColor(dc, kRgbFooterVersion);
DrawText(dc, reasampler::appVersion().c_str(), -1, &vrc,
DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
drawCenteredText(bmp, vrc, reasampler::appVersion().c_str(),
kRgbFooterVersion, DT_RIGHT);
}
// The prune button's rect within the footer, derived from the client size. SINGLE source
@@ -615,13 +629,8 @@ void drawPruneButton(LICE_IBitmap* bmp, int w, int h) {
LICE_FillRect(bmp, b.x, b.y, b.width, b.height, kColPruneBtnBg, 1.0f, 0);
LICE_DrawRect(bmp, b.x, b.y, b.width, b.height, kColPruneBtnBorder, 1.0f, 0);
HDC dc = bmp->getDC();
if (!dc) return;
RECT rc{b.x, b.y, b.x + b.width, b.y + b.height};
SetBkMode(dc, TRANSPARENT);
SetTextColor(dc, kRgbPruneBtnText);
DrawText(dc, "Prune", -1, &rc,
DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
drawCenteredText(bmp, rc, "Prune", kRgbPruneBtnText, DT_CENTER);
}
// True iff client-relative (x, y) falls inside the (non-degenerate) footer strip.
@@ -745,21 +754,16 @@ void drawActionButtons(LICE_IBitmap* bmp, int w, int h) {
const std::vector<ActionButtonRect> rects =
computeButtonRects(strip, n, kButtonMinWidth);
HDC dc = bmp->getDC();
for (const ActionButtonRect& r : rects) {
LICE_FillRect(bmp, r.x + 1, r.y + 2, r.width - 2, r.height - 4,
kColActionBtnBg, 1.0f, 0);
LICE_DrawRect(bmp, r.x + 1, r.y + 2, r.width - 2, r.height - 4,
kColActionBtnBorder, 1.0f, 0);
if (!dc) continue;
const ActionButtonRow& row = rows[static_cast<std::size_t>(r.index)];
const int cmd = resolveActionCommandId(row);
const std::string label = actionButtonLabel(row, cmd);
RECT rc{r.x + 4, r.y, r.x + r.width - 4, r.y + r.height};
SetTextColor(dc, kRgbActionBtnText);
SetBkMode(dc, TRANSPARENT);
DrawText(dc, label.c_str(), -1, &rc,
DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
drawCenteredText(bmp, rc, label.c_str(), kRgbActionBtnText, DT_CENTER);
}
}
@@ -2278,6 +2282,11 @@ void openPanel() {
}
initPreview();
// Create the kit's cached AA fonts before the first paint (Phase L, L1). Idempotent, so
// a reopen after closePanel (which leaves the fonts alive) is a cheap no-op; the fonts
// are torn down once at bankPanelShutdown. All panel text draws through these.
kitFontsInit();
g_panel.hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_BANK_PANEL),
GetMainHwnd(), dlgProc, 0);
if (!g_panel.hwnd) return;
@@ -2407,6 +2416,7 @@ void bankPanelToggledBanksFullHeight() {
void bankPanelShutdown() {
closePanel();
deinitPreview();
kitFontsShutdown(); // free the kit's cached AA fonts + their owned HFONTs (L1)
g_panel.cache.clear();
g_panel.session = nullptr;
}