// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #pragma once #include "../layout.h" #include "../../daemon/embedded_daemon.h" #include "../../daemon/xmrig_manager.h" #include "../../rpc/rpc_client.h" #include "../../rpc/rpc_worker.h" #include #include #include #include namespace dragonx { namespace ui { /** * @brief Console tab for daemon output and command input * * Shows dragonxd output and allows executing RPC commands. */ class ConsoleTab { public: ConsoleTab(); ~ConsoleTab() = default; /** * @brief Render the console tab * @param daemon Pointer to embedded daemon (may be null) * @param rpc Pointer to RPC client for command execution * @param xmrig Pointer to xmrig manager for pool mining output (may be null) */ void render(daemon::EmbeddedDaemon* daemon, rpc::RPCClient* rpc, rpc::RPCWorker* worker, daemon::XmrigManager* xmrig = nullptr); /** * @brief Render the RPC Command Reference popup at top-level scope. * Must be called outside any child window so the modal blocks all input. */ void renderCommandsPopupModal(); /** * @brief Add a line to the console output */ void addLine(const std::string& line, ImU32 color = IM_COL32(200, 200, 200, 255)); /** * @brief Clear console output */ void clear(); /** * @brief Check if auto-scroll is enabled */ bool isAutoScrollEnabled() const { return auto_scroll_; } // Scanline effect toggle (set from settings) static bool s_scanline_enabled; // Console output zoom factor (1.0 = default caption font size) static float s_console_zoom; // Show/hide daemon output messages static bool s_daemon_messages_enabled; // Show only error messages (filter toggle) static bool s_errors_only_enabled; /// Refresh console text colors for current theme (call after theme switch) static void refreshColors(); // Colors — follow active theme (public for use by notification forwarding) static ImU32 COLOR_COMMAND; static ImU32 COLOR_RESULT; static ImU32 COLOR_ERROR; static ImU32 COLOR_DAEMON; static ImU32 COLOR_INFO; private: struct ConsoleLine { std::string text; ImU32 color; }; void executeCommand(const std::string& cmd, rpc::RPCClient* rpc, rpc::RPCWorker* worker); void addCommandResult(const std::string& cmd, const std::string& result, bool is_error = false); void renderToolbar(daemon::EmbeddedDaemon* daemon); void renderOutput(); void renderInput(rpc::RPCClient* rpc, rpc::RPCWorker* worker); void renderCommandsPopup(); // Selection helpers void handleSelection(); std::string getSelectedText() const; void clearSelection(); // Convert screen position to line/column struct TextPos { int line = -1; int col = 0; }; TextPos screenToTextPos(ImVec2 screen_pos, float line_height) const; bool isPosBeforeOrEqual(const TextPos& a, const TextPos& b) const; TextPos selectionStart() const; // Returns the earlier of sel_anchor_ and sel_end_ TextPos selectionEnd() const; // Returns the later of sel_anchor_ and sel_end_ std::deque lines_; std::vector command_history_; int history_index_ = -1; char input_buffer_[4096] = {0}; bool auto_scroll_ = true; bool scroll_to_bottom_ = false; float scroll_up_cooldown_ = 0.0f; // seconds to wait before re-enabling auto-scroll int new_lines_since_scroll_ = 0; // new lines while scrolled up (for indicator) size_t last_daemon_output_size_ = 0; size_t last_xmrig_output_size_ = 0; bool shown_startup_message_ = false; daemon::EmbeddedDaemon::State last_daemon_state_ = daemon::EmbeddedDaemon::State::Stopped; bool last_rpc_connected_ = false; // Text selection state bool is_selecting_ = false; bool has_selection_ = false; TextPos sel_anchor_; // Where the mouse was first pressed TextPos sel_end_; // Where the mouse currently is / was released float output_scroll_y_ = 0.0f; // Track scroll position for selection ImVec2 output_origin_ = {0, 0}; // Top-left of output area float output_line_height_ = 0.0f; // Text line height (for scanline alignment) std::mutex lines_mutex_; // Output filter char filter_text_[128] = {0}; mutable std::vector visible_indices_; // Cached for selection mapping // Wrapped line height caching (for variable-height text wrapping) mutable std::vector wrapped_heights_; // Height of each visible line (accounts for wrapping) mutable std::vector cumulative_y_offsets_; // Cumulative Y offset for each visible line mutable float total_wrapped_height_ = 0.0f; // Total height of all visible lines mutable float cached_wrap_width_ = 0.0f; // Wrap width used for cached heights // Sub-row layout: each visible line is split into wrap segments so // selection and hit-testing know the exact screen position of every // character. struct WrapSegment { int byteStart; // byte offset into ConsoleLine::text int byteEnd; // byte offset past last char in this segment float yOffset; // Y offset of this segment relative to the line's top float height; // visual height of this segment }; mutable std::vector> visible_wrap_segments_; // [vi] -> segments // Commands popup bool show_commands_popup_ = false; }; } // namespace ui } // namespace dragonx