yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
session_coordinator.cc
Go to the documentation of this file.
2#include <absl/status/status.h>
3#include <absl/status/statusor.h>
4
5#include <algorithm>
6#include <cstdint>
7#include <cstdio>
8#include <cstring>
9#include <filesystem>
10#include <memory>
11#include <stdexcept>
12#include <string>
13#include <utility>
14
15#include "absl/strings/str_format.h"
21#include "app/gui/core/icons.h"
26#include "core/color.h"
27#include "editor/editor.h"
30#include "imgui/imgui.h"
31#include "util/log.h"
32#include "zelda3/game_data.h"
33
34namespace yaze {
35namespace editor {
36
38 ToastManager* toast_manager,
39 UserSettings* user_settings)
40 : panel_manager_(panel_manager),
41 toast_manager_(toast_manager),
42 user_settings_(user_settings) {}
43
45 RomSession* session) {
46 // Publish event to EventBus
47 if (event_bus_) {
48 // Track previous index for the event (before we update active_session_index_)
49 size_t old_index = active_session_index_;
51 SessionSwitchedEvent::Create(old_index, index, session));
52 }
53}
54
56 RomSession* session) {
57 // Publish event to EventBus
58 if (event_bus_) {
60 }
61}
62
64 // Publish event to EventBus
65 if (event_bus_) {
67 }
68}
69
71 RomSession* session) {
72 // Publish event to EventBus
73 if (event_bus_ && session) {
75 RomLoadedEvent::Create(&session->rom, session->filepath, index));
76 }
77}
78
82 return;
83 }
84
85 // Create new empty session
86 sessions_.push_back(std::make_unique<RomSession>());
88
89 // Set as active session
91
92 // Configure the new session
93 if (editor_manager_) {
94 auto& session = sessions_.back();
95 editor_manager_->ConfigureSession(session.get());
96 }
97
98 LOG_INFO("SessionCoordinator", "Created new session %zu (total: %zu)",
100
101 // Notify observers
103
104 ShowSessionOperationResult("Create Session", true);
105}
106
108 if (sessions_.empty())
109 return;
110
113 return;
114 }
115
116 // Create new empty session (cannot actually duplicate due to non-movable
117 // editors)
118 // TODO: Implement proper duplication when editors become movable
119 sessions_.push_back(std::make_unique<RomSession>());
121
122 // Set as active session
123 active_session_index_ = sessions_.size() - 1;
124
125 // Configure the new session
126 if (editor_manager_) {
127 auto& session = sessions_.back();
128 editor_manager_->ConfigureSession(session.get());
129 }
130
131 LOG_INFO("SessionCoordinator", "Duplicated session %zu (total: %zu)",
133
134 // Notify observers
136
137 ShowSessionOperationResult("Duplicate Session", true);
138}
139
143
145 if (!IsValidSessionIndex(index))
146 return;
147
149 // Don't allow closing the last session
150 if (toast_manager_) {
151 toast_manager_->Show("Cannot close the last session",
153 }
154 return;
155 }
156
157 // Unregister cards for this session
158 if (panel_manager_) {
160 }
161
162 // Notify observers before removal
163 NotifySessionClosed(index);
164
165 // Remove session (safe now with unique_ptr!)
166 sessions_.erase(sessions_.begin() + index);
168
169 // Adjust active session index
170 if (active_session_index_ >= index && active_session_index_ > 0) {
172 }
173
174 LOG_INFO("SessionCoordinator", "Closed session %zu (total: %zu)", index,
176
177 ShowSessionOperationResult("Close Session", true);
178}
179
181 CloseSession(index);
182}
183
185 if (!IsValidSessionIndex(index))
186 return;
187
188 size_t old_index = active_session_index_;
189 active_session_index_ = index;
190
191 if (panel_manager_) {
193 }
194
195 // Only notify if actually switching to a different session
196 if (old_index != index) {
197 NotifySessionSwitched(index, sessions_[index].get());
198 }
199}
200
202 SwitchToSession(index);
203}
204
208
211 return nullptr;
212 }
213 return sessions_[active_session_index_].get();
214}
215
219
221 auto* session = GetActiveRomSession();
222 return session ? &session->rom : nullptr;
223}
224
226 auto* session = GetActiveRomSession();
227 return session ? &session->game_data : nullptr;
228}
229
231 auto* session = GetActiveRomSession();
232 return session ? &session->editors : nullptr;
233}
234
235void* SessionCoordinator::GetSession(size_t index) const {
236 if (!IsValidSessionIndex(index)) {
237 return nullptr;
238 }
239 return sessions_[index].get();
240}
241
243 return session_count_ > 1;
244}
245
249
251 const std::string& filepath) const {
252 if (filepath.empty())
253 return false;
254
255 for (const auto& session : sessions_) {
256 if (session->filepath == filepath) {
257 return true;
258 }
259 }
260 return false;
261}
262
264 if (sessions_.empty())
265 return;
266
268 return;
269
270 ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver);
271 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
272 ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
273
274 if (!ImGui::Begin("Session Switcher", &show_session_switcher_)) {
275 ImGui::End();
276 return;
277 }
278
279 ImGui::Text("%s Active Sessions (%zu)", ICON_MD_TAB, session_count_);
280 ImGui::Separator();
281
282 for (size_t i = 0; i < sessions_.size(); ++i) {
283 bool is_active = (i == active_session_index_);
284
285 ImGui::PushID(static_cast<int>(i));
286
287 // Session tab
288 if (ImGui::Selectable(GetSessionDisplayName(i).c_str(), is_active)) {
290 }
291
292 // Right-click context menu
293 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
294 ImGui::OpenPopup("SessionContextMenu");
295 }
296
297 if (ImGui::BeginPopup("SessionContextMenu")) {
299 ImGui::EndPopup();
300 }
301
302 ImGui::PopID();
303 }
304
305 ImGui::Separator();
306
307 // Action buttons
308 if (ImGui::Button(absl::StrFormat("%s New Session", ICON_MD_ADD).c_str())) {
310 }
311
312 ImGui::SameLine();
313 if (ImGui::Button(
314 absl::StrFormat("%s Duplicate", ICON_MD_CONTENT_COPY).c_str())) {
316 }
317
318 ImGui::SameLine();
319 if (HasMultipleSessions() &&
320 ImGui::Button(absl::StrFormat("%s Close", ICON_MD_CLOSE).c_str())) {
322 }
323
324 ImGui::End();
325}
326
328 if (sessions_.empty())
329 return;
330
332 return;
333
334 ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_FirstUseEver);
335 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
336 ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
337
338 if (!ImGui::Begin("Session Manager", &show_session_manager_)) {
339 ImGui::End();
340 return;
341 }
342
343 // Session statistics
344 ImGui::Text("%s Session Statistics", ICON_MD_ANALYTICS);
345 ImGui::Separator();
346
347 ImGui::Text("Total Sessions: %zu", GetTotalSessionCount());
348 ImGui::Text("Loaded Sessions: %zu", GetLoadedSessionCount());
349 ImGui::Text("Empty Sessions: %zu", GetEmptySessionCount());
350
351 ImGui::Spacing();
352
353 // Session list
354 if (ImGui::BeginTable("SessionTable", 4,
355 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
356 ImGuiTableFlags_Resizable)) {
357 ImGui::TableSetupColumn("Session", ImGuiTableColumnFlags_WidthStretch,
358 0.3f);
359 ImGui::TableSetupColumn("ROM File", ImGuiTableColumnFlags_WidthStretch,
360 0.4f);
361 ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 0.2f);
362 ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed,
363 120.0f);
364 ImGui::TableHeadersRow();
365
366 for (size_t i = 0; i < sessions_.size(); ++i) {
367 const auto& session = sessions_[i];
368 bool is_active = (i == active_session_index_);
369
370 ImGui::PushID(static_cast<int>(i));
371
372 ImGui::TableNextRow();
373
374 // Session name
375 ImGui::TableNextColumn();
376 if (is_active) {
377 ImGui::TextColored(gui::GetSuccessColor(), "%s %s",
379 GetSessionDisplayName(i).c_str());
380 } else {
381 ImGui::Text("%s %s", ICON_MD_RADIO_BUTTON_UNCHECKED,
382 GetSessionDisplayName(i).c_str());
383 }
384
385 // ROM file
386 ImGui::TableNextColumn();
387 if (session->rom.is_loaded()) {
388 ImGui::Text("%s", session->filepath.c_str());
389 } else {
390 ImGui::TextDisabled("(No ROM loaded)");
391 }
392
393 // Status
394 ImGui::TableNextColumn();
395 if (session->rom.is_loaded()) {
396 ImGui::TextColored(gui::GetSuccessColor(), "Loaded");
397 } else {
398 ImGui::TextColored(gui::GetWarningColor(), "Empty");
399 }
400
401 // Actions
402 ImGui::TableNextColumn();
403 if (!is_active && ImGui::SmallButton("Switch")) {
405 }
406
407 ImGui::SameLine();
408 if (HasMultipleSessions() && ImGui::SmallButton("Close")) {
409 CloseSession(i);
410 }
411
412 ImGui::PopID();
413 }
414
415 ImGui::EndTable();
416 }
417
418 ImGui::End();
419}
420
423 return;
424
425 ImGui::SetNextWindowSize(ImVec2(300, 150), ImGuiCond_Always);
426 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
427 ImGuiCond_Always, ImVec2(0.5f, 0.5f));
428
429 if (!ImGui::Begin("Rename Session", &show_session_rename_dialog_)) {
430 ImGui::End();
431 return;
432 }
433
434 ImGui::Text("Rename session %zu:", session_to_rename_);
435 ImGui::InputText("Name", session_rename_buffer_,
436 sizeof(session_rename_buffer_));
437
438 ImGui::Spacing();
439
440 if (ImGui::Button("OK")) {
443 session_rename_buffer_[0] = '\0';
444 }
445
446 ImGui::SameLine();
447 if (ImGui::Button("Cancel")) {
449 session_rename_buffer_[0] = '\0';
450 }
451
452 ImGui::End();
453}
454
456 if (sessions_.empty())
457 return;
458
459 if (gui::BeginThemedTabBar("SessionTabs")) {
460 for (size_t i = 0; i < sessions_.size(); ++i) {
461 bool is_active = (i == active_session_index_);
462 const auto& session = sessions_[i];
463
464 std::string tab_name = GetSessionDisplayName(i);
465 if (session->rom.is_loaded()) {
466 tab_name += " ";
467 tab_name += ICON_MD_CHECK_CIRCLE;
468 }
469
470 if (ImGui::BeginTabItem(tab_name.c_str())) {
471 if (!is_active) {
473 }
474 ImGui::EndTabItem();
475 }
476
477 // Right-click context menu
478 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
479 ImGui::OpenPopup(absl::StrFormat("SessionTabContext_%zu", i).c_str());
480 }
481
482 if (ImGui::BeginPopup(
483 absl::StrFormat("SessionTabContext_%zu", i).c_str())) {
485 ImGui::EndPopup();
486 }
487 }
489 }
490}
491
493 if (!HasMultipleSessions())
494 return;
495
496 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
497 ImVec4 accent_color = ConvertColorToImVec4(theme.accent);
498
499 {
500 gui::StyleColorGuard accent_guard(ImGuiCol_Text, accent_color);
501 ImGui::Text("%s Session %zu", ICON_MD_TAB, active_session_index_);
502 }
503
504 if (ImGui::IsItemHovered()) {
505 ImGui::SetTooltip("Active Session: %s\nClick to open session switcher",
507 }
508
509 if (ImGui::IsItemClicked()) {
511 }
512}
513
514std::string SessionCoordinator::GetSessionDisplayName(size_t index) const {
515 if (!IsValidSessionIndex(index)) {
516 return "Invalid Session";
517 }
518
519 const auto& session = sessions_[index];
520
521 if (!session->custom_name.empty()) {
522 return session->custom_name;
523 }
524
525 if (session->rom.is_loaded()) {
526 return absl::StrFormat(
527 "Session %zu (%s)", index,
528 std::filesystem::path(session->filepath).stem().string());
529 }
530
531 return absl::StrFormat("Session %zu (Empty)", index);
532}
533
537
539 const std::string& new_name) {
540 if (!IsValidSessionIndex(index) || new_name.empty())
541 return;
542
543 sessions_[index]->custom_name = new_name;
544 LOG_INFO("SessionCoordinator", "Renamed session %zu to '%s'", index,
545 new_name.c_str());
546}
547
549 const std::string& editor_name, size_t session_index) const {
550 if (sessions_.size() <= 1) {
551 // Single session - use simple name
552 return editor_name;
553 }
554
555 if (session_index >= sessions_.size()) {
556 return editor_name;
557 }
558
559 // Multi-session - include session identifier
560 const auto& session = sessions_[session_index];
561 std::string session_name = session->custom_name.empty()
562 ? session->rom.title()
563 : session->custom_name;
564
565 // Truncate long session names
566 if (session_name.length() > 20) {
567 session_name = session_name.substr(0, 17) + "...";
568 }
569
570 return absl::StrFormat("%s - %s##session_%zu", editor_name, session_name,
571 session_index);
572}
573
575 SwitchToSession(index);
576}
577
581
582// Panel coordination across sessions
588
594
595void SessionCoordinator::ShowPanelsInCategory(const std::string& category) {
596 if (panel_manager_) {
598 }
599}
600
601void SessionCoordinator::HidePanelsInCategory(const std::string& category) {
602 if (panel_manager_) {
604 }
605}
606
608 return index < sessions_.size();
609}
610
612 if (sessions_.empty())
613 return;
614
615 size_t original_session_idx = active_session_index_;
616
617 for (size_t session_idx = 0; session_idx < sessions_.size(); ++session_idx) {
618 auto& session = sessions_[session_idx];
619 if (!session->rom.is_loaded())
620 continue; // Skip sessions with invalid ROMs
621
622 // Switch context
623 SwitchToSession(session_idx);
624
625 for (auto editor : session->editors.active_editors_) {
626 if (*editor->active()) {
627 if (editor->type() == EditorType::kOverworld) {
628 auto& overworld_editor = static_cast<OverworldEditor&>(*editor);
629 if (overworld_editor.jump_to_tab() != -1) {
630 // Set the dungeon editor to the jump to tab
631 session->editors.GetDungeonEditor()->add_room(
632 overworld_editor.jump_to_tab());
633 overworld_editor.jump_to_tab_ = -1;
634 }
635 }
636
637 // CARD-BASED EDITORS: Don't wrap in Begin/End, they manage own windows
638 bool is_card_based_editor =
639 EditorManager::IsPanelBasedEditor(editor->type());
640
641 if (is_card_based_editor) {
642 // Panel-based editors create their own top-level windows
643 // No parent wrapper needed - this allows independent docking
644 if (editor_manager_) {
646 }
647
648 absl::Status status = editor->Update();
649
650 // Route editor errors to toast manager
651 if (!status.ok() && toast_manager_) {
652 std::string editor_name =
653 kEditorNames[static_cast<int>(editor->type())];
655 absl::StrFormat("%s Error: %s", editor_name, status.message()),
656 ToastType::kError, 8.0f);
657 }
658
659 } else {
660 // TRADITIONAL EDITORS: Wrap in Begin/End
661 std::string window_title = GenerateUniqueEditorTitle(
662 kEditorNames[static_cast<int>(editor->type())], session_idx);
663
664 // Set window to maximize on first open
665 ImGui::SetNextWindowSize(ImGui::GetMainViewport()->WorkSize,
666 ImGuiCond_FirstUseEver);
667 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->WorkPos,
668 ImGuiCond_FirstUseEver);
669
670 if (ImGui::Begin(window_title.c_str(), editor->active(),
671 ImGuiWindowFlags_None)) { // Allow full docking
672 // Temporarily switch context for this editor's update
673 // (Already switched via SwitchToSession)
674 if (editor_manager_) {
676 }
677
678 absl::Status status = editor->Update();
679
680 // Route editor errors to toast manager
681 if (!status.ok() && toast_manager_) {
682 std::string editor_name =
683 kEditorNames[static_cast<int>(editor->type())];
684 toast_manager_->Show(absl::StrFormat("%s Error: %s", editor_name,
685 status.message()),
686 ToastType::kError, 8.0f);
687 }
688 }
689 ImGui::End();
690 }
691 }
692 }
693 }
694
695 // Restore original session context
696 SwitchToSession(original_session_idx);
697}
698
699bool SessionCoordinator::IsSessionActive(size_t index) const {
700 return index == active_session_index_;
701}
702
703bool SessionCoordinator::IsSessionLoaded(size_t index) const {
704 return IsValidSessionIndex(index) && sessions_[index]->rom.is_loaded();
705}
706
710
712 size_t count = 0;
713 for (const auto& session : sessions_) {
714 if (session->rom.is_loaded()) {
715 count++;
716 }
717 }
718 return count;
719}
720
724
725absl::Status SessionCoordinator::LoadRomIntoSession(const std::string& filename,
726 size_t session_index) {
727 if (filename.empty()) {
728 return absl::InvalidArgumentError("Invalid parameters");
729 }
730
731 size_t target_index =
732 (session_index == SIZE_MAX) ? active_session_index_ : session_index;
733 if (!IsValidSessionIndex(target_index)) {
734 return absl::InvalidArgumentError("Invalid session index");
735 }
736
737 // TODO: Implement actual ROM loading
738 LOG_INFO("SessionCoordinator", "LoadRomIntoSession: %s -> session %zu",
739 filename.c_str(), target_index);
740
741 return absl::OkStatus();
742}
743
745 const std::string& filename) {
747 return absl::FailedPreconditionError("No active session");
748 }
749
750 // TODO: Implement actual ROM saving
751 LOG_INFO("SessionCoordinator", "SaveActiveSession: session %zu",
753
754 return absl::OkStatus();
755}
756
757absl::Status SessionCoordinator::SaveSessionAs(size_t session_index,
758 const std::string& filename) {
759 if (!IsValidSessionIndex(session_index) || filename.empty()) {
760 return absl::InvalidArgumentError("Invalid parameters");
761 }
762
763 // TODO: Implement actual ROM saving
764 LOG_INFO("SessionCoordinator", "SaveSessionAs: session %zu -> %s",
765 session_index, filename.c_str());
766
767 return absl::OkStatus();
768}
769
771 Rom&& rom, const std::string& filepath) {
772 size_t new_session_id = sessions_.size();
773 sessions_.push_back(std::make_unique<RomSession>(
774 std::move(rom), user_settings_, new_session_id, editor_registry_));
775 auto& session = sessions_.back();
776 session->filepath = filepath;
777
779 SwitchToSession(new_session_id);
780
781 // Notify observers
782 NotifySessionCreated(new_session_id, session.get());
783 NotifySessionRomLoaded(new_session_id, session.get());
784
785 return session.get();
786}
787
789 // Mark empty sessions as closed (except keep at least one)
790 size_t loaded_count = 0;
791 for (const auto& session : sessions_) {
792 if (session->rom.is_loaded()) {
793 loaded_count++;
794 }
795 }
796
797 if (loaded_count > 0) {
798 for (auto it = sessions_.begin(); it != sessions_.end();) {
799 if (!(*it)->rom.is_loaded() && sessions_.size() > 1) {
800 it = sessions_.erase(it);
801 } else {
802 ++it;
803 }
804 }
805 }
806
808 LOG_INFO("SessionCoordinator", "Cleaned up closed sessions (remaining: %zu)",
810}
811
813 if (sessions_.empty())
814 return;
815
816 // Unregister all session cards
817 if (panel_manager_) {
818 for (size_t i = 0; i < sessions_.size(); ++i) {
820 }
821 }
822
823 sessions_.clear();
826
827 LOG_INFO("SessionCoordinator", "Cleared all sessions");
828}
829
831 if (sessions_.empty())
832 return;
833
834 size_t next_index = (active_session_index_ + 1) % sessions_.size();
835 SwitchToSession(next_index);
836}
837
839 if (sessions_.empty())
840 return;
841
842 size_t prev_index = (active_session_index_ == 0) ? sessions_.size() - 1
844 SwitchToSession(prev_index);
845}
846
848 if (sessions_.empty())
849 return;
851}
852
854 if (sessions_.empty())
855 return;
856 SwitchToSession(sessions_.size() - 1);
857}
858
860 if (!sessions_.empty() && active_session_index_ >= sessions_.size()) {
861 active_session_index_ = sessions_.size() - 1;
862 }
863}
864
866 if (!IsValidSessionIndex(index)) {
867 throw std::out_of_range(
868 absl::StrFormat("Invalid session index: %zu", index));
869 }
870}
871
873 const std::string& base_name) const {
874 if (sessions_.empty())
875 return base_name;
876
877 std::string name = base_name;
878 int counter = 1;
879
880 while (true) {
881 bool found = false;
882 for (const auto& session : sessions_) {
883 if (session->custom_name == name) {
884 found = true;
885 break;
886 }
887 }
888
889 if (!found)
890 break;
891
892 name = absl::StrFormat("%s %d", base_name, counter++);
893 }
894
895 return name;
896}
897
899 if (toast_manager_) {
901 absl::StrFormat("Maximum %zu sessions allowed", kMaxSessions),
903 }
904}
905
907 const std::string& operation, bool success) {
908 if (toast_manager_) {
909 std::string message =
910 absl::StrFormat("%s %s", operation, success ? "succeeded" : "failed");
912 toast_manager_->Show(message, type);
913 }
914}
915
916void SessionCoordinator::DrawSessionTab(size_t index, bool is_active) {
917 if (index >= sessions_.size())
918 return;
919
920 const auto& session = sessions_[index];
921
922 ImVec4 color = GetSessionColor(index);
923 gui::StyleColorGuard tab_color_guard(ImGuiCol_Text, color);
924
925 std::string tab_name = GetSessionDisplayName(index);
926 if (session->rom.is_loaded()) {
927 tab_name += " ";
928 tab_name += ICON_MD_CHECK_CIRCLE;
929 }
930
931 if (ImGui::BeginTabItem(tab_name.c_str())) {
932 if (!is_active) {
933 SwitchToSession(index);
934 }
935 ImGui::EndTabItem();
936 }
937}
938
940 if (ImGui::MenuItem(
941 absl::StrFormat("%s Switch to Session", ICON_MD_TAB).c_str())) {
942 SwitchToSession(index);
943 }
944
945 if (ImGui::MenuItem(absl::StrFormat("%s Rename", ICON_MD_EDIT).c_str())) {
946 session_to_rename_ = index;
947 strncpy(session_rename_buffer_, GetSessionDisplayName(index).c_str(),
948 sizeof(session_rename_buffer_) - 1);
951 }
952
953 if (ImGui::MenuItem(
954 absl::StrFormat("%s Duplicate", ICON_MD_CONTENT_COPY).c_str())) {
955 // TODO: Implement session duplication
956 }
957
958 ImGui::Separator();
959
960 if (HasMultipleSessions() &&
961 ImGui::MenuItem(
962 absl::StrFormat("%s Close Session", ICON_MD_CLOSE).c_str())) {
963 CloseSession(index);
964 }
965}
966
968 if (index >= sessions_.size())
969 return;
970
971 const auto& session = sessions_[index];
972 ImVec4 color = GetSessionColor(index);
973
974 gui::StyleColorGuard badge_guard(ImGuiCol_Text, color);
975
976 if (session->rom.is_loaded()) {
977 ImGui::Text("%s", ICON_MD_CHECK_CIRCLE);
978 } else {
979 ImGui::Text("%s", ICON_MD_RADIO_BUTTON_UNCHECKED);
980 }
981}
982
983ImVec4 SessionCoordinator::GetSessionColor(size_t index) const {
984 // Generate consistent colors for sessions
985 static const ImVec4 colors[] = {
986 ImVec4(0.0f, 1.0f, 0.0f, 1.0f), // Green
987 ImVec4(0.0f, 0.5f, 1.0f, 1.0f), // Blue
988 ImVec4(1.0f, 0.5f, 0.0f, 1.0f), // Orange
989 ImVec4(1.0f, 0.0f, 1.0f, 1.0f), // Magenta
990 ImVec4(1.0f, 1.0f, 0.0f, 1.0f), // Yellow
991 ImVec4(0.0f, 1.0f, 1.0f, 1.0f), // Cyan
992 ImVec4(1.0f, 0.0f, 0.0f, 1.0f), // Red
993 ImVec4(0.5f, 0.5f, 0.5f, 1.0f), // Gray
994 };
995
996 return colors[index % (sizeof(colors) / sizeof(colors[0]))];
997}
998
999std::string SessionCoordinator::GetSessionIcon(size_t index) const {
1000 if (index >= sessions_.size())
1002
1003 const auto& session = sessions_[index];
1004
1005 if (session->rom.is_loaded()) {
1006 return ICON_MD_CHECK_CIRCLE;
1007 } else {
1009 }
1010}
1011
1012bool SessionCoordinator::IsSessionEmpty(size_t index) const {
1013 return IsValidSessionIndex(index) && !sessions_[index]->rom.is_loaded();
1014}
1015
1016bool SessionCoordinator::IsSessionClosed(size_t index) const {
1017 return !IsValidSessionIndex(index);
1018}
1019
1021 // TODO: Implement modification tracking
1022 return false;
1023}
1024
1025} // namespace editor
1026} // namespace yaze
void Publish(const T &event)
Definition event_bus.h:35
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
static bool IsPanelBasedEditor(EditorType type)
Contains a complete set of editors for a single ROM instance.
virtual void ConfigureSession(RomSession *session)=0
virtual void SetCurrentEditor(Editor *editor)=0
Main UI class for editing overworld maps in A Link to the Past.
Central registry for all editor cards with session awareness and dependency injection.
void SetActiveSession(size_t session_id)
void UnregisterSession(size_t session_id)
void HideAllPanelsInSession(size_t session_id)
void ShowAllPanelsInCategory(size_t session_id, const std::string &category)
void HideAllPanelsInCategory(size_t session_id, const std::string &category)
void ShowAllPanelsInSession(size_t session_id)
void NotifySessionCreated(size_t index, RomSession *session)
void * GetSession(size_t index) const
std::string GenerateUniqueEditorTitle(const std::string &editor_name, size_t session_index) const
zelda3::GameData * GetCurrentGameData() const
void NotifySessionRomLoaded(size_t index, RomSession *session)
absl::StatusOr< RomSession * > CreateSessionFromRom(Rom &&rom, const std::string &filepath)
absl::Status SaveSessionAs(size_t session_index, const std::string &filename)
absl::Status SaveActiveSession(const std::string &filename="")
ImVec4 GetSessionColor(size_t index) const
absl::Status LoadRomIntoSession(const std::string &filename, size_t session_index=SIZE_MAX)
std::string GetSessionDisplayName(size_t index) const
void RenameSession(size_t index, const std::string &new_name)
bool IsSessionModified(size_t index) const
SessionCoordinator(PanelManager *panel_manager, ToastManager *toast_manager, UserSettings *user_settings)
bool HasDuplicateSession(const std::string &filepath) const
void ShowPanelsInCategory(const std::string &category)
void HidePanelsInCategory(const std::string &category)
bool IsSessionClosed(size_t index) const
std::string GetSessionIcon(size_t index) const
std::string GetActiveSessionDisplayName() const
void ShowSessionOperationResult(const std::string &operation, bool success)
bool IsValidSessionIndex(size_t index) const
bool IsSessionEmpty(size_t index) const
void DrawSessionTab(size_t index, bool is_active)
bool IsSessionActive(size_t index) const
std::vector< std::unique_ptr< RomSession > > sessions_
void ValidateSessionIndex(size_t index) const
void NotifySessionSwitched(size_t index, RomSession *session)
bool IsSessionLoaded(size_t index) const
std::string GenerateUniqueSessionName(const std::string &base_name) const
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
Manages user preferences and settings persistence.
RAII guard for ImGui style colors.
Definition style_guard.h:27
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_ADD
Definition icons.h:86
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:400
#define ICON_MD_RADIO_BUTTON_CHECKED
Definition icons.h:1548
#define ICON_MD_TAB
Definition icons.h:1930
#define ICON_MD_CONTENT_COPY
Definition icons.h:465
#define ICON_MD_RADIO_BUTTON_UNCHECKED
Definition icons.h:1551
#define ICON_MD_CLOSE
Definition icons.h:418
#define ICON_MD_ANALYTICS
Definition icons.h:154
#define LOG_INFO(category, format,...)
Definition log.h:105
constexpr std::array< const char *, 14 > kEditorNames
Definition editor.h:217
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:134
ImVec4 GetSuccessColor()
Definition ui_helpers.cc:48
bool BeginThemedTabBar(const char *id, ImGuiTabBarFlags flags)
A stylized tab bar with "Mission Control" branding.
void EndThemedTabBar()
ImVec4 GetWarningColor()
Definition ui_helpers.cc:53
static RomLoadedEvent Create(Rom *r, const std::string &file, size_t session)
Definition core_events.h:32
Represents a single session, containing a ROM and its associated editors.
static SessionClosedEvent Create(size_t idx)
static SessionCreatedEvent Create(size_t idx, RomSession *sess)
static SessionSwitchedEvent Create(size_t old_idx, size_t new_idx, RomSession *sess)
Definition core_events.h:93