feat(market): combine portfolio address filter + selection onto one row

Merge the two address-section rows into one: the All/Shielded/Transparent
segmented type filter sits on the left and Select all / Clear / Funded are
right-aligned on the same line, both vertically centered. Select-all is deferred
to a flag applied after the filtered set is built, so it still targets the
current filter (and stays idempotent via PortfolioEntryAdd's dedup).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-03 23:37:10 -05:00
parent 4411cb45e2
commit 8c2b0521a6

View File

@@ -987,18 +987,34 @@ static void RenderPortfolioEditor(App* app)
ImGui::SetNextItemWidth(-1);
ImGui::InputTextWithHint("##pfSearch", TR("portfolio_search"), s_pf_search, sizeof(s_pf_search));
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
// Type filter segmented control on its own row (compact).
// Filter + selection on one row: type-filter segmented (left) + Select all / Clear /
// Funded (right). Select-all is deferred so it applies to the freshly-filtered set below.
bool selAllClicked = false;
{
const char* flabels[3] = { TR("portfolio_select_all"), TR("shielded"), TR("transparent") };
const char* selLbl = TR("portfolio_select_shown");
const char* clrLbl = TR("portfolio_clear_sel");
ImGuiStyle& st = ImGui::GetStyle();
ImVec2 pillPad(Layout::spacingLg(), Layout::spacingSm()); // roomier text padding
float defFrameH = ImGui::GetFrameHeight();
float fundedW = defFrameH + st.ItemInnerSpacing.x + ImGui::CalcTextSize(TR("portfolio_funded")).x;
float pillH = ImGui::GetTextLineHeight() + pillPad.y * 2.0f;
float selW = ImGui::CalcTextSize(selLbl).x + pillPad.x * 2.0f;
float clrW = ImGui::CalcTextSize(clrLbl).x + pillPad.x * 2.0f;
float groupW = selW + clrW + fundedW + st.ItemSpacing.x * 2.0f;
float segH = 26.0f * dp;
float availW = ImGui::GetContentRegionAvail().x;
float segW = std::min(availW, 360.0f * dp);
float rowW = ImGui::GetContentRegionAvail().x;
float segW = std::min(360.0f * dp, std::max(160.0f * dp, rowW - groupW - Layout::spacingMd()));
float rowH = std::max(segH, pillH);
ImVec2 rowStart = ImGui::GetCursorScreenPos();
// Segmented type filter (left), vertically centered in the row.
float segY = rowStart.y + (rowH - segH) * 0.5f;
float cellW = segW / 3.0f;
ImVec2 sMin = ImGui::GetCursorScreenPos();
ImDrawList* fdl = ImGui::GetWindowDrawList();
fdl->AddRectFilled(sMin, ImVec2(sMin.x + segW, sMin.y + segH), WithAlpha(OnSurface(), 20), segH * 0.5f);
fdl->AddRectFilled(ImVec2(rowStart.x, segY), ImVec2(rowStart.x + segW, segY + segH),
WithAlpha(OnSurface(), 20), segH * 0.5f);
for (int f = 0; f < 3; f++) {
ImVec2 cMin(sMin.x + f * cellW, sMin.y), cMax(cMin.x + cellW, sMin.y + segH);
ImVec2 cMin(rowStart.x + f * cellW, segY), cMax(cMin.x + cellW, segY + segH);
bool active = (s_pf_type_filter == f);
bool hov = ImGui::IsMouseHoveringRect(cMin, cMax);
if (active)
@@ -1016,8 +1032,21 @@ static void RenderPortfolioEditor(App* app)
if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
ImGui::PopID();
}
ImGui::SetCursorScreenPos(ImVec2(sMin.x, sMin.y + segH));
ImGui::Dummy(ImVec2(availW, 0));
// Select all / Clear (rounded pills) + Funded toggle (right), vertically centered.
float grpX = rowStart.x + std::max(0.0f, rowW - groupW);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.0f * dp);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, pillPad);
ImGui::SetCursorScreenPos(ImVec2(grpX, rowStart.y + (rowH - pillH) * 0.5f));
if (ImGui::Button(selLbl)) selAllClicked = true;
ImGui::SameLine();
if (ImGui::Button(clrLbl)) s_pf_addrs.clear();
ImGui::PopStyleVar(2);
ImGui::SameLine();
ImGui::SetCursorScreenPos(ImVec2(ImGui::GetCursorScreenPos().x,
rowStart.y + (rowH - defFrameH) * 0.5f)); // center vs. pills
ImGui::Checkbox(TR("portfolio_funded"), &s_pf_funded_only);
ImGui::SetCursorScreenPos(ImVec2(rowStart.x, rowStart.y + rowH));
ImGui::Dummy(ImVec2(rowW, 0));
}
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
std::string search = s_pf_search;
@@ -1038,36 +1067,8 @@ static void RenderPortfolioEditor(App* app)
if (sx != sy) return sx;
return x->balance > y->balance;
});
// Select all / Clear (rounded pills) + Funded toggle — one row, right-aligned.
{
const char* selLbl = TR("portfolio_select_shown");
const char* clrLbl = TR("portfolio_clear_sel");
ImGuiStyle& st = ImGui::GetStyle();
ImVec2 pillPad(Layout::spacingLg(), Layout::spacingSm()); // roomier text padding
// Measure the checkbox at default padding and the pills at their (larger) padding, so
// the whole group can be right-aligned before it's drawn.
float defFrameH = ImGui::GetFrameHeight();
float fundedW = defFrameH + st.ItemInnerSpacing.x + ImGui::CalcTextSize(TR("portfolio_funded")).x;
float pillH = ImGui::GetTextLineHeight() + pillPad.y * 2.0f;
float selW = ImGui::CalcTextSize(selLbl).x + pillPad.x * 2.0f;
float clrW = ImGui::CalcTextSize(clrLbl).x + pillPad.x * 2.0f;
float groupW = selW + clrW + fundedW + st.ItemSpacing.x * 2.0f;
float rowH = std::max(pillH, defFrameH);
float rowY = ImGui::GetCursorPosY();
float availW = ImGui::GetContentRegionAvail().x;
if (availW > groupW) ImGui::SetCursorPosX(ImGui::GetCursorPosX() + availW - groupW);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.0f * dp);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, pillPad);
ImGui::SetCursorPosY(rowY + (rowH - pillH) * 0.5f);
if (ImGui::Button(selLbl))
for (const AddressInfo* a : filtered) data::PortfolioEntryAdd(s_pf_addrs, a->address);
ImGui::SameLine();
if (ImGui::Button(clrLbl)) s_pf_addrs.clear();
ImGui::PopStyleVar(2);
ImGui::SameLine();
ImGui::SetCursorPosY(rowY + (rowH - defFrameH) * 0.5f); // center vs. pills
ImGui::Checkbox(TR("portfolio_funded"), &s_pf_funded_only);
}
if (selAllClicked)
for (const AddressInfo* a : filtered) data::PortfolioEntryAdd(s_pf_addrs, a->address);
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
ImDrawList* ldl = pfBeginScrollChild("##pfAddrList", s_pf_addr_fade,
ImVec2(Layout::spacingMd(), Layout::spacingSm()), dp);