refactor(console): phase 5b — decompose toolbar/input/commands-popup methods
Finish the thin-view pass on the remaining large render methods (pure code motion, no behavior change): - renderToolbar (225 -> 99 lines): extracted drawToolbarStatus(), the drawLogFilterToggles() checkbox group, drawFilterInput(), and drawZoomControls(). - renderInput: factored the command echo + built-in interception + submit into submitConsoleCommand(exec, cmd) -> bool, leaving renderInput to own just the glass panel + InputText + completion/history callback. - renderCommandsPopup (194 -> 135 lines): removed the duplicated lowercase-and- find filter logic (match-count loop and per-row filter now share consoleCommandMatchesFilter()) and extracted the [optional]-param dimming loop into drawConsoleCommandParams(). Full-node + lite build clean; ctest green; source hygiene clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -366,30 +366,8 @@ void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec)
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + Layout::spacingMd());
|
||||
|
||||
// Backend status with colored dot (daemon state / lite connection).
|
||||
{
|
||||
ConsoleStatusLine st = exec.toolbarStatus();
|
||||
if (!st.text.empty()) {
|
||||
ImVec2 cp = ImGui::GetCursorScreenPos();
|
||||
float dotR = schema::UI().drawElement("tabs.console", "status-dot-radius-base").size + schema::UI().drawElement("tabs.console", "status-dot-radius-scale").size * Layout::hScale();
|
||||
float dotY = cp.y + ImGui::GetTextLineHeight() * 0.5f;
|
||||
float dotX = cp.x + dotR + 2;
|
||||
drawToolbarStatus(exec);
|
||||
|
||||
if (st.pulse) {
|
||||
float a = schema::UI().drawElement("animations", "pulse-base-glow").size + schema::UI().drawElement("animations", "pulse-amp-glow").size * (float)std::sin((double)ImGui::GetTime() * schema::UI().drawElement("animations", "pulse-speed-fast").size);
|
||||
ImU32 pCol = (st.color & 0x00FFFFFF) | ((ImU32)(255 * a) << 24);
|
||||
dl->AddCircleFilled(ImVec2(dotX, dotY), dotR, pCol);
|
||||
} else {
|
||||
dl->AddCircleFilled(ImVec2(dotX, dotY), dotR, st.color);
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(dotR * 2 + 6, 0));
|
||||
ImGui::SameLine();
|
||||
Type().textColored(TypeStyle::Caption, st.color, st.text.c_str());
|
||||
} else {
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("console_no_daemon"));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
@@ -406,49 +384,8 @@ void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec)
|
||||
|
||||
// Log filters (daemon/errors/rpc-trace/app) apply only to a daemon log source.
|
||||
if (exec.hasLogFilters()) {
|
||||
// Daemon messages toggle
|
||||
ImGui::Checkbox(TR("console_daemon"), &s_daemon_messages_enabled);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip("%s", TR("console_show_daemon_output"));
|
||||
drawLogFilterToggles();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
} // exec.hasLogFilters()
|
||||
|
||||
// Clear button
|
||||
if (TactileButton(TR("console_clear"), ImVec2(0, 0), schema::UI().resolveFont("button"))) {
|
||||
@@ -501,6 +438,90 @@ void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec)
|
||||
ImGui::SameLine();
|
||||
|
||||
// Output filter input
|
||||
drawFilterInput();
|
||||
|
||||
// Zoom +/- buttons (right side of toolbar)
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
drawZoomControls();
|
||||
}
|
||||
|
||||
void ConsoleTab::drawToolbarStatus(ConsoleCommandExecutor& exec)
|
||||
{
|
||||
using namespace material;
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
ConsoleStatusLine st = exec.toolbarStatus();
|
||||
if (!st.text.empty()) {
|
||||
ImVec2 cp = ImGui::GetCursorScreenPos();
|
||||
float dotR = schema::UI().drawElement("tabs.console", "status-dot-radius-base").size + schema::UI().drawElement("tabs.console", "status-dot-radius-scale").size * Layout::hScale();
|
||||
float dotY = cp.y + ImGui::GetTextLineHeight() * 0.5f;
|
||||
float dotX = cp.x + dotR + 2;
|
||||
|
||||
if (st.pulse) {
|
||||
float a = schema::UI().drawElement("animations", "pulse-base-glow").size + schema::UI().drawElement("animations", "pulse-amp-glow").size * (float)std::sin((double)ImGui::GetTime() * schema::UI().drawElement("animations", "pulse-speed-fast").size);
|
||||
ImU32 pCol = (st.color & 0x00FFFFFF) | ((ImU32)(255 * a) << 24);
|
||||
dl->AddCircleFilled(ImVec2(dotX, dotY), dotR, pCol);
|
||||
} else {
|
||||
dl->AddCircleFilled(ImVec2(dotX, dotY), dotR, st.color);
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(dotR * 2 + 6, 0));
|
||||
ImGui::SameLine();
|
||||
Type().textColored(TypeStyle::Caption, st.color, st.text.c_str());
|
||||
} else {
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("console_no_daemon"));
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleTab::drawLogFilterToggles()
|
||||
{
|
||||
// Daemon messages toggle
|
||||
ImGui::Checkbox(TR("console_daemon"), &s_daemon_messages_enabled);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip("%s", TR("console_show_daemon_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();
|
||||
}
|
||||
|
||||
void ConsoleTab::drawFilterInput()
|
||||
{
|
||||
using namespace material;
|
||||
float zoomBtnSpace = ImGui::GetFrameHeight() * 2.0f + Layout::spacingSm() * 3.0f;
|
||||
float filterAvail = ImGui::GetContentRegionAvail().x - zoomBtnSpace;
|
||||
float filterW = std::min(schema::UI().drawElement("tabs.console", "filter-max-width").size, filterAvail * schema::UI().drawElement("tabs.console", "filter-width-ratio").size);
|
||||
@@ -512,31 +533,29 @@ void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec)
|
||||
Type().textColored(TypeStyle::Caption,
|
||||
filter_match_count_ > 0 ? OnSurfaceMedium() : Error(), mc.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Zoom +/- buttons (right side of toolbar)
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
{
|
||||
auto& S = schema::UI();
|
||||
float zoomStep = S.drawElement("tabs.console", "zoom-step").sizeOr(0.1f);
|
||||
float zoomMin = S.drawElement("tabs.console", "zoom-min").sizeOr(0.5f);
|
||||
float zoomMax = S.drawElement("tabs.console", "zoom-max").sizeOr(3.0f);
|
||||
float btnSz = ImGui::GetFrameHeight();
|
||||
void ConsoleTab::drawZoomControls()
|
||||
{
|
||||
using namespace material;
|
||||
auto& S = schema::UI();
|
||||
float zoomStep = S.drawElement("tabs.console", "zoom-step").sizeOr(0.1f);
|
||||
float zoomMin = S.drawElement("tabs.console", "zoom-min").sizeOr(0.5f);
|
||||
float zoomMax = S.drawElement("tabs.console", "zoom-max").sizeOr(3.0f);
|
||||
float btnSz = ImGui::GetFrameHeight();
|
||||
|
||||
if (TactileButton(ICON_MD_REMOVE, ImVec2(btnSz, btnSz), Type().iconMed())) {
|
||||
s_console_zoom = std::max(zoomMin, s_console_zoom - zoomStep);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip(TR("console_zoom_out"), s_console_zoom * 100.0f);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (TactileButton(ICON_MD_ADD, ImVec2(btnSz, btnSz), Type().iconMed())) {
|
||||
s_console_zoom = std::min(zoomMax, s_console_zoom + zoomStep);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip(TR("console_zoom_in"), s_console_zoom * 100.0f);
|
||||
}
|
||||
if (TactileButton(ICON_MD_REMOVE, ImVec2(btnSz, btnSz), Type().iconMed())) {
|
||||
s_console_zoom = std::max(zoomMin, s_console_zoom - zoomStep);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip(TR("console_zoom_out"), s_console_zoom * 100.0f);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (TactileButton(ICON_MD_ADD, ImVec2(btnSz, btnSz), Type().iconMed())) {
|
||||
s_console_zoom = std::min(zoomMax, s_console_zoom + zoomStep);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip(TR("console_zoom_in"), s_console_zoom * 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1108,34 +1127,7 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
|
||||
if (tb == std::string::npos) cmd.clear(); else cmd = cmd.substr(tb);
|
||||
while (!cmd.empty() && (cmd.back() == ' ' || cmd.back() == '\t')) cmd.pop_back();
|
||||
|
||||
if (!cmd.empty()) {
|
||||
addLine("> " + cmd, ConsoleChannel::Command);
|
||||
AppendConsoleHistory(command_history_, cmd, 100);
|
||||
history_index_ = -1;
|
||||
|
||||
// First token, lowercased, for built-in interception.
|
||||
std::string first;
|
||||
{
|
||||
size_t fb = cmd.find_first_not_of(" \t");
|
||||
size_t fe = cmd.find_first_of(" \t", fb);
|
||||
first = cmd.substr(fb, fe == std::string::npos ? std::string::npos : fe - fb);
|
||||
std::transform(first.begin(), first.end(), first.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
}
|
||||
auto add = [this](const std::string& l, ConsoleChannel c) { addLine(l, c); };
|
||||
if (first == "clear" || first == "cls") {
|
||||
// View-only clear — NEVER forwarded (the lite backend's `clear` wipes tx history).
|
||||
clear();
|
||||
selection_.clear();
|
||||
} else if (first == "help") {
|
||||
exec.printHelp(add);
|
||||
} else if (first == "quit" || first == "exit") {
|
||||
addLine(TR("console_quit_note"), ConsoleChannel::Info);
|
||||
} else if (!exec.isReady()) {
|
||||
addLine(TR("console_not_connected"), ConsoleChannel::Error);
|
||||
} else {
|
||||
exec.submit(cmd);
|
||||
}
|
||||
if (submitConsoleCommand(exec, cmd)) {
|
||||
input_buffer_[0] = '\0';
|
||||
reclaim_focus = true;
|
||||
}
|
||||
@@ -1150,6 +1142,94 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
|
||||
}
|
||||
}
|
||||
|
||||
bool ConsoleTab::submitConsoleCommand(ConsoleCommandExecutor& exec, const std::string& cmd)
|
||||
{
|
||||
if (cmd.empty()) return false;
|
||||
|
||||
addLine("> " + cmd, ConsoleChannel::Command);
|
||||
AppendConsoleHistory(command_history_, cmd, 100);
|
||||
history_index_ = -1;
|
||||
|
||||
// First token, lowercased, for built-in interception.
|
||||
std::string first;
|
||||
{
|
||||
size_t fb = cmd.find_first_not_of(" \t");
|
||||
size_t fe = cmd.find_first_of(" \t", fb);
|
||||
first = cmd.substr(fb, fe == std::string::npos ? std::string::npos : fe - fb);
|
||||
std::transform(first.begin(), first.end(), first.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
}
|
||||
auto add = [this](const std::string& l, ConsoleChannel c) { addLine(l, c); };
|
||||
if (first == "clear" || first == "cls") {
|
||||
// View-only clear — NEVER forwarded (the lite backend's `clear` wipes tx history).
|
||||
clear();
|
||||
selection_.clear();
|
||||
} else if (first == "help") {
|
||||
exec.printHelp(add);
|
||||
} else if (first == "quit" || first == "exit") {
|
||||
addLine(TR("console_quit_note"), ConsoleChannel::Info);
|
||||
} else if (!exec.isReady()) {
|
||||
addLine(TR("console_not_connected"), ConsoleChannel::Error);
|
||||
} else {
|
||||
exec.submit(cmd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// True if any of a command's name/desc/params contains `filterLower` (already lowercased).
|
||||
// An empty filter matches everything.
|
||||
bool consoleCommandMatchesFilter(const char* name, const char* desc, const char* params,
|
||||
const std::string& filterLower)
|
||||
{
|
||||
if (filterLower.empty()) return true;
|
||||
auto contains = [&filterLower](const char* s) {
|
||||
std::string v(s);
|
||||
std::transform(v.begin(), v.end(), v.begin(), ::tolower);
|
||||
return v.find(filterLower) != std::string::npos;
|
||||
};
|
||||
return contains(name) || contains(desc) || contains(params);
|
||||
}
|
||||
|
||||
// Draw a command's parameter string into the current table cell, dimming optional [params].
|
||||
void drawConsoleCommandParams(const char* params)
|
||||
{
|
||||
using namespace material;
|
||||
const char* p = params;
|
||||
bool first = true;
|
||||
while (*p) {
|
||||
const char* bracketStart = strchr(p, '[');
|
||||
if (bracketStart) {
|
||||
// Draw the required part before the bracket.
|
||||
if (bracketStart > p) {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
std::string req(p, bracketStart);
|
||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()), "%s", req.c_str());
|
||||
first = false;
|
||||
}
|
||||
const char* bracketEnd = strchr(bracketStart, ']');
|
||||
if (bracketEnd) {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
std::string opt(bracketStart, bracketEnd + 1);
|
||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), "%s", opt.c_str());
|
||||
first = false;
|
||||
p = bracketEnd + 1;
|
||||
} else {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()), "%s", bracketStart);
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()), "%s", p);
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void ConsoleTab::renderCommandsPopup()
|
||||
{
|
||||
using namespace material;
|
||||
@@ -1190,15 +1270,8 @@ void ConsoleTab::renderCommandsPopup()
|
||||
matchCount = cat.count;
|
||||
} else {
|
||||
for (int i = 0; i < cat.count; i++) {
|
||||
std::string name(cat.commands[i].name);
|
||||
std::string desc(cat.commands[i].desc);
|
||||
std::string params(cat.commands[i].params);
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
std::transform(desc.begin(), desc.end(), desc.begin(), ::tolower);
|
||||
std::transform(params.begin(), params.end(), params.begin(), ::tolower);
|
||||
if (name.find(filter) != std::string::npos ||
|
||||
desc.find(filter) != std::string::npos ||
|
||||
params.find(filter) != std::string::npos) {
|
||||
if (consoleCommandMatchesFilter(cat.commands[i].name, cat.commands[i].desc,
|
||||
cat.commands[i].params, filter)) {
|
||||
matchCount++;
|
||||
}
|
||||
}
|
||||
@@ -1234,20 +1307,9 @@ void ConsoleTab::renderCommandsPopup()
|
||||
|
||||
for (int i = 0; i < cat.count; i++) {
|
||||
const auto& cmd = cat.commands[i];
|
||||
std::string nameLower(cmd.name);
|
||||
std::string descLower(cmd.desc);
|
||||
std::string paramsLower(cmd.params);
|
||||
std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower);
|
||||
std::transform(descLower.begin(), descLower.end(), descLower.begin(), ::tolower);
|
||||
std::transform(paramsLower.begin(), paramsLower.end(), paramsLower.begin(), ::tolower);
|
||||
|
||||
if (!filter.empty() &&
|
||||
nameLower.find(filter) == std::string::npos &&
|
||||
descLower.find(filter) == std::string::npos &&
|
||||
paramsLower.find(filter) == std::string::npos) {
|
||||
if (!consoleCommandMatchesFilter(cmd.name, cmd.desc, cmd.params, filter))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||
@@ -1275,48 +1337,7 @@ void ConsoleTab::renderCommandsPopup()
|
||||
ImGui::PopStyleColor(3);
|
||||
if (showParams) {
|
||||
ImGui::TableNextColumn();
|
||||
// Style optional params [param] in dimmed text
|
||||
const char* p = cmd.params;
|
||||
bool first = true;
|
||||
while (*p) {
|
||||
const char* bracketStart = strchr(p, '[');
|
||||
if (bracketStart) {
|
||||
// Draw required part before bracket
|
||||
if (bracketStart > p) {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
std::string req(p, bracketStart);
|
||||
ImGui::TextColored(
|
||||
ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()),
|
||||
"%s", req.c_str());
|
||||
first = false;
|
||||
}
|
||||
// Find matching ]
|
||||
const char* bracketEnd = strchr(bracketStart, ']');
|
||||
if (bracketEnd) {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
std::string opt(bracketStart, bracketEnd + 1);
|
||||
ImGui::TextColored(
|
||||
ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()),
|
||||
"%s", opt.c_str());
|
||||
first = false;
|
||||
p = bracketEnd + 1;
|
||||
} else {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(
|
||||
ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()),
|
||||
"%s", bracketStart);
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!first) ImGui::SameLine(0, 0);
|
||||
ImGui::TextColored(
|
||||
ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()),
|
||||
"%s", p);
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawConsoleCommandParams(cmd.params);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(
|
||||
|
||||
@@ -100,10 +100,20 @@ private:
|
||||
// Format a completed command result (JSON role -> channel) into console lines.
|
||||
void addFormattedResult(const std::string& result, bool is_error);
|
||||
void renderStatusHeader(ConsoleCommandExecutor& exec);
|
||||
void renderToolbar(ConsoleCommandExecutor& exec);
|
||||
void renderInput(ConsoleCommandExecutor& exec);
|
||||
void renderCommandsPopup();
|
||||
|
||||
// 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 drawFilterInput(); // text filter + match count
|
||||
void drawZoomControls(); // zoom -/+ buttons
|
||||
|
||||
// renderInput() draws the command line; dispatch is factored out:
|
||||
void renderInput(ConsoleCommandExecutor& exec);
|
||||
// Echo + handle a submitted command line (built-ins + submit). True if non-empty/handled.
|
||||
bool submitConsoleCommand(ConsoleCommandExecutor& exec, const std::string& cmd);
|
||||
|
||||
// renderOutput() orchestrates the scrollable output area; these are its sub-steps:
|
||||
void renderOutput();
|
||||
void computeVisibleLines(bool& hasTextFilter, std::string& filterLower); // -> visible_indices_
|
||||
|
||||
Reference in New Issue
Block a user