#pragma once // rect.h — the ONE concrete pixel rectangle (Q-W1, T2-05 ≡ T4-21). // // Before Q-W1 the codebase carried 12+ byte-identical {x, y, width, height} structs // (ButtonRect / FooterRect / CellRect / KitBox / ...) plus a second LTRB grammar on // the VST side (editor_geometry's left/top/right/bottom Rect). This is the single // owner: one CONCRETE type (deliberately NOT a template — the role types differed in // name only, so a template would model nothing), with per-role aliases at the old // definition sites so call sites keep their semantic names // (`using ButtonRect = ui::Rect;`). // // Grammar: XYWH storage (the majority grammar — every extension role struct), with // right()/bottom() accessors and an ltrb() factory so the former LTRB call sites // convert mechanically. Half-open on both axes: a rect covers // [x, x+width) × [y, y+height) — the same convention LICE/SWELL RECTs use, and the // one every hitTest* in the codebase already implements. // // PURE MODULE: standard library only. Header-only; behavior is covered by the role // modules' own test executables (prune_button / footer_bar / bank_grid / ... and the // instrument-ui suites), which exercise every alias against these semantics. namespace reasampler::ui { struct Rect { int x = 0; int y = 0; int width = 0; int height = 0; // Exclusive edges (half-open convention). int right() const { return x + width; } int bottom() const { return y + height; } // A zero-or-negative-area rect means "not placed / suppressed": the caller must // not draw or hit-test it (the shared graceful-degradation contract). bool empty() const { return width <= 0 || height <= 0; } // The former LTRB grammar's constructor (editor_geometry and friends): edges in, // extents stored. right/bottom exclusive, matching right()/bottom(). static Rect ltrb(int left, int top, int right, int bottom) { return Rect{left, top, right - left, bottom - top}; } bool operator==(const Rect& o) const { return x == o.x && y == o.y && width == o.width && height == o.height; } bool operator!=(const Rect& o) const { return !(*this == o); } }; // True iff (px, py) falls inside r under the half-open convention. An empty rect // contains nothing, so a suppressed affordance can never claim a click. inline bool contains(const Rect& r, int px, int py) { return px >= r.x && px < r.x + r.width && py >= r.y && py < r.y + r.height; } } // namespace reasampler::ui