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"
20#include "app/gui/core/icons.h"
22#include "core/color.h"
23#include "editor/editor.h"
26#include "imgui/imgui.h"
27#include "util/log.h"
28#include "zelda3/game_data.h"
29
30namespace yaze {
31namespace editor {
32
34 ToastManager* toast_manager,
35 UserSettings* user_settings)
36 : panel_manager_(panel_manager),
37 toast_manager_(toast_manager),
38 user_settings_(user_settings) {}
39
41 if (observer) {
42 observers_.push_back(observer);
43 }
44}
45
47 observers_.erase(
48 std::remove(observers_.begin(), observers_.end(), observer),
49 observers_.end());
50}
51
53 RomSession* session) {
54 for (auto* observer : observers_) {
55 observer->OnSessionSwitched(index, session);
56 }
57}
58
60 RomSession* session) {
61 for (auto* observer : observers_) {
62 observer->OnSessionCreated(index, session);
63 }
64}
65
67 for (auto* observer : observers_) {
68 observer->OnSessionClosed(index);
69 }
70}
71
73 RomSession* session) {
74 for (auto* observer : observers_) {
75 observer->OnSessionRomLoaded(index, session);
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(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%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(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "Loaded");
397 } else {
398 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "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 (ImGui::BeginTabBar("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 }
488 ImGui::EndTabBar();
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 ImGui::PushStyleColor(ImGuiCol_Text, accent_color);
500 ImGui::Text("%s Session %zu", ICON_MD_TAB, active_session_index_);
501 ImGui::PopStyleColor();
502
503 if (ImGui::IsItemHovered()) {
504 ImGui::SetTooltip("Active Session: %s\nClick to open session switcher",
506 }
507
508 if (ImGui::IsItemClicked()) {
510 }
511}
512
513std::string SessionCoordinator::GetSessionDisplayName(size_t index) const {
514 if (!IsValidSessionIndex(index)) {
515 return "Invalid Session";
516 }
517
518 const auto& session = sessions_[index];
519
520 if (!session->custom_name.empty()) {
521 return session->custom_name;
522 }
523
524 if (session->rom.is_loaded()) {
525 return absl::StrFormat(
526 "Session %zu (%s)", index,
527 std::filesystem::path(session->filepath).stem().string());
528 }
529
530 return absl::StrFormat("Session %zu (Empty)", index);
531}
532
536
538 const std::string& new_name) {
539 if (!IsValidSessionIndex(index) || new_name.empty())
540 return;
541
542 sessions_[index]->custom_name = new_name;
543 LOG_INFO("SessionCoordinator", "Renamed session %zu to '%s'", index,
544 new_name.c_str());
545}
546
548 const std::string& editor_name, size_t session_index) const {
549 if (sessions_.size() <= 1) {
550 // Single session - use simple name
551 return editor_name;
552 }
553
554 if (session_index >= sessions_.size()) {
555 return editor_name;
556 }
557
558 // Multi-session - include session identifier
559 const auto& session = sessions_[session_index];
560 std::string session_name =
561 session->custom_name.empty() ? session->rom.title() : session->custom_name;
562
563 // Truncate long session names
564 if (session_name.length() > 20) {
565 session_name = session_name.substr(0, 17) + "...";
566 }
567
568 return absl::StrFormat("%s - %s##session_%zu", editor_name, session_name,
569 session_index);
570}
571
573 SwitchToSession(index);
574}
575
579
580// Panel coordination across sessions
586
592
593void SessionCoordinator::ShowPanelsInCategory(const std::string& category) {
594 if (panel_manager_) {
596 }
597}
598
599void SessionCoordinator::HidePanelsInCategory(const std::string& category) {
600 if (panel_manager_) {
602 }
603}
604
606 return index < sessions_.size();
607}
608
610 if (sessions_.empty())
611 return;
612
613 size_t original_session_idx = active_session_index_;
614
615 for (size_t session_idx = 0; session_idx < sessions_.size(); ++session_idx) {
616 auto& session = sessions_[session_idx];
617 if (!session->rom.is_loaded())
618 continue; // Skip sessions with invalid ROMs
619
620 // Switch context
621 SwitchToSession(session_idx);
622
623 for (auto editor : session->editors.active_editors_) {
624 if (*editor->active()) {
625 if (editor->type() == EditorType::kOverworld) {
626 auto& overworld_editor = static_cast<OverworldEditor&>(*editor);
627 if (overworld_editor.jump_to_tab() != -1) {
628 // Set the dungeon editor to the jump to tab
629 session->editors.GetDungeonEditor()->add_room(
630 overworld_editor.jump_to_tab());
631 overworld_editor.jump_to_tab_ = -1;
632 }
633 }
634
635 // CARD-BASED EDITORS: Don't wrap in Begin/End, they manage own windows
636 bool is_card_based_editor = EditorManager::IsPanelBasedEditor(editor->type());
637
638 if (is_card_based_editor) {
639 // Panel-based editors create their own top-level windows
640 // No parent wrapper needed - this allows independent docking
641 if (editor_manager_) {
643 }
644
645 absl::Status status = editor->Update();
646
647 // Route editor errors to toast manager
648 if (!status.ok() && toast_manager_) {
649 std::string editor_name = kEditorNames[static_cast<int>(editor->type())];
651 absl::StrFormat("%s Error: %s", editor_name, status.message()),
652 ToastType::kError, 8.0f);
653 }
654
655 } else {
656 // TRADITIONAL EDITORS: Wrap in Begin/End
657 std::string window_title =
658 GenerateUniqueEditorTitle(kEditorNames[static_cast<int>(editor->type())], session_idx);
659
660 // Set window to maximize on first open
661 ImGui::SetNextWindowSize(ImGui::GetMainViewport()->WorkSize,
662 ImGuiCond_FirstUseEver);
663 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->WorkPos,
664 ImGuiCond_FirstUseEver);
665
666 if (ImGui::Begin(window_title.c_str(), editor->active(),
667 ImGuiWindowFlags_None)) { // Allow full docking
668 // Temporarily switch context for this editor's update
669 // (Already switched via SwitchToSession)
670 if (editor_manager_) {
672 }
673
674 absl::Status status = editor->Update();
675
676 // Route editor errors to toast manager
677 if (!status.ok() && toast_manager_) {
678 std::string editor_name = kEditorNames[static_cast<int>(editor->type())];
679 toast_manager_->Show(absl::StrFormat("%s Error: %s", editor_name,
680 status.message()),
681 ToastType::kError, 8.0f);
682 }
683 }
684 ImGui::End();
685 }
686 }
687 }
688 }
689
690 // Restore original session context
691 SwitchToSession(original_session_idx);
692}
693
694bool SessionCoordinator::IsSessionActive(size_t index) const {
695 return index == active_session_index_;
696}
697
698bool SessionCoordinator::IsSessionLoaded(size_t index) const {
699 return IsValidSessionIndex(index) && sessions_[index]->rom.is_loaded();
700}
701
705
707 size_t count = 0;
708 for (const auto& session : sessions_) {
709 if (session->rom.is_loaded()) {
710 count++;
711 }
712 }
713 return count;
714}
715
719
720absl::Status SessionCoordinator::LoadRomIntoSession(const std::string& filename,
721 size_t session_index) {
722 if (filename.empty()) {
723 return absl::InvalidArgumentError("Invalid parameters");
724 }
725
726 size_t target_index =
727 (session_index == SIZE_MAX) ? active_session_index_ : session_index;
728 if (!IsValidSessionIndex(target_index)) {
729 return absl::InvalidArgumentError("Invalid session index");
730 }
731
732 // TODO: Implement actual ROM loading
733 LOG_INFO("SessionCoordinator", "LoadRomIntoSession: %s -> session %zu",
734 filename.c_str(), target_index);
735
736 return absl::OkStatus();
737}
738
740 const std::string& filename) {
742 return absl::FailedPreconditionError("No active session");
743 }
744
745 // TODO: Implement actual ROM saving
746 LOG_INFO("SessionCoordinator", "SaveActiveSession: session %zu",
748
749 return absl::OkStatus();
750}
751
752absl::Status SessionCoordinator::SaveSessionAs(size_t session_index,
753 const std::string& filename) {
754 if (!IsValidSessionIndex(session_index) || filename.empty()) {
755 return absl::InvalidArgumentError("Invalid parameters");
756 }
757
758 // TODO: Implement actual ROM saving
759 LOG_INFO("SessionCoordinator", "SaveSessionAs: session %zu -> %s",
760 session_index, filename.c_str());
761
762 return absl::OkStatus();
763}
764
766 Rom&& rom, const std::string& filepath) {
767 size_t new_session_id = sessions_.size();
768 sessions_.push_back(std::make_unique<RomSession>(std::move(rom), user_settings_, new_session_id));
769 auto& session = sessions_.back();
770 session->filepath = filepath;
771
773 SwitchToSession(new_session_id);
774
775 // Notify observers
776 NotifySessionCreated(new_session_id, session.get());
777 NotifySessionRomLoaded(new_session_id, session.get());
778
779 return session.get();
780}
781
783 // Mark empty sessions as closed (except keep at least one)
784 size_t loaded_count = 0;
785 for (const auto& session : sessions_) {
786 if (session->rom.is_loaded()) {
787 loaded_count++;
788 }
789 }
790
791 if (loaded_count > 0) {
792 for (auto it = sessions_.begin(); it != sessions_.end();) {
793 if (!(*it)->rom.is_loaded() && sessions_.size() > 1) {
794 it = sessions_.erase(it);
795 } else {
796 ++it;
797 }
798 }
799 }
800
802 LOG_INFO("SessionCoordinator", "Cleaned up closed sessions (remaining: %zu)",
804}
805
807 if (sessions_.empty())
808 return;
809
810 // Unregister all session cards
811 if (panel_manager_) {
812 for (size_t i = 0; i < sessions_.size(); ++i) {
814 }
815 }
816
817 sessions_.clear();
820
821 LOG_INFO("SessionCoordinator", "Cleared all sessions");
822}
823
825 if (sessions_.empty())
826 return;
827
828 size_t next_index = (active_session_index_ + 1) % sessions_.size();
829 SwitchToSession(next_index);
830}
831
833 if (sessions_.empty())
834 return;
835
836 size_t prev_index = (active_session_index_ == 0) ? sessions_.size() - 1
838 SwitchToSession(prev_index);
839}
840
842 if (sessions_.empty())
843 return;
845}
846
848 if (sessions_.empty())
849 return;
850 SwitchToSession(sessions_.size() - 1);
851}
852
854 if (!sessions_.empty() &&
856 active_session_index_ = sessions_.size() - 1;
857 }
858}
859
861 if (!IsValidSessionIndex(index)) {
862 throw std::out_of_range(
863 absl::StrFormat("Invalid session index: %zu", index));
864 }
865}
866
868 const std::string& base_name) const {
869 if (sessions_.empty())
870 return base_name;
871
872 std::string name = base_name;
873 int counter = 1;
874
875 while (true) {
876 bool found = false;
877 for (const auto& session : sessions_) {
878 if (session->custom_name == name) {
879 found = true;
880 break;
881 }
882 }
883
884 if (!found)
885 break;
886
887 name = absl::StrFormat("%s %d", base_name, counter++);
888 }
889
890 return name;
891}
892
894 if (toast_manager_) {
896 absl::StrFormat("Maximum %zu sessions allowed", kMaxSessions),
898 }
899}
900
902 const std::string& operation, bool success) {
903 if (toast_manager_) {
904 std::string message =
905 absl::StrFormat("%s %s", operation, success ? "succeeded" : "failed");
907 toast_manager_->Show(message, type);
908 }
909}
910
911void SessionCoordinator::DrawSessionTab(size_t index, bool is_active) {
912 if (index >= sessions_.size())
913 return;
914
915 const auto& session = sessions_[index];
916
917 ImVec4 color = GetSessionColor(index);
918 ImGui::PushStyleColor(ImGuiCol_Text, color);
919
920 std::string tab_name = GetSessionDisplayName(index);
921 if (session->rom.is_loaded()) {
922 tab_name += " ";
923 tab_name += ICON_MD_CHECK_CIRCLE;
924 }
925
926 if (ImGui::BeginTabItem(tab_name.c_str())) {
927 if (!is_active) {
928 SwitchToSession(index);
929 }
930 ImGui::EndTabItem();
931 }
932
933 ImGui::PopStyleColor();
934}
935
937 if (ImGui::MenuItem(
938 absl::StrFormat("%s Switch to Session", ICON_MD_TAB).c_str())) {
939 SwitchToSession(index);
940 }
941
942 if (ImGui::MenuItem(absl::StrFormat("%s Rename", ICON_MD_EDIT).c_str())) {
943 session_to_rename_ = index;
944 strncpy(session_rename_buffer_, GetSessionDisplayName(index).c_str(),
945 sizeof(session_rename_buffer_) - 1);
948 }
949
950 if (ImGui::MenuItem(
951 absl::StrFormat("%s Duplicate", ICON_MD_CONTENT_COPY).c_str())) {
952 // TODO: Implement session duplication
953 }
954
955 ImGui::Separator();
956
957 if (HasMultipleSessions() &&
958 ImGui::MenuItem(
959 absl::StrFormat("%s Close Session", ICON_MD_CLOSE).c_str())) {
960 CloseSession(index);
961 }
962}
963
965 if (index >= sessions_.size())
966 return;
967
968 const auto& session = sessions_[index];
969 ImVec4 color = GetSessionColor(index);
970
971 ImGui::PushStyleColor(ImGuiCol_Text, color);
972
973 if (session->rom.is_loaded()) {
974 ImGui::Text("%s", ICON_MD_CHECK_CIRCLE);
975 } else {
976 ImGui::Text("%s", ICON_MD_RADIO_BUTTON_UNCHECKED);
977 }
978
979 ImGui::PopStyleColor();
980}
981
982ImVec4 SessionCoordinator::GetSessionColor(size_t index) const {
983 // Generate consistent colors for sessions
984 static const ImVec4 colors[] = {
985 ImVec4(0.0f, 1.0f, 0.0f, 1.0f), // Green
986 ImVec4(0.0f, 0.5f, 1.0f, 1.0f), // Blue
987 ImVec4(1.0f, 0.5f, 0.0f, 1.0f), // Orange
988 ImVec4(1.0f, 0.0f, 1.0f, 1.0f), // Magenta
989 ImVec4(1.0f, 1.0f, 0.0f, 1.0f), // Yellow
990 ImVec4(0.0f, 1.0f, 1.0f, 1.0f), // Cyan
991 ImVec4(1.0f, 0.0f, 0.0f, 1.0f), // Red
992 ImVec4(0.5f, 0.5f, 0.5f, 1.0f), // Gray
993 };
994
995 return colors[index % (sizeof(colors) / sizeof(colors[0]))];
996}
997
998std::string SessionCoordinator::GetSessionIcon(size_t index) const {
999 if (index >= sessions_.size())
1001
1002 const auto& session = sessions_[index];
1003
1004 if (session->rom.is_loaded()) {
1005 return ICON_MD_CHECK_CIRCLE;
1006 } else {
1008 }
1009}
1010
1011bool SessionCoordinator::IsSessionEmpty(size_t index) const {
1012 return IsValidSessionIndex(index) && !sessions_[index]->rom.is_loaded();
1013}
1014
1015bool SessionCoordinator::IsSessionClosed(size_t index) const {
1016 return !IsValidSessionIndex(index);
1017}
1018
1020 // TODO: Implement modification tracking
1021 return false;
1022}
1023
1024} // namespace editor
1025} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
void ConfigureSession(RomSession *session)
void SetCurrentEditor(Editor *editor)
static bool IsPanelBasedEditor(EditorType type)
Contains a complete set of editors for a single ROM instance.
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
void RemoveObserver(SessionObserver *observer)
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
std::vector< SessionObserver * > observers_
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 AddObserver(SessionObserver *observer)
void NotifySessionSwitched(size_t index, RomSession *session)
bool IsSessionLoaded(size_t index) const
std::string GenerateUniqueSessionName(const std::string &base_name) const
Observer interface for session state changes.
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
Manages user preferences and settings persistence.
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:167
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:23
Represents a single session, containing a ROM and its associated editors.