refactor(market): extract pure portfolio grid-layout into pfComputeGridLayout
Pull the ~30-line row-major cell placement (honor stored placement else auto-place) out of RenderMarketTab into a pure, deterministic helper taking (entries, cols, minW, minH). Also bump the grid resize-readout buffer 16->32 to silence a worst-case -Wformat-truncation the extraction surfaced. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1143,6 +1143,44 @@ static void RenderPortfolioEditor(App* app)
|
||||
|
||||
bool PortfolioEditorActive() { return s_pfEdit.open; }
|
||||
|
||||
// Resolve each portfolio group's grid cell: honor a stored placement when it fits, else auto-place
|
||||
// row-major into the first free cells. Pure + deterministic (no ImGui). One PfCell per entry.
|
||||
static std::vector<PfCell> pfComputeGridLayout(
|
||||
const std::vector<config::Settings::PortfolioEntry>& entries, int cols, int minW, int minH)
|
||||
{
|
||||
int n = (int)entries.size();
|
||||
std::vector<PfCell> layout((size_t)std::max(0, n));
|
||||
std::vector<std::vector<char>> occ;
|
||||
auto ensure = [&](int rEnd) { while ((int)occ.size() < rEnd) occ.emplace_back(cols, 0); };
|
||||
auto fits = [&](int c, int r, int w, int h) -> bool {
|
||||
if (c < 0 || r < 0 || c + w > cols) return false;
|
||||
ensure(r + h);
|
||||
for (int rr = r; rr < r + h; rr++) for (int cc = c; cc < c + w; cc++) if (occ[rr][cc]) return false;
|
||||
return true;
|
||||
};
|
||||
auto mark = [&](int c, int r, int w, int h) { ensure(r + h);
|
||||
for (int rr = r; rr < r + h; rr++) for (int cc = c; cc < c + w; cc++) occ[rr][cc] = 1; };
|
||||
std::vector<char> placed((size_t)std::max(0, n), 0);
|
||||
for (int i = 0; i < n; i++) {
|
||||
const auto& e = entries[i];
|
||||
int w = std::max(minW, std::min(e.gridW, cols)), h = std::max(minH, e.gridH);
|
||||
if (e.gridCol >= 0 && e.gridRow >= 0 && fits(e.gridCol, e.gridRow, w, h)) {
|
||||
layout[i] = {e.gridCol, e.gridRow, w, h}; mark(e.gridCol, e.gridRow, w, h); placed[i] = 1;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (placed[i]) continue;
|
||||
const auto& e = entries[i];
|
||||
int w = std::max(minW, std::min(e.gridW, cols)), h = std::max(minH, e.gridH);
|
||||
int fc = 0, fr = 0; bool found = false;
|
||||
for (int r = 0; !found && r < 4096; r++)
|
||||
for (int c = 0; c + w <= cols; c++)
|
||||
if (fits(c, r, w, h)) { fc = c; fr = r; found = true; break; }
|
||||
layout[i] = {fc, fr, w, h}; mark(fc, fr, w, h);
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
void RenderMarketTab(App* app)
|
||||
{
|
||||
auto& S = schema::UI();
|
||||
@@ -1237,37 +1275,7 @@ void RenderMarketTab(App* app)
|
||||
float pfCellH = pfCellW;
|
||||
// Resolve each group's grid cell: honor a stored placement when it fits, else auto-place
|
||||
// row-major into the first free cells. Deterministic each frame.
|
||||
std::vector<PfCell> pfLayout((size_t)std::max(0, pfN));
|
||||
{
|
||||
std::vector<std::vector<char>> occ;
|
||||
auto ensure = [&](int rEnd) { while ((int)occ.size() < rEnd) occ.emplace_back(pfCols, 0); };
|
||||
auto fits = [&](int c, int r, int w, int h) -> bool {
|
||||
if (c < 0 || r < 0 || c + w > pfCols) return false;
|
||||
ensure(r + h);
|
||||
for (int rr = r; rr < r + h; rr++) for (int cc = c; cc < c + w; cc++) if (occ[rr][cc]) return false;
|
||||
return true;
|
||||
};
|
||||
auto mark = [&](int c, int r, int w, int h) { ensure(r + h);
|
||||
for (int rr = r; rr < r + h; rr++) for (int cc = c; cc < c + w; cc++) occ[rr][cc] = 1; };
|
||||
std::vector<char> placed((size_t)pfN, 0);
|
||||
for (int i = 0; i < pfN; i++) {
|
||||
const auto& e = pfEntriesGeo[i];
|
||||
int w = std::max(pfMinW, std::min(e.gridW, pfCols)), h = std::max(pfMinH, e.gridH);
|
||||
if (e.gridCol >= 0 && e.gridRow >= 0 && fits(e.gridCol, e.gridRow, w, h)) {
|
||||
pfLayout[i] = {e.gridCol, e.gridRow, w, h}; mark(e.gridCol, e.gridRow, w, h); placed[i] = 1;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < pfN; i++) {
|
||||
if (placed[i]) continue;
|
||||
const auto& e = pfEntriesGeo[i];
|
||||
int w = std::max(pfMinW, std::min(e.gridW, pfCols)), h = std::max(pfMinH, e.gridH);
|
||||
int fc = 0, fr = 0; bool found = false;
|
||||
for (int r = 0; !found && r < 4096; r++)
|
||||
for (int c = 0; c + w <= pfCols; c++)
|
||||
if (fits(c, r, w, h)) { fc = c; fr = r; found = true; break; }
|
||||
pfLayout[i] = {fc, fr, w, h}; mark(fc, fr, w, h);
|
||||
}
|
||||
}
|
||||
std::vector<PfCell> pfLayout = pfComputeGridLayout(pfEntriesGeo, pfCols, pfMinW, pfMinH);
|
||||
int pfMaxRow = 0; for (const auto& L : pfLayout) pfMaxRow = std::max(pfMaxRow, L.row + L.h);
|
||||
// Content height = the grid plus a couple of empty rows so cards can be dragged below the
|
||||
// current bottom (the tab scrolls when the total exceeds the window).
|
||||
@@ -2035,7 +2043,7 @@ void RenderMarketTab(App* app)
|
||||
// Live size readout (e.g. "8\xC3\x972") so the reached grid span is visible — the
|
||||
// minimum is pfMinW x pfMinH (8x2).
|
||||
{
|
||||
char szb[16]; snprintf(szb, sizeof(szb), "%d\xC3\x97%d", nw, nh);
|
||||
char szb[32]; snprintf(szb, sizeof(szb), "%d\xC3\x97%d", nw, nh);
|
||||
ImVec2 tsz = sub1->CalcTextSizeA(sub1->LegacySize, FLT_MAX, 0, szb);
|
||||
ImVec2 tp((mn.x + mx.x) * 0.5f - tsz.x * 0.5f, (mn.y + mx.y) * 0.5f - tsz.y * 0.5f);
|
||||
dl->AddRectFilled(ImVec2(tp.x - 6, tp.y - 3), ImVec2(tp.x + tsz.x + 6, tp.y + tsz.y + 3),
|
||||
|
||||
Reference in New Issue
Block a user