#include "tui/tui.hpp" #include "system/system.hpp" #include #include #include using namespace ftxui; Tui::Tui() : cursor_pos(0), history_idx(-1), scroll_offset(0), quit(false), in_source(false), loading(false), tick_in_flight(false), loading_idx(0), loading_executed(0), loading_lineno(0), loading_prev_in_source(false), screen_ptr(nullptr), screen_idx(4), // boot to the dashboard; console (screen 0) is now a sub-screen connect_m1_idx(0), connect_m2_idx(0), connect_p1_idx(0), connect_p2_idx(0), connect_focus_idx(0), explore_module_idx(0), explore_types{"parts", "signals", "connections"}, explore_type_idx(0), explore_child_idx(0), explore_detail_idx(0), explore_focus_idx(0), settype_m_idx(0), settype_p_idx(0), settype_focus_idx(0) { LoadHistory(); RegisterCommands(); Print("essim — type 'help' for commands, 'quit' to exit."); } Tui::~Tui() = default; void Tui::Run() { auto screen = ScreenInteractive::Fullscreen(); screen_ptr = &screen; auto main_screen = BuildMainScreen(screen); auto connect_screen = BuildConnectScreen(); auto settype_screen = BuildSettypeScreen(); auto explore_screen = BuildExploreScreen() | Modal(BuildSignalTypeModal(), &sigtype_dialog_open); auto dashboard_screen = BuildDashboardScreen(); auto analyze_screen = BuildAnalyzeScreen(); auto tab = Container::Tab( {main_screen, connect_screen, settype_screen, explore_screen, dashboard_screen, analyze_screen}, &screen_idx); // Palette is a global Modal — overlays the tab on every screen. auto with_palette = tab | Modal(BuildPaletteModal(), &palette_open); auto root = CatchEvent(with_palette, [this](Event e) { // Modals (palette + sigtype popup) own their events while open. if (palette_open || sigtype_dialog_open) return false; // Ctrl-P opens the palette from any screen. if (e == Event::CtrlP) { OpenPalette(); return true; } // screen_idx mapping: 0 = console, 1 = connect, 2 = set-connector-type, // 3 = explore, 4 = dashboard (home), 5 = analyze. switch (screen_idx) { case 5: // analyze if (e == Event::Escape) { screen_idx = 4; return true; } if (e == Event::Tab || e == Event::ArrowRight) { analyze_focus_idx = (analyze_focus_idx + 1) % 3; return true; } if (e == Event::TabReverse || e == Event::ArrowLeft) { analyze_focus_idx = (analyze_focus_idx + 2) % 3; return true; } return false; case 4: // dashboard (home) if (e == Event::Escape) { return true; } if (e == Event::PageDown) { dashboard_scroll_offset += 10; return true; } if (e == Event::PageUp) { dashboard_scroll_offset = std::max(0, dashboard_scroll_offset - 10); return true; } if (e == Event::Home) { dashboard_scroll_offset = 0; return true; } if (e == Event::End) { dashboard_scroll_offset = 100000; return true; } if (e == Event::Character("q")) { Dispatch("quit"); return true; } if (e == Event::Character("c")) { screen_idx = 0; return true; } if (e == Event::Character("p")) { Dispatch("connect"); return true; } if (e == Event::Character("t")) { Dispatch("set-connector-type"); return true; } if (e == Event::Character("e")) { Dispatch("explore"); return true; } if (e == Event::Character("a")) { screen_idx = 5; return true; } return false; case 3: // explore if (e == Event::Escape) { screen_idx = 4; return true; } if (e == Event::Tab) { explore_focus_idx = (explore_focus_idx + 1) % 6; return true; } if (e == Event::TabReverse) { explore_focus_idx = (explore_focus_idx + 5) % 6; return true; } return false; case 2: // set-connector-type if (e == Event::Escape) { screen_idx = 4; return true; } if (e == Event::Tab) { settype_focus_idx = (settype_focus_idx + 1) % 5; return true; } if (e == Event::TabReverse) { settype_focus_idx = (settype_focus_idx + 4) % 5; return true; } return false; case 1: // connect if (e == Event::Escape) { screen_idx = 4; return true; } if (e == Event::Tab) { connect_focus_idx = (connect_focus_idx + 1) % 7; return true; } if (e == Event::TabReverse) { connect_focus_idx = (connect_focus_idx + 6) % 7; return true; } return false; default: // 0: main (console / log view) if (e == Event::Special("\x02tick")) { ProcessNextSourceLine(); return true; } if (e == Event::Escape) { if (!pending.empty()) { CancelPending(); return true; } screen_idx = 4; return true; } if (e == Event::PageUp) { scroll_offset += 10; return true; } if (e == Event::PageDown) { scroll_offset = std::max(0, scroll_offset - 10); return true; } if (e == Event::Home) { scroll_offset = (int)output.size(); return true; } if (e == Event::End) { scroll_offset = 0; return true; } if (e == Event::ArrowUp || e == Event::ArrowDown) { if (pending.empty()) { if (e == Event::ArrowUp) HistoryUp(); else HistoryDown(); } return true; } if (e == Event::Tab) { if (pending.empty()) { CompleteInline(); } else { switch (pending.front().completion) { case Completion::Path: CompletePath(); break; case Completion::Command: CompleteCommand(); break; case Completion::None: break; } } return true; } return false; } }); screen.Loop(root); }