Add error list dock window, cleaned some nodes

This commit is contained in:
anthony@rabine.fr 2025-10-02 14:10:50 +02:00
parent 8111f0a362
commit 3e00fb1c83
20 changed files with 399 additions and 121 deletions

View file

@ -7,7 +7,7 @@
PrintNode::PrintNode(const std::string &type) PrintNode::PrintNode(const std::string &type)
: BaseNode(type, "Print Node") : 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); auto v = std::make_shared<Variable>(m_label);
v->SetConstant(true); v->SetConstant(true);
m_label = v->GetLabel(); m_label = v->GetLabel();
@ -15,6 +15,17 @@ PrintNode::PrintNode(const std::string &type)
SetBehavior(BaseNode::BEHAVIOR_EXECUTION); SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
// Add execution input port (sync)
AddInputPort(Port::EXECUTION_PORT, ">");
// 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));
}
// Add execution output port
AddOutputPort(Port::EXECUTION_PORT, ">");
SetText(""); SetText("");
} }
@ -24,11 +35,9 @@ void PrintNode::Initialize()
m_variables.at(m_label)->SetTextValue(j["text"].get<std::string>()); m_variables.at(m_label)->SetTextValue(j["text"].get<std::string>());
} }
void PrintNode::SetText(const std::string &text) void PrintNode::SetText(const std::string &text)
{ {
m_variables.at(m_label)->SetValue<std::string>(text); m_variables.at(m_label)->SetValue<std::string>(text);
SetInternalData({{"text", text}}); SetInternalData({{"text", text}});
} }
@ -41,4 +50,3 @@ std::string PrintNode::GetText() const
{ {
return m_variables.at(m_label)->GetValue<std::string>(); return m_variables.at(m_label)->GetValue<std::string>();
} }

View file

@ -17,8 +17,8 @@ public:
std::string GetLabel() const; std::string GetLabel() const;
std::string GetText() const; std::string GetText() const;
static constexpr int MAX_INPUT_COUNT = 4;
private: private:
std::string m_label; // Label for the string literal std::string m_label; // Label for the string literal
uint32_t m_arguments{0}; // number of arguments
}; };

View file

@ -3,19 +3,19 @@
#include "connection.h" #include "connection.h"
#include "sys_lib.h" #include "sys_lib.h"
VariableNode::VariableNode(const std::string &type) VariableNode::VariableNode(const std::string &type)
: BaseNode(type, "Variable Node") : BaseNode(type, "Variable Node", BaseNode::BEHAVIOR_DATA)
{ {
nlohmann::json j{ {"uuid", ""} }; nlohmann::json j{ {"uuid", ""} };
SetInternalData(j); SetInternalData(j);
SetBehavior(BaseNode::BEHAVIOR_DATA);
// Add data output port
AddOutputPort(Port::DATA_PORT, "value");
} }
void VariableNode::Initialize() void VariableNode::Initialize()
{ {
nlohmann::json j = GetInternalData(); nlohmann::json j = GetInternalData();
m_variableUuid = j["uuid"].get<std::string>(); m_variableUuid = j["uuid"].get<std::string>();
} }
@ -33,5 +33,16 @@ std::string VariableNode::GetVariableUuid() const
return m_variableUuid; 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;
}

View file

@ -1,27 +1,26 @@
#pragma once #pragma once
#include <string> #include <string>
#include "variable.h"
#include "i_story_manager.h" #include "i_story_manager.h"
#include "base_node.h" #include "base_node.h"
#include "i_script_node.h" #include "i_script_node.h"
#include "i_story_project.h" #include "i_story_project.h"
#include "variable.h"
class VariableNode : public BaseNode class VariableNode : public BaseNode
{ {
public: public:
VariableNode(const std::string &type);
VariableNode(const std::string &type = "variable-node");
virtual void Initialize() override; virtual void Initialize() override;
void SetVariableUuid(const std::string &uuid); void SetVariableUuid(const std::string &uuid);
std::string GetVariableUuid() const; std::string GetVariableUuid() const;
void SetVariable(std::shared_ptr<Variable> var);
std::shared_ptr<Variable> GetVariable() const;
private: private:
std::string m_variableUuid; std::string m_variableUuid;
std::shared_ptr<Variable> m_variable;
}; };

View file

