imnodes_internal.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. #pragma once
  2. #include <imgui.h>
  3. #define IMGUI_DEFINE_MATH_OPERATORS
  4. #include <imgui_internal.h>
  5. #include <assert.h>
  6. #include <limits.h>
  7. // the structure of this file:
  8. //
  9. // [SECTION] internal enums
  10. // [SECTION] internal data structures
  11. // [SECTION] global and editor context structs
  12. // [SECTION] object pool implementation
  13. struct ImNodesContext;
  14. extern ImNodesContext* GImNodes;
  15. // [SECTION] internal enums
  16. typedef int ImNodesScope;
  17. typedef int ImNodesAttributeType;
  18. typedef int ImNodesUIState;
  19. typedef int ImNodesClickInteractionType;
  20. typedef int ImNodesLinkCreationType;
  21. enum ImNodesScope_
  22. {
  23. ImNodesScope_None = 1,
  24. ImNodesScope_Editor = 1 << 1,
  25. ImNodesScope_Node = 1 << 2,
  26. ImNodesScope_Attribute = 1 << 3
  27. };
  28. enum ImNodesAttributeType_
  29. {
  30. ImNodesAttributeType_None,
  31. ImNodesAttributeType_Input,
  32. ImNodesAttributeType_Output
  33. };
  34. enum ImNodesUIState_
  35. {
  36. ImNodesUIState_None = 0,
  37. ImNodesUIState_LinkStarted = 1 << 0,
  38. ImNodesUIState_LinkDropped = 1 << 1,
  39. ImNodesUIState_LinkCreated = 1 << 2
  40. };
  41. enum ImNodesClickInteractionType_
  42. {
  43. ImNodesClickInteractionType_Node,
  44. ImNodesClickInteractionType_Link,
  45. ImNodesClickInteractionType_LinkCreation,
  46. ImNodesClickInteractionType_Panning,
  47. ImNodesClickInteractionType_BoxSelection,
  48. ImNodesClickInteractionType_MiniMapPanning,
  49. ImNodesClickInteractionType_MiniMapZooming,
  50. ImNodesClickInteractionType_MiniMapSnapping,
  51. ImNodesClickInteractionType_ImGuiItem,
  52. ImNodesClickInteractionType_None
  53. };
  54. enum ImNodesLinkCreationType_
  55. {
  56. ImNodesLinkCreationType_Standard,
  57. ImNodesLinkCreationType_FromDetach
  58. };
  59. // Callback type used to specify special behavior when hovering a node in the minimap
  60. typedef void (*ImNodesMiniMapNodeHoveringCallback)(int, void*);
  61. // [SECTION] internal data structures
  62. // The object T must have the following interface:
  63. //
  64. // struct T
  65. // {
  66. // T();
  67. //
  68. // int id;
  69. // };
  70. template<typename T>
  71. struct ImObjectPool
  72. {
  73. ImVector<T> Pool;
  74. ImVector<bool> InUse;
  75. ImVector<int> FreeList;
  76. ImGuiStorage IdMap;
  77. ImObjectPool() : Pool(), InUse(), FreeList(), IdMap() {}
  78. };
  79. // Emulates std::optional<int> using the sentinel value `INVALID_INDEX`.
  80. struct ImOptionalIndex
  81. {
  82. ImOptionalIndex() : _Index(INVALID_INDEX) {}
  83. ImOptionalIndex(const int value) : _Index(value) {}
  84. // Observers
  85. inline bool HasValue() const { return _Index != INVALID_INDEX; }
  86. inline int Value() const
  87. {
  88. assert(HasValue());
  89. return _Index;
  90. }
  91. // Modifiers
  92. inline ImOptionalIndex& operator=(const int value)
  93. {
  94. _Index = value;
  95. return *this;
  96. }
  97. inline void Reset() { _Index = INVALID_INDEX; }
  98. inline bool operator==(const ImOptionalIndex& rhs) const { return _Index == rhs._Index; }
  99. inline bool operator==(const int rhs) const { return _Index == rhs; }
  100. inline bool operator!=(const ImOptionalIndex& rhs) const { return _Index != rhs._Index; }
  101. inline bool operator!=(const int rhs) const { return _Index != rhs; }
  102. static const int INVALID_INDEX = -1;
  103. private:
  104. int _Index;
  105. };
  106. struct ImNodeData
  107. {
  108. int Id;
  109. ImVec2 Origin; // The node origin is in editor space
  110. ImRect TitleBarContentRect;
  111. ImRect Rect;
  112. struct
  113. {
  114. ImU32 Background, BackgroundHovered, BackgroundSelected, Outline, Titlebar, TitlebarHovered,
  115. TitlebarSelected;
  116. } ColorStyle;
  117. struct
  118. {
  119. float CornerRounding;
  120. ImVec2 Padding;
  121. float BorderThickness;
  122. } LayoutStyle;
  123. ImVector<int> PinIndices;
  124. bool Draggable;
  125. ImNodeData(const int node_id)
  126. : Id(node_id), Origin(100.0f, 100.0f), TitleBarContentRect(),
  127. Rect(ImVec2(0.0f, 0.0f), ImVec2(0.0f, 0.0f)), ColorStyle(), LayoutStyle(), PinIndices(),
  128. Draggable(true)
  129. {
  130. }
  131. ~ImNodeData() { Id = INT_MIN; }
  132. };
  133. struct ImPinData
  134. {
  135. int Id;
  136. int ParentNodeIdx;
  137. ImRect AttributeRect;
  138. ImNodesAttributeType Type;
  139. ImNodesPinShape Shape;
  140. ImVec2 Pos; // screen-space coordinates
  141. int Flags;
  142. struct
  143. {
  144. ImU32 Background, Hovered;
  145. } ColorStyle;
  146. ImPinData(const int pin_id)
  147. : Id(pin_id), ParentNodeIdx(), AttributeRect(), Type(ImNodesAttributeType_None),
  148. Shape(ImNodesPinShape_CircleFilled), Pos(), Flags(ImNodesAttributeFlags_None),
  149. ColorStyle()
  150. {
  151. }
  152. };
  153. struct ImLinkData
  154. {
  155. int Id;
  156. int StartPinIdx, EndPinIdx;
  157. struct
  158. {
  159. ImU32 Base, Hovered, Selected;
  160. } ColorStyle;
  161. ImLinkData(const int link_id) : Id(link_id), StartPinIdx(), EndPinIdx(), ColorStyle() {}
  162. };
  163. struct ImClickInteractionState
  164. {
  165. ImNodesClickInteractionType Type;
  166. struct
  167. {
  168. int StartPinIdx;
  169. ImOptionalIndex EndPinIdx;
  170. ImNodesLinkCreationType Type;
  171. } LinkCreation;
  172. struct
  173. {
  174. ImRect Rect;
  175. } BoxSelector;
  176. ImClickInteractionState() : Type(ImNodesClickInteractionType_None) {}
  177. };
  178. struct ImNodesColElement
  179. {
  180. ImU32 Color;
  181. ImNodesCol Item;
  182. ImNodesColElement(const ImU32 c, const ImNodesCol s) : Color(c), Item(s) {}
  183. };
  184. struct ImNodesStyleVarElement
  185. {
  186. ImNodesStyleVar Item;
  187. float Value;
  188. ImNodesStyleVarElement(const float value, const ImNodesStyleVar variable)
  189. : Item(variable), Value(value)
  190. {
  191. }
  192. };
  193. // [SECTION] global and editor context structs
  194. struct ImNodesEditorContext
  195. {
  196. ImObjectPool<ImNodeData> Nodes;
  197. ImObjectPool<ImPinData> Pins;
  198. ImObjectPool<ImLinkData> Links;
  199. ImVector<int> NodeDepthOrder;
  200. // ui related fields
  201. ImVec2 Panning;
  202. ImVector<int> SelectedNodeIndices;
  203. ImVector<int> SelectedLinkIndices;
  204. ImClickInteractionState ClickInteraction;
  205. ImNodesEditorContext()
  206. : Nodes(), Pins(), Links(), Panning(0.f, 0.f), SelectedNodeIndices(), SelectedLinkIndices(),
  207. ClickInteraction()
  208. {
  209. }
  210. };
  211. struct ImNodesContext
  212. {
  213. ImNodesEditorContext* DefaultEditorCtx;
  214. ImNodesEditorContext* EditorCtx;
  215. // Canvas draw list and helper state
  216. ImDrawList* CanvasDrawList;
  217. ImGuiStorage NodeIdxToSubmissionIdx;
  218. ImVector<int> NodeIdxSubmissionOrder;
  219. ImVector<int> NodeIndicesOverlappingWithMouse;
  220. ImVector<int> OccludedPinIndices;
  221. // Canvas extents
  222. ImVec2 CanvasOriginScreenSpace;
  223. ImRect CanvasRectScreenSpace;
  224. // MiniMap state
  225. ImRect MiniMapRectScreenSpace;
  226. ImVec2 MiniMapRectSnappingOffset;
  227. float MiniMapZoom;
  228. ImNodesMiniMapNodeHoveringCallback MiniMapNodeHoveringCallback;
  229. void* MiniMapNodeHoveringCallbackUserData;
  230. // Debug helpers
  231. ImNodesScope CurrentScope;
  232. // Configuration state
  233. ImNodesIO Io;
  234. ImNodesStyle Style;
  235. ImVector<ImNodesColElement> ColorModifierStack;
  236. ImVector<ImNodesStyleVarElement> StyleModifierStack;
  237. ImGuiTextBuffer TextBuffer;
  238. int CurrentAttributeFlags;
  239. ImVector<int> AttributeFlagStack;
  240. // UI element state
  241. int CurrentNodeIdx;
  242. int CurrentPinIdx;
  243. int CurrentAttributeId;
  244. ImOptionalIndex HoveredNodeIdx;
  245. ImOptionalIndex HoveredLinkIdx;
  246. ImOptionalIndex HoveredPinIdx;
  247. ImOptionalIndex DeletedLinkIdx;
  248. ImOptionalIndex SnapLinkIdx;
  249. // Event helper state
  250. // TODO: this should be a part of a state machine, and not a member of the global struct.
  251. // Unclear what parts of the code this relates to.
  252. int ImNodesUIState;
  253. int ActiveAttributeId;
  254. bool ActiveAttribute;
  255. // ImGui::IO cache
  256. ImVec2 MousePos;
  257. bool LeftMouseClicked;
  258. bool LeftMouseReleased;
  259. bool AltMouseClicked;
  260. bool LeftMouseDragging;
  261. bool AltMouseDragging;
  262. float AltMouseScrollDelta;
  263. };
  264. namespace ImNodes
  265. {
  266. static inline ImNodesEditorContext& EditorContextGet()
  267. {
  268. // No editor context was set! Did you forget to call ImNodes::CreateContext()?
  269. assert(GImNodes->EditorCtx != NULL);
  270. return *GImNodes->EditorCtx;
  271. }
  272. // [SECTION] ObjectPool implementation
  273. template<typename T>
  274. static inline int ObjectPoolFind(const ImObjectPool<T>& objects, const int id)
  275. {
  276. const int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);
  277. return index;
  278. }
  279. template<typename T>
  280. static inline void ObjectPoolUpdate(ImObjectPool<T>& objects)
  281. {
  282. objects.FreeList.clear();
  283. for (int i = 0; i < objects.InUse.size(); ++i)
  284. {
  285. if (!objects.InUse[i])
  286. {
  287. objects.IdMap.SetInt(objects.Pool[i].Id, -1);
  288. objects.FreeList.push_back(i);
  289. (objects.Pool.Data + i)->~T();
  290. }
  291. }
  292. }
  293. template<>
  294. inline void ObjectPoolUpdate(ImObjectPool<ImNodeData>& nodes)
  295. {
  296. nodes.FreeList.clear();
  297. for (int i = 0; i < nodes.InUse.size(); ++i)
  298. {
  299. if (nodes.InUse[i])
  300. {
  301. nodes.Pool[i].PinIndices.clear();
  302. }
  303. else
  304. {
  305. const int previous_id = nodes.Pool[i].Id;
  306. const int previous_idx = nodes.IdMap.GetInt(previous_id, -1);
  307. if (previous_idx != -1)
  308. {
  309. assert(previous_idx == i);
  310. // Remove node idx form depth stack the first time we detect that this idx slot is
  311. // unused
  312. ImVector<int>& depth_stack = EditorContextGet().NodeDepthOrder;
  313. const int* const elem = depth_stack.find(i);
  314. assert(elem != depth_stack.end());
  315. depth_stack.erase(elem);
  316. }
  317. nodes.IdMap.SetInt(previous_id, -1);
  318. nodes.FreeList.push_back(i);
  319. (nodes.Pool.Data + i)->~ImNodeData();
  320. }
  321. }
  322. }
  323. template<typename T>
  324. static inline void ObjectPoolReset(ImObjectPool<T>& objects)
  325. {
  326. if (!objects.InUse.empty())
  327. {
  328. memset(objects.InUse.Data, 0, objects.InUse.size_in_bytes());
  329. }
  330. }
  331. template<typename T>
  332. static inline int ObjectPoolFindOrCreateIndex(ImObjectPool<T>& objects, const int id)
  333. {
  334. int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);
  335. // Construct new object
  336. if (index == -1)
  337. {
  338. if (objects.FreeList.empty())
  339. {
  340. index = objects.Pool.size();
  341. IM_ASSERT(objects.Pool.size() == objects.InUse.size());
  342. const int new_size = objects.Pool.size() + 1;
  343. objects.Pool.resize(new_size);
  344. objects.InUse.resize(new_size);
  345. }
  346. else
  347. {
  348. index = objects.FreeList.back();
  349. objects.FreeList.pop_back();
  350. }
  351. IM_PLACEMENT_NEW(objects.Pool.Data + index) T(id);
  352. objects.IdMap.SetInt(static_cast<ImGuiID>(id), index);
  353. }
  354. // Flag it as used
  355. objects.InUse[index] = true;
  356. return index;
  357. }
  358. template<>
  359. inline int ObjectPoolFindOrCreateIndex(ImObjectPool<ImNodeData>& nodes, const int node_id)
  360. {
  361. int node_idx = nodes.IdMap.GetInt(static_cast<ImGuiID>(node_id), -1);
  362. // Construct new node
  363. if (node_idx == -1)
  364. {
  365. if (nodes.FreeList.empty())
  366. {
  367. node_idx = nodes.Pool.size();
  368. IM_ASSERT(nodes.Pool.size() == nodes.InUse.size());
  369. const int new_size = nodes.Pool.size() + 1;
  370. nodes.Pool.resize(new_size);
  371. nodes.InUse.resize(new_size);
  372. }
  373. else
  374. {
  375. node_idx = nodes.FreeList.back();
  376. nodes.FreeList.pop_back();
  377. }
  378. IM_PLACEMENT_NEW(nodes.Pool.Data + node_idx) ImNodeData(node_id);
  379. nodes.IdMap.SetInt(static_cast<ImGuiID>(node_id), node_idx);
  380. ImNodesEditorContext& editor = EditorContextGet();
  381. editor.NodeDepthOrder.push_back(node_idx);
  382. }
  383. // Flag node as used
  384. nodes.InUse[node_idx] = true;
  385. return node_idx;
  386. }
  387. template<typename T>
  388. static inline T& ObjectPoolFindOrCreateObject(ImObjectPool<T>& objects, const int id)
  389. {
  390. const int index = ObjectPoolFindOrCreateIndex(objects, id);
  391. return objects.Pool[index];
  392. }
  393. } // namespace ImNodes