Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
NodeGraphPanel.h
Go to the documentation of this file.
1/*
2 * Olympe Blueprint Editor - Node Graph Panel
3 *
4 * GUI panel for visual node graph editing using ImNodes
5 * Supports Behavior Trees and HFSM editing
6 *
7 * @deprecated (Phase 7) NodeGraphPanel is the legacy BT v2 editor.
8 * For new VS v4 graphs use VisualScriptEditorPanel.
9 * NodeGraphPanel is retained for BehaviorTreeDebugWindow (BT debug visualisation).
10 */
11
12#pragma once
13
14#include <string>
15#include <vector>
16#include <unordered_set>
17#include <memory>
18#include "BTNodeGraphManager.h"
19#include "../EditorCommon/EditorAutosaveManager.h"
20#include "../third_party/imnodes/imnodes.h"
22
23namespace Olympe
24{
25 // -------------------------------------------------------------------------
26 // Phase 8: Subgraph tab descriptor
27 // -------------------------------------------------------------------------
28
29 /**
30 * @struct GraphTab
31 * @brief Represents one open tab in the NodeGraphPanel tab bar.
32 *
33 * The root graph always has graphPath == "root".
34 * A subgraph tab has graphPath == "subgraphs/<uuid>".
35 */
36 struct GraphTab
37 {
38 std::string tabID; ///< Unique identifier (UUID or "root")
39 std::string displayName; ///< Label shown on the tab ("Root" or subgraph name)
40 std::string graphPath; ///< "root" or "subgraphs/<uuid>"
41 bool isDirty; ///< True when the graph has unsaved changes
42
44 GraphTab(const std::string& id,
45 const std::string& name,
46 const std::string& path)
47 : tabID(id), displayName(name), graphPath(path), isDirty(false) {}
48 };
49
50 /**
51 * NodeGraphPanel - ImGui/ImNodes panel for node graph editing
52 * Provides visual editor for behavior trees and state machines
53 */
55 {
56 public:
59
60 void Initialize();
61 void Shutdown();
62 void Render();
63 void RenderContent(); // Render without window wrapper - for fixed layout
64
65 void RenderGraphTabs();
66 void RenderGraph();
67 void RenderContextMenu();
71 void HandleNodeInteractions(int graphID);
72
73 // -----------------------------------------------------------------------
74 // Phase 8: Subgraph tab system
75 // -----------------------------------------------------------------------
76
77 /**
78 * @brief Renders the subgraph-aware tab bar above the graph canvas.
79 *
80 * Shows one tab per open subgraph plus the root graph. A "+ New SubGraph"
81 * button at the end creates an empty subgraph and opens it.
82 */
84
85 /**
86 * @brief Opens (or focuses) the subgraph identified by @p subgraphUUID
87 * in a new tab. Called on double-click of a BT_SubGraph node.
88 *
89 * @param subgraphUUID UUID key in data.subgraphs.
90 * @param displayName Name shown on the tab.
91 */
92 void OpenSubgraphTab(const std::string& subgraphUUID,
93 const std::string& displayName);
94
95 /**
96 * @brief Closes the tab at @p index. The root tab (index 0) cannot be closed.
97 */
98 void CloseSubgraphTab(int index);
99
100 /**
101 * @brief Creates an empty subgraph, inserts it into the active blueprint's
102 * data.subgraphs dict, and opens it in a new tab.
103 *
104 * @param name Human-readable name for the new subgraph.
105 */
106 void CreateEmptySubgraph(const std::string& name);
107
108 /**
109 * @brief Returns the GraphTab for the currently active tab.
110 */
111 const GraphTab* GetActiveTab() const;
112
113 /**
114 * @brief Returns the subgraph UUID for the active tab, or empty string
115 * if the root graph is active.
116 */
117 std::string GetActiveSubgraphUUID() const;
118
119 /**
120 * @brief Render a single node with a coloured title bar, icon, and typed pins.
121 * Called from RenderGraph() for every node in the active graph.
122 * @param node Pointer to the graph node to render.
123 * @param globalNodeUID ImNodes global unique ID for the node.
124 * @param graphID Active graph ID (used for debug-highlight check).
125 * @param connectedAttrIDs Set of connected attribute IDs (for filled/outlined shapes).
126 */
128 const std::unordered_set<int>& connectedAttrIDs = {});
129
130 /**
131 * @brief Render a single typed attribute pin using ImDrawList shapes.
132 * @param attrId ImNodes attribute ID.
133 * @param label Text label shown next to the pin.
134 * @param isInput True for input (left) attribute; false for output (right).
135 * @param isExec True to use the exec (triangle) pin shape; false for data (circle).
136 * @param connectedAttrIDs Set of connected attribute IDs (for filled/outlined shapes).
137 */
138 void RenderTypedPin(int attrId, const char* label, bool isInput, bool isExec,
139 const std::unordered_set<int>& connectedAttrIDs = {});
140
141 /**
142 * @brief Overlay glow-coloured lines on links that connect to/from the
143 * active debug node, giving a visual "active link" indicator.
144 *
145 * Must be called AFTER ImNodes::EndNodeEditor() so that node screen-space
146 * positions are valid.
147 *
148 * @param graph Active NodeGraph.
149 * @param graphID Active graph ID.
150 */
151 void RenderActiveLinks(NodeGraph* graph, int graphID);
152
153 /**
154 * @brief Render execution indices (1, 2, 3, ...n) on connection lines
155 * for Sequence and Selector nodes based on child Y-position ordering.
156 *
157 * Phase 38: Y-Axis positional execution ordering - indices auto-calculated
158 * from GetChildrenSortedByY() which sorts children by editorPosY.
159 *
160 * Must be called AFTER ImNodes::EndNodeEditor() so that node screen-space
161 * positions are valid.
162 *
163 * @param graph Active NodeGraph.
164 * @param graphID Active graph ID.
165 */
166 void RenderConnectionIndices(NodeGraph* graph, int graphID);
167
168 // Node creation helpers
169 void CreateNewNode(const char* nodeType, float x, float y);
170
171 // Synchronize node positions from ImNodes to the graph data
172 void SyncNodePositionsFromImNodes(int graphID);
173
174 // Helper for converting global UID to local node ID
175 int GlobalUIDToLocalNodeID(int globalUID, int graphID) const
176 {
177 return globalUID - (graphID * 10000); // 10000 is GRAPH_ID_MULTIPLIER
178 }
179
180 // -----------------------------------------------------------------------
181 // Runtime debug overlay
182 // -----------------------------------------------------------------------
183
184 /**
185 * @brief Set the local node ID that is currently executing.
186 * Pass -1 to clear the highlight.
187 * The value is stored in a static so it is visible to all panel
188 * instances and to the WorldBridge callback.
189 */
190 static void SetActiveDebugNode(int localNodeId);
191
192 // ImNodes state
195 bool m_ShowContextMenu = false;
196 float m_ContextMenuPosX = 0.0f;
197 float m_ContextMenuPosY = 0.0f;
198
199 // Control rendering behavior when embedded in other renderers
200 bool m_SuppressGraphTabs = false; ///< When true, RenderGraphTabs() is skipped (used by BehaviorTreeRenderer)
201
202 // Node editing modal
207
208 // For tracking node movement (undo/redo)
209 bool m_NodeDragStarted = false;
211 float m_DragStartX = 0.0f;
212 float m_DragStartY = 0.0f;
213
214 // Context-menu fuzzy search buffer
216
217 // -----------------------------------------------------------------------
218 // Minimap
219 // -----------------------------------------------------------------------
220
221 /// When true the built-in ImNodes minimap is rendered in the bottom-right
222 /// corner of the node editor canvas.
223 bool m_ShowMinimap = true;
224
225 // -----------------------------------------------------------------------
226 // Snap-to-grid
227 // -----------------------------------------------------------------------
228
229 /// When true node positions are rounded to the nearest grid cell on move.
230 bool m_SnapToGrid = false;
231
232 /// Grid cell size in canvas units used when snap-to-grid is enabled.
233 float m_SnapGridSize = 16.0f;
234
235 private:
236 /// Backing storage for SetActiveDebugNode: the local node ID currently
237 /// executing (-1 = none). Shared across all panel instances.
239
240 /// Async autosave manager – persists node positions without blocking the UI.
242
243 /// Tracks which global node UIDs have already had their ImNodes position
244 /// initialised. Prevents SetNodeGridSpacePos() from overriding user drags
245 /// on subsequent frames. Cleared whenever the active graph changes.
246 std::unordered_set<int> m_positionedNodes;
247
248 /// Graph ID that was active last frame; used to detect graph switches so
249 /// m_positionedNodes can be cleared.
251
252 // -----------------------------------------------------------------------
253 // Phase 8: Subgraph tab state
254 // -----------------------------------------------------------------------
255
256 /// Ordered list of open subgraph tabs. Index 0 is always the root graph.
257 std::vector<GraphTab> m_SubgraphTabs;
258
259 /// Index into m_SubgraphTabs of the currently visible tab.
261
262 /// Buffer used by the "New SubGraph" name input popup.
264
265 // -----------------------------------------------------------------------
266 // Phase 35.0: imnodes context management
267 // -----------------------------------------------------------------------
268
269 /// Dedicated imnodes rendering context for this panel instance.
270 /// Prevents viewport state collision with other graph renderers.
272
273 // -----------------------------------------------------------------------
274 // Phase 36: Canvas editor minimap framework
275 // -----------------------------------------------------------------------
276
277 /// Canvas editor adapter for minimap support (Phase 36)
278 /// Abstracts imnodes minimap rendering through ICanvasEditor interface
279 std::unique_ptr<class ImNodesCanvasEditor> m_canvasEditor;
280 };
281
282 } // namespace Olympe
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
ICanvasEditor adapter for ImNodes-based editors (VisualScript)
NodeGraphPanel - ImGui/ImNodes panel for node graph editing Provides visual editor for behavior trees...
void RenderSubgraphTabBar()
Renders the subgraph-aware tab bar above the graph canvas.
const GraphTab * GetActiveTab() const
Returns the GraphTab for the currently active tab.
void CreateNewNode(const char *nodeType, float x, float y)
ImNodesEditorContext * m_imnodesContext
Dedicated imnodes rendering context for this panel instance.
char m_NewSubgraphNameBuffer[128]
Buffer used by the "New SubGraph" name input popup.
int m_lastActiveGraphId
Graph ID that was active last frame; used to detect graph switches so m_positionedNodes can be cleare...
void CloseSubgraphTab(int index)
Closes the tab at index.
bool m_SnapToGrid
When true node positions are rounded to the nearest grid cell on move.
float m_SnapGridSize
Grid cell size in canvas units used when snap-to-grid is enabled.
std::vector< GraphTab > m_SubgraphTabs
Ordered list of open subgraph tabs. Index 0 is always the root graph.
void OpenSubgraphTab(const std::string &subgraphUUID, const std::string &displayName)
Opens (or focuses) the subgraph identified by subgraphUUID in a new tab.
void RenderActiveLinks(NodeGraph *graph, int graphID)
Overlay glow-coloured lines on links that connect to/from the active debug node, giving a visual "act...
static int s_ActiveDebugNodeId
Backing storage for SetActiveDebugNode: the local node ID currently executing (-1 = none).
bool m_SuppressGraphTabs
When true, RenderGraphTabs() is skipped (used by BehaviorTreeRenderer)
int m_ActiveSubgraphTabIndex
Index into m_SubgraphTabs of the currently visible tab.
bool m_ShowMinimap
When true the built-in ImNodes minimap is rendered in the bottom-right corner of the node editor canv...
std::unordered_set< int > m_positionedNodes
Tracks which global node UIDs have already had their ImNodes position initialised.
std::string GetActiveSubgraphUUID() const
Returns the subgraph UUID for the active tab, or empty string if the root graph is active.
void SyncNodePositionsFromImNodes(int graphID)
void RenderTypedPin(int attrId, const char *label, bool isInput, bool isExec, const std::unordered_set< int > &connectedAttrIDs={})
Render a single typed attribute pin using ImDrawList shapes.
int GlobalUIDToLocalNodeID(int globalUID, int graphID) const
std::unique_ptr< class ImNodesCanvasEditor > m_canvasEditor
Canvas editor adapter for minimap support (Phase 36) Abstracts imnodes minimap rendering through ICan...
void HandleNodeInteractions(int graphID)
EditorAutosaveManager m_autosave
Async autosave manager – persists node positions without blocking the UI.
void CreateEmptySubgraph(const std::string &name)
Creates an empty subgraph, inserts it into the active blueprint's data.subgraphs dict,...
void RenderNodePinsAndContent(GraphNode *node, int globalNodeUID, int graphID, const std::unordered_set< int > &connectedAttrIDs={})
Render a single node with a coloured title bar, icon, and typed pins.
void RenderConnectionIndices(NodeGraph *graph, int graphID)
Render execution indices (1, 2, 3, ...n) on connection lines for Sequence and Selector nodes based on...
static void SetActiveDebugNode(int localNodeId)
Set the local node ID that is currently executing.
< Provides AssetID and INVALID_ASSET_ID
Represents one open tab in the NodeGraphPanel tab bar.
std::string graphPath
"root" or "subgraphs/<uuid>"
bool isDirty
True when the graph has unsaved changes.
GraphTab(const std::string &id, const std::string &name, const std::string &path)
std::string displayName
Label shown on the tab ("Root" or subgraph name)
std::string tabID
Unique identifier (UUID or "root")