feat(editor): enhance card-based editor functionality and streamline initialization
- Updated EditorManager to support new card-based editors, including Emulator, Hex, and Assembly editors. - Added centralized registration of editor cards with EditorCardManager, improving visibility management. - Implemented methods to retrieve editor types from categories and manage card visibility dynamically. - Enhanced initialization processes for various editors to ensure proper card registration and default visibility settings. Benefits: - Improved user experience by organizing editor cards and providing quick access to new editor functionalities. - Streamlined editor management, making it easier to switch between different editing contexts and enhancing overall workflow efficiency.
This commit is contained in:
@@ -174,6 +174,17 @@ FolderItem LoadFolder(const std::string& folder) {
|
||||
|
||||
void AssemblyEditor::Initialize() {
|
||||
text_editor_.SetLanguageDefinition(GetAssemblyLanguageDef());
|
||||
|
||||
// Register cards with EditorCardManager
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
card_manager.RegisterCard({.card_id = "assembly.editor", .display_name = "Assembly Editor",
|
||||
.icon = ICON_MD_CODE, .category = "Assembly",
|
||||
.shortcut_hint = "", .priority = 10});
|
||||
card_manager.RegisterCard({.card_id = "assembly.file_browser", .display_name = "File Browser",
|
||||
.icon = ICON_MD_FOLDER_OPEN, .category = "Assembly",
|
||||
.shortcut_hint = "", .priority = 20});
|
||||
|
||||
// Don't show by default - only show when user explicitly opens Assembly Editor
|
||||
}
|
||||
|
||||
absl::Status AssemblyEditor::Load() {
|
||||
|
||||
@@ -108,6 +108,10 @@ void DungeonEditorV2::Initialize(gfx::IRenderer* renderer, Rom* rom) {
|
||||
.visibility_flag = &show_debug_controls_,
|
||||
.priority = 80
|
||||
});
|
||||
|
||||
// Show control panel and room selector by default when Dungeon Editor is activated
|
||||
show_control_panel_ = true;
|
||||
show_room_selector_ = true;
|
||||
}
|
||||
|
||||
void DungeonEditorV2::Initialize() {}
|
||||
@@ -187,32 +191,6 @@ absl::Status DungeonEditorV2::Update() {
|
||||
// CARD-BASED EDITOR: All windows are independent top-level cards
|
||||
// No parent wrapper - this allows closing control panel without affecting rooms
|
||||
|
||||
// Optional control panel (can be hidden/minimized)
|
||||
if (show_control_panel_) {
|
||||
DrawControlPanel();
|
||||
} else if (control_panel_minimized_) {
|
||||
// Draw floating icon button to reopen
|
||||
ImGui::SetNextWindowPos(ImVec2(10, 100));
|
||||
ImGui::SetNextWindowSize(ImVec2(50, 50));
|
||||
ImGuiWindowFlags icon_flags = ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoDocking;
|
||||
|
||||
if (ImGui::Begin("##DungeonControlIcon", nullptr, icon_flags)) {
|
||||
if (ImGui::Button(ICON_MD_CASTLE, ImVec2(40, 40))) {
|
||||
show_control_panel_ = true;
|
||||
control_panel_minimized_ = false;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Open Dungeon Controls");
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// Render all independent cards (these are ALL top-level windows now)
|
||||
DrawLayout();
|
||||
|
||||
return absl::OkStatus();
|
||||
@@ -235,73 +213,6 @@ absl::Status DungeonEditorV2::Save() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void DungeonEditorV2::DrawToolset() {
|
||||
// Draw VSCode-style sidebar using EditorCardManager
|
||||
// auto& card_manager = gui::EditorCardManager::Get();
|
||||
// card_manager.DrawSidebar("Dungeon");
|
||||
}
|
||||
|
||||
void DungeonEditorV2::DrawControlPanel() {
|
||||
// Small, collapsible control panel for dungeon editor
|
||||
ImGui::SetNextWindowSize(ImVec2(280, 280), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(10, 100), ImGuiCond_FirstUseEver);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_None;
|
||||
|
||||
if (ImGui::Begin(ICON_MD_CASTLE " Dungeon Controls", &show_control_panel_, flags)) {
|
||||
ImGui::TextWrapped("Welcome to Dungeon Editor V2!");
|
||||
ImGui::TextDisabled("Use checkboxes below to open cards");
|
||||
ImGui::Separator();
|
||||
|
||||
DrawToolset();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Quick Toggles:");
|
||||
|
||||
// Checkbox grid for quick toggles
|
||||
if (ImGui::BeginTable("##QuickToggles", 2, ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("Rooms", &show_room_selector_);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("Matrix", &show_room_matrix_);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("Entrances", &show_entrances_list_);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("Graphics", &show_room_graphics_);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("Objects", &show_object_editor_);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("Palette", &show_palette_editor_);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("Debug", &show_debug_controls_);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Minimize button
|
||||
if (ImGui::SmallButton(ICON_MD_MINIMIZE " Minimize to Icon")) {
|
||||
control_panel_minimized_ = true;
|
||||
show_control_panel_ = false;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Collapse to floating icon. Rooms stay open.");
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void DungeonEditorV2::DrawLayout() {
|
||||
// NO TABLE LAYOUT - All independent dockable EditorCards
|
||||
// All cards check their visibility flags and can be closed with X button
|
||||
|
||||
@@ -102,13 +102,11 @@ class DungeonEditorV2 : public Editor {
|
||||
// Simple UI layout
|
||||
void DrawLayout();
|
||||
void DrawRoomTab(int room_id);
|
||||
void DrawToolset();
|
||||
void DrawRoomMatrixCard();
|
||||
void DrawRoomsListCard();
|
||||
void DrawEntrancesListCard();
|
||||
void DrawRoomGraphicsCard();
|
||||
void DrawDebugControlsCard();
|
||||
void DrawControlPanel();
|
||||
|
||||
// Texture processing (critical for rendering)
|
||||
void ProcessDeferredTextures();
|
||||
|
||||
@@ -91,17 +91,22 @@ std::string GetEditorName(EditorType type) {
|
||||
} // namespace
|
||||
|
||||
// Static registry of editors that use the card-based layout system
|
||||
// These editors register their cards with EditorCardManager
|
||||
// These editors register their cards with EditorCardManager and manage their own windows
|
||||
// They do NOT need the traditional ImGui::Begin/End wrapper - they create cards internally
|
||||
bool EditorManager::IsCardBasedEditor(EditorType type) {
|
||||
switch (type) {
|
||||
case EditorType::kDungeon:
|
||||
case EditorType::kPalette:
|
||||
case EditorType::kGraphics:
|
||||
case EditorType::kScreen:
|
||||
case EditorType::kSprite:
|
||||
case EditorType::kMessage:
|
||||
case EditorType::kOverworld:
|
||||
case EditorType::kDungeon: // ✅ Full card system
|
||||
case EditorType::kPalette: // ✅ Full card system
|
||||
case EditorType::kGraphics: // ✅ EditorCard wrappers + Toolset
|
||||
case EditorType::kScreen: // ✅ EditorCard wrappers + Toolset
|
||||
case EditorType::kSprite: // ✅ EditorCard wrappers + Toolset
|
||||
case EditorType::kOverworld: // ✅ Inline EditorCard + Toolset
|
||||
case EditorType::kEmulator: // ✅ Emulator UI panels as cards
|
||||
case EditorType::kMessage: // ✅ Message editor cards
|
||||
case EditorType::kHex: // ✅ Memory/Hex editor
|
||||
case EditorType::kAssembly: // ✅ Assembly editor
|
||||
return true;
|
||||
// Music: Traditional UI - needs wrapper
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -127,11 +132,30 @@ std::string EditorManager::GetEditorCategory(EditorType type) {
|
||||
return "Screen";
|
||||
case EditorType::kEmulator:
|
||||
return "Emulator";
|
||||
case EditorType::kHex:
|
||||
return "Memory";
|
||||
case EditorType::kAssembly:
|
||||
return "Assembly";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
EditorType EditorManager::GetEditorTypeFromCategory(const std::string& category) {
|
||||
if (category == "Dungeon") return EditorType::kDungeon;
|
||||
if (category == "Palette") return EditorType::kPalette;
|
||||
if (category == "Graphics") return EditorType::kGraphics;
|
||||
if (category == "Overworld") return EditorType::kOverworld;
|
||||
if (category == "Sprite") return EditorType::kSprite;
|
||||
if (category == "Message") return EditorType::kMessage;
|
||||
if (category == "Music") return EditorType::kMusic;
|
||||
if (category == "Screen") return EditorType::kScreen;
|
||||
if (category == "Emulator") return EditorType::kEmulator;
|
||||
if (category == "Memory") return EditorType::kHex;
|
||||
if (category == "Assembly") return EditorType::kAssembly;
|
||||
return EditorType::kUnknown;
|
||||
}
|
||||
|
||||
void EditorManager::HideCurrentEditorCards() {
|
||||
if (!current_editor_) {
|
||||
return;
|
||||
@@ -221,6 +245,37 @@ void EditorManager::Initialize(gfx::IRenderer* renderer, const std::string& file
|
||||
"global.toggle_sidebar",
|
||||
{ImGuiKey_LeftCtrl, ImGuiKey_B},
|
||||
[this]() { show_card_sidebar_ = !show_card_sidebar_; });
|
||||
|
||||
// Register emulator cards early (emulator Initialize might not be called)
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
card_manager.RegisterCard({.card_id = "emulator.cpu_debugger", .display_name = "CPU Debugger",
|
||||
.icon = ICON_MD_BUG_REPORT, .category = "Emulator", .priority = 10});
|
||||
card_manager.RegisterCard({.card_id = "emulator.ppu_viewer", .display_name = "PPU Viewer",
|
||||
.icon = ICON_MD_VIDEOGAME_ASSET, .category = "Emulator", .priority = 20});
|
||||
card_manager.RegisterCard({.card_id = "emulator.memory_viewer", .display_name = "Memory Viewer",
|
||||
.icon = ICON_MD_MEMORY, .category = "Emulator", .priority = 30});
|
||||
card_manager.RegisterCard({.card_id = "emulator.breakpoints", .display_name = "Breakpoints",
|
||||
.icon = ICON_MD_STOP, .category = "Emulator", .priority = 40});
|
||||
card_manager.RegisterCard({.card_id = "emulator.performance", .display_name = "Performance",
|
||||
.icon = ICON_MD_SPEED, .category = "Emulator", .priority = 50});
|
||||
card_manager.RegisterCard({.card_id = "emulator.ai_agent", .display_name = "AI Agent",
|
||||
.icon = ICON_MD_SMART_TOY, .category = "Emulator", .priority = 60});
|
||||
card_manager.RegisterCard({.card_id = "emulator.save_states", .display_name = "Save States",
|
||||
.icon = ICON_MD_SAVE, .category = "Emulator", .priority = 70});
|
||||
card_manager.RegisterCard({.card_id = "emulator.keyboard_config", .display_name = "Keyboard Config",
|
||||
.icon = ICON_MD_KEYBOARD, .category = "Emulator", .priority = 80});
|
||||
card_manager.RegisterCard({.card_id = "emulator.apu_debugger", .display_name = "APU Debugger",
|
||||
.icon = ICON_MD_AUDIOTRACK, .category = "Emulator", .priority = 90});
|
||||
card_manager.RegisterCard({.card_id = "emulator.audio_mixer", .display_name = "Audio Mixer",
|
||||
.icon = ICON_MD_AUDIO_FILE, .category = "Emulator", .priority = 100});
|
||||
|
||||
// Show CPU debugger and PPU viewer by default for emulator
|
||||
card_manager.ShowCard("emulator.cpu_debugger");
|
||||
card_manager.ShowCard("emulator.ppu_viewer");
|
||||
|
||||
// Register memory/hex editor card
|
||||
card_manager.RegisterCard({.card_id = "memory.hex_editor", .display_name = "Hex Editor",
|
||||
.icon = ICON_MD_MEMORY, .category = "Memory", .priority = 10});
|
||||
|
||||
// Initialize project file editor
|
||||
project_file_editor_.SetToastManager(&toast_manager_);
|
||||
@@ -411,54 +466,7 @@ void EditorManager::Initialize(gfx::IRenderer* renderer, const std::string& file
|
||||
// Initialize editor selection dialog callback
|
||||
editor_selection_dialog_.SetSelectionCallback([this](EditorType type) {
|
||||
editor_selection_dialog_.MarkRecentlyUsed(type);
|
||||
|
||||
// Handle agent editor separately (doesn't require ROM)
|
||||
if (type == EditorType::kAgent) {
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
agent_editor_.toggle_active();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_editor_set_) return;
|
||||
|
||||
switch (type) {
|
||||
case EditorType::kOverworld:
|
||||
current_editor_set_->overworld_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kDungeon:
|
||||
current_editor_set_->dungeon_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kGraphics:
|
||||
current_editor_set_->graphics_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kSprite:
|
||||
current_editor_set_->sprite_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kMessage:
|
||||
current_editor_set_->message_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kMusic:
|
||||
current_editor_set_->music_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kPalette:
|
||||
current_editor_set_->palette_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kScreen:
|
||||
current_editor_set_->screen_editor_.toggle_active();
|
||||
break;
|
||||
case EditorType::kAssembly:
|
||||
show_asm_editor_ = true;
|
||||
break;
|
||||
case EditorType::kEmulator:
|
||||
show_emulator_ = true;
|
||||
break;
|
||||
case EditorType::kSettings:
|
||||
current_editor_set_->settings_editor_.toggle_active();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SwitchToEditor(type); // Use centralized method
|
||||
});
|
||||
|
||||
// Load user settings - this must happen after context is initialized
|
||||
@@ -537,37 +545,37 @@ void EditorManager::Initialize(gfx::IRenderer* renderer, const std::string& file
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"F1", ImGuiKey_F1, [this]() { popup_manager_->Show("About"); });
|
||||
|
||||
// Editor shortcuts (Ctrl+1-9, Ctrl+0)
|
||||
// Editor shortcuts (Ctrl+1-9, Ctrl+0) - all use SwitchToEditor for consistency
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Overworld Editor", {ImGuiKey_1, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->overworld_editor_.toggle_active(); });
|
||||
"Overworld Editor", {ImGuiKey_LeftCtrl, ImGuiKey_1},
|
||||
[this]() { SwitchToEditor(EditorType::kOverworld); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Dungeon Editor", {ImGuiKey_2, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->dungeon_editor_.toggle_active(); });
|
||||
"Dungeon Editor", {ImGuiKey_LeftCtrl, ImGuiKey_2},
|
||||
[this]() { SwitchToEditor(EditorType::kDungeon); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Graphics Editor", {ImGuiKey_3, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->graphics_editor_.toggle_active(); });
|
||||
"Graphics Editor", {ImGuiKey_LeftCtrl, ImGuiKey_3},
|
||||
[this]() { SwitchToEditor(EditorType::kGraphics); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Sprite Editor", {ImGuiKey_4, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->sprite_editor_.toggle_active(); });
|
||||
"Sprite Editor", {ImGuiKey_LeftCtrl, ImGuiKey_4},
|
||||
[this]() { SwitchToEditor(EditorType::kSprite); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Message Editor", {ImGuiKey_5, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->message_editor_.toggle_active(); });
|
||||
"Message Editor", {ImGuiKey_LeftCtrl, ImGuiKey_5},
|
||||
[this]() { SwitchToEditor(EditorType::kMessage); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Music Editor", {ImGuiKey_6, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->music_editor_.toggle_active(); });
|
||||
"Music Editor", {ImGuiKey_LeftCtrl, ImGuiKey_6},
|
||||
[this]() { SwitchToEditor(EditorType::kMusic); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Palette Editor", {ImGuiKey_7, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->palette_editor_.toggle_active(); });
|
||||
"Palette Editor", {ImGuiKey_LeftCtrl, ImGuiKey_7},
|
||||
[this]() { SwitchToEditor(EditorType::kPalette); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Screen Editor", {ImGuiKey_8, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->screen_editor_.toggle_active(); });
|
||||
"Screen Editor", {ImGuiKey_LeftCtrl, ImGuiKey_8},
|
||||
[this]() { SwitchToEditor(EditorType::kScreen); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Assembly Editor", {ImGuiKey_9, ImGuiMod_Ctrl},
|
||||
[this]() { show_asm_editor_ = true; });
|
||||
"Assembly Editor", {ImGuiKey_LeftCtrl, ImGuiKey_9},
|
||||
[this]() { SwitchToEditor(EditorType::kAssembly); });
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
"Settings Editor", {ImGuiKey_0, ImGuiMod_Ctrl},
|
||||
[this]() { if (current_editor_set_) current_editor_set_->settings_editor_.toggle_active(); });
|
||||
"Settings Editor", {ImGuiKey_LeftCtrl, ImGuiKey_0},
|
||||
[this]() { SwitchToEditor(EditorType::kSettings); });
|
||||
|
||||
// Editor Selection Dialog shortcut
|
||||
context_.shortcut_manager.RegisterShortcut(
|
||||
@@ -912,13 +920,6 @@ absl::Status EditorManager::Update() {
|
||||
}
|
||||
}
|
||||
|
||||
// Draw sidebar for current card-based editor (only if sidebar is visible)
|
||||
if (show_card_sidebar_ && current_editor_ && IsCardBasedEditor(current_editor_->type())) {
|
||||
std::string category = GetEditorCategory(current_editor_->type());
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
card_manager.DrawSidebar(category);
|
||||
}
|
||||
|
||||
if (show_performance_dashboard_) {
|
||||
gfx::PerformanceDashboard::Get().Render();
|
||||
}
|
||||
@@ -933,6 +934,59 @@ absl::Status EditorManager::Update() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Draw unified sidebar LAST so it appears on top of all other windows
|
||||
if (show_card_sidebar_ && current_editor_set_) {
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
// Collect all active card-based editors
|
||||
std::vector<std::string> active_categories;
|
||||
for (size_t session_idx = 0; session_idx < sessions_.size(); ++session_idx) {
|
||||
auto& session = sessions_[session_idx];
|
||||
if (!session.rom.is_loaded()) continue;
|
||||
|
||||
for (auto editor : session.editors.active_editors_) {
|
||||
if (*editor->active() && IsCardBasedEditor(editor->type())) {
|
||||
std::string category = GetEditorCategory(editor->type());
|
||||
if (std::find(active_categories.begin(), active_categories.end(), category) == active_categories.end()) {
|
||||
active_categories.push_back(category);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which category to show in sidebar
|
||||
std::string sidebar_category;
|
||||
|
||||
// Priority 1: Use active_category from card manager (user's last interaction)
|
||||
if (!card_manager.GetActiveCategory().empty() &&
|
||||
std::find(active_categories.begin(), active_categories.end(),
|
||||
card_manager.GetActiveCategory()) != active_categories.end()) {
|
||||
sidebar_category = card_manager.GetActiveCategory();
|
||||
}
|
||||
// Priority 2: Use first active category
|
||||
else if (!active_categories.empty()) {
|
||||
sidebar_category = active_categories[0];
|
||||
card_manager.SetActiveCategory(sidebar_category);
|
||||
}
|
||||
|
||||
// Draw sidebar if we have a category
|
||||
if (!sidebar_category.empty()) {
|
||||
// Callback to switch editors when category button is clicked
|
||||
auto category_switch_callback = [this](const std::string& new_category) {
|
||||
EditorType editor_type = GetEditorTypeFromCategory(new_category);
|
||||
if (editor_type != EditorType::kUnknown) {
|
||||
SwitchToEditor(editor_type);
|
||||
}
|
||||
};
|
||||
|
||||
auto collapse_callback = [this]() {
|
||||
show_card_sidebar_ = false;
|
||||
};
|
||||
|
||||
card_manager.DrawSidebar(sidebar_category, active_categories, category_switch_callback, collapse_callback);
|
||||
}
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -1112,23 +1166,23 @@ void EditorManager::BuildModernMenu() {
|
||||
[this]() { show_editor_selection_ = true; }, "Ctrl+E")
|
||||
.Separator()
|
||||
.Item("Overworld", ICON_MD_MAP,
|
||||
[this]() { current_editor_set_->overworld_editor_.set_active(true); }, "Ctrl+1")
|
||||
[this]() { SwitchToEditor(EditorType::kOverworld); }, "Ctrl+1")
|
||||
.Item("Dungeon", ICON_MD_CASTLE,
|
||||
[this]() { current_editor_set_->dungeon_editor_.set_active(true); }, "Ctrl+2")
|
||||
[this]() { SwitchToEditor(EditorType::kDungeon); }, "Ctrl+2")
|
||||
.Item("Graphics", ICON_MD_IMAGE,
|
||||
[this]() { current_editor_set_->graphics_editor_.set_active(true); }, "Ctrl+3")
|
||||
[this]() { SwitchToEditor(EditorType::kGraphics); }, "Ctrl+3")
|
||||
.Item("Sprites", ICON_MD_TOYS,
|
||||
[this]() { current_editor_set_->sprite_editor_.set_active(true); }, "Ctrl+4")
|
||||
[this]() { SwitchToEditor(EditorType::kSprite); }, "Ctrl+4")
|
||||
.Item("Messages", ICON_MD_CHAT_BUBBLE,
|
||||
[this]() { current_editor_set_->message_editor_.set_active(true); }, "Ctrl+5")
|
||||
[this]() { SwitchToEditor(EditorType::kMessage); }, "Ctrl+5")
|
||||
.Item("Music", ICON_MD_MUSIC_NOTE,
|
||||
[this]() { current_editor_set_->music_editor_.set_active(true); }, "Ctrl+6")
|
||||
[this]() { SwitchToEditor(EditorType::kMusic); }, "Ctrl+6")
|
||||
.Item("Palettes", ICON_MD_PALETTE,
|
||||
[this]() { current_editor_set_->palette_editor_.set_active(true); }, "Ctrl+7")
|
||||
[this]() { SwitchToEditor(EditorType::kPalette); }, "Ctrl+7")
|
||||
.Item("Screens", ICON_MD_TV,
|
||||
[this]() { current_editor_set_->screen_editor_.set_active(true); }, "Ctrl+8")
|
||||
[this]() { SwitchToEditor(EditorType::kScreen); }, "Ctrl+8")
|
||||
.Item("Hex Editor", ICON_MD_DATA_ARRAY,
|
||||
[this]() { show_memory_editor_ = true; }, "Ctrl+0")
|
||||
[this]() { gui::EditorCardManager::Get().ShowCard("memory.hex_editor"); }, "Ctrl+0")
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
.Item("AI Agent", ICON_MD_SMART_TOY,
|
||||
[this]() { agent_editor_.set_active(true); }, "Ctrl+Shift+A")
|
||||
@@ -1388,9 +1442,9 @@ void EditorManager::BuildModernMenu() {
|
||||
.Separator()
|
||||
// Development Tools
|
||||
.Item("Memory Editor", ICON_MD_MEMORY,
|
||||
[this]() { show_memory_editor_ = true; })
|
||||
[this]() { gui::EditorCardManager::Get().ShowCard("memory.hex_editor"); })
|
||||
.Item("Assembly Editor", ICON_MD_CODE,
|
||||
[this]() { show_asm_editor_ = true; })
|
||||
[this]() { gui::EditorCardManager::Get().ShowCard("assembly.editor"); })
|
||||
.Item("Feature Flags", ICON_MD_FLAG,
|
||||
[this]() { popup_manager_->Show("Feature Flags"); })
|
||||
.Separator()
|
||||
@@ -1512,11 +1566,15 @@ void EditorManager::DrawMenuBar() {
|
||||
ShowDemoWindow(&show_imgui_demo_);
|
||||
if (show_imgui_metrics_)
|
||||
ShowMetricsWindow(&show_imgui_metrics_);
|
||||
if (show_memory_editor_ && current_editor_set_) {
|
||||
current_editor_set_->memory_editor_.Update(show_memory_editor_);
|
||||
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
if (card_manager.IsCardVisible("memory.hex_editor") && current_editor_set_) {
|
||||
bool show_memory = true;
|
||||
current_editor_set_->memory_editor_.Update(show_memory);
|
||||
}
|
||||
if (show_asm_editor_ && current_editor_set_) {
|
||||
current_editor_set_->assembly_editor_.Update(show_asm_editor_);
|
||||
if (card_manager.IsCardVisible("assembly.editor") && current_editor_set_) {
|
||||
bool show_asm = true;
|
||||
current_editor_set_->assembly_editor_.Update(show_asm);
|
||||
}
|
||||
|
||||
// Project file editor
|
||||
@@ -1551,10 +1609,9 @@ void EditorManager::DrawMenuBar() {
|
||||
DrawWelcomeScreen();
|
||||
}
|
||||
|
||||
// Emulator is now card-based - it creates its own windows
|
||||
if (show_emulator_) {
|
||||
Begin("Emulator", &show_emulator_, ImGuiWindowFlags_MenuBar);
|
||||
emulator_.Run(current_rom_);
|
||||
End();
|
||||
}
|
||||
|
||||
// Enhanced Command Palette UI with Fuzzy Search
|
||||
@@ -2172,6 +2229,11 @@ absl::Status EditorManager::LoadAssets() {
|
||||
|
||||
current_editor_set_->overworld_editor_.Initialize();
|
||||
current_editor_set_->message_editor_.Initialize();
|
||||
current_editor_set_->graphics_editor_.Initialize();
|
||||
current_editor_set_->screen_editor_.Initialize();
|
||||
current_editor_set_->sprite_editor_.Initialize();
|
||||
current_editor_set_->palette_editor_.Initialize();
|
||||
current_editor_set_->assembly_editor_.Initialize();
|
||||
// Initialize the dungeon editor with the renderer
|
||||
current_editor_set_->dungeon_editor_.Initialize(renderer_, current_rom_);
|
||||
ASSIGN_OR_RETURN(*gfx::Arena::Get().mutable_gfx_sheets(),
|
||||
@@ -3352,14 +3414,40 @@ void EditorManager::JumpToOverworldMap(int map_id) {
|
||||
}
|
||||
|
||||
void EditorManager::SwitchToEditor(EditorType editor_type) {
|
||||
// Find the editor tab and activate it
|
||||
for (size_t i = 0; i < current_editor_set_->active_editors_.size(); ++i) {
|
||||
if (current_editor_set_->active_editors_[i]->type() == editor_type) {
|
||||
current_editor_set_->active_editors_[i]->set_active(true);
|
||||
if (!current_editor_set_) return;
|
||||
|
||||
// Toggle the editor
|
||||
for (auto* editor : current_editor_set_->active_editors_) {
|
||||
if (editor->type() == editor_type) {
|
||||
editor->toggle_active();
|
||||
|
||||
// Set editor as the current/focused one
|
||||
// This will make it visible when tabs are rendered
|
||||
break;
|
||||
if (IsCardBasedEditor(editor_type)) {
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
if (*editor->active()) {
|
||||
// Editor activated - set its category
|
||||
card_manager.SetActiveCategory(GetEditorCategory(editor_type));
|
||||
} else {
|
||||
// Editor deactivated - switch to another active card-based editor
|
||||
for (auto* other : current_editor_set_->active_editors_) {
|
||||
if (*other->active() && IsCardBasedEditor(other->type()) && other != editor) {
|
||||
card_manager.SetActiveCategory(GetEditorCategory(other->type()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle non-editor-class cases
|
||||
if (editor_type == EditorType::kAssembly) {
|
||||
show_asm_editor_ = !show_asm_editor_;
|
||||
} else if (editor_type == EditorType::kEmulator) {
|
||||
show_emulator_ = !show_emulator_;
|
||||
if (show_emulator_) {
|
||||
gui::EditorCardManager::Get().SetActiveCategory("Emulator");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ class EditorManager {
|
||||
// Card-based editor registry
|
||||
static bool IsCardBasedEditor(EditorType type);
|
||||
static std::string GetEditorCategory(EditorType type);
|
||||
static EditorType GetEditorTypeFromCategory(const std::string& category);
|
||||
bool IsSidebarVisible() const { return show_card_sidebar_; }
|
||||
void SetSidebarVisible(bool visible) { show_card_sidebar_ = visible; }
|
||||
|
||||
|
||||
@@ -43,48 +43,23 @@ constexpr ImGuiTableFlags kGfxEditTableFlags =
|
||||
ImGuiTableFlags_SizingFixedFit;
|
||||
|
||||
void GraphicsEditor::Initialize() {
|
||||
// Register cards with EditorCardManager during initialization (once)
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "graphics.sheet_editor",
|
||||
.display_name = "Sheet Editor",
|
||||
.icon = ICON_MD_EDIT,
|
||||
.category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+1",
|
||||
.visibility_flag = &show_sheet_editor_,
|
||||
.priority = 10
|
||||
});
|
||||
card_manager.RegisterCard({.card_id = "graphics.sheet_editor", .display_name = "Sheet Editor",
|
||||
.icon = ICON_MD_EDIT, .category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+1", .priority = 10});
|
||||
card_manager.RegisterCard({.card_id = "graphics.sheet_browser", .display_name = "Sheet Browser",
|
||||
.icon = ICON_MD_VIEW_LIST, .category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+2", .priority = 20});
|
||||
card_manager.RegisterCard({.card_id = "graphics.player_animations", .display_name = "Player Animations",
|
||||
.icon = ICON_MD_PERSON, .category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+3", .priority = 30});
|
||||
card_manager.RegisterCard({.card_id = "graphics.prototype_viewer", .display_name = "Prototype Viewer",
|
||||
.icon = ICON_MD_CONSTRUCTION, .category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+4", .priority = 40});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "graphics.sheet_browser",
|
||||
.display_name = "Sheet Browser",
|
||||
.icon = ICON_MD_VIEW_LIST,
|
||||
.category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+2",
|
||||
.visibility_flag = &show_sheet_browser_,
|
||||
.priority = 20
|
||||
});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "graphics.player_animations",
|
||||
.display_name = "Player Animations",
|
||||
.icon = ICON_MD_PERSON,
|
||||
.category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+3",
|
||||
.visibility_flag = &show_player_animations_,
|
||||
.priority = 30
|
||||
});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "graphics.prototype_viewer",
|
||||
.display_name = "Prototype Viewer",
|
||||
.icon = ICON_MD_CONSTRUCTION,
|
||||
.category = "Graphics",
|
||||
.shortcut_hint = "Ctrl+Shift+4",
|
||||
.visibility_flag = &show_prototype_viewer_,
|
||||
.priority = 40
|
||||
});
|
||||
// Show sheet editor by default when Graphics Editor is activated
|
||||
card_manager.ShowCard("graphics.sheet_editor");
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::Load() {
|
||||
@@ -124,56 +99,46 @@ absl::Status GraphicsEditor::Load() {
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::Update() {
|
||||
DrawToolset();
|
||||
gui::VerticalSpacing(2.0f);
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
static gui::EditorCard sheet_editor_card("Sheet Editor", ICON_MD_EDIT);
|
||||
static gui::EditorCard sheet_browser_card("Sheet Browser", ICON_MD_VIEW_LIST);
|
||||
static gui::EditorCard player_anims_card("Player Animations", ICON_MD_PERSON);
|
||||
static gui::EditorCard prototype_card("Prototype Viewer", ICON_MD_CONSTRUCTION);
|
||||
|
||||
// Create session-aware cards (non-static for multi-session support)
|
||||
gui::EditorCard sheet_editor_card(MakeCardTitle("Sheet Editor").c_str(), ICON_MD_EDIT);
|
||||
gui::EditorCard sheet_browser_card(MakeCardTitle("Sheet Browser").c_str(), ICON_MD_VIEW_LIST);
|
||||
gui::EditorCard player_anims_card(MakeCardTitle("Player Animations").c_str(), ICON_MD_PERSON);
|
||||
gui::EditorCard prototype_card(MakeCardTitle("Prototype Viewer").c_str(), ICON_MD_CONSTRUCTION);
|
||||
sheet_editor_card.SetDefaultSize(900, 700);
|
||||
sheet_browser_card.SetDefaultSize(400, 600);
|
||||
player_anims_card.SetDefaultSize(500, 600);
|
||||
prototype_card.SetDefaultSize(600, 500);
|
||||
|
||||
if (show_sheet_editor_) {
|
||||
if (sheet_editor_card.Begin(&show_sheet_editor_)) {
|
||||
status_ = UpdateGfxEdit();
|
||||
}
|
||||
sheet_editor_card.End(); // ALWAYS call End after Begin
|
||||
// Get visibility flags from card manager and pass to Begin()
|
||||
if (sheet_editor_card.Begin(card_manager.GetVisibilityFlag("graphics.sheet_editor"))) {
|
||||
status_ = UpdateGfxEdit();
|
||||
sheet_editor_card.End();
|
||||
}
|
||||
|
||||
if (show_sheet_browser_) {
|
||||
if (sheet_browser_card.Begin(&show_sheet_browser_)) {
|
||||
if (asset_browser_.Initialized == false) {
|
||||
asset_browser_.Initialize(gfx::Arena::Get().gfx_sheets());
|
||||
}
|
||||
asset_browser_.Draw(gfx::Arena::Get().gfx_sheets());
|
||||
if (sheet_browser_card.Begin(card_manager.GetVisibilityFlag("graphics.sheet_browser"))) {
|
||||
if (asset_browser_.Initialized == false) {
|
||||
asset_browser_.Initialize(gfx::Arena::Get().gfx_sheets());
|
||||
}
|
||||
sheet_browser_card.End(); // ALWAYS call End after Begin
|
||||
asset_browser_.Draw(gfx::Arena::Get().gfx_sheets());
|
||||
sheet_browser_card.End();
|
||||
}
|
||||
|
||||
if (show_player_animations_) {
|
||||
if (player_anims_card.Begin(&show_player_animations_)) {
|
||||
status_ = UpdateLinkGfxView();
|
||||
}
|
||||
player_anims_card.End(); // ALWAYS call End after Begin
|
||||
if (player_anims_card.Begin(card_manager.GetVisibilityFlag("graphics.player_animations"))) {
|
||||
status_ = UpdateLinkGfxView();
|
||||
player_anims_card.End();
|
||||
}
|
||||
|
||||
if (show_prototype_viewer_) {
|
||||
if (prototype_card.Begin(&show_prototype_viewer_)) {
|
||||
status_ = UpdateScadView();
|
||||
}
|
||||
prototype_card.End(); // ALWAYS call End after Begin
|
||||
if (prototype_card.Begin(card_manager.GetVisibilityFlag("graphics.prototype_viewer"))) {
|
||||
status_ = UpdateScadView();
|
||||
prototype_card.End();
|
||||
}
|
||||
|
||||
CLEAR_AND_RETURN_STATUS(status_)
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void GraphicsEditor::DrawToolset() {
|
||||
// Sidebar is now drawn by EditorManager for card-based editors
|
||||
// This method kept for compatibility but sidebar handles card toggles
|
||||
}
|
||||
|
||||
|
||||
absl::Status GraphicsEditor::UpdateGfxEdit() {
|
||||
if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags,
|
||||
ImVec2(0, 0))) {
|
||||
@@ -606,8 +571,6 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() {
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::UpdateScadView() {
|
||||
DrawToolset();
|
||||
|
||||
if (open_memory_editor_) {
|
||||
ImGui::Begin("Memory Editor", &open_memory_editor_);
|
||||
RETURN_IF_ERROR(DrawMemoryEditor())
|
||||
|
||||
@@ -107,7 +107,6 @@ class GraphicsEditor : public Editor {
|
||||
absl::Status DrawTilemapImport();
|
||||
|
||||
// Other Functions
|
||||
void DrawToolset();
|
||||
absl::Status DrawPaletteControls();
|
||||
absl::Status DrawClipboardImport();
|
||||
absl::Status DrawExperimentalFeatures();
|
||||
@@ -117,12 +116,7 @@ class GraphicsEditor : public Editor {
|
||||
absl::Status DecompressSuperDonkey();
|
||||
|
||||
// Member Variables
|
||||
// Card visibility - ALL FALSE by default to prevent crash on ROM load
|
||||
// Cards only shown when user explicitly opens them via View menu or shortcuts
|
||||
bool show_sheet_editor_ = false;
|
||||
bool show_sheet_browser_ = false;
|
||||
bool show_player_animations_ = false;
|
||||
bool show_prototype_viewer_ = false;
|
||||
// Card visibility managed by EditorCardManager
|
||||
|
||||
ImVec4 current_color_;
|
||||
uint16_t current_sheet_ = 0;
|
||||
|
||||
@@ -30,58 +30,26 @@ namespace editor {
|
||||
constexpr uint32_t kRedPen = 0xFF0000FF;
|
||||
|
||||
void ScreenEditor::Initialize() {
|
||||
// Register cards with EditorCardManager during initialization (once)
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "screen.dungeon_maps",
|
||||
.display_name = "Dungeon Maps",
|
||||
.icon = ICON_MD_MAP,
|
||||
.category = "Screen",
|
||||
.shortcut_hint = "Alt+1",
|
||||
.visibility_flag = &show_dungeon_maps_,
|
||||
.priority = 10
|
||||
});
|
||||
card_manager.RegisterCard({.card_id = "screen.dungeon_maps", .display_name = "Dungeon Maps",
|
||||
.icon = ICON_MD_MAP, .category = "Screen",
|
||||
.shortcut_hint = "Alt+1", .priority = 10});
|
||||
card_manager.RegisterCard({.card_id = "screen.inventory_menu", .display_name = "Inventory Menu",
|
||||
.icon = ICON_MD_INVENTORY, .category = "Screen",
|
||||
.shortcut_hint = "Alt+2", .priority = 20});
|
||||
card_manager.RegisterCard({.card_id = "screen.overworld_map", .display_name = "Overworld Map",
|
||||
.icon = ICON_MD_PUBLIC, .category = "Screen",
|
||||
.shortcut_hint = "Alt+3", .priority = 30});
|
||||
card_manager.RegisterCard({.card_id = "screen.title_screen", .display_name = "Title Screen",
|
||||
.icon = ICON_MD_TITLE, .category = "Screen",
|
||||
.shortcut_hint = "Alt+4", .priority = 40});
|
||||
card_manager.RegisterCard({.card_id = "screen.naming_screen", .display_name = "Naming Screen",
|
||||
.icon = ICON_MD_EDIT, .category = "Screen",
|
||||
.shortcut_hint = "Alt+5", .priority = 50});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "screen.inventory_menu",
|
||||
.display_name = "Inventory Menu",
|
||||
.icon = ICON_MD_INVENTORY,
|
||||
.category = "Screen",
|
||||
.shortcut_hint = "Alt+2",
|
||||
.visibility_flag = &show_inventory_menu_,
|
||||
.priority = 20
|
||||
});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "screen.overworld_map",
|
||||
.display_name = "Overworld Map",
|
||||
.icon = ICON_MD_PUBLIC,
|
||||
.category = "Screen",
|
||||
.shortcut_hint = "Alt+3",
|
||||
.visibility_flag = &show_overworld_map_,
|
||||
.priority = 30
|
||||
});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "screen.title_screen",
|
||||
.display_name = "Title Screen",
|
||||
.icon = ICON_MD_TITLE,
|
||||
.category = "Screen",
|
||||
.shortcut_hint = "Alt+4",
|
||||
.visibility_flag = &show_title_screen_,
|
||||
.priority = 40
|
||||
});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "screen.naming_screen",
|
||||
.display_name = "Naming Screen",
|
||||
.icon = ICON_MD_EDIT,
|
||||
.category = "Screen",
|
||||
.shortcut_hint = "Alt+5",
|
||||
.visibility_flag = &show_naming_screen_,
|
||||
.priority = 50
|
||||
});
|
||||
// Show title screen by default
|
||||
card_manager.ShowCard("screen.title_screen");
|
||||
}
|
||||
|
||||
absl::Status ScreenEditor::Load() {
|
||||
@@ -119,45 +87,40 @@ absl::Status ScreenEditor::Load() {
|
||||
}
|
||||
|
||||
absl::Status ScreenEditor::Update() {
|
||||
DrawToolset();
|
||||
gui::VerticalSpacing(2.0f);
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
// Create session-aware cards (non-static for multi-session support)
|
||||
gui::EditorCard dungeon_maps_card(MakeCardTitle("Dungeon Maps").c_str(), ICON_MD_MAP);
|
||||
gui::EditorCard inventory_menu_card(MakeCardTitle("Inventory Menu").c_str(), ICON_MD_INVENTORY);
|
||||
gui::EditorCard overworld_map_card(MakeCardTitle("Overworld Map").c_str(), ICON_MD_PUBLIC);
|
||||
gui::EditorCard title_screen_card(MakeCardTitle("Title Screen").c_str(), ICON_MD_TITLE);
|
||||
gui::EditorCard naming_screen_card(MakeCardTitle("Naming Screen").c_str(), ICON_MD_EDIT_ATTRIBUTES);
|
||||
static gui::EditorCard dungeon_maps_card("Dungeon Maps", ICON_MD_MAP);
|
||||
static gui::EditorCard inventory_menu_card("Inventory Menu", ICON_MD_INVENTORY);
|
||||
static gui::EditorCard overworld_map_card("Overworld Map", ICON_MD_PUBLIC);
|
||||
static gui::EditorCard title_screen_card("Title Screen", ICON_MD_TITLE);
|
||||
static gui::EditorCard naming_screen_card("Naming Screen", ICON_MD_EDIT_ATTRIBUTES);
|
||||
|
||||
if (show_dungeon_maps_) {
|
||||
if (dungeon_maps_card.Begin(&show_dungeon_maps_)) {
|
||||
DrawDungeonMapsEditor();
|
||||
}
|
||||
dungeon_maps_card.End(); // ALWAYS call End after Begin
|
||||
dungeon_maps_card.SetDefaultSize(800, 600);
|
||||
inventory_menu_card.SetDefaultSize(800, 600);
|
||||
overworld_map_card.SetDefaultSize(600, 500);
|
||||
title_screen_card.SetDefaultSize(600, 500);
|
||||
naming_screen_card.SetDefaultSize(500, 400);
|
||||
|
||||
// Get visibility flags from card manager and pass to Begin()
|
||||
if (dungeon_maps_card.Begin(card_manager.GetVisibilityFlag("screen.dungeon_maps"))) {
|
||||
DrawDungeonMapsEditor();
|
||||
dungeon_maps_card.End();
|
||||
}
|
||||
if (show_inventory_menu_) {
|
||||
if (inventory_menu_card.Begin(&show_inventory_menu_)) {
|
||||
DrawInventoryMenuEditor();
|
||||
}
|
||||
inventory_menu_card.End(); // ALWAYS call End after Begin
|
||||
if (inventory_menu_card.Begin(card_manager.GetVisibilityFlag("screen.inventory_menu"))) {
|
||||
DrawInventoryMenuEditor();
|
||||
inventory_menu_card.End();
|
||||
}
|
||||
if (show_overworld_map_) {
|
||||
if (overworld_map_card.Begin(&show_overworld_map_)) {
|
||||
DrawOverworldMapEditor();
|
||||
}
|
||||
overworld_map_card.End(); // ALWAYS call End after Begin
|
||||
if (overworld_map_card.Begin(card_manager.GetVisibilityFlag("screen.overworld_map"))) {
|
||||
DrawOverworldMapEditor();
|
||||
overworld_map_card.End();
|
||||
}
|
||||
if (show_title_screen_) {
|
||||
if (title_screen_card.Begin(&show_title_screen_)) {
|
||||
DrawTitleScreenEditor();
|
||||
}
|
||||
title_screen_card.End(); // ALWAYS call End after Begin
|
||||
if (title_screen_card.Begin(card_manager.GetVisibilityFlag("screen.title_screen"))) {
|
||||
DrawTitleScreenEditor();
|
||||
title_screen_card.End();
|
||||
}
|
||||
if (show_naming_screen_) {
|
||||
if (naming_screen_card.Begin(&show_naming_screen_)) {
|
||||
DrawNamingScreenEditor();
|
||||
}
|
||||
naming_screen_card.End(); // ALWAYS call End after Begin
|
||||
if (naming_screen_card.Begin(card_manager.GetVisibilityFlag("screen.naming_screen"))) {
|
||||
DrawNamingScreenEditor();
|
||||
naming_screen_card.End();
|
||||
}
|
||||
|
||||
return status_;
|
||||
|
||||
@@ -78,14 +78,6 @@ class ScreenEditor : public Editor {
|
||||
|
||||
EditingMode current_mode_ = EditingMode::DRAW;
|
||||
|
||||
// Card visibility - ALL FALSE by default to prevent crash on ROM load
|
||||
// Cards only shown when user explicitly opens them via View menu or shortcuts
|
||||
bool show_dungeon_maps_ = false;
|
||||
bool show_inventory_menu_ = false;
|
||||
bool show_overworld_map_ = false;
|
||||
bool show_title_screen_ = false;
|
||||
bool show_naming_screen_ = false;
|
||||
|
||||
bool binary_gfx_loaded_ = false;
|
||||
|
||||
uint8_t selected_room = 0;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "imgui.h"
|
||||
@@ -61,7 +62,7 @@ constexpr ImGuiTableFlags kMessageTableFlags = ImGuiTableFlags_Hideable |
|
||||
ImGuiTableFlags_Resizable;
|
||||
|
||||
void MessageEditor::Initialize() {
|
||||
// Register cards with EditorCardManager
|
||||
// Register cards with EditorCardManager (using centralized visibility)
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
card_manager.RegisterCard({
|
||||
@@ -69,7 +70,6 @@ void MessageEditor::Initialize() {
|
||||
.display_name = "Message List",
|
||||
.icon = ICON_MD_LIST,
|
||||
.category = "Message",
|
||||
.visibility_flag = &show_message_list_,
|
||||
.priority = 10
|
||||
});
|
||||
|
||||
@@ -78,7 +78,6 @@ void MessageEditor::Initialize() {
|
||||
.display_name = "Message Editor",
|
||||
.icon = ICON_MD_EDIT,
|
||||
.category = "Message",
|
||||
.visibility_flag = &show_message_editor_,
|
||||
.priority = 20
|
||||
});
|
||||
|
||||
@@ -87,7 +86,6 @@ void MessageEditor::Initialize() {
|
||||
.display_name = "Font Atlas",
|
||||
.icon = ICON_MD_FONT_DOWNLOAD,
|
||||
.category = "Message",
|
||||
.visibility_flag = &show_font_atlas_,
|
||||
.priority = 30
|
||||
});
|
||||
|
||||
@@ -96,10 +94,12 @@ void MessageEditor::Initialize() {
|
||||
.display_name = "Dictionary",
|
||||
.icon = ICON_MD_BOOK,
|
||||
.category = "Message",
|
||||
.visibility_flag = &show_dictionary_,
|
||||
.priority = 40
|
||||
});
|
||||
|
||||
// Show message list by default
|
||||
card_manager.ShowCard("message.message_list");
|
||||
|
||||
for (int i = 0; i < kWidthArraySize; i++) {
|
||||
message_preview_.width_array[i] = rom()->data()[kCharactersWidth + i];
|
||||
}
|
||||
@@ -143,30 +143,51 @@ absl::Status MessageEditor::Load() {
|
||||
}
|
||||
|
||||
absl::Status MessageEditor::Update() {
|
||||
if (BeginTable("##MessageEditor", 4, kMessageTableFlags)) {
|
||||
TableSetupColumn("List");
|
||||
TableSetupColumn("Contents");
|
||||
TableSetupColumn("Font Atlas");
|
||||
TableSetupColumn("Commands");
|
||||
TableHeadersRow();
|
||||
|
||||
TableNextColumn();
|
||||
DrawMessageList();
|
||||
|
||||
TableNextColumn();
|
||||
DrawCurrentMessage();
|
||||
|
||||
TableNextColumn();
|
||||
DrawFontAtlas();
|
||||
DrawExpandedMessageSettings();
|
||||
|
||||
TableNextColumn();
|
||||
DrawTextCommands();
|
||||
DrawSpecialCharacters();
|
||||
DrawDictionary();
|
||||
|
||||
EndTable();
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
// Message List Card
|
||||
if (card_manager.IsCardVisible("message.message_list")) {
|
||||
static gui::EditorCard list_card("Message List", ICON_MD_LIST);
|
||||
list_card.SetDefaultSize(400, 600);
|
||||
if (list_card.Begin()) {
|
||||
DrawMessageList();
|
||||
list_card.End();
|
||||
}
|
||||
}
|
||||
|
||||
// Message Editor Card
|
||||
if (card_manager.IsCardVisible("message.message_editor")) {
|
||||
static gui::EditorCard editor_card("Message Editor", ICON_MD_EDIT);
|
||||
editor_card.SetDefaultSize(500, 600);
|
||||
if (editor_card.Begin()) {
|
||||
DrawCurrentMessage();
|
||||
editor_card.End();
|
||||
}
|
||||
}
|
||||
|
||||
// Font Atlas Card
|
||||
if (card_manager.IsCardVisible("message.font_atlas")) {
|
||||
static gui::EditorCard font_card("Font Atlas", ICON_MD_FONT_DOWNLOAD);
|
||||
font_card.SetDefaultSize(400, 500);
|
||||
if (font_card.Begin()) {
|
||||
DrawFontAtlas();
|
||||
DrawExpandedMessageSettings();
|
||||
font_card.End();
|
||||
}
|
||||
}
|
||||
|
||||
// Dictionary Card
|
||||
if (card_manager.IsCardVisible("message.dictionary")) {
|
||||
static gui::EditorCard dict_card("Dictionary", ICON_MD_BOOK);
|
||||
dict_card.SetDefaultSize(400, 500);
|
||||
if (dict_card.Begin()) {
|
||||
DrawTextCommands();
|
||||
DrawSpecialCharacters();
|
||||
DrawDictionary();
|
||||
dict_card.End();
|
||||
}
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "app/editor/message/message_data.h"
|
||||
#include "app/editor/message/message_preview.h"
|
||||
#include "app/gui/editor_card_manager.h"
|
||||
#include "app/gui/editor_layout.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/style.h"
|
||||
|
||||
@@ -51,6 +51,17 @@ void OverworldEditor::Initialize() {
|
||||
// Register cards with EditorCardManager
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
// Register Overworld Canvas (main canvas card with toolset)
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "overworld.canvas",
|
||||
.display_name = "Overworld Canvas",
|
||||
.icon = ICON_MD_MAP,
|
||||
.category = "Overworld",
|
||||
.shortcut_hint = "Ctrl+Shift+O",
|
||||
.visibility_flag = &show_overworld_canvas_,
|
||||
.priority = 5 // Show first, most important
|
||||
});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "overworld.tile16_selector",
|
||||
.display_name = "Tile16 Selector",
|
||||
@@ -193,11 +204,8 @@ absl::Status OverworldEditor::Update() {
|
||||
return status_;
|
||||
}
|
||||
|
||||
// Modern layout - no tabs, just toolbar + canvas + floating cards
|
||||
DrawToolset();
|
||||
gui::VerticalSpacing(2.0f);
|
||||
|
||||
// Create session-aware cards (non-static for multi-session support)
|
||||
gui::EditorCard overworld_canvas_card(MakeCardTitle("Overworld Canvas").c_str(), ICON_MD_PUBLIC);
|
||||
gui::EditorCard tile16_card(MakeCardTitle("Tile16 Selector").c_str(), ICON_MD_GRID_3X3);
|
||||
gui::EditorCard tile8_card(MakeCardTitle("Tile8 Selector").c_str(), ICON_MD_GRID_4X4);
|
||||
gui::EditorCard area_gfx_card(MakeCardTitle("Area Graphics").c_str(), ICON_MD_IMAGE);
|
||||
@@ -211,6 +219,9 @@ absl::Status OverworldEditor::Update() {
|
||||
static bool cards_configured = false;
|
||||
if (!cards_configured) {
|
||||
// Position cards for optimal workflow
|
||||
overworld_canvas_card.SetDefaultSize(1000, 700);
|
||||
overworld_canvas_card.SetPosition(gui::EditorCard::Position::Floating);
|
||||
|
||||
tile16_card.SetDefaultSize(300, 600);
|
||||
tile16_card.SetPosition(gui::EditorCard::Position::Right);
|
||||
|
||||
@@ -239,7 +250,13 @@ absl::Status OverworldEditor::Update() {
|
||||
}
|
||||
|
||||
// Main canvas (full width when cards are docked)
|
||||
DrawOverworldCanvas();
|
||||
if (show_overworld_canvas_) {
|
||||
if (overworld_canvas_card.Begin(&show_overworld_canvas_)) {
|
||||
DrawToolset();
|
||||
DrawOverworldCanvas();
|
||||
}
|
||||
overworld_canvas_card.End(); // ALWAYS call End after Begin
|
||||
}
|
||||
|
||||
// Floating tile selector cards (4 tabs converted to separate cards)
|
||||
if (show_tile16_selector_) {
|
||||
|
||||
@@ -296,6 +296,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
bool show_overlay_preview_ = false;
|
||||
|
||||
// Card visibility states - Start hidden to prevent crash
|
||||
bool show_overworld_canvas_ = true;
|
||||
bool show_tile16_selector_ = false;
|
||||
bool show_tile8_selector_ = false;
|
||||
bool show_area_gfx_ = false;
|
||||
|
||||
@@ -295,6 +295,9 @@ void PaletteEditor::Initialize() {
|
||||
.visibility_flag = &show_custom_palette_,
|
||||
.priority = 80
|
||||
});
|
||||
|
||||
// Show control panel by default when Palette Editor is activated
|
||||
show_control_panel_ = true;
|
||||
}
|
||||
|
||||
absl::Status PaletteEditor::Load() {
|
||||
|
||||
@@ -25,28 +25,17 @@ using ImGui::TableSetupColumn;
|
||||
using ImGui::Text;
|
||||
|
||||
void SpriteEditor::Initialize() {
|
||||
// Register cards with EditorCardManager during initialization (once)
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "sprite.vanilla_editor",
|
||||
.display_name = "Vanilla Sprites",
|
||||
.icon = ICON_MD_SMART_TOY,
|
||||
.category = "Sprite",
|
||||
.shortcut_hint = "Alt+Shift+1",
|
||||
.visibility_flag = &show_vanilla_editor_,
|
||||
.priority = 10
|
||||
});
|
||||
card_manager.RegisterCard({.card_id = "sprite.vanilla_editor", .display_name = "Vanilla Sprites",
|
||||
.icon = ICON_MD_SMART_TOY, .category = "Sprite",
|
||||
.shortcut_hint = "Alt+Shift+1", .priority = 10});
|
||||
card_manager.RegisterCard({.card_id = "sprite.custom_editor", .display_name = "Custom Sprites",
|
||||
.icon = ICON_MD_ADD_CIRCLE, .category = "Sprite",
|
||||
.shortcut_hint = "Alt+Shift+2", .priority = 20});
|
||||
|
||||
card_manager.RegisterCard({
|
||||
.card_id = "sprite.custom_editor",
|
||||
.display_name = "Custom Sprites",
|
||||
.icon = ICON_MD_ADD_CIRCLE,
|
||||
.category = "Sprite",
|
||||
.shortcut_hint = "Alt+Shift+2",
|
||||
.visibility_flag = &show_custom_editor_,
|
||||
.priority = 20
|
||||
});
|
||||
// Show vanilla editor by default
|
||||
card_manager.ShowCard("sprite.vanilla_editor");
|
||||
}
|
||||
|
||||
absl::Status SpriteEditor::Load() {
|
||||
@@ -56,29 +45,26 @@ absl::Status SpriteEditor::Load() {
|
||||
|
||||
absl::Status SpriteEditor::Update() {
|
||||
if (rom()->is_loaded() && !sheets_loaded_) {
|
||||
// Load the values for current_sheets_ array
|
||||
sheets_loaded_ = true;
|
||||
}
|
||||
|
||||
DrawToolset();
|
||||
gui::VerticalSpacing(2.0f);
|
||||
auto& card_manager = gui::EditorCardManager::Get();
|
||||
|
||||
// Create session-aware cards (non-static for multi-session support)
|
||||
gui::EditorCard vanilla_card(MakeCardTitle("Vanilla Sprites").c_str(), ICON_MD_PEST_CONTROL_RODENT);
|
||||
gui::EditorCard custom_card(MakeCardTitle("Custom Sprites").c_str(), ICON_MD_ADD_MODERATOR);
|
||||
static gui::EditorCard vanilla_card("Vanilla Sprites", ICON_MD_SMART_TOY);
|
||||
static gui::EditorCard custom_card("Custom Sprites", ICON_MD_ADD_CIRCLE);
|
||||
|
||||
if (show_vanilla_editor_) {
|
||||
if (vanilla_card.Begin(&show_vanilla_editor_)) {
|
||||
DrawVanillaSpriteEditor();
|
||||
}
|
||||
vanilla_card.End(); // ALWAYS call End after Begin
|
||||
vanilla_card.SetDefaultSize(900, 700);
|
||||
custom_card.SetDefaultSize(800, 600);
|
||||
|
||||
// Get visibility flags from card manager and pass to Begin()
|
||||
if (vanilla_card.Begin(card_manager.GetVisibilityFlag("sprite.vanilla_editor"))) {
|
||||
DrawVanillaSpriteEditor();
|
||||
vanilla_card.End();
|
||||
}
|
||||
|
||||
if (show_custom_editor_) {
|
||||
if (custom_card.Begin(&show_custom_editor_)) {
|
||||
DrawCustomSprites();
|
||||
}
|
||||
custom_card.End(); // ALWAYS call End after Begin
|
||||
if (custom_card.Begin(card_manager.GetVisibilityFlag("sprite.custom_editor"))) {
|
||||
DrawCustomSprites();
|
||||
custom_card.End();
|
||||
}
|
||||
|
||||
return status_.ok() ? absl::OkStatus() : status_;
|
||||
|
||||
@@ -37,8 +37,8 @@ constexpr ImGuiTableFlags kSpriteTableFlags =
|
||||
*/
|
||||
class SpriteEditor : public Editor {
|
||||
public:
|
||||
explicit SpriteEditor(Rom* rom = nullptr) : rom_(rom) {
|
||||
type_ = EditorType::kSprite;
|
||||
explicit SpriteEditor(Rom* rom = nullptr) : rom_(rom) {
|
||||
type_ = EditorType::kSprite;
|
||||
}
|
||||
|
||||
void Initialize() override;
|
||||
@@ -51,10 +51,10 @@ class SpriteEditor : public Editor {
|
||||
absl::Status Paste() override { return absl::UnimplementedError("Paste"); }
|
||||
absl::Status Find() override { return absl::UnimplementedError("Find"); }
|
||||
absl::Status Save() override { return absl::UnimplementedError("Save"); }
|
||||
|
||||
|
||||
// Set the ROM pointer
|
||||
void set_rom(Rom* rom) { rom_ = rom; }
|
||||
|
||||
|
||||
// Get the ROM pointer
|
||||
Rom* rom() const { return rom_; }
|
||||
|
||||
@@ -84,11 +84,6 @@ class SpriteEditor : public Editor {
|
||||
void DrawAnimationFrames();
|
||||
void DrawToolset();
|
||||
|
||||
// Card visibility - ALL FALSE by default to prevent crash on ROM load
|
||||
// Cards only shown when user explicitly opens them via View menu or shortcuts
|
||||
bool show_vanilla_editor_ = false;
|
||||
bool show_custom_editor_ = false;
|
||||
|
||||
ImVector<int> active_sprites_; /**< Active sprites. */
|
||||
|
||||
int current_sprite_id_; /**< Current sprite ID. */
|
||||
|
||||
@@ -140,25 +140,37 @@ std::vector<ImGuiKey> ParseShortcut(const std::string& shortcut) {
|
||||
void ExecuteShortcuts(const ShortcutManager& shortcut_manager) {
|
||||
// Check for keyboard shortcuts using the shortcut manager
|
||||
for (const auto& shortcut : shortcut_manager.GetShortcuts()) {
|
||||
bool keys_pressed = true;
|
||||
// Check for all the keys in the shortcut
|
||||
bool modifiers_held = true;
|
||||
bool key_pressed = false;
|
||||
ImGuiKey main_key = ImGuiKey_None;
|
||||
|
||||
// Separate modifiers from main key
|
||||
for (const auto& key : shortcut.second.keys) {
|
||||
if (key == ImGuiMod_Ctrl) {
|
||||
keys_pressed &= ImGui::GetIO().KeyCtrl;
|
||||
} else if (key == ImGuiMod_Alt) {
|
||||
keys_pressed &= ImGui::GetIO().KeyAlt;
|
||||
} else if (key == ImGuiMod_Shift) {
|
||||
keys_pressed &= ImGui::GetIO().KeyShift;
|
||||
} else if (key == ImGuiMod_Super) {
|
||||
keys_pressed &= ImGui::GetIO().KeySuper;
|
||||
if (key == ImGuiMod_Ctrl || key == ImGuiMod_Alt ||
|
||||
key == ImGuiMod_Shift || key == ImGuiMod_Super) {
|
||||
// Check if modifier is held
|
||||
if (key == ImGuiMod_Ctrl) {
|
||||
modifiers_held &= ImGui::GetIO().KeyCtrl;
|
||||
} else if (key == ImGuiMod_Alt) {
|
||||
modifiers_held &= ImGui::GetIO().KeyAlt;
|
||||
} else if (key == ImGuiMod_Shift) {
|
||||
modifiers_held &= ImGui::GetIO().KeyShift;
|
||||
} else if (key == ImGuiMod_Super) {
|
||||
modifiers_held &= ImGui::GetIO().KeySuper;
|
||||
}
|
||||
} else {
|
||||
keys_pressed &= ImGui::IsKeyDown(key);
|
||||
}
|
||||
if (!keys_pressed) {
|
||||
break;
|
||||
// This is the main key - use IsKeyPressed for single trigger
|
||||
main_key = key;
|
||||
}
|
||||
}
|
||||
if (keys_pressed) {
|
||||
|
||||
// Check if main key was pressed (not just held)
|
||||
if (main_key != ImGuiKey_None) {
|
||||
key_pressed = ImGui::IsKeyPressed(main_key, false); // false = no repeat
|
||||
}
|
||||
|
||||
// Execute if modifiers held and key pressed
|
||||
if (modifiers_held && key_pressed && shortcut.second.callback) {
|
||||
shortcut.second.callback();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user