3#include <ftxui/component/component.hpp>
4#include <ftxui/component/screen_interactive.hpp>
5#include <ftxui/dom/elements.hpp>
6#include <ftxui/screen/terminal.hpp>
10#include "absl/strings/str_format.h"
20 : screen_(ScreenInteractive::TerminalOutput()), rom_context_(rom_context) {
40 {text(rom_loaded ?
"✅ Ready" :
"⚠ Awaiting ROM") |
41 color(rom_loaded ? Color::GreenLight : Color::YellowLight),
49 return std::vector<std::string>{
50 "agent::chat — conversational ROM inspector",
51 "rom::info — metadata & validation",
"dungeon::list — dungeon manifest",
52 "gfx::export — sprite/palette dump",
"project::build — apply patches"};
56 return std::vector<std::string>{
57 "[pending] Implement dungeon diff visualizer",
58 "[pending] Integrate context panes",
59 "[todo] Hook TODO manager into project manifests"};
110 screen_.PostEvent(Event::Custom);
115 screen_.PostEvent(Event::Custom);
120 screen_.PostEvent(Event::Custom);
125 screen_.PostEvent(Event::Custom);
137 rows.push_back(text(
"No TODOs available") | dim | center);
139 for (
const auto& line : items) {
140 rows.push_back(text(line));
145 {window(text(
"📝 TODO Overlay") | bold,
146 vbox({separatorLight(),
147 vbox(rows) | frame | size(HEIGHT, LESS_THAN, 15) |
148 size(WIDTH, LESS_THAN, 80),
150 text(
"Ctrl+T to close • Enter to jump via command "
156 screen_.PostEvent(Event::Custom);
158 screen_.PostEvent(Event::Custom);
171 std::function<std::vector<std::string>()> provider) {
176 std::function<std::vector<std::string>()> provider) {
181 auto terminal = Terminal::Size();
182 if (terminal.dimx < 120) {
191 std::vector<std::string> items = {
"🔍 Hex Viewer",
"🎨 Palette Editor",
192 "📝 TODO Manager",
"🔧 ROM Tools",
193 "🎮 Graphics Tools",
"⚙️ Settings",
197 auto state = std::make_shared<MenuState>();
200 option.focused_entry = &state->selected;
201 option.on_enter = [
this, state] {
202 switch (state->selected) {
230 auto menu = Menu(&state->items, &state->selected, option);
232 return Renderer(menu, [
this, menu, state] {
234 return vbox({banner, separator(), menu->Render(), separator(),
237 text(
"↑/↓: Navigate | Enter: Select | q: Quit") | dim |
239 borderRounded | bgcolor(Color::Black);
246 return Renderer([
this] {
247 std::vector<Element> cards;
248 cards.push_back(vbox({text(
"🤖 Overview") | bold,
249 text(
"AI assistant for ROM editing"),
250 text(
"Press 'f' for fullscreen chat") | dim}) |
259 borderRounded | color(Color::GreenLight));
261 cards.push_back(vbox({text(
"⚠ No ROM loaded") | color(Color::Yellow),
262 text(
"Use Load ROM from main menu") | dim}) |
266 cards.push_back(vbox({text(
"🛠 Integrations") | bold,
267 text(
"• TODO manager status") | dim,
268 text(
"• Command palette shortcuts") | dim,
269 text(
"• Tool dispatcher metrics") | dim}) |
274 text(
"Shortcuts: f fullscreen | c toggle chat | /help "
277 borderRounded | bgcolor(Color::Black);
282 auto input_message = std::make_shared<std::string>();
283 auto input_component = Input(input_message.get(),
"Type your message...");
285 auto send_button = Button(
"Send", [
this, input_message] {
286 if (input_message->empty())
290 if (*input_message ==
"/exit") {
295 input_message->clear();
300 CatchEvent(input_component, [
this, input_message](
const Event& event) {
301 if (event == Event::Return) {
302 if (input_message->empty())
305 if (*input_message ==
"/exit") {
310 input_message->clear();
316 auto container = Container::Vertical({input_component, send_button});
318 return Renderer(container, [
this, container, input_component, send_button] {
319 return vbox({text(
"🤖 AI Chat") | bold | center, separator(),
320 text(
"Chat functionality integrated into unified layout") |
323 hbox({text(
"You: ") | bold, input_component->Render() | flex,
324 text(
" "), send_button->Render()}),
326 text(
"Commands: /exit, /clear, /help") | dim | center});
331 return Renderer([
this] {
334 color(Color::GreenLight)
335 : text(
"ROM: none") | color(Color::RedLight);
339 : text(
"Ready") | color(Color::GrayLight);
343 std::vector<Element> sections = {
345 separatorLight(), provider_status, separatorLight(),
346 command_tiles, separatorLight(), todo_tiles};
349 sections.push_back(separatorLight());
353 return vbox(sections) | borderRounded | bgcolor(Color::Black);
360 std::vector<std::string> items = {
361 "🔧 ROM Tools (press t)",
"🎨 Graphics Tools (ref gfx::export)",
362 "📝 TODO Manager (ref todo::list)",
"⚙️ Settings",
"❓ Help"};
365 auto state = std::make_shared<ToolsState>();
367 option.on_change = [
this, state] {
368 if (!state->items.empty()) {
372 auto menu = Menu(&state->items, &state->selected, option);
374 return Renderer(menu, [
this, menu, state] {
376 menu->Render(), separator(),
377 text(
"Select a tool category") | dim | center, separator(),
379 borderRounded | bgcolor(Color::Black);
384 auto offset = std::make_shared<int>(0);
385 const int lines_to_show = 20;
387 return Renderer([
this, offset, lines_to_show] {
389 return vbox({text(
"🔍 Hex Viewer") | bold | center, separator(),
390 text(
"No ROM loaded") | center | color(Color::Red),
392 text(
"Load a ROM to view hex data") | center | dim}) |
396 std::vector<Element> rows;
397 for (
int i = 0; i < lines_to_show; ++i) {
398 int current_offset = *offset + (i * 16);
404 row.push_back(text(absl::StrFormat(
"0x%08X: ", current_offset)) |
405 color(Color::Yellow));
407 for (
int j = 0; j < 16; ++j) {
409 row.push_back(text(absl::StrFormat(
412 row.push_back(text(
" "));
416 row.push_back(separator());
418 for (
int j = 0; j < 16; ++j) {
421 row.push_back(text(std::isprint(c) ? std::string(1, c) :
"."));
423 row.push_back(text(
" "));
427 rows.push_back(hbox(row));
432 return vbox({text(
"🔍 Hex Viewer") | bold | center, separator(), workflow,
433 separator(), vbox(rows) | frame | flex, separator(),
434 text(absl::StrFormat(
"Offset: 0x%08X", *offset)) |
436 separator(), text(
"↑/↓: Scroll | q: Back") | dim | center}) |
437 borderRounded | bgcolor(Color::Black);
442 return Renderer([
this] {
445 {vbox({text(
"🌈 Overview") | bold,
446 text(
"Preview palette indices and colors"),
447 text(
"Highlight sprite-specific palettes") | dim}) |
448 borderRounded | bgcolor(Color::Black),
449 vbox({text(
"🧪 Roadmap") | bold,
450 text(
"• Live recolor with undo stack"),
451 text(
"• Sprite preview viewport"),
452 text(
"• Export to .pal/.act")}) |
453 borderRounded | bgcolor(Color::Black),
454 vbox({text(
"🗒 TODO") | bold,
455 text(
"Link to command palette"),
456 text(
"Use animation timeline"),
457 text(
"Add palette history panel") | dim}) |
458 borderRounded | bgcolor(Color::Black)}),
460 text(
"Press 'q' to go back") | dim | center}) |
466 return Renderer([
this] {
467 std::vector<Element> todo_cards;
470 todo_cards.push_back(text(
"• " + item));
473 if (todo_cards.empty()) {
474 todo_cards.push_back(text(
"No TODOs yet") | dim);
479 vbox(todo_cards) | borderRounded | bgcolor(Color::Black),
482 "Press Ctrl+T anywhere to toggle the popup todo overlay.") |
485 text(
"Press 'q' to go back") | dim | center}) |
493 std::vector<std::string> items = {
494 "Apply Asar Patch — todo#123",
"Apply BPS Patch — todo#124",
495 "Extract Symbols — todo#098",
"Validate Assembly — todo#087",
496 "Generate Save File — todo#142",
"Back"};
499 auto state = std::make_shared<ToolsState>();
500 auto menu = Menu(&state->items, &state->selected);
502 return Renderer(menu, [
this, menu, state] {
503 return vbox({text(
"🔧 ROM Tools") | bold | center, separator(),
504 menu->Render(), separator(),
505 text(
"Select a ROM tool") | dim | center}) |
513 std::vector<std::string> items = {
"Palette Editor — ref gfx::export",
514 "Hex Viewer — ref rom::hex",
"Back"};
517 auto state = std::make_shared<ToolsState>();
518 auto menu = Menu(&state->items, &state->selected);
520 return Renderer(menu, [
this, menu, state] {
521 return vbox({text(
"🎨 Graphics Tools") | bold | center, separator(),
522 menu->Render(), separator(),
523 text(
"Select a graphics tool") | dim | center}) |
529 struct SettingsState {
530 int left_width_slider;
531 int right_width_slider;
532 int bottom_height_slider;
535 auto state = std::make_shared<SettingsState>();
540 auto left_width_control =
541 Slider(
"Left Panel Width: ", &state->left_width_slider, 20, 60, 1);
542 auto right_width_control =
543 Slider(
"Right Panel Width: ", &state->right_width_slider, 30, 60, 1);
544 auto bottom_height_control =
545 Slider(
"Bottom Panel Height: ", &state->bottom_height_slider, 10, 30, 1);
547 auto apply_button = Button(
"Apply Changes", [
this, state] {
551 screen_.PostEvent(Event::Custom);
554 auto reset_button = Button(
"Reset to Defaults", [
this, state] {
555 state->left_width_slider = 30;
556 state->right_width_slider = 40;
557 state->bottom_height_slider = 15;
561 screen_.PostEvent(Event::Custom);
564 auto controls = Container::Vertical(
565 {left_width_control, right_width_control, bottom_height_control,
566 Container::Horizontal({apply_button, reset_button})});
568 return Renderer(controls, [
this, controls, state, left_width_control,
569 right_width_control, bottom_height_control,
570 apply_button, reset_button] {
574 text(
"Customize the TUI layout") | center | dim,
576 hbox({text(
"Left Panel Width: ") | bold,
577 text(absl::StrFormat(
"%d", state->left_width_slider))}),
578 left_width_control->Render(),
580 hbox({text(
"Right Panel Width: ") | bold,
581 text(absl::StrFormat(
"%d", state->right_width_slider))}),
582 right_width_control->Render(),
584 hbox({text(
"Bottom Panel Height: ") | bold,
585 text(absl::StrFormat(
"%d", state->bottom_height_slider))}),
586 bottom_height_control->Render(),
588 hbox({apply_button->Render(), text(
" "), reset_button->Render()}) |
591 text(
"Panel Visibility:") | bold,
592 hbox({text(
"Chat: ") | bold,
595 text(
" "), text(
"Status: ") | bold,
600 text(
"Keyboard Shortcuts:") | bold,
601 text(
" c - Toggle chat panel") | dim,
602 text(
" s - Toggle status panel") | dim,
603 text(
" Esc/b - Back to menu") | dim,
605 text(
"Changes apply immediately") | center | dim});
610 return Renderer([
this] {
614 text(
"Unified TUI Layout - ROM Editor & AI Agent") | center | dim,
616 text(
"Global Shortcuts:") | bold | color(Color::Yellow),
617 text(
" q - Quit application"),
618 text(
" h - Show this help"),
619 text(
" m - Main menu"),
620 text(
" Esc/b - Back to previous panel"),
622 text(
"Panel Controls:") | bold | color(Color::Yellow),
623 text(
" c - Toggle chat panel"),
624 text(
" s - Toggle status panel"),
625 text(
" f - Open full chat interface"),
626 text(
" t - ROM tools"),
628 text(
"Navigation:") | bold | color(Color::Yellow),
629 text(
" ↑/↓ - Navigate menus"),
630 text(
" Enter - Select item"),
631 text(
" Tab - Switch focus"),
633 text(
"Chat Commands:") | bold | color(Color::Yellow),
634 text(
" /exit - Exit chat"),
635 text(
" /clear - Clear history"),
636 text(
" /help - Show chat help"),
638 text(
"Available Tools:") | bold | color(Color::Green),
639 text(
" • Hex Viewer - Inspect ROM data"),
640 text(
" • Palette Editor - Edit color palettes"),
641 text(
" • TODO Manager - Track tasks"),
642 text(
" • AI Chat - Natural language ROM queries"),
643 text(
" • Dungeon Tools - Room inspection & editing"),
644 text(
" • Graphics Tools - Sprite & tile editing"),
646 text(
"Press 'Esc' or 'b' to go back") | dim | center});
652 auto all_panels = Container::Tab(
659 return Renderer(all_panels, [
this, all_panels] {
661 Component left_panel;
663 case PanelType::kMainMenu:
664 left_panel = main_menu_panel_;
666 case PanelType::kHexViewer:
667 left_panel = hex_viewer_panel_;
669 case PanelType::kPaletteEditor:
670 left_panel = palette_editor_panel_;
672 case PanelType::kTodoManager:
673 left_panel = todo_manager_panel_;
675 case PanelType::kRomTools:
676 left_panel = rom_tools_panel_;
678 case PanelType::kGraphicsTools:
679 left_panel = graphics_tools_panel_;
681 case PanelType::kSettings:
682 left_panel = settings_panel_;
684 case PanelType::kHelp:
685 left_panel = help_panel_;
688 left_panel = main_menu_panel_;
693 Component right_panel;
702 hbox({left_panel->Render() | flex, separatorLight(),
703 right_panel->Render() |
709 vbox({top_section | flex, separatorLight(),
712 bgcolor(Color::Black);
720 Element content = top_section | bgcolor(Color::Black);
730 if (event == Event::Escape || event == Event::Character(
'b')) {
738 if (event == Event::Special({20})) {
743 if (event == Event::Character(
'q') ||
744 (event == Event::Character(
'q') &&
750 if (event == Event::Character(
'h')) {
755 if (event == Event::Character(
'c')) {
760 if (event == Event::Character(
's')) {
765 if (event == Event::Character(
't')) {
770 if (event == Event::Character(
'm')) {
775 if (event == Event::Character(
'f')) {
780 screen_.PostEvent(Event::Custom);
797 title =
"🎮 Main Menu";
809 title =
"🔍 Hex Viewer";
812 title =
"🎨 Palette Editor";
815 title =
"📝 TODO Manager";
818 title =
"🔧 ROM Tools";
821 title =
"🎨 Graphics Tools";
824 title =
"⚙️ Settings";
831 return text(title) | bold | center;
836 {text(absl::StrFormat(
"Panel: %s",
847 text(
"Shortcuts: Ctrl+T TODO Overlay | f Full Chat | m Main Menu") |
852 return text(
"🎮 Z3ED CLI") | bold | center;
856 return text(
"Workflow: Active") | color(Color::Green);
860 return vbox({text(
"Command Hints:") | bold,
861 text(
" Ctrl+T - Toggle TODO overlay"),
862 text(
" f - Full chat mode"), text(
" m - Main menu")});
866 return text(
"TODO Stack: Empty") | dim;
871 return text(
"No items") | center | dim;
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
const auto & vector() const
ftxui::Component unified_layout_
ftxui::Element RenderTodoStack()
ftxui::Component CreateToolsPanel()
ftxui::Component CreatePaletteEditorPanel()
ftxui::Component graphics_tools_panel_
void SwitchToolPanel(PanelType panel)
ftxui::Component CreateHelpPanel()
void SetStatusProvider(std::function< ftxui::Element()> provider)
bool todo_overlay_visible_
ftxui::Component settings_panel_
void SetLayoutConfig(const LayoutConfig &config)
std::function< bool(const ftxui::Event &) panel_event_handler_)
ftxui::Element RenderCommandHints()
UnifiedLayout(Rom *rom_context=nullptr)
std::function< ftxui::Element()> status_provider_
ftxui::Component rom_tools_panel_
ftxui::Component CreateRomToolsPanel()
ftxui::Element RenderStatusBar()
ftxui::Component hex_viewer_panel_
ftxui::Component CreateChatPanel()
ftxui::ScreenInteractive screen_
bool HandleGlobalEvents(const ftxui::Event &event)
std::unique_ptr< tui::ChatTUI > chat_tui_
ftxui::Element RenderPanelHeader(PanelType panel)
ftxui::Element RenderResponsiveGrid(const std::vector< ftxui::Element > &tiles)
void SwitchMainPanel(PanelType panel)
ftxui::Component status_panel_
ftxui::Component palette_editor_panel_
ftxui::Component chat_panel_
ftxui::Component help_panel_
ftxui::Component main_menu_panel_
void SetTodoProvider(std::function< std::vector< std::string >()> provider)
void SetRomContext(Rom *rom_context)
ftxui::Component CreateHexViewerPanel()
std::function< std::vector< std::string >()> todo_provider_
ftxui::Component CreateSettingsPanel()
ftxui::Component todo_manager_panel_
ftxui::Component todo_overlay_component_
ftxui::Element RenderWorkflowLane()
ftxui::Component CreateStatusPanel()
ftxui::Component tools_panel_
void SetCommandSummaryProvider(std::function< std::vector< std::string >()> provider)
bool HandlePanelEvents(const ftxui::Event &event)
ftxui::Component CreateUnifiedLayout()
ftxui::Component CreateGraphicsToolsPanel()
ftxui::Component CreateTodoManagerPanel()
ftxui::Component CreateMainMenuPanel()
ftxui::Element RenderAnimatedBanner()
std::function< std::vector< std::string >()> command_summary_provider_
std::function< bool(const ftxui::Event &) global_event_handler_)
PanelType active_tool_panel
std::vector< std::string > active_workflows
std::string current_rom_file
std::string current_error
PanelType active_main_panel
std::string command_palette_hint