#pragma once #include "fgc/ui/IUserInterface.h" #include #include #include #include #include namespace ftxui { class ScreenInteractive; } namespace fgc { // Full-screen FTXUI dashboard: sectioned, colored panels (gimbal, sensors, // camera, connectivity) updated in place, a scrolling log pane fed from a Logger // sink, and a nano-style key bar. Pure observer + command source: it renders the // UiSnapshot it pulls and forwards keystrokes/typed commands to the sink. // // Compiled only when FGC_WITH_TUI; the Application falls back to HeadlessUi // otherwise. class TuiUi : public IUserInterface { public: TuiUi(); ~TuiUi() override; void start(SnapshotFn snapshot, CommandSink sink) override; void stop() override; private: void uiLoop(); // runs the FTXUI event loop (own thread) void refreshLoop(); // posts redraw events at ~10 Hz (own thread) void pushLog(LogLevel level, const std::string& line); SnapshotFn snapshot_; CommandSink sink_; // Raw pointer to the loop thread's stack-local screen (ScreenInteractive is // neither copyable nor movable, so it can't be a value/unique_ptr member). // Set inside uiLoop(); read by stop()/refreshLoop() to Exit()/PostEvent(). std::atomic screen_{nullptr}; std::thread ui_thread_; std::thread refresh_thread_; std::atomic running_{false}; // Log ring buffer (newest last), filled by the Logger sink. std::mutex log_mutex_; std::deque log_; static constexpr size_t kLogCap = 500; }; } // namespace fgc