Files
reasampler/src/core/instrument/ui/capture_browser.cpp
T

97 lines
3.7 KiB
C++

// capture_browser.cpp — see capture_browser.h. Pure math; no host types.
#include "core/instrument/ui/capture_browser.h"
#include <algorithm>
namespace reasampler::instrument::ui {
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::ltrb(0, 0, cw, tabH);
out.grid = Rect::ltrb(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.x + col * kBrowserCardWidth;
const int top = layout.grid.y + row * kBrowserCardHeight;
return Rect::ltrb(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::ltrb(cell.x + kBrowserCardGutter, cell.y + 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::ltrb(content.x, content.y, content.right(), content.y + 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::ltrb(content.x, 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.x) / kBrowserCardWidth;
const int row = (y - layout.grid.y) / 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.x, std::max(0, strip.width), index, tabCount);
const int right = tabEdge(strip.x, std::max(0, strip.width), index + 1, tabCount);
return Rect::ltrb(left, strip.y, 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::instrument::ui