feat(market): line/candle toggle + ~50% taller chart
- Add a chart-style toggle (line vs candlestick) next to the interval buttons, shown only when the selected range has per-exchange candles (the aggregate / Live view is line-only). It flips s_mkt.chartStyle; candles draw when OHLC exists AND the user hasn't switched to the line. Icon reflects the current style; tooltip says what a click switches to. Two i18n keys across 8 languages. - Make the price chart ~50% taller: scale the height floor / desired / viewport cap (110->165, x1.5 desired, 0.22->0.33 of available) for a roomier plot. Verified via a forced-OHLC render: the taller chart, the toggle button, and candles with a correct week/day x-axis. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "Preisdaten werden geladen...",
|
||||
"market_price_unavailable": "Preisdaten nicht verfügbar",
|
||||
"market_refresh_price": "Preisdaten aktualisieren",
|
||||
"market_style_candle": "Zu Kerzenchart wechseln",
|
||||
"market_style_line": "Zum Liniendiagramm wechseln",
|
||||
"market_trade_on": "Handeln auf %s",
|
||||
"market_updated": "\\xc2\\xb7 Aktualisiert %s",
|
||||
"market_vol_short": "Vol.",
|
||||
|
||||
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "Cargando datos de precio...",
|
||||
"market_price_unavailable": "Datos de precio no disponibles",
|
||||
"market_refresh_price": "Actualizar datos de precio",
|
||||
"market_style_candle": "Cambiar a velas",
|
||||
"market_style_line": "Cambiar a gráfico de líneas",
|
||||
"market_trade_on": "Operar en %s",
|
||||
"market_updated": "\\xc2\\xb7 Actualizado %s",
|
||||
"market_vol_short": "Vol",
|
||||
|
||||
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "Chargement des données de prix...",
|
||||
"market_price_unavailable": "Données de prix indisponibles",
|
||||
"market_refresh_price": "Actualiser les données de prix",
|
||||
"market_style_candle": "Passer aux chandeliers",
|
||||
"market_style_line": "Passer au graphique en ligne",
|
||||
"market_trade_on": "Échanger sur %s",
|
||||
"market_updated": "\\xc2\\xb7 Mis à jour %s",
|
||||
"market_vol_short": "Vol",
|
||||
|
||||
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "価格データを読み込み中...",
|
||||
"market_price_unavailable": "価格データが利用できません",
|
||||
"market_refresh_price": "価格データを更新",
|
||||
"market_style_candle": "ローソク足に切り替え",
|
||||
"market_style_line": "折れ線チャートに切り替え",
|
||||
"market_trade_on": "%s で取引",
|
||||
"market_updated": "\\xc2\\xb7 更新: %s",
|
||||
"market_vol_short": "出来高",
|
||||
|
||||
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "가격 데이터를 불러오는 중...",
|
||||
"market_price_unavailable": "가격 데이터를 사용할 수 없습니다",
|
||||
"market_refresh_price": "가격 데이터 새로고침",
|
||||
"market_style_candle": "캔들차트로 전환",
|
||||
"market_style_line": "선형 차트로 전환",
|
||||
"market_trade_on": "%s에서 거래",
|
||||
"market_updated": "\\xc2\\xb7 업데이트됨 %s",
|
||||
"market_vol_short": "거래량",
|
||||
|
||||
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "Carregando dados de preço...",
|
||||
"market_price_unavailable": "Dados de preço indisponíveis",
|
||||
"market_refresh_price": "Atualizar dados de preço",
|
||||
"market_style_candle": "Mudar para velas",
|
||||
"market_style_line": "Mudar para gráfico de linhas",
|
||||
"market_trade_on": "Negociar no %s",
|
||||
"market_updated": "\\xc2\\xb7 Atualizado %s",
|
||||
"market_vol_short": "Vol",
|
||||
|
||||
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "Загрузка данных о ценах...",
|
||||
"market_price_unavailable": "Данные о ценах недоступны",
|
||||
"market_refresh_price": "Обновить данные о ценах",
|
||||
"market_style_candle": "Переключить на свечи",
|
||||
"market_style_line": "Переключить на линейный график",
|
||||
"market_trade_on": "Торговать на %s",
|
||||
"market_updated": "\\xc2\\xb7 Обновлено %s",
|
||||
"market_vol_short": "Объём",
|
||||
|
||||
@@ -548,6 +548,8 @@
|
||||
"market_price_loading": "正在加载价格数据...",
|
||||
"market_price_unavailable": "价格数据不可用",
|
||||
"market_refresh_price": "刷新价格数据",
|
||||
"market_style_candle": "切换到蜡烛图",
|
||||
"market_style_line": "切换到折线图",
|
||||
"market_trade_on": "在 %s 交易",
|
||||
"market_updated": "\\xc2\\xb7 已更新 %s",
|
||||
"market_vol_short": "成交量",
|
||||
|
||||
@@ -2260,6 +2260,18 @@ TRANSLATIONS = {
|
||||
"ru": "Загрузка истории цен", "zh": "正在加载价格历史",
|
||||
"ja": "価格履歴を読み込み中", "ko": "가격 기록 불러오는 중"
|
||||
},
|
||||
"market_style_line": {
|
||||
"es": "Cambiar a gráfico de líneas", "de": "Zum Liniendiagramm wechseln",
|
||||
"fr": "Passer au graphique en ligne", "pt": "Mudar para gráfico de linhas",
|
||||
"ru": "Переключить на линейный график", "zh": "切换到折线图",
|
||||
"ja": "折れ線チャートに切り替え", "ko": "선형 차트로 전환"
|
||||
},
|
||||
"market_style_candle": {
|
||||
"es": "Cambiar a velas", "de": "Zu Kerzenchart wechseln",
|
||||
"fr": "Passer aux chandeliers", "pt": "Mudar para velas",
|
||||
"ru": "Переключить на свечи", "zh": "切换到蜡烛图",
|
||||
"ja": "ローソク足に切り替え", "ko": "캔들차트로 전환"
|
||||
},
|
||||
}
|
||||
|
||||
def main():
|
||||
|
||||
@@ -44,6 +44,7 @@ struct MarketViewState {
|
||||
int pairIdx = 0;
|
||||
bool stateLoaded = false;
|
||||
int chartInterval = 4; // main chart range: 0=Live 1=1H 2=1D 3=1W 4=1M (default 1M)
|
||||
int chartStyle = 1; // 0 = line, 1 = candlestick (only applies when per-exchange OHLC exists)
|
||||
};
|
||||
static MarketViewState s_mkt;
|
||||
|
||||
@@ -1412,6 +1413,29 @@ static void mktDrawPriceChart(const MktCtx& cx)
|
||||
bx += bw + Layout::spacingXs();
|
||||
}
|
||||
|
||||
// Line/candle toggle — only when the selected range has per-exchange candles (the aggregate /
|
||||
// Live view is line-only, so the toggle is hidden there).
|
||||
if (cx.chartCandles && cx.chartCandles->size() >= 2) {
|
||||
bx += Layout::spacingSm();
|
||||
ImFont* icoF = material::Typography::instance().iconSmall();
|
||||
const bool isCandle = (s_mkt.chartStyle == 1);
|
||||
const char* styleIcon = isCandle ? ICON_MD_CANDLESTICK_CHART : ICON_MD_SHOW_CHART;
|
||||
ImVec2 tmn(bx, rowTop), tmx(bx + pillH, rowTop + pillH);
|
||||
bool thov = material::IsRectHovered(tmn, tmx);
|
||||
if (thov) { dl->AddRectFilled(tmn, tmx, IM_COL32(255, 255, 255, 20), 4.0f);
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); }
|
||||
ImVec2 tiSz = icoF->CalcTextSizeA(icoF->LegacySize, FLT_MAX, 0, styleIcon);
|
||||
dl->AddText(icoF, icoF->LegacySize,
|
||||
ImVec2(tmn.x + (pillH - tiSz.x) * 0.5f, tmn.y + (pillH - tiSz.y) * 0.5f),
|
||||
thov ? OnSurface() : OnSurfaceMedium(), styleIcon);
|
||||
ImGui::SetCursorScreenPos(tmn);
|
||||
if (ImGui::InvisibleButton("##ChartStyle", ImVec2(pillH, pillH)))
|
||||
s_mkt.chartStyle = isCandle ? 0 : 1;
|
||||
if (ImGui::IsItemHovered())
|
||||
material::Tooltip("%s", TR(isCandle ? "market_style_line" : "market_style_candle"));
|
||||
bx += pillH;
|
||||
}
|
||||
|
||||
// Refresh button (far right).
|
||||
float rEdge = chartMax.x - chartPad;
|
||||
ImFont* iconSmall = material::Typography::instance().iconSmall();
|
||||
@@ -1465,7 +1489,8 @@ static void mktDrawPriceChart(const MktCtx& cx)
|
||||
float plotH = plotBottom - plotTop;
|
||||
|
||||
const auto& candles = *cx.chartCandles;
|
||||
const bool hasCandles = candles.size() >= 2; // per-exchange OHLC -> candlesticks, else a line
|
||||
// Candlesticks when per-exchange OHLC exists AND the user hasn't switched to the line view.
|
||||
const bool hasCandles = candles.size() >= 2 && s_mkt.chartStyle == 1;
|
||||
if (hasCandles || s_mkt.history.size() >= 2) {
|
||||
// Compute Y range with padding — candles span low..high, the line spans close..close.
|
||||
double yMin, yMax;
|
||||
@@ -1941,7 +1966,8 @@ void RenderMarketTab(App* app)
|
||||
float mktDp = Layout::dpiScale();
|
||||
|
||||
// -- Compact price chart: a modest responsive height, no longer stretched to fill the tab. --
|
||||
float chartH = std::max(110.0f * vs, std::min(chartElem.height * vs, marketAvail.y * 0.22f));
|
||||
// ~50% taller than before (floor / desired / viewport-cap all scaled) — a roomier price chart.
|
||||
float chartH = std::max(165.0f * vs, std::min(chartElem.height * 1.5f * vs, marketAvail.y * 0.33f));
|
||||
|
||||
// -- Hero header: size to the ACTUAL content (price row + separator gap + stats row) so the
|
||||
// chart starts right after "24H VOLUME"/"Market Cap" instead of below a reserved empty band. --
|
||||
|
||||
@@ -1348,6 +1348,8 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["market_btc_price"] = "BTC PRICE";
|
||||
strings_["market_no_history"] = "No price history available";
|
||||
strings_["market_chart_loading"] = "Loading price history";
|
||||
strings_["market_style_line"] = "Switch to line chart";
|
||||
strings_["market_style_candle"] = "Switch to candlesticks";
|
||||
strings_["market_no_price"] = "No price data";
|
||||
strings_["market_now"] = "Now";
|
||||
strings_["market_pct_shielded"] = "%.0f%% Shielded";
|
||||
|
||||
Reference in New Issue
Block a user