// editor_geometry.cpp — see editor_geometry.h. Pure math; no host types. #include "editor_geometry.h" #include namespace reasampler::vst { namespace { // Spike editor layout constants. These are the editor's fixed metrics; the real // editor (S4/S5) will parameterize as its content demands. constexpr int kTitleBarHeight = 28; constexpr int kButtonMargin = 10; constexpr int kButtonWidth = 120; constexpr int kButtonHeight = 24; } // namespace bool contains(const Rect& r, int x, int y) { if (r.width() <= 0 || r.height() <= 0) return false; return x >= r.left && x < r.right && y >= r.top && y < r.bottom; } EditorLayout layoutEditor(int w, int h) { // Clamp the surface to non-negative extents so a degenerate view can't produce // inverted rects. const int cw = std::max(0, w); const int ch = std::max(0, h); EditorLayout out; // Title bar spans the top, clamped so it never exceeds the client height. const int titleH = std::min(kTitleBarHeight, ch); out.titleBar = Rect{0, 0, cw, titleH}; // Canvas is everything below the title bar. out.canvas = Rect{0, titleH, cw, ch}; // Button sits at the top-left of the canvas, inset by a margin, and is clamped to // fit inside the canvas so it never overhangs on a small view. const int bx = out.canvas.left + kButtonMargin; const int by = out.canvas.top + kButtonMargin; const int bRight = std::min(bx + kButtonWidth, out.canvas.right); const int bBottom = std::min(by + kButtonHeight, out.canvas.bottom); out.button = Rect{bx, by, std::max(bx, bRight), std::max(by, bBottom)}; return out; } HitTarget hitTest(const EditorLayout& layout, int x, int y) { if (contains(layout.button, x, y)) return HitTarget::kButton; return HitTarget::kNone; } Rect sampleRowRect(const EditorLayout& layout, int index) { if (index < 0) return Rect{}; const int top = layout.canvas.top + index * kSampleRowHeight; return Rect{layout.canvas.left, top, layout.canvas.right, top + kSampleRowHeight}; } int sampleRowHitTest(const EditorLayout& layout, int rowCount, int x, int y) { if (rowCount <= 0) return -1; // Must be within the canvas horizontally and at/below its top. if (x < layout.canvas.left || x >= layout.canvas.right) return -1; if (y < layout.canvas.top) return -1; // Clip at the canvas bottom: clicks in the canvas's dead-zone below the last // visible row agree with sampleRowRect, which does not clamp rows to canvas.bottom. if (y >= layout.canvas.bottom) return -1; const int index = (y - layout.canvas.top) / kSampleRowHeight; if (index < 0 || index >= rowCount) return -1; // Guard the bottom edge: a click below the last row's bottom is outside. const Rect r = sampleRowRect(layout, index); if (y >= r.bottom) return -1; return index; } } // namespace reasampler::vst