refactor(market): extract pair selector into mktDrawPairSelector
Move the exchange/pair chip grid (wrapping flat chips + click-to-switch + attribution line) out of RenderMarketTab into mktDrawPairSelector(app, registry, availWidth), recomputing its own schema/fonts/market. Drop the now-unused ovFont local. Verbatim body. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1297,6 +1297,102 @@ static void mktDrawCard(const MktCardCtx& cx, ImVec2 gcMin, ImVec2 gcMax,
|
||||
}
|
||||
}
|
||||
|
||||
// Pair selector: every trading pair across all exchanges as flat wrapping chips; clicking one
|
||||
// switches the active exchange/pair (persisted) and refreshes market data. Followed by attribution.
|
||||
static void mktDrawPairSelector(App* app, const std::vector<data::ExchangeInfo>& registry, float availWidth)
|
||||
{
|
||||
auto& S = schema::UI();
|
||||
const auto& market = app->getWalletState().market;
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
ImFont* capFont = Type().caption();
|
||||
ImFont* ovFont = Type().overline();
|
||||
float gap = Layout::cardGap();
|
||||
char buf[128];
|
||||
|
||||
ImGui::Dummy(ImVec2(0, S.drawElement("tabs.market", "exchange-top-gap").size));
|
||||
{
|
||||
float chipH = S.drawElement("tabs.market", "pair-chip-height").height;
|
||||
float chipR = S.drawElement("tabs.market", "pair-chip-radius").radius;
|
||||
float chipSpacing = S.drawElement("tabs.market", "pair-chip-spacing").size;
|
||||
float innerGap = Layout::spacingSm();
|
||||
float sidePad = Layout::spacingMd();
|
||||
|
||||
ImVec2 origin = ImGui::GetCursorScreenPos();
|
||||
float left = origin.x;
|
||||
float right = origin.x + availWidth;
|
||||
float cx = left;
|
||||
float cy = origin.y;
|
||||
int btnCounter = 0;
|
||||
|
||||
for (int ex = 0; ex < (int)registry.size(); ex++) {
|
||||
for (int pr = 0; pr < (int)registry[ex].pairs.size(); pr++) {
|
||||
const std::string& pairName = registry[ex].pairs[pr].displayName;
|
||||
const std::string& exName = registry[ex].name;
|
||||
|
||||
float pairW = capFont->CalcTextSizeA(capFont->LegacySize, FLT_MAX, 0, pairName.c_str()).x;
|
||||
float exW = ovFont->CalcTextSizeA(ovFont->LegacySize, FLT_MAX, 0, exName.c_str()).x;
|
||||
float cw = sidePad * 2.0f + pairW + innerGap + exW;
|
||||
|
||||
// Wrap to the next row when the pill would overflow (never on an empty row).
|
||||
if (cx + cw > right && cx > left) {
|
||||
cx = left;
|
||||
cy += chipH + chipSpacing;
|
||||
}
|
||||
|
||||
ImVec2 cMin(cx, cy);
|
||||
ImVec2 cMax(cx + cw, cy + chipH);
|
||||
bool selected = (ex == s_mkt.exchangeIdx && pr == s_mkt.pairIdx);
|
||||
bool hov = material::IsRectHovered(cMin, cMax);
|
||||
ImU32 chipBg = selected ? WithAlpha(Primary(), 200)
|
||||
: (hov ? WithAlpha(OnSurface(), 35) : WithAlpha(OnSurface(), 20));
|
||||
ImU32 chipBorder = selected ? Primary() : WithAlpha(OnSurface(), 40);
|
||||
ImU32 pairCol = selected ? IM_COL32(255, 255, 255, 255) : OnSurface();
|
||||
ImU32 exCol = selected ? WithAlpha(IM_COL32(255, 255, 255, 255), 190) : OnSurfaceDisabled();
|
||||
|
||||
dl->AddRectFilled(cMin, cMax, chipBg, chipR);
|
||||
dl->AddRect(cMin, cMax, chipBorder, chipR, 0, 1.0f);
|
||||
|
||||
float tx = cx + sidePad;
|
||||
dl->AddText(capFont, capFont->LegacySize,
|
||||
ImVec2(tx, cy + (chipH - capFont->LegacySize) * 0.5f), pairCol, pairName.c_str());
|
||||
dl->AddText(ovFont, ovFont->LegacySize,
|
||||
ImVec2(tx + pairW + innerGap, cy + (chipH - ovFont->LegacySize) * 0.5f),
|
||||
exCol, exName.c_str());
|
||||
|
||||
ImGui::SetCursorScreenPos(cMin);
|
||||
snprintf(buf, sizeof(buf), "##PairBtn%d", btnCounter++);
|
||||
if (ImGui::InvisibleButton(buf, ImVec2(cw, chipH))) {
|
||||
if (ex != s_mkt.exchangeIdx || pr != s_mkt.pairIdx) {
|
||||
s_mkt.exchangeIdx = ex;
|
||||
s_mkt.pairIdx = pr;
|
||||
app->settings()->setSelectedExchange(exName);
|
||||
app->settings()->setSelectedPair(pairName);
|
||||
app->settings()->save();
|
||||
app->refreshMarketData();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
|
||||
cx += cw + chipSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
// Advance the cursor past the wrapped rows.
|
||||
ImGui::SetCursorScreenPos(ImVec2(left, cy + chipH));
|
||||
ImGui::Dummy(ImVec2(availWidth, 0));
|
||||
|
||||
// Attribution (moved here from the removed exchange-selector row).
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("market_attribution"));
|
||||
if (!market.last_updated.empty()) {
|
||||
ImGui::SameLine(0, 12);
|
||||
snprintf(buf, sizeof(buf), " \xc2\xb7 Updated %s", market.last_updated.c_str());
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), buf);
|
||||
}
|
||||
ImGui::Dummy(ImVec2(0, gap));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderMarketTab(App* app)
|
||||
{
|
||||
auto& S = schema::UI();
|
||||
@@ -1346,7 +1442,6 @@ void RenderMarketTab(App* app)
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
GlassPanelSpec glassSpec;
|
||||
glassSpec.rounding = Layout::glassRounding();
|
||||
ImFont* ovFont = Type().overline();
|
||||
ImFont* capFont = Type().caption();
|
||||
ImFont* sub1 = Type().subtitle1();
|
||||
ImFont* body2 = Type().body2();
|
||||
@@ -1794,88 +1889,7 @@ void RenderMarketTab(App* app)
|
||||
// PAIR SELECTOR — every trading pair across all exchanges shown as
|
||||
// round buttons (flat; no exchange dropdown). Wraps to multiple rows.
|
||||
// ================================================================
|
||||
ImGui::Dummy(ImVec2(0, S.drawElement("tabs.market", "exchange-top-gap").size));
|
||||
{
|
||||
float chipH = S.drawElement("tabs.market", "pair-chip-height").height;
|
||||
float chipR = S.drawElement("tabs.market", "pair-chip-radius").radius;
|
||||
float chipSpacing = S.drawElement("tabs.market", "pair-chip-spacing").size;
|
||||
float innerGap = Layout::spacingSm();
|
||||
float sidePad = Layout::spacingMd();
|
||||
|
||||
ImVec2 origin = ImGui::GetCursorScreenPos();
|
||||
float left = origin.x;
|
||||
float right = origin.x + availWidth;
|
||||
float cx = left;
|
||||
float cy = origin.y;
|
||||
int btnCounter = 0;
|
||||
|
||||
for (int ex = 0; ex < (int)registry.size(); ex++) {
|
||||
for (int pr = 0; pr < (int)registry[ex].pairs.size(); pr++) {
|
||||
const std::string& pairName = registry[ex].pairs[pr].displayName;
|
||||
const std::string& exName = registry[ex].name;
|
||||
|
||||
float pairW = capFont->CalcTextSizeA(capFont->LegacySize, FLT_MAX, 0, pairName.c_str()).x;
|
||||
float exW = ovFont->CalcTextSizeA(ovFont->LegacySize, FLT_MAX, 0, exName.c_str()).x;
|
||||
float cw = sidePad * 2.0f + pairW + innerGap + exW;
|
||||
|
||||
// Wrap to the next row when the pill would overflow (never on an empty row).
|
||||
if (cx + cw > right && cx > left) {
|
||||
cx = left;
|
||||
cy += chipH + chipSpacing;
|
||||
}
|
||||
|
||||
ImVec2 cMin(cx, cy);
|
||||
ImVec2 cMax(cx + cw, cy + chipH);
|
||||
bool selected = (ex == s_mkt.exchangeIdx && pr == s_mkt.pairIdx);
|
||||
bool hov = material::IsRectHovered(cMin, cMax);
|
||||
ImU32 chipBg = selected ? WithAlpha(Primary(), 200)
|
||||
: (hov ? WithAlpha(OnSurface(), 35) : WithAlpha(OnSurface(), 20));
|
||||
ImU32 chipBorder = selected ? Primary() : WithAlpha(OnSurface(), 40);
|
||||
ImU32 pairCol = selected ? IM_COL32(255, 255, 255, 255) : OnSurface();
|
||||
ImU32 exCol = selected ? WithAlpha(IM_COL32(255, 255, 255, 255), 190) : OnSurfaceDisabled();
|
||||
|
||||
dl->AddRectFilled(cMin, cMax, chipBg, chipR);
|
||||
dl->AddRect(cMin, cMax, chipBorder, chipR, 0, 1.0f);
|
||||
|
||||
float tx = cx + sidePad;
|
||||
dl->AddText(capFont, capFont->LegacySize,
|
||||
ImVec2(tx, cy + (chipH - capFont->LegacySize) * 0.5f), pairCol, pairName.c_str());
|
||||
dl->AddText(ovFont, ovFont->LegacySize,
|
||||
ImVec2(tx + pairW + innerGap, cy + (chipH - ovFont->LegacySize) * 0.5f),
|
||||
exCol, exName.c_str());
|
||||
|
||||
ImGui::SetCursorScreenPos(cMin);
|
||||
snprintf(buf, sizeof(buf), "##PairBtn%d", btnCounter++);
|
||||
if (ImGui::InvisibleButton(buf, ImVec2(cw, chipH))) {
|
||||
if (ex != s_mkt.exchangeIdx || pr != s_mkt.pairIdx) {
|
||||
s_mkt.exchangeIdx = ex;
|
||||
s_mkt.pairIdx = pr;
|
||||
app->settings()->setSelectedExchange(exName);
|
||||
app->settings()->setSelectedPair(pairName);
|
||||
app->settings()->save();
|
||||
app->refreshMarketData();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
|
||||
cx += cw + chipSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
// Advance the cursor past the wrapped rows.
|
||||
ImGui::SetCursorScreenPos(ImVec2(left, cy + chipH));
|
||||
ImGui::Dummy(ImVec2(availWidth, 0));
|
||||
|
||||
// Attribution (moved here from the removed exchange-selector row).
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("market_attribution"));
|
||||
if (!market.last_updated.empty()) {
|
||||
ImGui::SameLine(0, 12);
|
||||
snprintf(buf, sizeof(buf), " \xc2\xb7 Updated %s", market.last_updated.c_str());
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), buf);
|
||||
}
|
||||
ImGui::Dummy(ImVec2(0, gap));
|
||||
}
|
||||
mktDrawPairSelector(app, registry, availWidth);
|
||||
|
||||
// ================================================================
|
||||
// PORTFOLIO — floating summary (no card background) + custom-group cards
|
||||
|
||||
Reference in New Issue
Block a user