mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-08 09:43:32 +01:00
Compare commits
4 commits
8111f0a362
...
663fa47004
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
663fa47004 | ||
|
|
0be3ff2203 | ||
|
|
6d544f5879 | ||
|
|
3e00fb1c83 |
37 changed files with 823 additions and 726 deletions
|
|
@ -17,6 +17,11 @@ public:
|
|||
PROJECT_TYPE_PRIMITIVE = 2
|
||||
};
|
||||
|
||||
struct FunctionInfo {
|
||||
std::string uuid;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
virtual ~IStoryProject() {};
|
||||
|
||||
virtual std::string GetName() const = 0;
|
||||
|
|
@ -26,6 +31,7 @@ public:
|
|||
virtual std::string GetUuid() const = 0;
|
||||
virtual std::string GetTitleImage() const = 0;
|
||||
virtual std::string GetTitleSound() const = 0;
|
||||
virtual std::vector<FunctionInfo> GetFunctionsList() const = 0;
|
||||
|
||||
virtual void SetTitleImage(const std::string &titleImage) = 0;
|
||||
virtual void SetTitleSound(const std::string &titleSound) = 0;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
#include "ast_builder.h"
|
||||
#include "assembly_generator.h"
|
||||
#include "call_function_node.h"
|
||||
|
||||
class AssemblyGeneratorChip32 : public AssemblyGenerator
|
||||
{
|
||||
public:
|
||||
AssemblyGeneratorChip32(const GeneratorContext& context)
|
||||
: AssemblyGenerator(context)
|
||||
, m_currentContext(FunctionContext::MAIN_PROGRAM)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -28,6 +30,13 @@ public:
|
|||
GenerateOperatorNode(node);
|
||||
}
|
||||
else if (node->IsType<FunctionEntryNode>()) {
|
||||
// Détecter si c'est le main ou une sous-fonction
|
||||
// Weight 100 = fonction principale (main)
|
||||
auto* entry = node->GetAs<FunctionEntryNode>();
|
||||
m_currentContext = (entry->GetWeight() >= 100)
|
||||
? FunctionContext::MAIN_PROGRAM
|
||||
: FunctionContext::SUB_FUNCTION;
|
||||
|
||||
GenerateFunctionEntry(node);
|
||||
}
|
||||
else if (node->IsType<BranchNode>()) {
|
||||
|
|
@ -36,12 +45,20 @@ public:
|
|||
else if (node->IsType<PrintNode>()) {
|
||||
GeneratePrintNode(node);
|
||||
}
|
||||
else if (node->IsType<CallFunctionNode>()) {
|
||||
GenerateCallFunctionNode(node);
|
||||
}
|
||||
|
||||
// // If there is no any children, put an halt
|
||||
// Détection automatique des fins de fonction/programme
|
||||
if (node->GetChildCount() == 0)
|
||||
{
|
||||
AddComment("Program exit");
|
||||
m_assembly << " halt\n";
|
||||
if (m_currentContext == FunctionContext::MAIN_PROGRAM) {
|
||||
AddComment("Program exit (automatic)");
|
||||
m_assembly << " halt\n";
|
||||
} else {
|
||||
AddComment("Function return (automatic)");
|
||||
m_assembly << " ret\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +72,12 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
enum class FunctionContext {
|
||||
MAIN_PROGRAM,
|
||||
SUB_FUNCTION
|
||||
};
|
||||
|
||||
FunctionContext m_currentContext;
|
||||
|
||||
virtual void GenerateMain() override {
|
||||
// Program entry point
|
||||
|
|
@ -62,7 +85,39 @@ private:
|
|||
}
|
||||
|
||||
void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) {
|
||||
AddComment("Function Entry");
|
||||
auto* entry = node->GetAs<FunctionEntryNode>();
|
||||
|
||||
if (m_currentContext == FunctionContext::MAIN_PROGRAM) {
|
||||
AddComment("Main function entry");
|
||||
} else {
|
||||
AddComment("Function entry");
|
||||
// Si nécessaire, sauvegarder les registres
|
||||
// m_assembly << " push r0\n";
|
||||
// m_assembly << " push r1\n";
|
||||
// etc.
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateCallFunctionNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* callNode = node->GetAs<CallFunctionNode>();
|
||||
if (!callNode) return;
|
||||
|
||||
std::string functionName = callNode->GetFunctionName();
|
||||
|
||||
AddComment("Call function: " + functionName);
|
||||
m_depth++;
|
||||
|
||||
// Préparer les arguments si nécessaire
|
||||
// Dans votre système, les variables globales sont utilisées
|
||||
// donc pas besoin de passer des arguments sur la pile
|
||||
|
||||
// Appel de la fonction
|
||||
m_assembly << " call " << GetFunctionLabel(functionName) << "\n";
|
||||
|
||||
// Après le retour de la fonction, les variables globales
|
||||
// ont potentiellement été modifiées et sont directement accessibles
|
||||
|
||||
m_depth--;
|
||||
}
|
||||
|
||||
void GenerateBranchNode(std::shared_ptr<ASTNode> node)
|
||||
|
|
@ -88,24 +143,20 @@ private:
|
|||
|
||||
std::string label = printNode->GetLabel();
|
||||
|
||||
|
||||
m_assembly << " push r0\n"
|
||||
<< " push r1\n"
|
||||
<< " lcons r0, $" << label << "\n"
|
||||
<< " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments
|
||||
<< " syscall 4\n"
|
||||
<< " pop r1\n"
|
||||
<< " pop r0\n";
|
||||
|
||||
// << ""mov r2, %2 // arguments are in r2, r3, r4 etc.
|
||||
|
||||
m_assembly << " push r0\n"
|
||||
<< " push r1\n"
|
||||
<< " lcons r0, $" << label << "\n"
|
||||
<< " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments
|
||||
<< " syscall 4\n"
|
||||
<< " pop r1\n"
|
||||
<< " pop r0\n";
|
||||
}
|
||||
|
||||
void GenerateOperatorNode(std::shared_ptr<ASTNode> node) {
|
||||
auto* opNode = node->GetAs<OperatorNode>();
|
||||
if (!opNode) return;
|
||||
|
||||
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType())));
|
||||
AddComment("Operator: " + opNode->GetOperatorSymbol());
|
||||
m_depth++;
|
||||
|
||||
// Generate code for variables usage
|
||||
|
|
@ -125,7 +176,7 @@ private:
|
|||
{
|
||||
// Generate code to load the variable value
|
||||
// FIXME: hardcoded 4 bytes, replace by actual real variable size
|
||||
m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << "; Load variable " << var->GetVariableName() << "\n";
|
||||
m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << " ; Load variable " << var->GetVariableName() << "\n";
|
||||
m_assembly << " push r" << reg << "\n";
|
||||
}
|
||||
else
|
||||
|
|
@ -135,13 +186,9 @@ private:
|
|||
}
|
||||
reg++;
|
||||
}
|
||||
|
||||
|
||||
// m_assembly << " load r0, " << inputNode.node->GetId() << "\n";
|
||||
}
|
||||
|
||||
|
||||
// Generate operator code
|
||||
// Generate operator code based on type
|
||||
switch (opNode->GetOperationType()) {
|
||||
case OperatorNode::OperationType::ADD:
|
||||
m_assembly << " pop r0\n"
|
||||
|
|
@ -167,28 +214,133 @@ private:
|
|||
<< " div r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::MODULO:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " mod r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::EQUAL:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " cmp r0, r1\n"
|
||||
<< " lcons r0, 1\n"
|
||||
<< " skipz\n"
|
||||
<< " lcons r0, 0\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::NOT_EQUAL:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " cmp r0, r1\n"
|
||||
<< " lcons r0, 0\n"
|
||||
<< " skipz\n"
|
||||
<< " lcons r0, 1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::GREATER_THAN:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " cmp r0, r1\n"
|
||||
<< " lcons r0, 1\n"
|
||||
<< " skipgt\n"
|
||||
<< " lcons r0, 0\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::LESS_THAN:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " cmp r0, r1\n"
|
||||
<< " lcons r0, 1\n"
|
||||
<< " skiplt\n"
|
||||
<< " lcons r0, 0\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::GREATER_EQUAL:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " cmp r0, r1\n"
|
||||
<< " lcons r0, 1\n"
|
||||
<< " skipge\n"
|
||||
<< " lcons r0, 0\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::LESS_EQUAL:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " cmp r0, r1\n"
|
||||
<< " lcons r0, 1\n"
|
||||
<< " skiple\n"
|
||||
<< " lcons r0, 0\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::AND:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " and r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::GREATER_THAN:
|
||||
case OperatorNode::OperationType::OR:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " gt r0, r0, r1\n"
|
||||
<< " or r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::NOT:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " not r0\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::BITWISE_AND:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " and r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::BITWISE_OR:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " or r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::BITWISE_XOR:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " xor r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::BITWISE_NOT:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " not r0\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::LEFT_SHIFT:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " shl r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
case OperatorNode::OperationType::RIGHT_SHIFT:
|
||||
m_assembly << " pop r0\n"
|
||||
<< " pop r1\n"
|
||||
<< " shr r0, r1\n"
|
||||
<< " push r0\n";
|
||||
break;
|
||||
default:
|
||||
// Make voluntary bad assembly
|
||||
m_assembly << "------>>>> OPERATOR NOT IMPLEMENTED: " << opNode->GetOperatorSymbol() << "\n";
|
||||
break;
|
||||
throw std::runtime_error("Unsupported operator type");
|
||||
}
|
||||
|
||||
m_depth--;
|
||||
}
|
||||
|
||||
virtual void Visit(const std::shared_ptr<Variable> v) override
|
||||
// Helper pour générer le label d'une fonction à partir de son nom
|
||||
std::string GetFunctionLabel(const std::string& functionName) {
|
||||
// Convertir le nom de fonction en label valide
|
||||
// Par exemple: "MyFunction" -> ".func_MyFunction"
|
||||
return ".func_" + functionName;
|
||||
}
|
||||
|
||||
virtual void Visit(const std::shared_ptr<Variable> v) override
|
||||
{
|
||||
if (v->IsConstant())
|
||||
{
|
||||
|
|
@ -232,7 +384,4 @@ private:
|
|||
m_assembly << "$" << v->GetLabel() << " DVB, " << (v->GetValue<bool>() ? "1" : "0") << " ; " << v->GetVariableName() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -102,6 +102,22 @@ public:
|
|||
return m_weight;
|
||||
}
|
||||
|
||||
void SetupExecutionPorts(bool hasInput = true,
|
||||
int numOutputs = 1,
|
||||
bool customRendering = true)
|
||||
{
|
||||
if (m_behavior != BEHAVIOR_EXECUTION) return;
|
||||
|
||||
if (hasInput) {
|
||||
AddInputPort(Port::Type::EXECUTION_PORT, ">", customRendering);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numOutputs; ++i) {
|
||||
std::string label = (numOutputs == 1) ? ">" : std::to_string(i);
|
||||
AddOutputPort(Port::Type::EXECUTION_PORT, label, customRendering);
|
||||
}
|
||||
}
|
||||
|
||||
void SetId(const std::string &id) { m_uuid = id; }
|
||||
std::string GetId() const { return m_uuid; }
|
||||
|
||||
|
|
@ -121,8 +137,8 @@ public:
|
|||
}
|
||||
|
||||
// Port management
|
||||
void AddInputPort(Port::Type type, const std::string& label) {
|
||||
m_inputPorts.push_back({type, label});
|
||||
void AddInputPort(Port::Type type, const std::string& label, bool customRendering = false) {
|
||||
m_inputPorts.push_back({type, label, customRendering});
|
||||
}
|
||||
|
||||
void AddOutputPort(Port::Type type, const std::string& label, bool customRendering = false) {
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
#include "call_function_node.h"
|
||||
#include "story_project.h"
|
||||
#include "connection.h"
|
||||
#include "sys_lib.h"
|
||||
|
||||
|
||||
CallFunctionNode::CallFunctionNode(const std::string &type)
|
||||
: BaseNode(type, "Call Function Node")
|
||||
{
|
||||
nlohmann::json j{ {"function", ""} };
|
||||
SetInternalData(j);
|
||||
}
|
||||
|
||||
void CallFunctionNode::Initialize()
|
||||
{
|
||||
nlohmann::json j = GetInternalData();
|
||||
// m_image = j["image"].get<std::string>();
|
||||
// m_sound = j["sound"].get<std::string>();
|
||||
}
|
||||
|
||||
|
|
@ -1,19 +1,51 @@
|
|||
// call_function_node.h
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "i_story_manager.h"
|
||||
#include "base_node.h"
|
||||
#include "i_script_node.h"
|
||||
#include "i_story_project.h"
|
||||
|
||||
class CallFunctionNode : public BaseNode
|
||||
{
|
||||
public:
|
||||
CallFunctionNode(const std::string &type);
|
||||
CallFunctionNode(const std::string &type)
|
||||
: BaseNode(type, "Call Function Node")
|
||||
, m_functionName("")
|
||||
, m_functionUuid("")
|
||||
{
|
||||
SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
|
||||
SetupExecutionPorts(true, 1, true); // 1 entrée, 1 sortie
|
||||
}
|
||||
|
||||
virtual void Initialize() override;
|
||||
void Initialize() override {
|
||||
// Charger le nom et l'UUID de la fonction depuis les données internes
|
||||
nlohmann::json j = GetInternalData();
|
||||
if (j.contains("functionName")) {
|
||||
m_functionName = j["functionName"].get<std::string>();
|
||||
}
|
||||
if (j.contains("functionUuid")) {
|
||||
m_functionUuid = j["functionUuid"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetFunctionName() const {
|
||||
return m_functionName;
|
||||
}
|
||||
|
||||
std::string GetFunctionUuid() const {
|
||||
return m_functionUuid;
|
||||
}
|
||||
|
||||
void SetFunction(const std::string& uuid, const std::string& name) {
|
||||
m_functionUuid = uuid;
|
||||
m_functionName = name;
|
||||
|
||||
// Sauvegarder dans les données internes pour la persistance
|
||||
nlohmann::json j;
|
||||
j["functionName"] = m_functionName;
|
||||
j["functionUuid"] = m_functionUuid;
|
||||
SetInternalData(j);
|
||||
}
|
||||
|
||||
private:
|
||||
nlohmann::json m_content;
|
||||
};
|
||||
|
||||
std::string m_functionName;
|
||||
std::string m_functionUuid;
|
||||
};
|
||||
|
|
@ -11,7 +11,7 @@ public:
|
|||
{
|
||||
SetWeight(100);
|
||||
SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
|
||||
AddOutputPort(BaseNode::Port::Type::EXECUTION_PORT, ">", true);
|
||||
SetupExecutionPorts(false, 1, true);
|
||||
}
|
||||
|
||||
void Initialize() override {
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "base_node.h"
|
||||
|
||||
class FunctionExitNode : public BaseNode
|
||||
{
|
||||
public:
|
||||
FunctionExitNode(const std::string &type)
|
||||
: BaseNode(type, "Function Exit Node")
|
||||
{
|
||||
|
||||
SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
|
||||
}
|
||||
|
||||
void Initialize() override {
|
||||
// Initialisation spécifique pour FunctionExitNode
|
||||
// Par exemple, préparer les sorties nécessaires pour la fonction
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Ajoutez des méthodes spécifiques pour gérer la sortie de la fonction
|
||||
void FinalizeFunctionExit() {
|
||||
// Logique pour finaliser la sortie de la fonction
|
||||
}
|
||||
};
|
||||
|
|
@ -7,14 +7,20 @@
|
|||
PrintNode::PrintNode(const std::string &type)
|
||||
: BaseNode(type, "Print Node")
|
||||
{
|
||||
// Create empty variable in memory
|
||||
// Create empty variable in memory for the format string
|
||||
auto v = std::make_shared<Variable>(m_label);
|
||||
v->SetConstant(true);
|
||||
m_label = v->GetLabel();
|
||||
m_variables[m_label] = v;
|
||||
|
||||
SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
|
||||
|
||||
SetupExecutionPorts(true, 1, true);
|
||||
|
||||
// Add 4 data input ports for arguments
|
||||
for (int i = 0; i < MAX_INPUT_COUNT; ++i) {
|
||||
AddInputPort(Port::DATA_PORT, "arg" + std::to_string(i));
|
||||
}
|
||||
|
||||
SetText("");
|
||||
}
|
||||
|
||||
|
|
@ -24,11 +30,9 @@ void PrintNode::Initialize()
|
|||
m_variables.at(m_label)->SetTextValue(j["text"].get<std::string>());
|
||||
}
|
||||
|
||||
|
||||
void PrintNode::SetText(const std::string &text)
|
||||
{
|
||||
m_variables.at(m_label)->SetValue<std::string>(text);
|
||||
|
||||
SetInternalData({{"text", text}});
|
||||
}
|
||||
|
||||
|
|
@ -40,5 +44,4 @@ std::string PrintNode::GetLabel() const
|
|||
std::string PrintNode::GetText() const
|
||||
{
|
||||
return m_variables.at(m_label)->GetValue<std::string>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,9 +16,9 @@ public:
|
|||
void SetText(const std::string &text);
|
||||
std::string GetLabel() const;
|
||||
std::string GetText() const;
|
||||
|
||||
static constexpr int MAX_INPUT_COUNT = 4;
|
||||
|
||||
private:
|
||||
std::string m_label; // Label for the string literal
|
||||
uint32_t m_arguments{0}; // number of arguments
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -3,19 +3,19 @@
|
|||
#include "connection.h"
|
||||
#include "sys_lib.h"
|
||||
|
||||
|
||||
VariableNode::VariableNode(const std::string &type)
|
||||
: BaseNode(type, "Variable Node")
|
||||
: BaseNode(type, "Variable Node", BaseNode::BEHAVIOR_DATA)
|
||||
{
|
||||
nlohmann::json j{ {"uuid", ""} };
|
||||
SetInternalData(j);
|
||||
SetBehavior(BaseNode::BEHAVIOR_DATA);
|
||||
|
||||
// Add data output port
|
||||
AddOutputPort(Port::DATA_PORT, "value");
|
||||
}
|
||||
|
||||
void VariableNode::Initialize()
|
||||
{
|
||||
nlohmann::json j = GetInternalData();
|
||||
|
||||
m_variableUuid = j["uuid"].get<std::string>();
|
||||
}
|
||||
|
||||
|
|
@ -33,5 +33,16 @@ std::string VariableNode::GetVariableUuid() const
|
|||
return m_variableUuid;
|
||||
}
|
||||
|
||||
void VariableNode::SetVariable(std::shared_ptr<Variable> var)
|
||||
{
|
||||
m_variable = var;
|
||||
if (var) {
|
||||
SetVariableUuid(var->GetUuid());
|
||||
SetTitle(var->GetLabel());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Variable> VariableNode::GetVariable() const
|
||||
{
|
||||
return m_variable;
|
||||
}
|
||||
|
|
@ -1,27 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "variable.h"
|
||||
#include "i_story_manager.h"
|
||||
#include "base_node.h"
|
||||
#include "i_script_node.h"
|
||||
#include "i_story_project.h"
|
||||
#include "variable.h"
|
||||
|
||||
class VariableNode : public BaseNode
|
||||
{
|
||||
public:
|
||||
|
||||
VariableNode(const std::string &type = "variable-node");
|
||||
VariableNode(const std::string &type);
|
||||
|
||||
virtual void Initialize() override;
|
||||
|
||||
void SetVariableUuid(const std::string &uuid);
|
||||
|
||||
std::string GetVariableUuid() const;
|
||||
|
||||
void SetVariable(std::shared_ptr<Variable> var);
|
||||
std::shared_ptr<Variable> GetVariable() const;
|
||||
|
||||
private:
|
||||
std::string m_variableUuid;
|
||||
|
||||
};
|
||||
|
||||
std::shared_ptr<Variable> m_variable;
|
||||
};
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
#include "story_project.h"
|
||||
#include "story_primitive.h"
|
||||
#include "function_entry_node.h"
|
||||
#include "function_exit_node.h"
|
||||
|
||||
|
||||
static const std::string OperatorNodeUuid = "0226fdac-8f7a-47d7-8584-b23aceb712ec";
|
||||
static const std::string CallFunctionNodeUuid = "02745f38-9b11-49fe-94b1-b2a6b78249fb";
|
||||
|
|
@ -24,7 +24,7 @@ static const std::string VariableNodeUuid = "020cca4e-9cdc-47e7-a6a5-53e4c9152ed
|
|||
static const std::string PrintNodeUuid = "02ee27bc-ff1d-4f94-b700-eab55052ad1c";
|
||||
static const std::string SyscallNodeUuid = "02225cff-4975-400e-8130-41524d8af773";
|
||||
static const std::string FunctionEntryNodeUuid = "02fd145a-b3a6-43c2-83ce-6a187e6d4b5b";
|
||||
static const std::string FunctionExitNodeUuid = "027b723d-2327-4646-a17a-79ddc2e016e4";
|
||||
static const std::string DUMMY_a_prendre_Uuid = "027b723d-2327-4646-a17a-79ddc2e016e4";
|
||||
|
||||
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &type);
|
||||
|
||||
|
|
@ -44,7 +44,6 @@ public:
|
|||
registerNode<PrintNode>(PrintNodeUuid, std::make_shared<StoryPrimitive>("Print"));
|
||||
registerNode<SyscallNode>(SyscallNodeUuid, std::make_shared<StoryPrimitive>("System call"));
|
||||
registerNode<FunctionEntryNode>(FunctionEntryNodeUuid, std::make_shared<StoryPrimitive>("Function entry"));
|
||||
registerNode<FunctionExitNode>(FunctionExitNodeUuid, std::make_shared<StoryPrimitive>("Function exit"));
|
||||
}
|
||||
|
||||
~NodesFactory() = default;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class StoryPage : public IStoryPage
|
|||
public:
|
||||
StoryPage(const std::string_view uuid)
|
||||
: m_uuid(uuid)
|
||||
, m_name("Unnamed Page")
|
||||
{
|
||||
}
|
||||
~StoryPage() {
|
||||
|
|
@ -26,6 +27,9 @@ public:
|
|||
|
||||
std::string_view Uuid() const { return m_uuid; }
|
||||
|
||||
std::string_view GetName() const { return m_name; }
|
||||
void SetName(const std::string& name) { m_name = name; }
|
||||
|
||||
void AddNode(std::shared_ptr<BaseNode> node) {
|
||||
m_nodes.push_back(node);
|
||||
}
|
||||
|
|
@ -125,6 +129,7 @@ public:
|
|||
{
|
||||
nlohmann::json model;
|
||||
model["uuid"] = m_uuid;
|
||||
model["name"] = m_name;
|
||||
|
||||
nlohmann::json nodes = nlohmann::json::array();
|
||||
for (const auto & n : m_nodes)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ public:
|
|||
return m_uuid;
|
||||
}
|
||||
|
||||
virtual std::vector<FunctionInfo> GetFunctionsList() const override {
|
||||
return std::vector<FunctionInfo>();
|
||||
}
|
||||
|
||||
|
||||
virtual std::string GetTitleImage() const {
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ void StoryProject::DeleteNode(const std::string_view &page_uuid, const std::stri
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<StoryPage> StoryProject::GetPage(const std::string &uuid)
|
||||
std::shared_ptr<StoryPage> StoryProject::GetPage(const std::string_view &uuid)
|
||||
{
|
||||
for (const auto & p : m_pages)
|
||||
{
|
||||
|
|
@ -268,6 +268,7 @@ bool StoryProject::ModelFromJson(const nlohmann::json &model, NodesFactory &fact
|
|||
// 1. Create the page in memory
|
||||
auto p = std::make_shared<StoryPage>(pageModel["uuid"].get<std::string>());
|
||||
m_pages.push_back(p);
|
||||
p->SetName(pageModel.value("name", "Unnamed Page"));
|
||||
|
||||
// 2. Load the nodes
|
||||
nlohmann::json nodesJsonArray = pageModel["nodes"];
|
||||
|
|
@ -332,6 +333,30 @@ bool StoryProject::CopyProgramTo(uint8_t *memory, uint32_t size)
|
|||
return success;
|
||||
}
|
||||
|
||||
std::vector<IStoryProject::FunctionInfo> StoryProject::GetFunctionsList() const
|
||||
{
|
||||
std::vector<IStoryProject::FunctionInfo> functions;
|
||||
|
||||
// Parcourir toutes les pages du projet
|
||||
for (const auto& page : m_pages)
|
||||
{
|
||||
// Exclure la page main (MainUuid)
|
||||
if (page->Uuid() == MainUuid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ajouter la page à la liste des fonctions disponibles
|
||||
IStoryProject::FunctionInfo info;
|
||||
info.uuid = page->Uuid();
|
||||
info.name = page->GetName();
|
||||
|
||||
functions.push_back(info);
|
||||
}
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
bool StoryProject::GetAssemblyLine(uint32_t pointer_counter, uint32_t &line)
|
||||
{
|
||||
bool success = false;
|
||||
|
|
|
|||
|
|
@ -99,10 +99,11 @@ public:
|
|||
virtual void SetName(const std::string &name) override { m_name = name; }
|
||||
virtual void SetUuid(const std::string &uuid) override { m_uuid = uuid; }
|
||||
virtual Type GetProjectType() const override { return m_projectType; }
|
||||
std::vector<FunctionInfo> GetFunctionsList() const override;
|
||||
|
||||
// Node interaction
|
||||
std::shared_ptr<StoryPage> CreatePage(const std::string_view uuid);
|
||||
std::shared_ptr<StoryPage> GetPage(const std::string &uuid);
|
||||
std::shared_ptr<StoryPage> GetPage(const std::string_view &uuid);
|
||||
void AddNode(const std::string_view &page, std::shared_ptr<BaseNode> node);
|
||||
|
||||
void AddConnection(const std::string_view &page, std::shared_ptr<Connection> c);
|
||||
|
|
|
|||
|
|
@ -147,6 +147,21 @@ public:
|
|||
return GetValue<bool>();
|
||||
}
|
||||
|
||||
std::string GetValueAsString() const {
|
||||
switch (m_valueType) {
|
||||
case ValueType::INTEGER:
|
||||
return std::to_string(GetValue<int>());
|
||||
case ValueType::FLOAT:
|
||||
return std::to_string(GetValue<float>());
|
||||
case ValueType::BOOL:
|
||||
return GetValue<bool>() ? "true" : "false";
|
||||
case ValueType::STRING:
|
||||
return GetValue<std::string>();
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
using VariableValue = std::variant<int, float, bool, std::string>;
|
||||
|
||||
std::string GetUuid() const {
|
||||
|
|
|
|||
|
|
@ -138,11 +138,11 @@ set(SRCS
|
|||
## Docks
|
||||
src/docks/emulator_dock.cpp
|
||||
src/docks/resources_dock.cpp
|
||||
src/docks/error_list_dock.cpp
|
||||
|
||||
# src/node_editor/media_node_widget.cpp
|
||||
src/node_editor/base_node_widget.cpp
|
||||
src/node_editor/node_editor_window.cpp
|
||||
src/node_editor/call_function_node_widget.cpp
|
||||
src/node_editor/module_node_widget.cpp
|
||||
src/node_editor/variable_node_widget.cpp
|
||||
src/node_editor/operator_node_widget.cpp
|
||||
|
|
@ -184,7 +184,6 @@ set(SRCS
|
|||
../core/story-manager/src/nodes/compare_node.cpp
|
||||
../core/story-manager/src/nodes/branch_node.cpp
|
||||
../core/story-manager/src/nodes/variable_node.cpp
|
||||
../core/story-manager/src/nodes/call_function_node.cpp
|
||||
../core/story-manager/src/nodes/module_node.cpp
|
||||
../core/story-manager/src/nodes/print_node.cpp
|
||||
../core/story-manager/src/nodes/syscall_node.cpp
|
||||
|
|
|
|||
|
|
@ -9,32 +9,32 @@ Size=400,400
|
|||
Collapsed=0
|
||||
|
||||
[Window][Library Manager]
|
||||
Pos=435,26
|
||||
Size=845,388
|
||||
Pos=656,26
|
||||
Size=624,313
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][Console]
|
||||
Pos=60,450
|
||||
Size=610,270
|
||||
Size=475,270
|
||||
Collapsed=0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Emulator]
|
||||
Pos=435,26
|
||||
Size=845,388
|
||||
Pos=656,26
|
||||
Size=624,313
|
||||
Collapsed=0
|
||||
DockId=0x00000003,5
|
||||
|
||||
[Window][Code viewer]
|
||||
Pos=435,26
|
||||
Size=845,388
|
||||
Pos=656,26
|
||||
Size=624,313
|
||||
Collapsed=0
|
||||
DockId=0x00000003,4
|
||||
|
||||
[Window][Resources]
|
||||
Pos=435,26
|
||||
Size=845,388
|
||||
Pos=656,26
|
||||
Size=624,313
|
||||
Collapsed=0
|
||||
DockId=0x00000003,1
|
||||
|
||||
|
|
@ -50,26 +50,26 @@ Size=150,42
|
|||
Collapsed=0
|
||||
|
||||
[Window][Variables]
|
||||
Pos=672,450
|
||||
Size=608,270
|
||||
Pos=537,450
|
||||
Size=743,270
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][CPU]
|
||||
Pos=435,26
|
||||
Size=845,388
|
||||
Pos=656,26
|
||||
Size=624,313
|
||||
Collapsed=0
|
||||
DockId=0x00000003,2
|
||||
|
||||
[Window][RAM view]
|
||||
Pos=435,26
|
||||
Size=845,388
|
||||
Pos=656,26
|
||||
Size=624,313
|
||||
Collapsed=0
|
||||
DockId=0x00000003,3
|
||||
|
||||
[Window][Properties]
|
||||
Pos=435,416
|
||||
Size=845,32
|
||||
Pos=656,341
|
||||
Size=624,107
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
|
|
@ -90,13 +90,13 @@ Collapsed=0
|
|||
|
||||
[Window][Module editor]
|
||||
Pos=60,26
|
||||
Size=373,422
|
||||
Size=594,422
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
|
||||
[Window][Story editor]
|
||||
Pos=60,26
|
||||
Size=373,422
|
||||
Size=594,422
|
||||
Collapsed=0
|
||||
DockId=0x00000001,1
|
||||
|
||||
|
|
@ -105,6 +105,12 @@ Pos=490,260
|
|||
Size=687,422
|
||||
Collapsed=0
|
||||
|
||||
[Window][Error List]
|
||||
Pos=60,450
|
||||
Size=475,270
|
||||
Collapsed=0
|
||||
DockId=0x00000004,1
|
||||
|
||||
[Table][0x7728942D,5]
|
||||
RefScale=20
|
||||
Column 0 Width=44 Sort=0v
|
||||
|
|
@ -144,11 +150,11 @@ Column 0 Sort=0v
|
|||
[Docking][Data]
|
||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y
|
||||
DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,422 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=373,694 CentralNode=1 Selected=0x93ADCAAB
|
||||
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=845,694 Split=Y Selected=0x52EB28B5
|
||||
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,388 Selected=0x63869CAF
|
||||
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,32 Selected=0x8C72BEA8
|
||||
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=790,694 CentralNode=1 Selected=0x93ADCAAB
|
||||
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=624,694 Split=Y Selected=0x52EB28B5
|
||||
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,476 Selected=0x63869CAF
|
||||
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,163 Selected=0x8C72BEA8
|
||||
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,270 Split=X Selected=0xEA83D666
|
||||
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=610,192 Selected=0xEA83D666
|
||||
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=608,192 Selected=0x6DE9B20C
|
||||
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=475,192 Selected=0xD246D6BE
|
||||
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=743,192 Selected=0x6DE9B20C
|
||||
|
||||
|
|
|
|||
99
story-editor/src/docks/error_list_dock.cpp
Normal file
99
story-editor/src/docks/error_list_dock.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#include "error_list_dock.h"
|
||||
#include "imgui.h"
|
||||
|
||||
void ErrorListDock::Draw() {
|
||||
WindowBase::BeginDraw();
|
||||
|
||||
|
||||
ImGui::SetWindowSize(ImVec2(800, 200), ImGuiCond_FirstUseEver);
|
||||
|
||||
// Header avec compteur
|
||||
size_t errorCount = GetErrorCount();
|
||||
size_t warningCount = GetWarningCount();
|
||||
|
||||
if (errorCount > 0) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.9f, 0.2f, 0.2f, 1.0f));
|
||||
ImGui::Text("%s %zu", ICON_FA_TIMES_CIRCLE, errorCount);
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "%s 0", ICON_FA_TIMES_CIRCLE);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (warningCount > 0) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.0f, 1.0f));
|
||||
ImGui::Text("%s %zu", ICON_FA_EXCLAMATION_TRIANGLE, warningCount);
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "%s 0", ICON_FA_EXCLAMATION_TRIANGLE);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(ICON_FA_TRASH " Clear")) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// AJOUT du BeginChild pour la zone scrollable
|
||||
ImGui::BeginChild("ErrorListContent", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
|
||||
// Afficher un message si pas d'erreurs
|
||||
if (m_errors.empty()) {
|
||||
ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f),
|
||||
"%s No errors or warnings", ICON_FA_CHECK_CIRCLE);
|
||||
} else {
|
||||
// Table des erreurs
|
||||
if (ImGui::BeginTable("ErrorTable", 3,
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
|
||||
{
|
||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 80);
|
||||
ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("Node", ImGuiTableColumnFlags_WidthFixed, 80);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (size_t i = 0; i < m_errors.size(); ++i) {
|
||||
const auto& error = m_errors[i];
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// Type column
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, error.GetTypeColor());
|
||||
ImGui::Text("%s %s", error.GetTypeIcon().c_str(),
|
||||
error.type == CompilationError::ERROR ? "Error" :
|
||||
error.type == CompilationError::WARNING ? "Warning" : "Info");
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// Message column
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::TextWrapped("%s", error.message.c_str());
|
||||
|
||||
// Node column (clickable to navigate)
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
if (!error.nodeId.empty()) {
|
||||
if (ImGui::SmallButton(("Go##" + std::to_string(i)).c_str())) {
|
||||
// TODO: Emit event to navigate to node
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("?");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Node: %s", error.nodeId.c_str());
|
||||
}
|
||||
} else {
|
||||
ImGui::TextDisabled("-");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
WindowBase::EndDraw();
|
||||
}
|
||||
75
story-editor/src/docks/error_list_dock.h
Normal file
75
story-editor/src/docks/error_list_dock.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include "window_base.h"
|
||||
#include "IconsFontAwesome5_c.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
struct CompilationError {
|
||||
enum Type {
|
||||
ERROR,
|
||||
WARNING,
|
||||
INFO
|
||||
};
|
||||
|
||||
Type type;
|
||||
std::string message;
|
||||
std::string nodeId; // UUID du nœud concerné
|
||||
int line;
|
||||
|
||||
std::string GetTypeIcon() const {
|
||||
switch(type) {
|
||||
case ERROR: return ICON_FA_TIMES_CIRCLE;
|
||||
case WARNING: return ICON_FA_EXCLAMATION_TRIANGLE;
|
||||
case INFO: return ICON_FA_INFO_CIRCLE;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
ImVec4 GetTypeColor() const {
|
||||
switch(type) {
|
||||
case ERROR: return ImVec4(0.9f, 0.2f, 0.2f, 1.0f);
|
||||
case WARNING: return ImVec4(1.0f, 0.8f, 0.0f, 1.0f);
|
||||
case INFO: return ImVec4(0.3f, 0.7f, 1.0f, 1.0f);
|
||||
}
|
||||
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
};
|
||||
|
||||
class ErrorListDock : public WindowBase {
|
||||
public:
|
||||
ErrorListDock() : WindowBase("Error List") {}
|
||||
|
||||
void Draw() override;
|
||||
|
||||
void Clear() { m_errors.clear(); }
|
||||
void AddError(const CompilationError& error) { m_errors.push_back(error); }
|
||||
void AddError(const std::string& message, const std::string& nodeId = "", int line = 0) {
|
||||
m_errors.push_back({CompilationError::ERROR, message, nodeId, line});
|
||||
}
|
||||
void AddWarning(const std::string& message, const std::string& nodeId = "", int line = 0) {
|
||||
m_errors.push_back({CompilationError::WARNING, message, nodeId, line});
|
||||
}
|
||||
void AddInfo(const std::string& message, const std::string& nodeId = "", int line = 0) {
|
||||
m_errors.push_back({CompilationError::INFO, message, nodeId, line});
|
||||
}
|
||||
|
||||
bool HasErrors() const {
|
||||
return std::any_of(m_errors.begin(), m_errors.end(),
|
||||
[](const auto& e) { return e.type == CompilationError::ERROR; });
|
||||
}
|
||||
|
||||
size_t GetErrorCount() const {
|
||||
return std::count_if(m_errors.begin(), m_errors.end(),
|
||||
[](const auto& e) { return e.type == CompilationError::ERROR; });
|
||||
}
|
||||
|
||||
size_t GetWarningCount() const {
|
||||
return std::count_if(m_errors.begin(), m_errors.end(),
|
||||
[](const auto& e) { return e.type == CompilationError::WARNING; });
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<CompilationError> m_errors;
|
||||
};
|
||||
|
|
@ -664,16 +664,16 @@ void Gui::ApplyTheme()
|
|||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
|
||||
|
||||
// ===== AMÉLIORATION DES ONGLETS =====
|
||||
// Onglet inactif (non sélectionné)
|
||||
colors[ImGuiCol_Tab] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
||||
// Onglet inactif (non sélectionné) - TRÈS FONCÉ
|
||||
colors[ImGuiCol_Tab] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f);
|
||||
// Onglet survolé
|
||||
colors[ImGuiCol_TabHovered] = ImVec4(0.25f, 0.60f, 0.80f, 1.00f);
|
||||
// Onglet actif (sélectionné) - couleur vive et contrastée
|
||||
// Onglet actif (sélectionné dans fenêtre focusée) - BLEU VIF
|
||||
colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.65f, 0.85f, 1.00f);
|
||||
// Onglet inactif dans une fenêtre non-focusée
|
||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f);
|
||||
// Onglet actif dans une fenêtre non-focusée
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.18f, 0.45f, 0.60f, 1.00f);
|
||||
// Onglet inactif dans une fenêtre non-focusée - TRÈS FONCÉ
|
||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f);
|
||||
// Onglet actif dans une fenêtre non-focusée - BEAUCOUP PLUS FONCÉ
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
||||
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||
|
|
@ -701,8 +701,8 @@ void Gui::ApplyTheme()
|
|||
style.PopupRounding = 2.0f;
|
||||
style.ScrollbarRounding = 12.0f;
|
||||
style.ScrollbarSize = 13.0f;
|
||||
style.TabBorderSize = 0.0f; // Pas de bordure autour des onglets
|
||||
style.TabRounding = 4.0f; // Coins arrondis pour les onglets
|
||||
style.TabBorderSize = 0.0f;
|
||||
style.TabRounding = 4.0f;
|
||||
style.WindowRounding = 4.0f;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
enum ToastType {
|
||||
Success,
|
||||
Warning,
|
||||
Error
|
||||
Error,
|
||||
Info
|
||||
};
|
||||
|
||||
struct Toast {
|
||||
|
|
@ -26,7 +27,7 @@ struct Toast {
|
|||
class ImGuiToastNotifier {
|
||||
private:
|
||||
std::vector<Toast> toasts;
|
||||
const float TOAST_WIDTH = 300.0f;
|
||||
const float TOAST_WIDTH = 350.0f;
|
||||
const float TOAST_PADDING = 10.0f;
|
||||
|
||||
public:
|
||||
|
|
@ -34,12 +35,43 @@ public:
|
|||
toasts.push_back({title, text, type, std::chrono::steady_clock::now(), duration});
|
||||
}
|
||||
|
||||
// Helper methods pour les cas communs
|
||||
void success(const std::string& message) {
|
||||
addToast("Success", message, ToastType::Success, 3.0f);
|
||||
}
|
||||
|
||||
void error(const std::string& message, float duration = 5.0f) {
|
||||
addToast("Error", message, ToastType::Error, duration);
|
||||
}
|
||||
|
||||
void warning(const std::string& message) {
|
||||
addToast("Warning", message, ToastType::Warning, 4.0f);
|
||||
}
|
||||
|
||||
void info(const std::string& message) {
|
||||
addToast("Info", message, ToastType::Info, 3.0f);
|
||||
}
|
||||
|
||||
// Pour les erreurs de compilation
|
||||
void compilationFailed(size_t errorCount, size_t warningCount = 0) {
|
||||
std::string msg = std::to_string(errorCount) + " error(s) found";
|
||||
if (warningCount > 0) {
|
||||
msg += ", " + std::to_string(warningCount) + " warning(s)";
|
||||
}
|
||||
msg += ". Check Error List for details.";
|
||||
addToast("Compilation Failed", msg, ToastType::Error, 6.0f);
|
||||
}
|
||||
|
||||
void compilationSuccess(float duration = 2.5f) {
|
||||
addToast("Compilation Success", "Build completed successfully", ToastType::Success, duration);
|
||||
}
|
||||
|
||||
void render() {
|
||||
if (toasts.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the main viewport work area (excludes menu bar, status bar, etc.)
|
||||
// Get the main viewport work area
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImVec2 work_pos = viewport->WorkPos;
|
||||
ImVec2 work_size = viewport->WorkSize;
|
||||
|
|
@ -54,7 +86,6 @@ public:
|
|||
ImGui::SetNextWindowSize(ImVec2(TOAST_WIDTH, 0), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowBgAlpha(0.90f);
|
||||
|
||||
// Add NoNav to prevent interfering with other windows
|
||||
ImGuiWindowFlags window_flags =
|
||||
ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
|
|
@ -103,6 +134,10 @@ public:
|
|||
color = ImVec4(0.94f, 0.31f, 0.31f, 1.0f);
|
||||
icon = ICON_FA_TIMES_CIRCLE;
|
||||
break;
|
||||
case Info:
|
||||
color = ImVec4(0.3f, 0.7f, 1.0f, 1.0f);
|
||||
icon = ICON_FA_INFO_CIRCLE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw icon and title on the same line
|
||||
|
|
@ -111,13 +146,13 @@ public:
|
|||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); // Use default font for title
|
||||
ImGui::TextUnformatted(it->title.c_str());
|
||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]);
|
||||
ImGui::Text("%s", it->title.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
// Draw message text with wrapping
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + TOAST_WIDTH - 24.0f);
|
||||
ImGui::TextUnformatted(it->text.c_str());
|
||||
ImGui::TextWrapped("%s", it->text.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
|
||||
ImGui::PopStyleVar(); // Alpha
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#include "print_node_widget.h"
|
||||
#include "syscall_node_widget.h"
|
||||
#include "function_entry_widget.h"
|
||||
#include "function_exit_widget.h"
|
||||
|
||||
|
||||
MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appController)
|
||||
: m_logger(logger)
|
||||
|
|
@ -74,7 +74,6 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
|
|||
m_widgetFactory.registerNode<PrintNodeWidget>(PrintNodeUuid);
|
||||
m_widgetFactory.registerNode<SyscallNodeWidget>(SyscallNodeUuid);
|
||||
m_widgetFactory.registerNode<FunctionEntryWidget>(FunctionEntryNodeUuid);
|
||||
m_widgetFactory.registerNode<FunctionExitWidget>(FunctionExitNodeUuid);
|
||||
|
||||
m_eventBus.Subscribe<OpenProjectEvent>([this](const OpenProjectEvent &event) {
|
||||
OpenProject(event.GetUuid());
|
||||
|
|
@ -517,6 +516,7 @@ bool MainWindow::Loop()
|
|||
|
||||
// ------------ Draw all windows
|
||||
m_libraryWindow.Draw();
|
||||
m_errorListDock.Draw();
|
||||
|
||||
if (m_appController.IsLibraryManagerInitialized())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "debugger_window.h"
|
||||
#include "emulator_dock.h"
|
||||
#include "resources_dock.h"
|
||||
#include "error_list_dock.h"
|
||||
#include "node_editor_window.h"
|
||||
#include "properties_window.h"
|
||||
#include "variables_window.h"
|
||||
|
|
@ -50,6 +51,7 @@ private:
|
|||
|
||||
Gui m_gui;
|
||||
EmulatorDock m_emulatorDock;
|
||||
ErrorListDock m_errorListDock;
|
||||
ConsoleWindow m_consoleWindow;
|
||||
DebuggerWindow m_debuggerWindow;
|
||||
CpuWindow m_cpuWindow;
|
||||
|
|
|
|||
|
|
@ -25,4 +25,68 @@ void BaseNodeWidget::Initialize()
|
|||
|
||||
}
|
||||
|
||||
void BaseNodeWidget::DrawSocket(const Nw::Pin &pin)
|
||||
{
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
// Taille du socket
|
||||
float socket_size = 4.0f;
|
||||
|
||||
// Définir les 5 points du polygone (flèche pointant vers la droite pour Output)
|
||||
// Pour Input, la flèche pointerait vers la gauche
|
||||
ImVec2 p1, p2, p3, p4, p5;
|
||||
|
||||
if (pin.pinKind == Nw::PinKind::Output) {
|
||||
// Flèche pointant vers la droite (→)
|
||||
p1 = ImVec2(pin.pinPoint.x - socket_size * 1.5f, pin.pinPoint.y - socket_size);
|
||||
p2 = ImVec2(pin.pinPoint.x - socket_size * 0.5f, pin.pinPoint.y - socket_size);
|
||||
p3 = ImVec2(pin.pinPoint.x + socket_size * 0.5f, pin.pinPoint.y); // Pointe
|
||||
p4 = ImVec2(pin.pinPoint.x - socket_size * 0.5f, pin.pinPoint.y + socket_size);
|
||||
p5 = ImVec2(pin.pinPoint.x - socket_size * 1.5f, pin.pinPoint.y + socket_size);
|
||||
} else {
|
||||
// Flèche pointant vers la gauche (←)
|
||||
p1 = ImVec2(pin.pinPoint.x + socket_size * 1.5f, pin.pinPoint.y - socket_size);
|
||||
p2 = ImVec2(pin.pinPoint.x + socket_size * 0.5f, pin.pinPoint.y - socket_size);
|
||||
p3 = ImVec2(pin.pinPoint.x - socket_size * 0.5f, pin.pinPoint.y); // Pointe
|
||||
p4 = ImVec2(pin.pinPoint.x + socket_size * 0.5f, pin.pinPoint.y + socket_size);
|
||||
p5 = ImVec2(pin.pinPoint.x + socket_size * 1.5f, pin.pinPoint.y + socket_size);
|
||||
}
|
||||
|
||||
ImVec2 vertices[] = {p1, p2, p3, p4, p5};
|
||||
|
||||
// Rectangle pour la détection de hover
|
||||
ImVec2 tl = pin.pinPoint - ImVec2(socket_size * 1.5f, socket_size);
|
||||
ImVec2 br = pin.pinPoint + ImVec2(socket_size * 1.5f, socket_size);
|
||||
|
||||
bool hovered = ImGui::IsItemHovered() || ImGui::IsMouseHoveringRect(tl, br);
|
||||
|
||||
// Dessin du socket
|
||||
if (pin.isConnected) {
|
||||
// Rempli quand connecté
|
||||
draw_list->AddConvexPolyFilled(vertices, IM_ARRAYSIZE(vertices),
|
||||
pin.style.color);
|
||||
} else {
|
||||
// Contour seulement quand non connecté
|
||||
if (hovered) {
|
||||
draw_list->AddPolyline(vertices, IM_ARRAYSIZE(vertices),
|
||||
pin.style.color,
|
||||
ImDrawFlags_Closed,
|
||||
pin.style.socket_hovered_radius); // Épaisseur au hover
|
||||
} else {
|
||||
draw_list->AddPolyline(vertices, IM_ARRAYSIZE(vertices),
|
||||
pin.style.color,
|
||||
ImDrawFlags_Closed,
|
||||
pin.style.socket_thickness); // Épaisseur normale
|
||||
}
|
||||
}
|
||||
|
||||
// Optionnel : dessiner la décoration (fond hover) si nécessaire
|
||||
if (hovered) {
|
||||
draw_list->AddRectFilled(pin.pos - pin.style.padding,
|
||||
pin.pos + pin.size + pin.style.padding,
|
||||
pin.style.bg_hover_color,
|
||||
pin.style.bg_radius);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public:
|
|||
virtual void DrawProperties(std::shared_ptr<IStoryProject> story) = 0;
|
||||
|
||||
|
||||
virtual void DrawSocket(const Nw::Pin &pin) {}
|
||||
virtual void DrawSocket(const Nw::Pin &pin);
|
||||
|
||||
|
||||
virtual bool HasSync() const {
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
#include <sstream>
|
||||
#include "call_function_node_widget.h"
|
||||
|
||||
#include "IconsMaterialDesignIcons.h"
|
||||
#include "story_project.h"
|
||||
#include "uuid.h"
|
||||
|
||||
CallFunctionNodeWidget::CallFunctionNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node)
|
||||
: BaseNodeWidget(manager, node)
|
||||
, m_manager(manager)
|
||||
{
|
||||
m_functionUuid = Uuid().String();
|
||||
}
|
||||
|
||||
void CallFunctionNodeWidget::Draw()
|
||||
{
|
||||
ImGui::TextUnformatted(m_functionName.c_str());
|
||||
if (ImGui::Button("> Open function"))
|
||||
{
|
||||
m_manager.OpenFunction(m_functionUuid, m_functionName);
|
||||
}
|
||||
}
|
||||
|
||||
void CallFunctionNodeWidget::Initialize()
|
||||
{
|
||||
BaseNodeWidget::Initialize();
|
||||
m_functionName = "Function";
|
||||
}
|
||||
|
||||
void CallFunctionNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
// call_function_node_widget.h
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "base_node_widget.h"
|
||||
#include "i_story_manager.h"
|
||||
|
|
@ -11,22 +11,74 @@
|
|||
#include "call_function_node.h"
|
||||
#include "gui.h"
|
||||
|
||||
|
||||
class CallFunctionNodeWidget : public BaseNodeWidget
|
||||
{
|
||||
public:
|
||||
CallFunctionNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
|
||||
CallFunctionNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node)
|
||||
: BaseNodeWidget(manager, node)
|
||||
, m_manager(manager)
|
||||
{
|
||||
m_callFunctionNode = std::dynamic_pointer_cast<CallFunctionNode>(node);
|
||||
SetTitle("Call Function");
|
||||
}
|
||||
|
||||
void Draw() override;
|
||||
void Initialize() override {
|
||||
BaseNodeWidget::Initialize();
|
||||
m_functionName = m_callFunctionNode->GetFunctionName();
|
||||
m_functionUuid = m_callFunctionNode->GetFunctionUuid();
|
||||
}
|
||||
|
||||
virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override;
|
||||
virtual void Initialize() override;
|
||||
void DrawProperties(std::shared_ptr<IStoryProject> story) override {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
// Liste déroulante des fonctions disponibles
|
||||
if (ImGui::BeginCombo("Function", m_functionName.empty() ? "<Select function>" : m_functionName.c_str())) {
|
||||
|
||||
// Récupérer la liste des fonctions du projet
|
||||
auto functions = story->GetFunctionsList(); // À implémenter dans IStoryProject
|
||||
|
||||
for (size_t i = 0; i < functions.size(); ++i) {
|
||||
const bool is_selected = (m_functionUuid == functions[i].uuid);
|
||||
|
||||
if (ImGui::Selectable(functions[i].name.c_str(), is_selected)) {
|
||||
m_functionUuid = functions[i].uuid;
|
||||
m_functionName = functions[i].name;
|
||||
m_callFunctionNode->SetFunction(m_functionUuid, m_functionName);
|
||||
}
|
||||
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
// Bouton pour ouvrir la fonction dans l'éditeur
|
||||
ImGui::Spacing();
|
||||
|
||||
// Désactiver le bouton si aucune fonction n'est sélectionnée
|
||||
if (m_functionUuid.empty()) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
|
||||
if (ImGui::Button("> Open function")) {
|
||||
m_manager.OpenFunction(m_functionUuid, m_functionName);
|
||||
}
|
||||
|
||||
if (m_functionUuid.empty()) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
void Draw() override {
|
||||
// Afficher le nom de la fonction dans le noeud
|
||||
ImGui::TextUnformatted(m_functionName.empty()
|
||||
? "<No function>"
|
||||
: m_functionName.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
IStoryManager &m_manager;
|
||||
|
||||
std::shared_ptr<CallFunctionNode> m_callFunctionNode;
|
||||
|
||||
std::string m_functionName;
|
||||
std::string m_functionUuid;
|
||||
};
|
||||
std::string m_functionUuid;
|
||||
};
|
||||
|
|
@ -11,109 +11,6 @@
|
|||
#include "function_entry_node.h"
|
||||
#include "gui.h"
|
||||
|
||||
|
||||
void DrawBlueprintSyncSocket(ImDrawList* draw_list, const ImVec2& center, float size, ImU32 color, bool filled = true) {
|
||||
const float half_size = size * 0.5f;
|
||||
const float triangle_size = size * 0.6f; // Triangle légèrement plus petit que le carré
|
||||
|
||||
// Coordonnées du carré (partie gauche)
|
||||
ImVec2 square_min = ImVec2(center.x - half_size, center.y - half_size);
|
||||
ImVec2 square_max = ImVec2(center.x, center.y + half_size);
|
||||
|
||||
// Coordonnées du triangle (partie droite, pointant vers la droite)
|
||||
ImVec2 triangle_p1 = ImVec2(center.x, center.y - triangle_size * 0.5f); // Point haut
|
||||
ImVec2 triangle_p2 = ImVec2(center.x, center.y + triangle_size * 0.5f); // Point bas
|
||||
ImVec2 triangle_p3 = ImVec2(center.x + triangle_size * 0.7f, center.y); // Point de la pointe
|
||||
|
||||
if (filled) {
|
||||
// Dessiner le carré rempli
|
||||
draw_list->AddRectFilled(square_min, square_max, color);
|
||||
|
||||
// Dessiner le triangle rempli
|
||||
draw_list->AddTriangleFilled(triangle_p1, triangle_p2, triangle_p3, color);
|
||||
} else {
|
||||
// Dessiner les contours
|
||||
const float thickness = 2.0f;
|
||||
|
||||
// Contour du carré
|
||||
draw_list->AddRect(square_min, square_max, color, 0.0f, 0, thickness);
|
||||
|
||||
// Contour du triangle
|
||||
draw_list->AddTriangle(triangle_p1, triangle_p2, triangle_p3, color, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
// Version avec dégradé pour un effet plus moderne
|
||||
void DrawBlueprintSyncSocketGradient(ImDrawList* draw_list, const ImVec2& center, float size, ImU32 color_start, ImU32 color_end) {
|
||||
const float half_size = size * 0.5f;
|
||||
const float triangle_size = size * 0.6f;
|
||||
|
||||
// Coordonnées du carré
|
||||
ImVec2 square_min = ImVec2(center.x - half_size, center.y - half_size);
|
||||
ImVec2 square_max = ImVec2(center.x, center.y + half_size);
|
||||
|
||||
// Coordonnées du triangle
|
||||
ImVec2 triangle_p1 = ImVec2(center.x, center.y - triangle_size * 0.5f);
|
||||
ImVec2 triangle_p2 = ImVec2(center.x, center.y + triangle_size * 0.5f);
|
||||
ImVec2 triangle_p3 = ImVec2(center.x + triangle_size * 0.7f, center.y);
|
||||
|
||||
// Carré avec dégradé horizontal
|
||||
draw_list->AddRectFilledMultiColor(
|
||||
square_min, square_max,
|
||||
color_start, color_end,
|
||||
color_end, color_start
|
||||
);
|
||||
|
||||
// Triangle uni (couleur de fin du dégradé)
|
||||
draw_list->AddTriangleFilled(triangle_p1, triangle_p2, triangle_p3, color_end);
|
||||
}
|
||||
|
||||
// Variante avec animation de pulsation pour indiquer l'activité
|
||||
void DrawBlueprintSyncSocketAnimated(ImDrawList* draw_list, const ImVec2& center, float size, ImU32 color, float time) {
|
||||
// Effet de pulsation basé sur le temps
|
||||
float pulse = 0.8f + 0.2f * sinf(time * 3.0f); // Oscille entre 0.8 et 1.0
|
||||
float animated_size = size * pulse;
|
||||
|
||||
// Socket principal
|
||||
DrawBlueprintSyncSocket(draw_list, center, animated_size, color, true);
|
||||
|
||||
// Halo subtil autour
|
||||
ImU32 halo_color = ImGui::ColorConvertFloat4ToU32(ImVec4(
|
||||
((color >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f,
|
||||
((color >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f,
|
||||
((color >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f,
|
||||
0.3f * (pulse - 0.8f) * 5.0f // Alpha qui varie avec la pulsation
|
||||
));
|
||||
|
||||
DrawBlueprintSyncSocket(draw_list, center, size * 1.2f, halo_color, false);
|
||||
}
|
||||
|
||||
// Utilisation dans ImNodeFlow
|
||||
void DrawSyncSocketInNode(ImDrawList* draw_list, const ImVec2& socket_pos, bool is_connected, bool is_hovered) {
|
||||
const float socket_size = 16.0f;
|
||||
|
||||
// Couleurs selon l'état
|
||||
ImU32 base_color = IM_COL32(100, 150, 255, 255); // Bleu par défaut
|
||||
ImU32 connected_color = IM_COL32(50, 255, 100, 255); // Vert si connecté
|
||||
ImU32 hover_color = IM_COL32(255, 200, 50, 255); // Orange au survol
|
||||
|
||||
ImU32 final_color = base_color;
|
||||
if (is_connected) final_color = connected_color;
|
||||
if (is_hovered) final_color = hover_color;
|
||||
|
||||
// Dessiner le socket
|
||||
if (is_connected) {
|
||||
// Version animée si connecté
|
||||
float time = ImGui::GetTime();
|
||||
DrawBlueprintSyncSocketAnimated(draw_list, socket_pos, socket_size, final_color, time);
|
||||
} else {
|
||||
// Version statique
|
||||
DrawBlueprintSyncSocket(draw_list, socket_pos, socket_size, final_color, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class FunctionEntryWidget : public BaseNodeWidget
|
||||
{
|
||||
public:
|
||||
|
|
@ -129,141 +26,6 @@ public:
|
|||
ImGui::SetNextItemWidth(100.f);
|
||||
}
|
||||
|
||||
|
||||
void DrawSocket(const Nw::Pin &pin) override
|
||||
{
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
// Taille du socket
|
||||
float socket_size = 4.0f;
|
||||
|
||||
// Définir les 5 points du polygone (flèche pointant vers la droite pour Output)
|
||||
// Pour Input, la flèche pointerait vers la gauche
|
||||
ImVec2 p1, p2, p3, p4, p5;
|
||||
|
||||
if (pin.pinKind == Nw::PinKind::Output) {
|
||||
// Flèche pointant vers la droite (→)
|
||||
p1 = ImVec2(pin.pinPoint.x - socket_size * 1.5f, pin.pinPoint.y - socket_size);
|
||||
p2 = ImVec2(pin.pinPoint.x - socket_size * 0.5f, pin.pinPoint.y - socket_size);
|
||||
p3 = ImVec2(pin.pinPoint.x + socket_size * 0.5f, pin.pinPoint.y); // Pointe
|
||||
p4 = ImVec2(pin.pinPoint.x - socket_size * 0.5f, pin.pinPoint.y + socket_size);
|
||||
p5 = ImVec2(pin.pinPoint.x - socket_size * 1.5f, pin.pinPoint.y + socket_size);
|
||||
} else {
|
||||
// Flèche pointant vers la gauche (←)
|
||||
p1 = ImVec2(pin.pinPoint.x + socket_size * 1.5f, pin.pinPoint.y - socket_size);
|
||||
p2 = ImVec2(pin.pinPoint.x + socket_size * 0.5f, pin.pinPoint.y - socket_size);
|
||||
p3 = ImVec2(pin.pinPoint.x - socket_size * 0.5f, pin.pinPoint.y); // Pointe
|
||||
p4 = ImVec2(pin.pinPoint.x + socket_size * 0.5f, pin.pinPoint.y + socket_size);
|
||||
p5 = ImVec2(pin.pinPoint.x + socket_size * 1.5f, pin.pinPoint.y + socket_size);
|
||||
}
|
||||
|
||||
ImVec2 vertices[] = {p1, p2, p3, p4, p5};
|
||||
|
||||
// Rectangle pour la détection de hover
|
||||
ImVec2 tl = pin.pinPoint - ImVec2(socket_size * 1.5f, socket_size);
|
||||
ImVec2 br = pin.pinPoint + ImVec2(socket_size * 1.5f, socket_size);
|
||||
|
||||
bool hovered = ImGui::IsItemHovered() || ImGui::IsMouseHoveringRect(tl, br);
|
||||
|
||||
// Dessin du socket
|
||||
if (pin.isConnected) {
|
||||
// Rempli quand connecté
|
||||
draw_list->AddConvexPolyFilled(vertices, IM_ARRAYSIZE(vertices),
|
||||
pin.style.color);
|
||||
} else {
|
||||
// Contour seulement quand non connecté
|
||||
if (hovered) {
|
||||
draw_list->AddPolyline(vertices, IM_ARRAYSIZE(vertices),
|
||||
pin.style.color,
|
||||
ImDrawFlags_Closed,
|
||||
pin.style.socket_hovered_radius); // Épaisseur au hover
|
||||
} else {
|
||||
draw_list->AddPolyline(vertices, IM_ARRAYSIZE(vertices),
|
||||
pin.style.color,
|
||||
ImDrawFlags_Closed,
|
||||
pin.style.socket_thickness); // Épaisseur normale
|
||||
}
|
||||
}
|
||||
|
||||
// Optionnel : dessiner la décoration (fond hover) si nécessaire
|
||||
if (hovered) {
|
||||
draw_list->AddRectFilled(pin.pos - pin.style.padding,
|
||||
pin.pos + pin.size + pin.style.padding,
|
||||
pin.style.bg_hover_color,
|
||||
pin.style.bg_radius);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// bonne position du socket
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
// 1. Dessiner le socket à pin.pinPoint (pas à pin.pos !)
|
||||
if (pin.isConnected) {
|
||||
draw_list->AddCircleFilled(pin.pinPoint,
|
||||
pin.style.socket_connected_radius,
|
||||
pin.style.color);
|
||||
} else {
|
||||
// Gérer le hover vous-même si nécessaire
|
||||
ImVec2 tl = pin.pinPoint - ImVec2(pin.style.socket_radius, pin.style.socket_radius);
|
||||
ImVec2 br = pin.pinPoint + ImVec2(pin.style.socket_radius, pin.style.socket_radius);
|
||||
bool hovered = ImGui::IsMouseHoveringRect(tl, br);
|
||||
|
||||
draw_list->AddCircle(pin.pinPoint,
|
||||
hovered ? pin.style.socket_hovered_radius
|
||||
: pin.style.socket_radius,
|
||||
pin.style.color,
|
||||
pin.style.socket_shape,
|
||||
pin.style.socket_thickness);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
float socket_size = 4;
|
||||
|
||||
// pin.pos.x = pin.pos.x + 10;
|
||||
|
||||
ImVec2 w_pos = ImGui::GetCursorPos();
|
||||
std::cout << "x = " << w_pos.x << ", y = " << w_pos.y << std::endl;;
|
||||
|
||||
// Définir les points du polygone pour le symbole de synchronisation
|
||||
// C'est un polygone fermé à 5 points
|
||||
ImVec2 p1(pin.pos.x - socket_size * 0.5f, pin.pos.y - socket_size);
|
||||
ImVec2 p2(pin.pos.x + socket_size * 0.5f, pin.pos.y - socket_size);
|
||||
ImVec2 p3(pin.pos.x + socket_size * 0.5f, pin.pos.y + socket_size);
|
||||
ImVec2 p4(pin.pos.x - socket_size * 0.5f, pin.pos.y + socket_size);
|
||||
ImVec2 p5(pin.pos.x + socket_size * 1.5f, pin.pos.y);
|
||||
|
||||
ImVec2 vertices[] = {p1, p2, p5, p3, p4}; // Ordre des sommets
|
||||
|
||||
// Pour la détection de survol (hover) on peut toujours utiliser le rectangle englobant
|
||||
ImVec2 tl = pin.pos - ImVec2(socket_size * 1.5f, socket_size);
|
||||
ImVec2 br = pin.pos + ImVec2(socket_size * 1.5f, socket_size);
|
||||
|
||||
if (pin.isConnected)
|
||||
{
|
||||
draw_list->AddConvexPolyFilled(vertices, IM_ARRAYSIZE(vertices), IM_COL32(255,255,255,255));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImGui::IsItemHovered() || ImGui::IsMouseHoveringRect(tl, br))
|
||||
{
|
||||
draw_list->AddPolyline(vertices, IM_ARRAYSIZE(vertices),IM_COL32(255,255,255,255), ImDrawFlags_Closed, 2.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_list->AddPolyline(vertices, IM_ARRAYSIZE(vertices), IM_COL32(255,255,255,255), ImDrawFlags_Closed, 1.3f);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
virtual bool HasSync() const override {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
#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 "function_exit_node.h"
|
||||
#include "gui.h"
|
||||
|
||||
|
||||
class FunctionExitWidget : public BaseNodeWidget
|
||||
{
|
||||
public:
|
||||
FunctionExitWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node)
|
||||
: BaseNodeWidget(manager, node)
|
||||
, m_manager(manager)
|
||||
{
|
||||
m_functionExitNode = std::dynamic_pointer_cast<FunctionExitNode>(node);
|
||||
SetTitle("Function Exit");
|
||||
}
|
||||
|
||||
void Draw() override {
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
}
|
||||
|
||||
virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override {
|
||||
|
||||
}
|
||||
virtual void Initialize() override {
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
IStoryManager &m_manager;
|
||||
|
||||
std::shared_ptr<FunctionExitNode> m_functionExitNode;
|
||||
|
||||
};
|
||||
|
|
@ -10,25 +10,7 @@
|
|||
#include "node_widget_factory.h"
|
||||
#include "i_story_manager.h"
|
||||
#include "ImNodeFlow.h"
|
||||
|
||||
class SimpleSum : public ImFlow::BaseNode {
|
||||
public:
|
||||
SimpleSum() {
|
||||
setTitle("Simple sum");
|
||||
setStyle(ImFlow::NodeStyle::green());
|
||||
ImFlow::BaseNode::addIN<int>("In", 0, ImFlow::ConnectionFilter::SameType());
|
||||
ImFlow::BaseNode::addOUT<int>("Out", nullptr)->behaviour([this]() { return getInVal<int>("In") + m_valB; });
|
||||
}
|
||||
|
||||
void draw() override {
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::InputInt("##ValB", &m_valB);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_valB = 0;
|
||||
};
|
||||
|
||||
#include "base_node.h"
|
||||
|
||||
// Generic delegate
|
||||
class NodeDelegate : public ImFlow::BaseNode {
|
||||
|
|
@ -45,20 +27,16 @@ public:
|
|||
setTitle(m_widget->GetTitle());
|
||||
setStyle(ImFlow::NodeStyle::green());
|
||||
|
||||
// Add Sync input if it is an executable node
|
||||
if (m_widget->HasSync())
|
||||
{
|
||||
ImFlow::BaseNode::addIN<int>(">", 0, ImFlow::ConnectionFilter::SameType());
|
||||
}
|
||||
|
||||
// Add inputs
|
||||
for (int i = 0; i < m_widget->Inputs(); ++i) {
|
||||
|
||||
auto port = m_widget->Base()->GetInputPort(i);
|
||||
|
||||
std::string label = (port.type == ::BaseNode::Port::Type::EXECUTION_PORT) ? "" : port.label;
|
||||
|
||||
if (port.customSocketIcon)
|
||||
{
|
||||
ImFlow::BaseNode::addIN<int>("In" + std::to_string(i), 0, ImFlow::ConnectionFilter::SameType())->renderer([this, i](ImFlow::Pin* p) {
|
||||
ImFlow::BaseNode::addIN<int>(label, 0, ImFlow::ConnectionFilter::SameType())->renderer([this, i](ImFlow::Pin* p) {
|
||||
Nw::Pin pin;
|
||||
pin.index = i;
|
||||
pin.isConnected = p->isConnected();
|
||||
|
|
@ -72,7 +50,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
ImFlow::BaseNode::addIN<int>("In" + std::to_string(i), 0, ImFlow::ConnectionFilter::SameType());
|
||||
ImFlow::BaseNode::addIN<int>(label, 0, ImFlow::ConnectionFilter::SameType());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,9 +58,11 @@ public:
|
|||
for (int i = 0; i < m_widget->Outputs(); ++i)
|
||||
{
|
||||
auto port = m_widget->Base()->GetOutputPort(i);
|
||||
// Détermine le label : vide pour les ports d'exécution, utilise port.label pour les ports de données
|
||||
std::string label = (port.type == ::BaseNode::Port::Type::EXECUTION_PORT) ? "" : port.label;
|
||||
if (port.customSocketIcon)
|
||||
{
|
||||
ImFlow::BaseNode::addOUT<int>("Out" + std::to_string(i), nullptr)->renderer([this, i](ImFlow::Pin* p) {
|
||||
ImFlow::BaseNode::addOUT<int>(label, nullptr)->renderer([this, i](ImFlow::Pin* p) {
|
||||
|
||||
Nw::Pin pin;
|
||||
pin.index = i;
|
||||
|
|
@ -97,7 +77,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
ImFlow::BaseNode::addOUT<int>("Out" + std::to_string(i), nullptr)->behaviour([this, i]() { return getInVal<int>("In" + std::to_string(i)) + m_valB; });
|
||||
ImFlow::BaseNode::addOUT<int>(label, nullptr)->behaviour([this, i]() { return getInVal<int>("In" + std::to_string(i)) + m_valB; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -216,41 +196,10 @@ struct NodeEditorPage : public ImFlow::BaseNode
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
for (const auto & n : m_nodes)
|
||||
{
|
||||
ImGui::PushID(n->GetInternalId());
|
||||
n->Draw();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
for (const auto& linkInfo : m_links)
|
||||
{
|
||||
ed::Link(linkInfo->ed_link->Id, linkInfo->ed_link->OutputId, linkInfo->ed_link->InputId);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// bool GetNode(const ed::NodeId &nodeId, std::shared_ptr<BaseNodeWidget> &node) {
|
||||
// for (const auto & n : m_nodes)
|
||||
// {
|
||||
// if (n->GetInternalId() == nodeId.Get())
|
||||
// {
|
||||
// node = n;
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// void DeleteNode(const ed::NodeId &nodeId) {
|
||||
// m_nodes.remove_if([nodeId](const std::shared_ptr<BaseNodeWidget>& node) {
|
||||
// return node->GetInternalId() == nodeId.Get();
|
||||
// });
|
||||
// }
|
||||
|
||||
std::shared_ptr<BaseNodeWidget> GetSelectedNode() {
|
||||
std::shared_ptr<BaseNodeWidget> GetSelectedNode()
|
||||
{
|
||||
|
||||
std::shared_ptr<BaseNodeWidget> selected;
|
||||
|
||||
|
|
@ -275,124 +224,9 @@ struct NodeEditorPage : public ImFlow::BaseNode
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if (ed::GetSelectedObjectCount() > 0)
|
||||
// {
|
||||
// ed::NodeId nId;
|
||||
// int nodeCount = ed::GetSelectedNodes(&nId, 1);
|
||||
|
||||
// if (nodeCount > 0)
|
||||
// {
|
||||
// for (auto & n : m_nodes)
|
||||
// {
|
||||
// if (n->GetInternalId() == nId.Get())
|
||||
// {
|
||||
// selected = n;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return selected;
|
||||
}
|
||||
|
||||
// void AddNode(std::shared_ptr<BaseNodeWidget> node) {
|
||||
// m_nodes.push_back(node);
|
||||
// }
|
||||
|
||||
// void Clear() {
|
||||
// m_nodes.clear();
|
||||
// m_links.clear();
|
||||
// }
|
||||
/*
|
||||
bool GetModel(ed::LinkId linkId, std::shared_ptr<Connection> &model) {
|
||||
for (const auto& linkInfo : m_links)
|
||||
{
|
||||
if (linkInfo->ed_link->Id == linkId)
|
||||
{
|
||||
model = linkInfo->model;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EraseLink(ed::LinkId linkId) {
|
||||
m_links.remove_if([linkId](const std::shared_ptr<LinkInfo>& linkInfo) {
|
||||
return linkInfo->ed_link->Id == linkId;
|
||||
});
|
||||
}
|
||||
|
||||
// retourne 1 si c'est une sortie, 2 une entrée, 0 pas trouvé
|
||||
int FindNodeAndPin(ed::PinId pinId, int &foundIndex, std::string &foundNodeId)
|
||||
{
|
||||
int success = 0;
|
||||
for (const auto & n : m_nodes)
|
||||
{
|
||||
// std::cout << "---> Node: " << n->Base()->GetId() << std::endl;
|
||||
|
||||
if (n->HasOnputPinId(pinId, foundIndex))
|
||||
{
|
||||
foundNodeId = n->Base()->GetId();
|
||||
success = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n->HasInputPinId(pinId, foundIndex))
|
||||
{
|
||||
foundNodeId = n->Base()->GetId();
|
||||
success = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
ed::PinId GetInputPin(const std::string &modelNodeId, int pinIndex)
|
||||
{
|
||||
ed::PinId id = 0;
|
||||
|
||||
for (auto & n : m_nodes)
|
||||
{
|
||||
if (n->Base()->GetId() == modelNodeId)
|
||||
{
|
||||
id = n->GetInputPinAt(pinIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id.Get() == 0)
|
||||
{
|
||||
std::cout << "Invalid Id: " << modelNodeId << " input pin: " << pinIndex <<" not found" << std::endl;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
ed::PinId GetOutputPin(const std::string &modelNodeId, int pinIndex)
|
||||
{
|
||||
ed::PinId id = 0;
|
||||
|
||||
for (auto & n : m_nodes)
|
||||
{
|
||||
if (n->Base()->GetId() == modelNodeId)
|
||||
{
|
||||
id = n->GetOutputPinAt(pinIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id.Get() == 0)
|
||||
{
|
||||
std::cout << "Invalid Id: " << modelNodeId << " output pin: " << pinIndex <<" not found" << std::endl;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private:
|
||||
std::string m_uuid;
|
||||
std::string m_name;
|
||||
|
|
|
|||
|
|
@ -75,6 +75,11 @@ void NodeEditorWindow::LoadPage(const std::string &uuid, const std::string &name
|
|||
{
|
||||
// New page
|
||||
page = std::make_shared<NodeEditorPage>(uuid, name);
|
||||
auto storyPage = m_story->GetPage(uuid);
|
||||
if (!storyPage) {
|
||||
storyPage = m_story->CreatePage(uuid);
|
||||
}
|
||||
storyPage->SetName(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -251,14 +256,20 @@ void NodeEditorWindow::SaveNodesToProject()
|
|||
return;
|
||||
}
|
||||
|
||||
// Clear current project structure
|
||||
m_story->Clear();
|
||||
|
||||
// Pour toutes les pages
|
||||
// IMPORTANT: Ne PAS appeler Clear() car cela efface aussi les variables!
|
||||
// Au lieu de cela, on efface seulement les pages
|
||||
for (const auto& page : m_pages)
|
||||
{
|
||||
// Create the page in the project
|
||||
auto currentPage = m_story->CreatePage(page->Uuid());
|
||||
// Récupérer la page correspondante dans le projet
|
||||
auto projectPage = m_story->GetPage(page->Uuid());
|
||||
|
||||
if (!projectPage) {
|
||||
// La page n'existe pas, la créer
|
||||
projectPage = m_story->CreatePage(page->Uuid());
|
||||
} else {
|
||||
// La page existe, vider son contenu (nodes et links)
|
||||
projectPage->Clear();
|
||||
}
|
||||
|
||||
// 1. Save all nodes with their updated positions
|
||||
for (auto &nodeEntry : page->mINF.getNodes())
|
||||
|
|
@ -280,7 +291,7 @@ void NodeEditorWindow::SaveNodesToProject()
|
|||
baseNode->SetPosition(nodePos.x, nodePos.y);
|
||||
|
||||
// Add node to project
|
||||
m_story->AddNode(currentPage->Uuid(), baseNode);
|
||||
m_story->AddNode(projectPage->Uuid(), baseNode);
|
||||
|
||||
std::cout << "Saved node: " << baseNode->GetId()
|
||||
<< " at (" << nodePos.x << ", " << nodePos.y << ")" << std::endl;
|
||||
|
|
@ -369,7 +380,7 @@ void NodeEditorWindow::SaveNodesToProject()
|
|||
connection->inPortIndex = rightPinIndex;
|
||||
|
||||
// Add connection to project
|
||||
m_story->AddConnection(currentPage->Uuid(), connection);
|
||||
m_story->AddConnection(projectPage->Uuid(), connection);
|
||||
|
||||
std::cout << "Saved connection: " << connection->outNodeId
|
||||
<< "[" << connection->outPortIndex << "] -> "
|
||||
|
|
@ -378,7 +389,7 @@ void NodeEditorWindow::SaveNodesToProject()
|
|||
}
|
||||
}
|
||||
|
||||
std::cout << "SaveNodesToProject completed successfully" << std::endl;
|
||||
std::cout << "SaveNodesToProject completed successfully (variables preserved)" << std::endl;
|
||||
}
|
||||
|
||||
void NodeEditorWindow::OpenFunction(const std::string &uuid, const std::string &name)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include <sstream>
|
||||
#include "print_node_widget.h"
|
||||
|
||||
|
|
@ -13,40 +12,55 @@ PrintNodeWidget::PrintNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNod
|
|||
, m_manager(manager)
|
||||
{
|
||||
m_printNode = std::dynamic_pointer_cast<PrintNode>(node);
|
||||
// Create defaut one input and one output
|
||||
// AddInputs(2);
|
||||
// SetInputPinName(0, ">");
|
||||
// SetInputPinName(1, "Argument 1");
|
||||
// AddOutputs(1);
|
||||
// SetOutPinName(0, ">");
|
||||
SetTitle("Print");
|
||||
}
|
||||
|
||||
void PrintNodeWidget::Initialize()
|
||||
{
|
||||
BaseNodeWidget::Initialize();
|
||||
|
||||
// Copy current text to buffer
|
||||
auto text = m_printNode->GetText();
|
||||
if (text.size() < MAX_PRINT_SIZE) {
|
||||
text.copy(m_buffer, text.size());
|
||||
m_buffer[text.size()] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PrintNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
|
||||
{
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Format string:");
|
||||
|
||||
ImGui::PushItemWidth(200.0f);
|
||||
|
||||
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)
|
||||
{
|
||||
// Edit the format string
|
||||
if (ImGui::InputText("##format", m_buffer, sizeof(m_buffer))) {
|
||||
m_printNode->SetText(m_buffer);
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
// Show help text
|
||||
ImGui::TextDisabled("Use {0}, {1}, {2}, {3} for arguments");
|
||||
|
||||
// Display current text
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Preview: %s", m_printNode->GetText().c_str());
|
||||
}
|
||||
|
||||
void PrintNodeWidget::Draw()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Display format string in the node body
|
||||
std::string displayText = m_printNode->GetText();
|
||||
if (displayText.empty()) {
|
||||
displayText = "<empty>";
|
||||
}
|
||||
|
||||
// Truncate if too long
|
||||
if (displayText.length() > 30) {
|
||||
displayText = displayText.substr(0, 27) + "...";
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted(displayText.c_str());
|
||||
}
|
||||
|
|
@ -10,17 +10,15 @@
|
|||
#include "i_story_project.h"
|
||||
#include "gui.h"
|
||||
#include "print_node.h"
|
||||
#include "media_node.h"
|
||||
|
||||
class PrintNodeWidget : public BaseNodeWidget
|
||||
{
|
||||
public:
|
||||
|
||||
static const int MAX_PRINT_SIZE = 128;
|
||||
static const int MAX_PRINT_SIZE = 256;
|
||||
|
||||
PrintNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
|
||||
|
||||
void Draw() override;
|
||||
|
||||
virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override;
|
||||
virtual void Initialize() override;
|
||||
|
||||
|
|
@ -29,4 +27,4 @@ private:
|
|||
std::shared_ptr<PrintNode> m_printNode;
|
||||
|
||||
static char m_buffer[MAX_PRINT_SIZE];
|
||||
};
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include <sstream>
|
||||
#include "variable_node_widget.h"
|
||||
|
||||
|
|
@ -17,17 +16,16 @@ VariableNodeWidget::VariableNodeWidget(IStoryManager &manager, std::shared_ptr<B
|
|||
void VariableNodeWidget::Initialize()
|
||||
{
|
||||
BaseNodeWidget::Initialize();
|
||||
|
||||
m_selectedVariableUuid = m_variableNode->GetVariableUuid();
|
||||
}
|
||||
|
||||
|
||||
void VariableNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
|
||||
{
|
||||
// Initialize variable name from UUID on first call
|
||||
if (!m_isInitialized)
|
||||
{
|
||||
m_isInitialized = true;
|
||||
story->ScanVariable([this] (std::shared_ptr<Variable> var) {
|
||||
story->ScanVariable([this](std::shared_ptr<Variable> var) {
|
||||
if (var->GetUuid() == m_selectedVariableUuid)
|
||||
{
|
||||
m_selectedVariableName = var->GetVariableName();
|
||||
|
|
@ -36,39 +34,51 @@ void VariableNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
|
|||
}
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Variable:");
|
||||
|
||||
static ImGuiComboFlags flags = 0;
|
||||
|
||||
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
||||
|
||||
if (ImGui::BeginCombo("Variables list", m_selectedVariableName.c_str(), flags))
|
||||
if (ImGui::BeginCombo("##variables", m_selectedVariableName.c_str(), flags))
|
||||
{
|
||||
int i = 0;
|
||||
story->ScanVariable([&i, this] (std::shared_ptr<Variable> var) {
|
||||
|
||||
// ImGui::PushID(static_cast<int>(i)); // Assure l'unicité des widgets
|
||||
|
||||
story->ScanVariable([&i, this](std::shared_ptr<Variable> var) {
|
||||
const bool is_selected = (m_selectedIndex == i);
|
||||
std::string l = var->GetVariableName();
|
||||
if (ImGui::Selectable(l.c_str(), is_selected))
|
||||
std::string label = var->GetVariableName();
|
||||
|
||||
if (ImGui::Selectable(label.c_str(), is_selected))
|
||||
{
|
||||
m_selectedIndex = i;
|
||||
m_selectedVariableName = l;
|
||||
m_selectedVariableName = label;
|
||||
m_variableNode->SetVariableUuid(var->GetUuid());
|
||||
m_variableNode->SetVariable(var);
|
||||
SetTitle(label);
|
||||
}
|
||||
|
||||
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
|
||||
if (is_selected)
|
||||
// Set the initial focus when opening the combo
|
||||
if (is_selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
||||
i++;
|
||||
});
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
|
||||
// Show variable details if selected
|
||||
if (!m_selectedVariableUuid.empty()) {
|
||||
ImGui::Separator();
|
||||
story->ScanVariable([this](std::shared_ptr<Variable> var) {
|
||||
if (var->GetUuid() == m_selectedVariableUuid) {
|
||||
ImGui::Text("Type: %s", Variable::ValueTypeToString(var->GetValueType()).c_str());
|
||||
ImGui::Text("Value: %s", var->GetValueAsString().c_str());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void VariableNodeWidget::Draw()
|
||||
{
|
||||
// Display variable name in the node
|
||||
ImGui::TextUnformatted(m_selectedVariableName.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@
|
|||
#include "i_story_project.h"
|
||||
#include "gui.h"
|
||||
#include "variable_node.h"
|
||||
#include "media_node.h"
|
||||
|
||||
class VariableNodeWidget : public BaseNodeWidget
|
||||
{
|
||||
|
|
@ -18,7 +17,6 @@ public:
|
|||
VariableNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
|
||||
|
||||
void Draw() override;
|
||||
|
||||
virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override;
|
||||
virtual void Initialize() override;
|
||||
|
||||
|
|
@ -28,5 +26,5 @@ private:
|
|||
std::shared_ptr<VariableNode> m_variableNode;
|
||||
int m_selectedIndex{-1};
|
||||
std::string m_selectedVariableUuid;
|
||||
std::string m_selectedVariableName;
|
||||
};
|
||||
std::string m_selectedVariableName{"<none>"};
|
||||
};
|
||||
Loading…
Reference in a new issue