feat(editor): introduce LayoutManager for enhanced editor layouts
- Added LayoutManager to manage ImGui DockBuilder layouts for various editor types, providing professional default layouts similar to VSCode. - Integrated layout initialization and persistence features, allowing users to save and load custom layouts. - Updated EditorManager to initialize LayoutManager and set default layouts upon editor activation. Benefits: - Improves user experience by offering tailored layouts for different editing tasks. - Enhances maintainability by centralizing layout management and initialization logic within the new LayoutManager class.
This commit is contained in:
@@ -48,6 +48,7 @@ set(
|
|||||||
app/editor/system/window_delegate.cc
|
app/editor/system/window_delegate.cc
|
||||||
app/editor/system/shortcut_configurator.cc
|
app/editor/system/shortcut_configurator.cc
|
||||||
app/editor/ui/editor_selection_dialog.cc
|
app/editor/ui/editor_selection_dialog.cc
|
||||||
|
app/editor/ui/layout_manager.cc
|
||||||
app/editor/ui/menu_builder.cc
|
app/editor/ui/menu_builder.cc
|
||||||
app/editor/ui/ui_coordinator.cc
|
app/editor/ui/ui_coordinator.cc
|
||||||
app/editor/ui/welcome_screen.cc
|
app/editor/ui/welcome_screen.cc
|
||||||
|
|||||||
@@ -182,6 +182,9 @@ EditorManager::EditorManager()
|
|||||||
*session_coordinator_, window_delegate_, toast_manager_, *popup_manager_,
|
*session_coordinator_, window_delegate_, toast_manager_, *popup_manager_,
|
||||||
shortcut_manager_);
|
shortcut_manager_);
|
||||||
|
|
||||||
|
// STEP 4.5: Initialize LayoutManager (DockBuilder layouts for editors)
|
||||||
|
layout_manager_ = std::make_unique<LayoutManager>();
|
||||||
|
|
||||||
// STEP 5: ShortcutConfigurator created later in Initialize() method
|
// STEP 5: ShortcutConfigurator created later in Initialize() method
|
||||||
// It depends on all above coordinators being available
|
// It depends on all above coordinators being available
|
||||||
}
|
}
|
||||||
@@ -1954,6 +1957,12 @@ void EditorManager::SwitchToEditor(EditorType editor_type) {
|
|||||||
// Editor activated - set its category
|
// Editor activated - set its category
|
||||||
card_registry_.SetActiveCategory(
|
card_registry_.SetActiveCategory(
|
||||||
EditorRegistry::GetEditorCategory(editor_type));
|
EditorRegistry::GetEditorCategory(editor_type));
|
||||||
|
|
||||||
|
// Initialize default layout on first activation
|
||||||
|
if (layout_manager_ && !layout_manager_->IsLayoutInitialized(editor_type)) {
|
||||||
|
ImGuiID dockspace_id = ImGui::GetID("MainDockSpace");
|
||||||
|
layout_manager_->InitializeEditorLayout(editor_type, dockspace_id);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Editor deactivated - switch to another active card-based editor
|
// Editor deactivated - switch to another active card-based editor
|
||||||
for (auto* other : current_editor_set_->active_editors_) {
|
for (auto* other : current_editor_set_->active_editors_) {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "app/editor/system/toast_manager.h"
|
#include "app/editor/system/toast_manager.h"
|
||||||
#include "app/editor/system/window_delegate.h"
|
#include "app/editor/system/window_delegate.h"
|
||||||
#include "app/editor/ui/editor_selection_dialog.h"
|
#include "app/editor/ui/editor_selection_dialog.h"
|
||||||
|
#include "app/editor/ui/layout_manager.h"
|
||||||
#include "app/editor/ui/menu_builder.h"
|
#include "app/editor/ui/menu_builder.h"
|
||||||
#include "app/editor/ui/ui_coordinator.h"
|
#include "app/editor/ui/ui_coordinator.h"
|
||||||
#include "app/editor/ui/welcome_screen.h"
|
#include "app/editor/ui/welcome_screen.h"
|
||||||
@@ -409,6 +410,7 @@ class EditorManager {
|
|||||||
std::unique_ptr<UICoordinator> ui_coordinator_;
|
std::unique_ptr<UICoordinator> ui_coordinator_;
|
||||||
WindowDelegate window_delegate_;
|
WindowDelegate window_delegate_;
|
||||||
std::unique_ptr<SessionCoordinator> session_coordinator_;
|
std::unique_ptr<SessionCoordinator> session_coordinator_;
|
||||||
|
std::unique_ptr<LayoutManager> layout_manager_; // DockBuilder layout management
|
||||||
|
|
||||||
float autosave_timer_ = 0.0f;
|
float autosave_timer_ = 0.0f;
|
||||||
|
|
||||||
|
|||||||
@@ -218,18 +218,19 @@ void ConfigureEditorShortcuts(const ShortcutDependencies& deps,
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (card_registry) {
|
if (card_registry) {
|
||||||
|
// Note: Using Ctrl+Alt for card shortcuts to avoid conflicts with Save As (Ctrl+Shift+S)
|
||||||
RegisterIfValid(shortcut_manager, "Show Dungeon Cards",
|
RegisterIfValid(shortcut_manager, "Show Dungeon Cards",
|
||||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_D},
|
{ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_D},
|
||||||
[card_registry]() {
|
[card_registry]() {
|
||||||
card_registry->ShowAllCardsInCategory("Dungeon");
|
card_registry->ShowAllCardsInCategory("Dungeon");
|
||||||
});
|
});
|
||||||
RegisterIfValid(shortcut_manager, "Show Graphics Cards",
|
RegisterIfValid(shortcut_manager, "Show Graphics Cards",
|
||||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_G},
|
{ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_G},
|
||||||
[card_registry]() {
|
[card_registry]() {
|
||||||
card_registry->ShowAllCardsInCategory("Graphics");
|
card_registry->ShowAllCardsInCategory("Graphics");
|
||||||
});
|
});
|
||||||
RegisterIfValid(shortcut_manager, "Show Screen Cards",
|
RegisterIfValid(shortcut_manager, "Show Screen Cards",
|
||||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_S},
|
{ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_S},
|
||||||
[card_registry]() {
|
[card_registry]() {
|
||||||
card_registry->ShowAllCardsInCategory("Screen");
|
card_registry->ShowAllCardsInCategory("Screen");
|
||||||
});
|
});
|
||||||
@@ -320,8 +321,9 @@ void ConfigureMenuShortcuts(const ShortcutDependencies& deps,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Note: Changed from Ctrl+Shift+R to Ctrl+Alt+R to avoid conflict with Proposal Drawer
|
||||||
RegisterIfValid(shortcut_manager, "Reset Layout",
|
RegisterIfValid(shortcut_manager, "Reset Layout",
|
||||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_R},
|
{ImGuiMod_Ctrl, ImGuiMod_Alt, ImGuiKey_R},
|
||||||
[workspace_manager]() {
|
[workspace_manager]() {
|
||||||
if (workspace_manager) {
|
if (workspace_manager) {
|
||||||
workspace_manager->ResetWorkspaceLayout();
|
workspace_manager->ResetWorkspaceLayout();
|
||||||
|
|||||||
413
src/app/editor/ui/layout_manager.cc
Normal file
413
src/app/editor/ui/layout_manager.cc
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
#include "app/editor/ui/layout_manager.h"
|
||||||
|
|
||||||
|
#include "imgui/imgui.h"
|
||||||
|
#include "imgui/imgui_internal.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace editor {
|
||||||
|
|
||||||
|
void LayoutManager::InitializeEditorLayout(EditorType type,
|
||||||
|
ImGuiID dockspace_id) {
|
||||||
|
// Don't reinitialize if already set up
|
||||||
|
if (IsLayoutInitialized(type)) {
|
||||||
|
LOG_INFO("LayoutManager",
|
||||||
|
"Layout for editor type %d already initialized, skipping",
|
||||||
|
static_cast<int>(type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("LayoutManager", "Initializing layout for editor type %d",
|
||||||
|
static_cast<int>(type));
|
||||||
|
|
||||||
|
// Clear existing layout for this dockspace
|
||||||
|
ImGui::DockBuilderRemoveNode(dockspace_id);
|
||||||
|
ImGui::DockBuilderAddNode(dockspace_id,
|
||||||
|
ImGuiDockNodeFlags_DockSpace);
|
||||||
|
ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetMainViewport()->Size);
|
||||||
|
|
||||||
|
// Build layout based on editor type
|
||||||
|
switch (type) {
|
||||||
|
case EditorType::kOverworld:
|
||||||
|
BuildOverworldLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kDungeon:
|
||||||
|
BuildDungeonLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kGraphics:
|
||||||
|
BuildGraphicsLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kPalette:
|
||||||
|
BuildPaletteLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kScreen:
|
||||||
|
BuildScreenLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kMusic:
|
||||||
|
BuildMusicLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kSprite:
|
||||||
|
BuildSpriteLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kMessage:
|
||||||
|
BuildMessageLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kAssembly:
|
||||||
|
BuildAssemblyLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
case EditorType::kSettings:
|
||||||
|
BuildSettingsLayout(dockspace_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WARN("LayoutManager", "No layout defined for editor type %d",
|
||||||
|
static_cast<int>(type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalize the layout
|
||||||
|
ImGui::DockBuilderFinish(dockspace_id);
|
||||||
|
|
||||||
|
// Mark as initialized
|
||||||
|
MarkLayoutInitialized(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildOverworldLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Overworld
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 25%: Tile16 Selector (top 50%) + Tile8 Selector (bottom 50%)
|
||||||
|
// - Center 60%: Main Canvas (full height)
|
||||||
|
// - Right 15%: Area Graphics (top 60%) + Scratch Pad (bottom 40%)
|
||||||
|
//
|
||||||
|
// Additional floating cards:
|
||||||
|
// - Tile16 Editor (floating, 800x600)
|
||||||
|
// - GFX Groups (floating, 700x550)
|
||||||
|
// - Usage Stats (floating, 600x500)
|
||||||
|
// - V3 Settings (floating, 500x600)
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_center_id = 0;
|
||||||
|
ImGuiID dock_right_id = 0;
|
||||||
|
|
||||||
|
// Split dockspace: Left 25% | Center 60% | Right 15%
|
||||||
|
dock_left_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.25f,
|
||||||
|
nullptr, &dockspace_id);
|
||||||
|
dock_right_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right,
|
||||||
|
0.20f, nullptr, &dockspace_id);
|
||||||
|
dock_center_id = dockspace_id; // Center is what remains
|
||||||
|
|
||||||
|
// Split left panel: Tile16 (top) and Tile8 (bottom)
|
||||||
|
ImGuiID dock_left_top = 0;
|
||||||
|
ImGuiID dock_left_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_left_id, ImGuiDir_Down, 0.50f, nullptr, &dock_left_top);
|
||||||
|
|
||||||
|
// Split right panel: Area Graphics (top) and Scratch Pad (bottom)
|
||||||
|
ImGuiID dock_right_top = 0;
|
||||||
|
ImGuiID dock_right_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_right_id, ImGuiDir_Down, 0.40f, nullptr, &dock_right_top);
|
||||||
|
|
||||||
|
// Dock windows to their designated nodes
|
||||||
|
ImGui::DockBuilderDockWindow(" Overworld Canvas", dock_center_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Tile16 Selector", dock_left_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Tile8 Selector", dock_left_bottom);
|
||||||
|
ImGui::DockBuilderDockWindow(" Area Graphics", dock_right_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Scratch Pad", dock_right_bottom);
|
||||||
|
|
||||||
|
// Note: Floating windows (Tile16 Editor, GFX Groups, etc.) are not docked
|
||||||
|
// They will appear as floating windows with their configured default positions
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildDungeonLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Dungeon
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 20%: Room Selector (top 60%) + Entrances (bottom 40%)
|
||||||
|
// - Center 65%: Room Canvas + Tabs for multiple rooms
|
||||||
|
// - Right 15%: Object Editor (top) + Palette Editor (bottom)
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_center_id = 0;
|
||||||
|
ImGuiID dock_right_id = 0;
|
||||||
|
|
||||||
|
// Split dockspace: Left 20% | Center 65% | Right 15%
|
||||||
|
dock_left_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.20f,
|
||||||
|
nullptr, &dockspace_id);
|
||||||
|
dock_right_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right,
|
||||||
|
0.19f, nullptr, &dockspace_id);
|
||||||
|
dock_center_id = dockspace_id;
|
||||||
|
|
||||||
|
// Split left panel: Room Selector (top 60%) and Entrances (bottom 40%)
|
||||||
|
ImGuiID dock_left_top = 0;
|
||||||
|
ImGuiID dock_left_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_left_id, ImGuiDir_Down, 0.40f, nullptr, &dock_left_top);
|
||||||
|
|
||||||
|
// Split right panel: Object Editor (top 50%) and Palette Editor (bottom 50%)
|
||||||
|
ImGuiID dock_right_top = 0;
|
||||||
|
ImGuiID dock_right_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_right_id, ImGuiDir_Down, 0.50f, nullptr, &dock_right_top);
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" Rooms List", dock_left_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Entrances", dock_left_bottom);
|
||||||
|
ImGui::DockBuilderDockWindow(" Object Editor", dock_right_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Palette Editor", dock_right_bottom);
|
||||||
|
|
||||||
|
// Room tabs and Room Matrix are floating by default
|
||||||
|
// Individual room windows (###RoomCard*) will dock together due to their
|
||||||
|
// window class
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildGraphicsLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Graphics
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 30%: Sheet Browser
|
||||||
|
// - Center 50%: Sheet Editor
|
||||||
|
// - Right 20%: Animations (top) + Prototype (bottom)
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_center_id = 0;
|
||||||
|
ImGuiID dock_right_id = 0;
|
||||||
|
|
||||||
|
// Split dockspace: Left 30% | Center 50% | Right 20%
|
||||||
|
dock_left_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.30f,
|
||||||
|
nullptr, &dockspace_id);
|
||||||
|
dock_right_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right,
|
||||||
|
0.29f, nullptr, &dockspace_id);
|
||||||
|
dock_center_id = dockspace_id;
|
||||||
|
|
||||||
|
// Split right panel: Animations (top) and Prototype (bottom)
|
||||||
|
ImGuiID dock_right_top = 0;
|
||||||
|
ImGuiID dock_right_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_right_id, ImGuiDir_Down, 0.50f, nullptr, &dock_right_top);
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" GFX Sheets", dock_left_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Sheet Editor", dock_center_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Animations", dock_right_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Prototype", dock_right_bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildPaletteLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Palette
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 25%: Group Manager (top) + ROM Palette Browser (bottom)
|
||||||
|
// - Center 50%: Main Palette Editor
|
||||||
|
// - Right 25%: SNES Palette (top) + Color Harmony Tools (bottom)
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_center_id = 0;
|
||||||
|
ImGuiID dock_right_id = 0;
|
||||||
|
|
||||||
|
// Split dockspace: Left 25% | Center 50% | Right 25%
|
||||||
|
dock_left_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.25f,
|
||||||
|
nullptr, &dockspace_id);
|
||||||
|
dock_right_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right,
|
||||||
|
0.33f, nullptr, &dockspace_id);
|
||||||
|
dock_center_id = dockspace_id;
|
||||||
|
|
||||||
|
// Split left panel: Group Manager (top) and ROM Browser (bottom)
|
||||||
|
ImGuiID dock_left_top = 0;
|
||||||
|
ImGuiID dock_left_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_left_id, ImGuiDir_Down, 0.50f, nullptr, &dock_left_top);
|
||||||
|
|
||||||
|
// Split right panel: SNES Palette (top) and Color Tools (bottom)
|
||||||
|
ImGuiID dock_right_top = 0;
|
||||||
|
ImGuiID dock_right_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_right_id, ImGuiDir_Down, 0.50f, nullptr, &dock_right_top);
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" Group Manager", dock_left_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" ROM Palette Browser", dock_left_bottom);
|
||||||
|
ImGui::DockBuilderDockWindow(" Palette Editor", dock_center_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" SNES Palette", dock_right_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Color Harmony", dock_right_bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildScreenLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Screen
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Grid layout with Overworld Map in center (larger)
|
||||||
|
// - Corners: Dungeon Maps, Title Screen, Inventory Menu, Naming Screen
|
||||||
|
|
||||||
|
ImGuiID dock_top = 0;
|
||||||
|
ImGuiID dock_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dockspace_id, ImGuiDir_Down, 0.50f, nullptr, &dock_top);
|
||||||
|
|
||||||
|
// Split top: left and right
|
||||||
|
ImGuiID dock_top_left = 0;
|
||||||
|
ImGuiID dock_top_right = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_top, ImGuiDir_Right, 0.50f, nullptr, &dock_top_left);
|
||||||
|
|
||||||
|
// Split bottom: left and right
|
||||||
|
ImGuiID dock_bottom_left = 0;
|
||||||
|
ImGuiID dock_bottom_right = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_bottom, ImGuiDir_Right, 0.50f, nullptr, &dock_bottom_left);
|
||||||
|
|
||||||
|
// Dock windows in grid
|
||||||
|
ImGui::DockBuilderDockWindow(" Dungeon Map Editor", dock_top_left);
|
||||||
|
ImGui::DockBuilderDockWindow(" Title Screen", dock_top_right);
|
||||||
|
ImGui::DockBuilderDockWindow(" Inventory Menu", dock_bottom_left);
|
||||||
|
ImGui::DockBuilderDockWindow(" Naming Screen", dock_bottom_right);
|
||||||
|
|
||||||
|
// Overworld Map could be floating or in center - let user configure
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildMusicLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Music Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 30%: Music Tracker
|
||||||
|
// - Center 45%: Instrument Editor
|
||||||
|
// - Right 25%: Assembly/Export
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_center_id = 0;
|
||||||
|
ImGuiID dock_right_id = 0;
|
||||||
|
|
||||||
|
// Split dockspace: Left 30% | Center 45% | Right 25%
|
||||||
|
dock_left_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.30f,
|
||||||
|
nullptr, &dockspace_id);
|
||||||
|
dock_right_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right,
|
||||||
|
0.36f, nullptr, &dockspace_id);
|
||||||
|
dock_center_id = dockspace_id;
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" Music Tracker", dock_left_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Instrument Editor", dock_center_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Music Assembly", dock_right_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildSpriteLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Sprite
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 50%: Vanilla Sprites
|
||||||
|
// - Right 50%: Custom Sprites
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_right_id = ImGui::DockBuilderSplitNode(
|
||||||
|
dockspace_id, ImGuiDir_Right, 0.50f, nullptr, &dock_left_id);
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" Vanilla Sprites", dock_left_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Custom Sprites", dock_right_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildMessageLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Message
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 25%: Message List
|
||||||
|
// - Center 50%: Message Editor
|
||||||
|
// - Right 25%: Font Atlas (top) + Dictionary (bottom)
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_center_id = 0;
|
||||||
|
ImGuiID dock_right_id = 0;
|
||||||
|
|
||||||
|
// Split dockspace: Left 25% | Center 50% | Right 25%
|
||||||
|
dock_left_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.25f,
|
||||||
|
nullptr, &dockspace_id);
|
||||||
|
dock_right_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right,
|
||||||
|
0.33f, nullptr, &dockspace_id);
|
||||||
|
dock_center_id = dockspace_id;
|
||||||
|
|
||||||
|
// Split right panel: Font Atlas (top) and Dictionary (bottom)
|
||||||
|
ImGuiID dock_right_top = 0;
|
||||||
|
ImGuiID dock_right_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_right_id, ImGuiDir_Down, 0.50f, nullptr, &dock_right_top);
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" Message List", dock_left_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Message Editor", dock_center_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Font Atlas", dock_right_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Dictionary", dock_right_bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildAssemblyLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Assembly
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 60%: Code Editor
|
||||||
|
// - Right 40%: Output/Errors (top) + Documentation (bottom)
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_right_id = ImGui::DockBuilderSplitNode(
|
||||||
|
dockspace_id, ImGuiDir_Right, 0.40f, nullptr, &dock_left_id);
|
||||||
|
|
||||||
|
// Split right panel: Output (top) and Docs (bottom)
|
||||||
|
ImGuiID dock_right_top = 0;
|
||||||
|
ImGuiID dock_right_bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
dock_right_id, ImGuiDir_Down, 0.50f, nullptr, &dock_right_top);
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" Assembly Editor", dock_left_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Assembly Output", dock_right_top);
|
||||||
|
ImGui::DockBuilderDockWindow(" Assembly Docs", dock_right_bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::BuildSettingsLayout(ImGuiID dockspace_id) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement DockBuilder layout for Settings
|
||||||
|
// Editor
|
||||||
|
//
|
||||||
|
// Desired layout:
|
||||||
|
// - Left 25%: Category navigation (vertical list)
|
||||||
|
// - Right 75%: Settings content for selected category
|
||||||
|
|
||||||
|
ImGuiID dock_left_id = 0;
|
||||||
|
ImGuiID dock_right_id = ImGui::DockBuilderSplitNode(
|
||||||
|
dockspace_id, ImGuiDir_Right, 0.75f, nullptr, &dock_left_id);
|
||||||
|
|
||||||
|
// Dock windows
|
||||||
|
ImGui::DockBuilderDockWindow(" Settings Navigation", dock_left_id);
|
||||||
|
ImGui::DockBuilderDockWindow(" Settings Content", dock_right_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::SaveCurrentLayout(const std::string& name) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement layout saving to file
|
||||||
|
// Use ImGui::SaveIniSettingsToMemory() and write to custom file
|
||||||
|
LOG_INFO("LayoutManager", "Saving layout: %s", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::LoadLayout(const std::string& name) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement layout loading from file
|
||||||
|
// Use ImGui::LoadIniSettingsFromMemory() and read from custom file
|
||||||
|
LOG_INFO("LayoutManager", "Loading layout: %s", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::ResetToDefaultLayout(EditorType type) {
|
||||||
|
layouts_initialized_[type] = false;
|
||||||
|
LOG_INFO("LayoutManager", "Reset layout for editor type %d",
|
||||||
|
static_cast<int>(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayoutManager::IsLayoutInitialized(EditorType type) const {
|
||||||
|
auto it = layouts_initialized_.find(type);
|
||||||
|
return it != layouts_initialized_.end() && it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::MarkLayoutInitialized(EditorType type) {
|
||||||
|
layouts_initialized_[type] = true;
|
||||||
|
LOG_INFO("LayoutManager", "Marked layout for editor type %d as initialized",
|
||||||
|
static_cast<int>(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::ClearInitializationFlags() {
|
||||||
|
layouts_initialized_.clear();
|
||||||
|
LOG_INFO("LayoutManager", "Cleared all layout initialization flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace editor
|
||||||
|
} // namespace yaze
|
||||||
|
|
||||||
96
src/app/editor/ui/layout_manager.h
Normal file
96
src/app/editor/ui/layout_manager.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#ifndef YAZE_APP_EDITOR_UI_LAYOUT_MANAGER_H_
|
||||||
|
#define YAZE_APP_EDITOR_UI_LAYOUT_MANAGER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "app/editor/editor.h"
|
||||||
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace editor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class LayoutManager
|
||||||
|
* @brief Manages ImGui DockBuilder layouts for each editor type
|
||||||
|
*
|
||||||
|
* Provides professional default layouts using ImGui's DockBuilder API,
|
||||||
|
* similar to VSCode's workspace layouts. Each editor type has a custom
|
||||||
|
* layout optimized for its workflow.
|
||||||
|
*
|
||||||
|
* Features:
|
||||||
|
* - Per-editor default layouts (Overworld, Dungeon, Graphics, etc.)
|
||||||
|
* - Layout persistence and restoration
|
||||||
|
* - Workspace presets (Developer, Designer, Modder)
|
||||||
|
* - Dynamic layout initialization on first editor switch
|
||||||
|
*/
|
||||||
|
class LayoutManager {
|
||||||
|
public:
|
||||||
|
LayoutManager() = default;
|
||||||
|
~LayoutManager() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the default layout for a specific editor type
|
||||||
|
* @param type The editor type to initialize
|
||||||
|
* @param dockspace_id The ImGui dockspace ID to build the layout in
|
||||||
|
*/
|
||||||
|
void InitializeEditorLayout(EditorType type, ImGuiID dockspace_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Save the current layout with a custom name
|
||||||
|
* @param name The name to save the layout under
|
||||||
|
*/
|
||||||
|
void SaveCurrentLayout(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a saved layout by name
|
||||||
|
* @param name The name of the layout to load
|
||||||
|
*/
|
||||||
|
void LoadLayout(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the layout for an editor to its default
|
||||||
|
* @param type The editor type to reset
|
||||||
|
*/
|
||||||
|
void ResetToDefaultLayout(EditorType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a layout has been initialized for an editor
|
||||||
|
* @param type The editor type to check
|
||||||
|
* @return True if layout is initialized
|
||||||
|
*/
|
||||||
|
bool IsLayoutInitialized(EditorType type) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mark a layout as initialized
|
||||||
|
* @param type The editor type to mark
|
||||||
|
*/
|
||||||
|
void MarkLayoutInitialized(EditorType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear all initialization flags (for testing)
|
||||||
|
*/
|
||||||
|
void ClearInitializationFlags();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// DockBuilder layout implementations for each editor type
|
||||||
|
void BuildOverworldLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildDungeonLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildGraphicsLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildPaletteLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildScreenLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildMusicLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildSpriteLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildMessageLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildAssemblyLayout(ImGuiID dockspace_id);
|
||||||
|
void BuildSettingsLayout(ImGuiID dockspace_id);
|
||||||
|
|
||||||
|
// Track which layouts have been initialized
|
||||||
|
std::unordered_map<EditorType, bool> layouts_initialized_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace editor
|
||||||
|
} // namespace yaze
|
||||||
|
|
||||||
|
#endif // YAZE_APP_EDITOR_UI_LAYOUT_MANAGER_H_
|
||||||
|
|
||||||
@@ -107,6 +107,7 @@ void UICoordinator::DrawAllUI() {
|
|||||||
// Draw UI windows and dialogs
|
// Draw UI windows and dialogs
|
||||||
// Session dialogs are drawn by SessionCoordinator separately to avoid duplication
|
// Session dialogs are drawn by SessionCoordinator separately to avoid duplication
|
||||||
DrawCommandPalette(); // Ctrl+Shift+P
|
DrawCommandPalette(); // Ctrl+Shift+P
|
||||||
|
DrawGlobalSearch(); // Ctrl+Shift+K
|
||||||
DrawLayoutPresets(); // Layout preset dialogs
|
DrawLayoutPresets(); // Layout preset dialogs
|
||||||
DrawWelcomeScreen(); // Welcome screen
|
DrawWelcomeScreen(); // Welcome screen
|
||||||
DrawProjectHelp(); // Project help
|
DrawProjectHelp(); // Project help
|
||||||
@@ -304,6 +305,10 @@ void UICoordinator::DrawWelcomeScreen() {
|
|||||||
// Draw the welcome screen
|
// Draw the welcome screen
|
||||||
LOG_INFO("UICoordinator", "Rendering welcome screen window");
|
LOG_INFO("UICoordinator", "Rendering welcome screen window");
|
||||||
|
|
||||||
|
// Reset first show flag to override ImGui ini state
|
||||||
|
// This ensures the window appears even if imgui.ini has it hidden
|
||||||
|
welcome_screen_->ResetFirstShow();
|
||||||
|
|
||||||
// Update recent projects before showing
|
// Update recent projects before showing
|
||||||
welcome_screen_->RefreshRecentProjects();
|
welcome_screen_->RefreshRecentProjects();
|
||||||
|
|
||||||
@@ -670,6 +675,153 @@ void UICoordinator::DrawCommandPalette() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UICoordinator::DrawGlobalSearch() {
|
||||||
|
if (!show_global_search_) return;
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
|
||||||
|
|
||||||
|
SetNextWindowPos(GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||||
|
SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
|
bool show_search = true;
|
||||||
|
if (Begin(absl::StrFormat("%s Global Search", ICON_MD_SEARCH).c_str(),
|
||||||
|
&show_search, ImGuiWindowFlags_NoCollapse)) {
|
||||||
|
|
||||||
|
// Search input with focus management
|
||||||
|
SetNextItemWidth(-100);
|
||||||
|
if (IsWindowAppearing()) {
|
||||||
|
SetKeyboardFocusHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool input_changed = InputTextWithHint(
|
||||||
|
"##global_search_query",
|
||||||
|
absl::StrFormat("%s Search ROM data, cards, editors, resources...", ICON_MD_SEARCH).c_str(),
|
||||||
|
global_search_query_, IM_ARRAYSIZE(global_search_query_));
|
||||||
|
|
||||||
|
SameLine();
|
||||||
|
if (Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
|
||||||
|
global_search_query_[0] = '\0';
|
||||||
|
input_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator();
|
||||||
|
|
||||||
|
// Search results organized by category
|
||||||
|
if (BeginTabBar("SearchCategories")) {
|
||||||
|
// TODO: [EditorManagerRefactor] Implement actual ROM data searching
|
||||||
|
// This should search through:
|
||||||
|
// - Editor cards (all registered cards across all editors)
|
||||||
|
// - ROM resources (palettes, graphics, sprites, etc.)
|
||||||
|
// - Text strings (messages, dialogue)
|
||||||
|
// - Map names, room names, sprite names
|
||||||
|
// - Memory addresses and labels
|
||||||
|
|
||||||
|
if (BeginTabItem(absl::StrFormat("%s All Results", ICON_MD_LIST).c_str())) {
|
||||||
|
if (global_search_query_[0] != '\0') {
|
||||||
|
// Search through editor cards
|
||||||
|
TextColored(gui::ConvertColorToImVec4(theme.info),
|
||||||
|
"%s Editor Cards", ICON_MD_DASHBOARD);
|
||||||
|
Separator();
|
||||||
|
|
||||||
|
// Get current session ID from editor manager
|
||||||
|
size_t current_session_id = 0;
|
||||||
|
if (editor_manager_) {
|
||||||
|
current_session_id = editor_manager_->GetCurrentSessionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all cards in current session
|
||||||
|
auto card_ids = card_registry_.GetCardsInSession(current_session_id);
|
||||||
|
bool found_cards = false;
|
||||||
|
|
||||||
|
for (const auto& card_id : card_ids) {
|
||||||
|
const auto* card_info = card_registry_.GetCardInfo(current_session_id, card_id);
|
||||||
|
if (!card_info) continue;
|
||||||
|
|
||||||
|
std::string search_lower = global_search_query_;
|
||||||
|
std::string card_lower = card_info->display_name;
|
||||||
|
std::transform(search_lower.begin(), search_lower.end(),
|
||||||
|
search_lower.begin(), ::tolower);
|
||||||
|
std::transform(card_lower.begin(), card_lower.end(),
|
||||||
|
card_lower.begin(), ::tolower);
|
||||||
|
|
||||||
|
if (card_lower.find(search_lower) != std::string::npos) {
|
||||||
|
if (Selectable(absl::StrFormat("%s %s - %s",
|
||||||
|
card_info->icon.c_str(),
|
||||||
|
card_info->display_name.c_str(),
|
||||||
|
card_info->category.c_str()).c_str())) {
|
||||||
|
// Show the card when selected
|
||||||
|
card_registry_.ShowCard(current_session_id, card_id);
|
||||||
|
show_global_search_ = false;
|
||||||
|
}
|
||||||
|
if (IsItemHovered()) {
|
||||||
|
BeginTooltip();
|
||||||
|
Text("Category: %s", card_info->category.c_str());
|
||||||
|
Text("Shortcut: %s", card_info->shortcut_hint.c_str());
|
||||||
|
Text("Click to open");
|
||||||
|
EndTooltip();
|
||||||
|
}
|
||||||
|
found_cards = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_cards) {
|
||||||
|
PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
|
||||||
|
Text("No cards found matching '%s'", global_search_query_);
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacing();
|
||||||
|
Spacing();
|
||||||
|
|
||||||
|
// TODO: [EditorManagerRefactor] Add more search categories:
|
||||||
|
// - ROM Resources (palettes, graphics, sprites)
|
||||||
|
// - Text/Messages
|
||||||
|
// - Map/Room names
|
||||||
|
// - Memory addresses
|
||||||
|
} else {
|
||||||
|
PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
|
||||||
|
Text("%s Enter search query to find ROM data, cards, and resources",
|
||||||
|
ICON_MD_INFO);
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BeginTabItem(absl::StrFormat("%s Cards", ICON_MD_DASHBOARD).c_str())) {
|
||||||
|
Text("Card-specific search coming soon...");
|
||||||
|
EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BeginTabItem(absl::StrFormat("%s ROM Data", ICON_MD_STORAGE).c_str())) {
|
||||||
|
Text("ROM data search coming soon...");
|
||||||
|
EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BeginTabItem(absl::StrFormat("%s Text", ICON_MD_TEXT_FIELDS).c_str())) {
|
||||||
|
Text("Text search coming soon...");
|
||||||
|
EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
EndTabBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status bar
|
||||||
|
Separator();
|
||||||
|
Text("%s Global Search", ICON_MD_INFO);
|
||||||
|
SameLine();
|
||||||
|
PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
|
||||||
|
Text("| Currently searches: Editor Cards | More categories coming soon");
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
// Update visibility state
|
||||||
|
if (!show_search) {
|
||||||
|
show_global_search_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace editor
|
} // namespace editor
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,15 @@ bool WelcomeScreen::Show(bool* p_open) {
|
|||||||
ImGui::SetNextWindowPos(center, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
ImGui::SetNextWindowPos(center, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||||
ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_Always);
|
ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_Always);
|
||||||
|
|
||||||
|
// CRITICAL: Override ImGui's saved window state from imgui.ini
|
||||||
|
// Without this, ImGui will restore the last saved state (hidden/collapsed)
|
||||||
|
// even when our logic says the window should be visible
|
||||||
|
if (first_show_attempt_) {
|
||||||
|
ImGui::SetNextWindowCollapsed(false); // Force window to be expanded
|
||||||
|
ImGui::SetNextWindowFocus(); // Bring window to front
|
||||||
|
first_show_attempt_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoCollapse |
|
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoCollapse |
|
||||||
ImGuiWindowFlags_NoResize |
|
ImGuiWindowFlags_NoResize |
|
||||||
ImGuiWindowFlags_NoMove;
|
ImGuiWindowFlags_NoMove;
|
||||||
|
|||||||
@@ -79,6 +79,11 @@ class WelcomeScreen {
|
|||||||
*/
|
*/
|
||||||
void MarkManuallyClosed() { manually_closed_ = true; }
|
void MarkManuallyClosed() { manually_closed_ = true; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset first show flag (for testing/forcing display)
|
||||||
|
*/
|
||||||
|
void ResetFirstShow() { first_show_attempt_ = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DrawHeader();
|
void DrawHeader();
|
||||||
void DrawQuickActions();
|
void DrawQuickActions();
|
||||||
@@ -90,6 +95,7 @@ class WelcomeScreen {
|
|||||||
|
|
||||||
std::vector<RecentProject> recent_projects_;
|
std::vector<RecentProject> recent_projects_;
|
||||||
bool manually_closed_ = false;
|
bool manually_closed_ = false;
|
||||||
|
bool first_show_attempt_ = true; // Override ImGui ini state on first display
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
std::function<void()> open_rom_callback_;
|
std::function<void()> open_rom_callback_;
|
||||||
|
|||||||
Reference in New Issue
Block a user