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)
|
void RenderMarketTab(App* app)
|
||||||
{
|
{
|
||||||
auto& S = schema::UI();
|
auto& S = schema::UI();
|
||||||
@@ -1346,7 +1442,6 @@ void RenderMarketTab(App* app)
|
|||||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||||
GlassPanelSpec glassSpec;
|
GlassPanelSpec glassSpec;
|
||||||
glassSpec.rounding = Layout::glassRounding();
|
glassSpec.rounding = Layout::glassRounding();
|
||||||
ImFont* ovFont = Type().overline();
|
|
||||||
ImFont* capFont = Type().caption();
|
ImFont* capFont = Type().caption();
|
||||||
ImFont* sub1 = Type().subtitle1();
|
ImFont* sub1 = Type().subtitle1();
|
||||||
ImFont* body2 = Type().body2();
|
ImFont* body2 = Type().body2();
|
||||||
@@ -1794,88 +1889,7 @@ void RenderMarketTab(App* app)
|
|||||||
// PAIR SELECTOR — every trading pair across all exchanges shown as
|
// PAIR SELECTOR — every trading pair across all exchanges shown as
|
||||||
// round buttons (flat; no exchange dropdown). Wraps to multiple rows.
|
// round buttons (flat; no exchange dropdown). Wraps to multiple rows.
|
||||||
// ================================================================
|
// ================================================================
|
||||||
ImGui::Dummy(ImVec2(0, S.drawElement("tabs.market", "exchange-top-gap").size));
|
mktDrawPairSelector(app, registry, availWidth);
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
// PORTFOLIO — floating summary (no card background) + custom-group cards
|
// PORTFOLIO — floating summary (no card background) + custom-group cards
|
||||||
|
|||||||
Reference in New Issue
Block a user