Q-W1 pt2: core/shell/app relocation + sub-namespaces; one concrete ui::Rect (LTRB fork retired); slot_map split from bank_book; BankIndex→BankModel; 59/59 green
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
#include "core/ui/rect.h"
|
||||
// footer_bar — the REAPER-free, LICE-free layout + hit-test math for the bank_panel's L4
|
||||
// footer LEFT group: the narrowed [Arrange|Design] mode toggle, its compact per-mode count
|
||||
// label, and the Tail button, laid out left-to-right at the footer's left. The panel shell
|
||||
// (bank_panel.cpp) owns the SWELL window, LICE drawing, and the click dispatch (cycle tail /
|
||||
// activate a mode); what is NOT DAW-bound — WHERE the toggle box, the count label, and the
|
||||
// Tail button sit, and which one a click lands on — lives here so it is unit-tested outside
|
||||
// the DAW (CLAUDE.md §load-bearing split). Mirror of action_bar / mode_switch / prune_button.
|
||||
//
|
||||
// -- Footer affordance order (L4, left -> right) -------------------------------
|
||||
//
|
||||
// [Arrange|Design] toggle . count label . Tail button . ... . Prune (rightmost, warn)
|
||||
//
|
||||
// The two view/session controls (mode toggle, tail) group at the LEFT as the "how this
|
||||
// panel/capture behaves" cluster; Prune stays isolated at the far RIGHT, warn-colored and
|
||||
// set apart (it is the only byte-deleting affordance). This module lays out the LEFT group
|
||||
// ONLY — the rightmost Prune button remains owned by prune_button (computePruneButton), so
|
||||
// the two never fight over the same pixels. footer_bar reserves a right margin (rightReserve)
|
||||
// so its own affordances never run under the prune button's region.
|
||||
//
|
||||
// The mode toggle is drawn as an N-segment control (2 segments for Arrange|Design; N general).
|
||||
// footer_bar returns only the toggle's BOX (fit to its text width); the shell hands that box's
|
||||
// width to the pure mode_switch (computeSegmentRects / hitTestSegment) for the per-segment
|
||||
// tiling and hit-test, so mode_switch stays the ONE owner of segment geometry. footer_bar
|
||||
// decides the toggle's placement + overall width; mode_switch subdivides it.
|
||||
//
|
||||
// Naming: the rect-role family (ButtonRect / FooterRect / FooterBarRect / ...) is unified on
|
||||
// the ONE concrete ui::Rect (core/ui/rect.h, Q-W1 T2-05) — the per-role names are aliases, so
|
||||
// the former hand-collision bookkeeping is retired. FooterRect (prune_button) remains the
|
||||
// shared input-strip spelling; this module's output/spec/hit types carry the FooterBar* prefix.
|
||||
//
|
||||
// PURE MODULE: NO REAPER types, NO SWELL, NO LICE, NO vendor/ includes. Standard library only.
|
||||
|
||||
#include "core/ui/prune_button.h" // FooterRect — the footer strip input type (shared, not re-minted)
|
||||
|
||||
namespace reasampler::ui {
|
||||
|
||||
// One placed affordance's pixel rectangle within the footer, top-left origin. A zero-area rect
|
||||
// (empty()) means "not placed" (the footer was too narrow to host it after the ones before it),
|
||||
// so the shell draws/hit-tests nothing for it — graceful degradation, mirroring prune_button.
|
||||
using FooterBarRect = Rect; // Q-W1: the shared concrete ui::Rect (core/ui/rect.h), role-aliased
|
||||
|
||||
// The laid-out footer LEFT group: the mode toggle box, the count label box, and the Tail
|
||||
// button box, in left-to-right order. Any box may be empty (suppressed) when the footer is
|
||||
// too narrow to fit it left of the reserved right margin — placement is greedy left-to-right,
|
||||
// so an earlier affordance survives while a later one drops (the toggle is most important,
|
||||
// the Tail button drops first on a very narrow footer).
|
||||
struct FooterBarLayout {
|
||||
FooterBarRect toggle; // the [Arrange|Design] segmented control's overall box
|
||||
FooterBarRect count; // the compact per-mode count label (right of the toggle)
|
||||
FooterBarRect tail; // the Tail button (right of the count label)
|
||||
|
||||
bool operator==(const FooterBarLayout& o) const {
|
||||
return toggle == o.toggle && count == o.count && tail == o.tail;
|
||||
}
|
||||
};
|
||||
|
||||
// Which footer LEFT-group affordance a point landed on (or None for a miss / a suppressed
|
||||
// affordance). Prune is NOT here — the shell hit-tests it separately via hitTestPruneButton.
|
||||
enum class FooterHit { None, Toggle, Tail };
|
||||
|
||||
// Layout inputs for the footer LEFT group, in pixels. Defaults are the bank_panel footer
|
||||
// metrics; the shell passes its own so draw and hit-test share ONE source of truth.
|
||||
// * toggleWidth — the [Arrange|Design] toggle's overall width. Sized to fit its two
|
||||
// segment labels comfortably (a NARROW control, per L4 §3 — no longer the
|
||||
// full-width top header). The shell picks this to fit its text; the pure
|
||||
// module treats it as a fixed input.
|
||||
// * countWidth — the compact per-mode count label's width (e.g. "2 tracks"). 0 hides it.
|
||||
// * tailWidth — the Tail button's width (fits "Tail: Manual 8.0s" comfortably).
|
||||
// * gap — horizontal gap between adjacent affordances.
|
||||
// * leftPad — inset from the footer left edge to the toggle's left edge.
|
||||
// * verticalInset — top/bottom gap inside the footer so the controls read as raised, not
|
||||
// full-height fills (matches prune_button's verticalInset).
|
||||
// * rightReserve — pixels reserved at the footer's RIGHT for the prune button + version
|
||||
// readout region; footer_bar never places an affordance whose right edge
|
||||
// would cross into (footer.right - rightReserve). Keeps the LEFT group
|
||||
// clear of the RIGHT prune/version region without those modules coupling.
|
||||
struct FooterBarSpec {
|
||||
int toggleWidth = 132;
|
||||
int countWidth = 64;
|
||||
int tailWidth = 132;
|
||||
int gap = 6;
|
||||
int leftPad = 8;
|
||||
int verticalInset = 4;
|
||||
int rightReserve = 168; // clears prune_button (rightInset 84 + width 72) + margin
|
||||
};
|
||||
|
||||
// Lays out the footer LEFT group inside `footer` per `spec`, left-to-right: toggle, then the
|
||||
// count label, then the Tail button, each `gap` px apart, starting at footer.left + leftPad,
|
||||
// vertically centred by verticalInset. Greedy: an affordance is placed only if its whole box
|
||||
// fits left of (footer.right - rightReserve); otherwise it (and, since placement is ordered,
|
||||
// it alone or the ones after it) is suppressed (empty box). A degenerate footer (width/height
|
||||
// <= 0) yields an all-empty layout. countWidth <= 0 suppresses the count label (and the gap
|
||||
// that would precede the Tail button collapses so the Tail sits right after the toggle).
|
||||
FooterBarLayout computeFooterBar(const FooterRect& footer, const FooterBarSpec& spec);
|
||||
|
||||
// The footer LEFT-group affordance the point (px, py) (SWELL/LICE top-left client coords) lands
|
||||
// on, or FooterHit::None for a miss (outside every placed box, or on the count label — which is
|
||||
// a passive readout, not a control). Half-open bounds [x, x+width) x [y, y+height) match
|
||||
// computeFooterBar so draw and hit-test agree on the same pixels. An empty (suppressed) box
|
||||
// never claims a point. The shell checks the toggle hit FIRST for a segment sub-hit (via
|
||||
// mode_switch over the toggle box), then the Tail hit; this returns which region was struck.
|
||||
FooterHit hitTestFooterBar(int px, int py, const FooterBarLayout& layout);
|
||||
|
||||
} // namespace reasampler::ui
|
||||
Reference in New Issue
Block a user