yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
ui_coordinator.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <functional>
5#include <memory>
6#include <string>
7#include <vector>
8
9#include "absl/strings/str_format.h"
10#include "core/project.h"
11#include "app/editor/editor.h"
21#include "app/gui/core/icons.h"
23#include "app/gui/core/style.h"
25#include "imgui/imgui.h"
26#include "util/file_util.h"
27
28namespace yaze {
29namespace editor {
30
32 EditorManager* editor_manager,
33 RomFileManager& rom_manager,
34 ProjectManager& project_manager,
35 EditorRegistry& editor_registry,
36 EditorCardRegistry& card_registry,
37 SessionCoordinator& session_coordinator,
38 WindowDelegate& window_delegate,
39 ToastManager& toast_manager,
40 PopupManager& popup_manager,
41 ShortcutManager& shortcut_manager)
42 : editor_manager_(editor_manager),
43 rom_manager_(rom_manager),
44 project_manager_(project_manager),
45 editor_registry_(editor_registry),
46 card_registry_(card_registry),
47 session_coordinator_(session_coordinator),
48 window_delegate_(window_delegate),
49 toast_manager_(toast_manager),
50 popup_manager_(popup_manager),
51 shortcut_manager_(shortcut_manager) {
52
53 // Initialize welcome screen with proper callbacks
54 welcome_screen_ = std::make_unique<WelcomeScreen>();
55
56 // Wire welcome screen callbacks to EditorManager
57 welcome_screen_->SetOpenRomCallback([this]() {
58 if (editor_manager_) {
59 auto status = editor_manager_->LoadRom();
60 if (!status.ok()) {
61 toast_manager_.Show(
62 absl::StrFormat("Failed to load ROM: %s", status.message()),
63 ToastType::kError);
64 } else {
65 // Hide welcome screen on successful ROM load
66 show_welcome_screen_ = false;
67 welcome_screen_manually_closed_ = true;
68 }
69 }
70 });
71
72 welcome_screen_->SetNewProjectCallback([this]() {
73 if (editor_manager_) {
74 auto status = editor_manager_->CreateNewProject();
75 if (!status.ok()) {
76 toast_manager_.Show(
77 absl::StrFormat("Failed to create project: %s", status.message()),
78 ToastType::kError);
79 } else {
80 // Hide welcome screen on successful project creation
81 show_welcome_screen_ = false;
82 welcome_screen_manually_closed_ = true;
83 }
84 }
85 });
86
87 welcome_screen_->SetOpenProjectCallback([this](const std::string& filepath) {
88 if (editor_manager_) {
89 auto status = editor_manager_->OpenRomOrProject(filepath);
90 if (!status.ok()) {
91 toast_manager_.Show(
92 absl::StrFormat("Failed to open project: %s", status.message()),
93 ToastType::kError);
94 } else {
95 // Hide welcome screen on successful project open
96 show_welcome_screen_ = false;
97 welcome_screen_manually_closed_ = true;
98 }
99 }
100 });
101}
102
104 // Note: Theme styling is applied by ThemeManager, not here
105 // This is called from EditorManager::Update() - don't call menu bar stuff here
106
107 // Draw UI windows and dialogs
108 // Session dialogs are drawn by SessionCoordinator separately to avoid duplication
109 DrawCommandPalette(); // Ctrl+Shift+P
110 DrawGlobalSearch(); // Ctrl+Shift+K
111 DrawWorkspacePresetDialogs(); // Save/Load workspace dialogs
112 DrawLayoutPresets(); // Layout preset dialogs
113 DrawWelcomeScreen(); // Welcome screen
114 DrawProjectHelp(); // Project help
115 DrawWindowManagementUI(); // Window management
116}
117
119 auto* current_rom = editor_manager_->GetCurrentRom();
120 ImGui::SameLine((ImGui::GetWindowWidth() / 2) - 100);
121 if (current_rom && current_rom->is_loaded()) {
122 ImGui::SetNextItemWidth(ImGui::GetWindowWidth() / 6);
123 if (ImGui::BeginCombo("##ROMSelector", current_rom->short_name().c_str())) {
124 for (size_t i = 0; i < session_coordinator_.GetTotalSessionCount(); ++i) {
125 if (session_coordinator_.IsSessionClosed(i)) continue;
126
127 auto* session = static_cast<RomSession*>(session_coordinator_.GetSession(i));
128 if (!session) continue;
129
130 Rom* rom = &session->rom;
131 ImGui::PushID(static_cast<int>(i));
132 bool selected = (rom == current_rom);
133 if (ImGui::Selectable(rom->short_name().c_str(), selected)) {
135 }
136 ImGui::PopID();
137 }
138 ImGui::EndCombo();
139 }
140 // Inline status next to ROM selector
141 ImGui::SameLine();
142 ImGui::Text("Size: %.1f MB", current_rom->size() / 1048576.0f);
143
144 // Context-sensitive card control (right after ROM info)
145 ImGui::SameLine();
147 } else {
148 ImGui::Text("No ROM loaded");
149 }
150}
151
153 // Get current ROM from EditorManager (RomFileManager doesn't track "current")
154 auto* current_rom = editor_manager_->GetCurrentRom();
155
156 // Calculate version width for right alignment
157 std::string version_text = absl::StrFormat("v%s", editor_manager_->version().c_str());
158 float version_width = ImGui::CalcTextSize(version_text.c_str()).x;
159
160 // Session indicator with Material Design styling
162 ImGui::SameLine();
163 std::string session_button_text = absl::StrFormat("%s %zu", ICON_MD_TAB,
165
166 // Material Design button styling
167 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetPrimaryVec4());
168 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetPrimaryHoverVec4());
169 ImGui::PushStyleColor(ImGuiCol_ButtonActive, gui::GetPrimaryActiveVec4());
170
171 if (ImGui::SmallButton(session_button_text.c_str())) {
173 }
174
175 ImGui::PopStyleColor(3);
176
177 if (ImGui::IsItemHovered()) {
178 ImGui::SetTooltip("Switch Sessions (Ctrl+Tab)");
179 }
180 }
181
182 // ROM information display with Material Design card styling
183 ImGui::SameLine();
184 if (current_rom && current_rom->is_loaded()) {
185 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
186 std::string rom_title = current_rom->title();
187 if (current_rom->dirty()) {
188 ImGui::Text("%s %s*", ICON_MD_CIRCLE, rom_title.c_str());
189 if (ImGui::IsItemHovered()) {
190 ImGui::SetTooltip("Unsaved changes");
191 }
192 } else {
193 ImGui::Text("%s %s", ICON_MD_INSERT_DRIVE_FILE, rom_title.c_str());
194 }
195 ImGui::PopStyleColor();
196 } else {
197 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextDisabledVec4());
198 ImGui::Text("%s No ROM", ICON_MD_WARNING);
199 ImGui::PopStyleColor();
200 }
201
202 // Version info aligned to far right
203 ImGui::SameLine(ImGui::GetWindowWidth() - version_width - 15.0f);
204 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextDisabledVec4());
205 ImGui::Text("%s", version_text.c_str());
206 ImGui::PopStyleColor();
207}
208
210 // Get the currently active editor directly from EditorManager
211 // This ensures we show cards for the correct editor that has focus
212 auto* active_editor = editor_manager_->GetCurrentEditor();
213 if (!active_editor) return;
214
215 // Only show card control for card-based editors (not palette, not assembly in legacy mode, etc.)
216 if (!editor_registry_.IsCardBasedEditor(active_editor->type())) {
217 return;
218 }
219
220 // Get the category and session for the active editor
221 std::string category = editor_registry_.GetEditorCategory(active_editor->type());
222 size_t session_id = editor_manager_->GetCurrentSessionId();
223
224 // Draw compact card control in menu bar (mini dropdown for cards)
225 ImGui::SameLine();
226 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighVec4());
227 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetSurfaceContainerHighestVec4());
228
229 if (ImGui::SmallButton(absl::StrFormat("%s %s", ICON_MD_LAYERS, category.c_str()).c_str())) {
230 ImGui::OpenPopup("##CardQuickAccess");
231 }
232
233 ImGui::PopStyleColor(2);
234
235 if (ImGui::IsItemHovered()) {
236 ImGui::SetTooltip("Quick access to %s cards", category.c_str());
237 }
238
239 // Quick access popup for toggling cards
240 if (ImGui::BeginPopup("##CardQuickAccess")) {
241 auto cards = card_registry_.GetCardsInCategory(session_id, category);
242
243 for (const auto& card : cards) {
244 bool visible = card.visibility_flag ? *card.visibility_flag : false;
245 if (ImGui::MenuItem(card.display_name.c_str(), nullptr, visible)) {
246 if (visible) {
247 card_registry_.HideCard(session_id, card.card_id);
248 } else {
249 card_registry_.ShowCard(session_id, card.card_id);
250 }
251 }
252 }
253 ImGui::EndPopup();
254 }
255}
256
257// ============================================================================
258// Session UI Delegation
259// ============================================================================
260// All session-related UI is now managed by SessionCoordinator to eliminate
261// duplication. UICoordinator methods delegate to SessionCoordinator.
262
266
270
272 if (visible) {
274 } else {
276 }
277}
278
279// ============================================================================
280// Layout and Window Management UI
281// ============================================================================
282
284 // TODO: [EditorManagerRefactor] Implement full layout preset UI with save/load
285 // For now, this is accessed via Window menu items that call workspace_manager directly
286}
287
289 // ============================================================================
290 // SIMPLIFIED WELCOME SCREEN LOGIC
291 // ============================================================================
292 // Auto-show: When no ROM is loaded (unless manually closed this session)
293 // Auto-hide: When ROM is loaded
294 // Manual control: Can be opened via Help > Welcome Screen menu
295 // ============================================================================
296
297 if (!editor_manager_) {
298 LOG_ERROR("UICoordinator", "EditorManager is null - cannot check ROM state");
299 return;
300 }
301
302 if (!welcome_screen_) {
303 LOG_ERROR("UICoordinator", "WelcomeScreen object is null - cannot render");
304 return;
305 }
306
307 // Check ROM state
308 auto* current_rom = editor_manager_->GetCurrentRom();
309 bool rom_is_loaded = current_rom && current_rom->is_loaded();
310
311 // SIMPLIFIED LOGIC: Auto-show when no ROM, auto-hide when ROM loads
312 if (!rom_is_loaded && !welcome_screen_manually_closed_) {
314 }
315
316 if (rom_is_loaded && !welcome_screen_manually_closed_) {
317 show_welcome_screen_ = false;
318 }
319
320 // Don't show if flag is false
322 return;
323 }
324
325 // Reset first show flag to override ImGui ini state
326 welcome_screen_->ResetFirstShow();
327
328 // Update recent projects before showing
329 welcome_screen_->RefreshRecentProjects();
330
331 // Show the welcome screen window
332 bool is_open = true;
333 welcome_screen_->Show(&is_open);
334
335 // If user closed it via X button, respect that
336 if (!is_open) {
337 show_welcome_screen_ = false;
339 }
340
341 // If an action was taken (ROM loaded, project opened), the welcome screen will auto-hide
342 // next frame when rom_is_loaded becomes true
343}
344
346 // TODO: [EditorManagerRefactor] Implement project help dialog
347 // Show context-sensitive help based on current editor and ROM state
348}
349
352 ImGui::Begin("Save Workspace Preset", &show_save_workspace_preset_,
353 ImGuiWindowFlags_AlwaysAutoResize);
354 static char preset_name[128] = "";
355 ImGui::InputText("Name", preset_name, IM_ARRAYSIZE(preset_name));
356 if (ImGui::Button("Save", gui::kDefaultModalSize)) {
357 if (strlen(preset_name) > 0) {
361 preset_name[0] = '\0';
362 }
363 }
364 ImGui::SameLine();
365 if (ImGui::Button("Cancel", gui::kDefaultModalSize)) {
367 preset_name[0] = '\0';
368 }
369 ImGui::End();
370 }
371
373 ImGui::Begin("Load Workspace Preset", &show_load_workspace_preset_,
374 ImGuiWindowFlags_AlwaysAutoResize);
375
376 // Lazy load workspace presets when UI is accessed
378
379 if (auto* workspace_manager = editor_manager_->workspace_manager()) {
380 for (const auto& name : workspace_manager->workspace_presets()) {
381 if (ImGui::Selectable(name.c_str())) {
385 }
386 }
387 if (workspace_manager->workspace_presets().empty())
388 ImGui::Text("No presets found");
389 }
390 ImGui::End();
391 }
392}
393
395 // TODO: [EditorManagerRefactor] Implement window management dialog
396 // Provide UI for toggling window visibility, managing docking, etc.
397}
398
400 // Draw all registered popups
402}
403
404void UICoordinator::ShowPopup(const std::string& popup_name) {
405 popup_manager_.Show(popup_name.c_str());
406}
407
408void UICoordinator::HidePopup(const std::string& popup_name) {
409 popup_manager_.Hide(popup_name.c_str());
410}
411
413 // Display Settings is now a popup managed by PopupManager
414 // Delegate directly to PopupManager instead of UICoordinator
416}
417
419 if (!editor_manager_) return;
420
421 auto* current_editor = editor_manager_->GetCurrentEditor();
422 if (!current_editor) return;
423
424 std::string category = editor_registry_.GetEditorCategory(current_editor->type());
426
427 LOG_INFO("UICoordinator", "Hid all cards in category: %s", category.c_str());
428}
429
433
437
438// Helper methods for drawing operations
440 // TODO: [EditorManagerRefactor] Implement session indicator in menu bar
441}
442
444 // TODO: [EditorManagerRefactor] Implement session tabs UI
445}
446
448 // TODO: [EditorManagerRefactor] Implement session status badges
449}
450
451// Material Design component helpers
452void UICoordinator::DrawMaterialButton(const std::string& text, const std::string& icon,
453 const ImVec4& color, std::function<void()> callback,
454 bool enabled) {
455 if (!enabled) {
456 ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighestVec4());
457 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetOnSurfaceVariantVec4());
458 }
459
460 std::string button_text = absl::StrFormat("%s %s", icon.c_str(), text.c_str());
461 if (ImGui::Button(button_text.c_str())) {
462 if (enabled && callback) {
463 callback();
464 }
465 }
466
467 if (!enabled) {
468 ImGui::PopStyleColor(2);
469 }
470}
471
472// Layout and positioning helpers
473void UICoordinator::CenterWindow(const std::string& window_name) {
474 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
475}
476
477void UICoordinator::PositionWindow(const std::string& window_name, float x, float y) {
478 ImGui::SetNextWindowPos(ImVec2(x, y), ImGuiCond_Appearing);
479}
480
481void UICoordinator::SetWindowSize(const std::string& window_name, float width, float height) {
482 ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_FirstUseEver);
483}
484
485// Icon and theming helpers
487 switch (type) {
493 case EditorType::kScreen: return ICON_MD_TV;
500 default: return ICON_MD_HELP;
501 }
502}
503
505 // TODO: [EditorManagerRefactor] Map editor types to theme colors
506 // Use ThemeManager to get Material Design color names
507 return "primary";
508}
509
511 // TODO: [EditorManagerRefactor] Apply editor-specific theme overrides
512 // Use ThemeManager to push/pop style colors based on editor type
513}
514
516 if (!show_command_palette_) return;
517
518 using namespace ImGui;
519 auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
520
521 SetNextWindowPos(GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
522 SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
523
524 bool show_palette = true;
525 if (Begin(absl::StrFormat("%s Command Palette", ICON_MD_SEARCH).c_str(),
526 &show_palette, ImGuiWindowFlags_NoCollapse)) {
527
528 // Search input with focus management
529 SetNextItemWidth(-100);
530 if (IsWindowAppearing()) {
531 SetKeyboardFocusHere();
533 }
534
535 bool input_changed = InputTextWithHint(
536 "##cmd_query",
537 absl::StrFormat("%s Search commands (fuzzy matching enabled)...", ICON_MD_SEARCH).c_str(),
539
540 SameLine();
541 if (Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
542 command_palette_query_[0] = '\0';
543 input_changed = true;
545 }
546
547 Separator();
548
549 // Fuzzy filter commands with scoring
550 std::vector<std::pair<int, std::pair<std::string, std::string>>> scored_commands;
551 std::string query_lower = command_palette_query_;
552 std::transform(query_lower.begin(), query_lower.end(), query_lower.begin(), ::tolower);
553
554 for (const auto& entry : shortcut_manager_.GetShortcuts()) {
555 const auto& name = entry.first;
556 const auto& shortcut = entry.second;
557
558 std::string name_lower = name;
559 std::transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower);
560
561 int score = 0;
562 if (command_palette_query_[0] == '\0') {
563 score = 1; // Show all when no query
564 } else if (name_lower.find(query_lower) == 0) {
565 score = 1000; // Starts with
566 } else if (name_lower.find(query_lower) != std::string::npos) {
567 score = 500; // Contains
568 } else {
569 // Fuzzy match - characters in order
570 size_t text_idx = 0, query_idx = 0;
571 while (text_idx < name_lower.length() && query_idx < query_lower.length()) {
572 if (name_lower[text_idx] == query_lower[query_idx]) {
573 score += 10;
574 query_idx++;
575 }
576 text_idx++;
577 }
578 if (query_idx != query_lower.length()) score = 0;
579 }
580
581 if (score > 0) {
582 std::string shortcut_text = shortcut.keys.empty()
583 ? ""
584 : absl::StrFormat("(%s)", PrintShortcut(shortcut.keys).c_str());
585 scored_commands.push_back({score, {name, shortcut_text}});
586 }
587 }
588
589 std::sort(scored_commands.begin(), scored_commands.end(),
590 [](const auto& a, const auto& b) { return a.first > b.first; });
591
592 // Display results with categories
593 if (BeginTabBar("CommandCategories")) {
594 if (BeginTabItem(absl::StrFormat("%s All Commands", ICON_MD_LIST).c_str())) {
595 if (gui::LayoutHelpers::BeginTableWithTheming("CommandPaletteTable", 3,
596 ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp,
597 ImVec2(0, -30))) {
598
599 TableSetupColumn("Command", ImGuiTableColumnFlags_WidthStretch, 0.5f);
600 TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthStretch, 0.3f);
601 TableSetupColumn("Score", ImGuiTableColumnFlags_WidthStretch, 0.2f);
602 TableHeadersRow();
603
604 for (size_t i = 0; i < scored_commands.size(); ++i) {
605 const auto& [score, cmd_pair] = scored_commands[i];
606 const auto& [command_name, shortcut_text] = cmd_pair;
607
608 TableNextRow();
609 TableNextColumn();
610
611 PushID(static_cast<int>(i));
612 bool is_selected = (static_cast<int>(i) == command_palette_selected_idx_);
613 if (Selectable(command_name.c_str(), is_selected,
614 ImGuiSelectableFlags_SpanAllColumns)) {
616 const auto& shortcuts = shortcut_manager_.GetShortcuts();
617 auto it = shortcuts.find(command_name);
618 if (it != shortcuts.end() && it->second.callback) {
619 it->second.callback();
620 show_command_palette_ = false;
621 }
622 }
623 PopID();
624
625 TableNextColumn();
626 PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_secondary));
627 Text("%s", shortcut_text.c_str());
628 PopStyleColor();
629
630 TableNextColumn();
631 if (score > 0) {
632 PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
633 Text("%d", score);
634 PopStyleColor();
635 }
636 }
637
639 }
640 EndTabItem();
641 }
642
643 if (BeginTabItem(absl::StrFormat("%s Recent", ICON_MD_HISTORY).c_str())) {
644 Text("Recent commands coming soon...");
645 EndTabItem();
646 }
647
648 if (BeginTabItem(absl::StrFormat("%s Frequent", ICON_MD_STAR).c_str())) {
649 Text("Frequent commands coming soon...");
650 EndTabItem();
651 }
652
653 EndTabBar();
654 }
655
656 // Status bar with tips
657 Separator();
658 Text("%s %zu commands | Score: fuzzy match", ICON_MD_INFO, scored_commands.size());
659 SameLine();
660 PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
661 Text("| ↑↓=Navigate | Enter=Execute | Esc=Close");
662 PopStyleColor();
663 }
664 End();
665
666 // Update visibility state
667 if (!show_palette) {
668 show_command_palette_ = false;
669 }
670}
671
673 if (!show_global_search_) return;
674
675 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
676 ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
677 ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
678
679 bool show_search = true;
680 if (ImGui::Begin(
681 absl::StrFormat("%s Global Search", ICON_MD_MANAGE_SEARCH).c_str(),
682 &show_search, ImGuiWindowFlags_NoCollapse)) {
683
684 // Enhanced search input with focus management
685 ImGui::SetNextItemWidth(-100);
686 if (ImGui::IsWindowAppearing()) {
687 ImGui::SetKeyboardFocusHere();
688 }
689
690 bool input_changed = ImGui::InputTextWithHint(
691 "##global_query",
692 absl::StrFormat("%s Search everything...", ICON_MD_SEARCH).c_str(),
694
695 ImGui::SameLine();
696 if (ImGui::Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
697 global_search_query_[0] = '\0';
698 input_changed = true;
699 }
700
701 ImGui::Separator();
702
703 // Tabbed search results for better organization
704 if (ImGui::BeginTabBar("SearchResultTabs")) {
705
706 // Recent Files Tab
707 if (ImGui::BeginTabItem(
708 absl::StrFormat("%s Recent Files", ICON_MD_HISTORY).c_str())) {
710 auto recent_files = manager.GetRecentFiles();
711
712 if (ImGui::BeginTable("RecentFilesTable", 3,
713 ImGuiTableFlags_ScrollY |
714 ImGuiTableFlags_RowBg |
715 ImGuiTableFlags_SizingStretchProp)) {
716
717 ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch,
718 0.6f);
719 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed,
720 80.0f);
721 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed,
722 100.0f);
723 ImGui::TableHeadersRow();
724
725 for (const auto& file : recent_files) {
726 if (global_search_query_[0] != '\0' && file.find(global_search_query_) == std::string::npos)
727 continue;
728
729 ImGui::TableNextRow();
730 ImGui::TableNextColumn();
731 ImGui::Text("%s", util::GetFileName(file).c_str());
732
733 ImGui::TableNextColumn();
734 std::string ext = util::GetFileExtension(file);
735 if (ext == "sfc" || ext == "smc") {
736 ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s ROM",
738 } else if (ext == "yaze") {
739 ImGui::TextColored(ImVec4(0.2f, 0.6f, 0.8f, 1.0f), "%s Project",
741 } else {
742 ImGui::Text("%s File", ICON_MD_DESCRIPTION);
743 }
744
745 ImGui::TableNextColumn();
746 ImGui::PushID(file.c_str());
747 if (ImGui::Button("Open")) {
748 auto status = editor_manager_->OpenRomOrProject(file);
749 if (!status.ok()) {
750 toast_manager_.Show(absl::StrCat("Failed to open: ", status.message()), ToastType::kError);
751 }
753 }
754 ImGui::PopID();
755 }
756
757 ImGui::EndTable();
758 }
759 ImGui::EndTabItem();
760 }
761
762 // Labels Tab (only if ROM is loaded)
763 auto* current_rom = editor_manager_->GetCurrentRom();
764 if (current_rom && current_rom->resource_label()) {
765 if (ImGui::BeginTabItem(
766 absl::StrFormat("%s Labels", ICON_MD_LABEL).c_str())) {
767 auto& labels = current_rom->resource_label()->labels_;
768
769 if (ImGui::BeginTable("LabelsTable", 3,
770 ImGuiTableFlags_ScrollY |
771 ImGuiTableFlags_RowBg |
772 ImGuiTableFlags_SizingStretchProp)) {
773
774 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed,
775 100.0f);
776 ImGui::TableSetupColumn("Label",
777 ImGuiTableColumnFlags_WidthStretch, 0.4f);
778 ImGui::TableSetupColumn("Value",
779 ImGuiTableColumnFlags_WidthStretch, 0.6f);
780 ImGui::TableHeadersRow();
781
782 for (const auto& type_pair : labels) {
783 for (const auto& kv : type_pair.second) {
784 if (global_search_query_[0] != '\0' &&
785 kv.first.find(global_search_query_) == std::string::npos &&
786 kv.second.find(global_search_query_) == std::string::npos)
787 continue;
788
789 ImGui::TableNextRow();
790 ImGui::TableNextColumn();
791 ImGui::Text("%s", type_pair.first.c_str());
792
793 ImGui::TableNextColumn();
794 if (ImGui::Selectable(kv.first.c_str(), false,
795 ImGuiSelectableFlags_SpanAllColumns)) {
796 // Future: navigate to related editor/location
797 }
798
799 ImGui::TableNextColumn();
800 ImGui::TextDisabled("%s", kv.second.c_str());
801 }
802 }
803
804 ImGui::EndTable();
805 }
806 ImGui::EndTabItem();
807 }
808 }
809
810 // Sessions Tab
812 if (ImGui::BeginTabItem(
813 absl::StrFormat("%s Sessions", ICON_MD_TAB).c_str())) {
814 ImGui::Text("Search and switch between active sessions:");
815
816 for (size_t i = 0; i < session_coordinator_.GetTotalSessionCount(); ++i) {
817 std::string session_info = session_coordinator_.GetSessionDisplayName(i);
818 if (session_info == "[CLOSED SESSION]")
819 continue;
820
821 if (global_search_query_[0] != '\0' &&
822 session_info.find(global_search_query_) == std::string::npos)
823 continue;
824
825 bool is_current = (i == session_coordinator_.GetActiveSessionIndex());
826 if (is_current) {
827 ImGui::PushStyleColor(ImGuiCol_Text,
828 ImVec4(0.2f, 0.8f, 0.2f, 1.0f));
829 }
830
831 if (ImGui::Selectable(absl::StrFormat("%s %s %s", ICON_MD_TAB,
832 session_info.c_str(),
833 is_current ? "(Current)" : "")
834 .c_str())) {
835 if (!is_current) {
838 }
839 }
840
841 if (is_current) {
842 ImGui::PopStyleColor();
843 }
844 }
845 ImGui::EndTabItem();
846 }
847 }
848
849 ImGui::EndTabBar();
850 }
851
852 // Status bar
853 ImGui::Separator();
854 ImGui::Text("%s Global search across all YAZE data", ICON_MD_INFO);
855 }
856 ImGui::End();
857
858 // Update visibility state
859 if (!show_search) {
861 }
862}
863
864} // namespace editor
865} // namespace yaze
866
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:74
auto short_name() const
Definition rom.h:213
Central registry for all editor cards with session awareness and dependency injection.
bool HideCard(size_t session_id, const std::string &base_card_id)
Hide a card programmatically.
std::vector< CardInfo > GetCardsInCategory(size_t session_id, const std::string &category) const
Get cards in a specific category for a session.
void HideAllCardsInCategory(size_t session_id, const std::string &category)
Hide all cards in a category for a session.
bool ShowCard(size_t session_id, const std::string &base_card_id)
Show a card programmatically.
The EditorManager controls the main editor window and manages the various editor classes.
void SaveWorkspacePreset(const std::string &name)
void SwitchToSession(size_t index)
WorkspaceManager * workspace_manager()
void LoadWorkspacePreset(const std::string &name)
absl::Status CreateNewProject(const std::string &template_name="Basic ROM Hack")
auto GetCurrentEditor() const -> Editor *
absl::Status LoadRom()
Load a ROM file into a new or existing session.
size_t GetCurrentSessionId() const
auto GetCurrentRom() const -> Rom *
absl::Status OpenRomOrProject(const std::string &filename)
Manages editor types, categories, and lifecycle.
static bool IsCardBasedEditor(EditorType type)
static std::string GetEditorCategory(EditorType type)
void Show(const char *name)
void Hide(const char *name)
Handles all project file operations.
Handles all ROM file I/O operations.
High-level orchestrator for multi-session UI.
void * GetSession(size_t index) const
std::string GetSessionDisplayName(size_t index) const
bool IsSessionClosed(size_t index) const
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
ShortcutManager & shortcut_manager_
void DrawMaterialButton(const std::string &text, const std::string &icon, const ImVec4 &color, std::function< void()> callback, bool enabled=true)
void SetSessionSwitcherVisible(bool visible)
void SetGlobalSearchVisible(bool visible)
void HidePopup(const std::string &popup_name)
SessionCoordinator & session_coordinator_
std::string GetColorForEditor(EditorType type) const
EditorCardRegistry & card_registry_
UICoordinator(EditorManager *editor_manager, RomFileManager &rom_manager, ProjectManager &project_manager, EditorRegistry &editor_registry, EditorCardRegistry &card_registry, SessionCoordinator &session_coordinator, WindowDelegate &window_delegate, ToastManager &toast_manager, PopupManager &popup_manager, ShortcutManager &shortcut_manager)
std::string GetIconForEditor(EditorType type) const
WindowDelegate & window_delegate_
void ShowPopup(const std::string &popup_name)
void PositionWindow(const std::string &window_name, float x, float y)
void SetWindowSize(const std::string &window_name, float width, float height)
void ApplyEditorTheme(EditorType type)
std::unique_ptr< WelcomeScreen > welcome_screen_
EditorRegistry & editor_registry_
void CenterWindow(const std::string &window_name)
Low-level window operations with minimal dependencies.
static void EndTableWithTheming()
static bool BeginTableWithTheming(const char *str_id, int columns, ImGuiTableFlags flags=0, const ImVec2 &outer_size=ImVec2(0, 0), float inner_width=0.0f)
static ThemeManager & Get()
const EnhancedTheme & GetCurrentTheme() const
static RecentFilesManager & GetInstance()
Definition project.h:244
#define ICON_MD_INSERT_DRIVE_FILE
Definition icons.h:997
#define ICON_MD_SETTINGS
Definition icons.h:1697
#define ICON_MD_INFO
Definition icons.h:991
#define ICON_MD_WARNING
Definition icons.h:2121
#define ICON_MD_SEARCH
Definition icons.h:1671
#define ICON_MD_DATA_ARRAY
Definition icons.h:517
#define ICON_MD_STAR
Definition icons.h:1846
#define ICON_MD_PLAY_ARROW
Definition icons.h:1477
#define ICON_MD_CIRCLE
Definition icons.h:409
#define ICON_MD_MAP
Definition icons.h:1171
#define ICON_MD_CODE
Definition icons.h:432
#define ICON_MD_LABEL
Definition icons.h:1051
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2074
#define ICON_MD_CHAT_BUBBLE
Definition icons.h:393
#define ICON_MD_CASTLE
Definition icons.h:378
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1262
#define ICON_MD_LIST
Definition icons.h:1092
#define ICON_MD_MANAGE_SEARCH
Definition icons.h:1170
#define ICON_MD_LAYERS
Definition icons.h:1066
#define ICON_MD_IMAGE
Definition icons.h:980
#define ICON_MD_CLEAR
Definition icons.h:414
#define ICON_MD_DESCRIPTION
Definition icons.h:537
#define ICON_MD_TAB
Definition icons.h:1928
#define ICON_MD_FOLDER
Definition icons.h:807
#define ICON_MD_PALETTE
Definition icons.h:1368
#define ICON_MD_TV
Definition icons.h:2030
#define ICON_MD_TOYS
Definition icons.h:2000
#define ICON_MD_HELP
Definition icons.h:931
#define ICON_MD_HISTORY
Definition icons.h:944
#define LOG_ERROR(category, format,...)
Definition log.h:110
#define LOG_INFO(category, format,...)
Definition log.h:106
Definition input.cc:20
constexpr const char * kDisplaySettings
std::string PrintShortcut(const std::vector< ImGuiKey > &keys)
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:21
ImVec4 GetSurfaceContainerHighestVec4()
ImVec4 GetPrimaryActiveVec4()
ImVec4 GetPrimaryVec4()
ImVec4 GetTextDisabledVec4()
ImVec4 GetTextSecondaryVec4()
ImVec4 GetSurfaceContainerHighVec4()
constexpr ImVec2 kDefaultModalSize
Definition input.h:21
ImVec4 GetPrimaryHoverVec4()
ImVec4 GetOnSurfaceVariantVec4()
std::string GetFileName(const std::string &filename)
Gets the filename from a full path.
Definition file_util.cc:19
std::string GetFileExtension(const std::string &filename)
Gets the file extension from a filename.
Definition file_util.cc:15
Main namespace for the application.
Definition controller.cc:20
Represents a single session, containing a ROM and its associated editors.