Raise the editor floor to 1190x680, derived from the deck's declared width budget, and make row membership a property of the group
This commit is contained in:
@@ -314,7 +314,7 @@ anything for a trigger shape.
|
||||
- `browser_scroll` — scroll + type-to-filter layered over `capture_browser`: vertical scroll offset, scrollbar thumb, thumb-drag mapping, and name-substring search.
|
||||
- `param_slider` — parameter control-panel: vertical stack of TOGGLE (two-segment selector) and SLIDER (horizontal track) rows; maps normalized value to/from handle pixel.
|
||||
- `embed_strip` — compact single-row control layout for embed mode in the track FX chain.
|
||||
- `knob_deck` — pure knob-deck layout + hit-test (FB1): group-box / caption-row / compact-toggle / knob-cell geometry, deterministic whole-group wrap, `DeckLayout` / `DeckHit`. Mirror of `action_bar`/`param_slider`; no LICE or REAPER types. Carries a SECOND hit-test, `hitTestKnobFace`, resolved against the drawn CIRCLES rather than the cell: a double-click reset is aimed at a dial, so the label band and the cell margins must miss where a drag grab deliberately does not, and only a radial resolve can tell the inner curve dial from the outer ring it sits inside. **The cell/knob/label sizes and `sample_bands`' editor floor move as a pair** — wider cells need a wider floor width or the deck wraps to a fourth row. A group carries TWO caption-toggle slots, laid right-to-left: the second exists because a group whose knob row is wider than its caption row has caption slack a toggle can occupy for free, and the deck has fourteen pixels of headroom on its first row at the editor's floor width — a `rowToggle` would widen the GROUP and wrap the deck to a fourth row, past what the minimum window holds. **A group's cell run is a RESERVED WIDTH, not a fixed cell size**: a `-1` id reserves one cell's width without a cell, and the cells present divide the whole run between them at one uniform integer width (residue in symmetric end margins). That is what lets a mode flip drop controls from a face — Trigger's AMP and FILTER ENV lose their Sustain/Release stages — without either reflowing the deck or leaving dead slots in the box; a face with fewer controls simply gets roomier cells. Do not reintroduce fixed-width cells with blank slots.
|
||||
- `knob_deck` — pure knob-deck layout + hit-test (FB1): group-box / caption-row / compact-toggle / knob-cell geometry, deterministic whole-group wrap, `DeckLayout` / `DeckHit`. Mirror of `action_bar`/`param_slider`; no LICE or REAPER types. Carries a SECOND hit-test, `hitTestKnobFace`, resolved against the drawn CIRCLES rather than the cell: a double-click reset is aimed at a dial, so the label band and the cell margins must miss where a drag grab deliberately does not, and only a radial resolve can tell the inner curve dial from the outer ring it sits inside. The deck's width budget at the editor's floor — the row block, the spanning deck's reserve, the ceiling, and what drives the floor — is declared and reasoned at the constants themselves (`knob_deck.h`); every group's categorical row is `deck_groups`' `deckRowFor`. A group carries TWO caption-toggle slots, laid right-to-left: the second exists because a group whose knob row is wider than its caption row has caption slack a toggle can occupy for free, where a `rowToggle` widens the GROUP and is charged against that budget — which is why the env decks' mode toggles ride the caption row. **A group's cell run is a RESERVED WIDTH, not a fixed cell size**: a `-1` id reserves one cell's width without a cell, and the cells present divide the whole run between them at one uniform integer width (residue in symmetric end margins). That is what lets a mode flip drop controls from a face — Trigger's AMP and FILTER ENV lose their Sustain/Release stages — without either reflowing the deck or leaving dead slots in the box; a face with fewer controls simply gets roomier cells. Do not reintroduce fixed-width cells with blank slots.
|
||||
- `deck_values` — the deck's control-id ↔ parameter-set BINDING and its display units, split
|
||||
from the editor shell on the same axis `deck_groups` was split from `knob_deck`: `deck_groups`
|
||||
says which controls exist, this says what each one's value MEANS. Holds `deckParamNorm` /
|
||||
|
||||
@@ -130,6 +130,29 @@ std::vector<DeckGroupDesc> sampleDeckGroups(PlayMode playMode) {
|
||||
return out;
|
||||
}
|
||||
|
||||
DeckRow deckRowFor(DeckGroupId group) {
|
||||
// Every enumerator listed and no default, on the same gate isLiveDeckParam below relies on.
|
||||
switch (group) {
|
||||
case kGroupPitch:
|
||||
case kGroupFilter:
|
||||
case kGroupVelocity:
|
||||
case kGroupVoice:
|
||||
return DeckRow::Sound;
|
||||
case kGroupPitchEnv:
|
||||
case kGroupFilterEnv:
|
||||
case kGroupAmpEnv:
|
||||
return DeckRow::Contour;
|
||||
case kGroupMaster:
|
||||
return DeckRow::Spanning;
|
||||
}
|
||||
// Unreachable for a valid enumerator, and Spanning rather than Sound ON PURPOSE: the
|
||||
// -Wswitch gate is compiler-dependent, so on a toolchain that does not raise it a dropped
|
||||
// case arm falls here instead. Sound is what a new group most plausibly IS, which would
|
||||
// make the fall-through invisible; Spanning is the one row nothing may silently join, so
|
||||
// the tests' partition count catches it.
|
||||
return DeckRow::Spanning;
|
||||
}
|
||||
|
||||
CurveTarget curveTargetFor(int controlId) {
|
||||
switch (static_cast<DeckParam>(controlId)) {
|
||||
case DeckParam::kAmpVelCurve: return CurveTarget::kAmp;
|
||||
|
||||
@@ -101,6 +101,16 @@ enum DeckGroupId {
|
||||
kGroupMaster,
|
||||
};
|
||||
|
||||
// The deck's two categorical rows, plus the row-spanning bus deck. Sound is what the voice
|
||||
// IS, Contour is how it moves over time, Spanning is what happens after the mixer.
|
||||
enum class DeckRow { Sound, Contour, Spanning };
|
||||
|
||||
// Which row a group belongs to. Membership is a property of the GROUP; width is a property of
|
||||
// its descriptor — separating them is what lets the row law be settled while the descriptors
|
||||
// are still moving. Total over DeckGroupId by an exhaustive switch with no default, so a group
|
||||
// added without a row cannot silently become Sound.
|
||||
DeckRow deckRowFor(DeckGroupId group);
|
||||
|
||||
// Which velocity curve a deck cell edits, or kNone when the control is an ordinary knob. THE
|
||||
// one place a control id resolves to a curve target — paint (draw a curve thumbnail, not a
|
||||
// dial) and hit-test (open a popup, not start a drag) both read this predicate rather than
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
namespace reasampler::instrument::ui {
|
||||
|
||||
// Fixed deck metrics, exposed so the shell and tests agree. The cell/knob/label sizes were
|
||||
// raised together for legibility at high pixel densities; the editor's floor width
|
||||
// (sample_bands) is what absorbs the wider cells, so the two move as a pair.
|
||||
// raised together for legibility at high pixel densities. The deck's cell metrics AND its
|
||||
// group/row composition BOTH drive sample_bands' kEditorMinWidth; none of the three may move
|
||||
// alone.
|
||||
inline constexpr int kDeckCellW = 60; // one knob cell
|
||||
inline constexpr int kDeckCellH = 74;
|
||||
inline constexpr int kDeckKnobSize = 40; // knob diameter inside the cell
|
||||
@@ -46,6 +47,19 @@ inline constexpr int kDeckInnerDialSize = 20;
|
||||
inline constexpr int kDeckGroupH =
|
||||
kDeckGroupPadY + kDeckCaptionH + kDeckCaptionGap + kDeckCellH + kDeckGroupPadY;
|
||||
|
||||
// --- The deck's width budget at the editor's floor ------------------------------------
|
||||
// DECLARATIONS of budget, not measurements: nothing here is computed from a descriptor, and a
|
||||
// group inventory that overruns one is what fails. sample_bands' kEditorMinWidth is derived
|
||||
// from the first two — kDeckRowBlockW + kDeckGroupGap + kDeckSpanningW + 2*kPad — and the
|
||||
// identity is asserted in test_deck_groups.cpp rather than coded, so the allocator keeps no
|
||||
// include edge to this header.
|
||||
inline constexpr int kDeckRowBlockW = 1020; // the block both categorical rows justify inside
|
||||
inline constexpr int kDeckSpanningW = 142; // the right-anchored spanning deck, outside the block
|
||||
// The hard ceiling the FLOOR may not exceed; the window itself still grows freely above it.
|
||||
// The gap between it and kEditorMinWidth is the whole width budget for the life of this
|
||||
// layout — see instrument-control-surface.md §1.6 before spending any of it.
|
||||
inline constexpr int kEditorCeilingWidth = 1280;
|
||||
|
||||
// A two-segment compact toggle (always 2 segments — the Mono/Stereo grammar). id -1 = absent.
|
||||
struct DeckToggleDesc {
|
||||
int id = -1; // shell control id returned by the hit-test; -1 = no toggle
|
||||
|
||||
@@ -16,7 +16,12 @@ inline constexpr int kPad = 8;
|
||||
// exactly this, and there is no scroll, so anything smaller pushes the deck band off the
|
||||
// window bottom (computeSampleBands' waveform-floor-wins degrade). Growing is fine — the
|
||||
// waveform band is the elastic one. Both the enforced minimum and the opening rect read this.
|
||||
inline constexpr int kEditorMinWidth = 980;
|
||||
//
|
||||
// The width is a LITERAL here on purpose, though it is derived from knob_deck's width budget:
|
||||
// this allocator is deliberately independent of the deck (it takes deckHeight as a parameter
|
||||
// for exactly that reason), so the derivation is asserted in test_deck_groups.cpp — the one
|
||||
// place that already includes both headers — rather than coded as an include edge.
|
||||
inline constexpr int kEditorMinWidth = 1190;
|
||||
inline constexpr int kEditorMinHeight = 680;
|
||||
|
||||
// Chrome band: the toolbar row (title + nav) stacked over the control row (piano strip,
|
||||
|
||||
Reference in New Issue
Block a user