diff --git a/core/README.md b/core/README.md deleted file mode 100644 index 315b1f4..0000000 --- a/core/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# StoryTeller core components - -Each component is organized as follow: - -Directories: -- interfaces: contains only pure virtual C++ interface classes -- lib: shared static classes utilities -- src: core implementation (private files) - - -# story-manager - -GUI agnostic implementation of the editor engine. - -# story-vm - - diff --git a/core/story-manager/src/compiler/assembly_generator.h b/core/story-manager/src/compiler/assembly_generator.h index 04387c1..f4a5234 100644 --- a/core/story-manager/src/compiler/assembly_generator.h +++ b/core/story-manager/src/compiler/assembly_generator.h @@ -20,7 +20,14 @@ class AssemblyGenerator : public IVariableVisitor { public: - struct GeneratorContext { + enum class Section { + NONE, + DATA, + TEXT + }; + + struct GeneratorContext + { std::string timestamp; std::string username; bool debugOutput; @@ -56,36 +63,68 @@ public: m_currentSection = Section::NONE; } - std::string GenerateAssembly(std::vector> &nodes, const std::vector>& order, const std::vector> &variables) + void GenerateHeader() { + AddComment("Assembly generated by Visual Node Editor"); + AddComment("Generation time: " + m_context.timestamp); + AddComment("Generated by: " + m_context.username); + AddComment("Optimization: " + m_context.optimizeCode ? "enabled" : "disabled"); + } + + virtual void GenerateExit() = 0; + + void StartSection(Section section) { + if (m_currentSection == section) return; + + m_currentSection = section; + switch (section) { + case Section::DATA: + AddComment("======================= DATA ======================="); + break; + case Section::TEXT: + AddComment("======================= CODE ======================="); + GenerateMain(); + break; + default: + break; + } + } + + void GenerateNodesVariables(const std::vector> &nodes) { - Reset(); - - // Generate header comments - GenerateHeader(); + // Generate all constants + for (const auto& n : nodes) { + n->Accept(*this); + } - // Generate data section - StartSection(Section::DATA); - GenerateDataSection(nodes, variables); + m_assembly << "\n\n"; + } - // Generate text section - StartSection(Section::TEXT); - GenerateTextSection(order); + void GenerateGlobalVariables(const std::vector> &variables) + { + for (const auto& v : variables) { + GenerateVariable(v); + } + } + void GenerateTextSection(const std::vector>& orderedNodes) + { + for (const auto& node : orderedNodes) + { + GenerateNodeCode(node); + } + } + + std::string GetAssembly() const { return m_assembly.str(); } protected: - enum class Section { - NONE, - DATA, - TEXT - }; virtual void GenerateNodeCode(std::shared_ptr node, bool isDataPath = false) = 0; virtual void AddComment(const std::string& comment) = 0; - virtual void GenerateExit() = 0; + virtual void GenerateMain() = 0; virtual void GenerateVariable(const std::shared_ptr v) = 0; @@ -102,6 +141,8 @@ protected: return prefix + "_" + std::to_string(m_labelCounter++); } + + protected: GeneratorContext m_context; std::stringstream m_assembly; @@ -115,83 +156,5 @@ protected: private: - void GenerateHeader() { - AddComment("Assembly generated by Visual Node Editor"); - AddComment("Generation time: " + m_context.timestamp); - AddComment("Generated by: " + m_context.username); - AddComment("Optimization: " + m_context.optimizeCode ? "enabled" : "disabled"); - } - - void StartSection(Section section) { - if (m_currentSection == section) return; - - m_currentSection = section; - switch (section) { - case Section::DATA: - AddComment("======================= DATA ======================="); - break; - case Section::TEXT: - AddComment("======================= CODE ======================="); - break; - default: - break; - } - } - - void GenerateDataSection(const std::vector> &nodes, const std::vector> &variables) - { - // Generate all constants - for (const auto& n : nodes) { - n->Accept(*this); - } - - // generate all variables in RAM - for (auto & v : variables) - { - GenerateVariable(v); - } - - m_assembly << "\n\n"; - } - - void GenerateTextSection(const std::vector>& orderedNodes) { - // Program entry point - m_assembly << ".main:\n"; - - for (const auto& node : orderedNodes) { - GenerateNodeCode(node); - } - - // Program exit - GenerateExit(); - } - - void CollectVariables(std::shared_ptr node) - { - if (!node) return; - - if (node->IsType()) { - auto* varNode = node->GetAs(); - /* - std::string varName = varNode->GetN(); - if (m_variableAddresses.find(varName) == m_variableAddresses.end()) { - m_variableAddresses[varName] = varName; - m_assembly << varName << ":\n" << varNode->GenerateAssembly(); - } - */ - } - - // Traverse children - for (auto& child : node->children) { - CollectVariables(child); - } - - // Traverse data inputs - for (const auto& [port, inputNode] : node->dataInputs) { - CollectVariables(inputNode); - } - } - - }; \ No newline at end of file diff --git a/core/story-manager/src/compiler/assembly_generator_chip32.h b/core/story-manager/src/compiler/assembly_generator_chip32.h index dc13f76..c292c32 100644 --- a/core/story-manager/src/compiler/assembly_generator_chip32.h +++ b/core/story-manager/src/compiler/assembly_generator_chip32.h @@ -37,28 +37,30 @@ public: GeneratePrintNode(node); } - // // If we're processing a data path, traverse data outputs - // if (isDataPath) { - // for (const auto& [port, outputs] : node->dataOutputs) { - // for (const auto& target : outputs) { - // GenerateNodeCode(target.node, true); - // } - // } - // } - + // // If there is no any children, put an halt + if (node->GetChildCount() == 0) + { + AddComment("Program exit"); + m_assembly << " halt\n"; + } } virtual void AddComment(const std::string& comment) { m_assembly << std::string(m_depth * 4, ' ') << "; " << comment << "\n"; } - virtual void GenerateExit() { + virtual void GenerateExit() override { AddComment("Program exit"); m_assembly << " halt\n"; } private: + virtual void GenerateMain() override { + // Program entry point + m_assembly << ".main:\n"; + } + void GenerateFunctionEntry(std::shared_ptr node) { AddComment("Function Entry"); } diff --git a/core/story-manager/src/compiler/ast_builder.h b/core/story-manager/src/compiler/ast_builder.h index c1cc746..267a60b 100644 --- a/core/story-manager/src/compiler/ast_builder.h +++ b/core/story-manager/src/compiler/ast_builder.h @@ -4,6 +4,7 @@ #include "base_node.h" #include "connection.h" #include "function_entry_node.h" +#include "variable_node.h" #include #include @@ -24,7 +25,7 @@ public: std::shared_ptr node; // Execution flow children (for EXECUTION_LINKJ connections) - std::vector> children; + std::vector> children; // Data inputs: port_index -> source node std::unordered_map> dataInputs; @@ -32,6 +33,10 @@ public: // Data outputs: output_port_index -> vector of (target node, target port) std::unordered_map> dataOutputs; + bool HasChildren(std::shared_ptr c) const { + return std::find(children.begin(), children.end(), c) != children.end(); + } + bool IsExecutionNode() const { return node->GetBehavior() == BaseNode::Behavior::BEHAVIOR_EXECUTION; } @@ -202,24 +207,33 @@ private: void BuildExecutionPath(std::vector>& tree, const std::unordered_map>& nodeMap) { - std::queue> queue; - queue.push(tree.front()); + // For each node in the tree, find its children based on the connections + for (const auto& node : tree) + { + std::queue> queue; + queue.push(node); - while (!queue.empty()) { - auto current = queue.front(); - queue.pop(); + while (!queue.empty()) { + auto current = queue.front(); + queue.pop(); - // Find execution connections from this node - for (const auto& conn : m_connections) - { - if (conn->outNodeId == current->node->GetId()) + // Find connections from this node + for (const auto& conn : m_connections) { - auto targetNode = nodeMap.find(conn->inNodeId); - if (targetNode != nodeMap.end()) + if (conn->outNodeId == current->node->GetId()) { - auto childNode = targetNode->second; - current->children.push_back(childNode); - queue.push(childNode); + auto targetNode = nodeMap.find(conn->inNodeId); + if (targetNode != nodeMap.end()) + { + auto childNode = targetNode->second; + + // Si le noeud n'a pas déjà cet enfant, on l'ajoute + if (!current->HasChildren(childNode)) + { + current->children.push_back(childNode); + queue.push(childNode); + } + } } } } diff --git a/core/story-manager/src/compiler/flow_generator.h b/core/story-manager/src/compiler/flow_generator.h index 7620a09..361e600 100644 --- a/core/story-manager/src/compiler/flow_generator.h +++ b/core/story-manager/src/compiler/flow_generator.h @@ -61,6 +61,10 @@ protected: } + virtual void GenerateMain() override { + // Program entry point + FlowVisualizer::PrintNodeExecution("Main Entry", m_depth); + } virtual void Visit(const std::shared_ptr v) { diff --git a/core/story-manager/src/nodes/function_entry_node.h b/core/story-manager/src/nodes/function_entry_node.h index faf8e8e..a71b01f 100644 --- a/core/story-manager/src/nodes/function_entry_node.h +++ b/core/story-manager/src/nodes/function_entry_node.h @@ -17,11 +17,6 @@ public: // Par exemple, préparer les entrées nécessaires pour la fonction } - std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override { - // Logique de construction pour FunctionEntryNode - return GetMyEntryLabel() + ":\n"; - } - // Ajoutez des méthodes spécifiques pour gérer l'entrée de la fonction void PrepareFunctionEntry() { // Logique pour préparer l'entrée de la fonction diff --git a/core/story-manager/src/nodes/operator_node.h b/core/story-manager/src/nodes/operator_node.h index 026f040..34a4ac0 100644 --- a/core/story-manager/src/nodes/operator_node.h +++ b/core/story-manager/src/nodes/operator_node.h @@ -1,9 +1,5 @@ #pragma once -#include "base_node.h" - -#pragma once - #include "base_node.h" #include #include @@ -36,6 +32,39 @@ public: RIGHT_SHIFT // Right shift (>>) }; + struct OperatorDesc { + std::string name; + std::string symbol; + }; + + const std::unordered_map& GetOperators() const + { + static const std::unordered_map Operators = { + {OperationType::ADD, {"Addition", "+"}}, + {OperationType::SUBTRACT, {"Subtraction", "-"}}, + {OperationType::MULTIPLY, {"Multiplication", "*"}}, + {OperationType::DIVIDE, {"Division", "/"}}, + {OperationType::MODULO, {"Modulo", "%"}}, + {OperationType::AND, {"Logical AND", "&&"}}, + {OperationType::OR, {"Logical OR", "||"}}, + {OperationType::NOT, {"Logical NOT", "!"}}, + {OperationType::XOR, {"Logical XOR", "^"}}, + {OperationType::EQUAL, {"Equal to", "=="}}, + {OperationType::NOT_EQUAL, {"Not equal to", "!="}}, + {OperationType::GREATER_THAN, {"Greater than", ">"}}, + {OperationType::LESS_THAN, {"Less than", "<"}}, + {OperationType::GREATER_EQUAL, {"Greater than or equal to", ">="}}, + {OperationType::LESS_EQUAL, {"Less than or equal to", "<="}}, + {OperationType::BITWISE_AND, {"Bitwise AND", "&"}}, + {OperationType::BITWISE_OR, {"Bitwise OR", "|"}}, + {OperationType::BITWISE_XOR, {"Bitwise XOR", "^"}}, + {OperationType::BITWISE_NOT, {"Bitwise NOT", "~"}}, + {OperationType::LEFT_SHIFT, {"Left shift", "<<"}}, + {OperationType::RIGHT_SHIFT, {"Right shift", ">>"}} + }; + return Operators; + } + OperatorNode(const std::string& type = "operator-node", const std::string& typeName = "Operator") : BaseNode(type, typeName, BaseNode::Behavior::BEHAVIOR_DATA) @@ -61,51 +90,11 @@ public: // Get the symbol representation of the operator std::string GetOperatorSymbol() const { - static const std::unordered_map symbolMap = { - {OperationType::ADD, "+"}, - {OperationType::SUBTRACT, "-"}, - {OperationType::MULTIPLY, "*"}, - {OperationType::DIVIDE, "/"}, - {OperationType::MODULO, "%"}, - {OperationType::AND, "&&"}, - {OperationType::OR, "||"}, - {OperationType::NOT, "!"}, - {OperationType::XOR, "^"}, - {OperationType::EQUAL, "=="}, - {OperationType::NOT_EQUAL, "!="}, - {OperationType::GREATER_THAN, ">"}, - {OperationType::LESS_THAN, "<"}, - {OperationType::GREATER_EQUAL, ">="}, - {OperationType::LESS_EQUAL, "<="}, - {OperationType::BITWISE_AND, "&"}, - {OperationType::BITWISE_OR, "|"}, - {OperationType::BITWISE_XOR, "^"}, - {OperationType::BITWISE_NOT, "~"}, - {OperationType::LEFT_SHIFT, "<<"}, - {OperationType::RIGHT_SHIFT, ">>"} - }; - + auto symbolMap = GetOperators(); auto it = symbolMap.find(m_operationType); - return it != symbolMap.end() ? it->second : "?"; + return it != symbolMap.end() ? it->second.symbol : "?"; } - std::string Build(IStoryPage& page, const StoryOptions& options, int nb_out_conns) override { - std::stringstream ss; - ss << "// Operator: " << GetOperatorSymbol() << "\n"; - - // For unary operators - if (IsUnaryOperator()) { - ss << GetOperatorSymbol() << "operand"; - } - // For binary operators - else { - ss << "operand1 " << GetOperatorSymbol() << " operand2"; - } - - return ss.str(); - } - - private: OperationType m_operationType; @@ -130,61 +119,20 @@ private: AddOutputPort(Port::DATA_PORT, "out"); } - static std::string OperatorTypeToString(OperationType type) { - static const std::unordered_map typeMap = { - {OperationType::ADD, "add"}, - {OperationType::SUBTRACT, "subtract"}, - {OperationType::MULTIPLY, "multiply"}, - {OperationType::DIVIDE, "divide"}, - {OperationType::MODULO, "modulo"}, - {OperationType::AND, "and"}, - {OperationType::OR, "or"}, - {OperationType::NOT, "not"}, - {OperationType::XOR, "xor"}, - {OperationType::EQUAL, "equal"}, - {OperationType::NOT_EQUAL, "not_equal"}, - {OperationType::GREATER_THAN, "greater_than"}, - {OperationType::LESS_THAN, "less_than"}, - {OperationType::GREATER_EQUAL, "greater_equal"}, - {OperationType::LESS_EQUAL, "less_equal"}, - {OperationType::BITWISE_AND, "bitwise_and"}, - {OperationType::BITWISE_OR, "bitwise_or"}, - {OperationType::BITWISE_XOR, "bitwise_xor"}, - {OperationType::BITWISE_NOT, "bitwise_not"}, - {OperationType::LEFT_SHIFT, "left_shift"}, - {OperationType::RIGHT_SHIFT, "right_shift"} - }; - - auto it = typeMap.find(type); - return it != typeMap.end() ? it->second : "unknown"; + std::string OperatorTypeName(OperationType type) const { + auto symbolMap = GetOperators(); + auto it = symbolMap.find(type); + return it != symbolMap.end() ? it->second.name : "Unknown"; } - static OperationType StringToOperationType(const std::string& str) { - static const std::unordered_map typeMap = { - {"add", OperationType::ADD}, - {"subtract", OperationType::SUBTRACT}, - {"multiply", OperationType::MULTIPLY}, - {"divide", OperationType::DIVIDE}, - {"modulo", OperationType::MODULO}, - {"and", OperationType::AND}, - {"or", OperationType::OR}, - {"not", OperationType::NOT}, - {"xor", OperationType::XOR}, - {"equal", OperationType::EQUAL}, - {"not_equal", OperationType::NOT_EQUAL}, - {"greater_than", OperationType::GREATER_THAN}, - {"less_than", OperationType::LESS_THAN}, - {"greater_equal", OperationType::GREATER_EQUAL}, - {"less_equal", OperationType::LESS_EQUAL}, - {"bitwise_and", OperationType::BITWISE_AND}, - {"bitwise_or", OperationType::BITWISE_OR}, - {"bitwise_xor", OperationType::BITWISE_XOR}, - {"bitwise_not", OperationType::BITWISE_NOT}, - {"left_shift", OperationType::LEFT_SHIFT}, - {"right_shift", OperationType::RIGHT_SHIFT} - }; + OperationType SymbolToOperationType(const std::string& str) const { + auto symbolMap = GetOperators(); - auto it = typeMap.find(str); - return it != typeMap.end() ? it->second : OperationType::ADD; + for (const auto& pair : symbolMap) { + if (pair.second.symbol == str) { + return pair.first; + } + } + return OperationType::ADD; // Default to ADD if not found } }; diff --git a/core/story-manager/src/nodes/print_node.cpp b/core/story-manager/src/nodes/print_node.cpp index 4b3b4ba..872f656 100644 --- a/core/story-manager/src/nodes/print_node.cpp +++ b/core/story-manager/src/nodes/print_node.cpp @@ -19,10 +19,3 @@ void PrintNode::Initialize() { } - -std::string PrintNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) -{ - return ""; -} - - diff --git a/core/story-manager/src/nodes/print_node.h b/core/story-manager/src/nodes/print_node.h index ab486d5..66afa07 100644 --- a/core/story-manager/src/nodes/print_node.h +++ b/core/story-manager/src/nodes/print_node.h @@ -12,7 +12,6 @@ public: PrintNode(const std::string &type); virtual void Initialize() override; - virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override; void SetText(const std::string &text) { diff --git a/core/story-manager/src/nodes/variable_node.h b/core/story-manager/src/nodes/variable_node.h index 6a91668..5945a52 100644 --- a/core/story-manager/src/nodes/variable_node.h +++ b/core/story-manager/src/nodes/variable_node.h @@ -27,7 +27,7 @@ public: } private: -std::shared_ptr m_variable; + std::shared_ptr m_variable; }; diff --git a/core/story-manager/src/story_page.h b/core/story-manager/src/story_page.h index 4a1a884..434a245 100644 --- a/core/story-manager/src/story_page.h +++ b/core/story-manager/src/story_page.h @@ -8,6 +8,7 @@ #include "i_story_project.h" #include "base_node.h" #include "connection.h" +#include "assembly_generator.h" class StoryPage : public IStoryPage { @@ -50,18 +51,20 @@ public: m_nodes.clear(); } - void Build(std::stringstream &code, IStoryProject &project) + void BuildNodesVariables(AssemblyGenerator &generator) { - // // First generate all constants - // for (const auto & n : m_nodes) - // { - // code << n->GenerateConstants(*this, project, OutputsCount(n->GetId())) << "\n"; - // } + std::vector> nodes(m_nodes.begin(), m_nodes.end()); + generator.GenerateNodesVariables(nodes); + } - // for (const auto & n : m_nodes) - // { - // code << n->Build(*this, project.GetOptions(), OutputsCount(n->GetId())) << "\n"; - // } + void BuildNodes(AssemblyGenerator &generator) + { + std::vector> nodes(m_nodes.begin(), m_nodes.end()); + std::vector> links(m_links.begin(), m_links.end()); + ASTBuilder builder(nodes, links); + auto pathTree = builder.BuildAST(); + + generator.GenerateTextSection(pathTree); } virtual void GetNodeConnections(std::list> &c, const std::string &nodeId) override diff --git a/core/story-manager/src/story_project.cpp b/core/story-manager/src/story_project.cpp index f016f69..ed54065 100644 --- a/core/story-manager/src/story_project.cpp +++ b/core/story-manager/src/story_project.cpp @@ -10,14 +10,19 @@ // #include "media_node.h" #include "function_node.h" #include "variable_node.h" +#include "operator_node.h" +#include "print_node.h" #include "sys_lib.h" +#include "assembly_generator_chip32.h" StoryProject::StoryProject(ILogger &log) : m_log(log) { // registerNode("media-node"); + registerNode("operator-node"); registerNode("function-node"); registerNode("variable-node"); + registerNode("print-node"); } StoryProject::~StoryProject() @@ -380,42 +385,59 @@ bool StoryProject::UseResource(const std::string &label) bool StoryProject::GenerateScript(std::string &codeStr) { std::stringstream code; - std::stringstream chip32; - std::string firstNode; - - for (const auto & p : m_pages) - { - firstNode = p->FindFirstNode(); - } - - if (firstNode == "") - { - m_log.Log("First node not found, there must be only one node with a free input."); - return false; - } - - code << "\tjump " << BaseNode::GetEntryLabel(firstNode) << "\r\n"; // Empty resources usage m_usedLabels.clear(); - // On build toutes les pages + + + // Create generator context with current time and user + AssemblyGenerator::GeneratorContext context( + "2025-04-08 12:09:01", // Current UTC time + "story-editor", // Current user + true, // Enable debug output + true, // Enable optimizations + 1024 // Stack size + ); + + // Create generator + AssemblyGeneratorChip32 generator(context); + + + generator.Reset(); + + // Generate header comments + generator.GenerateHeader(); + + // Generate data section + generator.StartSection(AssemblyGenerator::Section::DATA); for (const auto & p : m_pages) { - p->Build(code, *this); + p->BuildNodesVariables(generator); + } + generator.GenerateGlobalVariables(m_variables); + + // Generate text section + generator.StartSection(AssemblyGenerator::Section::TEXT); + + for (const auto & p : m_pages) + { + p->BuildNodes(generator); } - codeStr = code.str(); + generator.GenerateExit(); + + codeStr = generator.GetAssembly(); // Add our utility functions - std::string buffer; + // std::string buffer; - std::ifstream f("scripts/media.chip32"); - f.seekg(0, std::ios::end); - buffer.resize(f.tellg()); - f.seekg(0); - f.read(buffer.data(), buffer.size()); - codeStr += buffer; + // std::ifstream f("scripts/media.chip32"); + // f.seekg(0, std::ios::end); + // buffer.resize(f.tellg()); + // f.seekg(0); + // f.read(buffer.data(), buffer.size()); + // codeStr += buffer; return true; } diff --git a/core/story-manager/tests/test_ast.cpp b/core/story-manager/tests/test_ast.cpp index 77db8be..cf2a92d 100644 --- a/core/story-manager/tests/test_ast.cpp +++ b/core/story-manager/tests/test_ast.cpp @@ -216,7 +216,7 @@ TEST_CASE( "Check various indentations and typos" ) { // Create generator context with current time and user AssemblyGenerator::GeneratorContext context( "2025-04-08 12:09:01", // Current UTC time - "arabine", // Current user + "unit-test-ast", // Current user true, // Enable debug output true, // Enable optimizations 1024 // Stack size @@ -232,13 +232,28 @@ TEST_CASE( "Check various indentations and typos" ) { // Generate flow in the console VisualFlowGenerator flowGenerator(context); FlowVisualizer::PrintHeader("arabine", "2025-04-08 12:03:01"); - std::string flow = flowGenerator.GenerateAssembly(nodes, pathTree, variables); + flowGenerator.GenerateTextSection(pathTree); + std::string flow = flowGenerator.GetAssembly(); std::cout << "\nGenerated flow:\n" << flow << std::endl; - // Generate assembly - std::string assembly = generator.GenerateAssembly(nodes, pathTree, variables); + //------------------------------------ Generate assembly ------------------------------------ + + generator.Reset(); + + // Generate header comments + generator.GenerateHeader(); + + // Generate data section + generator.StartSection(AssemblyGenerator::Section::DATA); + generator.GenerateNodesVariables(nodes); + generator.GenerateGlobalVariables(variables); + generator.StartSection(AssemblyGenerator::Section::TEXT); + generator.GenerateTextSection(pathTree); + generator.GenerateExit(); + + std::string assembly = generator.GetAssembly(); std::cout << "\nGenerated assembly:\n" << assembly << std::endl; diff --git a/story-editor/CMakeLists.txt b/story-editor/CMakeLists.txt index 918a2e7..23bd78c 100644 --- a/story-editor/CMakeLists.txt +++ b/story-editor/CMakeLists.txt @@ -135,6 +135,8 @@ set(SRCS src/node_editor/node_editor_window.cpp src/node_editor/function_node_widget.cpp src/node_editor/variable_node_widget.cpp + src/node_editor/operator_node_widget.cpp + src/node_editor/print_node_widget.cpp src/gui.cpp src/media_converter.cpp @@ -177,6 +179,7 @@ set(SRCS ../core/story-manager/src/nodes/branch_node.cpp ../core/story-manager/src/nodes/variable_node.cpp ../core/story-manager/src/nodes/function_node.cpp + ../core/story-manager/src/nodes/print_node.cpp ../core/story-manager/src/nodes/connection.cpp ../core/story-manager/lib/sys_lib.cpp diff --git a/story-editor/imgui.ini b/story-editor/imgui.ini index 1bac5e9..7e834c7 100644 --- a/story-editor/imgui.ini +++ b/story-editor/imgui.ini @@ -9,63 +9,69 @@ Size=400,400 Collapsed=0 [Window][Library Manager] -Pos=672,26 -Size=608,694 +Pos=900,26 +Size=380,322 Collapsed=0 -DockId=0x00000002,0 +DockId=0x00000003,0 [Window][Console] -Pos=386,659 -Size=1152,344 +Pos=60,545 +Size=1220,175 Collapsed=0 +DockId=0x00000008,0 [Window][Emulator] -Pos=269,26 -Size=401,694 +Pos=398,26 +Size=500,517 Collapsed=0 DockId=0x00000005,1 [Window][Code viewer] -Pos=269,26 -Size=401,694 +Pos=398,26 +Size=500,517 Collapsed=0 DockId=0x00000005,0 [Window][Resources] -Pos=672,26 -Size=608,694 +Pos=900,26 +Size=380,322 Collapsed=0 -DockId=0x00000002,1 +DockId=0x00000003,1 [Window][Node editor] -Pos=96,129 -Size=394,407 +Pos=60,26 +Size=336,517 Collapsed=0 +DockId=0x00000004,0 [Window][TOOLBAR] -Pos=96,105 +Pos=92,208 Size=79,42 Collapsed=0 [Window][Variables] -Pos=199,187 -Size=121,72 +Pos=398,26 +Size=500,517 Collapsed=0 +DockId=0x00000005,2 [Window][CPU] -Pos=515,59 -Size=626,744 +Pos=900,26 +Size=380,322 Collapsed=0 +DockId=0x00000003,2 [Window][RAM view] -Pos=378,79 -Size=738,442 +Pos=900,26 +Size=380,322 Collapsed=0 +DockId=0x00000003,3 [Window][Properties] -Pos=754,344 -Size=626,744 +Pos=900,350 +Size=380,193 Collapsed=0 +DockId=0x00000006,0 [Window][ToolBar] Pos=0,26 @@ -97,9 +103,13 @@ Column 1 Width=88 Column 2 Width=124 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=X - DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=610,694 Split=X - DockNode ID=0x00000004 Parent=0x00000001 SizeRef=397,600 CentralNode=1 Selected=0x63869CAF - DockNode ID=0x00000005 Parent=0x00000001 SizeRef=401,600 Selected=0x4B07C626 - DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=608,694 Selected=0x30401527 +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y + DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,517 Split=X + DockNode ID=0x00000001 Parent=0x00000007 SizeRef=838,694 Split=X + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=336,600 CentralNode=1 Selected=0xBB79A587 + DockNode ID=0x00000005 Parent=0x00000001 SizeRef=500,600 Selected=0x52EB28B5 + DockNode ID=0x00000002 Parent=0x00000007 SizeRef=380,694 Split=Y Selected=0xE5897A33 + DockNode ID=0x00000003 Parent=0x00000002 SizeRef=608,322 Selected=0x63869CAF + DockNode ID=0x00000006 Parent=0x00000002 SizeRef=608,193 Selected=0x8C72BEA8 + DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,175 Selected=0xEA83D666 diff --git a/story-editor/src/node_editor/base_node_widget.cpp b/story-editor/src/node_editor/base_node_widget.cpp index d8a692e..ea229e0 100644 --- a/story-editor/src/node_editor/base_node_widget.cpp +++ b/story-editor/src/node_editor/base_node_widget.cpp @@ -19,9 +19,12 @@ BaseNodeWidget::~BaseNodeWidget() std::cout << " <-- Deleted node widget: " << (int)m_node->ID.Get() << std::endl; } -void BaseNodeWidget::AddInput() +void BaseNodeWidget::AddInputs(int num) { - m_node->Inputs.emplace_back(GetNextId(), "", PinType::Flow); + for (int i = 0; i < num; i++) + { + m_node->Inputs.emplace_back(GetNextId(), "", PinType::Flow); + } } void BaseNodeWidget::AddOutputs(int num) @@ -32,6 +35,21 @@ void BaseNodeWidget::AddOutputs(int num) } } +void BaseNodeWidget::SetInputs(uint32_t num) +{ + if (num > Inputs()) + { + AddInputs(num - Inputs()); + } + else if (num < Inputs()) + { + for (unsigned int i = 0; i < (Inputs() - num); i++) + { + m_node->Inputs.pop_back(); + } + } +} + void BaseNodeWidget::SetOutputs(uint32_t num) { if (num > Outputs()) @@ -59,6 +77,15 @@ void BaseNodeWidget::Initialize() } + +void BaseNodeWidget::SetInputPinName(int pinIndex, const std::string &name) +{ + if (pinIndex < m_node->Inputs.size()) + { + m_node->Inputs[pinIndex].Name = name; + } +} + void BaseNodeWidget::SetOutPinName(int pinIndex, const std::string &name) { if (pinIndex < m_node->Outputs.size()) diff --git a/story-editor/src/node_editor/base_node_widget.h b/story-editor/src/node_editor/base_node_widget.h index 7ec9bc8..b6326ad 100644 --- a/story-editor/src/node_editor/base_node_widget.h +++ b/story-editor/src/node_editor/base_node_widget.h @@ -106,6 +106,7 @@ public: virtual void Draw() = 0; virtual void DrawProperties() = 0; + void SetInputPinName(int pinIndex, const std::string &name); void SetOutPinName(int pinIndex, const std::string &name); void FrameStart(); @@ -189,10 +190,10 @@ public: } return found; } - - - void AddInput(); + + void AddInputs(int num = 1); void AddOutputs(int num = 1); + void SetInputs(uint32_t num); void SetOutputs(uint32_t num); void DeleteOutput(); diff --git a/story-editor/src/node_editor/function_node_widget.cpp b/story-editor/src/node_editor/function_node_widget.cpp index 06839bb..75f7c82 100644 --- a/story-editor/src/node_editor/function_node_widget.cpp +++ b/story-editor/src/node_editor/function_node_widget.cpp @@ -12,7 +12,7 @@ FunctionNodeWidget::FunctionNodeWidget(IStoryManager &manager, std::shared_ptr("media-node"); + registerNode("operator-node"); registerNode("function-node"); registerNode("variable-node"); + registerNode("print-node"); } - + NodeEditorWindow::~NodeEditorWindow() { m_pages.clear(); diff --git a/story-editor/src/node_editor/operator_node_widget.cpp b/story-editor/src/node_editor/operator_node_widget.cpp new file mode 100644 index 0000000..4f82935 --- /dev/null +++ b/story-editor/src/node_editor/operator_node_widget.cpp @@ -0,0 +1,81 @@ + +#include +#include "operator_node_widget.h" + +namespace ed = ax::NodeEditor; +#include "IconsMaterialDesignIcons.h" +#include "story_project.h" +#include "uuid.h" + +OperatorNodeWidget::OperatorNodeWidget(IStoryManager &manager, std::shared_ptr node) + : BaseNodeWidget(manager, node) + , m_manager(manager) +{ + m_opNode = std::dynamic_pointer_cast(node); + + // Create defaut one input and one output + AddInputs(2); + SetInputPinName(0, "A"); + SetInputPinName(1, "B"); + AddOutputs(1); + SetOutPinName(0, "="); +} + +void OperatorNodeWidget::Initialize() +{ + BaseNodeWidget::Initialize(); +} + + + +void OperatorNodeWidget::DrawProperties() +{ + ImGui::AlignTextToFramePadding(); + static ImGuiComboFlags flags = 0; + + if (ImGui::BeginCombo("Operators", m_selectedOperatorSymbol.c_str(), flags)) + { + int i = 0; + + for (auto& op : m_opNode->GetOperators()) + { + // ImGui::PushID(static_cast(i)); // Assure l'unicité des widgets + if (op.first == m_selectedOperatorType) + { + m_selectedIndex = i; + } + + const bool is_selected = (m_selectedIndex == i); + + if (ImGui::Selectable(op.second.symbol.c_str(), is_selected)) + { + m_selectedIndex = i; + m_selectedOperatorSymbol = op.second.symbol; + m_opNode->SetOperationType(op.first); + } + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + { + ImGui::SetItemDefaultFocus(); + } + + i++; + } + ImGui::EndCombo(); + } + +} + +void OperatorNodeWidget::Draw() +{ + BaseNodeWidget::FrameStart(); + + ImGui::TextUnformatted(m_selectedOperatorSymbol.c_str()); + + DrawPins(); + + BaseNodeWidget::FrameEnd(); + +} + diff --git a/story-editor/src/node_editor/operator_node_widget.h b/story-editor/src/node_editor/operator_node_widget.h new file mode 100644 index 0000000..6bebe37 --- /dev/null +++ b/story-editor/src/node_editor/operator_node_widget.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +#include "base_node_widget.h" +#include "i_story_manager.h" +#include "i_story_project.h" +#include "gui.h" +#include "operator_node.h" +#include +#include "media_node.h" + +class OperatorNodeWidget : public BaseNodeWidget +{ +public: + OperatorNodeWidget(IStoryManager &manager, std::shared_ptr node); + + void Draw() override; + + virtual void DrawProperties() override; + virtual void Initialize() override; + +private: + IStoryManager &m_manager; + std::shared_ptr m_opNode; + int m_selectedIndex{-1}; + OperatorNode::OperationType m_selectedOperatorType{OperatorNode::OperationType::ADD}; + std::string m_selectedOperatorSymbol{"+"}; +}; diff --git a/story-editor/src/node_editor/print_node_widget.cpp b/story-editor/src/node_editor/print_node_widget.cpp new file mode 100644 index 0000000..d0dbc64 --- /dev/null +++ b/story-editor/src/node_editor/print_node_widget.cpp @@ -0,0 +1,56 @@ + +#include +#include "print_node_widget.h" + +namespace ed = ax::NodeEditor; +#include "IconsMaterialDesignIcons.h" +#include "story_project.h" +#include "uuid.h" + +char PrintNodeWidget::m_buffer[PrintNodeWidget::MAX_PRINT_SIZE] = {0}; + +PrintNodeWidget::PrintNodeWidget(IStoryManager &manager, std::shared_ptr node) + : BaseNodeWidget(manager, node) + , m_manager(manager) +{ + m_printNode = std::dynamic_pointer_cast(node); + // Create defaut one input and one output + AddInputs(1); + SetInputPinName(0, ""); + AddOutputs(1); + SetOutPinName(0, ""); +} + +void PrintNodeWidget::Initialize() +{ + BaseNodeWidget::Initialize(); +} + + +void PrintNodeWidget::DrawProperties() +{ + ImGui::AlignTextToFramePadding(); + + ImGui::PushItemWidth(100.0f); + + auto t = m_printNode->GetText(); + t.copy(m_buffer, sizeof(m_buffer) - 1); + + bool edited = ImGui::InputText("##edit", m_buffer, sizeof(m_buffer), ImGuiInputTextFlags_EnterReturnsTrue); + + if (edited) + { + m_printNode->SetText(m_buffer); + } +} + +void PrintNodeWidget::Draw() +{ + BaseNodeWidget::FrameStart(); + + DrawPins(); + + BaseNodeWidget::FrameEnd(); + +} + diff --git a/story-editor/src/node_editor/print_node_widget.h b/story-editor/src/node_editor/print_node_widget.h new file mode 100644 index 0000000..b98923b --- /dev/null +++ b/story-editor/src/node_editor/print_node_widget.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include + +#include "base_node_widget.h" +#include "i_story_manager.h" +#include "i_story_project.h" +#include "gui.h" +#include "print_node.h" +#include +#include "media_node.h" + +class PrintNodeWidget : public BaseNodeWidget +{ +public: + + static const int MAX_PRINT_SIZE = 128; + PrintNodeWidget(IStoryManager &manager, std::shared_ptr node); + + void Draw() override; + + virtual void DrawProperties() override; + virtual void Initialize() override; + +private: + IStoryManager &m_manager; + std::shared_ptr m_printNode; + + static char m_buffer[MAX_PRINT_SIZE]; +}; diff --git a/story-editor/src/node_editor/variable_node_widget.cpp b/story-editor/src/node_editor/variable_node_widget.cpp index 2fdf13f..9fb66db 100644 --- a/story-editor/src/node_editor/variable_node_widget.cpp +++ b/story-editor/src/node_editor/variable_node_widget.cpp @@ -11,6 +11,7 @@ VariableNodeWidget::VariableNodeWidget(IStoryManager &manager, std::shared_ptr(node); // Create defaut one input and one output //AddInput(); AddOutputs(1); @@ -42,6 +43,7 @@ void VariableNodeWidget::DrawProperties() { m_selectedIndex = i; m_selectedVariable = l; + m_variableNode->SetVariable(var); } // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)