Add D5 Design-View mode switch to bank panel

New pure mode_switch module (header-rect -> N equal segment rects + point hit-test, unit-tested) plus a segmented switch in the bank_panel header: one lit segment per registered mode, click activates via view::applyMode. Grid offset below the header.
This commit is contained in:
2026-07-23 12:35:46 -04:00
parent 9ff123e5e1
commit 314c3331da
5 changed files with 438 additions and 7 deletions
+64
View File
@@ -0,0 +1,64 @@
// mode_switch — pure implementation. See mode_switch.h. NO REAPER / SWELL / vendor.
#include "mode_switch.h"
#include <cstddef>
namespace reasampler {
namespace {
// The left edge of segment i in a header of the given x-origin and width divided
// into `count` segments. Boundary i is x + (i * width) / count, so segment i spans
// [edge(i), edge(i+1)). Because every boundary is derived from the same formula,
// consecutive segments share an exact edge (no gap, no overlap) and edge(count)
// == x + width precisely. count assumed >= 1 by callers.
int segmentEdge(int x, int width, int i, int count) {
return x + (i * width) / count;
}
} // namespace
std::vector<SegmentRect> computeSegmentRects(const HeaderRect& header,
int segmentCount) {
std::vector<SegmentRect> rects;
if (segmentCount <= 0 || header.width <= 0) return rects;
rects.reserve(static_cast<std::size_t>(segmentCount));
for (int i = 0; i < segmentCount; ++i) {
const int left = segmentEdge(header.x, header.width, i, segmentCount);
const int right = segmentEdge(header.x, header.width, i + 1, segmentCount);
SegmentRect r;
r.x = left;
r.y = header.y;
r.width = right - left; // absorbs rounding; adjacent segments abut exactly
r.height = header.height;
rects.push_back(r);
}
return rects;
}
int hitTestSegment(int px, int py, const HeaderRect& header, int segmentCount) {
if (segmentCount <= 0 || header.width <= 0 || header.height <= 0) return -1;
// Reject anything outside the header band first (half-open bounds match the
// segment rects). Below the header is where the grid lives — the panel falls
// through to grid handling on a -1.
if (px < header.x || px >= header.x + header.width ||
py < header.y || py >= header.y + header.height)
return -1;
// Inside the band: find the segment whose [edge(i), edge(i+1)) contains px.
// Linear over N (N is tiny — one per mode); mirrors the boundary formula so the
// hit matches the drawn segment exactly.
for (int i = 0; i < segmentCount; ++i) {
const int left = segmentEdge(header.x, header.width, i, segmentCount);
const int right = segmentEdge(header.x, header.width, i + 1, segmentCount);
if (px >= left && px < right) return i;
}
// Guard: px == header.x + header.width would fail the < above but was already
// excluded by the band check. Any residual falls to -1 (defensive, unreachable).
return -1;
}
} // namespace reasampler