mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Start of module editor with pre version of independant factory
This commit is contained in:
parent
b962d303c5
commit
81f7e9343b
10 changed files with 218 additions and 80 deletions
|
|
@ -32,7 +32,7 @@ class IStoryManager
|
|||
public:
|
||||
virtual ~IStoryManager() {}
|
||||
|
||||
virtual void OpenProject(const std::string &uuid) = 0;
|
||||
virtual void OpenProject(const std::string &uuid, IStoryManager::ProjectType type) = 0;
|
||||
virtual void ImportProject(const std::string &fileName, int format) = 0;
|
||||
virtual void Log(const std::string &txt, bool critical = false) = 0;
|
||||
virtual void PlaySoundFile(const std::string &fileName) = 0;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class IStoryProject
|
|||
{
|
||||
public:
|
||||
|
||||
enum ProjectType
|
||||
enum Type
|
||||
{
|
||||
PROJECT_TYPE_STORY = 0,
|
||||
PROJECT_TYPE_MODULE = 1,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <filesystem>
|
||||
|
||||
#include "json.hpp"
|
||||
// #include "media_node.h"
|
||||
#include "function_node.h"
|
||||
|
|
@ -7,20 +12,34 @@
|
|||
#include "operator_node.h"
|
||||
#include "print_node.h"
|
||||
#include "syscall_node.h"
|
||||
#include "story_project.h"
|
||||
|
||||
static const std::string OperatorNodeUuid = "0226fdac-8f7a-47d7-8584-b23aceb712ec";
|
||||
static const std::string FunctionNodeUuid = "02745f38-9b11-49fe-94b1-b2a6b78249fb";
|
||||
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";
|
||||
|
||||
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &type);
|
||||
|
||||
class NodesFactory
|
||||
{
|
||||
|
||||
public:
|
||||
NodesFactory() {
|
||||
|
||||
NodesFactory(ILogger &log)
|
||||
: m_log(log)
|
||||
, m_rootPath("")
|
||||
{
|
||||
// Register node types
|
||||
// registerNode<MediaNode>("media-node");
|
||||
registerNode<OperatorNode>("operator-node");
|
||||
registerNode<FunctionNode>("function-node");
|
||||
registerNode<VariableNode>("variable-node");
|
||||
registerNode<PrintNode>("print-node");
|
||||
registerNode<SyscallNode>("syscall-node");
|
||||
registerNode<OperatorNode>(OperatorNodeUuid, nullptr);
|
||||
registerNode<FunctionNode>(FunctionNodeUuid, nullptr);
|
||||
registerNode<VariableNode>(VariableNodeUuid, nullptr);
|
||||
registerNode<PrintNode>(PrintNodeUuid, nullptr);
|
||||
registerNode<SyscallNode>(SyscallNodeUuid, nullptr);
|
||||
}
|
||||
|
||||
~NodesFactory() = default;
|
||||
|
||||
std::vector<std::string> GetNodeTypes() const {
|
||||
|
|
@ -38,12 +57,58 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
auto n = i->second(type);
|
||||
auto n = i->second.second(type);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
void SetModulesRootDirectory(const std::string &rootPath) {
|
||||
m_rootPath = rootPath;
|
||||
}
|
||||
|
||||
void ScanModules() {
|
||||
// This function should scan the rootPath for modules and register them
|
||||
// For now, we just log the root path
|
||||
std::cout << "Scanning modules in: " << m_rootPath << std::endl;
|
||||
// Here you would implement the logic to scan the directory and register modules
|
||||
|
||||
// For example, you could read JSON files in the directory and create nodes based on their content
|
||||
// This is a placeholder for actual scanning logic
|
||||
// Example: registerNode<CustomModuleNode>("custom-module-node");
|
||||
|
||||
// Loop through files in m_rootPath
|
||||
// and register them as nodes if they match certain criteria
|
||||
for (const auto& entry : std::filesystem::directory_iterator(m_rootPath))
|
||||
{
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".json")
|
||||
{
|
||||
// Load the JSON file and register a node based on its content
|
||||
std::ifstream file(entry.path());
|
||||
nlohmann::json j;
|
||||
file >> j;
|
||||
|
||||
auto p = std::make_shared<StoryProject>(m_log);
|
||||
p->ParseStoryInformation(j);
|
||||
|
||||
if (p->IsModule())
|
||||
{
|
||||
registerNode<FunctionNode>(FunctionNodeUuid, 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
|
||||
|
||||
// Maybe this algorithm:
|
||||
// 1. load all function nodes
|
||||
// 2. for each function node, check if it has a "requires" field
|
||||
// 3. if it does, check if we have them
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ILogger &m_log;
|
||||
std::string m_rootPath;
|
||||
|
||||
template<class NodeType>
|
||||
struct Factory {
|
||||
|
|
@ -52,12 +117,13 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &type);
|
||||
typedef std::map<std::string, GenericCreator> Registry;
|
||||
// UUID is the key, and the value is a function that creates the node
|
||||
typedef std::map<std::string, std::pair<std::shared_ptr<IStoryProject>, GenericCreator>> Registry;
|
||||
Registry m_registry;
|
||||
|
||||
template<class Derived>
|
||||
void registerNode(const std::string& key) {
|
||||
m_registry.insert(typename Registry::value_type(key, Factory<Derived>::create_func));
|
||||
void registerNode(const std::string& uuid, std::shared_ptr<IStoryProject> moduleInfo = nullptr) {
|
||||
info.creator = ;
|
||||
m_registry.insert(typename Registry::value_type(uuid, std::make_pair<moduleInfo, Factory<Derived>::create_func>));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ public:
|
|||
|
||||
virtual void Initialize() override;
|
||||
|
||||
private:
|
||||
void SetContent(nlohmann::json &content) {
|
||||
m_content = content;
|
||||
}
|
||||
|
||||
private:
|
||||
nlohmann::json m_content;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,23 @@ 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>();
|
||||
std::string typeString = projectData["type"].get<std::string>();
|
||||
|
||||
if (typeString == "story")
|
||||
{
|
||||
m_projectType = IStoryProject::PROJECT_TYPE_STORY;
|
||||
}
|
||||
else if (typeString == "module")
|
||||
{
|
||||
m_projectType = IStoryProject::PROJECT_TYPE_MODULE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.Log("Unknown project type: " + typeString, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_titleImage = projectData.value("title_image", "");
|
||||
m_titleSound = projectData.value("title_sound", "");
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ public:
|
|||
|
||||
// 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 ParseStoryInformation(nlohmann::json &j);
|
||||
|
||||
|
|
@ -117,9 +119,11 @@ private:
|
|||
std::string m_titleImage;
|
||||
std::string m_titleSound;
|
||||
std::string m_description;
|
||||
|
||||
IStoryProject::Type m_projectType{IStoryProject::PROJECT_TYPE_STORY};
|
||||
|
||||
uint32_t m_version;
|
||||
bool m_selected{false};
|
||||
IStoryProject::ProjectType m_type{IStoryProject::PROJECT_TYPE_STORY};
|
||||
|
||||
std::unordered_set<std::string> m_usedLabels; // permet de ne pas générer un label qui existe déjà
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,11 @@ if (!(x)) { \
|
|||
#include "json.hpp"
|
||||
|
||||
|
||||
NodeEditorWindow::NodeEditorWindow(IStoryManager &manager, NodesFactory &factory)
|
||||
: WindowBase("Node editor")
|
||||
NodeEditorWindow::NodeEditorWindow(IStoryManager &manager, NodesFactory &factory, IStoryManager::ProjectType type)
|
||||
: WindowBase(type == IStoryManager::ProjectType::PROJECT_TYPE_STORY ? "Story editor" : "Module editor")
|
||||
, m_manager(manager)
|
||||
, m_nodesFactory(factory)
|
||||
, m_editorType(type)
|
||||
{
|
||||
|
||||
// registerNode<MediaNodeWidget>("media-node");
|
||||
|
|
@ -379,26 +380,20 @@ void NodeEditorWindow::Draw()
|
|||
|
||||
void NodeEditorWindow::ToolbarUI()
|
||||
{
|
||||
auto& io = ImGui::GetIO();
|
||||
ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
ImVec2 window_size = ImGui::GetWindowSize();
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove;
|
||||
// if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
// {
|
||||
// const ImGuiViewport* viewport = ImGui::GetWindowViewport();
|
||||
// window_flags |= ImGuiWindowFlags_NoDocking;
|
||||
// io.ConfigViewportsNoDecoration = true;
|
||||
// ImGui::SetNextWindowViewport(viewport->ID);
|
||||
// }
|
||||
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
|
||||
// ImGui::PushStyleColor(ImGuiCol_Button, m_StyleColors[BluePrintStyleColor_ToolButton]);
|
||||
// ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_StyleColors[BluePrintStyleColor_ToolButtonHovered]);
|
||||
// ImGui::PushStyleColor(ImGuiCol_ButtonActive, m_StyleColors[BluePrintStyleColor_ToolButtonActive]);
|
||||
// ImGui::PushStyleColor(ImGuiCol_TexGlyphShadow, ImVec4(0.1, 0.1, 0.1, 0.8));
|
||||
// ImGui::PushStyleVar(ImGuiStyleVar_TexGlyphShadowOffset, ImVec2(2.0, 2.0));
|
||||
// auto& io = ImGui::GetIO();
|
||||
// ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
// ImVec2 window_size = ImGui::GetWindowSize();
|
||||
// ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove;
|
||||
|
||||
ImGui::Begin("TOOLBAR", NULL, window_flags);
|
||||
// ImGui::PopStyleVar();
|
||||
// ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
|
||||
|
||||
// ImGui::Begin("TOOLBAR", NULL, window_flags);
|
||||
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(10, 40));
|
||||
ImGui::BeginChild("ToolbarChild", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 1.5f), false, ImGuiWindowFlags_NoScrollbar);
|
||||
|
||||
ImGui::PushID(m_editorType);
|
||||
|
||||
// Draw call stack, each function is a button
|
||||
for (auto page : m_callStack)
|
||||
|
|
@ -422,11 +417,17 @@ void NodeEditorWindow::ToolbarUI()
|
|||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
// ImGui::PopStyleVar();
|
||||
// ImGui::PopStyleColor(4);
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
io.ConfigViewportsNoDecoration = false;
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
// ImGui::End();
|
||||
|
||||
ImGui::EndChild(); // Fin de la ChildWindow de la barre d'outils
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(0, 0));
|
||||
|
||||
|
||||
// if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
// {
|
||||
// io.ConfigViewportsNoDecoration = false;
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ namespace ed = ax::NodeEditor;
|
|||
class NodeEditorWindow : public WindowBase
|
||||
{
|
||||
public:
|
||||
NodeEditorWindow(IStoryManager &manager, NodesFactory &factory);
|
||||
|
||||
NodeEditorWindow(IStoryManager &manager, NodesFactory &factory, IStoryManager::ProjectType type = IStoryManager::ProjectType::PROJECT_TYPE_STORY);
|
||||
~NodeEditorWindow();
|
||||
virtual void Draw() override;
|
||||
|
||||
|
|
@ -40,6 +41,7 @@ public:
|
|||
private:
|
||||
IStoryManager &m_manager;
|
||||
NodesFactory &m_nodesFactory;
|
||||
IStoryManager::ProjectType m_editorType{IStoryManager::ProjectType::PROJECT_TYPE_STORY};
|
||||
|
||||
bool m_loaded{false};
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ MainWindow::MainWindow()
|
|||
, m_cpuWindow(*this)
|
||||
, m_resourcesWindow(*this)
|
||||
, m_nodeEditorWindow(*this, m_nodesFactory)
|
||||
, m_moduleEditorWindow(*this, m_nodesFactory, NodeEditorWindow::EditorType::NODE_EDITOR_MODULE)
|
||||
, m_libraryWindow(*this, m_libraryManager)
|
||||
, m_variablesWindow(*this)
|
||||
, m_player(*this)
|
||||
|
|
@ -582,6 +583,7 @@ bool MainWindow::Initialize()
|
|||
m_debuggerWindow.Initialize();
|
||||
m_emulatorWindow.Initialize();
|
||||
m_nodeEditorWindow.Initialize();
|
||||
m_moduleEditorWindow.Initialize();
|
||||
m_PropertiesWindow.Initialize();
|
||||
m_libraryWindow.Initialize();
|
||||
|
||||
|
|
@ -835,7 +837,7 @@ void MainWindow::ProjectPropertiesPopup()
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::SaveProject()
|
||||
void MainWindow::SaveProject(IStoryManager::ProjectType type)
|
||||
{
|
||||
nlohmann::json model;
|
||||
m_story->Save(m_resources);
|
||||
|
|
@ -844,7 +846,8 @@ void MainWindow::SaveProject()
|
|||
|
||||
void MainWindow::OpenProject(const std::string &uuid)
|
||||
{
|
||||
CloseProject();
|
||||
CloseProject(IStoryManager::ProjectType::PROJECT_TYPE_STORY);
|
||||
|
||||
m_story = m_libraryManager.GetStory(uuid);
|
||||
|
||||
// DEBUG CODE !!!!!!!!!!!!! Permet si décommenter de forcer l'import, permet de tester plus facilement l'algo en ouvrant le projet
|
||||
|
|
@ -875,6 +878,7 @@ void MainWindow::OpenProject(const std::string &uuid)
|
|||
}
|
||||
|
||||
m_nodeEditorWindow.Enable();
|
||||
|
||||
m_emulatorWindow.Enable();
|
||||
m_consoleWindow.Enable();
|
||||
m_debuggerWindow.Enable();
|
||||
|
|
@ -891,6 +895,70 @@ void MainWindow::OpenProject(const std::string &uuid)
|
|||
RefreshProjectInformation();
|
||||
}
|
||||
|
||||
void MainWindow::OpenModule(const std::string &uuid)
|
||||
{
|
||||
m_story = m_libraryManager.GetModule(uuid);
|
||||
if (!m_story)
|
||||
{
|
||||
Log("Cannot find module: " + uuid);
|
||||
}
|
||||
else if (m_story->Load(m_resources, m_nodesFactory))
|
||||
{
|
||||
Log("Open module success");
|
||||
m_moduleEditorWindow.Load(m_story);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Open module error");
|
||||
}
|
||||
|
||||
|
||||
m_moduleEditorWindow.Enable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MainWindow::CloseProject(IStoryManager::ProjectType type)
|
||||
{
|
||||
// FIXME: not sure but if present, we lost some information in the library manager
|
||||
|
||||
// if (m_story)
|
||||
// {
|
||||
// m_story->Clear();
|
||||
// m_story.reset();
|
||||
// }
|
||||
|
||||
m_resources.Clear();
|
||||
|
||||
if (type == IStoryManager::ProjectType::PROJECT_TYPE_STORY)
|
||||
{
|
||||
m_nodeEditorWindow.Initialize();
|
||||
m_nodeEditorWindow.Disable();
|
||||
}
|
||||
else if (type == IStoryManager::ProjectType::PROJECT_TYPE_MODULE)
|
||||
{
|
||||
m_moduleEditorWindow.Initialize();
|
||||
m_moduleEditorWindow.Disable();
|
||||
}
|
||||
|
||||
// FIXME: si un des deux types de projets est encore ouvert, on ne va pas fermer
|
||||
// le sautres fenêtres de preview
|
||||
|
||||
m_emulatorWindow.ClearImage();
|
||||
m_consoleWindow.ClearLog();
|
||||
m_debuggerWindow.ClearErrors();
|
||||
m_debuggerWindow.SetScript("");
|
||||
|
||||
m_emulatorWindow.Disable();
|
||||
m_debuggerWindow.Disable();
|
||||
m_resourcesWindow.Disable();
|
||||
m_PropertiesWindow.Disable();
|
||||
m_variablesWindow.Disable();
|
||||
m_cpuWindow.Disable();
|
||||
|
||||
RefreshProjectInformation();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::ImportProject(const std::string &filePathName, int format)
|
||||
{
|
||||
|
|
@ -927,36 +995,6 @@ void MainWindow::RefreshProjectInformation()
|
|||
}
|
||||
|
||||
|
||||
void MainWindow::CloseProject()
|
||||
{
|
||||
// FIXME: not sure but if present, we lost some information in the library manager
|
||||
|
||||
// if (m_story)
|
||||
// {
|
||||
// m_story->Clear();
|
||||
// m_story.reset();
|
||||
// }
|
||||
|
||||
m_resources.Clear();
|
||||
|
||||
m_nodeEditorWindow.Initialize();
|
||||
m_emulatorWindow.ClearImage();
|
||||
m_consoleWindow.ClearLog();
|
||||
m_debuggerWindow.ClearErrors();
|
||||
m_debuggerWindow.SetScript("");
|
||||
|
||||
m_nodeEditorWindow.Disable();
|
||||
m_emulatorWindow.Disable();
|
||||
m_debuggerWindow.Disable();
|
||||
m_resourcesWindow.Disable();
|
||||
m_PropertiesWindow.Disable();
|
||||
m_variablesWindow.Disable();
|
||||
m_cpuWindow.Disable();
|
||||
|
||||
RefreshProjectInformation();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::DrawToolBar(float topPadding)
|
||||
{
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration |
|
||||
|
|
@ -1031,6 +1069,7 @@ void MainWindow::Loop()
|
|||
m_debuggerWindow.Draw();
|
||||
m_resourcesWindow.Draw();
|
||||
m_nodeEditorWindow.Draw();
|
||||
m_moduleEditorWindow.Draw();
|
||||
m_variablesWindow.Draw();
|
||||
m_cpuWindow.Draw();
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,8 @@ private:
|
|||
|
||||
NodeEditorWindow m_nodeEditorWindow;
|
||||
|
||||
NodeEditorWindow m_moduleEditorWindow;
|
||||
|
||||
PropertiesWindow m_PropertiesWindow;
|
||||
|
||||
LibraryWindow m_libraryWindow;
|
||||
|
|
@ -134,7 +136,12 @@ private:
|
|||
WebServer m_webServer;
|
||||
|
||||
// From IStoryManager (proxy to StoryProject class)
|
||||
virtual void OpenProject(const std::string &uuid) override;
|
||||
virtual void OpenProject(const std::string &uuid, IStoryManager::ProjectType type) override;
|
||||
|
||||
void SaveProject(IStoryManager::ProjectType type);
|
||||
void CloseProject(IStoryManager::ProjectType type);
|
||||
|
||||
// From IStoryManager (proxy to StoryProject class)
|
||||
virtual void ImportProject(const std::string &filePathName, int format);
|
||||
virtual void PlaySoundFile(const std::string &fileName) override;;
|
||||
virtual std::string BuildFullAssetsPath(const std::string_view fileName) const override;
|
||||
|
|
@ -185,8 +192,6 @@ private:
|
|||
bool ShowQuitConfirm();
|
||||
void DrawToolBar(float topPadding);
|
||||
|
||||
void SaveProject();
|
||||
void CloseProject();
|
||||
void DrawStatusBar();
|
||||
|
||||
void UpdateVmView();
|
||||
|
|
|
|||
Loading…
Reference in a new issue