(WIP) Refactoring MainWindow, open existing module for edit (still buggy)
Some checks are pending
Build-StoryEditor / build_linux (push) Waiting to run
Build-StoryEditor / build_win32 (push) Waiting to run
Deploy-Documentation / deploy (push) Waiting to run

This commit is contained in:
anthony@rabine.fr 2025-07-27 23:25:57 +02:00
parent 65094d88a3
commit 03fc21dd17
15 changed files with 235 additions and 98 deletions

View file

@ -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<FilterIterator, FilterIterator> Images() = 0;
virtual std::pair<FilterIterator, FilterIterator> Sounds() = 0;

View file

@ -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;
};

View file

@ -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<BaseNode> (*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<NodeInfo> LitOfNodes() const {
std::vector<NodeInfo> 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<NodeInfo> LitOfModules() const {
std::vector<NodeInfo> 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<StoryProject> GetModule(const std::string &name)
std::shared_ptr<StoryProject> GetModule(const std::string &uuid)
{
std::shared_ptr<StoryProject> 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<StoryProject*>(n.second.first.get());
if (p == nullptr)
{
auto p = dynamic_cast<StoryProject*>(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<StoryProject>(entry.second.first);
if (module)
{
// Get the module from the registry
auto module = std::dynamic_pointer_cast<StoryProject>(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<ModuleNode>(ModuleNodeUuid, module);
registerNode<ModuleNode>(module->GetUuid(), module);
return module;
}
@ -166,7 +171,7 @@ public:
p->ParseStoryInformation(j);
if (p->IsModule())
{
registerNode<ModuleNode>(ModuleNodeUuid, p);
registerNode<ModuleNode>(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

View file

@ -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;
};

View file

@ -104,7 +104,7 @@ bool StoryProject::ParseStoryInformation(nlohmann::json &j)
m_name = projectData["name"].get<std::string>();
m_uuid = projectData["uuid"].get<std::string>();
m_uuid = projectData["description"].get<std::string>();
m_description = projectData["description"].get<std::string>();
std::string typeString = projectData["type"].get<std::string>();
if (typeString == "story")

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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 <string> // Pour std::string
#include "library_manager.h" // Pour LibraryManager::GetVersion()
#include <SDL3/SDL.h> // 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

View file

@ -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));

View file

@ -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;

View file

@ -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)

View file

@ -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();

View file

@ -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();
}
}

View file

@ -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;