From 3e00fb1c8354c0be255429a5a5c8644d6bbcab2e Mon Sep 17 00:00:00 2001 From: "anthony@rabine.fr" Date: Thu, 2 Oct 2025 14:10:50 +0200 Subject: [PATCH] Add error list dock window, cleaned some nodes --- core/story-manager/src/nodes/print_node.cpp | 18 +++- core/story-manager/src/nodes/print_node.h | 6 +- .../story-manager/src/nodes/variable_node.cpp | 21 +++- core/story-manager/src/nodes/variable_node.h | 15 ++- core/story-manager/src/story_project.cpp | 2 +- core/story-manager/src/story_project.h | 2 +- core/story-manager/src/variable.h | 15 +++ story-editor/CMakeLists.txt | 1 + story-editor/imgui.ini | 56 ++++++----- story-editor/src/docks/error_list_dock.cpp | 99 +++++++++++++++++++ story-editor/src/docks/error_list_dock.h | 75 ++++++++++++++ story-editor/src/gui.cpp | 18 ++-- story-editor/src/imgui_toast_notifier.h | 49 +++++++-- story-editor/src/main_window.cpp | 1 + story-editor/src/main_window.h | 2 + .../src/node_editor/node_editor_window.cpp | 24 +++-- .../src/node_editor/print_node_widget.cpp | 56 +++++++---- .../src/node_editor/print_node_widget.h | 8 +- .../src/node_editor/variable_node_widget.cpp | 46 +++++---- .../src/node_editor/variable_node_widget.h | 6 +- 20 files changed, 399 insertions(+), 121 deletions(-) create mode 100644 story-editor/src/docks/error_list_dock.cpp create mode 100644 story-editor/src/docks/error_list_dock.h diff --git a/core/story-manager/src/nodes/print_node.cpp b/core/story-manager/src/nodes/print_node.cpp index dc8620f..324b395 100644 --- a/core/story-manager/src/nodes/print_node.cpp +++ b/core/story-manager/src/nodes/print_node.cpp @@ -7,7 +7,7 @@ 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(m_label); v->SetConstant(true); m_label = v->GetLabel(); @@ -15,6 +15,17 @@ PrintNode::PrintNode(const std::string &type) 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(""); } @@ -24,11 +35,9 @@ void PrintNode::Initialize() m_variables.at(m_label)->SetTextValue(j["text"].get()); } - void PrintNode::SetText(const std::string &text) { m_variables.at(m_label)->SetValue(text); - SetInternalData({{"text", text}}); } @@ -40,5 +49,4 @@ std::string PrintNode::GetLabel() const std::string PrintNode::GetText() const { return m_variables.at(m_label)->GetValue(); -} - +} \ No newline at end of file diff --git a/core/story-manager/src/nodes/print_node.h b/core/story-manager/src/nodes/print_node.h index 36df5e8..1bbab04 100644 --- a/core/story-manager/src/nodes/print_node.h +++ b/core/story-manager/src/nodes/print_node.h @@ -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 -}; - +}; \ No newline at end of file diff --git a/core/story-manager/src/nodes/variable_node.cpp b/core/story-manager/src/nodes/variable_node.cpp index 5830942..d9f0436 100644 --- a/core/story-manager/src/nodes/variable_node.cpp +++ b/core/story-manager/src/nodes/variable_node.cpp @@ -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(); } @@ -33,5 +33,16 @@ std::string VariableNode::GetVariableUuid() const return m_variableUuid; } +void VariableNode::SetVariable(std::shared_ptr var) +{ + m_variable = var; + if (var) { + SetVariableUuid(var->GetUuid()); + SetTitle(var->GetLabel()); + } +} - +std::shared_ptr VariableNode::GetVariable() const +{ + return m_variable; +} \ No newline at end of file diff --git a/core/story-manager/src/nodes/variable_node.h b/core/story-manager/src/nodes/variable_node.h index 60b6434..fcd7948 100644 --- a/core/story-manager/src/nodes/variable_node.h +++ b/core/story-manager/src/nodes/variable_node.h @@ -1,27 +1,26 @@ #pragma once #include - -#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 var); + std::shared_ptr GetVariable() const; private: std::string m_variableUuid; - -}; - + std::shared_ptr m_variable; +}; \ No newline at end of file diff --git a/core/story-manager/src/story_project.cpp b/core/story-manager/src/story_project.cpp index f96b4f7..6e5a39d 100644 --- a/core/story-manager/src/story_project.cpp +++ b/core/story-manager/src/story_project.cpp @@ -179,7 +179,7 @@ void StoryProject::DeleteNode(const std::string_view &page_uuid, const std::stri } } -std::shared_ptr StoryProject::GetPage(const std::string &uuid) +std::shared_ptr StoryProject::GetPage(const std::string_view &uuid) { for (const auto & p : m_pages) { diff --git a/core/story-manager/src/story_project.h b/core/story-manager/src/story_project.h index ff3ad43..a4247a6 100644 --- a/core/story-manager/src/story_project.h +++ b/core/story-manager/src/story_project.h @@ -102,7 +102,7 @@ public: // Node interaction std::shared_ptr CreatePage(const std::string_view uuid); - std::shared_ptr GetPage(const std::string &uuid); + std::shared_ptr GetPage(const std::string_view &uuid); void AddNode(const std::string_view &page, std::shared_ptr node); void AddConnection(const std::string_view &page, std::shared_ptr c); diff --git a/core/story-manager/src/variable.h b/core/story-manager/src/variable.h index 425dcdd..2da3587 100644 --- a/core/story-manager/src/variable.h +++ b/core/story-manager/src/variable.h @@ -147,6 +147,21 @@ public: return GetValue(); } + std::string GetValueAsString() const { + switch (m_valueType) { + case ValueType::INTEGER: + return std::to_string(GetValue()); + case ValueType::FLOAT: + return std::to_string(GetValue()); + case ValueType::BOOL: + return GetValue() ? "true" : "false"; + case ValueType::STRING: + return GetValue(); + default: + return ""; + } + } + using VariableValue = std::variant; std::string GetUuid() const { diff --git a/story-editor/CMakeLists.txt b/story-editor/CMakeLists.txt index 60794cd..a949c92 100644 --- a/story-editor/CMakeLists.txt +++ b/story-editor/CMakeLists.txt @@ -138,6 +138,7 @@ 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 diff --git a/story-editor/imgui.ini b/story-editor/imgui.ini index 5add485..3bd7b69 100644 --- a/story-editor/imgui.ini +++ b/story-editor/imgui.ini @@ -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 diff --git a/story-editor/src/docks/error_list_dock.cpp b/story-editor/src/docks/error_list_dock.cpp new file mode 100644 index 0000000..e2134f9 --- /dev/null +++ b/story-editor/src/docks/error_list_dock.cpp @@ -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(); +} \ No newline at end of file diff --git a/story-editor/src/docks/error_list_dock.h b/story-editor/src/docks/error_list_dock.h new file mode 100644 index 0000000..8fd8aac --- /dev/null +++ b/story-editor/src/docks/error_list_dock.h @@ -0,0 +1,75 @@ +#pragma once + +#include "window_base.h" +#include "IconsFontAwesome5_c.h" +#include +#include +#include + +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 m_errors; +}; \ No newline at end of file diff --git a/story-editor/src/gui.cpp b/story-editor/src/gui.cpp index ab90b25..274c0b8 100644 --- a/story-editor/src/gui.cpp +++ b/story-editor/src/gui.cpp @@ -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; } diff --git a/story-editor/src/imgui_toast_notifier.h b/story-editor/src/imgui_toast_notifier.h index b7ac0a8..5e0a239 100644 --- a/story-editor/src/imgui_toast_notifier.h +++ b/story-editor/src/imgui_toast_notifier.h @@ -12,7 +12,8 @@ enum ToastType { Success, Warning, - Error + Error, + Info }; struct Toast { @@ -26,7 +27,7 @@ struct Toast { class ImGuiToastNotifier { private: std::vector 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 diff --git a/story-editor/src/main_window.cpp b/story-editor/src/main_window.cpp index 870eb9b..83af3f6 100644 --- a/story-editor/src/main_window.cpp +++ b/story-editor/src/main_window.cpp @@ -517,6 +517,7 @@ bool MainWindow::Loop() // ------------ Draw all windows m_libraryWindow.Draw(); + m_errorListDock.Draw(); if (m_appController.IsLibraryManagerInitialized()) { diff --git a/story-editor/src/main_window.h b/story-editor/src/main_window.h index 66410fe..2f5b600 100644 --- a/story-editor/src/main_window.h +++ b/story-editor/src/main_window.h @@ -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; diff --git a/story-editor/src/node_editor/node_editor_window.cpp b/story-editor/src/node_editor/node_editor_window.cpp index 684ff5f..eb36a0d 100644 --- a/story-editor/src/node_editor/node_editor_window.cpp +++ b/story-editor/src/node_editor/node_editor_window.cpp @@ -251,14 +251,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 +286,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 +375,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 +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) diff --git a/story-editor/src/node_editor/print_node_widget.cpp b/story-editor/src/node_editor/print_node_widget.cpp index e43e7eb..bd5a532 100644 --- a/story-editor/src/node_editor/print_node_widget.cpp +++ b/story-editor/src/node_editor/print_node_widget.cpp @@ -1,4 +1,3 @@ - #include #include "print_node_widget.h" @@ -13,40 +12,55 @@ PrintNodeWidget::PrintNodeWidget(IStoryManager &manager, std::shared_ptr(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 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 = ""; + } + + // Truncate if too long + if (displayText.length() > 30) { + displayText = displayText.substr(0, 27) + "..."; + } + + ImGui::TextUnformatted(displayText.c_str()); +} \ No newline at end of file diff --git a/story-editor/src/node_editor/print_node_widget.h b/story-editor/src/node_editor/print_node_widget.h index f3f00f7..7295bfe 100644 --- a/story-editor/src/node_editor/print_node_widget.h +++ b/story-editor/src/node_editor/print_node_widget.h @@ -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 node); void Draw() override; - virtual void DrawProperties(std::shared_ptr story) override; virtual void Initialize() override; @@ -29,4 +27,4 @@ private: std::shared_ptr m_printNode; static char m_buffer[MAX_PRINT_SIZE]; -}; +}; \ No newline at end of file diff --git a/story-editor/src/node_editor/variable_node_widget.cpp b/story-editor/src/node_editor/variable_node_widget.cpp index a7c580b..2f8f8bd 100644 --- a/story-editor/src/node_editor/variable_node_widget.cpp +++ b/story-editor/src/node_editor/variable_node_widget.cpp @@ -1,4 +1,3 @@ - #include #include "variable_node_widget.h" @@ -17,17 +16,16 @@ VariableNodeWidget::VariableNodeWidget(IStoryManager &manager, std::shared_ptrGetVariableUuid(); } - void VariableNodeWidget::DrawProperties(std::shared_ptr story) { + // Initialize variable name from UUID on first call if (!m_isInitialized) { m_isInitialized = true; - story->ScanVariable([this] (std::shared_ptr var) { + story->ScanVariable([this](std::shared_ptr var) { if (var->GetUuid() == m_selectedVariableUuid) { m_selectedVariableName = var->GetVariableName(); @@ -36,39 +34,51 @@ void VariableNodeWidget::DrawProperties(std::shared_ptr 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 var) { - - // ImGui::PushID(static_cast(i)); // Assure l'unicité des widgets - + story->ScanVariable([&i, this](std::shared_ptr 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 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()); -} - +} \ No newline at end of file diff --git a/story-editor/src/node_editor/variable_node_widget.h b/story-editor/src/node_editor/variable_node_widget.h index 79a0efc..7d2a379 100644 --- a/story-editor/src/node_editor/variable_node_widget.h +++ b/story-editor/src/node_editor/variable_node_widget.h @@ -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 node); void Draw() override; - virtual void DrawProperties(std::shared_ptr story) override; virtual void Initialize() override; @@ -28,5 +26,5 @@ private: std::shared_ptr m_variableNode; int m_selectedIndex{-1}; std::string m_selectedVariableUuid; - std::string m_selectedVariableName; -}; + std::string m_selectedVariableName{""}; +}; \ No newline at end of file