feat(market): fix portfolio Add button clipping; add accordion summaries
- Add button can no longer be cut off: it's now a normal widget below the group
list (in a group with the scroll child) instead of nested inside the list child.
- Stop the modal's 28x20 WindowPadding from cascading into the nested master/detail/
list children (pop it right after the card child begins) — that double-padding
was squeezing the master column and the Add button.
- Right pane navigability: collapsed accordion sections now show a compact summary
on the right (Appearance -> icon, Price -> basis, Addresses -> N selected), so a
group's state is readable without expanding. Section titles are consistent
title-case ("Appearance"/"Price"/"Addresses").
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -427,6 +427,7 @@ static void RenderPortfolioEditor(App* app)
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(28.0f, 20.0f));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(28.0f, 20.0f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
|
||||||
ImGui::BeginChild("##pfCard", ImVec2(cardW, cardH), ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar);
|
ImGui::BeginChild("##pfCard", ImVec2(cardW, cardH), ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar);
|
||||||
|
ImGui::PopStyleVar(); // pop WindowPadding — the 28x20 applies to ##pfCard only, not nested children
|
||||||
|
|
||||||
material::DrawDialogTitleBar(TR("portfolio_manage_title"), &s_portfolio_editor_open);
|
material::DrawDialogTitleBar(TR("portfolio_manage_title"), &s_portfolio_editor_open);
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) s_portfolio_editor_open = false;
|
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) s_portfolio_editor_open = false;
|
||||||
@@ -443,13 +444,12 @@ static void RenderPortfolioEditor(App* app)
|
|||||||
float masterW = std::min(std::max(contentW * 0.28f, 240.0f * dp), 320.0f * dp);
|
float masterW = std::min(std::max(contentW * 0.28f, 240.0f * dp), 320.0f * dp);
|
||||||
float detailW = contentW - masterW - gap;
|
float detailW = contentW - masterW - gap;
|
||||||
|
|
||||||
// ================= MASTER: group list =================
|
// ================= MASTER: scrollable group list + a pinned Add button below it =================
|
||||||
ImGui::BeginChild("##pfMaster", ImVec2(masterW, bodyH), false, ImGuiWindowFlags_NoScrollbar);
|
float addH = 34.0f * dp;
|
||||||
|
ImGui::BeginGroup();
|
||||||
{
|
{
|
||||||
const auto& entries = settings->getPortfolioEntries();
|
const auto& entries = settings->getPortfolioEntries();
|
||||||
float addH = 30.0f * dp;
|
ImGui::BeginChild("##pfMasterList", ImVec2(masterW, std::max(48.0f, bodyH - addH - Layout::spacingSm())), false);
|
||||||
ImGui::BeginChild("##pfMasterList",
|
|
||||||
ImVec2(0, std::max(48.0f, ImGui::GetContentRegionAvail().y - addH - Layout::spacingXs())), false);
|
|
||||||
{
|
{
|
||||||
ImDrawList* mdl = ImGui::GetWindowDrawList();
|
ImDrawList* mdl = ImGui::GetWindowDrawList();
|
||||||
if (entries.empty())
|
if (entries.empty())
|
||||||
@@ -489,10 +489,11 @@ static void RenderPortfolioEditor(App* app)
|
|||||||
if (clickedSel != -999) { commitIfNeeded(); PortfolioBeginEdit(app, clickedSel); }
|
if (clickedSel != -999) { commitIfNeeded(); PortfolioBeginEdit(app, clickedSel); }
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
|
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||||
if (ImGui::Button(TR("portfolio_add_entry"), ImVec2(-1, addH))) { commitIfNeeded(); PortfolioBeginEdit(app, -2); }
|
// Add button lives outside the scroll child (a normal widget) so it can never be clipped.
|
||||||
|
if (ImGui::Button(TR("portfolio_add_entry"), ImVec2(masterW, addH))) { commitIfNeeded(); PortfolioBeginEdit(app, -2); }
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndGroup();
|
||||||
|
|
||||||
ImGui::SameLine(0, gap);
|
ImGui::SameLine(0, gap);
|
||||||
|
|
||||||
@@ -574,16 +575,30 @@ static void RenderPortfolioEditor(App* app)
|
|||||||
ImGui::InputTextWithHint("##pfLabel", TR("portfolio_group_name"), s_pf_label, sizeof(s_pf_label));
|
ImGui::InputTextWithHint("##pfLabel", TR("portfolio_group_name"), s_pf_label, sizeof(s_pf_label));
|
||||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||||
|
|
||||||
// Accordion: exactly one section expanded at a time.
|
// Accordion: exactly one section expanded at a time. Collapsed sections show a compact
|
||||||
auto section = [&](const char* label, bool& openFlag) -> bool {
|
// summary on the right so a group's state is readable at a glance without expanding.
|
||||||
|
auto section = [&](const char* label, bool& openFlag, const std::string& summary) -> bool {
|
||||||
ImGui::SetNextItemOpen(openFlag, ImGuiCond_Always);
|
ImGui::SetNextItemOpen(openFlag, ImGuiCond_Always);
|
||||||
bool now = ImGui::CollapsingHeader(label);
|
bool now = ImGui::CollapsingHeader(label);
|
||||||
|
if (!now && !summary.empty()) {
|
||||||
|
ImVec2 hmn = ImGui::GetItemRectMin(), hmx = ImGui::GetItemRectMax();
|
||||||
|
float sw2 = capF->CalcTextSizeA(capF->LegacySize, FLT_MAX, 0, summary.c_str()).x;
|
||||||
|
ImGui::GetWindowDrawList()->AddText(capF, capF->LegacySize,
|
||||||
|
ImVec2(hmx.x - sw2 - Layout::spacingMd(), (hmn.y + hmx.y) * 0.5f - capF->LegacySize * 0.5f),
|
||||||
|
OnSurfaceMedium(), summary.c_str());
|
||||||
|
}
|
||||||
if (now != openFlag) { s_pf_sec_appearance = s_pf_sec_price = s_pf_sec_addresses = false; openFlag = now; }
|
if (now != openFlag) { s_pf_sec_appearance = s_pf_sec_price = s_pf_sec_addresses = false; openFlag = now; }
|
||||||
return openFlag;
|
return openFlag;
|
||||||
};
|
};
|
||||||
|
// Collapsed-section summaries.
|
||||||
|
const char* basisNames[4] = { TR("portfolio_price_usd"), TR("portfolio_price_btc"),
|
||||||
|
TR("portfolio_price_drgx"), TR("portfolio_price_manual") };
|
||||||
|
std::string apSummary = s_pf_icon.empty() ? std::string(TR("portfolio_no_icon")) : s_pf_icon;
|
||||||
|
std::string prSummary = basisNames[std::max(0, std::min(3, s_pf_price_basis))];
|
||||||
|
char adSummary[48]; snprintf(adSummary, sizeof(adSummary), TR("portfolio_addresses_sel"), (int)s_pf_addrs.size());
|
||||||
|
|
||||||
// ---- APPEARANCE (color + outline opacity + icon) ----
|
// ---- APPEARANCE (color + outline opacity + icon) ----
|
||||||
if (section(TR("portfolio_appearance"), s_pf_sec_appearance)) {
|
if (section(TR("portfolio_appearance"), s_pf_sec_appearance, apSummary)) {
|
||||||
ImGui::Indent(Layout::spacingSm());
|
ImGui::Indent(Layout::spacingSm());
|
||||||
// Color picker: preset swatches + a custom-color circle that opens a picker popup.
|
// Color picker: preset swatches + a custom-color circle that opens a picker popup.
|
||||||
{
|
{
|
||||||
@@ -698,7 +713,7 @@ static void RenderPortfolioEditor(App* app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- PRICE (basis, manual price, shown fields, sparkline) ----
|
// ---- PRICE (basis, manual price, shown fields, sparkline) ----
|
||||||
if (section(TR("portfolio_price"), s_pf_sec_price)) {
|
if (section(TR("portfolio_price"), s_pf_sec_price, prSummary)) {
|
||||||
ImGui::Indent(Layout::spacingSm());
|
ImGui::Indent(Layout::spacingSm());
|
||||||
const char* basisItems[4] = { TR("portfolio_price_usd"), TR("portfolio_price_btc"),
|
const char* basisItems[4] = { TR("portfolio_price_usd"), TR("portfolio_price_btc"),
|
||||||
TR("portfolio_price_drgx"), TR("portfolio_price_manual") };
|
TR("portfolio_price_drgx"), TR("portfolio_price_manual") };
|
||||||
@@ -737,7 +752,7 @@ static void RenderPortfolioEditor(App* app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- ADDRESSES (search, filter, select) ----
|
// ---- ADDRESSES (search, filter, select) ----
|
||||||
if (section(TR("portfolio_addresses_hdr"), s_pf_sec_addresses)) {
|
if (section(TR("portfolio_addresses_hdr"), s_pf_sec_addresses, adSummary)) {
|
||||||
ImGui::Indent(Layout::spacingSm());
|
ImGui::Indent(Layout::spacingSm());
|
||||||
{
|
{
|
||||||
char selc[48];
|
char selc[48];
|
||||||
@@ -884,7 +899,7 @@ static void RenderPortfolioEditor(App* app)
|
|||||||
|
|
||||||
ImGui::EndChild(); // ##pfCard
|
ImGui::EndChild(); // ##pfCard
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::PopStyleVar(2);
|
ImGui::PopStyleVar(); // ChildRounding (WindowPadding was popped right after BeginChild)
|
||||||
|
|
||||||
// Outside-click dismiss (guarded against the appearing frame and open popups).
|
// Outside-click dismiss (guarded against the appearing frame and open popups).
|
||||||
if (!popupOpen && !ImGui::IsWindowAppearing() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)
|
if (!popupOpen && !ImGui::IsWindowAppearing() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)
|
||||||
|
|||||||
@@ -1144,8 +1144,8 @@ void I18n::loadBuiltinEnglish()
|
|||||||
strings_["portfolio_spark_day"] = "Day";
|
strings_["portfolio_spark_day"] = "Day";
|
||||||
strings_["portfolio_spark_week"] = "Week";
|
strings_["portfolio_spark_week"] = "Week";
|
||||||
strings_["portfolio_spark_month"] = "Month";
|
strings_["portfolio_spark_month"] = "Month";
|
||||||
strings_["portfolio_appearance"] = "APPEARANCE";
|
strings_["portfolio_appearance"] = "Appearance";
|
||||||
strings_["portfolio_addresses_hdr"] = "ADDRESSES";
|
strings_["portfolio_addresses_hdr"] = "Addresses";
|
||||||
strings_["portfolio_search"] = "Search addresses\xE2\x80\xA6";
|
strings_["portfolio_search"] = "Search addresses\xE2\x80\xA6";
|
||||||
strings_["portfolio_funded"] = "Funded";
|
strings_["portfolio_funded"] = "Funded";
|
||||||
strings_["portfolio_select_all"] = "All";
|
strings_["portfolio_select_all"] = "All";
|
||||||
|
|||||||
Reference in New Issue
Block a user