palette: enlarge the region title into WCAG large class; repoint the grabbed envelope handle off hue
Corrects theme.h's large-text thresholds, names accent/secondary's real binding limiter, and adds compositeOver so the loop-span fill's 2.25:1 under-floor pair is asserted rather than assumed.
This commit is contained in:
+32
-11
@@ -43,15 +43,28 @@ L7 sub-pass, 2026-07-27):
|
||||
fills on `bg/cell` have a shrunken contrast cushion (primary ~7.6:1, tertiary
|
||||
~5.5:1, secondary only ~3.9:1 since it was darkened — all still clear 3:1, but
|
||||
re-check every one on any hue nudge). Body text on an accent fill is a tight AA
|
||||
4.5:1 pair, and for `accent/secondary` it is the *binding* limiter (~4.9:1), not
|
||||
the indicator floor. Take the most pastel value that still clears the floor,
|
||||
approached from the soft side, never re-saturated toward neon "to be safe."
|
||||
- **A mark drawn OVER an accent fill answers to two neighbours at once.**
|
||||
`overlay/trace` (the envelope trace on the waveform) must clear 3:1 against both
|
||||
`accent/primary` and `bg/base`, which sit 9.41:1 apart — so `sqrt(9.41)` ≈ 3.07:1
|
||||
is the ceiling for *any* single value, and the role sits at that optimum with no
|
||||
headroom either way. It is therefore confined to the waveform band: no value can
|
||||
clear 3:1 on `bg/cell` and against the lime simultaneously.
|
||||
4.5:1 pair (4.91:1 for `accent/secondary`). **The *binding* limiter on how dark
|
||||
`accent/secondary` may go is neither of those: it is the velocity-curve trace on
|
||||
a HOVER-lightened `bg/cell` at 3.03:1 against a 3:1 floor** — 1.2% headroom, the
|
||||
tightest pair in the tree, and invisible to any rest-surface check. Take the most
|
||||
pastel value that still clears the floor, approached from the soft side, never
|
||||
re-saturated toward neon "to be safe."
|
||||
- **A state surface is a DIFFERENT surface.** Hover lightens toward `accent/hot`,
|
||||
pressed darkens, disabled desaturates — each changes the contrast of everything
|
||||
drawn on it. Enumerate the state surfaces a role is drawn over, not just the rest
|
||||
ones; the limiter above is exactly the pair that enumeration missed.
|
||||
- **A mark drawn OVER an accent fill answers to two neighbours at once.** THE home
|
||||
for this rule. `overlay/trace` (the envelope trace on the waveform) must clear 3:1
|
||||
against both `accent/primary` and `bg/base`, which sit 9.41:1 apart — so
|
||||
`sqrt(9.41)` ≈ 3.07:1 is the ceiling for *any* single value, and the role sits at
|
||||
that optimum with no headroom either way. Three consequences, all load-bearing:
|
||||
the role is confined to the waveform band (no value clears 3:1 on `bg/cell` and
|
||||
against the lime at once); inside the 20%-alpha loop-span fill it is under floor
|
||||
at 2.25:1, and against `line/hairline`'s zero line at 1.92:1 — both KNOWN,
|
||||
ACCEPTED, and asserted as such, because no trace value fixes either; and any two
|
||||
values that BOTH clear the ceiling sit within 1.05:1 of each other, so a state of
|
||||
this mark (grabbed, hot, selected) **cannot** be carried by color and must be
|
||||
carried by size, fill-vs-outline, or shape.
|
||||
- **"Speed is the selling point" — a design constraint on this geometry, not
|
||||
just the draw layer.** Sub-frame hover/press/drag feedback must repaint
|
||||
immediately on the input message. **No decorative animation** — no
|
||||
@@ -79,7 +92,7 @@ L7 sub-pass, 2026-07-27):
|
||||
- `tab_strip` — REAPER-free scrollable tab-strip layout + hit-test for the named-banks strip.
|
||||
- `prune_button` — pure layout/hit-test for the `bank_panel` footer Prune button.
|
||||
- `drag_out` — pure OS drag-out module: gesture-boundary decision and path-list assembly. The `InstrumentDrop` gesture signals that the shell should execute an instrument-drop rather than a file-copy drag.
|
||||
- `theme` — pure palette module: role→color mapping, REAPER-grey neutral ladder + the pastel accent system, the keyboard strip's spectral ramp (its own three stops, deliberately not aliases of the accents), WCAG contrast-floor helpers.
|
||||
- `theme` — pure palette module: role→color mapping, REAPER-grey neutral ladder + the pastel accent system, the keyboard strip's spectral ramp, WCAG contrast-floor helpers + `compositeOver` (the effective color of a translucent fill, so alpha overlays are testable). Only the ramp's MID stop is its own constant; lo/hi are still aliases of `accent/primary`/`accent/tertiary`, so a categorical accent move CAN still reorder the ramp — `testSpectralRampLuminanceIsMonotonic` is the build-time catch, not the structure.
|
||||
- `component_geometry` — pure button/slider/list-row geometry + hover hit-test helpers.
|
||||
- `action_bar` — pure task-grouped action-bar layout/hit-test: clusters (Capture / Placement / Maintenance / Tagging / Switching).
|
||||
- `footer_bar` — pure footer layout/hit-test: `[Arrange|Design]` mode-toggle geometry, Tail button, and Prune placement.
|
||||
@@ -93,7 +106,15 @@ L7 sub-pass, 2026-07-27):
|
||||
|
||||
- The WCAG contrast-floor pairs above are real math in `theme`'s tests, not a
|
||||
visual eyeball check — any new hue or role needs its own contrast-floor
|
||||
assertion.
|
||||
assertion. Enumerate the draw sites by grep, not from memory: the enumeration
|
||||
must cover state surfaces (hover/pressed/active), translucent composites, and
|
||||
anything else drawn into the same rect, not just the rest surfaces.
|
||||
- **A text color's floor is set by its FONT, not by its role.** WCAG's large-scale
|
||||
class needs ≥24px, or ≥18.66px BOLD (`theme.h`'s thresholds); anything smaller is
|
||||
body class and answers to 4.5:1. A draw site relying on the 3:1 floor must pin its
|
||||
font metrics against those constants — `draw_kit.cpp`'s `Font::RegionTitle` is the
|
||||
worked example. A prior revision wrote the threshold ~25% low and let 15px
|
||||
semibold clear a floor it was not entitled to.
|
||||
- `card_drag`'s precedence order must stay a pure decision helper mirroring
|
||||
`drag_out::decideGesture` — don't let a shell reimplement gesture precedence
|
||||
ad hoc; the cursor-cue mapping in the shell must stay a thin lookup over the
|
||||
|
||||
+14
-10
@@ -34,22 +34,20 @@ constexpr KitColor kDirHairline {74, 74, 74, 255}; // #4a4a4a — subtle ste
|
||||
constexpr KitColor kDirTextPrimary{220, 220, 220, 255}; // #dcdcdc
|
||||
constexpr KitColor kDirTextDim {168, 168, 168, 255}; // #a8a8a8 (lifted from #a0a0a0)
|
||||
|
||||
// Accent system: primary = pastel lime (the live/active/selected signal); secondary = deep
|
||||
// teal, tertiary = pastel purple (CATEGORICAL distinctions — a KIND, never intensity).
|
||||
// accent/hot is a brighter tint OF the primary for hover/live/drag. Secondary is the one
|
||||
// accent off the pastel side: its binding limiter is the AA 4.5:1 text-on-fill pair (a bg/base
|
||||
// label on a secondary fill), NOT the 3:1 indicator floor, so it cannot go darker than this.
|
||||
// warn is reserved for byte-deleting states only.
|
||||
// Accent system — roles and their categorical meaning are core/ui/CLAUDE.md's. Warning only:
|
||||
// secondary CANNOT go darker. Its tightest pair is the velocity-curve trace on a HOVER-lightened
|
||||
// bg/cell (3.03:1 against a 3:1 floor — the whole tree's thinnest margin), which no rest-surface
|
||||
// check sees.
|
||||
constexpr KitColor kDirAccentPrimary {176, 224, 152, 255}; // #B0E098 — pastel lime
|
||||
constexpr KitColor kDirAccentSecondary{56, 168, 160, 255}; // #38A8A0 — deep teal
|
||||
constexpr KitColor kDirAccentTertiary {194, 170, 232, 255}; // #C2AAE8 — pastel purple
|
||||
constexpr KitColor kDirAccentHot {200, 236, 178, 255}; // #C8ECB2 — lighter pastel lime
|
||||
constexpr KitColor kDirWarn {235, 120, 90, 255}; // #eb785a — destructive only
|
||||
|
||||
// The envelope trace over the waveform. Two neighbours pin it at once — the lime accent it
|
||||
// crosses and bg/base behind it — which bound ANY single value to 3.07:1 against both; this is
|
||||
// that optimum, with no room in either direction. No categorical accent can carry it: every
|
||||
// one of them is light enough to fall under 2:1 against the lime.
|
||||
// The envelope trace over the waveform. Warning only (the two-neighbour rule is
|
||||
// core/ui/CLAUDE.md's): this value has NO room in either direction, and it is confined to the
|
||||
// waveform band — inside the 20%-alpha loop-span fill it already sits under floor at 2.25:1,
|
||||
// which no single value can fix.
|
||||
constexpr KitColor kDirOverlayTrace{129, 106, 166, 255}; // #816AA6 — muted violet
|
||||
|
||||
// Spectral ramp: pastel lime (low) -> pastel teal (mid) -> pastel purple (high). The mid stop
|
||||
@@ -160,6 +158,12 @@ KitColor spectralColor(double t) {
|
||||
return mix(kDirSpectralMid, kDirSpectralHi, (t - 0.5) / 0.5);
|
||||
}
|
||||
|
||||
KitColor compositeOver(const KitColor& over, const KitColor& under, double alpha) {
|
||||
if (alpha < 0.0) alpha = 0.0;
|
||||
if (alpha > 1.0) alpha = 1.0;
|
||||
return mix(under, over, alpha);
|
||||
}
|
||||
|
||||
double relativeLuminance(const KitColor& c) {
|
||||
return 0.2126 * linearizeChannel(c.r) +
|
||||
0.7152 * linearizeChannel(c.g) +
|
||||
|
||||
+23
-4
@@ -56,7 +56,14 @@ enum class InteractionState {
|
||||
Disabled,
|
||||
};
|
||||
|
||||
// Text size classes for the WCAG floor: "Large" (>= ~18.66px, or >= ~14px bold) and UI-state
|
||||
// WCAG 2.1's large-scale thresholds, in px at 96dpi (18pt = 24px normal, 14pt = 18.66px bold).
|
||||
// A previous revision wrote the BOLD threshold as the normal one and both ~25% low, which let
|
||||
// 15px semibold self-classify as Large and clear a floor it was not entitled to — draw sites
|
||||
// that want the Large floor static_assert their font against these.
|
||||
inline constexpr double kLargeTextMinPx = 24.0;
|
||||
inline constexpr double kLargeTextMinBoldPx = 18.66;
|
||||
|
||||
// Text size classes for the WCAG floor: "Large" (>= 24px, or >= ~18.66px BOLD) and UI-state
|
||||
// indicators clear at 3:1; body text clears at 4.5:1 (WCAG 2.1 AA).
|
||||
enum class TextClass {
|
||||
Body, // AA 4.5:1
|
||||
@@ -73,14 +80,26 @@ KitColor roleColorState(Role role, InteractionState state);
|
||||
|
||||
// Spectral hue ramp for the keyboard strip: maps normalized position t in [0, 1] (low note ->
|
||||
// high note) through a pastel lime -> teal -> purple arc, so the strip reads as part of the
|
||||
// palette rather than a separate flourish. The arc is its own three stops — a categorical
|
||||
// accent move must not be able to reorder it. t is clamped to [0, 1].
|
||||
// palette rather than a separate flourish. The MID stop is its own value; lo/hi remain aliases
|
||||
// of accent/primary and accent/tertiary, so a categorical accent move can still reorder the
|
||||
// ramp — testSpectralRampLuminanceIsMonotonic is the build-time catch, not the structure.
|
||||
// t is clamped to [0, 1].
|
||||
KitColor spectralColor(double t);
|
||||
|
||||
// --- WCAG contrast (the "punch" rule, made testable) --------------------------
|
||||
|
||||
// The effective opaque color of `over` drawn at `alpha` on top of `under` — the composition the
|
||||
// contrast math needs before it can judge a translucent fill. alpha is clamped to [0, 1]; the
|
||||
// result carries `under`'s alpha byte.
|
||||
KitColor compositeOver(const KitColor& over, const KitColor& under, double alpha);
|
||||
|
||||
// The waveform's loop-span fill alpha. Named HERE rather than at its draw site so the contrast
|
||||
// test composes the same value the shell draws with (see compositeOver).
|
||||
inline constexpr double kLoopSpanFillAlpha = 0.20;
|
||||
|
||||
// Relative luminance per WCAG 2.1 (sRGB linearization + 0.2126/0.7152/0.0722 weighting). Alpha
|
||||
// is ignored — a translucent overlay's effective color is the caller's to compose first.
|
||||
// is ignored — a translucent overlay's effective color is the caller's to compose first
|
||||
// (compositeOver).
|
||||
double relativeLuminance(const KitColor& c);
|
||||
|
||||
// WCAG contrast ratio between two colors, in [1, 21]. Symmetric.
|
||||
|
||||
@@ -25,11 +25,21 @@ using audio::computeEnvelope;
|
||||
|
||||
namespace {
|
||||
// Marker roles — semantic, drawn through the kit's palette: start AND loop start/end both
|
||||
// = teal (secondary). Markers are 2px bars and a 20%-alpha span fill, not the 1px trace, so
|
||||
// = teal (secondary). Markers are 2px bars and a translucent span fill, not the 1px trace, so
|
||||
// they live with 1.92:1 against the waveform; the trace, which cannot, has its own role.
|
||||
// Do not collapse the two back onto one role — they overlap in this rect.
|
||||
// Do not collapse the two back onto one role — they overlap in this rect. The trace crossing
|
||||
// the loop-span fill is a KNOWN, ACCEPTED under-floor pair (2.25:1 against a 3:1 floor), and no
|
||||
// trace value fixes it — see the two-neighbour rule in core/ui/CLAUDE.md. If it is ever
|
||||
// resolved, the FILL is what changes; do not nudge a color to chase it.
|
||||
constexpr Role kRoleStartMarker = Role::AccentSecondary;
|
||||
constexpr Role kRoleLoopMarker = Role::AccentSecondary;
|
||||
|
||||
// Envelope-handle half-extents. Grabbed grows and hollows out; kNodeGrabRadius (envelope_edit)
|
||||
// is the PICK radius and is unrelated — a handle may draw larger than it without widening any
|
||||
// hit region.
|
||||
constexpr int kEnvHandleRadius = 3;
|
||||
constexpr int kEnvHandleGrabbedRadius = 5;
|
||||
constexpr int kEnvHandleRingPx = 2;
|
||||
} // namespace
|
||||
|
||||
void ReaSamplerEditor::paintWaveform(LICE_IBitmap* bmp, const Rect& band) {
|
||||
@@ -84,7 +94,8 @@ void ReaSamplerEditor::paintWaveform(LICE_IBitmap* bmp, const Rect& band) {
|
||||
const int rx = frameToX(overlay, frames, m.loopEnd);
|
||||
if (rx > lx) {
|
||||
LICE_FillRect(bmp, lx, overlayRect.y, rx - lx, overlayRect.height,
|
||||
toLice(roleColor(kRoleLoopMarker)), 0.20f, 0);
|
||||
toLice(roleColor(kRoleLoopMarker)),
|
||||
static_cast<float>(kLoopSpanFillAlpha), 0);
|
||||
}
|
||||
}
|
||||
const std::int64_t markerFrames[3] = {m.start, m.loopStart, m.loopEnd};
|
||||
@@ -124,24 +135,35 @@ void ReaSamplerEditor::paintEnvelopeOverlay(LICE_IBitmap* bmp, const OverlayArea
|
||||
}
|
||||
prev = &v;
|
||||
}
|
||||
// Handles: a square per draggable stage node, a ROUND knot per curvable segment. Lit
|
||||
// accent-hot when this node is the grabbed one. Every vertex is guaranteed in-bounds; the
|
||||
// handle is additionally clamped inside the band so one on an edge node never overhangs
|
||||
// into the neighbouring bands.
|
||||
// Handles: a square per draggable stage node, a ROUND knot per curvable segment. Every
|
||||
// vertex is guaranteed in-bounds; the handle is additionally clamped inside the band so one
|
||||
// on an edge node never overhangs into the neighbouring bands.
|
||||
//
|
||||
// GRAB is signalled by SIZE + a punched-out core, NOT by a hotter hue — the one place the
|
||||
// kit's "brighter = hotter" convention is deliberately inverted, because a brighter tint is
|
||||
// a LOWER-contrast tint here: accent/hot sits at 1.15:1 against the lime it is drawn over.
|
||||
// The two-neighbour ceiling (core/ui/CLAUDE.md) leaves at most 1.05:1 between ANY two values
|
||||
// that both clear the floor over lime and bg/base, so no color can carry this state. The
|
||||
// grabbed mark stays overlay/trace and reads by its 3.07:1 ring against the lime plus a
|
||||
// 3.06:1 bg/base core inside it.
|
||||
const LICE_pixel handle = toLice(roleColor(Role::OverlayTrace));
|
||||
const LICE_pixel handleHot = toLice(roleColor(Role::AccentHot));
|
||||
const LICE_pixel core = toLice(roleColor(Role::BgBase));
|
||||
for (const EnvVertex& v : poly) {
|
||||
if (v.node == EnvNode::Origin || v.node == EnvNode::ReleaseEnd) continue;
|
||||
const bool grabbed = (drag_ == DragKind::kEnvNode && envNode_ == v.node);
|
||||
const int r = 3;
|
||||
const int r = grabbed ? kEnvHandleGrabbedRadius : kEnvHandleRadius;
|
||||
const int ir = r - kEnvHandleRingPx; // core radius; > 0 only when grabbed
|
||||
const int hx = (std::max)(area.x + r, (std::min)(area.right() - 1 - r, v.x));
|
||||
const int hy = (std::max)(area.y + r, (std::min)(area.bottom() - 1 - r, v.y));
|
||||
if (v.knot) {
|
||||
LICE_FillCircle(bmp, static_cast<float>(hx), static_cast<float>(hy),
|
||||
static_cast<float>(r), grabbed ? handleHot : handle, 1.0f, 0, true);
|
||||
static_cast<float>(r), handle, 1.0f, 0, true);
|
||||
if (grabbed)
|
||||
LICE_FillCircle(bmp, static_cast<float>(hx), static_cast<float>(hy),
|
||||
static_cast<float>(ir), core, 1.0f, 0, true);
|
||||
} else {
|
||||
LICE_FillRect(bmp, hx - r, hy - r, 2 * r, 2 * r, grabbed ? handleHot : handle, 1.0f,
|
||||
0);
|
||||
LICE_FillRect(bmp, hx - r, hy - r, 2 * r, 2 * r, handle, 1.0f, 0);
|
||||
if (grabbed) LICE_FillRect(bmp, hx - ir, hy - ir, 2 * ir, 2 * ir, core, 1.0f, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,17 @@ namespace {
|
||||
// this converts a KitColor's 8-bit alpha so a disabled surface composites at the right opacity.
|
||||
float drawAlpha(const KitColor& c) { return c.a / 255.0f; }
|
||||
|
||||
// Font::RegionTitle exists so an ACCENT-colored title can answer to the 3:1 indicator floor
|
||||
// instead of the 4.5:1 body floor. That entitlement is the font's, not the color's, so the
|
||||
// metrics are pinned here against theme's thresholds: shrink either one and the build stops
|
||||
// rather than silently reclassifying every pair drawn in it.
|
||||
constexpr int kRegionTitlePx = 19;
|
||||
constexpr int kRegionTitleWeight = FW_BOLD;
|
||||
static_assert(kRegionTitlePx >= ui::kLargeTextMinBoldPx, "region title must clear WCAG large");
|
||||
static_assert(kRegionTitleWeight >= FW_BOLD, "the large-bold threshold requires bold, not semi");
|
||||
|
||||
struct KitFonts {
|
||||
LICE_CachedFont regionTitle;
|
||||
LICE_CachedFont title;
|
||||
LICE_CachedFont label;
|
||||
LICE_CachedFont valueMono;
|
||||
@@ -65,6 +75,7 @@ void loadFont(LICE_CachedFont& dst, int pxHeight, int weight, const char* face)
|
||||
LICE_CachedFont* fontFor(Font f) {
|
||||
if (!g_fonts.ready) return nullptr;
|
||||
switch (f) {
|
||||
case Font::RegionTitle: return &g_fonts.regionTitle;
|
||||
case Font::Title: return &g_fonts.title;
|
||||
case Font::Label: return &g_fonts.label;
|
||||
case Font::ValueMono: return &g_fonts.valueMono;
|
||||
@@ -136,6 +147,7 @@ RECT toRect(const KitBox& b) {
|
||||
|
||||
void kitFontsInit() {
|
||||
if (g_fonts.ready) return; // idempotent
|
||||
loadFont(g_fonts.regionTitle, kRegionTitlePx, kRegionTitleWeight, "Segoe UI");
|
||||
loadFont(g_fonts.title, 15, FW_SEMIBOLD, "Segoe UI");
|
||||
loadFont(g_fonts.label, 12, FW_NORMAL, "Segoe UI");
|
||||
loadFont(g_fonts.valueMono, 12, FW_NORMAL, "Consolas");
|
||||
@@ -147,6 +159,7 @@ void kitFontsShutdown() {
|
||||
if (!g_fonts.ready) return; // idempotent
|
||||
// g_fonts is a static instance, never re-created, so free the HFONTs explicitly:
|
||||
// handing each a null font with OWNS_HFONT cleans up the prior HFONT (lice_text.h).
|
||||
g_fonts.regionTitle.SetFromHFont(nullptr, LICE_FONT_FLAG_OWNS_HFONT);
|
||||
g_fonts.title.SetFromHFont(nullptr, LICE_FONT_FLAG_OWNS_HFONT);
|
||||
g_fonts.label.SetFromHFont(nullptr, LICE_FONT_FLAG_OWNS_HFONT);
|
||||
g_fonts.valueMono.SetFromHFont(nullptr, LICE_FONT_FLAG_OWNS_HFONT);
|
||||
|
||||
@@ -42,13 +42,14 @@ using ui::ListRowBox;
|
||||
using ui::Role;
|
||||
using ui::SliderGeometry;
|
||||
|
||||
// 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.
|
||||
// The kit's 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
|
||||
ValueMono, // ~12px tabular/mono — numbers (dB/ms/notes) that must not jitter
|
||||
Micro, // ~10px dim — units, counts, keybinding sub-labels
|
||||
RegionTitle, // 19px BOLD — text that must qualify as WCAG large-scale (3:1 floor)
|
||||
Title, // ~15px semibold — headings (BODY class: 4.5:1 floor)
|
||||
Label, // ~12px regular — labels, body
|
||||
ValueMono, // ~12px tabular/mono — numbers (dB/ms/notes) that must not jitter
|
||||
Micro, // ~10px dim — units, counts, keybinding sub-labels
|
||||
};
|
||||
|
||||
// Horizontal text alignment for text(). Vertical is always centered in the rect (the kit's
|
||||
@@ -58,7 +59,7 @@ enum class Align { Left, Center, Right };
|
||||
// The one place a pure KitColor becomes a LICE_pixel. Defined in draw_kit.cpp.
|
||||
LICE_pixel toLice(const KitColor& c);
|
||||
|
||||
// Creates the four cached fonts once; idempotent. Segoe UI for title/label/micro,
|
||||
// Creates the cached fonts once; idempotent. Segoe UI for region-title/title/label/micro,
|
||||
// Consolas (tabular) for value-mono. No-op-safe: if font creation fails, text()
|
||||
// draws nothing rather than crashing.
|
||||
void kitFontsInit();
|
||||
|
||||
@@ -327,12 +327,14 @@ void drawRegionHeader(LICE_IBitmap* bmp, const RECT& region, const char* title,
|
||||
// Title, left. The two regions are distinct KINDS of container, so the title carries a
|
||||
// CATEGORICAL accent (secondary/tertiary mark kinds, never intensity) — Pool = secondary
|
||||
// teal, Banks = tertiary purple. This is a category mark, NOT the "what's live" signal
|
||||
// (that stays the primary-lime "Active:" readout beside it).
|
||||
// (that stays the primary-lime "Active:" readout beside it). Font::RegionTitle, not
|
||||
// Font::Title: an accent this deep only clears the 3:1 indicator floor, so the type has to
|
||||
// be large enough to be ENTITLED to it — see draw_kit.cpp's metrics static_assert.
|
||||
RECT titleRc = hdr;
|
||||
titleRc.left += 8;
|
||||
titleRc.right = titleRc.left + 120;
|
||||
const Role titleRole = poolBtnIsPool ? Role::AccentSecondary : Role::AccentTertiary;
|
||||
kitText(bmp, toKitBox(titleRc), title, Font::Title, titleRole, Align::Left);
|
||||
kitText(bmp, toKitBox(titleRc), title, Font::RegionTitle, titleRole, Align::Left);
|
||||
|
||||
// Active-bank readout — the UNMISTAKABLE indicator, in the PRIMARY accent role in BOTH
|
||||
// region headers so the active/capture-target bank is legible even when it is not the
|
||||
|
||||
@@ -198,7 +198,9 @@ inline constexpr int kTooltipCharPx = 7;
|
||||
inline constexpr int kTooltipTextH = 14;
|
||||
|
||||
// Client area top to bottom: top toolbar | split body | bottom toolbar | footer.
|
||||
inline constexpr int kRegionHeaderHeight = 24;
|
||||
// 26, not 24: Font::RegionTitle's line box (19px em + Segoe UI's leading) is ~25px, and
|
||||
// DT_VCENTER clips to the rect.
|
||||
inline constexpr int kRegionHeaderHeight = 26;
|
||||
inline constexpr int kTabStripHeight = 26;
|
||||
inline constexpr int kSplitDividerHeight = 3;
|
||||
inline constexpr int kFullHtBtnWidth = 22;
|
||||
|
||||
Reference in New Issue
Block a user