7151e19432
Reverse S4 auto-select (empty=silence+empty state), add peak-thumbnail capture browser + bank filter + keyboard-strip drag machine, v3 component state (selection + zones), and the S-NAME-1 filename/display rename (UID locked). MSVC min/max macro collisions fixed post-implementation; 26/26 tests green.
97 lines
3.7 KiB
C++
97 lines
3.7 KiB
C++
// capture_browser.cpp — see capture_browser.h. Pure math; no host types.
|
|
|
|
#include "capture_browser.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace reasampler::vst {
|
|
|
|
namespace {
|
|
|
|
// The left edge of tab i in a strip of the given x-origin and width divided into `count`
|
|
// equal segments (mirror of mode_switch::segmentEdge). Every boundary derives from the same
|
|
// formula, so consecutive tabs share an exact edge and the last tab reaches x+width exactly.
|
|
int tabEdge(int x, int width, int i, int count) {
|
|
return x + (i * width) / count;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
BrowserLayout layoutBrowser(int w, int h) {
|
|
const int cw = std::max(0, w);
|
|
const int ch = std::max(0, h);
|
|
|
|
BrowserLayout out;
|
|
const int tabH = std::min(kBrowserTabHeight, ch);
|
|
out.tabStrip = Rect{0, 0, cw, tabH};
|
|
out.grid = Rect{0, tabH, cw, ch};
|
|
|
|
const int gridW = std::max(0, out.grid.width());
|
|
out.columns = std::max(1, gridW / kBrowserCardWidth);
|
|
return out;
|
|
}
|
|
|
|
Rect cardCellRect(const BrowserLayout& layout, int index) {
|
|
if (index < 0) return Rect{};
|
|
const int cols = std::max(1, layout.columns);
|
|
const int col = index % cols;
|
|
const int row = index / cols;
|
|
const int left = layout.grid.left + col * kBrowserCardWidth;
|
|
const int top = layout.grid.top + row * kBrowserCardHeight;
|
|
return Rect{left, top, left + kBrowserCardWidth, top + kBrowserCardHeight};
|
|
}
|
|
|
|
Rect cardContentRect(const BrowserLayout& layout, int index) {
|
|
if (index < 0) return Rect{};
|
|
const Rect cell = cardCellRect(layout, index);
|
|
return Rect{cell.left + kBrowserCardGutter, cell.top + kBrowserCardGutter,
|
|
cell.right - kBrowserCardGutter, cell.bottom - kBrowserCardGutter};
|
|
}
|
|
|
|
Rect cardThumbnailRect(const BrowserLayout& layout, int index) {
|
|
if (index < 0) return Rect{};
|
|
const Rect content = cardContentRect(layout, index);
|
|
const int thumbH = std::min(kBrowserThumbHeight, std::max(0, content.height()));
|
|
return Rect{content.left, content.top, content.right, content.top + thumbH};
|
|
}
|
|
|
|
Rect cardLabelRect(const BrowserLayout& layout, int index) {
|
|
if (index < 0) return Rect{};
|
|
const Rect content = cardContentRect(layout, index);
|
|
const Rect thumb = cardThumbnailRect(layout, index);
|
|
return Rect{content.left, thumb.bottom, content.right, content.bottom};
|
|
}
|
|
|
|
int cardHitTest(const BrowserLayout& layout, int cardCount, int x, int y) {
|
|
if (cardCount <= 0) return -1;
|
|
if (!contains(layout.grid, x, y)) return -1;
|
|
const int cols = std::max(1, layout.columns);
|
|
const int col = (x - layout.grid.left) / kBrowserCardWidth;
|
|
const int row = (y - layout.grid.top) / kBrowserCardHeight;
|
|
if (col < 0 || col >= cols) return -1; // past the last column (right dead-zone)
|
|
const int index = row * cols + col;
|
|
if (index < 0 || index >= cardCount) return -1;
|
|
// Only a hit inside the card CONTENT counts — a click in the inter-card gutter misses.
|
|
if (!contains(cardContentRect(layout, index), x, y)) return -1;
|
|
return index;
|
|
}
|
|
|
|
Rect filterTabRect(const BrowserLayout& layout, int tabCount, int index) {
|
|
if (tabCount <= 0 || index < 0 || index >= tabCount) return Rect{};
|
|
const Rect& strip = layout.tabStrip;
|
|
const int left = tabEdge(strip.left, std::max(0, strip.width()), index, tabCount);
|
|
const int right = tabEdge(strip.left, std::max(0, strip.width()), index + 1, tabCount);
|
|
return Rect{left, strip.top, right, strip.bottom};
|
|
}
|
|
|
|
int filterTabHitTest(const BrowserLayout& layout, int tabCount, int x, int y) {
|
|
if (tabCount <= 0) return -1;
|
|
if (!contains(layout.tabStrip, x, y)) return -1;
|
|
for (int i = 0; i < tabCount; ++i) {
|
|
if (contains(filterTabRect(layout, tabCount, i), x, y)) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
} // namespace reasampler::vst
|