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:
+72
-21
@@ -64,12 +64,11 @@ static void testTextDimClearsItsFloorOnSurfaces() {
|
||||
}
|
||||
|
||||
static void testAccentsClearIndicatorFloorOnCell() {
|
||||
// DS-2 revised (grey re-read): each of the three pastel accents is used as a state
|
||||
// indicator / active fill on bg/cell (selection border, active segment, active tab).
|
||||
// The greyer surface shrank the cushion from ~15:1 (near-black) to ~6-7:1 (grey), so
|
||||
// this is re-verified on bg/cell (NOT the old near-black) at the 3:1 large/indicator
|
||||
// floor. If any pastel dropped below, the fix is to nudge that hue deeper (hue stays
|
||||
// lime/teal/purple) — the value the test locks proves it did not need it here.
|
||||
// Each accent is used as a state indicator / active fill on bg/cell (selection border,
|
||||
// active segment, active tab). The move to REAPER grey shrank the cushion from ~15:1 on
|
||||
// near-black to 3.9:1 (secondary) - 8.7:1 (hot), so the floor is verified on bg/cell, NOT
|
||||
// the old near-black. If a pastel drops below, nudge that hue deeper; hue stays
|
||||
// lime/teal/purple.
|
||||
for (Role a : {Role::AccentPrimary, Role::AccentSecondary, Role::AccentTertiary,
|
||||
Role::AccentHot}) {
|
||||
CHECK(contrastRatio(roleColor(a), roleColor(Role::BgCell))
|
||||
@@ -78,13 +77,21 @@ static void testAccentsClearIndicatorFloorOnCell() {
|
||||
// The primary accent also leads the mode-switch/tab active fill drawn over bg/base.
|
||||
CHECK(contrastRatio(roleColor(Role::AccentPrimary), roleColor(Role::BgBase))
|
||||
>= textFloor(TextClass::Large));
|
||||
// bank_panel draws categorical accents as text on bg/panel (region-title band):
|
||||
// AccentSecondary/Tertiary as region-title text; AccentPrimary as the "Active:" readout.
|
||||
// Verify all three clear the 3:1 large/indicator floor on bg/panel (the ACTUAL draw surface).
|
||||
}
|
||||
|
||||
// The docked panel's region-title band: secondary/tertiary as the title itself, primary as the
|
||||
// "Active:" readout beside it, all on bg/panel. The titles clear the 3:1 indicator floor and
|
||||
// NOT the 4.5:1 body floor (secondary sits at 4.38:1), so they are drawn in Font::RegionTitle —
|
||||
// 19px bold, which is what ENTITLES them to the large-text floor. draw_kit.cpp static_asserts
|
||||
// those metrics against theme's thresholds; that assert and this pair are one guard in two
|
||||
// halves, and removing either re-opens the AA failure that 15px semibold hid.
|
||||
static void testRegionTitleAccentsClearLargeFloorOnPanel() {
|
||||
for (Role a : {Role::AccentPrimary, Role::AccentSecondary, Role::AccentTertiary}) {
|
||||
CHECK(contrastRatio(roleColor(a), roleColor(Role::BgPanel))
|
||||
>= textFloor(TextClass::Large));
|
||||
}
|
||||
// Tighter pin at the measured value, so drift is caught before it reaches the floor.
|
||||
CHECK(contrastRatio(roleColor(Role::AccentSecondary), roleColor(Role::BgPanel)) >= 4.3);
|
||||
}
|
||||
|
||||
// Text drawn ON a pastel accent fill (retained tight pair, re-verified for the pastels):
|
||||
@@ -122,23 +129,65 @@ static void testSecondaryTertiaryAreDistinguishable() {
|
||||
}
|
||||
|
||||
// The envelope overlay is traced OVER the waveform, which draws in the primary accent — an
|
||||
// accent-on-accent pair no surface floor covers, since neither is a surface. overlay/trace
|
||||
// exists so that pair can clear the real 3:1 indicator floor; every categorical accent is light
|
||||
// enough to sit under 2:1 against the lime, so pointing the trace back at one fails here.
|
||||
// accent-on-accent pair no surface floor covers, since neither is a surface. Every categorical
|
||||
// accent is light enough to sit under 2:1 against the lime, so pointing the trace back at one
|
||||
// fails here.
|
||||
static void testOverlayTraceClearsIndicatorFloorOnTheWaveform() {
|
||||
CHECK(contrastRatio(roleColor(Role::OverlayTrace), roleColor(Role::AccentPrimary))
|
||||
>= textFloor(TextClass::Large));
|
||||
}
|
||||
|
||||
// The trace's own surface floor. bg/base is the only surface it draws on (the waveform band
|
||||
// fills with it), and that confinement is forced, not convenient: clearing 3:1 against the lime
|
||||
// caps the trace's luminance at 0.183, while clearing 3:1 on bg/cell would demand 0.227. The two
|
||||
// are mutually exclusive, so this role must not be reused outside that band.
|
||||
// The trace's own surface floor, on the bg/base the waveform band fills with. This pair does
|
||||
// double duty: the GRABBED envelope handle is an overlay/trace ring around a bg/base core, so
|
||||
// the same number is also that mark's internal ring-vs-core contrast.
|
||||
static void testOverlayTraceClearsFloorOnItsDrawSurface() {
|
||||
CHECK(contrastRatio(roleColor(Role::OverlayTrace), roleColor(Role::BgBase))
|
||||
>= textFloor(TextClass::Large));
|
||||
}
|
||||
|
||||
// The velocity-curve trace is drawn in accent/secondary over a HOVER-lightened bg/cell (the
|
||||
// chrome band's mini preview button). Hover lightens the surface toward accent/hot, closing on
|
||||
// the deep teal from below: 3.03:1 against a 3:1 floor — the thinnest margin in the tree, and
|
||||
// the true binding limiter on how dark accent/secondary may go. No rest-surface check sees it.
|
||||
static void testCurveTraceOnHoverSurfaceClearsFloor() {
|
||||
CHECK(contrastRatio(roleColor(Role::AccentSecondary),
|
||||
roleColorState(Role::BgCell, InteractionState::Hover))
|
||||
>= textFloor(TextClass::Large));
|
||||
}
|
||||
|
||||
// The trace's OTHER two neighbours in the waveform rect, both composited or drawn beneath it.
|
||||
// Enumerating only bg/base under-counted them.
|
||||
// - The loop-span fill: accent/secondary at kLoopSpanFillAlpha over bg/base. The trace over
|
||||
// that composite is 2.25:1 — a KNOWN, ACCEPTED under-floor pair, pinned here as a RANGE so
|
||||
// it is recorded rather than silently believed to clear. The two-neighbour ceiling means no
|
||||
// trace value fixes it (clearing the fill breaks the lime or bg/base pair); if it is ever
|
||||
// resolved, the FILL is what changes, and this assertion is what will fail first.
|
||||
// - drawWaveform's line/hairline zero line, at 1.92:1. Also under floor, and also unfixable
|
||||
// from the trace's side.
|
||||
static void testOverlayTraceAgainstItsRemainingNeighbours() {
|
||||
const KitColor loopFill = compositeOver(roleColor(Role::AccentSecondary),
|
||||
roleColor(Role::BgBase), kLoopSpanFillAlpha);
|
||||
const double onFill = contrastRatio(roleColor(Role::OverlayTrace), loopFill);
|
||||
CHECK(onFill >= 2.2 && onFill < textFloor(TextClass::Large));
|
||||
const double onZeroLine = contrastRatio(roleColor(Role::OverlayTrace),
|
||||
roleColor(Role::LineHairline));
|
||||
CHECK(onZeroLine >= 1.9 && onZeroLine < textFloor(TextClass::Large));
|
||||
}
|
||||
|
||||
// compositeOver is the arithmetic the pairs above depend on, so anchor it: full alpha is the
|
||||
// overlay, zero alpha is the surface, and the composite of a lighter color over a darker one
|
||||
// lands strictly between the two.
|
||||
static void testCompositeOverAnchors() {
|
||||
const KitColor over = roleColor(Role::AccentSecondary);
|
||||
const KitColor under = roleColor(Role::BgBase);
|
||||
CHECK(compositeOver(over, under, 1.0) == over);
|
||||
CHECK(compositeOver(over, under, 0.0) == under);
|
||||
CHECK(compositeOver(over, under, 5.0) == over); // alpha clamps
|
||||
CHECK(compositeOver(over, under, -1.0) == under);
|
||||
const double mid = relativeLuminance(compositeOver(over, under, 0.5));
|
||||
CHECK(mid > relativeLuminance(under) && mid < relativeLuminance(over));
|
||||
}
|
||||
|
||||
// editor_paint_waveform.cpp draws the loop span/markers and the envelope overlay trace into
|
||||
// the SAME overlay rect, so they must read as two things. Luminance cannot carry that — each is
|
||||
// pinned near its own floor — so the separation is a hue one: teal leans green over red, the
|
||||
@@ -156,11 +205,9 @@ static void testLoopMarkerAndOverlayTraceAreDistinct() {
|
||||
}
|
||||
|
||||
// AccentSecondary was darkened from a pastel teal (#84D6D0) to a deep teal (#38A8A0, same
|
||||
// hue/saturation, lower lightness). Locks the re-measured numbers so a future palette nudge
|
||||
// that erodes past either the 3:1 indicator floor or the tighter AA 4.5:1 text-on-fill floor
|
||||
// fails the build. The text-on-fill pair (bg/base label on a secondary fill) is the binding
|
||||
// limiter — it clears with far less headroom (~4.9:1) than the indicator floor on bg/cell
|
||||
// (~3.9:1), which is why the value could not go darker than this.
|
||||
// hue/saturation, lower lightness). Locks the re-measured numbers so a future nudge that erodes
|
||||
// past either the 3:1 indicator floor or the AA 4.5:1 text-on-fill floor fails the build. The
|
||||
// binding limiter on going darker is NOT one of these — it is the hover-surface pair above.
|
||||
static void testAccentSecondaryDarkerTealClearsFloors() {
|
||||
const KitColor sec = roleColor(Role::AccentSecondary);
|
||||
CHECK(contrastRatio(sec, roleColor(Role::BgBase)) >= textFloor(TextClass::Large));
|
||||
@@ -296,11 +343,15 @@ int main() {
|
||||
testTextPrimaryClearsBodyFloorOnSurfaces();
|
||||
testTextDimClearsItsFloorOnSurfaces();
|
||||
testAccentsClearIndicatorFloorOnCell();
|
||||
testRegionTitleAccentsClearLargeFloorOnPanel();
|
||||
testTextOnPastelFillClearsBodyFloor();
|
||||
testTextOnHoverSurfaceClearsFloor();
|
||||
testCurveTraceOnHoverSurfaceClearsFloor();
|
||||
testSecondaryTertiaryAreDistinguishable();
|
||||
testOverlayTraceClearsIndicatorFloorOnTheWaveform();
|
||||
testOverlayTraceClearsFloorOnItsDrawSurface();
|
||||
testOverlayTraceAgainstItsRemainingNeighbours();
|
||||
testCompositeOverAnchors();
|
||||
testLoopMarkerAndOverlayTraceAreDistinct();
|
||||
testAccentSecondaryDarkerTealClearsFloors();
|
||||
testWarnClearsStateFloorOnBackground();
|
||||
|
||||
Reference in New Issue
Block a user