// bank_grid — pure implementation. See bank_grid.h. NO REAPER / SWELL / vendor. #include "bank_grid.h" namespace reasampler { int columnsForWidth(int panelWidth, const GridSpec& spec) { // Layout: [gap][cell][gap][cell]...[cell][gap]. n cells occupy // gap + n*(cellWidth + gap). Solve for the largest n that fits panelWidth, // clamped to at least 1 so a too-narrow panel still shows a (clipped) column. const int cell = spec.cellWidth + spec.gap; if (cell <= 0) return 1; // degenerate spec — one column, avoid divide-by-zero const int usable = panelWidth - spec.gap; if (usable < spec.cellWidth) return 1; const int cols = usable / cell; return cols < 1 ? 1 : cols; } std::vector computeCellRects(int itemCount, int panelWidth, const GridSpec& spec) { std::vector rects; if (itemCount <= 0) return rects; const int cols = columnsForWidth(panelWidth, spec); rects.reserve(static_cast(itemCount)); for (int i = 0; i < itemCount; ++i) { const int col = i % cols; const int row = i / cols; CellRect r; r.x = spec.gap + col * (spec.cellWidth + spec.gap); r.y = spec.gap + row * (spec.cellHeight + spec.gap); r.width = spec.cellWidth; r.height = spec.cellHeight; rects.push_back(r); } return rects; } int contentHeight(int itemCount, int panelWidth, const GridSpec& spec) { if (itemCount <= 0) return 0; const int cols = columnsForWidth(panelWidth, spec); // Ceil-divide item count by columns to get the row count (partial last row // still occupies a full row of height). const int rows = (itemCount + cols - 1) / cols; return spec.gap + rows * (spec.cellHeight + spec.gap); } std::string thumbnailKeyString(const ThumbnailKey& key) { // Length-prefix the sampleId so a delimiter byte inside an id cannot forge a // collision with a different (id, width, generation) triple. std::string s; s.reserve(key.sampleId.size() + 32); s += std::to_string(key.sampleId.size()); s += ':'; s += key.sampleId; s += '|'; s += std::to_string(key.width); s += '|'; s += std::to_string(key.generation); return s; } } // namespace reasampler