@ -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) for (const auto & p : m_pages)
{ {

View file

@ -102,7 +102,7 @@ public:
// Node interaction // Node interaction
std::shared_ptr<StoryPage> CreatePage(const std::string_view uuid); 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 AddNode(const std::string_view &page, std::shared_ptr<BaseNode> node);
void AddConnection(const std::string_view &page, std::shared_ptr<Connection> c); void AddConnection(const std::string_view &page, std::shared_ptr<Connection> c);

View file

@ -147,6 +147,21 @@ public:
return GetValue<bool>(); 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>; using VariableValue = std::variant<int, float, bool, std::string>;
std::string GetUuid() const { std::string GetUuid() const {

View file

@ -138,6 +138,7 @@ set(SRCS
## Docks ## Docks
src/docks/emulator_dock.cpp src/docks/emulator_dock.cpp
src/docks/resources_dock.cpp src/docks/resources_dock.cpp
src/docks/error_list_dock.cpp
# src/node_editor/media_node_widget.cpp # src/node_editor/media_node_widget.cpp
src/node_editor/base_node_widget.cpp src/node_editor/base_node_widget.cpp

View file

@ -9,32 +9,32 @@ Size=400,400
Collapsed=0 Collapsed=0
[Window][Library Manager] [Window][Library Manager]
Pos=435,26 Pos=656,26
Size=845,388 Size=624,313
Collapsed=0 Collapsed=0
DockId=0x00000003,0 DockId=0x00000003,0
[Window][Console] [Window][Console]
Pos=60,450 Pos=60,450
Size=610,270 Size=475,270
Collapsed=0 Collapsed=0
DockId=0x00000004,0 DockId=0x00000004,0
[Window][Emulator] [Window][Emulator]
Pos=435,26 Pos=656,26
Size=845,388 Size=624,313
Collapsed=0 Collapsed=0
DockId=0x00000003,5 DockId=0x00000003,5
[Window][Code viewer] [Window][Code viewer]
Pos=435,26 Pos=656,26
Size=845,388 Size=624,313
Collapsed=0 Collapsed=0
DockId=0x00000003,4 DockId=0x00000003,4
[Window][Resources] [Window][Resources]
Pos=435,26 Pos=656,26
Size=845,388 Size=624,313
Collapsed=0 Collapsed=0
DockId=0x00000003,1 DockId=0x00000003,1
@ -50,26 +50,26 @@ Size=150,42
Collapsed=0 Collapsed=0
[Window][Variables] [Window][Variables]
Pos=672,450 Pos=537,450
Size=608,270 Size=743,270
Collapsed=0 Collapsed=0
DockId=0x00000005,0 DockId=0x00000005,0
[Window][CPU] [Window][CPU]
Pos=435,26 Pos=656,26
Size=845,388 Size=624,313
Collapsed=0 Collapsed=0
DockId=0x00000003,2 DockId=0x00000003,2
[Window][RAM view] [Window][RAM view]
Pos=435,26 Pos=656,26
Size=845,388 Size=624,313
Collapsed=0 Collapsed=0
DockId=0x00000003,3 DockId=0x00000003,3
[Window][Properties] [Window][Properties]
Pos=435,416 Pos=656,341
Size=845,32 Size=624,107
Collapsed=0 Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
@ -90,13 +90,13 @@ Collapsed=0
[Window][Module editor] [Window][Module editor]
Pos=60,26 Pos=60,26
Size=373,422 Size=594,422
Collapsed=0 Collapsed=0
DockId=0x00000001,0 DockId=0x00000001,0
[Window][Story editor] [Window][Story editor]
Pos=60,26 Pos=60,26
Size=373,422 Size=594,422
Collapsed=0 Collapsed=0
DockId=0x00000001,1 DockId=0x00000001,1
@ -105,6 +105,12 @@ Pos=490,260
Size=687,422 Size=687,422
Collapsed=0 Collapsed=0
[Window][Error List]
Pos=60,450
Size=475,270
Collapsed=0
DockId=0x00000004,1
[Table][0x7728942D,5] [Table][0x7728942D,5]
RefScale=20 RefScale=20
Column 0 Width=44 Sort=0v Column 0 Width=44 Sort=0v
@ -144,11 +150,11 @@ Column 0 Sort=0v
[Docking][Data] [Docking][Data]
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y 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=0x00000007 Parent=0x08BD597D SizeRef=1220,422 Split=X
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=373,694 CentralNode=1 Selected=0x93ADCAAB DockNode ID=0x00000001 Parent=0x00000007 SizeRef=790,694 CentralNode=1 Selected=0x93ADCAAB
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=845,694 Split=Y Selected=0x52EB28B5 DockNode ID=0x00000002 Parent=0x00000007 SizeRef=624,694 Split=Y Selected=0x52EB28B5
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,388 Selected=0x63869CAF DockNode ID=0x00000003 Parent=0x00000002 SizeRef=718,476 Selected=0x63869CAF
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,32 Selected=0x8C72BEA8 DockNode ID=0x00000006 Parent=0x00000002 SizeRef=718,163 Selected=0x8C72BEA8
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,270 Split=X Selected=0xEA83D666 DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,270 Split=X Selected=0xEA83D666
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=610,192 Selected=0xEA83D666 DockNode ID=0x00000004 Parent=0x00000008 SizeRef=475,192 Selected=0xD246D6BE
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=608,192 Selected=0x6DE9B20C DockNode ID=0x00000005 Parent=0x00000008 SizeRef=743,192 Selected=0x6DE9B20C

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

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

View file

@ -664,16 +664,16 @@ void Gui::ApplyTheme()
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
// ===== AMÉLIORATION DES ONGLETS ===== // ===== AMÉLIORATION DES ONGLETS =====
// Onglet inactif (non sélectionné) // Onglet inactif (non sélectionné) - TRÈS FONCÉ
colors[ImGuiCol_Tab] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f); colors[ImGuiCol_Tab] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f);
// Onglet survolé // Onglet survolé
colors[ImGuiCol_TabHovered] = ImVec4(0.25f, 0.60f, 0.80f, 1.00f); 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); colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.65f, 0.85f, 1.00f);
// Onglet inactif dans une fenêtre non-focusée // Onglet inactif dans une fenêtre non-focusée - TRÈS FONCÉ
colors[ImGuiCol_TabUnfocused] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); colors[ImGuiCol_TabUnfocused] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f);
// Onglet actif dans une fenêtre non-focusée // Onglet actif dans une fenêtre non-focusée - BEAUCOUP PLUS FONCÉ
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.18f, 0.45f, 0.60f, 1.00f); 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_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 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.PopupRounding = 2.0f;
style.ScrollbarRounding = 12.0f; style.ScrollbarRounding = 12.0f;
style.ScrollbarSize = 13.0f; style.ScrollbarSize = 13.0f;
style.TabBorderSize = 0.0f; // Pas de bordure autour des onglets style.TabBorderSize = 0.0f;
style.TabRounding = 4.0f; // Coins arrondis pour les onglets style.TabRounding = 4.0f;
style.WindowRounding = 4.0f; style.WindowRounding = 4.0f;
} }

