feat(console): terminal polish — lite/color-coded toggles, dark bg, monospace font
Work through the console items in todo.md: - Lite filter toggles (#5): replace the single hasLogFilters() bool with a ConsoleLogFilterCaps struct so each backend advertises which toggles apply. Full node = daemon/errors/rpc-trace/app; lite = errors-only + app (its diagnostics ring maps to the App/Error channels; the text filter is always shown). Lite previously showed no toggles at all. - Color-coded toggles (#6): each filter checkbox is tinted with its channel's accent color (daemon=blue, errors=red, rpc=secondary, app=teal) via a new channelAccentColor() that also drives the output's left accent bar — one source of truth for channel color. - Darker terminal look (#7): drop the light glass rectangle on the input; both output and input now get a terminal-dark overlay (tabs.console.bg-darken-alpha, default 110) and the input field blends into it (transparent frame bg). - Monospace font (#8): bundle Ubuntu Mono (res/fonts/UbuntuMono-R.ttf, Ubuntu Font License — same family as the existing Ubuntu fonts) via INCBIN, load it at caption size as Type().mono(), and render console output + input in it so pretty-printed JSON columns and terminal text align. Falls back to the proportional caption font if unavailable. Full-node + lite build clean; ctest green; source hygiene clean; sandboxed startup smoke confirms the mono font loads + atlas builds without crashing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -689,6 +689,7 @@ set_source_files_properties(
|
||||
"${CMAKE_SOURCE_DIR}/res/fonts/Ubuntu-R.ttf;\
|
||||
${CMAKE_SOURCE_DIR}/res/fonts/Ubuntu-Light.ttf;\
|
||||
${CMAKE_SOURCE_DIR}/res/fonts/Ubuntu-Medium.ttf;\
|
||||
${CMAKE_SOURCE_DIR}/res/fonts/UbuntuMono-R.ttf;\
|
||||
${CMAKE_SOURCE_DIR}/res/fonts/MaterialIcons-Regular.ttf;\
|
||||
${CMAKE_SOURCE_DIR}/res/fonts/MaterialDesignIcons-Pickaxe-Subset.ttf;\
|
||||
${CMAKE_SOURCE_DIR}/res/fonts/NotoSansCJK-Subset.ttf"
|
||||
|
||||
BIN
res/fonts/UbuntuMono-R.ttf
Normal file
BIN
res/fonts/UbuntuMono-R.ttf
Normal file
Binary file not shown.
@@ -908,6 +908,7 @@ scroll-fade-zone = { size = 24.0 }
|
||||
|
||||
[tabs.console]
|
||||
input-area-padding = 8.0
|
||||
bg-darken-alpha = { size = 110.0 } # black overlay alpha (0-255) for the terminal-dark output + input
|
||||
output-line-spacing = 2.0
|
||||
output = { line-spacing = 2 }
|
||||
scroll-multiplier = { size = 3.0 }
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
INCBIN(ubuntu_regular, "@CMAKE_SOURCE_DIR@/res/fonts/Ubuntu-R.ttf");
|
||||
INCBIN(ubuntu_light, "@CMAKE_SOURCE_DIR@/res/fonts/Ubuntu-Light.ttf");
|
||||
INCBIN(ubuntu_medium, "@CMAKE_SOURCE_DIR@/res/fonts/Ubuntu-Medium.ttf");
|
||||
INCBIN(ubuntu_mono, "@CMAKE_SOURCE_DIR@/res/fonts/UbuntuMono-R.ttf");
|
||||
INCBIN(material_icons, "@CMAKE_SOURCE_DIR@/res/fonts/MaterialIcons-Regular.ttf");
|
||||
INCBIN(mdi_pickaxe_subset, "@CMAKE_SOURCE_DIR@/res/fonts/MaterialDesignIcons-Pickaxe-Subset.ttf");
|
||||
INCBIN(noto_cjk_subset, "@CMAKE_SOURCE_DIR@/res/fonts/NotoSansCJK-Subset.ttf");
|
||||
|
||||
@@ -24,6 +24,9 @@ extern "C" {
|
||||
extern const unsigned char g_ubuntu_medium_data[];
|
||||
extern const unsigned int g_ubuntu_medium_size;
|
||||
|
||||
extern const unsigned char g_ubuntu_mono_data[];
|
||||
extern const unsigned int g_ubuntu_mono_size;
|
||||
|
||||
extern const unsigned char g_material_icons_data[];
|
||||
extern const unsigned int g_material_icons_size;
|
||||
|
||||
|
||||
@@ -183,7 +183,11 @@ bool Typography::load(ImGuiIO& io, float dpiScale)
|
||||
|
||||
// ButtonLg: Medium
|
||||
fonts_[14] = loadFont(io, kWeightMedium, Layout::kFontButtonLg() * scale, "ButtonLg");
|
||||
|
||||
|
||||
// Monospace (Ubuntu Mono) at caption size — used by the console so terminal text +
|
||||
// pretty-printed JSON columns align. Same size as Caption to keep line heights matched.
|
||||
mono_ = loadFont(io, kWeightMono, Layout::kFontCaption() * scale, "Mono");
|
||||
|
||||
// --- Icon fonts at multiple sizes ---
|
||||
// These are standalone fonts (not merged) so we can PushFont(iconXxx) for icon rendering.
|
||||
iconFonts_[0] = loadIconFont(io, 14.0f * scale, "IconSmall");
|
||||
@@ -236,6 +240,10 @@ ImFont* Typography::loadFont(ImGuiIO& io, int weight, float size, const char* na
|
||||
fontData = g_ubuntu_medium_data;
|
||||
fontDataLen = g_ubuntu_medium_size;
|
||||
break;
|
||||
case kWeightMono:
|
||||
fontData = g_ubuntu_mono_data;
|
||||
fontDataLen = g_ubuntu_mono_size;
|
||||
break;
|
||||
case kWeightRegular:
|
||||
default:
|
||||
fontData = g_ubuntu_regular_data;
|
||||
@@ -271,10 +279,10 @@ ImFont* Typography::loadFont(ImGuiIO& io, int weight, float size, const char* na
|
||||
cfg.GlyphRanges = glyphRanges;
|
||||
|
||||
// Create a unique name for this font variant
|
||||
snprintf(cfg.Name, sizeof(cfg.Name), "Ubuntu %s %.0fpx",
|
||||
weight == kWeightLight ? "Light" :
|
||||
weight == kWeightMedium ? "Medium" : "Regular",
|
||||
size);
|
||||
const char* weightName = weight == kWeightLight ? "Light" :
|
||||
weight == kWeightMedium ? "Medium" :
|
||||
weight == kWeightMono ? "Mono" : "Regular";
|
||||
snprintf(cfg.Name, sizeof(cfg.Name), "Ubuntu %s %.0fpx", weightName, size);
|
||||
|
||||
ImFont* font = io.Fonts->AddFontFromMemoryTTF(fontDataCopy, fontDataLen, size, &cfg);
|
||||
|
||||
|
||||
@@ -168,6 +168,10 @@ public:
|
||||
ImFont* caption() const { return getFont(TypeStyle::Caption); }
|
||||
ImFont* overline() const { return getFont(TypeStyle::Overline); }
|
||||
|
||||
// Monospace (Ubuntu Mono) at caption size — for the console, so JSON/columns align
|
||||
// like a real terminal. Falls back to the proportional caption font if not loaded.
|
||||
ImFont* mono() const { return mono_ ? mono_ : caption(); }
|
||||
|
||||
// Icon fonts — Material Design Icons merged at specific pixel sizes
|
||||
// Use these when you need to render an icon at a specific size via AddText/ImGui::Text.
|
||||
// Common sizes: iconSmall (14px), iconMed (18px), iconLarge (24px).
|
||||
@@ -253,12 +257,16 @@ private:
|
||||
static constexpr int kWeightLight = 300;
|
||||
static constexpr int kWeightRegular = 400;
|
||||
static constexpr int kWeightMedium = 500;
|
||||
static constexpr int kWeightMono = 401; // selects Ubuntu Mono (monospace, regular)
|
||||
|
||||
bool loaded_ = false;
|
||||
float dpiScale_ = 1.0f;
|
||||
|
||||
// Fonts for each type style
|
||||
ImFont* fonts_[15] = {};
|
||||
|
||||
// Monospace font (Ubuntu Mono) at caption size — console/terminal text.
|
||||
ImFont* mono_ = nullptr;
|
||||
|
||||
// Icon fonts at different sizes: [0]=small(14), [1]=med(18), [2]=large(24), [3]=xl(40)
|
||||
ImFont* iconFonts_[4] = {};
|
||||
|
||||
@@ -32,6 +32,17 @@ struct ConsoleStatusLine {
|
||||
bool pulse = false; // animate the toolbar dot (starting/connecting)
|
||||
};
|
||||
|
||||
// Which log-filter toggles the toolbar should show for a given backend. The full node has a
|
||||
// daemon/xmrig log + an RPC trace; the lite backend has neither (its diagnostics ring maps to
|
||||
// the App/Error channels), so it only wants the errors-only + app-messages toggles.
|
||||
struct ConsoleLogFilterCaps {
|
||||
bool daemon = false; // daemon + xmrig output toggle
|
||||
bool errorsOnly = false; // errors-only toggle
|
||||
bool rpcTrace = false; // RPC method/source trace toggle
|
||||
bool appMessages = false; // app / diagnostics log toggle
|
||||
bool any() const { return daemon || errorsOnly || rpcTrace || appMessages; }
|
||||
};
|
||||
|
||||
class ConsoleCommandExecutor {
|
||||
public:
|
||||
virtual ~ConsoleCommandExecutor() = default;
|
||||
@@ -53,7 +64,8 @@ public:
|
||||
|
||||
// UI-chrome capabilities.
|
||||
virtual bool hasRpcReference() const { return false; } // show the RPC command-reference popup
|
||||
virtual bool hasLogFilters() const { return false; } // show daemon/errors/rpc-trace/app filters
|
||||
// Which log-filter toggles the toolbar should show (default: none).
|
||||
virtual ConsoleLogFilterCaps logFilterCaps() const { return {}; }
|
||||
|
||||
// Print the backend-appropriate `help` output via `add`.
|
||||
virtual void printHelp(const ConsoleAddLineFn& add) = 0;
|
||||
@@ -75,7 +87,8 @@ public:
|
||||
bool pollResult(std::string& result, bool& isError) override;
|
||||
void pollLogLines(const ConsoleAddLineFn& add) override;
|
||||
bool hasRpcReference() const override { return true; }
|
||||
bool hasLogFilters() const override { return true; }
|
||||
// Full node: daemon/xmrig log, errors-only, RPC trace, and app messages.
|
||||
ConsoleLogFilterCaps logFilterCaps() const override { return {true, true, true, true}; }
|
||||
void printHelp(const ConsoleAddLineFn& add) override;
|
||||
ConsoleStatusLine toolbarStatus() const override;
|
||||
|
||||
@@ -99,6 +112,9 @@ public:
|
||||
void submit(const std::string& cmd) override;
|
||||
bool pollResult(std::string& result, bool& isError) override;
|
||||
void pollLogLines(const ConsoleAddLineFn& add) override;
|
||||
// Lite: no daemon log / RPC trace — its diagnostics ring maps to the App + Error
|
||||
// channels, so offer errors-only + app-messages (plus the always-shown text filter).
|
||||
ConsoleLogFilterCaps logFilterCaps() const override { return {false, true, false, true}; }
|
||||
void printHelp(const ConsoleAddLineFn& add) override;
|
||||
std::vector<ConsoleStatusLine> statusLines() const override;
|
||||
ConsoleStatusLine toolbarStatus() const override;
|
||||
|
||||
@@ -151,6 +151,23 @@ ImU32 ConsoleTab::channelTextColor(ConsoleChannel channel) const
|
||||
}
|
||||
}
|
||||
|
||||
ImU32 ConsoleTab::channelAccentColor(ConsoleChannel channel)
|
||||
{
|
||||
using namespace material;
|
||||
switch (channel) {
|
||||
case ConsoleChannel::Command: return Primary();
|
||||
case ConsoleChannel::Error: return Error();
|
||||
case ConsoleChannel::Warning: return Warning();
|
||||
case ConsoleChannel::Success: return Success();
|
||||
case ConsoleChannel::Rpc: return Secondary();
|
||||
case ConsoleChannel::Daemon: return IM_COL32(90, 130, 190, 210); // node log — blue
|
||||
case ConsoleChannel::Xmrig: return Warning(); // mining — amber
|
||||
case ConsoleChannel::App: return IM_COL32(120, 190, 160, 210); // app — teal
|
||||
case ConsoleChannel::Info: return OnSurfaceDisabled();
|
||||
default: return 0; // result / JSON roles get no accent
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleTab::ConsoleTab()
|
||||
{
|
||||
{
|
||||
@@ -246,6 +263,11 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
outGlass.rounding = Layout::glassRounding();
|
||||
outGlass.fillAlpha = 12;
|
||||
DrawGlassPanel(dlOut, outPanelMin, outPanelMax, outGlass);
|
||||
// Terminal-dark overlay: dim the glass so console text reads like a real terminal.
|
||||
{
|
||||
int darkA = static_cast<int>(schema::UI().drawElement("tabs.console", "bg-darken-alpha").sizeOr(110.0f));
|
||||
dlOut->AddRectFilled(outPanelMin, outPanelMax, IM_COL32(0, 0, 0, darkA), outGlass.rounding);
|
||||
}
|
||||
|
||||
int consoleParentVtx = dlOut->VtxBuffer.Size;
|
||||
|
||||
@@ -256,8 +278,8 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
int consoleChildVtx = consoleChildDL->VtxBuffer.Size;
|
||||
float consoleScrollY = ImGui::GetScrollY();
|
||||
float consoleScrollMaxY = ImGui::GetScrollMaxY();
|
||||
// Use smaller font for console output
|
||||
ImGui::PushFont(Type().caption());
|
||||
// Console output uses the monospace font so terminal text + JSON columns align.
|
||||
ImGui::PushFont(Type().mono());
|
||||
ImGui::SetWindowFontScale(s_console_zoom);
|
||||
renderOutput();
|
||||
ImGui::SetWindowFontScale(1.0f);
|
||||
@@ -270,7 +292,7 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
// away from the bottom before we check position again.
|
||||
scroll_.tickCooldown(ImGui::GetIO().DeltaTime);
|
||||
{
|
||||
float tolerance = Type().caption()->LegacySize * 1.5f;
|
||||
float tolerance = Type().mono()->LegacySize * 1.5f;
|
||||
bool atBottom = consoleScrollMaxY > 0.0f &&
|
||||
consoleScrollY >= consoleScrollMaxY - tolerance;
|
||||
scroll_.considerReenable(atBottom);
|
||||
@@ -280,7 +302,7 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
// When auto-scroll is off, force bottom fade to always show by
|
||||
// inflating scrollMax so the mask thinks there's content below.
|
||||
{
|
||||
float fadeZone = std::min(Type().caption()->LegacySize * 3.0f, outputH * 0.18f);
|
||||
float fadeZone = std::min(Type().mono()->LegacySize * 3.0f, outputH * 0.18f);
|
||||
float effectiveScrollMax = scroll_.autoScroll() ? consoleScrollMaxY
|
||||
: std::max(consoleScrollMaxY, consoleScrollY + 10.0f);
|
||||
ApplyScrollEdgeMask(dlOut, consoleParentVtx, consoleChildDL, consoleChildVtx,
|
||||
@@ -290,7 +312,7 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
// CRT scanline effect over output area — aligned to text lines
|
||||
if (s_scanline_enabled) {
|
||||
float textLineH = output_line_height_;
|
||||
if (textLineH <= 1.0f) textLineH = Type().caption()->LegacySize * s_console_zoom + 2.0f;
|
||||
if (textLineH <= 1.0f) textLineH = Type().mono()->LegacySize * s_console_zoom + 2.0f;
|
||||
|
||||
int lightAlpha = std::clamp((int)schema::UI().drawElement("tabs.console", "scanline-line-alpha").sizeOr(10.0f), 0, 255);
|
||||
int darkAlpha = std::clamp(lightAlpha + 10, 0, 255);
|
||||
@@ -382,9 +404,11 @@ void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec)
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
// Log filters (daemon/errors/rpc-trace/app) apply only to a daemon log source.
|
||||
if (exec.hasLogFilters()) {
|
||||
drawLogFilterToggles();
|
||||
// Log-filter toggles — only the ones the backend supports (full node = all; lite =
|
||||
// errors-only + app), each tinted with its channel color.
|
||||
ConsoleLogFilterCaps filterCaps = exec.logFilterCaps();
|
||||
if (filterCaps.any()) {
|
||||
drawLogFilterToggles(filterCaps);
|
||||
}
|
||||
|
||||
// Clear button
|
||||
@@ -474,49 +498,51 @@ void ConsoleTab::drawToolbarStatus(ConsoleCommandExecutor& exec)
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleTab::drawLogFilterToggles()
|
||||
void ConsoleTab::drawLogFilterToggles(const ConsoleLogFilterCaps& caps)
|
||||
{
|
||||
// Daemon messages toggle
|
||||
ImGui::Checkbox(TR("console_daemon"), &s_daemon_messages_enabled);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip("%s", TR("console_show_daemon_output"));
|
||||
// Each toggle is tinted with its channel's accent color (the same color as that channel's
|
||||
// left accent bar in the output), so the filter maps visually to the lines it controls.
|
||||
// Only the toggles the backend supports (caps) are shown — lite has no daemon/rpc-trace.
|
||||
bool drawnAny = false;
|
||||
auto separate = [&drawnAny]() {
|
||||
if (drawnAny) { ImGui::SameLine(); ImGui::Spacing(); ImGui::SameLine(); }
|
||||
drawnAny = true;
|
||||
};
|
||||
auto colored = [](ConsoleChannel ch, const char* label, bool* v, const char* tip) -> bool {
|
||||
ImVec4 c = ImGui::ColorConvertU32ToFloat4(channelAccentColor(ch));
|
||||
ImGui::PushStyleColor(ImGuiCol_CheckMark, c);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, c);
|
||||
bool changed = ImGui::Checkbox(label, v);
|
||||
ImGui::PopStyleColor(2);
|
||||
if (ImGui::IsItemHovered()) material::Tooltip("%s", tip);
|
||||
return changed;
|
||||
};
|
||||
|
||||
if (caps.daemon) {
|
||||
separate();
|
||||
colored(ConsoleChannel::Daemon, TR("console_daemon"), &s_daemon_messages_enabled,
|
||||
TR("console_show_daemon_output"));
|
||||
}
|
||||
if (caps.errorsOnly) {
|
||||
separate();
|
||||
colored(ConsoleChannel::Error, TR("console_errors"), &s_errors_only_enabled,
|
||||
TR("console_show_errors_only"));
|
||||
}
|
||||
if (caps.rpcTrace) {
|
||||
separate();
|
||||
// Captures method/source only, never results or params.
|
||||
if (colored(ConsoleChannel::Rpc, TR("console_rpc_trace"), &s_rpc_trace_enabled,
|
||||
TR("console_show_rpc_trace")))
|
||||
rpc::RPCClient::setTraceEnabled(s_rpc_trace_enabled);
|
||||
}
|
||||
if (caps.appMessages) {
|
||||
separate();
|
||||
colored(ConsoleChannel::App, TR("console_app"), &s_app_messages_enabled,
|
||||
TR("console_show_app_output"));
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
// Errors-only toggle
|
||||
ImGui::Checkbox(TR("console_errors"), &s_errors_only_enabled);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip("%s", TR("console_show_errors_only"));
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
// App RPC trace toggle — captures method/source only, never results or params
|
||||
if (ImGui::Checkbox(TR("console_rpc_trace"), &s_rpc_trace_enabled)) {
|
||||
rpc::RPCClient::setTraceEnabled(s_rpc_trace_enabled);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip("%s", TR("console_show_rpc_trace"));
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
// App messages toggle — "[app] ..." wallet log lines
|
||||
ImGui::Checkbox(TR("console_app"), &s_app_messages_enabled);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip("%s", TR("console_show_app_output"));
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
// Trailing spacer so the next toolbar item (Clear) stays on the same line.
|
||||
if (drawnAny) { ImGui::SameLine(); ImGui::Spacing(); ImGui::SameLine(); }
|
||||
}
|
||||
|
||||
void ConsoleTab::drawFilterInput()
|
||||
@@ -657,7 +683,7 @@ void ConsoleTab::renderOutput()
|
||||
// toggles — otherwise the geometry shift clamps the user back to
|
||||
// bottom and a single scroll-up tick can't escape.
|
||||
{
|
||||
float fadeZone = std::min(Type().caption()->LegacySize * 3.0f,
|
||||
float fadeZone = std::min(Type().mono()->LegacySize * 3.0f,
|
||||
ImGui::GetWindowHeight() * 0.18f);
|
||||
ImGui::Dummy(ImVec2(0, fadeZone));
|
||||
}
|
||||
@@ -825,21 +851,9 @@ void ConsoleTab::drawVisibleLines(float padX, float lineHeight, bool hasTextFilt
|
||||
float totalH = layout_.heights[vi];
|
||||
|
||||
// Left-edge channel accent bar, drawn in the padX margin so it never overlaps
|
||||
// the text or the selection highlight.
|
||||
// the text or the selection highlight. Same color that tints the toolbar toggle.
|
||||
if (line.channel != ConsoleChannel::None) {
|
||||
ImU32 barCol = 0;
|
||||
switch (line.channel) {
|
||||
case ConsoleChannel::Command: barCol = Primary(); break;
|
||||
case ConsoleChannel::Error: barCol = Error(); break;
|
||||
case ConsoleChannel::Warning: barCol = Warning(); break;
|
||||
case ConsoleChannel::Success: barCol = Success(); break;
|
||||
case ConsoleChannel::Rpc: barCol = Secondary(); break;
|
||||
case ConsoleChannel::Daemon: barCol = IM_COL32(90, 130, 190, 210); break; // node log — blue
|
||||
case ConsoleChannel::Xmrig: barCol = Warning(); break; // mining — amber
|
||||
case ConsoleChannel::App: barCol = IM_COL32(120, 190, 160, 210); break; // app — teal
|
||||
case ConsoleChannel::Info: barCol = OnSurfaceDisabled(); break;
|
||||
default: break; // result / JSON roles get no bar
|
||||
}
|
||||
ImU32 barCol = channelAccentColor(line.channel);
|
||||
if (barCol != 0) {
|
||||
float barW = 3.0f * Layout::hScale();
|
||||
float barX = output_origin_.x - padX + 3.0f * Layout::hScale();
|
||||
@@ -1109,10 +1123,12 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
|
||||
float inputPanelH = ImGui::GetFrameHeightWithSpacing() + Layout::spacingSm() + Layout::spacingXs();
|
||||
ImVec2 inMin = ImGui::GetCursorScreenPos();
|
||||
ImVec2 inMax(inMin.x + ImGui::GetContentRegionAvail().x, inMin.y + inputPanelH);
|
||||
GlassPanelSpec inGlass;
|
||||
inGlass.rounding = Layout::glassRounding();
|
||||
inGlass.fillAlpha = 12;
|
||||
material::DrawGlassPanel(dlIn, inMin, inMax, inGlass);
|
||||
// No light glass rectangle on the input — a flat terminal-dark bar instead, matching
|
||||
// the darkened output panel above.
|
||||
{
|
||||
int darkA = static_cast<int>(schema::UI().drawElement("tabs.console", "bg-darken-alpha").sizeOr(110.0f));
|
||||
dlIn->AddRectFilled(inMin, inMax, IM_COL32(0, 0, 0, darkA), Layout::glassRounding());
|
||||
}
|
||||
|
||||
// Center content vertically within glass panel
|
||||
float inputFrameH = ImGui::GetFrameHeight();
|
||||
@@ -1121,9 +1137,10 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
|
||||
|
||||
|
||||
|
||||
// Input field
|
||||
// Input field — monospace to match the terminal-style output.
|
||||
ImGui::PushFont(Type().mono());
|
||||
ImGui::PushItemWidth(-Layout::spacingMd());
|
||||
|
||||
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue |
|
||||
ImGuiInputTextFlags_CallbackHistory |
|
||||
ImGuiInputTextFlags_CallbackCompletion;
|
||||
@@ -1177,6 +1194,11 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Blend the field into the dark terminal bar: transparent frame, subtle hover/active.
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, IM_COL32(255, 255, 255, 12));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, IM_COL32(255, 255, 255, 18));
|
||||
|
||||
const bool busy = exec.busy();
|
||||
if (busy) ImGui::BeginDisabled();
|
||||
if (ImGui::InputText("##ConsoleInput", input_buffer_, sizeof(input_buffer_), flags, callback, this)) {
|
||||
@@ -1192,8 +1214,10 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
|
||||
}
|
||||
}
|
||||
if (busy) ImGui::EndDisabled();
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::PopFont();
|
||||
|
||||
// Auto-focus on input
|
||||
if (reclaim_focus) {
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace dragonx {
|
||||
namespace ui {
|
||||
|
||||
class ConsoleCommandExecutor;
|
||||
struct ConsoleLogFilterCaps;
|
||||
|
||||
/**
|
||||
* @brief Console tab — a rich terminal shared by the full-node and lite variants.
|
||||
@@ -92,6 +93,9 @@ private:
|
||||
// line stores only its semantic ConsoleChannel (in ConsoleModel); the text color and
|
||||
// the left accent-bar color are both derived from it at draw time.
|
||||
ImU32 channelTextColor(ConsoleChannel channel) const;
|
||||
// Saturated accent color for a channel — the left accent-bar color, also used to tint the
|
||||
// matching toolbar filter toggle. 0 for channels that get no accent (result/JSON/None).
|
||||
static ImU32 channelAccentColor(ConsoleChannel channel);
|
||||
|
||||
// Drain the thread-safe ingest queue into the visible model (once per frame, main
|
||||
// thread), applying the line cap + selection/scroll bookkeeping for the new lines.
|
||||
@@ -105,7 +109,7 @@ private:
|
||||
// renderToolbar() draws the top bar; these are its sub-steps:
|
||||
void renderToolbar(ConsoleCommandExecutor& exec);
|
||||
void drawToolbarStatus(ConsoleCommandExecutor& exec); // backend status dot + label
|
||||
void drawLogFilterToggles(); // daemon/errors/rpc/app checkboxes
|
||||
void drawLogFilterToggles(const ConsoleLogFilterCaps& caps); // color-coded filter checkboxes
|
||||
void drawFilterInput(); // text filter + match count
|
||||
void drawZoomControls(); // zoom -/+ buttons
|
||||
|
||||
|
||||
Reference in New Issue
Block a user