Build splitted to allow multi pages compilation, more widgets
Some checks failed
Build-StoryEditor / build_linux (push) Has been cancelled
Build-StoryEditor / build_win32 (push) Has been cancelled
Deploy-Documentation / deploy (push) Has been cancelled

This commit is contained in:
anthony@rabine.fr 2025-04-23 13:28:22 +02:00
parent 51eac85360
commit d6df8b65ab
24 changed files with 515 additions and 325 deletions

View file

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

View file

@ -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<std::shared_ptr<BaseNode>> &nodes, const std::vector<std::shared_ptr<ASTNode>>& order, const std::vector<std::shared_ptr<Variable>> &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<std::shared_ptr<BaseNode>> &nodes)
{
Reset();
// Generate all constants
for (const auto& n : nodes) {
n->Accept(*this);
}
// Generate header comments
GenerateHeader();
m_assembly << "\n\n";
}
// Generate data section
StartSection(Section::DATA);
GenerateDataSection(nodes, variables);
void GenerateGlobalVariables(const std::vector<std::shared_ptr<Variable>> &variables)
{
for (const auto& v : variables) {
GenerateVariable(v);
}
}
// Generate text section
StartSection(Section::TEXT);
GenerateTextSection(order);
void GenerateTextSection(const std::vector<std::shared_ptr<ASTNode>>& 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<ASTNode> 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<Variable> 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<std::shared_ptr<BaseNode>> &nodes, const std::vector<std::shared_ptr<Variable>> &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<std::shared_ptr<ASTNode>>& orderedNodes) {
// Program entry point
m_assembly << ".main:\n";
for (const auto& node : orderedNodes) {
GenerateNodeCode(node);
}
// Program exit
GenerateExit();
}
void CollectVariables(std::shared_ptr<ASTNode> node)
{
if (!node) return;
if (node->IsType<VariableNode>()) {
auto* varNode = node->GetAs<VariableNode>();
/*
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);
}
}
};

View file

@ -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<ASTNode> node) {
AddComment("Function Entry");
}

View file

@ -4,6 +4,7 @@
#include "base_node.h"
#include "connection.h"
#include "function_entry_node.h"
#include "variable_node.h"
#include <unordered_map>
#include <unordered_set>
@ -32,6 +33,10 @@ public:
// Data outputs: output_port_index -> vector of (target node, target port)
std::unordered_map<unsigned int, std::vector<DataTarget>> dataOutputs;
bool HasChildren(std::shared_ptr<ASTNode> c) const {
return std::find(children.begin(), children.end(), c) != children.end();
}
bool IsExecutionNode() const {
return node->GetBehavior() == BaseNode::Behavior::BEHAVIOR_EXECUTION;
}
@ -201,15 +206,18 @@ private:
void BuildExecutionPath(std::vector<std::shared_ptr<ASTNode>>& tree,
const std::unordered_map<std::string, std::shared_ptr<ASTNode>>& nodeMap)
{
// For each node in the tree, find its children based on the connections
for (const auto& node : tree)
{
std::queue<std::shared_ptr<ASTNode>> queue;
queue.push(tree.front());
queue.push(node);
while (!queue.empty()) {
auto current = queue.front();
queue.pop();
// Find execution connections from this node
// Find connections from this node
for (const auto& conn : m_connections)
{
if (conn->outNodeId == current->node->GetId())
@ -218,6 +226,10 @@ private:
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);
}
@ -225,6 +237,8 @@ private:
}
}
}
}
}
std::vector<std::shared_ptr<ASTNode>> ApplyKahnAlgorithm(const std::unordered_map<std::string, std::shared_ptr<ASTNode>> &nodeMap)
{

View file

@ -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<Variable> v) {

View file

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

View file

@ -1,9 +1,5 @@
#pragma once
#include "base_node.h"
#pragma once
#include "base_node.h"
#include <sstream>
#include <stdexcept>
@ -36,6 +32,39 @@ public:
RIGHT_SHIFT // Right shift (>>)
};
struct OperatorDesc {
std::string name;
std::string symbol;
};
const std::unordered_map<OperationType, OperatorDesc>& GetOperators() const
{
static const std::unordered_map<OperationType, OperatorDesc> 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<OperationType, std::string> 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<OperationType, std::string> 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<std::string, OperationType> 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
}
};

View file

@ -19,10 +19,3 @@ void PrintNode::Initialize()
{
}
std::string PrintNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
{
return "";
}

View file

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

View file

@ -27,7 +27,7 @@ public:
}
private:
std::shared_ptr<Variable> m_variable;
std::shared_ptr<Variable> m_variable;
};

View file

@ -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<std::shared_ptr<BaseNode>> 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<std::shared_ptr<BaseNode>> nodes(m_nodes.begin(), m_nodes.end());
std::vector<std::shared_ptr<Connection>> links(m_links.begin(), m_links.end());
ASTBuilder builder(nodes, links);
auto pathTree = builder.BuildAST();
generator.GenerateTextSection(pathTree);
}
virtual void GetNodeConnections(std::list<std::shared_ptr<Connection>> &c, const std::string &nodeId) override

View file

@ -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<MediaNode>("media-node");
registerNode<FunctionNode>("operator-node");
registerNode<FunctionNode>("function-node");
registerNode<VariableNode>("variable-node");
registerNode<PrintNode>("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;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -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();
@ -190,9 +191,9 @@ 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();

View file

@ -12,7 +12,7 @@ FunctionNodeWidget::FunctionNodeWidget(IStoryManager &manager, std::shared_ptr<B
, m_manager(manager)
{
// Create defaut one input and one output
AddInput();
AddInputs(1);
AddOutputs(2);
SetOutPinName(0, "Success");
SetOutPinName(1, "Failure");

View file

@ -12,6 +12,8 @@
#include "media_node_widget.h"
#include "function_node_widget.h"
#include "variable_node_widget.h"
#include "operator_node_widget.h"
#include "print_node_widget.h"
#include "gui.h"
#include "uuid.h"
@ -29,8 +31,10 @@ NodeEditorWindow::NodeEditorWindow(IStoryManager &manager)
{
// registerNode<MediaNodeWidget>("media-node");
registerNode<OperatorNodeWidget>("operator-node");
registerNode<FunctionNodeWidget>("function-node");
registerNode<VariableNodeWidget>("variable-node");
registerNode<PrintNodeWidget>("print-node");
}
NodeEditorWindow::~NodeEditorWindow()

View file

@ -0,0 +1,81 @@
#include <sstream>
#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<BaseNode> node)
: BaseNodeWidget(manager, node)
, m_manager(manager)
{
m_opNode = std::dynamic_pointer_cast<OperatorNode>(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<int>(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();
}

View file

@ -0,0 +1,32 @@
#pragma once
#include <vector>
#include <map>
#include <mutex>
#include <set>
#include "base_node_widget.h"
#include "i_story_manager.h"
#include "i_story_project.h"
#include "gui.h"
#include "operator_node.h"
#include <imgui_node_editor.h>
#include "media_node.h"
class OperatorNodeWidget : public BaseNodeWidget
{
public:
OperatorNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
void Draw() override;
virtual void DrawProperties() override;
virtual void Initialize() override;
private:
IStoryManager &m_manager;
std::shared_ptr<OperatorNode> m_opNode;
int m_selectedIndex{-1};
OperatorNode::OperationType m_selectedOperatorType{OperatorNode::OperationType::ADD};
std::string m_selectedOperatorSymbol{"+"};
};

View file

@ -0,0 +1,56 @@
#include <sstream>
#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<BaseNode> node)
: BaseNodeWidget(manager, node)
, m_manager(manager)
{
m_printNode = std::dynamic_pointer_cast<PrintNode>(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();
}

View file

@ -0,0 +1,33 @@
#pragma once
#include <vector>
#include <map>
#include <mutex>
#include <set>
#include "base_node_widget.h"
#include "i_story_manager.h"
#include "i_story_project.h"
#include "gui.h"
#include "print_node.h"
#include <imgui_node_editor.h>
#include "media_node.h"
class PrintNodeWidget : public BaseNodeWidget
{
public:
static const int MAX_PRINT_SIZE = 128;
PrintNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
void Draw() override;
virtual void DrawProperties() override;
virtual void Initialize() override;
private:
IStoryManager &m_manager;
std::shared_ptr<PrintNode> m_printNode;
static char m_buffer[MAX_PRINT_SIZE];
};

View file

@ -11,6 +11,7 @@ VariableNodeWidget::VariableNodeWidget(IStoryManager &manager, std::shared_ptr<B
: BaseNodeWidget(manager, node)
, m_manager(manager)
{
m_variableNode = std::dynamic_pointer_cast<VariableNode>(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)