View file

@ -12,7 +12,8 @@
enum ToastType { enum ToastType {
Success, Success,
Warning, Warning,
Error Error,
Info
}; };
struct Toast { struct Toast {
@ -26,7 +27,7 @@ struct Toast {
class ImGuiToastNotifier { class ImGuiToastNotifier {
private: private:
std::vector<Toast> toasts; std::vector<Toast> toasts;
const float TOAST_WIDTH = 300.0f; const float TOAST_WIDTH = 350.0f;
const float TOAST_PADDING = 10.0f; const float TOAST_PADDING = 10.0f;
public: public:
@ -34,12 +35,43 @@ public:
toasts.push_back({title, text, type, std::chrono::steady_clock::now(), duration}); 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() { void render() {
if (toasts.empty()) { if (toasts.empty()) {
return; return;
} }
// Get the main viewport work area (excludes menu bar, status bar, etc.) // Get the main viewport work area
ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGuiViewport* viewport = ImGui::GetMainViewport();
ImVec2 work_pos = viewport->WorkPos; ImVec2 work_pos = viewport->WorkPos;
ImVec2 work_size = viewport->WorkSize; ImVec2 work_size = viewport->WorkSize;
@ -54,7 +86,6 @@ public:
ImGui::SetNextWindowSize(ImVec2(TOAST_WIDTH, 0), ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2(TOAST_WIDTH, 0), ImGuiCond_Always);
ImGui::SetNextWindowBgAlpha(0.90f); ImGui::SetNextWindowBgAlpha(0.90f);
// Add NoNav to prevent interfering with other windows
ImGuiWindowFlags window_flags = ImGuiWindowFlags window_flags =
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoMove |
@ -103,6 +134,10 @@ public:
color = ImVec4(0.94f, 0.31f, 0.31f, 1.0f); color = ImVec4(0.94f, 0.31f, 0.31f, 1.0f);
icon = ICON_FA_TIMES_CIRCLE; icon = ICON_FA_TIMES_CIRCLE;
break; 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 // Draw icon and title on the same line
@ -111,13 +146,13 @@ public:
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); // Use default font for title ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]);
ImGui::TextUnformatted(it->title.c_str()); ImGui::Text("%s", it->title.c_str());
ImGui::PopFont(); ImGui::PopFont();
// Draw message text with wrapping // Draw message text with wrapping
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + TOAST_WIDTH - 24.0f); 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::PopTextWrapPos();
ImGui::PopStyleVar(); // Alpha ImGui::PopStyleVar(); // Alpha

View file

@ -517,6 +517,7 @@ bool MainWindow::Loop()
// ------------ Draw all windows // ------------ Draw all windows
m_libraryWindow.Draw(); m_libraryWindow.Draw();
m_errorListDock.Draw();
if (m_appController.IsLibraryManagerInitialized()) if (m_appController.IsLibraryManagerInitialized())
{ {

View file

@ -11,6 +11,7 @@
#include "debugger_window.h" #include "debugger_window.h"
#include "emulator_dock.h" #include "emulator_dock.h"
#include "resources_dock.h" #include "resources_dock.h"
#include "error_list_dock.h"
#include "node_editor_window.h" #include "node_editor_window.h"
#include "properties_window.h" #include "properties_window.h"
#include "variables_window.h" #include "variables_window.h"
@ -50,6 +51,7 @@ private:
Gui m_gui; Gui m_gui;
EmulatorDock m_emulatorDock; EmulatorDock m_emulatorDock;
ErrorListDock m_errorListDock;
ConsoleWindow m_consoleWindow; ConsoleWindow m_consoleWindow;
DebuggerWindow m_debuggerWindow; DebuggerWindow m_debuggerWindow;
CpuWindow m_cpuWindow; CpuWindow m_cpuWindow;

View file

@ -251,14 +251,20 @@ void NodeEditorWindow::SaveNodesToProject()
return; return;
} }
// Clear current project structure // IMPORTANT: Ne PAS appeler Clear() car cela efface aussi les variables!
m_story->Clear(); // Au lieu de cela, on efface seulement les pages
// Pour toutes les pages
for (const auto& page : m_pages) for (const auto& page : m_pages)
{ {
// Create the page in the project // Récupérer la page correspondante dans le projet
auto currentPage = m_story->CreatePage(page->Uuid()); 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 // 1. Save all nodes with their updated positions
for (auto &nodeEntry : page->mINF.getNodes()) for (auto &nodeEntry : page->mINF.getNodes())
@ -280,7 +286,7 @@ void NodeEditorWindow::SaveNodesToProject()
baseNode->SetPosition(nodePos.x, nodePos.y); baseNode->SetPosition(nodePos.x, nodePos.y);
// Add node to project // Add node to project
m_story->AddNode(currentPage->Uuid(), baseNode); m_story->AddNode(projectPage->Uuid(), baseNode);
std::cout << "Saved node: " << baseNode->GetId() std::cout << "Saved node: " << baseNode->GetId()
<< " at (" << nodePos.x << ", " << nodePos.y << ")" << std::endl; << " at (" << nodePos.x << ", " << nodePos.y << ")" << std::endl;
@ -369,7 +375,7 @@ void NodeEditorWindow::SaveNodesToProject()
connection->inPortIndex = rightPinIndex; connection->inPortIndex = rightPinIndex;
// Add connection to project // Add connection to project
m_story->AddConnection(currentPage->Uuid(), connection); m_story->AddConnection(projectPage->Uuid(), connection);
std::cout << "Saved connection: " << connection->outNodeId std::cout << "Saved connection: " << connection->outNodeId
<< "[" << connection->outPortIndex << "] -> " << "[" << connection->outPortIndex << "] -> "
@ -378,7 +384,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) void NodeEditorWindow::OpenFunction(const std::string &uuid, const std::string &name)

View file

@ -1,4 +1,3 @@
#include <sstream> #include <sstream>
#include "print_node_widget.h" #include "print_node_widget.h"
@ -13,40 +12,55 @@ PrintNodeWidget::PrintNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNod
, m_manager(manager) , m_manager(manager)
{ {
m_printNode = std::dynamic_pointer_cast<PrintNode>(node); m_printNode = std::dynamic_pointer_cast<PrintNode>(node);
// Create defaut one input and one output SetTitle("Print");
// AddInputs(2);
// SetInputPinName(0, ">");
// SetInputPinName(1, "Argument 1");
// AddOutputs(1);
// SetOutPinName(0, ">");
} }
void PrintNodeWidget::Initialize() void PrintNodeWidget::Initialize()
{ {
BaseNodeWidget::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) void PrintNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
{ {
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
ImGui::Text("Format string:");
ImGui::PushItemWidth(100.0f); ImGui::PushItemWidth(200.0f);
auto t = m_printNode->GetText(); // Edit the format string
t.copy(m_buffer, sizeof(m_buffer) - 1); if (ImGui::InputText("##format", m_buffer, sizeof(m_buffer))) {
bool edited = ImGui::InputText("##edit", m_buffer, sizeof(m_buffer), ImGuiInputTextFlags_EnterReturnsTrue);
// if (edited)
{
m_printNode->SetText(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() 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());
} }

View file

@ -10,17 +10,15 @@
#include "i_story_project.h" #include "i_story_project.h"
#include "gui.h" #include "gui.h"
#include "print_node.h" #include "print_node.h"
#include "media_node.h"
class PrintNodeWidget : public BaseNodeWidget class PrintNodeWidget : public BaseNodeWidget
{ {
public: public:
static const int MAX_PRINT_SIZE = 256;
static const int MAX_PRINT_SIZE = 128;
PrintNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node); PrintNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
void Draw() override; void Draw() override;
virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override; virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override;
virtual void Initialize() override; virtual void Initialize() override;

View file

@ -1,4 +1,3 @@
#include <sstream> #include <sstream>
#include "variable_node_widget.h" #include "variable_node_widget.h"
@ -17,17 +16,16 @@ VariableNodeWidget::VariableNodeWidget(IStoryManager &manager, std::shared_ptr<B
void VariableNodeWidget::Initialize() void VariableNodeWidget::Initialize()
{ {
BaseNodeWidget::Initialize(); BaseNodeWidget::Initialize();
m_selectedVariableUuid = m_variableNode->GetVariableUuid(); m_selectedVariableUuid = m_variableNode->GetVariableUuid();
} }
void VariableNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story) void VariableNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
{ {
// Initialize variable name from UUID on first call
if (!m_isInitialized) if (!m_isInitialized)
{ {
m_isInitialized = true; m_isInitialized = true;
story->ScanVariable([this] (std::shared_ptr<Variable> var) { story->ScanVariable([this](std::shared_ptr<Variable> var) {
if (var->GetUuid() == m_selectedVariableUuid) if (var->GetUuid() == m_selectedVariableUuid)
{ {
m_selectedVariableName = var->GetVariableName(); m_selectedVariableName = var->GetVariableName();
@ -36,39 +34,51 @@ void VariableNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
} }
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
static ImGuiComboFlags flags = 0; ImGui::Text("Variable:");
static ImGuiComboFlags flags = 0;
ImGui::SetNextItemOpen(true, ImGuiCond_Once); 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; int i = 0;
story->ScanVariable([&i, this] (std::shared_ptr<Variable> var) { story->ScanVariable([&i, this](std::shared_ptr<Variable> var) {
// ImGui::PushID(static_cast<int>(i)); // Assure l'unicité des widgets
const bool is_selected = (m_selectedIndex == i); const bool is_selected = (m_selectedIndex == i);
std::string l = var->GetVariableName(); std::string label = var->GetVariableName();
if (ImGui::Selectable(l.c_str(), is_selected))
if (ImGui::Selectable(label.c_str(), is_selected))
{ {
m_selectedIndex = i; m_selectedIndex = i;
m_selectedVariableName = l; m_selectedVariableName = label;
m_variableNode->SetVariableUuid(var->GetUuid()); m_variableNode->SetVariableUuid(var->GetUuid());
m_variableNode->SetVariable(var);
SetTitle(label);
} }
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus) // Set the initial focus when opening the combo
if (is_selected) if (is_selected) {
ImGui::SetItemDefaultFocus(); ImGui::SetItemDefaultFocus();
}
i++; i++;
}); });
ImGui::EndCombo(); 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() void VariableNodeWidget::Draw()
{ {
// Display variable name in the node
ImGui::TextUnformatted(m_selectedVariableName.c_str()); ImGui::TextUnformatted(m_selectedVariableName.c_str());
} }

View file

@ -10,7 +10,6 @@
#include "i_story_project.h" #include "i_story_project.h"
#include "gui.h" #include "gui.h"
#include "variable_node.h" #include "variable_node.h"
#include "media_node.h"
class VariableNodeWidget : public BaseNodeWidget class VariableNodeWidget : public BaseNodeWidget
{ {
@ -18,7 +17,6 @@ public:
VariableNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node); VariableNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
void Draw() override; void Draw() override;
virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override; virtual void DrawProperties(std::shared_ptr<IStoryProject> story) override;
virtual void Initialize() override; virtual void Initialize() override;
@ -28,5 +26,5 @@ private:
std::shared_ptr<VariableNode> m_variableNode; std::shared_ptr<VariableNode> m_variableNode;
int m_selectedIndex{-1}; int m_selectedIndex{-1};
std::string m_selectedVariableUuid; std::string m_selectedVariableUuid;
std::string m_selectedVariableName; std::string m_selectedVariableName{"<none>"};
}; };