mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Add module properties popup.
This commit is contained in:
parent
dc11cb33dd
commit
8aa18fa5af
7 changed files with 165 additions and 22 deletions
|
|
@ -34,6 +34,7 @@ public:
|
||||||
|
|
||||||
virtual void OpenProject(const std::string &uuid) = 0;
|
virtual void OpenProject(const std::string &uuid) = 0;
|
||||||
virtual void SaveProject() = 0;
|
virtual void SaveProject() = 0;
|
||||||
|
virtual void SaveModule() = 0;
|
||||||
virtual void ImportProject(const std::string &fileName, int format) = 0;
|
virtual void ImportProject(const std::string &fileName, int format) = 0;
|
||||||
virtual void Log(const std::string &txt, bool critical = false) = 0;
|
virtual void Log(const std::string &txt, bool critical = false) = 0;
|
||||||
virtual void PlaySoundFile(const std::string &fileName) = 0;
|
virtual void PlaySoundFile(const std::string &fileName) = 0;
|
||||||
|
|
@ -41,6 +42,7 @@ public:
|
||||||
virtual void OpenFunction(const std::string &uuid, const std::string &name) = 0;
|
virtual void OpenFunction(const std::string &uuid, const std::string &name) = 0;
|
||||||
|
|
||||||
virtual std::shared_ptr<IStoryProject> GetCurrentProject() = 0;
|
virtual std::shared_ptr<IStoryProject> GetCurrentProject() = 0;
|
||||||
|
virtual std::shared_ptr<IStoryProject> GetCurrentModule() = 0;
|
||||||
|
|
||||||
// Node interaction
|
// Node interaction
|
||||||
virtual void BuildCode(bool compileonly) = 0;
|
virtual void BuildCode(bool compileonly) = 0;
|
||||||
|
|
|
||||||
|
|
@ -854,5 +854,10 @@ void AppController::ImportProject(const std::string &filePathName, int format)
|
||||||
|
|
||||||
std::shared_ptr<IStoryProject> AppController::GetCurrentProject()
|
std::shared_ptr<IStoryProject> AppController::GetCurrentProject()
|
||||||
{
|
{
|
||||||
return m_story; // Retourne le projet actuel
|
return m_story;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<IStoryProject> AppController::GetCurrentModule()
|
||||||
|
{
|
||||||
|
return m_module;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,20 +60,19 @@ public:
|
||||||
void CloseProject();
|
void CloseProject();
|
||||||
void SaveProject();
|
void SaveProject();
|
||||||
std::shared_ptr<StoryProject> NewModule();
|
std::shared_ptr<StoryProject> NewModule();
|
||||||
void SaveModule();
|
|
||||||
void CloseModule();
|
void CloseModule();
|
||||||
std::shared_ptr<StoryProject> OpenModule(const std::string &uuid);
|
std::shared_ptr<StoryProject> OpenModule(const std::string &uuid);
|
||||||
void OpenStory(const std::string &path = "");
|
void OpenStory(const std::string &path = "");
|
||||||
void SaveStory(const std::string &path = "");
|
void SaveStory(const std::string &path = "");
|
||||||
void ExportStory(const std::string &filename);
|
void ExportStory(const std::string &filename);
|
||||||
std::shared_ptr<StoryProject> GetCurrentStory() const { return m_story; }
|
|
||||||
std::shared_ptr<StoryProject> GetCurrentModule() const { return m_module; }
|
|
||||||
void CompileNodes(IStoryProject::Type type);
|
void CompileNodes(IStoryProject::Type type);
|
||||||
void Build(bool compileonly);
|
void Build(bool compileonly);
|
||||||
void BuildModule(bool compileonly);
|
void BuildModule(bool compileonly);
|
||||||
void BuildCode(std::shared_ptr<StoryProject> story, bool compileonly, bool force = false);
|
void BuildCode(std::shared_ptr<StoryProject> story, bool compileonly, bool force = false);
|
||||||
|
|
||||||
// --- Fonctions de IStoryManager ---
|
// --- Fonctions de IStoryManager ---
|
||||||
|
void SaveModule() override;
|
||||||
virtual void SetExternalSourceFile(const std::string &filename) override;
|
virtual void SetExternalSourceFile(const std::string &filename) override;
|
||||||
virtual void LoadBinaryStory(const std::string &filename) override;
|
virtual void LoadBinaryStory(const std::string &filename) override;
|
||||||
virtual void ToggleBreakpoint(int line) override;
|
virtual void ToggleBreakpoint(int line) override;
|
||||||
|
|
@ -90,6 +89,7 @@ public:
|
||||||
virtual std::string VmState() const override;
|
virtual std::string VmState() const override;
|
||||||
virtual void BuildCode(bool compileonly);
|
virtual void BuildCode(bool compileonly);
|
||||||
virtual std::shared_ptr<IStoryProject> GetCurrentProject() override;
|
virtual std::shared_ptr<IStoryProject> GetCurrentProject() override;
|
||||||
|
virtual std::shared_ptr<IStoryProject> GetCurrentModule() override;
|
||||||
|
|
||||||
// --- Fonctions de IAudioEvent ---
|
// --- Fonctions de IAudioEvent ---
|
||||||
virtual void EndOfAudio() override;
|
virtual void EndOfAudio() override;
|
||||||
|
|
|
||||||
116
story-editor/src/dialogs/module_properties_dialog.h
Normal file
116
story-editor/src/dialogs/module_properties_dialog.h
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
// module_properties_dialog.h
|
||||||
|
#ifndef MODULE_PROPERTIES_DIALOG_H
|
||||||
|
#define MODULE_PROPERTIES_DIALOG_H
|
||||||
|
|
||||||
|
#include "dialog_base.h"
|
||||||
|
#include <string>
|
||||||
|
#include "i_story_manager.h"
|
||||||
|
#include "IconsMaterialDesignIcons.h"
|
||||||
|
|
||||||
|
class ModulePropertiesDialog : public DialogBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModulePropertiesDialog(IStoryManager &storyManager)
|
||||||
|
: m_storyManager(storyManager)
|
||||||
|
{
|
||||||
|
m_module_name[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Affiche le popup "Module Properties".
|
||||||
|
// Doit être appelée à chaque frame dans la boucle de rendu ImGui.
|
||||||
|
void Draw() override
|
||||||
|
{
|
||||||
|
auto module = m_storyManager.GetCurrentModule();
|
||||||
|
if (module)
|
||||||
|
{
|
||||||
|
if (m_firstOpen)
|
||||||
|
{
|
||||||
|
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||||
|
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||||
|
m_firstOpen = false;
|
||||||
|
// Copy current module name to the edit buffer
|
||||||
|
std::size_t length = module->GetName().copy(m_module_name, sizeof(m_module_name) - 1);
|
||||||
|
m_module_name[length] = '\0';
|
||||||
|
}
|
||||||
|
DrawContent(module);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IStoryManager &m_storyManager;
|
||||||
|
char m_module_name[256] = "";
|
||||||
|
|
||||||
|
// Implémentation de la méthode virtuelle pure GetTitle()
|
||||||
|
const char* GetTitle() const override
|
||||||
|
{
|
||||||
|
return "ModulePropertiesPopup";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawContent(std::shared_ptr<IStoryProject> module)
|
||||||
|
{
|
||||||
|
if (ImGui::BeginPopupModal(GetTitle(), nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGui::Text(ICON_MDI_PUZZLE_OUTLINE " Module Properties");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// Module Name
|
||||||
|
ImGui::Text("Module name:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(300.0f);
|
||||||
|
ImGui::InputTextWithHint("##module_name", "Enter module name", m_module_name, IM_ARRAYSIZE(m_module_name));
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
if (ImGui::Button("OK", ImVec2(120, 0)))
|
||||||
|
{
|
||||||
|
// Validate and save
|
||||||
|
if (strlen(m_module_name) > 0)
|
||||||
|
{
|
||||||
|
module->SetName(m_module_name);
|
||||||
|
m_storyManager.SaveModule();
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show error: name cannot be empty
|
||||||
|
ImGui::OpenPopup("EmptyNameError");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
||||||
|
{
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error popup for empty name
|
||||||
|
if (ImGui::BeginPopupModal("EmptyNameError", NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGui::Text(ICON_MDI_ALERT " Module name cannot be empty!");
|
||||||
|
ImGui::Spacing();
|
||||||
|
if (ImGui::Button("OK", ImVec2(120, 0)))
|
||||||
|
{
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MODULE_PROPERTIES_DIALOG_H
|
||||||
|
|
@ -58,7 +58,7 @@ private:
|
||||||
|
|
||||||
void DrawContent(std::shared_ptr<IStoryProject> story)
|
void DrawContent(std::shared_ptr<IStoryProject> story)
|
||||||
{
|
{
|
||||||
if (ImGui::BeginPopupModal(GetTitle(), NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
if (ImGui::BeginPopupModal(GetTitle(), nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
{
|
{
|
||||||
|
|
||||||
ImGui::Text("Project name: "); ImGui::SameLine();
|
ImGui::Text("Project name: "); ImGui::SameLine();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include "main_window.h"
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "main_window.h"
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include "platform_folders.h"
|
#include "platform_folders.h"
|
||||||
|
|
||||||
|
|
@ -24,6 +26,7 @@
|
||||||
|
|
||||||
#include "app_controller.h"
|
#include "app_controller.h"
|
||||||
#include "all_events.h"
|
#include "all_events.h"
|
||||||
|
#include "story_project.h"
|
||||||
|
|
||||||
#include "nodes_factory.h"
|
#include "nodes_factory.h"
|
||||||
#include "media_node_widget.h"
|
#include "media_node_widget.h"
|
||||||
|
|
@ -55,6 +58,7 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
|
||||||
, m_moduleEditorWindow(appController, appController.GetNodesFactory(), m_widgetFactory, IStoryProject::PROJECT_TYPE_MODULE)
|
, m_moduleEditorWindow(appController, appController.GetNodesFactory(), m_widgetFactory, IStoryProject::PROJECT_TYPE_MODULE)
|
||||||
, m_libraryWindow(appController, appController.GetLibraryManager(), appController.GetNodesFactory(), eventBus)
|
, m_libraryWindow(appController, appController.GetLibraryManager(), appController.GetNodesFactory(), eventBus)
|
||||||
, m_projectPropertiesDialog(appController, appController.GetResourceManager())
|
, m_projectPropertiesDialog(appController, appController.GetResourceManager())
|
||||||
|
, m_modulePropertiesDialog(appController)
|
||||||
{
|
{
|
||||||
CloseProject();
|
CloseProject();
|
||||||
CloseModule();
|
CloseModule();
|
||||||
|
|
@ -174,12 +178,12 @@ float MainWindow::DrawMainMenuBar()
|
||||||
{
|
{
|
||||||
CloseProject();
|
CloseProject();
|
||||||
|
|
||||||
m_story = m_appController.NewProject();
|
auto newProject = m_appController.NewProject();
|
||||||
|
|
||||||
if (m_story)
|
if (newProject)
|
||||||
{
|
{
|
||||||
m_appController.SaveProject();
|
m_appController.SaveProject();
|
||||||
OpenProject(m_story->GetUuid());
|
OpenProject(newProject->GetUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +205,7 @@ float MainWindow::DrawMainMenuBar()
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool init = m_story ? true : false; // local copy because CloseProject() changes the status between BeginDisabled/EndDisabled
|
bool init = m_nodeEditorWindow.GetCurrentStory() ? true : false; // local copy because CloseProject() changes the status between BeginDisabled/EndDisabled
|
||||||
if (!init)
|
if (!init)
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
|
|
||||||
|
|
@ -244,6 +248,11 @@ float MainWindow::DrawMainMenuBar()
|
||||||
CloseModule();
|
CloseModule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Module settings"))
|
||||||
|
{
|
||||||
|
m_modulePropertiesDialog.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
@ -273,10 +282,14 @@ float MainWindow::DrawMainMenuBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_aboutDialog.Open();
|
m_aboutDialog.Open();
|
||||||
if (m_story)
|
if (m_nodeEditorWindow.GetCurrentStory())
|
||||||
{
|
{
|
||||||
m_projectPropertiesDialog.Open();
|
m_projectPropertiesDialog.Open();
|
||||||
}
|
}
|
||||||
|
if (m_moduleEditorWindow.GetCurrentStory())
|
||||||
|
{
|
||||||
|
m_modulePropertiesDialog.Open();
|
||||||
|
}
|
||||||
|
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
@ -339,8 +352,9 @@ bool MainWindow::ShowQuitConfirm()
|
||||||
|
|
||||||
void MainWindow::OpenProject(const std::string &uuid)
|
void MainWindow::OpenProject(const std::string &uuid)
|
||||||
{
|
{
|
||||||
m_nodeEditorWindow.Load(m_story);
|
auto p = dynamic_pointer_cast<StoryProject>(m_appController.GetCurrentProject());
|
||||||
auto proj = m_story->GetProjectFilePath();
|
m_nodeEditorWindow.Load(p);
|
||||||
|
auto proj = p->GetProjectFilePath();
|
||||||
// Add to recent if not exists
|
// Add to recent if not exists
|
||||||
if (std::find(m_recentProjects.begin(), m_recentProjects.end(), proj) == m_recentProjects.end())
|
if (std::find(m_recentProjects.begin(), m_recentProjects.end(), proj) == m_recentProjects.end())
|
||||||
{
|
{
|
||||||
|
|
@ -452,9 +466,14 @@ void MainWindow::RefreshProjectInformation()
|
||||||
{
|
{
|
||||||
std::string fullText = "Story Editor " + LibraryManager::GetVersion();
|
std::string fullText = "Story Editor " + LibraryManager::GetVersion();
|
||||||
|
|
||||||
if (m_story)
|
auto p = m_nodeEditorWindow.GetCurrentStory();
|
||||||
|
if (p)
|
||||||
{
|
{
|
||||||
fullText += " - " + m_story->GetProjectFilePath();
|
auto proj = dynamic_pointer_cast<StoryProject>(p);
|
||||||
|
if (proj)
|
||||||
|
{
|
||||||
|
fullText += " - " + proj->GetProjectFilePath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_gui.SetWindowTitle(fullText);
|
m_gui.SetWindowTitle(fullText);
|
||||||
}
|
}
|
||||||
|
|
@ -607,14 +626,14 @@ bool MainWindow::Loop()
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_S, false))
|
if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_S, false))
|
||||||
{
|
{
|
||||||
if (moduleEditorFocused && m_module)
|
if (moduleEditorFocused && m_moduleEditorWindow.GetCurrentStory())
|
||||||
{
|
{
|
||||||
// Si l'éditeur de module a le focus, sauvegarder le module
|
// Si l'éditeur de module a le focus, sauvegarder le module
|
||||||
m_appController.SaveModule();
|
m_appController.SaveModule();
|
||||||
m_toastNotifier.success("Module sauvegardé");
|
m_toastNotifier.success("Module sauvegardé");
|
||||||
m_logger.Log("Module sauvegardé via Ctrl+S");
|
m_logger.Log("Module sauvegardé via Ctrl+S");
|
||||||
}
|
}
|
||||||
else if (m_story)
|
else if (m_nodeEditorWindow.GetCurrentStory())
|
||||||
{
|
{
|
||||||
// Sinon, sauvegarder l'histoire principale
|
// Sinon, sauvegarder l'histoire principale
|
||||||
m_appController.SaveProject();
|
m_appController.SaveProject();
|
||||||
|
|
@ -633,12 +652,12 @@ bool MainWindow::Loop()
|
||||||
{
|
{
|
||||||
bool moduleEditorFocused = m_moduleEditorWindow.IsFocused();
|
bool moduleEditorFocused = m_moduleEditorWindow.IsFocused();
|
||||||
|
|
||||||
if (moduleEditorFocused && m_module)
|
if (moduleEditorFocused && m_moduleEditorWindow.GetCurrentStory())
|
||||||
{
|
{
|
||||||
m_logger.Log("Building module...");
|
m_logger.Log("Building module...");
|
||||||
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_MODULE);
|
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_MODULE);
|
||||||
}
|
}
|
||||||
else if (m_story)
|
else if (m_nodeEditorWindow.GetCurrentStory())
|
||||||
{
|
{
|
||||||
m_logger.Log("Building story...");
|
m_logger.Log("Building story...");
|
||||||
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_STORY);
|
m_appController.CompileNodes(IStoryProject::PROJECT_TYPE_STORY);
|
||||||
|
|
@ -648,6 +667,7 @@ bool MainWindow::Loop()
|
||||||
|
|
||||||
m_aboutDialog.Draw();
|
m_aboutDialog.Draw();
|
||||||
m_projectPropertiesDialog.Draw();
|
m_projectPropertiesDialog.Draw();
|
||||||
|
m_modulePropertiesDialog.Draw();
|
||||||
|
|
||||||
m_toastNotifier.render();
|
m_toastNotifier.render();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
// Dialogs
|
// Dialogs
|
||||||
#include "about_dialog.h"
|
#include "about_dialog.h"
|
||||||
#include "project_properties_dialog.h"
|
#include "project_properties_dialog.h"
|
||||||
|
#include "module_properties_dialog.h"
|
||||||
|
|
||||||
#include "event_bus.h"
|
#include "event_bus.h"
|
||||||
#include "app_controller.h"
|
#include "app_controller.h"
|
||||||
|
|
@ -31,6 +32,7 @@
|
||||||
#include "LanguageSelector.h"
|
#include "LanguageSelector.h"
|
||||||
#include "chip32_machine.h"
|
#include "chip32_machine.h"
|
||||||
|
|
||||||
|
|
||||||
class MainWindow : public std::enable_shared_from_this<MainWindow>, public ILogSubject
|
class MainWindow : public std::enable_shared_from_this<MainWindow>, public ILogSubject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -48,9 +50,6 @@ private:
|
||||||
AppController &m_appController; // Controller for application logic
|
AppController &m_appController; // Controller for application logic
|
||||||
NodeWidgetFactory m_widgetFactory;
|
NodeWidgetFactory m_widgetFactory;
|
||||||
|
|
||||||
std::shared_ptr<StoryProject> m_story; // Current story
|
|
||||||
std::shared_ptr<StoryProject> m_module; // Current module
|
|
||||||
|
|
||||||
std::vector<std::string> m_recentProjects;
|
std::vector<std::string> m_recentProjects;
|
||||||
|
|
||||||
Gui m_gui;
|
Gui m_gui;
|
||||||
|
|
@ -69,6 +68,7 @@ private:
|
||||||
// Dialogs
|
// Dialogs
|
||||||
AboutDialog m_aboutDialog;
|
AboutDialog m_aboutDialog;
|
||||||
ProjectPropertiesDialog m_projectPropertiesDialog;
|
ProjectPropertiesDialog m_projectPropertiesDialog;
|
||||||
|
ModulePropertiesDialog m_modulePropertiesDialog;
|
||||||
|
|
||||||
ImGuiToastNotifier m_toastNotifier;
|
ImGuiToastNotifier m_toastNotifier;
|
||||||
LanguageSelector m_languageSelector;
|
LanguageSelector m_languageSelector;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue