diff --git a/core/story-manager/interfaces/i_story_manager.h b/core/story-manager/interfaces/i_story_manager.h index 7caae03..0f1bd75 100644 --- a/core/story-manager/interfaces/i_story_manager.h +++ b/core/story-manager/interfaces/i_story_manager.h @@ -39,6 +39,9 @@ public: virtual std::string BuildFullAssetsPath(const std::string_view fileName) const = 0; virtual void OpenFunction(const std::string &uuid, const std::string &name) = 0; + // Modules + virtual void OpenModule(const std::string &uuid) = 0; + // Resources management virtual std::pair Images() = 0; virtual std::pair Sounds() = 0; diff --git a/core/story-manager/interfaces/i_story_project.h b/core/story-manager/interfaces/i_story_project.h index 6ff3a96..422a547 100644 --- a/core/story-manager/interfaces/i_story_project.h +++ b/core/story-manager/interfaces/i_story_project.h @@ -18,7 +18,9 @@ public: virtual ~IStoryProject() {}; virtual std::string GetName() const = 0; - + virtual std::string GetDescription() const = 0; + virtual bool IsModule() const = 0; + virtual std::string GetUuid() const = 0; }; diff --git a/core/story-manager/lib/nodes_factory.h b/core/story-manager/lib/nodes_factory.h index 8d057f6..f094966 100644 --- a/core/story-manager/lib/nodes_factory.h +++ b/core/story-manager/lib/nodes_factory.h @@ -21,7 +21,7 @@ static const std::string CallFunctionNodeUuid = "02745f38-9b11-49fe-94b1-b2a6b78 static const std::string VariableNodeUuid = "020cca4e-9cdc-47e7-a6a5-53e4c9152ed0"; static const std::string PrintNodeUuid = "02ee27bc-ff1d-4f94-b700-eab55052ad1c"; static const std::string SyscallNodeUuid = "02225cff-4975-400e-8130-41524d8af773"; -static const std::string ModuleNodeUuid = "02e4c728-ef72-4003-b7c8-2bee8834a47e"; + typedef std::shared_ptr (*GenericCreator)(const std::string &type); @@ -48,12 +48,25 @@ public: struct NodeInfo { std::string uuid; std::string name; + std::string description; }; // key: uuid, value: node name std::vector LitOfNodes() const { std::vector l; - for(auto const& imap: m_registry) l.push_back(NodeInfo{imap.first, imap.second.first->GetName() }); + for (auto const& imap : m_registry) { + l.push_back(NodeInfo{imap.first, imap.second.first->GetName(), imap.second.first->GetDescription() }); + } + return l; + } + + std::vector LitOfModules() const { + std::vector l; + for (auto const& imap : m_registry) { + if (imap.second.first->IsModule()) { + l.push_back(NodeInfo{imap.first, imap.second.first->GetName(), imap.second.first->GetDescription() }); + } + } return l; } @@ -71,27 +84,23 @@ public: } } - std::shared_ptr GetModule(const std::string &name) + std::shared_ptr GetModule(const std::string &uuid) { std::shared_ptr module; // Scan all function nodes and find the one with that name for (auto n : m_registry) { - if (n.first == ModuleNodeUuid) + if (n.first == uuid) { if (n.second.first) { - // We have a module here, get the name - if (n.second.first->GetName() == name) + auto p = dynamic_cast(n.second.first.get()); + if (p == nullptr) { - auto p = dynamic_cast(n.second.first.get()); - if (p == nullptr) - { - throw std::runtime_error("Node is not a StoryProject"); - } - module = p->shared_from_this(); + throw std::runtime_error("Node is not a StoryProject"); } + module = p->shared_from_this(); } } } @@ -103,15 +112,11 @@ public: { for (const auto &entry : m_registry) { - // Uniquement les modules custom (ici ModuleNodeUuid) - if (entry.first == ModuleNodeUuid) + // Only modules + auto module = std::dynamic_pointer_cast(entry.second.first); + if (module) { - // Get the module from the registry - auto module = std::dynamic_pointer_cast(entry.second.first); - if (module) - { - module->Save(manager); - } + module->Save(manager); } } } @@ -131,7 +136,7 @@ public: module->SetProjectType(IStoryProject::PROJECT_TYPE_MODULE); // Register as module node if not already in registry - registerNode(ModuleNodeUuid, module); + registerNode(module->GetUuid(), module); return module; } @@ -166,7 +171,7 @@ public: p->ParseStoryInformation(j); if (p->IsModule()) { - registerNode(ModuleNodeUuid, p); + registerNode(p->GetUuid(), p); // For now, function node use only primitives nodes // FIXME: in the future, allow function node to use other function nodes // Need a list of required nodes to be registered diff --git a/core/story-manager/src/story_primitive.h b/core/story-manager/src/story_primitive.h index 7a6604f..4c0ad97 100644 --- a/core/story-manager/src/story_primitive.h +++ b/core/story-manager/src/story_primitive.h @@ -7,8 +7,10 @@ class StoryPrimitive : public IStoryProject { public: - StoryPrimitive(const std::string &name) + StoryPrimitive(const std::string &name, const std::string &description = "", const std::string &uuid = "00000000-0000-0000-0000-000000000000") : m_name(name) + , m_description(description) + , m_uuid(uuid) { } @@ -19,7 +21,23 @@ public: return m_name; } + virtual std::string GetDescription() const + { + return m_description; + } + + virtual bool IsModule() const + { + return false; // This is not a module, it's a primitive + } + + virtual std::string GetUuid() const + { + return m_uuid; + } + private: std::string m_name; - + std::string m_description; + std::string m_uuid; }; \ No newline at end of file diff --git a/core/story-manager/src/story_project.cpp b/core/story-manager/src/story_project.cpp index 8531700..a26a83c 100644 --- a/core/story-manager/src/story_project.cpp +++ b/core/story-manager/src/story_project.cpp @@ -104,7 +104,7 @@ bool StoryProject::ParseStoryInformation(nlohmann::json &j) m_name = projectData["name"].get(); m_uuid = projectData["uuid"].get(); - m_uuid = projectData["description"].get(); + m_description = projectData["description"].get(); std::string typeString = projectData["type"].get(); if (typeString == "story") diff --git a/core/story-manager/src/story_project.h b/core/story-manager/src/story_project.h index 243db9a..8c5433b 100644 --- a/core/story-manager/src/story_project.h +++ b/core/story-manager/src/story_project.h @@ -87,9 +87,9 @@ public: std::string GetTitleSound() const { return m_titleSound; } // Initialize with an existing project - const bool IsInitialized() const { return m_initialized; } - const bool IsModule() const { return m_projectType == IStoryProject::PROJECT_TYPE_MODULE; } - const bool IsStory() const { return m_projectType == IStoryProject::PROJECT_TYPE_STORY; } + bool IsInitialized() const { return m_initialized; } + bool IsModule() const override { return m_projectType == IStoryProject::PROJECT_TYPE_MODULE; } + bool IsStory() const { return m_projectType == IStoryProject::PROJECT_TYPE_STORY; } void SetProjectType(IStoryProject::Type type) { m_projectType = type; } bool ParseStoryInformation(nlohmann::json &j); diff --git a/story-editor/CMakeLists.txt b/story-editor/CMakeLists.txt index efbe108..45a45d2 100644 --- a/story-editor/CMakeLists.txt +++ b/story-editor/CMakeLists.txt @@ -118,17 +118,19 @@ add_subdirectory(externals/SDL_image EXCLUDE_FROM_ALL) set(SRCS src/main.cpp + src/main_window.cpp src/windows/window_base.cpp src/windows/console_window.cpp - src/windows/emulator_window.cpp - src/windows/main_window.cpp src/windows/library_window.cpp src/windows/resources_window.cpp src/windows/properties_window.cpp src/windows/debugger_window.cpp src/windows/cpu_window.cpp src/windows/variables_window.cpp + + ## Docks + src/docks/emulator_dock.cpp # src/node_editor/media_node_widget.cpp src/node_editor/base_node_widget.cpp @@ -263,6 +265,8 @@ target_include_directories(${STORY_EDITOR_PROJECT} PUBLIC src/importers src/node_editor src/windows + src/docks + src/dialogs ../firmware/library ../core/chip32 diff --git a/story-editor/imgui.ini b/story-editor/imgui.ini index 088f469..8af86e4 100644 --- a/story-editor/imgui.ini +++ b/story-editor/imgui.ini @@ -9,8 +9,8 @@ Size=400,400 Collapsed=0 [Window][Library Manager] -Pos=643,26 -Size=637,268 +Pos=568,26 +Size=712,288 Collapsed=0 DockId=0x00000003,0 @@ -21,20 +21,20 @@ Collapsed=0 DockId=0x00000004,0 [Window][Emulator] -Pos=643,26 -Size=637,268 +Pos=568,26 +Size=712,288 Collapsed=0 DockId=0x00000003,5 [Window][Code viewer] -Pos=643,26 -Size=637,268 +Pos=568,26 +Size=712,288 Collapsed=0 DockId=0x00000003,4 [Window][Resources] -Pos=643,26 -Size=637,268 +Pos=568,26 +Size=712,288 Collapsed=0 DockId=0x00000003,1 @@ -56,20 +56,20 @@ Collapsed=0 DockId=0x00000005,0 [Window][CPU] -Pos=643,26 -Size=637,268 +Pos=568,26 +Size=712,288 Collapsed=0 DockId=0x00000003,2 [Window][RAM view] -Pos=643,26 -Size=637,268 +Pos=568,26 +Size=712,288 Collapsed=0 DockId=0x00000003,3 [Window][Properties] -Pos=643,296 -Size=637,169 +Pos=568,316 +Size=712,149 Collapsed=0 DockId=0x00000006,0 @@ -90,13 +90,13 @@ Collapsed=0 [Window][Module editor] Pos=60,26 -Size=581,439 +Size=506,439 Collapsed=0 DockId=0x00000001,1 [Window][Story editor] Pos=60,26 -Size=581,439 +Size=506,439 Collapsed=0 DockId=0x00000001,0 @@ -119,13 +119,26 @@ Column 0 Width=259 Sort=0v Column 1 Width=88 Column 2 Width=124 +[Table][0x37CE7681,4] +RefScale=20 +Column 0 Width=567 Sort=0v +Column 1 Width=3930 +Column 2 Width=47 +Column 3 Width=93 + +[Table][0xC3F86B91,3] +RefScale=20 +Column 0 Width=120 Sort=0v +Column 1 Width=104 +Column 2 Width=120 + [Docking][Data] DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,439 Split=X - DockNode ID=0x00000001 Parent=0x00000007 SizeRef=581,694 CentralNode=1 Selected=0x54E37131 - DockNode ID=0x00000002 Parent=0x00000007 SizeRef=637,694 Split=Y Selected=0x52EB28B5 - DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,268 Selected=0x63869CAF - DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,169 Selected=0x8C72BEA8 + DockNode ID=0x00000001 Parent=0x00000007 SizeRef=506,694 CentralNode=1 Selected=0x93ADCAAB + DockNode ID=0x00000002 Parent=0x00000007 SizeRef=712,694 Split=Y Selected=0x52EB28B5 + DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,369 Selected=0x63869CAF + DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,191 Selected=0x8C72BEA8 DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,253 Split=X Selected=0xEA83D666 DockNode ID=0x00000004 Parent=0x00000008 SizeRef=610,192 Selected=0xEA83D666 DockNode ID=0x00000005 Parent=0x00000008 SizeRef=608,192 Selected=0x6DE9B20C diff --git a/story-editor/src/dialogs/about_dialog.h b/story-editor/src/dialogs/about_dialog.h new file mode 100644 index 0000000..5ee708a --- /dev/null +++ b/story-editor/src/dialogs/about_dialog.h @@ -0,0 +1,73 @@ +// about_dialog.h +#ifndef ABOUT_DIALOG_H +#define ABOUT_DIALOG_H + +#include "imgui.h" // Nécessaire pour ImGui::BeginPopupModal, ImGui::Text, etc. +#include // Pour std::string +#include "library_manager.h" // Pour LibraryManager::GetVersion() +#include // Pour SDL_GetPlatform(), SDL_GetNumLogicalCPUCores(), SDL_GetSystemRAM() + +// Il est important de noter que cette classe AboutDialog +// dépendra de ImGui et de SDL pour afficher les informations +// système, comme c'est le cas dans le code original de MainWindow. + +class AboutDialog +{ +public: + AboutDialog() = default; + + // Affiche le popup "About". + // Doit être appelée à chaque frame dans la boucle de rendu ImGui. + void Draw() + { + // Toujours centrer cette fenêtre lorsqu'elle apparaît + ImVec2 center = ImGui::GetMainViewport()->GetCenter(); + ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + + if (ImGui::BeginPopupModal("AboutPopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("Story Editor - v%s", LibraryManager::GetVersion().c_str()); + ImGui::Text("http://www.openstoryteller.org"); + ImGui::Separator(); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Platform"); + + ImGui::Text("%s", SDL_GetPlatform()); + ImGui::Text("CPU cores: %d", SDL_GetNumLogicalCPUCores()); + ImGui::Text("RAM: %.2f GB", SDL_GetSystemRAM() / 1024.0f); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Separator(); + + ImGui::SameLine(300); + if (ImGui::Button("Close", ImVec2(100, 35))) + { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } + + // Ouvre le popup "About". + // Doit être appelée lorsque l'utilisateur clique sur "About" dans le menu. + void Open() + { + if (m_showAboutPopup) + { + ImGui::OpenPopup("AboutPopup"); + } + } + + void Show() + { + m_showAboutPopup = true; + } + + void Reset() + { + m_showAboutPopup = false; + } + +private: + bool m_showAboutPopup = false; // Indique si le popup "About" doit être affiché +}; + +#endif // ABOUT_DIALOG_H \ No newline at end of file diff --git a/story-editor/src/windows/emulator_window.cpp b/story-editor/src/docks/emulator_dock.cpp similarity index 94% rename from story-editor/src/windows/emulator_window.cpp rename to story-editor/src/docks/emulator_dock.cpp index 91b3a1a..9e86299 100644 --- a/story-editor/src/windows/emulator_window.cpp +++ b/story-editor/src/docks/emulator_dock.cpp @@ -1,23 +1,23 @@ -#include "emulator_window.h" +#include "emulator_dock.h" #include "gui.h" #include "ImGuiFileDialog.h" #include "IconsMaterialDesignIcons.h" -EmulatorWindow::EmulatorWindow(IStoryManager &proj) +EmulatorDock::EmulatorDock(IStoryManager &proj) : WindowBase("Emulator") , m_story(proj) { } -void EmulatorWindow::Initialize() +void EmulatorDock::Initialize() { } -void EmulatorWindow::Draw() +void EmulatorDock::Draw() { // if (!IsVisible()) // { @@ -170,12 +170,12 @@ void EmulatorWindow::Draw() WindowBase::EndDraw(); } -void EmulatorWindow::ClearImage() +void EmulatorDock::ClearImage() { m_image.Clear(); } -void EmulatorWindow::SetImage(const std::string &image) +void EmulatorDock::SetImage(const std::string &image) { m_imageFileName = image; m_image.Load(m_story.BuildFullAssetsPath(image)); diff --git a/story-editor/src/windows/emulator_window.h b/story-editor/src/docks/emulator_dock.h similarity index 79% rename from story-editor/src/windows/emulator_window.h rename to story-editor/src/docks/emulator_dock.h index 8560bca..4564870 100644 --- a/story-editor/src/windows/emulator_window.h +++ b/story-editor/src/docks/emulator_dock.h @@ -4,10 +4,10 @@ #include "i_story_manager.h" #include "gui.h" -class EmulatorWindow : public WindowBase +class EmulatorDock : public WindowBase { public: - EmulatorWindow(IStoryManager &proj); + EmulatorDock(IStoryManager &proj); void Initialize(); virtual void Draw() override; diff --git a/story-editor/src/windows/main_window.cpp b/story-editor/src/main_window.cpp similarity index 96% rename from story-editor/src/windows/main_window.cpp rename to story-editor/src/main_window.cpp index 667a421..18c396d 100644 --- a/story-editor/src/windows/main_window.cpp +++ b/story-editor/src/main_window.cpp @@ -32,7 +32,7 @@ MainWindow::MainWindow() , m_resourcesWindow(*this) , m_nodeEditorWindow(*this, m_nodesFactory) , m_moduleEditorWindow(*this, m_nodesFactory, IStoryProject::Type::PROJECT_TYPE_MODULE) - , m_libraryWindow(*this, m_libraryManager) + , m_libraryWindow(*this, m_libraryManager, m_nodesFactory) , m_variablesWindow(*this) , m_player(*this) , m_webServer(m_libraryManager) @@ -435,7 +435,6 @@ void MainWindow::DrawStatusBar() float MainWindow::DrawMainMenuBar() { - bool showAboutPopup = false; bool showParameters = false; bool showNewProject = false; bool showOpenProject = false; @@ -529,7 +528,7 @@ float MainWindow::DrawMainMenuBar() { if (ImGui::MenuItem("About")) { - showAboutPopup = true; + m_aboutDialog.Show(); } ImGui::EndMenu(); } @@ -539,10 +538,7 @@ float MainWindow::DrawMainMenuBar() ImGui::EndMainMenuBar(); } - if (showAboutPopup) - { - ImGui::OpenPopup("AboutPopup"); - } + m_aboutDialog.Open(); if (showParameters) { @@ -556,34 +552,6 @@ float MainWindow::DrawMainMenuBar() } } - // Always center this window when appearing - ImVec2 center = ImGui::GetMainViewport()->GetCenter(); - //ImVec2 parent_pos = ImGui::GetWindowPos(); - //ImVec2 parent_size = ImGui::GetWindowSize(); - //ImVec2 center(parent_pos.x + parent_size.x * 0.5f, parent_pos.y + parent_size.y * 0.5f); - ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - - if (ImGui::BeginPopupModal("AboutPopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::Text("Story Editor - v%s", LibraryManager::GetVersion().c_str()); - ImGui::Text("http://www.openstoryteller.org"); - ImGui::Separator(); - ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Platform"); - - ImGui::Text("%s", SDL_GetPlatform()); - ImGui::Text("CPU cores: %d", SDL_GetNumLogicalCPUCores()); - ImGui::Text("RAM: %.2f GB", SDL_GetSystemRAM() / 1024.0f); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::Separator(); - - ImGui::SameLine(300); - if (ImGui::Button("Close", ImVec2(100, 35))) - { - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - return height; } @@ -1117,6 +1085,7 @@ void MainWindow::Loop() DrawToolBar(height); } + m_aboutDialog.Draw(); ProjectPropertiesPopup(); if (aboutToClose) diff --git a/story-editor/src/windows/main_window.h b/story-editor/src/main_window.h similarity index 97% rename from story-editor/src/windows/main_window.h rename to story-editor/src/main_window.h index 6e1ae00..7ca1e08 100644 --- a/story-editor/src/windows/main_window.h +++ b/story-editor/src/main_window.h @@ -8,7 +8,7 @@ #include "console_window.h" #include "debugger_window.h" -#include "emulator_window.h" +#include "emulator_dock.h" #include "resources_window.h" #include "node_editor_window.h" #include "properties_window.h" @@ -27,6 +27,9 @@ #include "web_server.h" #include "nodes_factory.h" +// Dialogs +#include "about_dialog.h" + struct DebugContext { uint32_t event_mask{0}; @@ -106,7 +109,7 @@ private: LibraryManager m_libraryManager; Gui m_gui; - EmulatorWindow m_emulatorWindow; + EmulatorDock m_emulatorWindow; ConsoleWindow m_consoleWindow; DebuggerWindow m_debuggerWindow; CpuWindow m_cpuWindow; @@ -136,6 +139,9 @@ private: WebServer m_webServer; + // Dialogs + AboutDialog m_aboutDialog; + // From IStoryManager (proxy to StoryProject class) virtual void OpenProject(const std::string &uuid) override; void SaveProject(); diff --git a/story-editor/src/windows/library_window.cpp b/story-editor/src/windows/library_window.cpp index 90fabe6..c786539 100644 --- a/story-editor/src/windows/library_window.cpp +++ b/story-editor/src/windows/library_window.cpp @@ -50,10 +50,11 @@ void download_file(CURL *curl, } -LibraryWindow::LibraryWindow(IStoryManager &project, LibraryManager &library) +LibraryWindow::LibraryWindow(IStoryManager &project, LibraryManager &library, NodesFactory &nodesFactory) : WindowBase("Library Manager") , m_storyManager(project) , m_libraryManager(library) + , m_nodesFactory(nodesFactory) { m_downloadThread = std::thread( std::bind(&LibraryWindow::DownloadThread, this) ); @@ -648,8 +649,50 @@ void LibraryWindow::Draw() ImGui::EndTabItem(); } + // ============================================================================ + // LOCAL MODULES LIST + // ============================================================================ + if (ImGui::BeginTabItem("Local modules ##ModuleTabBar", nullptr, ImGuiTabItemFlags_None)) + { + + const auto &modules = m_nodesFactory.LitOfModules(); + + if (ImGui::BeginTable("modules_table", 3, tableFlags)) + { + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableHeadersRow(); + + for (const auto &module : modules) + { + ImGui::TableNextColumn(); + ImGui::Text("%s", module.name.c_str()); + + ImGui::TableNextColumn(); + ImGui::Text("%s", module.description.c_str()); + + // Add a button to open the module + ImGui::TableNextColumn(); + ImGui::PushID(module.uuid.c_str()); + if (ImGui::SmallButton("Open")) + { + // Open the module in the editor + m_storyManager.OpenModule(module.uuid); + } + ImGui::PopID(); + } + + ImGui::EndTable(); + } + + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); } + } diff --git a/story-editor/src/windows/library_window.h b/story-editor/src/windows/library_window.h index 52d3385..4d57a59 100644 --- a/story-editor/src/windows/library_window.h +++ b/story-editor/src/windows/library_window.h @@ -65,7 +65,7 @@ struct TransferProgress { class LibraryWindow : public WindowBase { public: - LibraryWindow(IStoryManager &project, LibraryManager &library); + LibraryWindow(IStoryManager &project, LibraryManager &library, NodesFactory &nodesFactory); void Initialize(); virtual void Draw() override; @@ -74,6 +74,7 @@ public: private: IStoryManager &m_storyManager; LibraryManager &m_libraryManager; + NodesFactory &m_nodesFactory; Downloader m_downloader; CURL *m_curl;