From c31892ac05476215b5b17863ef51b26d77b36990 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Wed, 1 Apr 2026 00:04:06 +0300 Subject: [PATCH] Load/Save dialogues implemented --- .../editScene/systems/EditorUISystem.cpp | 157 +++++++++++++++++- .../editScene/systems/EditorUISystem.hpp | 17 ++ 2 files changed, 170 insertions(+), 4 deletions(-) diff --git a/src/features/editScene/systems/EditorUISystem.cpp b/src/features/editScene/systems/EditorUISystem.cpp index f6668c4..c76f2d9 100644 --- a/src/features/editScene/systems/EditorUISystem.cpp +++ b/src/features/editScene/systems/EditorUISystem.cpp @@ -7,6 +7,8 @@ #include "../ui/RenderableEditor.hpp" #include #include +#include +#include EditorUISystem::EditorUISystem(flecs::world &world, Ogre::SceneManager *sceneMgr) @@ -115,6 +117,11 @@ void EditorUISystem::update() if (m_gizmo && m_gizmo->isAttached()) { m_gizmo->update(); } + + // Render file dialog if open + if (m_showFileDialog) { + renderFileDialog(); + } } void EditorUISystem::setSelectedEntity(flecs::entity entity) @@ -149,11 +156,11 @@ void EditorUISystem::renderHierarchyWindow() if (ImGui::BeginMenuBar()) { // File menu if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Save Scene", "Ctrl+S")) { - saveScene("scene.json"); + if (ImGui::MenuItem("Save Scene...", "Ctrl+S")) { + showFileDialog(true); } - if (ImGui::MenuItem("Load Scene", "Ctrl+O")) { - loadScene("scene.json"); + if (ImGui::MenuItem("Load Scene...", "Ctrl+O")) { + showFileDialog(false); } ImGui::EndMenu(); } @@ -703,3 +710,145 @@ void EditorUISystem::loadScene(const std::string& filepath) "Failed to load scene: " + m_serializer->getLastError()); } } + + +// File Dialog Implementation + +void EditorUISystem::showFileDialog(bool isSave) +{ + m_showFileDialog = true; + m_fileDialogIsSave = isSave; + m_refreshDirectory = true; + + // Initialize current path if empty + if (m_currentPath.empty()) { + m_currentPath = std::filesystem::current_path().string(); + } + + // Set default filename for save dialog + if (isSave && strlen(m_filenameBuffer) == 0) { + std::strncpy(m_filenameBuffer, "scene.json", sizeof(m_filenameBuffer) - 1); + } +} + +void EditorUISystem::closeFileDialog() +{ + m_showFileDialog = false; +} + +void EditorUISystem::renderFileDialog() +{ + const char* title = m_fileDialogIsSave ? "Save Scene" : "Load Scene"; + + // Center the dialog + ImVec2 center = ImGui::GetMainViewport()->GetCenter(); + ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); + + if (!ImGui::Begin(title, &m_showFileDialog)) { + ImGui::End(); + return; + } + + // Current path display + ImGui::Text("Location: %s", m_currentPath.c_str()); + ImGui::Separator(); + + // Refresh directory contents if needed + if (m_refreshDirectory) { + m_directoryContents.clear(); + try { + for (const auto& entry : std::filesystem::directory_iterator(m_currentPath)) { + m_directoryContents.push_back(entry.path().filename().string()); + } + std::sort(m_directoryContents.begin(), m_directoryContents.end()); + } catch (...) { + // Ignore errors (e.g., permission denied) + } + m_refreshDirectory = false; + } + + // Parent directory button + if (ImGui::Button("..")) { + std::filesystem::path p(m_currentPath); + if (p.has_parent_path()) { + m_currentPath = p.parent_path().string(); + m_refreshDirectory = true; + } + } + ImGui::SameLine(); + ImGui::Text("(Parent Directory)"); + + // File list + ImGui::BeginChild("FileList", ImVec2(0, -60), true); + + for (const auto& name : m_directoryContents) { + std::filesystem::path fullPath = std::filesystem::path(m_currentPath) / name; + bool isDirectory = std::filesystem::is_directory(fullPath); + + // Skip non-json files in load mode (but show directories) + if (!m_fileDialogIsSave && !isDirectory) { + if (fullPath.extension() != ".json") { + continue; + } + } + + std::string label = isDirectory ? "[D] " + name : name; + + if (ImGui::Selectable(label.c_str(), m_selectedFile == name)) { + if (isDirectory) { + m_currentPath = fullPath.string(); + m_refreshDirectory = true; + m_selectedFile.clear(); + } else { + m_selectedFile = name; + std::strncpy(m_filenameBuffer, name.c_str(), sizeof(m_filenameBuffer) - 1); + } + } + + // Double-click to enter directory or select file + if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) { + if (isDirectory) { + m_currentPath = fullPath.string(); + m_refreshDirectory = true; + m_selectedFile.clear(); + } + } + } + + ImGui::EndChild(); + + // Filename input + ImGui::Separator(); + ImGui::Text("Filename:"); + ImGui::SameLine(); + ImGui::InputText("##filename", m_filenameBuffer, sizeof(m_filenameBuffer)); + + // Buttons + if (ImGui::Button(m_fileDialogIsSave ? "Save" : "Load", ImVec2(120, 0))) { + std::string filename(m_filenameBuffer); + if (!filename.empty()) { + // Add .json extension if missing in save mode + if (m_fileDialogIsSave && filename.find('.') == std::string::npos) { + filename += ".json"; + } + + std::string fullPath = (std::filesystem::path(m_currentPath) / filename).string(); + + if (m_fileDialogIsSave) { + saveScene(fullPath); + } else { + loadScene(fullPath); + } + closeFileDialog(); + } + } + + ImGui::SameLine(); + + if (ImGui::Button("Cancel", ImVec2(120, 0))) { + closeFileDialog(); + } + + ImGui::End(); +} diff --git a/src/features/editScene/systems/EditorUISystem.hpp b/src/features/editScene/systems/EditorUISystem.hpp index 503fe47..84f5990 100644 --- a/src/features/editScene/systems/EditorUISystem.hpp +++ b/src/features/editScene/systems/EditorUISystem.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../ui/ComponentRegistry.hpp" #include "../components/EntityName.hpp" #include "../gizmo/Gizmo.hpp" @@ -75,6 +76,13 @@ public: */ void loadScene(const std::string& filepath); + /** + * Show file dialog for save/load + */ + void showFileDialog(bool isSave); + void renderFileDialog(); + void closeFileDialog(); + private: // File menu void renderFileMenu(); @@ -116,6 +124,15 @@ private: // Settings bool m_parentSceneNodes = true; // Whether child entities inherit parent's SceneNode + // File dialog state + bool m_showFileDialog = false; + bool m_fileDialogIsSave = false; // true = save, false = load + std::string m_currentPath; + std::string m_selectedFile; + std::vector m_directoryContents; + bool m_refreshDirectory = true; + char m_filenameBuffer[256] = "scene.json"; + // Queries flecs::query m_nameQuery;