refactor(editor): introduce UICoordinator for UI management
- Added UICoordinator class to centralize UI drawing operations and state management, improving separation of concerns within the editor. - Refactored EditorManager to delegate UI-related tasks to UICoordinator, enhancing maintainability and clarity. - Updated CMake configuration to include new source files for the UICoordinator component. Benefits: - Streamlines UI management, leading to a more organized and efficient user experience. - Enhances the overall architecture by clearly defining roles for UI handling and editor operations.
This commit is contained in:
@@ -1,834 +0,0 @@
|
||||
#include "session_coordinator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/editor_manager.h"
|
||||
#include "app/gui/core/icons.h"
|
||||
#include "app/gui/core/theme_manager.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
SessionCoordinator::SessionCoordinator(void* sessions_ptr,
|
||||
SessionCardRegistry* card_registry,
|
||||
ToastManager* toast_manager)
|
||||
: sessions_ptr_(sessions_ptr),
|
||||
card_registry_(card_registry),
|
||||
toast_manager_(toast_manager) {
|
||||
auto* sessions = static_cast<std::deque<EditorManager::RomSession>*>(sessions_ptr_);
|
||||
if (sessions && !sessions->empty()) {
|
||||
active_session_index_ = 0;
|
||||
session_count_ = sessions->size();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper macro to get sessions pointer
|
||||
#define GET_SESSIONS() static_cast<std::deque<EditorManager::RomSession>*>(sessions_ptr_)
|
||||
|
||||
void SessionCoordinator::CreateNewSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions) return;
|
||||
|
||||
if (session_count_ >= kMaxSessions) {
|
||||
ShowSessionLimitWarning();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new empty session
|
||||
sessions->emplace_back();
|
||||
UpdateSessionCount();
|
||||
|
||||
// Set as active session
|
||||
active_session_index_ = sessions->size() - 1;
|
||||
|
||||
printf("[SessionCoordinator] Created new session %zu (total: %zu)\n",
|
||||
active_session_index_, session_count_);
|
||||
|
||||
ShowSessionOperationResult("Create Session", true);
|
||||
}
|
||||
|
||||
void SessionCoordinator::DuplicateCurrentSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
|
||||
if (session_count_ >= kMaxSessions) {
|
||||
ShowSessionLimitWarning();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new empty session (cannot actually duplicate due to non-movable editors)
|
||||
// TODO: Implement proper duplication when editors become movable
|
||||
sessions->emplace_back();
|
||||
UpdateSessionCount();
|
||||
|
||||
// Set as active session
|
||||
active_session_index_ = sessions->size() - 1;
|
||||
|
||||
printf("[SessionCoordinator] Duplicated session %zu (total: %zu)\n",
|
||||
active_session_index_, session_count_);
|
||||
|
||||
ShowSessionOperationResult("Duplicate Session", true);
|
||||
}
|
||||
|
||||
void SessionCoordinator::CloseCurrentSession() {
|
||||
CloseSession(active_session_index_);
|
||||
}
|
||||
|
||||
void SessionCoordinator::CloseSession(size_t index) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || !IsValidSessionIndex(index)) return;
|
||||
|
||||
if (session_count_ <= kMinSessions) {
|
||||
// Don't allow closing the last session
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("Cannot close the last session", ToastType::kWarning);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Unregister cards for this session
|
||||
if (card_registry_) {
|
||||
card_registry_->UnregisterSession(index);
|
||||
}
|
||||
|
||||
// Mark session as closed (don't erase due to non-movable editors)
|
||||
// TODO: Implement proper session removal when editors become movable
|
||||
sessions->at(index).custom_name = "[CLOSED SESSION]";
|
||||
|
||||
// Note: We don't actually remove from the deque because EditorSet is not movable
|
||||
// This is a temporary solution until we refactor to use unique_ptr<EditorSet>
|
||||
UpdateSessionCount();
|
||||
|
||||
// Adjust active session index
|
||||
if (active_session_index_ >= index && active_session_index_ > 0) {
|
||||
active_session_index_--;
|
||||
}
|
||||
|
||||
printf("[SessionCoordinator] Closed session %zu (total: %zu)\n",
|
||||
index, session_count_);
|
||||
|
||||
ShowSessionOperationResult("Close Session", true);
|
||||
}
|
||||
|
||||
void SessionCoordinator::RemoveSession(size_t index) {
|
||||
CloseSession(index);
|
||||
}
|
||||
|
||||
void SessionCoordinator::SwitchToSession(size_t index) {
|
||||
if (!IsValidSessionIndex(index)) return;
|
||||
|
||||
active_session_index_ = index;
|
||||
|
||||
if (card_registry_) {
|
||||
card_registry_->SetActiveSession(index);
|
||||
}
|
||||
|
||||
printf("[SessionCoordinator] Switched to session %zu\n", index);
|
||||
}
|
||||
|
||||
void SessionCoordinator::ActivateSession(size_t index) {
|
||||
SwitchToSession(index);
|
||||
}
|
||||
|
||||
size_t SessionCoordinator::GetActiveSessionIndex() const {
|
||||
return active_session_index_;
|
||||
}
|
||||
|
||||
void* SessionCoordinator::GetActiveSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || !IsValidSessionIndex(active_session_index_)) {
|
||||
return nullptr;
|
||||
}
|
||||
return &sessions->at(active_session_index_);
|
||||
}
|
||||
|
||||
void* SessionCoordinator::GetSession(size_t index) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || !IsValidSessionIndex(index)) {
|
||||
return nullptr;
|
||||
}
|
||||
return &sessions->at(index);
|
||||
}
|
||||
|
||||
bool SessionCoordinator::HasMultipleSessions() const {
|
||||
return session_count_ > 1;
|
||||
}
|
||||
|
||||
size_t SessionCoordinator::GetActiveSessionCount() const {
|
||||
return session_count_;
|
||||
}
|
||||
|
||||
bool SessionCoordinator::HasDuplicateSession(const std::string& filepath) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || filepath.empty()) return false;
|
||||
|
||||
for (const auto& session : *sessions) {
|
||||
if (session.filepath == filepath) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionSwitcher() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
|
||||
if (!show_session_switcher_) return;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
|
||||
ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
|
||||
if (!ImGui::Begin("Session Switcher", &show_session_switcher_)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("%s Active Sessions (%zu)", ICON_MD_TAB, session_count_);
|
||||
ImGui::Separator();
|
||||
|
||||
for (size_t i = 0; i < sessions->size(); ++i) {
|
||||
const auto& session = sessions->at(i);
|
||||
bool is_active = (i == active_session_index_);
|
||||
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
|
||||
// Session tab
|
||||
if (ImGui::Selectable(GetSessionDisplayName(i).c_str(), is_active)) {
|
||||
SwitchToSession(i);
|
||||
}
|
||||
|
||||
// Right-click context menu
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
ImGui::OpenPopup("SessionContextMenu");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("SessionContextMenu")) {
|
||||
DrawSessionContextMenu(i);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Action buttons
|
||||
if (ImGui::Button(absl::StrFormat("%s New Session", ICON_MD_ADD).c_str())) {
|
||||
CreateNewSession();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(absl::StrFormat("%s Duplicate", ICON_MD_CONTENT_COPY).c_str())) {
|
||||
DuplicateCurrentSession();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (HasMultipleSessions() && ImGui::Button(absl::StrFormat("%s Close", ICON_MD_CLOSE).c_str())) {
|
||||
CloseCurrentSession();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionManager() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
|
||||
if (!show_session_manager_) return;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
|
||||
ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
|
||||
if (!ImGui::Begin("Session Manager", &show_session_manager_)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// Session statistics
|
||||
ImGui::Text("%s Session Statistics", ICON_MD_ANALYTICS);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Total Sessions: %zu", GetTotalSessionCount());
|
||||
ImGui::Text("Loaded Sessions: %zu", GetLoadedSessionCount());
|
||||
ImGui::Text("Empty Sessions: %zu", GetEmptySessionCount());
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// Session list
|
||||
if (ImGui::BeginTable("SessionTable", 4,
|
||||
ImGuiTableFlags_Borders |
|
||||
ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_Resizable)) {
|
||||
|
||||
ImGui::TableSetupColumn("Session", ImGuiTableColumnFlags_WidthStretch, 0.3f);
|
||||
ImGui::TableSetupColumn("ROM File", ImGuiTableColumnFlags_WidthStretch, 0.4f);
|
||||
ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 0.2f);
|
||||
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 120.0f);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (size_t i = 0; i < sessions->size(); ++i) {
|
||||
const auto& session = sessions->at(i);
|
||||
bool is_active = (i == active_session_index_);
|
||||
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// Session name
|
||||
ImGui::TableNextColumn();
|
||||
if (is_active) {
|
||||
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%s %s",
|
||||
ICON_MD_RADIO_BUTTON_CHECKED, GetSessionDisplayName(i).c_str());
|
||||
} else {
|
||||
ImGui::Text("%s %s", ICON_MD_RADIO_BUTTON_UNCHECKED, GetSessionDisplayName(i).c_str());
|
||||
}
|
||||
|
||||
// ROM file
|
||||
ImGui::TableNextColumn();
|
||||
if (session.rom.is_loaded()) {
|
||||
ImGui::Text("%s", session.filepath.c_str());
|
||||
} else {
|
||||
ImGui::TextDisabled("(No ROM loaded)");
|
||||
}
|
||||
|
||||
// Status
|
||||
ImGui::TableNextColumn();
|
||||
if (session.rom.is_loaded()) {
|
||||
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "Loaded");
|
||||
} else {
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Empty");
|
||||
}
|
||||
|
||||
// Actions
|
||||
ImGui::TableNextColumn();
|
||||
if (!is_active && ImGui::SmallButton("Switch")) {
|
||||
SwitchToSession(i);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (HasMultipleSessions() && ImGui::SmallButton("Close")) {
|
||||
CloseSession(i);
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionRenameDialog() {
|
||||
if (!show_session_rename_dialog_) return;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(300, 150), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
|
||||
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
|
||||
if (!ImGui::Begin("Rename Session", &show_session_rename_dialog_)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Rename session %zu:", session_to_rename_);
|
||||
ImGui::InputText("Name", session_rename_buffer_, sizeof(session_rename_buffer_));
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
if (ImGui::Button("OK")) {
|
||||
RenameSession(session_to_rename_, session_rename_buffer_);
|
||||
show_session_rename_dialog_ = false;
|
||||
session_rename_buffer_[0] = '\0';
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel")) {
|
||||
show_session_rename_dialog_ = false;
|
||||
session_rename_buffer_[0] = '\0';
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionTabs() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
|
||||
if (ImGui::BeginTabBar("SessionTabs")) {
|
||||
for (size_t i = 0; i < sessions->size(); ++i) {
|
||||
bool is_active = (i == active_session_index_);
|
||||
const auto& session = sessions->at(i);
|
||||
|
||||
std::string tab_name = GetSessionDisplayName(i);
|
||||
if (session.rom.is_loaded()) {
|
||||
tab_name += " ";
|
||||
tab_name += ICON_MD_CHECK_CIRCLE;
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem(tab_name.c_str())) {
|
||||
if (!is_active) {
|
||||
SwitchToSession(i);
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// Right-click context menu
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
ImGui::OpenPopup(absl::StrFormat("SessionTabContext_%zu", i).c_str());
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup(absl::StrFormat("SessionTabContext_%zu", i).c_str())) {
|
||||
DrawSessionContextMenu(i);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionIndicator() {
|
||||
if (!HasMultipleSessions()) return;
|
||||
|
||||
const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
|
||||
ImVec4 accent_color = ConvertColorToImVec4(theme.accent);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, accent_color);
|
||||
ImGui::Text("%s Session %zu", ICON_MD_TAB, active_session_index_);
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Active Session: %s\nClick to open session switcher",
|
||||
GetActiveSessionDisplayName().c_str());
|
||||
}
|
||||
|
||||
if (ImGui::IsItemClicked()) {
|
||||
ToggleSessionSwitcher();
|
||||
}
|
||||
}
|
||||
|
||||
std::string SessionCoordinator::GetSessionDisplayName(size_t index) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || !IsValidSessionIndex(index)) {
|
||||
return "Invalid Session";
|
||||
}
|
||||
|
||||
const auto& session = sessions->at(index);
|
||||
|
||||
if (!session.custom_name.empty()) {
|
||||
return session.custom_name;
|
||||
}
|
||||
|
||||
if (session.rom.is_loaded()) {
|
||||
return absl::StrFormat("Session %zu (%s)", index,
|
||||
std::filesystem::path(session.filepath).stem().string());
|
||||
}
|
||||
|
||||
return absl::StrFormat("Session %zu (Empty)", index);
|
||||
}
|
||||
|
||||
std::string SessionCoordinator::GetActiveSessionDisplayName() const {
|
||||
return GetSessionDisplayName(active_session_index_);
|
||||
}
|
||||
|
||||
void SessionCoordinator::RenameSession(size_t index, const std::string& new_name) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || !IsValidSessionIndex(index) || new_name.empty()) return;
|
||||
|
||||
sessions->at(index).custom_name = new_name;
|
||||
printf("[SessionCoordinator] Renamed session %zu to '%s'\n", index, new_name.c_str());
|
||||
}
|
||||
|
||||
std::string SessionCoordinator::GenerateUniqueEditorTitle(
|
||||
const std::string& editor_name, size_t session_index) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
|
||||
if (!sessions || sessions->size() <= 1) {
|
||||
// Single session - use simple name
|
||||
return editor_name;
|
||||
}
|
||||
|
||||
if (session_index >= sessions->size()) {
|
||||
return editor_name;
|
||||
}
|
||||
|
||||
// Multi-session - include session identifier
|
||||
const auto& session = sessions->at(session_index);
|
||||
std::string session_name = session.custom_name.empty()
|
||||
? session.rom.title()
|
||||
: session.custom_name;
|
||||
|
||||
// Truncate long session names
|
||||
if (session_name.length() > 20) {
|
||||
session_name = session_name.substr(0, 17) + "...";
|
||||
}
|
||||
|
||||
return absl::StrFormat("%s - %s##session_%zu", editor_name, session_name,
|
||||
session_index);
|
||||
}
|
||||
|
||||
void SessionCoordinator::SetActiveSessionIndex(size_t index) {
|
||||
SwitchToSession(index);
|
||||
}
|
||||
|
||||
void SessionCoordinator::UpdateSessionCount() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (sessions) {
|
||||
session_count_ = sessions->size();
|
||||
} else {
|
||||
session_count_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::ShowAllCardsInActiveSession() {
|
||||
if (card_registry_) {
|
||||
card_registry_->ShowAllCardsInSession(active_session_index_);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::HideAllCardsInActiveSession() {
|
||||
if (card_registry_) {
|
||||
card_registry_->HideAllCardsInSession(active_session_index_);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::ShowCardsInCategory(const std::string& category) {
|
||||
if (card_registry_) {
|
||||
card_registry_->ShowAllCardsInCategory(active_session_index_, category);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::HideCardsInCategory(const std::string& category) {
|
||||
if (card_registry_) {
|
||||
card_registry_->HideAllCardsInCategory(active_session_index_, category);
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionCoordinator::IsValidSessionIndex(size_t index) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
return sessions && index < sessions->size();
|
||||
}
|
||||
|
||||
bool SessionCoordinator::IsSessionActive(size_t index) const {
|
||||
return index == active_session_index_;
|
||||
}
|
||||
|
||||
bool SessionCoordinator::IsSessionLoaded(size_t index) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
return IsValidSessionIndex(index) && sessions && sessions->at(index).rom.is_loaded();
|
||||
}
|
||||
|
||||
size_t SessionCoordinator::GetTotalSessionCount() const {
|
||||
return session_count_;
|
||||
}
|
||||
|
||||
size_t SessionCoordinator::GetLoadedSessionCount() const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions) return 0;
|
||||
|
||||
size_t count = 0;
|
||||
for (const auto& session : *sessions) {
|
||||
if (session.rom.is_loaded()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t SessionCoordinator::GetEmptySessionCount() const {
|
||||
return session_count_ - GetLoadedSessionCount();
|
||||
}
|
||||
|
||||
absl::Status SessionCoordinator::LoadRomIntoSession(const std::string& filename, size_t session_index) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || filename.empty()) {
|
||||
return absl::InvalidArgumentError("Invalid parameters");
|
||||
}
|
||||
|
||||
size_t target_index = (session_index == SIZE_MAX) ? active_session_index_ : session_index;
|
||||
if (!IsValidSessionIndex(target_index)) {
|
||||
return absl::InvalidArgumentError("Invalid session index");
|
||||
}
|
||||
|
||||
// TODO: Implement actual ROM loading
|
||||
printf("[SessionCoordinator] LoadRomIntoSession: %s -> session %zu\n",
|
||||
filename.c_str(), target_index);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status SessionCoordinator::SaveActiveSession(const std::string& filename) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || !IsValidSessionIndex(active_session_index_)) {
|
||||
return absl::FailedPreconditionError("No active session");
|
||||
}
|
||||
|
||||
// TODO: Implement actual ROM saving
|
||||
printf("[SessionCoordinator] SaveActiveSession: session %zu\n", active_session_index_);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status SessionCoordinator::SaveSessionAs(size_t session_index, const std::string& filename) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || !IsValidSessionIndex(session_index) || filename.empty()) {
|
||||
return absl::InvalidArgumentError("Invalid parameters");
|
||||
}
|
||||
|
||||
// TODO: Implement actual ROM saving
|
||||
printf("[SessionCoordinator] SaveSessionAs: session %zu -> %s\n",
|
||||
session_index, filename.c_str());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void SessionCoordinator::CleanupClosedSessions() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions) return;
|
||||
|
||||
// Mark empty sessions as closed (except keep at least one)
|
||||
// TODO: Actually remove when editors become movable
|
||||
size_t loaded_count = 0;
|
||||
for (auto& session : *sessions) {
|
||||
if (session.rom.is_loaded()) {
|
||||
loaded_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (loaded_count > 0) {
|
||||
for (auto& session : *sessions) {
|
||||
if (!session.rom.is_loaded() && sessions->size() > 1) {
|
||||
session.custom_name = "[CLOSED SESSION]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateSessionCount();
|
||||
printf("[SessionCoordinator] Cleaned up closed sessions (remaining: %zu)\n", session_count_);
|
||||
}
|
||||
|
||||
void SessionCoordinator::ClearAllSessions() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions) return;
|
||||
|
||||
// Unregister all session cards
|
||||
if (card_registry_) {
|
||||
for (size_t i = 0; i < sessions->size(); ++i) {
|
||||
card_registry_->UnregisterSession(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark all sessions as closed instead of clearing
|
||||
// TODO: Actually clear when editors become movable
|
||||
for (auto& session : *sessions) {
|
||||
session.custom_name = "[CLOSED SESSION]";
|
||||
}
|
||||
|
||||
active_session_index_ = 0;
|
||||
UpdateSessionCount();
|
||||
|
||||
printf("[SessionCoordinator] Cleared all sessions\n");
|
||||
}
|
||||
|
||||
void SessionCoordinator::FocusNextSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
|
||||
size_t next_index = (active_session_index_ + 1) % sessions->size();
|
||||
SwitchToSession(next_index);
|
||||
}
|
||||
|
||||
void SessionCoordinator::FocusPreviousSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
|
||||
size_t prev_index = (active_session_index_ == 0) ?
|
||||
sessions->size() - 1 : active_session_index_ - 1;
|
||||
SwitchToSession(prev_index);
|
||||
}
|
||||
|
||||
void SessionCoordinator::FocusFirstSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
SwitchToSession(0);
|
||||
}
|
||||
|
||||
void SessionCoordinator::FocusLastSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || sessions->empty()) return;
|
||||
SwitchToSession(sessions->size() - 1);
|
||||
}
|
||||
|
||||
void SessionCoordinator::UpdateActiveSession() {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (sessions && !sessions->empty() && active_session_index_ >= sessions->size()) {
|
||||
active_session_index_ = sessions->size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::ValidateSessionIndex(size_t index) const {
|
||||
if (!IsValidSessionIndex(index)) {
|
||||
throw std::out_of_range(absl::StrFormat("Invalid session index: %zu", index));
|
||||
}
|
||||
}
|
||||
|
||||
std::string SessionCoordinator::GenerateUniqueSessionName(const std::string& base_name) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions) return base_name;
|
||||
|
||||
std::string name = base_name;
|
||||
int counter = 1;
|
||||
|
||||
while (true) {
|
||||
bool found = false;
|
||||
for (const auto& session : *sessions) {
|
||||
if (session.custom_name == name) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) break;
|
||||
|
||||
name = absl::StrFormat("%s %d", base_name, counter++);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void SessionCoordinator::ShowSessionLimitWarning() {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Maximum %zu sessions allowed", kMaxSessions),
|
||||
ToastType::kWarning);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::ShowSessionOperationResult(const std::string& operation, bool success) {
|
||||
if (toast_manager_) {
|
||||
std::string message = absl::StrFormat("%s %s", operation,
|
||||
success ? "succeeded" : "failed");
|
||||
ToastType type = success ? ToastType::kSuccess : ToastType::kError;
|
||||
toast_manager_->Show(message, type);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionTab(size_t index, bool is_active) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || index >= sessions->size()) return;
|
||||
|
||||
const auto& session = sessions->at(index);
|
||||
|
||||
ImVec4 color = GetSessionColor(index);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
|
||||
std::string tab_name = GetSessionDisplayName(index);
|
||||
if (session.rom.is_loaded()) {
|
||||
tab_name += " ";
|
||||
tab_name += ICON_MD_CHECK_CIRCLE;
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem(tab_name.c_str())) {
|
||||
if (!is_active) {
|
||||
SwitchToSession(index);
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionContextMenu(size_t index) {
|
||||
if (ImGui::MenuItem(absl::StrFormat("%s Switch to Session", ICON_MD_TAB).c_str())) {
|
||||
SwitchToSession(index);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem(absl::StrFormat("%s Rename", ICON_MD_EDIT).c_str())) {
|
||||
session_to_rename_ = index;
|
||||
strncpy(session_rename_buffer_, GetSessionDisplayName(index).c_str(),
|
||||
sizeof(session_rename_buffer_) - 1);
|
||||
session_rename_buffer_[sizeof(session_rename_buffer_) - 1] = '\0';
|
||||
show_session_rename_dialog_ = true;
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem(absl::StrFormat("%s Duplicate", ICON_MD_CONTENT_COPY).c_str())) {
|
||||
// TODO: Implement session duplication
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (HasMultipleSessions() &&
|
||||
ImGui::MenuItem(absl::StrFormat("%s Close Session", ICON_MD_CLOSE).c_str())) {
|
||||
CloseSession(index);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCoordinator::DrawSessionBadge(size_t index) {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || index >= sessions->size()) return;
|
||||
|
||||
const auto& session = sessions->at(index);
|
||||
ImVec4 color = GetSessionColor(index);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
|
||||
if (session.rom.is_loaded()) {
|
||||
ImGui::Text("%s", ICON_MD_CHECK_CIRCLE);
|
||||
} else {
|
||||
ImGui::Text("%s", ICON_MD_RADIO_BUTTON_UNCHECKED);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImVec4 SessionCoordinator::GetSessionColor(size_t index) const {
|
||||
// Generate consistent colors for sessions
|
||||
static const ImVec4 colors[] = {
|
||||
ImVec4(0.0f, 1.0f, 0.0f, 1.0f), // Green
|
||||
ImVec4(0.0f, 0.5f, 1.0f, 1.0f), // Blue
|
||||
ImVec4(1.0f, 0.5f, 0.0f, 1.0f), // Orange
|
||||
ImVec4(1.0f, 0.0f, 1.0f, 1.0f), // Magenta
|
||||
ImVec4(1.0f, 1.0f, 0.0f, 1.0f), // Yellow
|
||||
ImVec4(0.0f, 1.0f, 1.0f, 1.0f), // Cyan
|
||||
ImVec4(1.0f, 0.0f, 0.0f, 1.0f), // Red
|
||||
ImVec4(0.5f, 0.5f, 0.5f, 1.0f), // Gray
|
||||
};
|
||||
|
||||
return colors[index % (sizeof(colors) / sizeof(colors[0]))];
|
||||
}
|
||||
|
||||
std::string SessionCoordinator::GetSessionIcon(size_t index) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
if (!sessions || index >= sessions->size()) return ICON_MD_RADIO_BUTTON_UNCHECKED;
|
||||
|
||||
const auto& session = sessions->at(index);
|
||||
|
||||
if (session.rom.is_loaded()) {
|
||||
return ICON_MD_CHECK_CIRCLE;
|
||||
} else {
|
||||
return ICON_MD_RADIO_BUTTON_UNCHECKED;
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionCoordinator::IsSessionEmpty(size_t index) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
return IsValidSessionIndex(index) && sessions && !sessions->at(index).rom.is_loaded();
|
||||
}
|
||||
|
||||
bool SessionCoordinator::IsSessionClosed(size_t index) const {
|
||||
return !IsValidSessionIndex(index);
|
||||
}
|
||||
|
||||
bool SessionCoordinator::IsSessionModified(size_t index) const {
|
||||
// TODO: Implement modification tracking
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
@@ -1,164 +0,0 @@
|
||||
#ifndef YAZE_APP_EDITOR_UI_SESSION_COORDINATOR_H_
|
||||
#define YAZE_APP_EDITOR_UI_SESSION_COORDINATOR_H_
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/editor/system/session_card_registry.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/rom.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
// Forward declarations
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
class EditorManager;
|
||||
}
|
||||
}
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
// Forward declarations
|
||||
class EditorSet;
|
||||
class ToastManager;
|
||||
|
||||
/**
|
||||
* @class SessionCoordinator
|
||||
* @brief High-level orchestrator for multi-session UI
|
||||
*
|
||||
* Manages session list UI, coordinates card visibility across sessions,
|
||||
* handles session activation/deactivation, and provides session-aware editor queries.
|
||||
*
|
||||
* This class lives in the ui/ layer and can depend on both system and gui components.
|
||||
*/
|
||||
class SessionCoordinator {
|
||||
public:
|
||||
explicit SessionCoordinator(void* sessions_ptr,
|
||||
SessionCardRegistry* card_registry,
|
||||
ToastManager* toast_manager);
|
||||
~SessionCoordinator() = default;
|
||||
|
||||
// Session lifecycle management
|
||||
void CreateNewSession();
|
||||
void DuplicateCurrentSession();
|
||||
void CloseCurrentSession();
|
||||
void CloseSession(size_t index);
|
||||
void RemoveSession(size_t index);
|
||||
void SwitchToSession(size_t index);
|
||||
|
||||
// Session activation and queries
|
||||
void ActivateSession(size_t index);
|
||||
size_t GetActiveSessionIndex() const;
|
||||
void* GetActiveSession();
|
||||
void* GetSession(size_t index);
|
||||
bool HasMultipleSessions() const;
|
||||
size_t GetActiveSessionCount() const;
|
||||
bool HasDuplicateSession(const std::string& filepath) const;
|
||||
|
||||
// Session UI components
|
||||
void DrawSessionSwitcher();
|
||||
void DrawSessionManager();
|
||||
void DrawSessionRenameDialog();
|
||||
void DrawSessionTabs();
|
||||
void DrawSessionIndicator();
|
||||
|
||||
// Session information
|
||||
std::string GetSessionDisplayName(size_t index) const;
|
||||
std::string GetActiveSessionDisplayName() const;
|
||||
void RenameSession(size_t index, const std::string& new_name);
|
||||
std::string GenerateUniqueEditorTitle(const std::string& editor_name, size_t session_index) const;
|
||||
|
||||
// Session state management
|
||||
void SetActiveSessionIndex(size_t index);
|
||||
void UpdateSessionCount();
|
||||
|
||||
// Card coordination across sessions
|
||||
void ShowAllCardsInActiveSession();
|
||||
void HideAllCardsInActiveSession();
|
||||
void ShowCardsInCategory(const std::string& category);
|
||||
void HideCardsInCategory(const std::string& category);
|
||||
|
||||
// Session validation
|
||||
bool IsValidSessionIndex(size_t index) const;
|
||||
bool IsSessionActive(size_t index) const;
|
||||
bool IsSessionLoaded(size_t index) const;
|
||||
|
||||
// Session statistics
|
||||
size_t GetTotalSessionCount() const;
|
||||
size_t GetLoadedSessionCount() const;
|
||||
size_t GetEmptySessionCount() const;
|
||||
|
||||
// Session operations with error handling
|
||||
absl::Status LoadRomIntoSession(const std::string& filename, size_t session_index = SIZE_MAX);
|
||||
absl::Status SaveActiveSession(const std::string& filename = "");
|
||||
absl::Status SaveSessionAs(size_t session_index, const std::string& filename);
|
||||
|
||||
// Session cleanup
|
||||
void CleanupClosedSessions();
|
||||
void ClearAllSessions();
|
||||
|
||||
// Session navigation
|
||||
void FocusNextSession();
|
||||
void FocusPreviousSession();
|
||||
void FocusFirstSession();
|
||||
void FocusLastSession();
|
||||
|
||||
// Session UI state
|
||||
void ShowSessionSwitcher() { show_session_switcher_ = true; }
|
||||
void HideSessionSwitcher() { show_session_switcher_ = false; }
|
||||
void ToggleSessionSwitcher() { show_session_switcher_ = !show_session_switcher_; }
|
||||
bool IsSessionSwitcherVisible() const { return show_session_switcher_; }
|
||||
|
||||
void ShowSessionManager() { show_session_manager_ = true; }
|
||||
void HideSessionManager() { show_session_manager_ = false; }
|
||||
void ToggleSessionManager() { show_session_manager_ = !show_session_manager_; }
|
||||
bool IsSessionManagerVisible() const { return show_session_manager_; }
|
||||
|
||||
private:
|
||||
// Core dependencies
|
||||
void* sessions_ptr_; // std::deque<EditorManager::RomSession>*
|
||||
SessionCardRegistry* card_registry_;
|
||||
ToastManager* toast_manager_;
|
||||
|
||||
// Session state
|
||||
size_t active_session_index_ = 0;
|
||||
size_t session_count_ = 0;
|
||||
|
||||
// UI state
|
||||
bool show_session_switcher_ = false;
|
||||
bool show_session_manager_ = false;
|
||||
bool show_session_rename_dialog_ = false;
|
||||
size_t session_to_rename_ = 0;
|
||||
char session_rename_buffer_[256] = {};
|
||||
|
||||
// Session limits
|
||||
static constexpr size_t kMaxSessions = 8;
|
||||
static constexpr size_t kMinSessions = 1;
|
||||
|
||||
// Helper methods
|
||||
void UpdateActiveSession();
|
||||
void ValidateSessionIndex(size_t index) const;
|
||||
std::string GenerateUniqueSessionName(const std::string& base_name) const;
|
||||
void ShowSessionLimitWarning();
|
||||
void ShowSessionOperationResult(const std::string& operation, bool success);
|
||||
|
||||
// UI helper methods
|
||||
void DrawSessionTab(size_t index, bool is_active);
|
||||
void DrawSessionContextMenu(size_t index);
|
||||
void DrawSessionBadge(size_t index);
|
||||
ImVec4 GetSessionColor(size_t index) const;
|
||||
std::string GetSessionIcon(size_t index) const;
|
||||
|
||||
// Session validation helpers
|
||||
bool IsSessionEmpty(size_t index) const;
|
||||
bool IsSessionClosed(size_t index) const;
|
||||
bool IsSessionModified(size_t index) const;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_UI_SESSION_COORDINATOR_H_
|
||||
492
src/app/editor/ui/ui_coordinator.cc
Normal file
492
src/app/editor/ui/ui_coordinator.cc
Normal file
@@ -0,0 +1,492 @@
|
||||
#include "app/editor/ui/ui_coordinator.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/editor/editor_manager.h"
|
||||
#include "app/editor/system/editor_registry.h"
|
||||
#include "app/editor/system/popup_manager.h"
|
||||
#include "app/editor/system/project_manager.h"
|
||||
#include "app/editor/system/rom_file_manager.h"
|
||||
#include "app/editor/system/session_coordinator.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/editor/system/window_delegate.h"
|
||||
#include "app/editor/ui/welcome_screen.h"
|
||||
#include "app/gui/core/icons.h"
|
||||
#include "app/gui/core/style.h"
|
||||
#include "app/gui/core/theme_manager.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
UICoordinator::UICoordinator(
|
||||
EditorManager* editor_manager,
|
||||
RomFileManager& rom_manager,
|
||||
ProjectManager& project_manager,
|
||||
EditorRegistry& editor_registry,
|
||||
SessionCoordinator& session_coordinator,
|
||||
WindowDelegate& window_delegate,
|
||||
ToastManager& toast_manager,
|
||||
PopupManager& popup_manager)
|
||||
: editor_manager_(editor_manager),
|
||||
rom_manager_(rom_manager),
|
||||
project_manager_(project_manager),
|
||||
editor_registry_(editor_registry),
|
||||
session_coordinator_(session_coordinator),
|
||||
window_delegate_(window_delegate),
|
||||
toast_manager_(toast_manager),
|
||||
popup_manager_(popup_manager) {
|
||||
|
||||
// Initialize welcome screen
|
||||
welcome_screen_ = std::make_unique<WelcomeScreen>();
|
||||
}
|
||||
|
||||
void UICoordinator::DrawAllUI() {
|
||||
// Apply Material Design styling
|
||||
ApplyMaterialDesignStyling();
|
||||
|
||||
// Draw all UI components in order
|
||||
DrawMenuBarExtras();
|
||||
DrawContextSensitiveCardControl();
|
||||
DrawSessionSwitcher();
|
||||
DrawSessionManager();
|
||||
DrawSessionRenameDialog();
|
||||
DrawLayoutPresets();
|
||||
DrawWelcomeScreen();
|
||||
DrawProjectHelp();
|
||||
DrawWindowManagementUI();
|
||||
|
||||
// Draw all popups
|
||||
DrawAllPopups();
|
||||
}
|
||||
|
||||
void UICoordinator::DrawMenuBarExtras() {
|
||||
auto* current_rom = rom_manager_.GetCurrentRom();
|
||||
std::string version_text = absl::StrFormat("v%s", editor_manager_->version().c_str());
|
||||
float version_width = ImGui::CalcTextSize(version_text.c_str()).x;
|
||||
float session_rom_area_width = 280.0f;
|
||||
|
||||
ImGui::SameLine(ImGui::GetWindowWidth() - version_width - 10 - session_rom_area_width);
|
||||
|
||||
// Session indicator with Material Design styling
|
||||
if (session_coordinator_.HasMultipleSessions()) {
|
||||
std::string session_button_text = absl::StrFormat("%s%zu", ICON_MD_TAB,
|
||||
session_coordinator_.GetActiveSessionCount());
|
||||
|
||||
// Material Design button styling
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, gui::GetPrimaryVec4());
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetPrimaryHoverVec4());
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, gui::GetPrimaryActiveVec4());
|
||||
|
||||
if (ImGui::SmallButton(session_button_text.c_str())) {
|
||||
session_coordinator_.ToggleSessionSwitcher();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Sessions: %zu active\nClick to switch",
|
||||
session_coordinator_.GetActiveSessionCount());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
// ROM information display with Material Design card styling
|
||||
if (current_rom && current_rom->is_loaded()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
|
||||
ImGui::Text("%s %s", ICON_MD_INSERT_DRIVE_FILE, current_rom->title().c_str());
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
// Version info with subtle styling
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextDisabledVec4());
|
||||
ImGui::Text("%s", version_text.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
void UICoordinator::DrawContextSensitiveCardControl() {
|
||||
// Get current editor and determine category
|
||||
auto* current_editor = editor_manager_->GetCurrentEditorSet();
|
||||
if (!current_editor) return;
|
||||
|
||||
// Find active card-based editor
|
||||
Editor* active_editor = nullptr;
|
||||
for (auto* editor : current_editor->active_editors_) {
|
||||
if (*editor->active() && editor_registry_.IsCardBasedEditor(editor->type())) {
|
||||
active_editor = editor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!active_editor) return;
|
||||
|
||||
std::string category = editor_registry_.GetEditorCategory(active_editor->type());
|
||||
|
||||
// Draw compact card control with session awareness
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
if (session_coordinator_.HasMultipleSessions()) {
|
||||
std::string session_prefix = absl::StrFormat("s%zu", session_coordinator_.GetActiveSessionIndex());
|
||||
card_manager.DrawCompactCardControlWithSession(category, session_prefix);
|
||||
} else {
|
||||
card_manager.DrawCompactCardControl(category);
|
||||
}
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionSwitcher() {
|
||||
if (!show_session_switcher_) return;
|
||||
|
||||
// Material Design dialog styling
|
||||
ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(16, 16));
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, gui::GetSurfaceVec4());
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, gui::GetOutlineVec4());
|
||||
|
||||
if (ImGui::Begin("Session Switcher", &show_session_switcher_,
|
||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse)) {
|
||||
|
||||
// Header with Material Design typography
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, gui::GetOnSurfaceVec4());
|
||||
ImGui::Text("%s Session Switcher", ICON_MD_TAB);
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Separator();
|
||||
|
||||
// Session list with Material Design list styling
|
||||
for (size_t i = 0; i < session_coordinator_.GetActiveSessionCount(); ++i) {
|
||||
std::string session_name = session_coordinator_.GetSessionDisplayName(i);
|
||||
bool is_active = (i == session_coordinator_.GetActiveSessionIndex());
|
||||
|
||||
// Active session highlighting
|
||||
if (is_active) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, gui::GetPrimaryVec4());
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, gui::GetPrimaryHoverVec4());
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, gui::GetOnPrimaryVec4());
|
||||
}
|
||||
|
||||
std::string button_text = absl::StrFormat("%s %s",
|
||||
is_active ? ICON_MD_RADIO_BUTTON_CHECKED : ICON_MD_RADIO_BUTTON_UNCHECKED,
|
||||
session_name.c_str());
|
||||
|
||||
if (ImGui::Button(button_text.c_str(), ImVec2(-1, 0))) {
|
||||
session_coordinator_.SwitchToSession(i);
|
||||
show_session_switcher_ = false;
|
||||
}
|
||||
|
||||
if (is_active) {
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Action buttons with Material Design styling
|
||||
if (ImGui::Button(absl::StrFormat("%s New Session", ICON_MD_ADD).c_str(), ImVec2(-1, 0))) {
|
||||
session_coordinator_.CreateNewSession();
|
||||
show_session_switcher_ = false;
|
||||
}
|
||||
|
||||
if (ImGui::Button(absl::StrFormat("%s Close", ICON_MD_CLOSE).c_str(), ImVec2(-1, 0))) {
|
||||
show_session_switcher_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionManager() {
|
||||
// TODO: Implement session manager dialog
|
||||
// This would be a more comprehensive session management interface
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionRenameDialog() {
|
||||
// TODO: Implement session rename dialog
|
||||
// This would allow users to rename sessions for better organization
|
||||
}
|
||||
|
||||
void UICoordinator::DrawLayoutPresets() {
|
||||
// TODO: Implement layout presets UI
|
||||
// This would show available layout presets (Developer, Designer, Modder)
|
||||
}
|
||||
|
||||
void UICoordinator::DrawWelcomeScreen() {
|
||||
if (!show_welcome_screen_) return;
|
||||
|
||||
if (welcome_screen_) {
|
||||
welcome_screen_->Show(&show_welcome_screen_);
|
||||
}
|
||||
}
|
||||
|
||||
void UICoordinator::DrawProjectHelp() {
|
||||
// TODO: Implement project help UI
|
||||
// This would show project-specific help and documentation
|
||||
}
|
||||
|
||||
void UICoordinator::DrawWindowManagementUI() {
|
||||
// TODO: Implement window management UI
|
||||
// This would provide controls for window visibility, docking, etc.
|
||||
}
|
||||
|
||||
void UICoordinator::DrawAllPopups() {
|
||||
// Draw all registered popups
|
||||
popup_manager_.DrawPopups();
|
||||
}
|
||||
|
||||
void UICoordinator::ShowPopup(const std::string& popup_name) {
|
||||
popup_manager_.Show(popup_name.c_str());
|
||||
}
|
||||
|
||||
void UICoordinator::HidePopup(const std::string& popup_name) {
|
||||
popup_manager_.Hide(popup_name.c_str());
|
||||
}
|
||||
|
||||
void UICoordinator::ShowEditorSelection() {
|
||||
show_editor_selection_ = true;
|
||||
}
|
||||
|
||||
void UICoordinator::ShowDisplaySettings() {
|
||||
show_display_settings_ = true;
|
||||
ShowPopup("Display Settings");
|
||||
}
|
||||
|
||||
void UICoordinator::ShowSessionSwitcher() {
|
||||
show_session_switcher_ = true;
|
||||
}
|
||||
|
||||
void UICoordinator::HideCurrentEditorCards() {
|
||||
// TODO: Implement card hiding logic
|
||||
// This would hide cards for the current editor
|
||||
}
|
||||
|
||||
void UICoordinator::ShowAllWindows() {
|
||||
window_delegate_.ShowAllWindows();
|
||||
}
|
||||
|
||||
void UICoordinator::HideAllWindows() {
|
||||
window_delegate_.HideAllWindows();
|
||||
}
|
||||
|
||||
void UICoordinator::ApplyMaterialDesignStyling() {
|
||||
// Apply Material Design 3 color scheme
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
// Set Material Design colors
|
||||
style.Colors[ImGuiCol_WindowBg] = gui::GetSurfaceVec4();
|
||||
style.Colors[ImGuiCol_ChildBg] = gui::GetSurfaceVariantVec4();
|
||||
style.Colors[ImGuiCol_PopupBg] = gui::GetSurfaceContainerVec4();
|
||||
style.Colors[ImGuiCol_Border] = gui::GetOutlineVec4();
|
||||
style.Colors[ImGuiCol_BorderShadow] = gui::GetShadowVec4();
|
||||
|
||||
// Text colors
|
||||
style.Colors[ImGuiCol_Text] = gui::GetOnSurfaceVec4();
|
||||
style.Colors[ImGuiCol_TextDisabled] = gui::GetOnSurfaceVariantVec4();
|
||||
|
||||
// Button colors
|
||||
style.Colors[ImGuiCol_Button] = gui::GetSurfaceContainerHighestVec4();
|
||||
style.Colors[ImGuiCol_ButtonHovered] = gui::GetSurfaceContainerHighVec4();
|
||||
style.Colors[ImGuiCol_ButtonActive] = gui::GetPrimaryVec4();
|
||||
|
||||
// Header colors
|
||||
style.Colors[ImGuiCol_Header] = gui::GetSurfaceContainerHighVec4();
|
||||
style.Colors[ImGuiCol_HeaderHovered] = gui::GetSurfaceContainerHighestVec4();
|
||||
style.Colors[ImGuiCol_HeaderActive] = gui::GetPrimaryVec4();
|
||||
|
||||
// Frame colors
|
||||
style.Colors[ImGuiCol_FrameBg] = gui::GetSurfaceContainerHighestVec4();
|
||||
style.Colors[ImGuiCol_FrameBgHovered] = gui::GetSurfaceContainerHighVec4();
|
||||
style.Colors[ImGuiCol_FrameBgActive] = gui::GetPrimaryVec4();
|
||||
|
||||
// Scrollbar colors
|
||||
style.Colors[ImGuiCol_ScrollbarBg] = gui::GetSurfaceContainerVec4();
|
||||
style.Colors[ImGuiCol_ScrollbarGrab] = gui::GetOutlineVec4();
|
||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = gui::GetOnSurfaceVariantVec4();
|
||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = gui::GetOnSurfaceVec4();
|
||||
|
||||
// Slider colors
|
||||
style.Colors[ImGuiCol_SliderGrab] = gui::GetPrimaryVec4();
|
||||
style.Colors[ImGuiCol_SliderGrabActive] = gui::GetPrimaryActiveVec4();
|
||||
|
||||
// Tab colors
|
||||
style.Colors[ImGuiCol_Tab] = gui::GetSurfaceContainerHighVec4();
|
||||
style.Colors[ImGuiCol_TabHovered] = gui::GetSurfaceContainerHighestVec4();
|
||||
style.Colors[ImGuiCol_TabActive] = gui::GetPrimaryVec4();
|
||||
style.Colors[ImGuiCol_TabUnfocused] = gui::GetSurfaceContainerVec4();
|
||||
style.Colors[ImGuiCol_TabUnfocusedActive] = gui::GetPrimaryActiveVec4();
|
||||
|
||||
// Title bar colors
|
||||
style.Colors[ImGuiCol_TitleBg] = gui::GetSurfaceContainerVec4();
|
||||
style.Colors[ImGuiCol_TitleBgActive] = gui::GetSurfaceContainerHighVec4();
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = gui::GetSurfaceContainerVec4();
|
||||
|
||||
// Menu bar colors
|
||||
style.Colors[ImGuiCol_MenuBarBg] = gui::GetSurfaceContainerVec4();
|
||||
|
||||
// Modal dimming
|
||||
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.6f);
|
||||
}
|
||||
|
||||
void UICoordinator::UpdateThemeElements() {
|
||||
// Update theme-specific elements
|
||||
ApplyMaterialDesignStyling();
|
||||
}
|
||||
|
||||
void UICoordinator::DrawThemePreview() {
|
||||
// TODO: Implement theme preview
|
||||
// This would show a preview of the current theme
|
||||
}
|
||||
|
||||
// Helper methods for drawing operations
|
||||
void UICoordinator::DrawSessionIndicator() {
|
||||
// TODO: Implement session indicator
|
||||
}
|
||||
|
||||
void UICoordinator::DrawVersionInfo() {
|
||||
// TODO: Implement version info display
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionTabs() {
|
||||
// TODO: Implement session tabs
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionBadges() {
|
||||
// TODO: Implement session badges
|
||||
}
|
||||
|
||||
// Material Design component helpers
|
||||
void UICoordinator::DrawMaterialButton(const std::string& text, const std::string& icon,
|
||||
std::function<void()> callback, bool enabled) {
|
||||
if (!enabled) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighestVec4());
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, gui::GetOnSurfaceVariantVec4());
|
||||
}
|
||||
|
||||
std::string button_text = absl::StrFormat("%s %s", icon.c_str(), text.c_str());
|
||||
if (ImGui::Button(button_text.c_str())) {
|
||||
if (enabled && callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
}
|
||||
|
||||
void UICoordinator::DrawMaterialCard(const std::string& title, const std::string& content) {
|
||||
// TODO: Implement Material Design card component
|
||||
}
|
||||
|
||||
void UICoordinator::DrawMaterialDialog(const std::string& title, std::function<void()> content) {
|
||||
// TODO: Implement Material Design dialog component
|
||||
}
|
||||
|
||||
// Layout and positioning helpers
|
||||
void UICoordinator::CenterWindow(const std::string& window_name) {
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
void UICoordinator::PositionWindow(const std::string& window_name, float x, float y) {
|
||||
ImGui::SetNextWindowPos(ImVec2(x, y), ImGuiCond_Appearing);
|
||||
}
|
||||
|
||||
void UICoordinator::SetWindowSize(const std::string& window_name, float width, float height) {
|
||||
ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_FirstUseEver);
|
||||
}
|
||||
|
||||
// Icon and theming helpers
|
||||
std::string UICoordinator::GetIconForEditor(EditorType type) const {
|
||||
switch (type) {
|
||||
case EditorType::kDungeon: return ICON_MD_CASTLE;
|
||||
case EditorType::kOverworld: return ICON_MD_MAP;
|
||||
case EditorType::kGraphics: return ICON_MD_IMAGE;
|
||||
case EditorType::kPalette: return ICON_MD_PALETTE;
|
||||
case EditorType::kSprite: return ICON_MD_TOYS;
|
||||
case EditorType::kScreen: return ICON_MD_TV;
|
||||
case EditorType::kMessage: return ICON_MD_CHAT_BUBBLE;
|
||||
case EditorType::kMusic: return ICON_MD_MUSIC_NOTE;
|
||||
case EditorType::kAssembly: return ICON_MD_CODE;
|
||||
case EditorType::kHex: return ICON_MD_DATA_ARRAY;
|
||||
case EditorType::kEmulator: return ICON_MD_PLAY_ARROW;
|
||||
case EditorType::kSettings: return ICON_MD_SETTINGS;
|
||||
default: return ICON_MD_HELP;
|
||||
}
|
||||
}
|
||||
|
||||
std::string UICoordinator::GetColorForEditor(EditorType type) const {
|
||||
// TODO: Implement editor-specific colors
|
||||
return "primary"; // Placeholder for now
|
||||
}
|
||||
|
||||
void UICoordinator::ApplyEditorTheme(EditorType type) {
|
||||
// TODO: Implement editor-specific theming
|
||||
}
|
||||
|
||||
// Session UI helpers
|
||||
void UICoordinator::DrawSessionList() {
|
||||
// TODO: Implement session list
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionControls() {
|
||||
// TODO: Implement session controls
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionInfo() {
|
||||
// TODO: Implement session info
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionStatus() {
|
||||
// TODO: Implement session status
|
||||
}
|
||||
|
||||
// Popup helpers
|
||||
void UICoordinator::DrawHelpMenuPopups() {
|
||||
// TODO: Implement help menu popups
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSettingsPopups() {
|
||||
// TODO: Implement settings popups
|
||||
}
|
||||
|
||||
void UICoordinator::DrawProjectPopups() {
|
||||
// TODO: Implement project popups
|
||||
}
|
||||
|
||||
void UICoordinator::DrawSessionPopups() {
|
||||
// TODO: Implement session popups
|
||||
}
|
||||
|
||||
// Window management helpers
|
||||
void UICoordinator::DrawWindowControls() {
|
||||
// TODO: Implement window controls
|
||||
}
|
||||
|
||||
void UICoordinator::DrawLayoutControls() {
|
||||
// TODO: Implement layout controls
|
||||
}
|
||||
|
||||
void UICoordinator::DrawDockingControls() {
|
||||
// TODO: Implement docking controls
|
||||
}
|
||||
|
||||
// Performance and debug UI
|
||||
void UICoordinator::DrawPerformanceUI() {
|
||||
// TODO: Implement performance UI
|
||||
}
|
||||
|
||||
void UICoordinator::DrawDebugUI() {
|
||||
// TODO: Implement debug UI
|
||||
}
|
||||
|
||||
void UICoordinator::DrawTestingUI() {
|
||||
// TODO: Implement testing UI
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
180
src/app/editor/ui/ui_coordinator.h
Normal file
180
src/app/editor/ui/ui_coordinator.h
Normal file
@@ -0,0 +1,180 @@
|
||||
#ifndef YAZE_APP_EDITOR_UI_UI_COORDINATOR_H_
|
||||
#define YAZE_APP_EDITOR_UI_UI_COORDINATOR_H_
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/editor/system/popup_manager.h"
|
||||
#include "app/editor/ui/welcome_screen.h"
|
||||
#include "app/gui/core/icons.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
// Forward declarations to avoid circular dependencies
|
||||
class EditorManager;
|
||||
class RomFileManager;
|
||||
class ProjectManager;
|
||||
class EditorRegistry;
|
||||
class SessionCoordinator;
|
||||
class ToastManager;
|
||||
class WindowDelegate;
|
||||
|
||||
/**
|
||||
* @class UICoordinator
|
||||
* @brief Handles all UI drawing operations and state management
|
||||
*
|
||||
* Extracted from EditorManager to provide focused UI coordination:
|
||||
* - Drawing operations (menus, dialogs, screens)
|
||||
* - UI state management (visibility, focus, layout)
|
||||
* - Popup and dialog coordination
|
||||
* - Welcome screen and session UI
|
||||
* - Material Design theming and icons
|
||||
*
|
||||
* This class follows the Single Responsibility Principle by focusing solely
|
||||
* on UI presentation and user interaction, delegating business logic to
|
||||
* specialized managers.
|
||||
*/
|
||||
class UICoordinator {
|
||||
public:
|
||||
// Constructor takes references to the managers it coordinates with
|
||||
UICoordinator(EditorManager* editor_manager,
|
||||
RomFileManager& rom_manager,
|
||||
ProjectManager& project_manager,
|
||||
EditorRegistry& editor_registry,
|
||||
SessionCoordinator& session_coordinator,
|
||||
WindowDelegate& window_delegate,
|
||||
ToastManager& toast_manager,
|
||||
PopupManager& popup_manager);
|
||||
~UICoordinator() = default;
|
||||
|
||||
// Non-copyable due to reference members
|
||||
UICoordinator(const UICoordinator&) = delete;
|
||||
UICoordinator& operator=(const UICoordinator&) = delete;
|
||||
|
||||
// Main UI drawing interface
|
||||
void DrawAllUI();
|
||||
void DrawMenuBarExtras();
|
||||
void DrawContextSensitiveCardControl();
|
||||
|
||||
// Session UI components
|
||||
void DrawSessionSwitcher();
|
||||
void DrawSessionManager();
|
||||
void DrawSessionRenameDialog();
|
||||
void DrawLayoutPresets();
|
||||
|
||||
// Welcome screen and project UI
|
||||
void DrawWelcomeScreen();
|
||||
void DrawProjectHelp();
|
||||
|
||||
// Window management UI
|
||||
void DrawWindowManagementUI();
|
||||
|
||||
// Popup and dialog management
|
||||
void DrawAllPopups();
|
||||
void ShowPopup(const std::string& popup_name);
|
||||
void HidePopup(const std::string& popup_name);
|
||||
|
||||
// UI state management
|
||||
void ShowEditorSelection();
|
||||
void ShowDisplaySettings();
|
||||
void ShowSessionSwitcher();
|
||||
void HideCurrentEditorCards();
|
||||
|
||||
// Window visibility management
|
||||
void ShowAllWindows();
|
||||
void HideAllWindows();
|
||||
|
||||
// UI state queries
|
||||
bool IsEditorSelectionVisible() const { return show_editor_selection_; }
|
||||
bool IsDisplaySettingsVisible() const { return show_display_settings_; }
|
||||
bool IsSessionSwitcherVisible() const { return show_session_switcher_; }
|
||||
bool IsWelcomeScreenVisible() const { return show_welcome_screen_; }
|
||||
|
||||
// UI state setters
|
||||
void SetEditorSelectionVisible(bool visible) { show_editor_selection_ = visible; }
|
||||
void SetDisplaySettingsVisible(bool visible) { show_display_settings_ = visible; }
|
||||
void SetSessionSwitcherVisible(bool visible) { show_session_switcher_ = visible; }
|
||||
void SetWelcomeScreenVisible(bool visible) { show_welcome_screen_ = visible; }
|
||||
|
||||
// Theme and styling helpers
|
||||
void ApplyMaterialDesignStyling();
|
||||
void UpdateThemeElements();
|
||||
void DrawThemePreview();
|
||||
|
||||
private:
|
||||
// References to coordinated managers
|
||||
EditorManager* editor_manager_;
|
||||
RomFileManager& rom_manager_;
|
||||
ProjectManager& project_manager_;
|
||||
EditorRegistry& editor_registry_;
|
||||
SessionCoordinator& session_coordinator_;
|
||||
WindowDelegate& window_delegate_;
|
||||
ToastManager& toast_manager_;
|
||||
PopupManager& popup_manager_;
|
||||
|
||||
// UI state flags
|
||||
bool show_editor_selection_ = false;
|
||||
bool show_display_settings_ = false;
|
||||
bool show_session_switcher_ = false;
|
||||
bool show_welcome_screen_ = true;
|
||||
bool show_global_search_ = false;
|
||||
bool show_performance_dashboard_ = false;
|
||||
bool show_imgui_demo_ = false;
|
||||
bool show_imgui_metrics_ = false;
|
||||
bool show_test_dashboard_ = false;
|
||||
|
||||
// Welcome screen component
|
||||
std::unique_ptr<WelcomeScreen> welcome_screen_;
|
||||
|
||||
// Helper methods for drawing operations
|
||||
void DrawSessionIndicator();
|
||||
void DrawVersionInfo();
|
||||
void DrawSessionTabs();
|
||||
void DrawSessionBadges();
|
||||
|
||||
// Material Design component helpers
|
||||
void DrawMaterialButton(const std::string& text, const std::string& icon,
|
||||
std::function<void()> callback, bool enabled = true);
|
||||
void DrawMaterialCard(const std::string& title, const std::string& content);
|
||||
void DrawMaterialDialog(const std::string& title, std::function<void()> content);
|
||||
|
||||
// Layout and positioning helpers
|
||||
void CenterWindow(const std::string& window_name);
|
||||
void PositionWindow(const std::string& window_name, float x, float y);
|
||||
void SetWindowSize(const std::string& window_name, float width, float height);
|
||||
|
||||
// Icon and theming helpers
|
||||
std::string GetIconForEditor(EditorType type) const;
|
||||
std::string GetColorForEditor(EditorType type) const;
|
||||
void ApplyEditorTheme(EditorType type);
|
||||
|
||||
// Session UI helpers
|
||||
void DrawSessionList();
|
||||
void DrawSessionControls();
|
||||
void DrawSessionInfo();
|
||||
void DrawSessionStatus();
|
||||
|
||||
// Popup helpers
|
||||
void DrawHelpMenuPopups();
|
||||
void DrawSettingsPopups();
|
||||
void DrawProjectPopups();
|
||||
void DrawSessionPopups();
|
||||
|
||||
// Window management helpers
|
||||
void DrawWindowControls();
|
||||
void DrawLayoutControls();
|
||||
void DrawDockingControls();
|
||||
|
||||
// Performance and debug UI
|
||||
void DrawPerformanceUI();
|
||||
void DrawDebugUI();
|
||||
void DrawTestingUI();
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_UI_UI_COORDINATOR_H_
|
||||
Reference in New Issue
Block a user