// capture_browser.cpp — see capture_browser.h. Pure math; no host types. #include "core/instrument/ui/capture_browser.h" #include 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