Fix deck-UI review findings: right-anchor MASTER's meter column, correct stale/overclaiming comments, split test_deck_groups.cpp on its commit-tier/overlay seam, and pin two width-ceiling assertions.

This commit is contained in:
2026-08-02 08:45:35 -04:00
parent df10ddacc2
commit 41876674e4
5 changed files with 304 additions and 231 deletions
+4
View File
@@ -79,6 +79,10 @@ reasampler_pure_library(deck_groups
# assertion needs the band allocator, and the MASTER-reserve identity needs the column width the
# PRIVATE edge above does not re-export.
reasampler_test(deck_groups LINK deck_groups sample_bands master_meter)
# The commit-tier + overlay-selection state machine, split out of deck_groups_tests on the seam
# those fixtures already had: deckParamCommit/liveCommitFor and the overlay predicates are pure
# control-id/enum logic that touches no layout, so this target needs no sample_bands/master_meter.
reasampler_test(deck_groups_state LINK deck_groups)
# The point-editing grammar both spline consumers share, so it links the curve itself (unlike
# envelope_overlay/envelope_edit, which stay engine-free — the staged envelopes touch no curve).
+7 -5
View File
@@ -8,8 +8,8 @@ namespace reasampler::instrument::ui {
namespace {
// The knob-row width of a group: cells side by side (no inter-cell gap — the 48px cell
// already carries its own breathing room around the 28px knob), plus the optional row
// The knob-row width of a group: cells side by side (no inter-cell gap — the 60px cell
// already carries its own breathing room around the 40px knob), plus the optional row
// toggle after a kDeckToggleGap. A spanning group's cells stack, so its knob row is one
// cell wide plus whatever readout column sits beside it.
int knobRowWidth(const DeckGroupDesc& g) {
@@ -109,8 +109,10 @@ DeckGroupLayout layoutGroup(const DeckGroupDesc& g, const Rect& box) {
slotTop += kDeckGroupH + kDeckRowGap;
}
if (g.column.id >= 0) {
// ONE rect spanning every slot, not a readout per row.
const int colX = innerLeft + (g.cellIds.empty() ? 0 : kDeckCellW + kDeckColumnGap);
// ONE rect spanning every slot, not a readout per row. Right-anchored off
// innerRight rather than measured past the cell slot, so a wider caption
// reserve on this group can never detach the column from the padding.
const int colX = innerRight - g.column.width;
out.column = DeckColumnLayout{
g.column.id, Rect::ltrb(colX, cellTop, colX + g.column.width,
box.bottom() - kDeckGroupPadY)};
@@ -156,7 +158,7 @@ std::vector<int> justifyGutters(int count, int total, int blockW) {
const int slack = blockW - total;
if (slack < gutters * kDeckGroupGap) {
// The block cannot hold the row: minimum gutters, and the row overruns to the right
// rather than wrapping. Unreachable in the editor — see layoutDeck's header note.
// rather than wrapping — see layoutDeck's header note for when this degrade applies.
return std::vector<int>(static_cast<std::size_t>(gutters), kDeckGroupGap);
}
const int base = slack / gutters;
+6 -8
View File
@@ -1,12 +1,8 @@
// knob_deck.h — knob-deck layout + hit-test for the Sample-face knob deck. Engine-free
// like param_slider: cells and toggles carry opaque shell-owned control ids. Mirror of
// action_bar/param_slider; the knob primitive itself (value<->needle-angle, drag) is
// param_slider's — a knob cell here is just a rect the shell composes it into.
//
// A group is a fenced box: caption row (caption left, toggles and a corner radio
// right-anchored) over a knob row of equal-width cells, optionally followed by one row
// toggle. Row membership is a PROPERTY OF THE GROUP (DeckRow), never a wrap outcome — see
// the justification law at layoutDeck.
// param_slider's — a knob cell here is just a rect the shell composes it into. Group/row
// composition and the justification law are this directory's own CLAUDE.md's to describe.
#pragma once
@@ -31,7 +27,8 @@ inline constexpr int kDeckGroupPadY = 4; // group box vertical inner paddin
inline constexpr int kDeckCaptionGap = 2; // caption row -> knob row gap
inline constexpr int kDeckToggleGap = 4; // caption text -> toggle / cells -> row toggle gap
inline constexpr int kDeckGroupGap = 12; // gap between groups on a row
inline constexpr int kDeckRowGap = 8; // gap between wrapped deck rows
inline constexpr int kDeckRowGap = 8; // gap between the deck's two categorical rows,
// and between the spanning deck's stacked slots
inline constexpr int kDeckRadioSize = 12; // the caption-row corner radio square
inline constexpr int kDeckColumnGap = 8; // the spanning deck's cell column -> its readout column
// The knob cell's INNER dial: a concentric sub-disc that edits a second, related value while
@@ -181,7 +178,8 @@ int deckHeight(const std::vector<DeckGroupDesc>& groups);
// divided equally with the integer residue going to the leftmost ones. Decks are never
// stretched. Below the width the block needs, every gutter sits at kDeckGroupGap and the row
// overflows right rather than wrapping — the shell clamps the window to a floor that fits
// (sample_bands' kEditorMinWidth), so that degrade is unreachable in the editor.
// (sample_bands' kEditorMinWidth) via checkSizeConstraint, a host-honoured clamp rather than a
// guarantee, so this degrade is defined and tested rather than assumed impossible.
DeckLayout layoutDeck(const std::vector<DeckGroupDesc>& groups, int left, int top,
int availWidth);