dear-imgui-raw-imnodes (empty) → 1.0.0
raw patch · 24 files changed
+6757/−0 lines, 24 filesdep +basedep +dear-imgui-rawdep +unliftio-core
Dependencies added: base, dear-imgui-raw, unliftio-core
Files
- CHANGELOG.md +14/−0
- LICENSE +26/−0
- README.md +5/−0
- cbits/DearImGuiCtors.cpp +54/−0
- cbits/DearImGuiWrappers.cpp +43/−0
- cbits/DearImGuiWrappers.h +41/−0
- cbits/dcimnodes.cpp +486/−0
- cbits/dcimnodes.h +435/−0
- cbits/imnodes/imnodes.cpp +3326/−0
- cbits/imnodes/imnodes.h +440/−0
- cbits/imnodes/imnodes_internal.h +500/−0
- dear-imgui-raw-imnodes.cabal +72/−0
- src/DearImGui/ImNodes/Context.hs +12/−0
- src/DearImGui/Raw/ImNodes.hsc +634/−0
- src/DearImGui/Raw/ImNodes/Context.hsc +14/−0
- src/DearImGui/Raw/ImNodes/EditorContext.hsc +14/−0
- src/DearImGui/Raw/ImNodes/Enums/AttributeFlags.hsc +39/−0
- src/DearImGui/Raw/ImNodes/Enums/Col.hsc +139/−0
- src/DearImGui/Raw/ImNodes/Enums/MiniMapLocation.hsc +35/−0
- src/DearImGui/Raw/ImNodes/Enums/PinShape.hsc +43/−0
- src/DearImGui/Raw/ImNodes/Enums/StyleFlags.hsc +39/−0
- src/DearImGui/Raw/ImNodes/Enums/StyleVar.hsc +83/−0
- src/DearImGui/Raw/ImNodes/ImNodesIO.hsc +163/−0
- src/DearImGui/Raw/ImNodes/Style.hsc +100/−0
+ CHANGELOG.md view
@@ -0,0 +1,14 @@+# Changelog for `dear-imgui-raw-imnodes`++All notable changes to this package will be documented in this file.++The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),+and this project adheres to the+[Haskell Package Versioning Policy](https://pvp.haskell.org/).++## 1.0.0 - 2026-10-21++Initial release.++- Generated with dear_bindings `v0.26` against Dear ImGui `v1.93.0-docking`.+- Bundles imnodes at commit `2d0c280` (`v0.5-41-g2d0c280`).
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright 2026 IC Rainbow++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,5 @@+# dear-imgui-raw-imnodes++Raw FFI bindings to [imnodes], node-graph editor widgets for Dear ImGui.++[imnodes]: https://github.com/Nelarius/imnodes
+ cbits/DearImGuiCtors.cpp view
@@ -0,0 +1,54 @@+// Generated by dear-bindings-ffi. Do not edit.+#include <new>+#include "imnodes.h"++extern "C" void ImNodesIO_Init_wrap(void* p) {+ using T = ::ImNodesIO;+ new (p) T();+}++extern "C" void ImNodesIO_Destroy_wrap(void* p) {+ using T = ::ImNodesIO;+ static_cast<T*>(p)->~T();+}++extern "C" void ImNodesIO_EmulateThreeButtonMouse_Init_wrap(void* p) {+ using T = struct ::ImNodesIO::EmulateThreeButtonMouse;+ new (p) T();+}++extern "C" void ImNodesIO_EmulateThreeButtonMouse_Destroy_wrap(void* p) {+ using T = struct ::ImNodesIO::EmulateThreeButtonMouse;+ static_cast<T*>(p)->~T();+}++extern "C" void ImNodesIO_LinkDetachWithModifierClick_Init_wrap(void* p) {+ using T = struct ::ImNodesIO::LinkDetachWithModifierClick;+ new (p) T();+}++extern "C" void ImNodesIO_LinkDetachWithModifierClick_Destroy_wrap(void* p) {+ using T = struct ::ImNodesIO::LinkDetachWithModifierClick;+ static_cast<T*>(p)->~T();+}++extern "C" void ImNodesIO_MultipleSelectModifier_Init_wrap(void* p) {+ using T = struct ::ImNodesIO::MultipleSelectModifier;+ new (p) T();+}++extern "C" void ImNodesIO_MultipleSelectModifier_Destroy_wrap(void* p) {+ using T = struct ::ImNodesIO::MultipleSelectModifier;+ static_cast<T*>(p)->~T();+}++extern "C" void ImNodesStyle_Init_wrap(void* p) {+ using T = ::ImNodesStyle;+ new (p) T();+}++extern "C" void ImNodesStyle_Destroy_wrap(void* p) {+ using T = ::ImNodesStyle;+ static_cast<T*>(p)->~T();+}+
+ cbits/DearImGuiWrappers.cpp view
@@ -0,0 +1,43 @@+// Generated by dear-bindings-ffi. Do not edit.+#include "DearImGuiWrappers.h"++extern "C" void ImNodesEditorContextGetPanning_wrap(ImVec2* _out) {+ *_out = ImNodesEditorContextGetPanning();+}++extern "C" void ImNodesEditorContextResetPanning_wrap(ImVec2 const* pos) {+ ImNodesEditorContextResetPanning(*pos);+}++extern "C" void ImNodesGetNodeDimensions_wrap(int id, ImVec2* _out) {+ *_out = ImNodesGetNodeDimensions(id);+}++extern "C" void ImNodesGetNodeEditorSpacePos_wrap(const int node_id, ImVec2* _out) {+ *_out = ImNodesGetNodeEditorSpacePos(node_id);+}++extern "C" void ImNodesGetNodeGridSpacePos_wrap(const int node_id, ImVec2* _out) {+ *_out = ImNodesGetNodeGridSpacePos(node_id);+}++extern "C" void ImNodesGetNodeScreenSpacePos_wrap(const int node_id, ImVec2* _out) {+ *_out = ImNodesGetNodeScreenSpacePos(node_id);+}++extern "C" void ImNodesPushStyleVarImVec2_wrap(ImNodesStyleVar style_item, ImVec2 const* value) {+ ImNodesPushStyleVarImVec2(style_item, *value);+}++extern "C" void ImNodesSetNodeEditorSpacePos_wrap(int node_id, ImVec2 const* editor_space_pos) {+ ImNodesSetNodeEditorSpacePos(node_id, *editor_space_pos);+}++extern "C" void ImNodesSetNodeGridSpacePos_wrap(int node_id, ImVec2 const* grid_pos) {+ ImNodesSetNodeGridSpacePos(node_id, *grid_pos);+}++extern "C" void ImNodesSetNodeScreenSpacePos_wrap(int node_id, ImVec2 const* screen_space_pos) {+ ImNodesSetNodeScreenSpacePos(node_id, *screen_space_pos);+}+
+ cbits/DearImGuiWrappers.h view
@@ -0,0 +1,41 @@+// Generated by dear-bindings-ffi. Do not edit.+#ifndef DEAR_IMGUI_WRAPPERS_H+#define DEAR_IMGUI_WRAPPERS_H++#include "dcimnodes.h"++#ifdef __cplusplus+extern "C" {+#endif++void ImNodesEditorContextGetPanning_wrap(ImVec2* _out);+void ImNodesEditorContextResetPanning_wrap(ImVec2 const* pos);+void ImNodesGetNodeDimensions_wrap(int id, ImVec2* _out);+void ImNodesGetNodeEditorSpacePos_wrap(const int node_id, ImVec2* _out);+void ImNodesGetNodeGridSpacePos_wrap(const int node_id, ImVec2* _out);+void ImNodesGetNodeScreenSpacePos_wrap(const int node_id, ImVec2* _out);+void ImNodesPushStyleVarImVec2_wrap(ImNodesStyleVar style_item, ImVec2 const* value);+void ImNodesSetNodeEditorSpacePos_wrap(int node_id, ImVec2 const* editor_space_pos);+void ImNodesSetNodeGridSpacePos_wrap(int node_id, ImVec2 const* grid_pos);+void ImNodesSetNodeScreenSpacePos_wrap(int node_id, ImVec2 const* screen_space_pos);+void ImNodesIO_Init_wrap(void* p);+void ImNodesIO_Destroy_wrap(void* p);++void ImNodesIO_EmulateThreeButtonMouse_Init_wrap(void* p);+void ImNodesIO_EmulateThreeButtonMouse_Destroy_wrap(void* p);++void ImNodesIO_LinkDetachWithModifierClick_Init_wrap(void* p);+void ImNodesIO_LinkDetachWithModifierClick_Destroy_wrap(void* p);++void ImNodesIO_MultipleSelectModifier_Init_wrap(void* p);+void ImNodesIO_MultipleSelectModifier_Destroy_wrap(void* p);++void ImNodesStyle_Init_wrap(void* p);+void ImNodesStyle_Destroy_wrap(void* p);+++#ifdef __cplusplus+}+#endif++#endif
+ cbits/dcimnodes.cpp view
@@ -0,0 +1,486 @@+// THIS FILE HAS BEEN AUTO-GENERATED BY THE 'DEAR BINDINGS' GENERATOR.+// **DO NOT EDIT DIRECTLY**+// https://github.com/dearimgui/dear_bindings++#include "imgui.h"+#include "imnodes.h"++// Glue file consumed by dear_bindings at imnodes-binding generation+// time. The cimgui namespace wraps the C-shape header so the+// generator can emit type aliases without colliding with the C+++// API; pulling dcimgui.h into the same namespace promotes ImVec2+// and friends from forward-declared (the dcimnodes.h default) to+// fully defined, which dcimnodes.cpp needs for its by-value+// argument/return shims.+#define DEAR_BINDINGS_INTERNAL_GLUE_CODE+namespace cimgui+{+#include "dcimgui.h"+#include "dcimnodes.h"+}+#undef DEAR_BINDINGS_INTERNAL_GLUE_CODE+// By-value struct conversions++static inline cimgui::ImVec2 ConvertFromCPP_ImVec2(const ::ImVec2& src)+{+ cimgui::ImVec2 dest;+ dest.x = src.x;+ dest.y = src.y;+ return dest;+}++static inline ::ImVec2 ConvertToCPP_ImVec2(const cimgui::ImVec2& src)+{+ ::ImVec2 dest;+ dest.x = src.x;+ dest.y = src.y;+ return dest;+}++static inline cimgui::ImVec4 ConvertFromCPP_ImVec4(const ::ImVec4& src)+{+ cimgui::ImVec4 dest;+ dest.x = src.x;+ dest.y = src.y;+ dest.z = src.z;+ dest.w = src.w;+ return dest;+}++static inline ::ImVec4 ConvertToCPP_ImVec4(const cimgui::ImVec4& src)+{+ ::ImVec4 dest;+ dest.x = src.x;+ dest.y = src.y;+ dest.z = src.z;+ dest.w = src.w;+ return dest;+}++static inline cimgui::ImTextureRef ConvertFromCPP_ImTextureRef(const ::ImTextureRef& src)+{+ cimgui::ImTextureRef dest;+ dest._TexData = reinterpret_cast<cimgui::ImTextureData*>(src._TexData);+ dest._TexID = src._TexID;+ return dest;+}++static inline ::ImTextureRef ConvertToCPP_ImTextureRef(const cimgui::ImTextureRef& src)+{+ ::ImTextureRef dest;+ dest._TexData = reinterpret_cast<::ImTextureData*>(src._TexData);+ dest._TexID = src._TexID;+ return dest;+}++static inline cimgui::ImColor ConvertFromCPP_ImColor(const ::ImColor& src)+{+ cimgui::ImColor dest;+ dest.Value.x = src.Value.x;+ dest.Value.y = src.Value.y;+ dest.Value.z = src.Value.z;+ dest.Value.w = src.Value.w;+ return dest;+}++static inline ::ImColor ConvertToCPP_ImColor(const cimgui::ImColor& src)+{+ ::ImColor dest;+ dest.Value.x = src.Value.x;+ dest.Value.y = src.Value.y;+ dest.Value.z = src.Value.z;+ dest.Value.w = src.Value.w;+ return dest;+}++// Function stubs++CIMGUI_API void cimgui::ImNodesSetImGuiContext(cimgui::ImGuiContext* ctx)+{+ ::ImNodes::SetImGuiContext(reinterpret_cast<::ImGuiContext*>(ctx));+}++CIMGUI_API cimgui::ImNodesContext* cimgui::ImNodesCreateContext(void)+{+ return reinterpret_cast<::cimgui::ImNodesContext*>(::ImNodes::CreateContext());+}++CIMGUI_API void cimgui::ImNodesDestroyContext(cimgui::ImNodesContext* ctx)+{+ ::ImNodes::DestroyContext(reinterpret_cast<::ImNodesContext*>(ctx));+}++CIMGUI_API cimgui::ImNodesContext* cimgui::ImNodesGetCurrentContext(void)+{+ return reinterpret_cast<::cimgui::ImNodesContext*>(::ImNodes::GetCurrentContext());+}++CIMGUI_API void cimgui::ImNodesSetCurrentContext(cimgui::ImNodesContext* ctx)+{+ ::ImNodes::SetCurrentContext(reinterpret_cast<::ImNodesContext*>(ctx));+}++CIMGUI_API cimgui::ImNodesEditorContext* cimgui::ImNodesEditorContextCreate(void)+{+ return reinterpret_cast<::cimgui::ImNodesEditorContext*>(::ImNodes::EditorContextCreate());+}++CIMGUI_API void cimgui::ImNodesEditorContextFree(cimgui::ImNodesEditorContext* __unnamed_arg0__)+{+ ::ImNodes::EditorContextFree(reinterpret_cast<::ImNodesEditorContext*>(__unnamed_arg0__));+}++CIMGUI_API void cimgui::ImNodesEditorContextSet(cimgui::ImNodesEditorContext* __unnamed_arg0__)+{+ ::ImNodes::EditorContextSet(reinterpret_cast<::ImNodesEditorContext*>(__unnamed_arg0__));+}++CIMGUI_API cimgui::ImVec2 cimgui::ImNodesEditorContextGetPanning(void)+{+ return ConvertFromCPP_ImVec2(::ImNodes::EditorContextGetPanning());+}++CIMGUI_API void cimgui::ImNodesEditorContextResetPanning(cimgui::ImVec2 pos)+{+ ::ImNodes::EditorContextResetPanning(ConvertToCPP_ImVec2(pos));+}++CIMGUI_API void cimgui::ImNodesEditorContextMoveToNode(const int node_id)+{+ ::ImNodes::EditorContextMoveToNode(node_id);+}++CIMGUI_API cimgui::ImNodesIO* cimgui::ImNodesGetIO(void)+{+ return reinterpret_cast<::cimgui::ImNodesIO*>(&::ImNodes::GetIO());+}++CIMGUI_API cimgui::ImNodesStyle* cimgui::ImNodesGetStyle(void)+{+ return reinterpret_cast<::cimgui::ImNodesStyle*>(&::ImNodes::GetStyle());+}++CIMGUI_API void cimgui::ImNodesStyleColorsDark(cimgui::ImNodesStyle* dest)+{+ ::ImNodes::StyleColorsDark(reinterpret_cast<::ImNodesStyle*>(dest));+}++CIMGUI_API void cimgui::ImNodesStyleColorsClassic(cimgui::ImNodesStyle* dest)+{+ ::ImNodes::StyleColorsClassic(reinterpret_cast<::ImNodesStyle*>(dest));+}++CIMGUI_API void cimgui::ImNodesStyleColorsLight(cimgui::ImNodesStyle* dest)+{+ ::ImNodes::StyleColorsLight(reinterpret_cast<::ImNodesStyle*>(dest));+}++CIMGUI_API const char* cimgui::ImNodesGetStyleColorName(ImNodesCol idx)+{+ return ::ImNodes::GetStyleColorName(idx);+}++CIMGUI_API void cimgui::ImNodesBeginNodeEditor(void)+{+ ::ImNodes::BeginNodeEditor();+}++CIMGUI_API void cimgui::ImNodesEndNodeEditor(void)+{+ ::ImNodes::EndNodeEditor();+}++CIMGUI_API void cimgui::ImNodesMiniMap(const float minimap_size_fraction, const ImNodesMiniMapLocation location, const cimgui::ImNodesMiniMapNodeHoveringCallback node_hovering_callback, const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data)+{+ ::ImNodes::MiniMap(minimap_size_fraction, location, reinterpret_cast<const ::ImNodesMiniMapNodeHoveringCallback>(node_hovering_callback), node_hovering_callback_data);+}++CIMGUI_API void cimgui::ImNodesPushColorStyle(ImNodesCol item, unsigned int color)+{+ ::ImNodes::PushColorStyle(item, color);+}++CIMGUI_API void cimgui::ImNodesPopColorStyle(void)+{+ ::ImNodes::PopColorStyle();+}++CIMGUI_API void cimgui::ImNodesPushStyleVar(ImNodesStyleVar style_item, float value)+{+ ::ImNodes::PushStyleVar(style_item, value);+}++CIMGUI_API void cimgui::ImNodesPushStyleVarImVec2(ImNodesStyleVar style_item, cimgui::ImVec2 value)+{+ ::ImNodes::PushStyleVar(style_item, ConvertToCPP_ImVec2(value));+}++CIMGUI_API void cimgui::ImNodesPopStyleVar(int count)+{+ ::ImNodes::PopStyleVar(count);+}++CIMGUI_API void cimgui::ImNodesBeginNode(int id)+{+ ::ImNodes::BeginNode(id);+}++CIMGUI_API void cimgui::ImNodesEndNode(void)+{+ ::ImNodes::EndNode();+}++CIMGUI_API cimgui::ImVec2 cimgui::ImNodesGetNodeDimensions(int id)+{+ return ConvertFromCPP_ImVec2(::ImNodes::GetNodeDimensions(id));+}++CIMGUI_API void cimgui::ImNodesBeginNodeTitleBar(void)+{+ ::ImNodes::BeginNodeTitleBar();+}++CIMGUI_API void cimgui::ImNodesEndNodeTitleBar(void)+{+ ::ImNodes::EndNodeTitleBar();+}++CIMGUI_API void cimgui::ImNodesBeginInputAttribute(int id, ImNodesPinShape shape)+{+ ::ImNodes::BeginInputAttribute(id, shape);+}++CIMGUI_API void cimgui::ImNodesEndInputAttribute(void)+{+ ::ImNodes::EndInputAttribute();+}++CIMGUI_API void cimgui::ImNodesBeginOutputAttribute(int id, ImNodesPinShape shape)+{+ ::ImNodes::BeginOutputAttribute(id, shape);+}++CIMGUI_API void cimgui::ImNodesEndOutputAttribute(void)+{+ ::ImNodes::EndOutputAttribute();+}++CIMGUI_API void cimgui::ImNodesBeginStaticAttribute(int id)+{+ ::ImNodes::BeginStaticAttribute(id);+}++CIMGUI_API void cimgui::ImNodesEndStaticAttribute(void)+{+ ::ImNodes::EndStaticAttribute();+}++CIMGUI_API void cimgui::ImNodesPushAttributeFlag(ImNodesAttributeFlags flag)+{+ ::ImNodes::PushAttributeFlag(flag);+}++CIMGUI_API void cimgui::ImNodesPopAttributeFlag(void)+{+ ::ImNodes::PopAttributeFlag();+}++CIMGUI_API void cimgui::ImNodesLink(int id, int start_attribute_id, int end_attribute_id)+{+ ::ImNodes::Link(id, start_attribute_id, end_attribute_id);+}++CIMGUI_API void cimgui::ImNodesSetNodeDraggable(int node_id, const bool draggable)+{+ ::ImNodes::SetNodeDraggable(node_id, draggable);+}++CIMGUI_API void cimgui::ImNodesSetNodeScreenSpacePos(int node_id, cimgui::ImVec2 screen_space_pos)+{+ ::ImNodes::SetNodeScreenSpacePos(node_id, ConvertToCPP_ImVec2(screen_space_pos));+}++CIMGUI_API void cimgui::ImNodesSetNodeEditorSpacePos(int node_id, cimgui::ImVec2 editor_space_pos)+{+ ::ImNodes::SetNodeEditorSpacePos(node_id, ConvertToCPP_ImVec2(editor_space_pos));+}++CIMGUI_API void cimgui::ImNodesSetNodeGridSpacePos(int node_id, cimgui::ImVec2 grid_pos)+{+ ::ImNodes::SetNodeGridSpacePos(node_id, ConvertToCPP_ImVec2(grid_pos));+}++CIMGUI_API cimgui::ImVec2 cimgui::ImNodesGetNodeScreenSpacePos(const int node_id)+{+ return ConvertFromCPP_ImVec2(::ImNodes::GetNodeScreenSpacePos(node_id));+}++CIMGUI_API cimgui::ImVec2 cimgui::ImNodesGetNodeEditorSpacePos(const int node_id)+{+ return ConvertFromCPP_ImVec2(::ImNodes::GetNodeEditorSpacePos(node_id));+}++CIMGUI_API cimgui::ImVec2 cimgui::ImNodesGetNodeGridSpacePos(const int node_id)+{+ return ConvertFromCPP_ImVec2(::ImNodes::GetNodeGridSpacePos(node_id));+}++CIMGUI_API void cimgui::ImNodesSnapNodeToGrid(int node_id)+{+ ::ImNodes::SnapNodeToGrid(node_id);+}++CIMGUI_API bool cimgui::ImNodesIsEditorHovered(void)+{+ return ::ImNodes::IsEditorHovered();+}++CIMGUI_API bool cimgui::ImNodesIsNodeHovered(int* node_id)+{+ return ::ImNodes::IsNodeHovered(node_id);+}++CIMGUI_API bool cimgui::ImNodesIsLinkHovered(int* link_id)+{+ return ::ImNodes::IsLinkHovered(link_id);+}++CIMGUI_API bool cimgui::ImNodesIsPinHovered(int* attribute_id)+{+ return ::ImNodes::IsPinHovered(attribute_id);+}++CIMGUI_API int cimgui::ImNodesNumSelectedNodes(void)+{+ return ::ImNodes::NumSelectedNodes();+}++CIMGUI_API int cimgui::ImNodesNumSelectedLinks(void)+{+ return ::ImNodes::NumSelectedLinks();+}++CIMGUI_API void cimgui::ImNodesGetSelectedNodes(int* node_ids)+{+ ::ImNodes::GetSelectedNodes(node_ids);+}++CIMGUI_API void cimgui::ImNodesGetSelectedLinks(int* link_ids)+{+ ::ImNodes::GetSelectedLinks(link_ids);+}++CIMGUI_API void cimgui::ImNodesClearNodeSelection(void)+{+ ::ImNodes::ClearNodeSelection();+}++CIMGUI_API void cimgui::ImNodesClearLinkSelection(void)+{+ ::ImNodes::ClearLinkSelection();+}++CIMGUI_API void cimgui::ImNodesSelectNode(int node_id)+{+ ::ImNodes::SelectNode(node_id);+}++CIMGUI_API void cimgui::ImNodesClearNodeSelectionInt(int node_id)+{+ ::ImNodes::ClearNodeSelection(node_id);+}++CIMGUI_API bool cimgui::ImNodesIsNodeSelected(int node_id)+{+ return ::ImNodes::IsNodeSelected(node_id);+}++CIMGUI_API void cimgui::ImNodesSelectLink(int link_id)+{+ ::ImNodes::SelectLink(link_id);+}++CIMGUI_API void cimgui::ImNodesClearLinkSelectionInt(int link_id)+{+ ::ImNodes::ClearLinkSelection(link_id);+}++CIMGUI_API bool cimgui::ImNodesIsLinkSelected(int link_id)+{+ return ::ImNodes::IsLinkSelected(link_id);+}++CIMGUI_API bool cimgui::ImNodesIsAttributeActive(void)+{+ return ::ImNodes::IsAttributeActive();+}++CIMGUI_API bool cimgui::ImNodesIsAnyAttributeActive(int* attribute_id)+{+ return ::ImNodes::IsAnyAttributeActive(attribute_id);+}++CIMGUI_API bool cimgui::ImNodesIsLinkStarted(int* started_at_attribute_id)+{+ return ::ImNodes::IsLinkStarted(started_at_attribute_id);+}++CIMGUI_API bool cimgui::ImNodesIsLinkDropped(int* started_at_attribute_id, bool including_detached_links)+{+ return ::ImNodes::IsLinkDropped(started_at_attribute_id, including_detached_links);+}++CIMGUI_API bool cimgui::ImNodesIsLinkCreated(int* started_at_attribute_id, int* ended_at_attribute_id, bool* created_from_snap)+{+ return ::ImNodes::IsLinkCreated(started_at_attribute_id, ended_at_attribute_id, created_from_snap);+}++CIMGUI_API bool cimgui::ImNodesIsLinkCreatedIntPtr(int* started_at_node_id, int* started_at_attribute_id, int* ended_at_node_id, int* ended_at_attribute_id, bool* created_from_snap)+{+ return ::ImNodes::IsLinkCreated(started_at_node_id, started_at_attribute_id, ended_at_node_id, ended_at_attribute_id, created_from_snap);+}++CIMGUI_API bool cimgui::ImNodesIsLinkDestroyed(int* link_id)+{+ return ::ImNodes::IsLinkDestroyed(link_id);+}++CIMGUI_API const char* cimgui::ImNodesSaveCurrentEditorStateToIniString(size_t* data_size)+{+ return ::ImNodes::SaveCurrentEditorStateToIniString(data_size);+}++CIMGUI_API const char* cimgui::ImNodesSaveEditorStateToIniString(const cimgui::ImNodesEditorContext* editor, size_t* data_size)+{+ return ::ImNodes::SaveEditorStateToIniString(reinterpret_cast<const ::ImNodesEditorContext*>(editor), data_size);+}++CIMGUI_API void cimgui::ImNodesLoadCurrentEditorStateFromIniString(const char* data, size_t data_size)+{+ ::ImNodes::LoadCurrentEditorStateFromIniString(data, data_size);+}++CIMGUI_API void cimgui::ImNodesLoadEditorStateFromIniString(cimgui::ImNodesEditorContext* editor, const char* data, size_t data_size)+{+ ::ImNodes::LoadEditorStateFromIniString(reinterpret_cast<::ImNodesEditorContext*>(editor), data, data_size);+}++CIMGUI_API void cimgui::ImNodesSaveCurrentEditorStateToIniFile(const char* file_name)+{+ ::ImNodes::SaveCurrentEditorStateToIniFile(file_name);+}++CIMGUI_API void cimgui::ImNodesSaveEditorStateToIniFile(const cimgui::ImNodesEditorContext* editor, const char* file_name)+{+ ::ImNodes::SaveEditorStateToIniFile(reinterpret_cast<const ::ImNodesEditorContext*>(editor), file_name);+}++CIMGUI_API void cimgui::ImNodesLoadCurrentEditorStateFromIniFile(const char* file_name)+{+ ::ImNodes::LoadCurrentEditorStateFromIniFile(file_name);+}++CIMGUI_API void cimgui::ImNodesLoadEditorStateFromIniFile(cimgui::ImNodesEditorContext* editor, const char* file_name)+{+ ::ImNodes::LoadEditorStateFromIniFile(reinterpret_cast<::ImNodesEditorContext*>(editor), file_name);+}
+ cbits/dcimnodes.h view
@@ -0,0 +1,435 @@+// THIS FILE HAS BEEN AUTO-GENERATED BY THE 'DEAR BINDINGS' GENERATOR.+// **DO NOT EDIT DIRECTLY**+// https://github.com/dearimgui/dear_bindings++#pragma once++#ifdef __cplusplus+extern "C"+{+#endif+// Auto-generated forward declarations for C header+typedef struct ImNodesIO_EmulateThreeButtonMouse_t ImNodesIO_EmulateThreeButtonMouse;+typedef struct ImNodesIO_LinkDetachWithModifierClick_t ImNodesIO_LinkDetachWithModifierClick;+typedef struct ImNodesIO_MultipleSelectModifier_t ImNodesIO_MultipleSelectModifier;+typedef struct ImNodesIO_t ImNodesIO;+typedef struct ImNodesStyle_t ImNodesStyle;+// ImDrawIdx: vertex index. [Compile-time configurable type]+// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).+// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.+#ifndef ImDrawIdx+typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)+#endif // #ifndef ImDrawIdx++#include <stddef.h>+#include "dcimgui.h"+#ifdef IMNODES_USER_CONFIG+#include IMNODES_USER_CONFIG+#endif // #ifdef IMNODES_USER_CONFIG+#ifndef ImNodes+#define ImNodes ImNodes+#endif // #ifndef ImNodes+typedef int ImNodesCol; // -> enum ImNodesCol_+typedef int ImNodesStyleVar; // -> enum ImNodesStyleVar_+typedef int ImNodesStyleFlags; // -> enum ImNodesStyleFlags_+typedef int ImNodesPinShape; // -> enum ImNodesPinShape_+typedef int ImNodesAttributeFlags; // -> enum ImNodesAttributeFlags_+typedef int ImNodesMiniMapLocation; // -> enum ImNodesMiniMapLocation_++typedef enum+{+ ImNodesCol_NodeBackground = 0,+ ImNodesCol_NodeBackgroundHovered,+ ImNodesCol_NodeBackgroundSelected,+ ImNodesCol_NodeOutline,+ ImNodesCol_TitleBar,+ ImNodesCol_TitleBarHovered,+ ImNodesCol_TitleBarSelected,+ ImNodesCol_Link,+ ImNodesCol_LinkHovered,+ ImNodesCol_LinkSelected,+ ImNodesCol_Pin,+ ImNodesCol_PinHovered,+ ImNodesCol_BoxSelector,+ ImNodesCol_BoxSelectorOutline,+ ImNodesCol_GridBackground,+ ImNodesCol_GridLine,+ ImNodesCol_GridLinePrimary,+ ImNodesCol_MiniMapBackground,+ ImNodesCol_MiniMapBackgroundHovered,+ ImNodesCol_MiniMapOutline,+ ImNodesCol_MiniMapOutlineHovered,+ ImNodesCol_MiniMapNodeBackground,+ ImNodesCol_MiniMapNodeBackgroundHovered,+ ImNodesCol_MiniMapNodeBackgroundSelected,+ ImNodesCol_MiniMapNodeOutline,+ ImNodesCol_MiniMapLink,+ ImNodesCol_MiniMapLinkSelected,+ ImNodesCol_MiniMapCanvas,+ ImNodesCol_MiniMapCanvasOutline,+ ImNodesCol_COUNT,+} ImNodesCol_;++typedef enum+{+ ImNodesStyleVar_GridSpacing = 0,+ ImNodesStyleVar_NodeCornerRounding,+ ImNodesStyleVar_NodePadding,+ ImNodesStyleVar_NodeBorderThickness,+ ImNodesStyleVar_LinkThickness,+ ImNodesStyleVar_LinkLineSegmentsPerLength,+ ImNodesStyleVar_LinkHoverDistance,+ ImNodesStyleVar_PinCircleRadius,+ ImNodesStyleVar_PinQuadSideLength,+ ImNodesStyleVar_PinTriangleSideLength,+ ImNodesStyleVar_PinLineThickness,+ ImNodesStyleVar_PinHoverRadius,+ ImNodesStyleVar_PinOffset,+ ImNodesStyleVar_MiniMapPadding,+ ImNodesStyleVar_MiniMapOffset,+ ImNodesStyleVar_COUNT,+} ImNodesStyleVar_;++typedef enum+{+ ImNodesStyleFlags_None = 0,+ ImNodesStyleFlags_NodeOutline = 1<<0,+ ImNodesStyleFlags_GridLines = 1<<2,+ ImNodesStyleFlags_GridLinesPrimary = 1<<3,+ ImNodesStyleFlags_GridSnapping = 1<<4,+} ImNodesStyleFlags_;++typedef enum+{+ ImNodesPinShape_Circle,+ ImNodesPinShape_CircleFilled,+ ImNodesPinShape_Triangle,+ ImNodesPinShape_TriangleFilled,+ ImNodesPinShape_Quad,+ ImNodesPinShape_QuadFilled,+} ImNodesPinShape_;++// This enum controls the way the attribute pins behave.+typedef enum+{+ ImNodesAttributeFlags_None = 0,+ // Allow detaching a link by left-clicking and dragging the link at a pin it is connected to.+ // NOTE: the user has to actually delete the link for this to work. A deleted link can be+ // detected by calling IsLinkDestroyed() after EndNodeEditor().+ ImNodesAttributeFlags_EnableLinkDetachWithDragClick = 1<<0,+ // Visual snapping of an in progress link will trigger IsLink Created/Destroyed events. Allows+ // for previewing the creation of a link while dragging it across attributes. See here for demo:+ // https://github.com/Nelarius/imnodes/issues/41#issuecomment-647132113 NOTE: the user has to+ // actually delete the link for this to work. A deleted link can be detected by calling+ // IsLinkDestroyed() after EndNodeEditor().+ ImNodesAttributeFlags_EnableLinkCreationOnSnap = 1<<1,+} ImNodesAttributeFlags_;++struct ImNodesIO_EmulateThreeButtonMouse_t+{+ // The keyboard modifier to use in combination with mouse left click to pan the editor view.+ // Set to NULL by default. To enable this feature, set the modifier to point to a boolean+ // indicating the state of a modifier. For example,+ //+ // ImNodes::GetIO().EmulateThreeButtonMouse.Modifier = &ImGui::GetIO().KeyAlt;+ const bool* Modifier;+};+struct ImNodesIO_LinkDetachWithModifierClick_t+{+ // Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL+ // by default. To enable the feature, set the modifier to point to a boolean indicating the+ // state of a modifier. For example,+ //+ // ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;+ //+ // Left-clicking a link with this modifier pressed will detach that link. NOTE: the user has+ // to actually delete the link for this to work. A deleted link can be detected by calling+ // IsLinkDestroyed() after EndNodeEditor().+ const bool* Modifier;+};+struct ImNodesIO_MultipleSelectModifier_t+{+ // Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL+ // by default. To enable the feature, set the modifier to point to a boolean indicating the+ // state of a modifier. For example,+ //+ // ImNodes::GetIO().MultipleSelectModifier.Modifier = &ImGui::GetIO().KeyCtrl;+ //+ // Left-clicking a node with this modifier pressed will add the node to the list of+ // currently selected nodes. If this value is NULL, the Ctrl key will be used.+ const bool* Modifier;+};+struct ImNodesIO_t+{+ ImNodesIO_EmulateThreeButtonMouse EmulateThreeButtonMouse;++ ImNodesIO_LinkDetachWithModifierClick LinkDetachWithModifierClick;++ ImNodesIO_MultipleSelectModifier MultipleSelectModifier;++ // Holding alt mouse button pans the node area, by default middle mouse button will be used+ // Set based on ImGuiMouseButton values+ int AltMouseButton;++ // Panning speed when dragging an element and mouse is outside the main editor view.+ float AutoPanningSpeed;+};++struct ImNodesStyle_t+{+ float GridSpacing;++ float NodeCornerRounding;+ ImVec2 NodePadding;+ float NodeBorderThickness;++ float LinkThickness;+ float LinkLineSegmentsPerLength;+ float LinkHoverDistance;++ // The following variables control the look and behavior of the pins. The default size of each+ // pin shape is balanced to occupy approximately the same surface area on the screen.++ // The circle radius used when the pin shape is either ImNodesPinShape_Circle or+ // ImNodesPinShape_CircleFilled.+ float PinCircleRadius;+ // The quad side length used when the shape is either ImNodesPinShape_Quad or+ // ImNodesPinShape_QuadFilled.+ float PinQuadSideLength;+ // The equilateral triangle side length used when the pin shape is either+ // ImNodesPinShape_Triangle or ImNodesPinShape_TriangleFilled.+ float PinTriangleSideLength;+ // The thickness of the line used when the pin shape is not filled.+ float PinLineThickness;+ // The radius from the pin's center position inside of which it is detected as being hovered+ // over.+ float PinHoverRadius;+ // Offsets the pins' positions from the edge of the node to the outside of the node.+ float PinOffset;++ // Mini-map padding size between mini-map edge and mini-map content.+ ImVec2 MiniMapPadding;+ // Mini-map offset from the screen side.+ ImVec2 MiniMapOffset;++ // By default, ImNodesStyleFlags_NodeOutline and ImNodesStyleFlags_Gridlines are enabled.+ ImNodesStyleFlags Flags;+ // Set these mid-frame using Push/PopColorStyle. You can index this color array with with a+ // ImNodesCol value.+ unsigned int Colors[ImNodesCol_COUNT];+};++typedef enum+{+ ImNodesMiniMapLocation_BottomLeft,+ ImNodesMiniMapLocation_BottomRight,+ ImNodesMiniMapLocation_TopLeft,+ ImNodesMiniMapLocation_TopRight,+} ImNodesMiniMapLocation_;++typedef struct ImGuiContext_t ImGuiContext;+typedef struct ImVec2_t ImVec2;++typedef struct ImNodesContext_t ImNodesContext;++// An editor context corresponds to a set of nodes in a single workspace (created with a single+// Begin/EndNodeEditor pair)+//+// By default, the library creates an editor context behind the scenes, so using any of the imnodes+// functions doesn't require you to explicitly create a context.+typedef struct ImNodesEditorContext_t ImNodesEditorContext;++// Callback type used to specify special behavior when hovering a node in the minimap+#ifndef ImNodesMiniMapNodeHoveringCallback+typedef void (*ImNodesMiniMapNodeHoveringCallback)(int, void*);+#endif // #ifndef ImNodesMiniMapNodeHoveringCallback+#ifndef ImNodesMiniMapNodeHoveringCallbackUserData+typedef void* ImNodesMiniMapNodeHoveringCallbackUserData;+#endif // #ifndef ImNodesMiniMapNodeHoveringCallbackUserData+// Call this function if you are compiling imnodes in to a dll, separate from ImGui. Calling this+// function sets the GImGui global variable, which is not shared across dll boundaries.+CIMGUI_API void ImNodesSetImGuiContext(ImGuiContext* ctx);++CIMGUI_API ImNodesContext* ImNodesCreateContext(void);+CIMGUI_API void ImNodesDestroyContext(ImNodesContext* ctx /* = NULL */); // NULL = destroy current context+CIMGUI_API ImNodesContext* ImNodesGetCurrentContext(void);+CIMGUI_API void ImNodesSetCurrentContext(ImNodesContext* ctx);++CIMGUI_API ImNodesEditorContext* ImNodesEditorContextCreate(void);+CIMGUI_API void ImNodesEditorContextFree(ImNodesEditorContext*);+CIMGUI_API void ImNodesEditorContextSet(ImNodesEditorContext*);+CIMGUI_API ImVec2 ImNodesEditorContextGetPanning(void);+CIMGUI_API void ImNodesEditorContextResetPanning(ImVec2 pos);+CIMGUI_API void ImNodesEditorContextMoveToNode(const int node_id);++CIMGUI_API ImNodesIO* ImNodesGetIO(void);++// Returns the global style struct. See the struct declaration for default values.+CIMGUI_API ImNodesStyle* ImNodesGetStyle(void);+// Style presets matching the dear imgui styles of the same name. If dest is NULL, the active+// context's ImNodesStyle instance will be used as the destination.+CIMGUI_API void ImNodesStyleColorsDark(ImNodesStyle* dest /* = NULL */); // on by default+CIMGUI_API void ImNodesStyleColorsClassic(ImNodesStyle* dest /* = NULL */);+CIMGUI_API void ImNodesStyleColorsLight(ImNodesStyle* dest /* = NULL */);+// Get a string corresponding to the enum value (for display, saving, etc.).+CIMGUI_API const char* ImNodesGetStyleColorName(ImNodesCol idx);++// The top-level function call. Call this before calling BeginNode/EndNode. Calling this function+// will result the node editor grid workspace being rendered.+CIMGUI_API void ImNodesBeginNodeEditor(void);+CIMGUI_API void ImNodesEndNodeEditor(void);++// Add a navigable minimap to the editor; call before EndNodeEditor after all+// nodes and links have been specified+CIMGUI_API void ImNodesMiniMap(const float minimap_size_fraction /* = 0.2f */, const ImNodesMiniMapLocation location /* = ImNodesMiniMapLocation_TopLeft */, const ImNodesMiniMapNodeHoveringCallback node_hovering_callback /* = NULL */, const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data /* = NULL */);++// Use PushColorStyle and PopColorStyle to modify ImNodesStyle::Colors mid-frame.+CIMGUI_API void ImNodesPushColorStyle(ImNodesCol item, unsigned int color);+CIMGUI_API void ImNodesPopColorStyle(void);+CIMGUI_API void ImNodesPushStyleVar(ImNodesStyleVar style_item, float value);+CIMGUI_API void ImNodesPushStyleVarImVec2(ImNodesStyleVar style_item, ImVec2 value);+CIMGUI_API void ImNodesPopStyleVar(int count /* = 1 */);++// id can be any positive or negative integer, but INT_MIN is currently reserved for internal use.+CIMGUI_API void ImNodesBeginNode(int id);+CIMGUI_API void ImNodesEndNode(void);++CIMGUI_API ImVec2 ImNodesGetNodeDimensions(int id);++// Place your node title bar content (such as the node title, using ImGui::Text) between the+// following function calls. These functions have to be called before adding any attributes, or the+// layout of the node will be incorrect.+CIMGUI_API void ImNodesBeginNodeTitleBar(void);+CIMGUI_API void ImNodesEndNodeTitleBar(void);++// Attributes are ImGui UI elements embedded within the node. Attributes can have pin shapes+// rendered next to them. Links are created between pins.+//+// The activity status of an attribute can be checked via the IsAttributeActive() and+// IsAnyAttributeActive() function calls. This is one easy way of checking for any changes made to+// an attribute's drag float UI, for instance.+//+// Each attribute id must be unique.++// Create an input attribute block. The pin is rendered on left side.+CIMGUI_API void ImNodesBeginInputAttribute(int id, ImNodesPinShape shape /* = ImNodesPinShape_CircleFilled */);+CIMGUI_API void ImNodesEndInputAttribute(void);+// Create an output attribute block. The pin is rendered on the right side.+CIMGUI_API void ImNodesBeginOutputAttribute(int id, ImNodesPinShape shape /* = ImNodesPinShape_CircleFilled */);+CIMGUI_API void ImNodesEndOutputAttribute(void);+// Create a static attribute block. A static attribute has no pin, and therefore can't be linked to+// anything. However, you can still use IsAttributeActive() and IsAnyAttributeActive() to check for+// attribute activity.+CIMGUI_API void ImNodesBeginStaticAttribute(int id);+CIMGUI_API void ImNodesEndStaticAttribute(void);++// Push a single AttributeFlags value. By default, only AttributeFlags_None is set.+CIMGUI_API void ImNodesPushAttributeFlag(ImNodesAttributeFlags flag);+CIMGUI_API void ImNodesPopAttributeFlag(void);++// Render a link between attributes.+// The attributes ids used here must match the ids used in Begin(Input|Output)Attribute function+// calls. The order of start_attr and end_attr doesn't make a difference for rendering the link.+CIMGUI_API void ImNodesLink(int id, int start_attribute_id, int end_attribute_id);++// Enable or disable the ability to click and drag a specific node.+CIMGUI_API void ImNodesSetNodeDraggable(int node_id, const bool draggable);++// The node's position can be expressed in three coordinate systems:+// * screen space coordinates, -- the origin is the upper left corner of the window.+// * editor space coordinates -- the origin is the upper left corner of the node editor window+// * grid space coordinates, -- the origin is the upper left corner of the node editor window,+// translated by the current editor panning vector (see EditorContextGetPanning() and+// EditorContextResetPanning())++// Use the following functions to get and set the node's coordinates in these coordinate systems.++CIMGUI_API void ImNodesSetNodeScreenSpacePos(int node_id, ImVec2 screen_space_pos);+CIMGUI_API void ImNodesSetNodeEditorSpacePos(int node_id, ImVec2 editor_space_pos);+CIMGUI_API void ImNodesSetNodeGridSpacePos(int node_id, ImVec2 grid_pos);++CIMGUI_API ImVec2 ImNodesGetNodeScreenSpacePos(const int node_id);+CIMGUI_API ImVec2 ImNodesGetNodeEditorSpacePos(const int node_id);+CIMGUI_API ImVec2 ImNodesGetNodeGridSpacePos(const int node_id);++// If ImNodesStyleFlags_GridSnapping is enabled, snap the specified node's origin to the grid.+CIMGUI_API void ImNodesSnapNodeToGrid(int node_id);++// Returns true if the current node editor canvas is being hovered over by the mouse, and is not+// blocked by any other windows.+CIMGUI_API bool ImNodesIsEditorHovered(void);+// The following functions return true if a UI element is being hovered over by the mouse cursor.+// Assigns the id of the UI element being hovered over to the function argument. Use these functions+// after EndNodeEditor() has been called.+CIMGUI_API bool ImNodesIsNodeHovered(int* node_id);+CIMGUI_API bool ImNodesIsLinkHovered(int* link_id);+CIMGUI_API bool ImNodesIsPinHovered(int* attribute_id);++// Use The following two functions to query the number of selected nodes or links in the current+// editor. Use after calling EndNodeEditor().+CIMGUI_API int ImNodesNumSelectedNodes(void);+CIMGUI_API int ImNodesNumSelectedLinks(void);+// Get the selected node/link ids. The pointer argument should point to an integer array with at+// least as many elements as the respective NumSelectedNodes/NumSelectedLinks function call+// returned.+CIMGUI_API void ImNodesGetSelectedNodes(int* node_ids);+CIMGUI_API void ImNodesGetSelectedLinks(int* link_ids);+// Clears the list of selected nodes/links. Useful if you want to delete a selected node or link.+CIMGUI_API void ImNodesClearNodeSelection(void);+CIMGUI_API void ImNodesClearLinkSelection(void);+// Use the following functions to add or remove individual nodes or links from the current editors+// selection. Note that all functions require the id to be an existing valid id for this editor.+// Select-functions has the precondition that the object is currently considered unselected.+// Clear-functions has the precondition that the object is currently considered selected.+// Preconditions listed above can be checked via IsNodeSelected/IsLinkSelected if not already+// known.+CIMGUI_API void ImNodesSelectNode(int node_id);+CIMGUI_API void ImNodesClearNodeSelectionInt(int node_id);+CIMGUI_API bool ImNodesIsNodeSelected(int node_id);+CIMGUI_API void ImNodesSelectLink(int link_id);+CIMGUI_API void ImNodesClearLinkSelectionInt(int link_id);+CIMGUI_API bool ImNodesIsLinkSelected(int link_id);++// Was the previous attribute active? This will continuously return true while the left mouse button+// is being pressed over the UI content of the attribute.+CIMGUI_API bool ImNodesIsAttributeActive(void);+// Was any attribute active? If so, sets the active attribute id to the output function argument.+CIMGUI_API bool ImNodesIsAnyAttributeActive(int* attribute_id /* = NULL */);++// Use the following functions to query a change of state for an existing link, or new link. Call+// these after EndNodeEditor().++// Did the user start dragging a new link from a pin?+CIMGUI_API bool ImNodesIsLinkStarted(int* started_at_attribute_id);+// Did the user drop the dragged link before attaching it to a pin?+// There are two different kinds of situations to consider when handling this event:+// 1) a link which is created at a pin and then dropped+// 2) an existing link which is detached from a pin and then dropped+// Use the including_detached_links flag to control whether this function triggers when the user+// detaches a link and drops it.+CIMGUI_API bool ImNodesIsLinkDropped(int* started_at_attribute_id /* = NULL */, bool including_detached_links /* = true */);+// Did the user finish creating a new link?+CIMGUI_API bool ImNodesIsLinkCreated(int* started_at_attribute_id, int* ended_at_attribute_id, bool* created_from_snap /* = NULL */);+CIMGUI_API bool ImNodesIsLinkCreatedIntPtr(int* started_at_node_id, int* started_at_attribute_id, int* ended_at_node_id, int* ended_at_attribute_id, bool* created_from_snap /* = NULL */);++// Was an existing link detached from a pin by the user? The detached link's id is assigned to the+// output argument link_id.+CIMGUI_API bool ImNodesIsLinkDestroyed(int* link_id);++// Use the following functions to write the editor context's state to a string, or directly to a+// file. The editor context is serialized in the INI file format.++CIMGUI_API const char* ImNodesSaveCurrentEditorStateToIniString(size_t* data_size /* = NULL */);+CIMGUI_API const char* ImNodesSaveEditorStateToIniString(const ImNodesEditorContext* editor, size_t* data_size /* = NULL */);++CIMGUI_API void ImNodesLoadCurrentEditorStateFromIniString(const char* data, size_t data_size);+CIMGUI_API void ImNodesLoadEditorStateFromIniString(ImNodesEditorContext* editor, const char* data, size_t data_size);++CIMGUI_API void ImNodesSaveCurrentEditorStateToIniFile(const char* file_name);+CIMGUI_API void ImNodesSaveEditorStateToIniFile(const ImNodesEditorContext* editor, const char* file_name);++CIMGUI_API void ImNodesLoadCurrentEditorStateFromIniFile(const char* file_name);+CIMGUI_API void ImNodesLoadEditorStateFromIniFile(ImNodesEditorContext* editor, const char* file_name);+#ifdef __cplusplus+} // End of extern "C" block+#endif
+ cbits/imnodes/imnodes.cpp view
@@ -0,0 +1,3326 @@+// the structure of this file:+//+// [SECTION] bezier curve helpers+// [SECTION] draw list helper+// [SECTION] ui state logic+// [SECTION] render helpers+// [SECTION] API implementation++#include "imnodes_internal.h"++// Check minimum ImGui version+#define MINIMUM_COMPATIBLE_IMGUI_VERSION 17400+#if IMGUI_VERSION_NUM < MINIMUM_COMPATIBLE_IMGUI_VERSION+#error "Minimum ImGui version requirement not met -- please use a newer version!"+#endif++#include <limits.h>+#include <math.h>+#include <new>+#include <stdint.h>+#include <stdio.h> // for fwrite, ssprintf, sscanf+#include <stdlib.h>+#include <string.h> // strlen, strncmp++// Use secure CRT function variants to avoid MSVC compiler errors+#ifdef _MSC_VER+#define sscanf sscanf_s+#endif++ImNodesContext* GImNodes = NULL;++namespace IMNODES_NAMESPACE+{+namespace+{+// [SECTION] bezier curve helpers++struct CubicBezier+{+ ImVec2 P0, P1, P2, P3;+ int NumSegments;+};++inline ImVec2 EvalCubicBezier(+ const float t,+ const ImVec2& P0,+ const ImVec2& P1,+ const ImVec2& P2,+ const ImVec2& P3)+{+ // B(t) = (1-t)**3 p0 + 3(1 - t)**2 t P1 + 3(1-t)t**2 P2 + t**3 P3++ const float u = 1.0f - t;+ const float b0 = u * u * u;+ const float b1 = 3 * u * u * t;+ const float b2 = 3 * u * t * t;+ const float b3 = t * t * t;+ return ImVec2(+ b0 * P0.x + b1 * P1.x + b2 * P2.x + b3 * P3.x,+ b0 * P0.y + b1 * P1.y + b2 * P2.y + b3 * P3.y);+}++// Calculates the closest point along each bezier curve segment.+ImVec2 GetClosestPointOnCubicBezier(const int num_segments, const ImVec2& p, const CubicBezier& cb)+{+ IM_ASSERT(num_segments > 0);+ ImVec2 p_last = cb.P0;+ ImVec2 p_closest;+ float p_closest_dist = FLT_MAX;+ float t_step = 1.0f / (float)num_segments;+ for (int i = 1; i <= num_segments; ++i)+ {+ ImVec2 p_current = EvalCubicBezier(t_step * i, cb.P0, cb.P1, cb.P2, cb.P3);+ ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);+ float dist = ImLengthSqr(p - p_line);+ if (dist < p_closest_dist)+ {+ p_closest = p_line;+ p_closest_dist = dist;+ }+ p_last = p_current;+ }+ return p_closest;+}++inline float GetDistanceToCubicBezier(+ const ImVec2& pos,+ const CubicBezier& cubic_bezier,+ const int num_segments)+{+ const ImVec2 point_on_curve = GetClosestPointOnCubicBezier(num_segments, pos, cubic_bezier);++ const ImVec2 to_curve = point_on_curve - pos;+ return ImSqrt(ImLengthSqr(to_curve));+}++inline ImRect GetContainingRectForCubicBezier(const CubicBezier& cb)+{+ const ImVec2 min = ImVec2(ImMin(cb.P0.x, cb.P3.x), ImMin(cb.P0.y, cb.P3.y));+ const ImVec2 max = ImVec2(ImMax(cb.P0.x, cb.P3.x), ImMax(cb.P0.y, cb.P3.y));++ const float hover_distance = GImNodes->Style.LinkHoverDistance;++ ImRect rect(min, max);+ rect.Add(cb.P1);+ rect.Add(cb.P2);+ rect.Expand(ImVec2(hover_distance, hover_distance));++ return rect;+}++inline CubicBezier GetCubicBezier(+ ImVec2 start,+ ImVec2 end,+ const ImNodesAttributeType start_type,+ const float line_segments_per_length)+{+ IM_ASSERT(+ (start_type == ImNodesAttributeType_Input) || (start_type == ImNodesAttributeType_Output));+ if (start_type == ImNodesAttributeType_Input)+ {+ ImSwap(start, end);+ }++ const float link_length = ImSqrt(ImLengthSqr(end - start));+ const ImVec2 offset = ImVec2(0.25f * link_length, 0.f);+ CubicBezier cubic_bezier;+ cubic_bezier.P0 = start;+ cubic_bezier.P1 = start + offset;+ cubic_bezier.P2 = end - offset;+ cubic_bezier.P3 = end;+ cubic_bezier.NumSegments = ImMax(static_cast<int>(link_length * line_segments_per_length), 1);+ return cubic_bezier;+}++inline float EvalImplicitLineEq(const ImVec2& p1, const ImVec2& p2, const ImVec2& p)+{+ return (p2.y - p1.y) * p.x + (p1.x - p2.x) * p.y + (p2.x * p1.y - p1.x * p2.y);+}++inline int Sign(float val) { return int(val > 0.0f) - int(val < 0.0f); }++inline bool RectangleOverlapsLineSegment(const ImRect& rect, const ImVec2& p1, const ImVec2& p2)+{+ // Trivial case: rectangle contains an endpoint+ if (rect.Contains(p1) || rect.Contains(p2))+ {+ return true;+ }++ // Flip rectangle if necessary+ ImRect flip_rect = rect;++ if (flip_rect.Min.x > flip_rect.Max.x)+ {+ ImSwap(flip_rect.Min.x, flip_rect.Max.x);+ }++ if (flip_rect.Min.y > flip_rect.Max.y)+ {+ ImSwap(flip_rect.Min.y, flip_rect.Max.y);+ }++ // Trivial case: line segment lies to one particular side of rectangle+ if ((p1.x < flip_rect.Min.x && p2.x < flip_rect.Min.x) ||+ (p1.x > flip_rect.Max.x && p2.x > flip_rect.Max.x) ||+ (p1.y < flip_rect.Min.y && p2.y < flip_rect.Min.y) ||+ (p1.y > flip_rect.Max.y && p2.y > flip_rect.Max.y))+ {+ return false;+ }++ const int corner_signs[4] = {+ Sign(EvalImplicitLineEq(p1, p2, flip_rect.Min)),+ Sign(EvalImplicitLineEq(p1, p2, ImVec2(flip_rect.Max.x, flip_rect.Min.y))),+ Sign(EvalImplicitLineEq(p1, p2, ImVec2(flip_rect.Min.x, flip_rect.Max.y))),+ Sign(EvalImplicitLineEq(p1, p2, flip_rect.Max))};++ int sum = 0;+ int sum_abs = 0;++ for (int i = 0; i < 4; ++i)+ {+ sum += corner_signs[i];+ sum_abs += abs(corner_signs[i]);+ }++ // At least one corner of rectangle lies on a different side of line segment+ return abs(sum) != sum_abs;+}++inline bool RectangleOverlapsBezier(const ImRect& rectangle, const CubicBezier& cubic_bezier)+{+ ImVec2 current =+ EvalCubicBezier(0.f, cubic_bezier.P0, cubic_bezier.P1, cubic_bezier.P2, cubic_bezier.P3);+ const float dt = 1.0f / cubic_bezier.NumSegments;+ for (int s = 0; s < cubic_bezier.NumSegments; ++s)+ {+ ImVec2 next = EvalCubicBezier(+ static_cast<float>((s + 1) * dt),+ cubic_bezier.P0,+ cubic_bezier.P1,+ cubic_bezier.P2,+ cubic_bezier.P3);+ if (RectangleOverlapsLineSegment(rectangle, current, next))+ {+ return true;+ }+ current = next;+ }+ return false;+}++inline bool RectangleOverlapsLink(+ const ImRect& rectangle,+ const ImVec2& start,+ const ImVec2& end,+ const ImNodesAttributeType start_type)+{+ // First level: simple rejection test via rectangle overlap:++ ImRect lrect = ImRect(start, end);+ if (lrect.Min.x > lrect.Max.x)+ {+ ImSwap(lrect.Min.x, lrect.Max.x);+ }++ if (lrect.Min.y > lrect.Max.y)+ {+ ImSwap(lrect.Min.y, lrect.Max.y);+ }++ if (rectangle.Overlaps(lrect))+ {+ // First, check if either one or both endpoinds are trivially contained+ // in the rectangle++ if (rectangle.Contains(start) || rectangle.Contains(end))+ {+ return true;+ }++ // Second level of refinement: do a more expensive test against the+ // link++ const CubicBezier cubic_bezier =+ GetCubicBezier(start, end, start_type, GImNodes->Style.LinkLineSegmentsPerLength);+ return RectangleOverlapsBezier(rectangle, cubic_bezier);+ }++ return false;+}++// [SECTION] coordinate space conversion helpers++inline ImVec2 ScreenSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v)+{+ return v - GImNodes->CanvasOriginScreenSpace - editor.Panning;+}++inline ImRect ScreenSpaceToGridSpace(const ImNodesEditorContext& editor, const ImRect& r)+{+ return ImRect(ScreenSpaceToGridSpace(editor, r.Min), ScreenSpaceToGridSpace(editor, r.Max));+}++inline ImVec2 GridSpaceToScreenSpace(const ImNodesEditorContext& editor, const ImVec2& v)+{+ return v + GImNodes->CanvasOriginScreenSpace + editor.Panning;+}++inline ImVec2 GridSpaceToEditorSpace(const ImNodesEditorContext& editor, const ImVec2& v)+{+ return v + editor.Panning;+}++inline ImVec2 EditorSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v)+{+ return v - editor.Panning;+}++inline ImVec2 EditorSpaceToScreenSpace(const ImVec2& v)+{+ return GImNodes->CanvasOriginScreenSpace + v;+}++inline ImVec2 MiniMapSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v)+{+ return (v - editor.MiniMapContentScreenSpace.Min) / editor.MiniMapScaling ++ editor.GridContentBounds.Min;+}++inline ImVec2 ScreenSpaceToMiniMapSpace(const ImNodesEditorContext& editor, const ImVec2& v)+{+ return (ScreenSpaceToGridSpace(editor, v) - editor.GridContentBounds.Min) *+ editor.MiniMapScaling ++ editor.MiniMapContentScreenSpace.Min;+}++inline ImRect ScreenSpaceToMiniMapSpace(const ImNodesEditorContext& editor, const ImRect& r)+{+ return ImRect(+ ScreenSpaceToMiniMapSpace(editor, r.Min), ScreenSpaceToMiniMapSpace(editor, r.Max));+}++// [SECTION] draw list helper++void ImDrawListGrowChannels(ImDrawList* draw_list, const int num_channels)+{+ ImDrawListSplitter& splitter = draw_list->_Splitter;++ if (splitter._Count == 1)+ {+ splitter.Split(draw_list, num_channels + 1);+ return;+ }++ // NOTE: this logic has been lifted from ImDrawListSplitter::Split with slight modifications+ // to allow nested splits. The main modification is that we only create new ImDrawChannel+ // instances after splitter._Count, instead of over the whole splitter._Channels array like+ // the regular ImDrawListSplitter::Split method does.++ const int old_channel_capacity = splitter._Channels.Size;+ // NOTE: _Channels is not resized down, and therefore _Count <= _Channels.size()!+ const int old_channel_count = splitter._Count;+ const int requested_channel_count = old_channel_count + num_channels;+ if (old_channel_capacity < old_channel_count + num_channels)+ {+ splitter._Channels.resize(requested_channel_count);+ }++ splitter._Count = requested_channel_count;++ for (int i = old_channel_count; i < requested_channel_count; ++i)+ {+ ImDrawChannel& channel = splitter._Channels[i];++ // If we're inside the old capacity region of the array, we need to reuse the existing+ // memory of the command and index buffers.+ if (i < old_channel_capacity)+ {+ channel._CmdBuffer.resize(0);+ channel._IdxBuffer.resize(0);+ }+ // Else, we need to construct new draw channels.+ else+ {+ IM_PLACEMENT_NEW(&channel) ImDrawChannel();+ }++ {+ ImDrawCmd draw_cmd;+ draw_cmd.ClipRect = draw_list->_ClipRectStack.back();+#if IMGUI_VERSION_NUM < 19200+ draw_cmd.TextureId = draw_list->_TextureIdStack.back();+#else+ draw_cmd.TexRef = draw_list->_TextureStack.back();+#endif+ channel._CmdBuffer.push_back(draw_cmd);+ }+ }+}++void ImDrawListSplitterSwapChannels(+ ImDrawListSplitter& splitter,+ const int lhs_idx,+ const int rhs_idx)+{+ if (lhs_idx == rhs_idx)+ {+ return;+ }++ IM_ASSERT(lhs_idx >= 0 && lhs_idx < splitter._Count);+ IM_ASSERT(rhs_idx >= 0 && rhs_idx < splitter._Count);++ ImDrawChannel& lhs_channel = splitter._Channels[lhs_idx];+ ImDrawChannel& rhs_channel = splitter._Channels[rhs_idx];+ lhs_channel._CmdBuffer.swap(rhs_channel._CmdBuffer);+ lhs_channel._IdxBuffer.swap(rhs_channel._IdxBuffer);++ const int current_channel = splitter._Current;++ if (current_channel == lhs_idx)+ {+ splitter._Current = rhs_idx;+ }+ else if (current_channel == rhs_idx)+ {+ splitter._Current = lhs_idx;+ }+}++void DrawListSet(ImDrawList* window_draw_list)+{+ GImNodes->CanvasDrawList = window_draw_list;+ GImNodes->NodeIdxToSubmissionIdx.Clear();+ GImNodes->NodeIdxSubmissionOrder.clear();+}++// The draw list channels are structured as follows. First we have our base channel, the canvas grid+// on which we render the grid lines in BeginNodeEditor(). The base channel is the reason+// draw_list_submission_idx_to_background_channel_idx offsets the index by one. Each BeginNode()+// call appends two new draw channels, for the node background and foreground. The node foreground+// is the channel into which the node's ImGui content is rendered. Finally, in EndNodeEditor() we+// append one last draw channel for rendering the selection box and the incomplete link on top of+// everything else.+//+// +----------+----------+----------+----------+----------+----------++// | | | | | | |+// |canvas |node |node |... |... |click |+// |grid |background|foreground| | |interaction+// | | | | | | |+// +----------+----------+----------+----------+----------+----------++// | |+// | submission idx |+// | |+// -----------------------++void DrawListAddNode(const int node_idx)+{+ GImNodes->NodeIdxToSubmissionIdx.SetInt(+ static_cast<ImGuiID>(node_idx), GImNodes->NodeIdxSubmissionOrder.Size);+ GImNodes->NodeIdxSubmissionOrder.push_back(node_idx);+ ImDrawListGrowChannels(GImNodes->CanvasDrawList, 2);+}++void DrawListAppendClickInteractionChannel()+{+ // NOTE: don't use this function outside of EndNodeEditor. Using this before all nodes have been+ // added will screw up the node draw order.+ ImDrawListGrowChannels(GImNodes->CanvasDrawList, 1);+}++int DrawListSubmissionIdxToBackgroundChannelIdx(const int submission_idx)+{+ // NOTE: the first channel is the canvas background, i.e. the grid+ return 1 + 2 * submission_idx;+}++int DrawListSubmissionIdxToForegroundChannelIdx(const int submission_idx)+{+ return DrawListSubmissionIdxToBackgroundChannelIdx(submission_idx) + 1;+}++void DrawListActivateClickInteractionChannel()+{+ GImNodes->CanvasDrawList->_Splitter.SetCurrentChannel(+ GImNodes->CanvasDrawList, GImNodes->CanvasDrawList->_Splitter._Count - 1);+}++void DrawListActivateCurrentNodeForeground()+{+ const int foreground_channel_idx =+ DrawListSubmissionIdxToForegroundChannelIdx(GImNodes->NodeIdxSubmissionOrder.Size - 1);+ GImNodes->CanvasDrawList->_Splitter.SetCurrentChannel(+ GImNodes->CanvasDrawList, foreground_channel_idx);+}++void DrawListActivateNodeBackground(const int node_idx)+{+ const int submission_idx =+ GImNodes->NodeIdxToSubmissionIdx.GetInt(static_cast<ImGuiID>(node_idx), -1);+ // There is a discrepancy in the submitted node count and the rendered node count! Did you call+ // one of the following functions+ // * EditorContextMoveToNode+ // * SetNodeScreenSpacePos+ // * SetNodeGridSpacePos+ // * SetNodeDraggable+ // after the BeginNode/EndNode function calls?+ IM_ASSERT(submission_idx != -1);+ const int background_channel_idx = DrawListSubmissionIdxToBackgroundChannelIdx(submission_idx);+ GImNodes->CanvasDrawList->_Splitter.SetCurrentChannel(+ GImNodes->CanvasDrawList, background_channel_idx);+}++void DrawListSwapSubmissionIndices(const int lhs_idx, const int rhs_idx)+{+ IM_ASSERT(lhs_idx != rhs_idx);++ const int lhs_foreground_channel_idx = DrawListSubmissionIdxToForegroundChannelIdx(lhs_idx);+ const int lhs_background_channel_idx = DrawListSubmissionIdxToBackgroundChannelIdx(lhs_idx);+ const int rhs_foreground_channel_idx = DrawListSubmissionIdxToForegroundChannelIdx(rhs_idx);+ const int rhs_background_channel_idx = DrawListSubmissionIdxToBackgroundChannelIdx(rhs_idx);++ ImDrawListSplitterSwapChannels(+ GImNodes->CanvasDrawList->_Splitter,+ lhs_background_channel_idx,+ rhs_background_channel_idx);+ ImDrawListSplitterSwapChannels(+ GImNodes->CanvasDrawList->_Splitter,+ lhs_foreground_channel_idx,+ rhs_foreground_channel_idx);+}++void DrawListSortChannelsByDepth(const ImVector<int>& node_idx_depth_order)+{+ if (GImNodes->NodeIdxToSubmissionIdx.Data.Size < 2)+ {+ return;+ }++ IM_ASSERT(node_idx_depth_order.Size == GImNodes->NodeIdxSubmissionOrder.Size);++ int start_idx = node_idx_depth_order.Size - 1;++ while (node_idx_depth_order[start_idx] == GImNodes->NodeIdxSubmissionOrder[start_idx])+ {+ if (--start_idx == 0)+ {+ // early out if submission order and depth order are the same+ return;+ }+ }++ // TODO: this is an O(N^2) algorithm. It might be worthwhile revisiting this to see if the time+ // complexity can be reduced.++ for (int depth_idx = start_idx; depth_idx > 0; --depth_idx)+ {+ const int node_idx = node_idx_depth_order[depth_idx];++ // Find the current index of the node_idx in the submission order array+ int submission_idx = -1;+ for (int i = 0; i < GImNodes->NodeIdxSubmissionOrder.Size; ++i)+ {+ if (GImNodes->NodeIdxSubmissionOrder[i] == node_idx)+ {+ submission_idx = i;+ break;+ }+ }+ IM_ASSERT(submission_idx >= 0);++ if (submission_idx == depth_idx)+ {+ continue;+ }++ for (int j = submission_idx; j < depth_idx; ++j)+ {+ DrawListSwapSubmissionIndices(j, j + 1);+ ImSwap(GImNodes->NodeIdxSubmissionOrder[j], GImNodes->NodeIdxSubmissionOrder[j + 1]);+ }+ }+}++// [SECTION] ui state logic++ImVec2 GetScreenSpacePinCoordinates(+ const ImRect& node_rect,+ const ImRect& attribute_rect,+ const ImNodesAttributeType type)+{+ IM_ASSERT(type == ImNodesAttributeType_Input || type == ImNodesAttributeType_Output);+ const float x = type == ImNodesAttributeType_Input+ ? (node_rect.Min.x - GImNodes->Style.PinOffset)+ : (node_rect.Max.x + GImNodes->Style.PinOffset);+ return ImVec2(x, 0.5f * (attribute_rect.Min.y + attribute_rect.Max.y));+}++ImVec2 GetScreenSpacePinCoordinates(const ImNodesEditorContext& editor, const ImPinData& pin)+{+ const ImRect& parent_node_rect = editor.Nodes.Pool[pin.ParentNodeIdx].Rect;+ return GetScreenSpacePinCoordinates(parent_node_rect, pin.AttributeRect, pin.Type);+}++bool MouseInCanvas()+{+ // This flag should be true either when hovering or clicking something in the canvas.+ const bool is_window_hovered_or_focused = ImGui::IsWindowHovered() || ImGui::IsWindowFocused();++ return is_window_hovered_or_focused &&+ GImNodes->CanvasRectScreenSpace.Contains(ImGui::GetMousePos());+}++void BeginNodeSelection(ImNodesEditorContext& editor, const int node_idx)+{+ // Don't start selecting a node if we are e.g. already creating and dragging+ // a new link! New link creation can happen when the mouse is clicked over+ // a node, but within the hover radius of a pin.+ if (editor.ClickInteraction.Type != ImNodesClickInteractionType_None)+ {+ return;+ }++ editor.ClickInteraction.Type = ImNodesClickInteractionType_Node;+ // If the node is not already contained in the selection, then we want only+ // the interaction node to be selected, effective immediately.+ //+ // If the multiple selection modifier is active, we want to add this node+ // to the current list of selected nodes.+ //+ // Otherwise, we want to allow for the possibility of multiple nodes to be+ // moved at once.+ if (!editor.SelectedNodeIndices.contains(node_idx))+ {+ editor.SelectedLinkIndices.clear();+ if (!GImNodes->MultipleSelectModifier)+ {+ editor.SelectedNodeIndices.clear();+ }+ editor.SelectedNodeIndices.push_back(node_idx);++ // Ensure that individually selected nodes get rendered on top+ ImVector<int>& depth_stack = editor.NodeDepthOrder;+ const int* const elem = depth_stack.find(node_idx);+ IM_ASSERT(elem != depth_stack.end());+ depth_stack.erase(elem);+ depth_stack.push_back(node_idx);+ }+ // Deselect a previously-selected node+ else if (GImNodes->MultipleSelectModifier)+ {+ const int* const node_ptr = editor.SelectedNodeIndices.find(node_idx);+ editor.SelectedNodeIndices.erase(node_ptr);++ // Don't allow dragging after deselecting+ editor.ClickInteraction.Type = ImNodesClickInteractionType_None;+ }++ // To support snapping of multiple nodes, we need to store the offset of+ // each node in the selection to the origin of the dragged node.+ const ImVec2 ref_origin = editor.Nodes.Pool[node_idx].Origin;+ editor.PrimaryNodeOffset =+ ref_origin + GImNodes->CanvasOriginScreenSpace + editor.Panning - GImNodes->MousePos;++ editor.SelectedNodeOffsets.clear();+ for (int idx = 0; idx < editor.SelectedNodeIndices.Size; idx++)+ {+ const int node = editor.SelectedNodeIndices[idx];+ const ImVec2 node_origin = editor.Nodes.Pool[node].Origin - ref_origin;+ editor.SelectedNodeOffsets.push_back(node_origin);+ }+}++void BeginLinkSelection(ImNodesEditorContext& editor, const int link_idx)+{+ editor.ClickInteraction.Type = ImNodesClickInteractionType_Link;+ // When a link is selected, clear all other selections, and insert the link+ // as the sole selection.+ editor.SelectedNodeIndices.clear();+ editor.SelectedLinkIndices.clear();+ editor.SelectedLinkIndices.push_back(link_idx);+}++void BeginLinkDetach(ImNodesEditorContext& editor, const int link_idx, const int detach_pin_idx)+{+ const ImLinkData& link = editor.Links.Pool[link_idx];+ ImClickInteractionState& state = editor.ClickInteraction;+ state.Type = ImNodesClickInteractionType_LinkCreation;+ state.LinkCreation.EndPinIdx.Reset();+ state.LinkCreation.StartPinIdx =+ detach_pin_idx == link.StartPinIdx ? link.EndPinIdx : link.StartPinIdx;+ GImNodes->DeletedLinkIdx = link_idx;+}++void BeginLinkCreation(ImNodesEditorContext& editor, const int hovered_pin_idx)+{+ editor.ClickInteraction.Type = ImNodesClickInteractionType_LinkCreation;+ editor.ClickInteraction.LinkCreation.StartPinIdx = hovered_pin_idx;+ editor.ClickInteraction.LinkCreation.EndPinIdx.Reset();+ editor.ClickInteraction.LinkCreation.Type = ImNodesLinkCreationType_Standard;+ GImNodes->ImNodesUIState |= ImNodesUIState_LinkStarted;+}++void BeginLinkInteraction(+ ImNodesEditorContext& editor,+ const int link_idx,+ const ImOptionalIndex pin_idx = ImOptionalIndex())+{+ // Check if we are clicking the link with the modifier pressed.+ // This will in a link detach via clicking.++ const bool modifier_pressed = GImNodes->Io.LinkDetachWithModifierClick.Modifier == NULL+ ? false+ : *GImNodes->Io.LinkDetachWithModifierClick.Modifier;++ if (modifier_pressed)+ {+ const ImLinkData& link = editor.Links.Pool[link_idx];+ const ImPinData& start_pin = editor.Pins.Pool[link.StartPinIdx];+ const ImPinData& end_pin = editor.Pins.Pool[link.EndPinIdx];+ const ImVec2& mouse_pos = GImNodes->MousePos;+ const float dist_to_start = ImLengthSqr(start_pin.Pos - mouse_pos);+ const float dist_to_end = ImLengthSqr(end_pin.Pos - mouse_pos);+ const int closest_pin_idx = dist_to_start < dist_to_end ? link.StartPinIdx : link.EndPinIdx;++ editor.ClickInteraction.Type = ImNodesClickInteractionType_LinkCreation;+ BeginLinkDetach(editor, link_idx, closest_pin_idx);+ editor.ClickInteraction.LinkCreation.Type = ImNodesLinkCreationType_FromDetach;+ }+ else+ {+ if (pin_idx.HasValue())+ {+ const int hovered_pin_flags = editor.Pins.Pool[pin_idx.Value()].Flags;++ // Check the 'click and drag to detach' case.+ if (hovered_pin_flags & ImNodesAttributeFlags_EnableLinkDetachWithDragClick)+ {+ BeginLinkDetach(editor, link_idx, pin_idx.Value());+ editor.ClickInteraction.LinkCreation.Type = ImNodesLinkCreationType_FromDetach;+ }+ else+ {+ BeginLinkCreation(editor, pin_idx.Value());+ }+ }+ else+ {+ BeginLinkSelection(editor, link_idx);+ }+ }+}++static inline bool IsMiniMapHovered();++void BeginCanvasInteraction(ImNodesEditorContext& editor)+{+ const bool any_ui_element_hovered =+ GImNodes->HoveredNodeIdx.HasValue() || GImNodes->HoveredLinkIdx.HasValue() ||+ GImNodes->HoveredPinIdx.HasValue() || ImGui::IsAnyItemHovered();++ const bool mouse_not_in_canvas = !MouseInCanvas();++ if (editor.ClickInteraction.Type != ImNodesClickInteractionType_None ||+ any_ui_element_hovered || mouse_not_in_canvas || !ImGui::IsWindowHovered())+ {+ return;+ }++ const bool started_panning = GImNodes->AltMouseClicked;++ if (started_panning)+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_Panning;+ }+ else if (GImNodes->LeftMouseClicked)+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_BoxSelection;+ editor.ClickInteraction.BoxSelector.Rect.Min =+ ScreenSpaceToGridSpace(editor, GImNodes->MousePos);+ }+}++void BoxSelectorUpdateSelection(ImNodesEditorContext& editor, ImRect box_rect)+{+ // Invert box selector coordinates as needed++ if (box_rect.Min.x > box_rect.Max.x)+ {+ ImSwap(box_rect.Min.x, box_rect.Max.x);+ }++ if (box_rect.Min.y > box_rect.Max.y)+ {+ ImSwap(box_rect.Min.y, box_rect.Max.y);+ }++ // Update node selection++ editor.SelectedNodeIndices.clear();++ // Test for overlap against node rectangles++ for (int node_idx = 0; node_idx < editor.Nodes.Pool.size(); ++node_idx)+ {+ if (editor.Nodes.InUse[node_idx])+ {+ ImNodeData& node = editor.Nodes.Pool[node_idx];+ if (box_rect.Overlaps(node.Rect))+ {+ editor.SelectedNodeIndices.push_back(node_idx);+ }+ }+ }++ // Update link selection++ editor.SelectedLinkIndices.clear();++ // Test for overlap against links++ for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)+ {+ if (editor.Links.InUse[link_idx])+ {+ const ImLinkData& link = editor.Links.Pool[link_idx];++ const ImPinData& pin_start = editor.Pins.Pool[link.StartPinIdx];+ const ImPinData& pin_end = editor.Pins.Pool[link.EndPinIdx];+ const ImRect& node_start_rect = editor.Nodes.Pool[pin_start.ParentNodeIdx].Rect;+ const ImRect& node_end_rect = editor.Nodes.Pool[pin_end.ParentNodeIdx].Rect;++ const ImVec2 start = GetScreenSpacePinCoordinates(+ node_start_rect, pin_start.AttributeRect, pin_start.Type);+ const ImVec2 end =+ GetScreenSpacePinCoordinates(node_end_rect, pin_end.AttributeRect, pin_end.Type);++ // Test+ if (RectangleOverlapsLink(box_rect, start, end, pin_start.Type))+ {+ editor.SelectedLinkIndices.push_back(link_idx);+ }+ }+ }+}++ImVec2 SnapOriginToGrid(ImVec2 origin)+{+ if (GImNodes->Style.Flags & ImNodesStyleFlags_GridSnapping)+ {+ const float spacing = GImNodes->Style.GridSpacing;+ const float spacing2 = spacing * 0.5f;++ // Snap the origin to the nearest grid point in any direction+ float modx = fmodf(fabsf(origin.x) + spacing2, spacing) - spacing2;+ float mody = fmodf(fabsf(origin.y) + spacing2, spacing) - spacing2;+ origin.x += (origin.x < 0.f) ? modx : -modx;+ origin.y += (origin.y < 0.f) ? mody : -mody;+ }++ return origin;+}++void TranslateSelectedNodes(ImNodesEditorContext& editor)+{+ if (GImNodes->LeftMouseDragging)+ {+ // If we have grid snap enabled, don't start moving nodes until we've moved the mouse+ // slightly+ const bool shouldTranslate = (GImNodes->Style.Flags & ImNodesStyleFlags_GridSnapping)+ ? ImGui::GetIO().MouseDragMaxDistanceSqr[0] > 5.0+ : true;++ const ImVec2 origin = SnapOriginToGrid(+ GImNodes->MousePos - GImNodes->CanvasOriginScreenSpace - editor.Panning ++ editor.PrimaryNodeOffset);+ for (int i = 0; i < editor.SelectedNodeIndices.size(); ++i)+ {+ const ImVec2 node_rel = editor.SelectedNodeOffsets[i];+ const int node_idx = editor.SelectedNodeIndices[i];+ ImNodeData& node = editor.Nodes.Pool[node_idx];+ if (node.Draggable && shouldTranslate)+ {+ node.Origin = origin + node_rel + editor.AutoPanningDelta;+ }+ }+ }+}++struct LinkPredicate+{+ bool operator()(const ImLinkData& lhs, const ImLinkData& rhs) const+ {+ // Do a unique compare by sorting the pins' addresses.+ // This catches duplicate links, whether they are in the+ // same direction or not.+ // Sorting by pin index should have the uniqueness guarantees as sorting+ // by id -- each unique id will get one slot in the link pool array.++ int lhs_start = lhs.StartPinIdx;+ int lhs_end = lhs.EndPinIdx;+ int rhs_start = rhs.StartPinIdx;+ int rhs_end = rhs.EndPinIdx;++ if (lhs_start > lhs_end)+ {+ ImSwap(lhs_start, lhs_end);+ }++ if (rhs_start > rhs_end)+ {+ ImSwap(rhs_start, rhs_end);+ }++ return lhs_start == rhs_start && lhs_end == rhs_end;+ }+};++ImOptionalIndex FindDuplicateLink(+ const ImNodesEditorContext& editor,+ const int start_pin_idx,+ const int end_pin_idx)+{+ ImLinkData test_link(0);+ test_link.StartPinIdx = start_pin_idx;+ test_link.EndPinIdx = end_pin_idx;+ for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)+ {+ const ImLinkData& link = editor.Links.Pool[link_idx];+ if (LinkPredicate()(test_link, link) && editor.Links.InUse[link_idx])+ {+ return ImOptionalIndex(link_idx);+ }+ }++ return ImOptionalIndex();+}++bool ShouldLinkSnapToPin(+ const ImNodesEditorContext& editor,+ const ImPinData& start_pin,+ const int hovered_pin_idx,+ const ImOptionalIndex duplicate_link)+{+ const ImPinData& end_pin = editor.Pins.Pool[hovered_pin_idx];++ // The end pin must be in a different node+ if (start_pin.ParentNodeIdx == end_pin.ParentNodeIdx)+ {+ return false;+ }++ // The end pin must be of a different type+ if (start_pin.Type == end_pin.Type)+ {+ return false;+ }++ // The link to be created must not be a duplicate, unless it is the link which was created on+ // snap. In that case we want to snap, since we want it to appear visually as if the created+ // link remains snapped to the pin.+ if (duplicate_link.HasValue() && !(duplicate_link == GImNodes->SnapLinkIdx))+ {+ return false;+ }++ return true;+}++void ClickInteractionUpdate(ImNodesEditorContext& editor)+{+ switch (editor.ClickInteraction.Type)+ {+ case ImNodesClickInteractionType_BoxSelection:+ {+ editor.ClickInteraction.BoxSelector.Rect.Max =+ ScreenSpaceToGridSpace(editor, GImNodes->MousePos);++ ImRect box_rect = editor.ClickInteraction.BoxSelector.Rect;+ box_rect.Min = GridSpaceToScreenSpace(editor, box_rect.Min);+ box_rect.Max = GridSpaceToScreenSpace(editor, box_rect.Max);++ BoxSelectorUpdateSelection(editor, box_rect);++ const ImU32 box_selector_color = GImNodes->Style.Colors[ImNodesCol_BoxSelector];+ const ImU32 box_selector_outline = GImNodes->Style.Colors[ImNodesCol_BoxSelectorOutline];+ GImNodes->CanvasDrawList->AddRectFilled(box_rect.Min, box_rect.Max, box_selector_color);+ GImNodes->CanvasDrawList->AddRect(box_rect.Min, box_rect.Max, box_selector_outline);++ if (GImNodes->LeftMouseReleased)+ {+ ImVector<int>& depth_stack = editor.NodeDepthOrder;+ const ImVector<int>& selected_idxs = editor.SelectedNodeIndices;++ // Bump the selected node indices, in order, to the top of the depth stack.+ // NOTE: this algorithm has worst case time complexity of O(N^2), if the node selection+ // is ~ N (due to selected_idxs.contains()).++ if ((selected_idxs.Size > 0) && (selected_idxs.Size < depth_stack.Size))+ {+ int num_moved = 0; // The number of indices moved. Stop after selected_idxs.Size+ for (int i = 0; i < depth_stack.Size - selected_idxs.Size; ++i)+ {+ for (int node_idx = depth_stack[i]; selected_idxs.contains(node_idx);+ node_idx = depth_stack[i])+ {+ depth_stack.erase(depth_stack.begin() + static_cast<size_t>(i));+ depth_stack.push_back(node_idx);+ ++num_moved;+ }++ if (num_moved == selected_idxs.Size)+ {+ break;+ }+ }+ }++ editor.ClickInteraction.Type = ImNodesClickInteractionType_None;+ }+ }+ break;+ case ImNodesClickInteractionType_Node:+ {+ TranslateSelectedNodes(editor);++ if (GImNodes->LeftMouseReleased)+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_None;+ }+ }+ break;+ case ImNodesClickInteractionType_Link:+ {+ if (GImNodes->LeftMouseReleased)+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_None;+ }+ }+ break;+ case ImNodesClickInteractionType_LinkCreation:+ {+ const ImPinData& start_pin =+ editor.Pins.Pool[editor.ClickInteraction.LinkCreation.StartPinIdx];++ const ImOptionalIndex maybe_duplicate_link_idx =+ GImNodes->HoveredPinIdx.HasValue()+ ? FindDuplicateLink(+ editor,+ editor.ClickInteraction.LinkCreation.StartPinIdx,+ GImNodes->HoveredPinIdx.Value())+ : ImOptionalIndex();++ const bool should_snap =+ GImNodes->HoveredPinIdx.HasValue() &&+ ShouldLinkSnapToPin(+ editor, start_pin, GImNodes->HoveredPinIdx.Value(), maybe_duplicate_link_idx);++ // If we created on snap and the hovered pin is empty or changed, then we need signal that+ // the link's state has changed.+ const bool snapping_pin_changed =+ editor.ClickInteraction.LinkCreation.EndPinIdx.HasValue() &&+ !(GImNodes->HoveredPinIdx == editor.ClickInteraction.LinkCreation.EndPinIdx);++ // Detach the link that was created by this link event if it's no longer in snap range+ if (snapping_pin_changed && GImNodes->SnapLinkIdx.HasValue())+ {+ BeginLinkDetach(+ editor,+ GImNodes->SnapLinkIdx.Value(),+ editor.ClickInteraction.LinkCreation.EndPinIdx.Value());+ }++ const ImVec2 start_pos = GetScreenSpacePinCoordinates(editor, start_pin);+ // If we are within the hover radius of a receiving pin, snap the link+ // endpoint to it+ const ImVec2 end_pos = should_snap+ ? GetScreenSpacePinCoordinates(+ editor, editor.Pins.Pool[GImNodes->HoveredPinIdx.Value()])+ : GImNodes->MousePos;++ const CubicBezier cubic_bezier = GetCubicBezier(+ start_pos, end_pos, start_pin.Type, GImNodes->Style.LinkLineSegmentsPerLength);+#if IMGUI_VERSION_NUM < 18000+ GImNodes->CanvasDrawList->AddBezierCurve(+#else+ GImNodes->CanvasDrawList->AddBezierCubic(+#endif+ cubic_bezier.P0,+ cubic_bezier.P1,+ cubic_bezier.P2,+ cubic_bezier.P3,+ GImNodes->Style.Colors[ImNodesCol_Link],+ GImNodes->Style.LinkThickness,+ cubic_bezier.NumSegments);++ const bool link_creation_on_snap =+ GImNodes->HoveredPinIdx.HasValue() &&+ (editor.Pins.Pool[GImNodes->HoveredPinIdx.Value()].Flags &+ ImNodesAttributeFlags_EnableLinkCreationOnSnap);++ if (!should_snap)+ {+ editor.ClickInteraction.LinkCreation.EndPinIdx.Reset();+ }++ const bool create_link =+ should_snap && (GImNodes->LeftMouseReleased || link_creation_on_snap);++ if (create_link && !maybe_duplicate_link_idx.HasValue())+ {+ // Avoid send OnLinkCreated() events every frame if the snap link is not saved+ // (only applies for EnableLinkCreationOnSnap)+ if (!GImNodes->LeftMouseReleased &&+ editor.ClickInteraction.LinkCreation.EndPinIdx == GImNodes->HoveredPinIdx)+ {+ break;+ }++ GImNodes->ImNodesUIState |= ImNodesUIState_LinkCreated;+ editor.ClickInteraction.LinkCreation.EndPinIdx = GImNodes->HoveredPinIdx.Value();+ }++ if (GImNodes->LeftMouseReleased)+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_None;+ if (!create_link)+ {+ GImNodes->ImNodesUIState |= ImNodesUIState_LinkDropped;+ }+ }+ }+ break;+ case ImNodesClickInteractionType_Panning:+ {+ const bool dragging = GImNodes->AltMouseDragging;++ if (dragging)+ {+ editor.Panning += ImGui::GetIO().MouseDelta;+ }+ else+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_None;+ }+ }+ break;+ case ImNodesClickInteractionType_ImGuiItem:+ {+ if (GImNodes->LeftMouseReleased)+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_None;+ }+ }+ case ImNodesClickInteractionType_None:+ break;+ default:+ IM_ASSERT(!"Unreachable code!");+ break;+ }+}++void ResolveOccludedPins(const ImNodesEditorContext& editor, ImVector<int>& occluded_pin_indices)+{+ const ImVector<int>& depth_stack = editor.NodeDepthOrder;++ occluded_pin_indices.resize(0);++ if (depth_stack.Size < 2)+ {+ return;+ }++ // For each node in the depth stack+ for (int depth_idx = 0; depth_idx < (depth_stack.Size - 1); ++depth_idx)+ {+ const ImNodeData& node_below = editor.Nodes.Pool[depth_stack[depth_idx]];++ // Iterate over the rest of the depth stack to find nodes overlapping the pins+ for (int next_depth_idx = depth_idx + 1; next_depth_idx < depth_stack.Size;+ ++next_depth_idx)+ {+ const ImRect& rect_above = editor.Nodes.Pool[depth_stack[next_depth_idx]].Rect;++ // Iterate over each pin+ for (int idx = 0; idx < node_below.PinIndices.Size; ++idx)+ {+ const int pin_idx = node_below.PinIndices[idx];+ const ImVec2& pin_pos = editor.Pins.Pool[pin_idx].Pos;++ if (rect_above.Contains(pin_pos))+ {+ occluded_pin_indices.push_back(pin_idx);+ }+ }+ }+ }+}++ImOptionalIndex ResolveHoveredPin(+ const ImObjectPool<ImPinData>& pins,+ const ImVector<int>& occluded_pin_indices)+{+ float smallest_distance = FLT_MAX;+ ImOptionalIndex pin_idx_with_smallest_distance;++ const float hover_radius_sqr = GImNodes->Style.PinHoverRadius * GImNodes->Style.PinHoverRadius;++ for (int idx = 0; idx < pins.Pool.Size; ++idx)+ {+ if (!pins.InUse[idx])+ {+ continue;+ }++ if (occluded_pin_indices.contains(idx))+ {+ continue;+ }++ const ImVec2& pin_pos = pins.Pool[idx].Pos;+ const float distance_sqr = ImLengthSqr(pin_pos - GImNodes->MousePos);++ // TODO: GImNodes->Style.PinHoverRadius needs to be copied into pin data and the pin-local+ // value used here. This is no longer called in BeginAttribute/EndAttribute scope and the+ // detected pin might have a different hover radius than what the user had when calling+ // BeginAttribute/EndAttribute.+ if (distance_sqr < hover_radius_sqr && distance_sqr < smallest_distance)+ {+ smallest_distance = distance_sqr;+ pin_idx_with_smallest_distance = idx;+ }+ }++ return pin_idx_with_smallest_distance;+}++ImOptionalIndex ResolveHoveredNode(const ImVector<int>& depth_stack)+{+ if (GImNodes->NodeIndicesOverlappingWithMouse.size() == 0)+ {+ return ImOptionalIndex();+ }++ if (GImNodes->NodeIndicesOverlappingWithMouse.size() == 1)+ {+ return ImOptionalIndex(GImNodes->NodeIndicesOverlappingWithMouse[0]);+ }++ int largest_depth_idx = -1;+ int node_idx_on_top = -1;++ for (int i = 0; i < GImNodes->NodeIndicesOverlappingWithMouse.size(); ++i)+ {+ const int node_idx = GImNodes->NodeIndicesOverlappingWithMouse[i];+ for (int depth_idx = 0; depth_idx < depth_stack.size(); ++depth_idx)+ {+ if (depth_stack[depth_idx] == node_idx && (depth_idx > largest_depth_idx))+ {+ largest_depth_idx = depth_idx;+ node_idx_on_top = node_idx;+ }+ }+ }++ IM_ASSERT(node_idx_on_top != -1);+ return ImOptionalIndex(node_idx_on_top);+}++ImOptionalIndex ResolveHoveredLink(+ const ImObjectPool<ImLinkData>& links,+ const ImObjectPool<ImPinData>& pins)+{+ float smallest_distance = FLT_MAX;+ ImOptionalIndex link_idx_with_smallest_distance;++ // There are two ways a link can be detected as "hovered".+ // 1. The link is within hover distance to the mouse. The closest such link is selected as being+ // hovered over.+ // 2. If the link is connected to the currently hovered pin.+ //+ // The latter is a requirement for link detaching with drag click to work, as both a link and+ // pin are required to be hovered over for the feature to work.++ for (int idx = 0; idx < links.Pool.Size; ++idx)+ {+ if (!links.InUse[idx])+ {+ continue;+ }++ const ImLinkData& link = links.Pool[idx];+ const ImPinData& start_pin = pins.Pool[link.StartPinIdx];+ const ImPinData& end_pin = pins.Pool[link.EndPinIdx];++ // If there is a hovered pin links can only be considered hovered if they use that pin+ if (GImNodes->HoveredPinIdx.HasValue())+ {+ if (GImNodes->HoveredPinIdx == link.StartPinIdx ||+ GImNodes->HoveredPinIdx == link.EndPinIdx)+ {+ return idx;+ }+ continue;+ }++ // TODO: the calculated CubicBeziers could be cached since we generate them again when+ // rendering the links++ const CubicBezier cubic_bezier = GetCubicBezier(+ start_pin.Pos, end_pin.Pos, start_pin.Type, GImNodes->Style.LinkLineSegmentsPerLength);++ // The distance test+ {+ const ImRect link_rect = GetContainingRectForCubicBezier(cubic_bezier);++ // First, do a simple bounding box test against the box containing the link+ // to see whether calculating the distance to the link is worth doing.+ if (link_rect.Contains(GImNodes->MousePos))+ {+ const float distance = GetDistanceToCubicBezier(+ GImNodes->MousePos, cubic_bezier, cubic_bezier.NumSegments);++ // TODO: GImNodes->Style.LinkHoverDistance could be also copied into ImLinkData,+ // since we're not calling this function in the same scope as ImNodes::Link(). The+ // rendered/detected link might have a different hover distance than what the user+ // had specified when calling Link()+ if (distance < GImNodes->Style.LinkHoverDistance && distance < smallest_distance)+ {+ smallest_distance = distance;+ link_idx_with_smallest_distance = idx;+ }+ }+ }+ }++ return link_idx_with_smallest_distance;+}++// [SECTION] render helpers++inline ImRect GetItemRect() { return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); }++inline ImVec2 GetNodeTitleBarOrigin(const ImNodeData& node)+{+ return node.Origin + node.LayoutStyle.Padding;+}++inline ImVec2 GetNodeContentOrigin(const ImNodeData& node)+{+ const ImVec2 title_bar_height =+ ImVec2(0.f, node.TitleBarContentRect.GetHeight() + 2.0f * node.LayoutStyle.Padding.y);+ return node.Origin + title_bar_height + node.LayoutStyle.Padding;+}++inline ImRect GetNodeTitleRect(const ImNodeData& node)+{+ ImRect expanded_title_rect = node.TitleBarContentRect;+ expanded_title_rect.Expand(node.LayoutStyle.Padding);++ return ImRect(+ expanded_title_rect.Min,+ expanded_title_rect.Min + ImVec2(node.Rect.GetWidth(), 0.f) ++ ImVec2(0.f, expanded_title_rect.GetHeight()));+}++void DrawGrid(ImNodesEditorContext& editor, const ImVec2& canvas_size)+{+ const ImVec2 offset = editor.Panning;+ ImU32 line_color = GImNodes->Style.Colors[ImNodesCol_GridLine];+ ImU32 line_color_prim = GImNodes->Style.Colors[ImNodesCol_GridLinePrimary];+ bool draw_primary = GImNodes->Style.Flags & ImNodesStyleFlags_GridLinesPrimary;++ for (float x = fmodf(offset.x, GImNodes->Style.GridSpacing); x < canvas_size.x;+ x += GImNodes->Style.GridSpacing)+ {+ GImNodes->CanvasDrawList->AddLine(+ EditorSpaceToScreenSpace(ImVec2(x, 0.0f)),+ EditorSpaceToScreenSpace(ImVec2(x, canvas_size.y)),+ offset.x - x == 0.f && draw_primary ? line_color_prim : line_color);+ }++ for (float y = fmodf(offset.y, GImNodes->Style.GridSpacing); y < canvas_size.y;+ y += GImNodes->Style.GridSpacing)+ {+ GImNodes->CanvasDrawList->AddLine(+ EditorSpaceToScreenSpace(ImVec2(0.0f, y)),+ EditorSpaceToScreenSpace(ImVec2(canvas_size.x, y)),+ offset.y - y == 0.f && draw_primary ? line_color_prim : line_color);+ }+}++struct QuadOffsets+{+ ImVec2 TopLeft, BottomLeft, BottomRight, TopRight;+};++QuadOffsets CalculateQuadOffsets(const float side_length)+{+ const float half_side = 0.5f * side_length;++ QuadOffsets offset;++ offset.TopLeft = ImVec2(-half_side, half_side);+ offset.BottomLeft = ImVec2(-half_side, -half_side);+ offset.BottomRight = ImVec2(half_side, -half_side);+ offset.TopRight = ImVec2(half_side, half_side);++ return offset;+}++struct TriangleOffsets+{+ ImVec2 TopLeft, BottomLeft, Right;+};++TriangleOffsets CalculateTriangleOffsets(const float side_length)+{+ // Calculates the Vec2 offsets from an equilateral triangle's midpoint to+ // its vertices. Here is how the left_offset and right_offset are+ // calculated.+ //+ // For an equilateral triangle of side length s, the+ // triangle's height, h, is h = s * sqrt(3) / 2.+ //+ // The length from the base to the midpoint is (1 / 3) * h. The length from+ // the midpoint to the triangle vertex is (2 / 3) * h.+ const float sqrt_3 = sqrtf(3.0f);+ const float left_offset = -0.1666666666667f * sqrt_3 * side_length;+ const float right_offset = 0.333333333333f * sqrt_3 * side_length;+ const float vertical_offset = 0.5f * side_length;++ TriangleOffsets offset;+ offset.TopLeft = ImVec2(left_offset, vertical_offset);+ offset.BottomLeft = ImVec2(left_offset, -vertical_offset);+ offset.Right = ImVec2(right_offset, 0.f);++ return offset;+}++void DrawPinShape(const ImVec2& pin_pos, const ImPinData& pin, const ImU32 pin_color)+{+ static const int CIRCLE_NUM_SEGMENTS = 8;++ switch (pin.Shape)+ {+ case ImNodesPinShape_Circle:+ {+ GImNodes->CanvasDrawList->AddCircle(+ pin_pos,+ GImNodes->Style.PinCircleRadius,+ pin_color,+ CIRCLE_NUM_SEGMENTS,+ GImNodes->Style.PinLineThickness);+ }+ break;+ case ImNodesPinShape_CircleFilled:+ {+ GImNodes->CanvasDrawList->AddCircleFilled(+ pin_pos, GImNodes->Style.PinCircleRadius, pin_color, CIRCLE_NUM_SEGMENTS);+ }+ break;+ case ImNodesPinShape_Quad:+ {+ const QuadOffsets offset = CalculateQuadOffsets(GImNodes->Style.PinQuadSideLength);+ GImNodes->CanvasDrawList->AddQuad(+ pin_pos + offset.TopLeft,+ pin_pos + offset.BottomLeft,+ pin_pos + offset.BottomRight,+ pin_pos + offset.TopRight,+ pin_color,+ GImNodes->Style.PinLineThickness);+ }+ break;+ case ImNodesPinShape_QuadFilled:+ {+ const QuadOffsets offset = CalculateQuadOffsets(GImNodes->Style.PinQuadSideLength);+ GImNodes->CanvasDrawList->AddQuadFilled(+ pin_pos + offset.TopLeft,+ pin_pos + offset.BottomLeft,+ pin_pos + offset.BottomRight,+ pin_pos + offset.TopRight,+ pin_color);+ }+ break;+ case ImNodesPinShape_Triangle:+ {+ const TriangleOffsets offset =+ CalculateTriangleOffsets(GImNodes->Style.PinTriangleSideLength);+ GImNodes->CanvasDrawList->AddTriangle(+ pin_pos + offset.TopLeft,+ pin_pos + offset.BottomLeft,+ pin_pos + offset.Right,+ pin_color,+ // NOTE: for some weird reason, the line drawn by AddTriangle is+ // much thinner than the lines drawn by AddCircle or AddQuad.+ // Multiplying the line thickness by two seemed to solve the+ // problem at a few different thickness values.+ 2.f * GImNodes->Style.PinLineThickness);+ }+ break;+ case ImNodesPinShape_TriangleFilled:+ {+ const TriangleOffsets offset =+ CalculateTriangleOffsets(GImNodes->Style.PinTriangleSideLength);+ GImNodes->CanvasDrawList->AddTriangleFilled(+ pin_pos + offset.TopLeft,+ pin_pos + offset.BottomLeft,+ pin_pos + offset.Right,+ pin_color);+ }+ break;+ default:+ IM_ASSERT(!"Invalid PinShape value!");+ break;+ }+}++void DrawPin(ImNodesEditorContext& editor, const int pin_idx)+{+ ImPinData& pin = editor.Pins.Pool[pin_idx];+ const ImRect& parent_node_rect = editor.Nodes.Pool[pin.ParentNodeIdx].Rect;++ pin.Pos = GetScreenSpacePinCoordinates(parent_node_rect, pin.AttributeRect, pin.Type);++ ImU32 pin_color = pin.ColorStyle.Background;++ if (GImNodes->HoveredPinIdx == pin_idx)+ {+ pin_color = pin.ColorStyle.Hovered;+ }++ DrawPinShape(pin.Pos, pin, pin_color);+}++void DrawNode(ImNodesEditorContext& editor, const int node_idx)+{+ const ImNodeData& node = editor.Nodes.Pool[node_idx];+ ImGui::SetCursorPos(node.Origin + editor.Panning);++ const bool node_hovered =+ GImNodes->HoveredNodeIdx == node_idx &&+ editor.ClickInteraction.Type != ImNodesClickInteractionType_BoxSelection;++ ImU32 node_background = node.ColorStyle.Background;+ ImU32 titlebar_background = node.ColorStyle.Titlebar;++ if (editor.SelectedNodeIndices.contains(node_idx))+ {+ node_background = node.ColorStyle.BackgroundSelected;+ titlebar_background = node.ColorStyle.TitlebarSelected;+ }+ else if (node_hovered)+ {+ node_background = node.ColorStyle.BackgroundHovered;+ titlebar_background = node.ColorStyle.TitlebarHovered;+ }++ {+ // node base+ GImNodes->CanvasDrawList->AddRectFilled(+ node.Rect.Min, node.Rect.Max, node_background, node.LayoutStyle.CornerRounding);++ // title bar:+ if (node.TitleBarContentRect.GetHeight() > 0.f)+ {+ ImRect title_bar_rect = GetNodeTitleRect(node);++#if IMGUI_VERSION_NUM < 18200+ GImNodes->CanvasDrawList->AddRectFilled(+ title_bar_rect.Min,+ title_bar_rect.Max,+ titlebar_background,+ node.LayoutStyle.CornerRounding,+ ImDrawCornerFlags_Top);+#elif IMGUI_VERSION_NUM < 19300+ GImNodes->CanvasDrawList->AddRectFilled(+ title_bar_rect.Min,+ title_bar_rect.Max,+ titlebar_background,+ node.LayoutStyle.CornerRounding,+ ImDrawFlags_RoundCornersTop);+#else+ GImNodes->CanvasDrawList->AddRectFilled(+ title_bar_rect.Min,+ title_bar_rect.Max,+ titlebar_background,+ node.LayoutStyle.CornerRounding,+ ImDrawFlags_RoundTop);+#endif+ }++ if ((GImNodes->Style.Flags & ImNodesStyleFlags_NodeOutline) != 0)+ {+#if IMGUI_VERSION_NUM < 18200+ GImNodes->CanvasDrawList->AddRect(+ node.Rect.Min,+ node.Rect.Max,+ node.ColorStyle.Outline,+ node.LayoutStyle.CornerRounding,+ ImDrawCornerFlags_All,+ node.LayoutStyle.BorderThickness);+#elif IMGUI_VERSION_NUM < 19276+ GImNodes->CanvasDrawList->AddRect(+ node.Rect.Min,+ node.Rect.Max,+ node.ColorStyle.Outline,+ node.LayoutStyle.CornerRounding,+ ImDrawFlags_RoundCornersAll,+ node.LayoutStyle.BorderThickness);+#elif IMGUI_VERSION_NUM < 19300+ GImNodes->CanvasDrawList->AddRect(+ node.Rect.Min,+ node.Rect.Max,+ node.ColorStyle.Outline,+ node.LayoutStyle.CornerRounding,+ node.LayoutStyle.BorderThickness,+ ImDrawFlags_RoundCornersAll);+#else+ GImNodes->CanvasDrawList->AddRect(+ node.Rect.Min,+ node.Rect.Max,+ node.ColorStyle.Outline,+ node.LayoutStyle.CornerRounding,+ node.LayoutStyle.BorderThickness,+ ImDrawFlags_RoundAll);+#endif+ }+ }++ for (int i = 0; i < node.PinIndices.size(); ++i)+ {+ DrawPin(editor, node.PinIndices[i]);+ }++ if (node_hovered)+ {+ GImNodes->HoveredNodeIdx = node_idx;+ }+}++void DrawLink(ImNodesEditorContext& editor, const int link_idx)+{+ const ImLinkData& link = editor.Links.Pool[link_idx];+ const ImPinData& start_pin = editor.Pins.Pool[link.StartPinIdx];+ const ImPinData& end_pin = editor.Pins.Pool[link.EndPinIdx];++ const CubicBezier cubic_bezier = GetCubicBezier(+ start_pin.Pos, end_pin.Pos, start_pin.Type, GImNodes->Style.LinkLineSegmentsPerLength);++ const bool link_hovered =+ GImNodes->HoveredLinkIdx == link_idx &&+ editor.ClickInteraction.Type != ImNodesClickInteractionType_BoxSelection;++ if (link_hovered)+ {+ GImNodes->HoveredLinkIdx = link_idx;+ }++ // It's possible for a link to be deleted in begin_link_interaction. A user+ // may detach a link, resulting in the link wire snapping to the mouse+ // position.+ //+ // In other words, skip rendering the link if it was deleted.+ if (GImNodes->DeletedLinkIdx == link_idx)+ {+ return;+ }++ ImU32 link_color = link.ColorStyle.Base;+ if (editor.SelectedLinkIndices.contains(link_idx))+ {+ link_color = link.ColorStyle.Selected;+ }+ else if (link_hovered)+ {+ link_color = link.ColorStyle.Hovered;+ }++#if IMGUI_VERSION_NUM < 18000+ GImNodes->CanvasDrawList->AddBezierCurve(+#else+ GImNodes->CanvasDrawList->AddBezierCubic(+#endif+ cubic_bezier.P0,+ cubic_bezier.P1,+ cubic_bezier.P2,+ cubic_bezier.P3,+ link_color,+ GImNodes->Style.LinkThickness,+ cubic_bezier.NumSegments);+}++void BeginPinAttribute(+ const int id,+ const ImNodesAttributeType type,+ const ImNodesPinShape shape,+ const int node_idx)+{+ // Make sure to call BeginNode() before calling+ // BeginAttribute()+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);+ GImNodes->CurrentScope = ImNodesScope_Attribute;++ ImGui::BeginGroup();+ ImGui::PushID(id);++ ImNodesEditorContext& editor = EditorContextGet();++ GImNodes->CurrentAttributeId = id;++ const int pin_idx = ObjectPoolFindOrCreateIndex(editor.Pins, id);+ GImNodes->CurrentPinIdx = pin_idx;+ ImPinData& pin = editor.Pins.Pool[pin_idx];+ pin.Id = id;+ pin.ParentNodeIdx = node_idx;+ pin.Type = type;+ pin.Shape = shape;+ pin.Flags = GImNodes->CurrentAttributeFlags;+ pin.ColorStyle.Background = GImNodes->Style.Colors[ImNodesCol_Pin];+ pin.ColorStyle.Hovered = GImNodes->Style.Colors[ImNodesCol_PinHovered];+}++void EndPinAttribute()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Attribute);+ GImNodes->CurrentScope = ImNodesScope_Node;++ ImGui::PopID();+ ImGui::EndGroup();++ if (ImGui::IsItemActive())+ {+ GImNodes->ActiveAttribute = true;+ GImNodes->ActiveAttributeId = GImNodes->CurrentAttributeId;+ }++ ImNodesEditorContext& editor = EditorContextGet();+ ImPinData& pin = editor.Pins.Pool[GImNodes->CurrentPinIdx];+ ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];+ pin.AttributeRect = GetItemRect();+ node.PinIndices.push_back(GImNodes->CurrentPinIdx);+}++void Initialize(ImNodesContext* context)+{+ context->CanvasOriginScreenSpace = ImVec2(0.0f, 0.0f);+ context->CanvasRectScreenSpace = ImRect(ImVec2(0.f, 0.f), ImVec2(0.f, 0.f));+ context->CurrentScope = ImNodesScope_None;++ context->CurrentPinIdx = INT_MAX;+ context->CurrentNodeIdx = INT_MAX;++ context->DefaultEditorCtx = EditorContextCreate();+ context->EditorCtx = context->DefaultEditorCtx;++ context->CurrentAttributeFlags = ImNodesAttributeFlags_None;+ context->AttributeFlagStack.push_back(GImNodes->CurrentAttributeFlags);++ StyleColorsDark(&context->Style);+}++void Shutdown(ImNodesContext* ctx) { EditorContextFree(ctx->DefaultEditorCtx); }++// [SECTION] minimap++static inline bool IsMiniMapActive()+{+ ImNodesEditorContext& editor = EditorContextGet();+ return editor.MiniMapEnabled && editor.MiniMapSizeFraction > 0.0f;+}++static inline bool IsMiniMapHovered()+{+ ImNodesEditorContext& editor = EditorContextGet();+ return IsMiniMapActive() &&+ ImGui::IsMouseHoveringRect(+ editor.MiniMapRectScreenSpace.Min, editor.MiniMapRectScreenSpace.Max);+}++static inline void CalcMiniMapLayout()+{+ ImNodesEditorContext& editor = EditorContextGet();+ const ImVec2 offset = GImNodes->Style.MiniMapOffset;+ const ImVec2 border = GImNodes->Style.MiniMapPadding;+ const ImRect editor_rect = GImNodes->CanvasRectScreenSpace;++ // Compute the size of the mini-map area+ ImVec2 mini_map_size;+ float mini_map_scaling;+ {+ const ImVec2 max_size =+ ImFloor(editor_rect.GetSize() * editor.MiniMapSizeFraction - border * 2.0f);+ const float max_size_aspect_ratio = max_size.x / max_size.y;+ const ImVec2 grid_content_size = editor.GridContentBounds.IsInverted()+ ? max_size+ : ImFloor(editor.GridContentBounds.GetSize());+ const float grid_content_aspect_ratio = grid_content_size.x / grid_content_size.y;+ mini_map_size = ImFloor(+ grid_content_aspect_ratio > max_size_aspect_ratio+ ? ImVec2(max_size.x, max_size.x / grid_content_aspect_ratio)+ : ImVec2(max_size.y * grid_content_aspect_ratio, max_size.y));+ mini_map_scaling = mini_map_size.x / grid_content_size.x;+ }++ // Compute location of the mini-map+ ImVec2 mini_map_pos;+ {+ ImVec2 align;++ switch (editor.MiniMapLocation)+ {+ case ImNodesMiniMapLocation_BottomRight:+ align.x = 1.0f;+ align.y = 1.0f;+ break;+ case ImNodesMiniMapLocation_BottomLeft:+ align.x = 0.0f;+ align.y = 1.0f;+ break;+ case ImNodesMiniMapLocation_TopRight:+ align.x = 1.0f;+ align.y = 0.0f;+ break;+ case ImNodesMiniMapLocation_TopLeft: // [[fallthrough]]+ default:+ align.x = 0.0f;+ align.y = 0.0f;+ break;+ }++ const ImVec2 top_left_pos = editor_rect.Min + offset + border;+ const ImVec2 bottom_right_pos = editor_rect.Max - offset - border - mini_map_size;+ mini_map_pos = ImFloor(ImLerp(top_left_pos, bottom_right_pos, align));+ }++ editor.MiniMapRectScreenSpace =+ ImRect(mini_map_pos - border, mini_map_pos + mini_map_size + border);+ editor.MiniMapContentScreenSpace = ImRect(mini_map_pos, mini_map_pos + mini_map_size);+ editor.MiniMapScaling = mini_map_scaling;+}++static void MiniMapDrawNode(ImNodesEditorContext& editor, const int node_idx)+{+ const ImNodeData& node = editor.Nodes.Pool[node_idx];++ const ImRect node_rect = ScreenSpaceToMiniMapSpace(editor, node.Rect);++ // Round to near whole pixel value for corner-rounding to prevent visual glitches+ const float mini_map_node_rounding =+ floorf(node.LayoutStyle.CornerRounding * editor.MiniMapScaling);++ ImU32 mini_map_node_background;++ if (editor.ClickInteraction.Type == ImNodesClickInteractionType_None &&+ ImGui::IsMouseHoveringRect(node_rect.Min, node_rect.Max))+ {+ mini_map_node_background = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundHovered];++ // Run user callback when hovering a mini-map node+ if (editor.MiniMapNodeHoveringCallback)+ {+ editor.MiniMapNodeHoveringCallback(node.Id, editor.MiniMapNodeHoveringCallbackUserData);+ }+ }+ else if (editor.SelectedNodeIndices.contains(node_idx))+ {+ mini_map_node_background = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundSelected];+ }+ else+ {+ mini_map_node_background = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackground];+ }++ const ImU32 mini_map_node_outline = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeOutline];++ GImNodes->CanvasDrawList->AddRectFilled(+ node_rect.Min, node_rect.Max, mini_map_node_background, mini_map_node_rounding);++ GImNodes->CanvasDrawList->AddRect(+ node_rect.Min, node_rect.Max, mini_map_node_outline, mini_map_node_rounding);+}++static void MiniMapDrawLink(ImNodesEditorContext& editor, const int link_idx)+{+ const ImLinkData& link = editor.Links.Pool[link_idx];+ const ImPinData& start_pin = editor.Pins.Pool[link.StartPinIdx];+ const ImPinData& end_pin = editor.Pins.Pool[link.EndPinIdx];++ const CubicBezier cubic_bezier = GetCubicBezier(+ ScreenSpaceToMiniMapSpace(editor, start_pin.Pos),+ ScreenSpaceToMiniMapSpace(editor, end_pin.Pos),+ start_pin.Type,+ GImNodes->Style.LinkLineSegmentsPerLength / editor.MiniMapScaling);++ // It's possible for a link to be deleted in begin_link_interaction. A user+ // may detach a link, resulting in the link wire snapping to the mouse+ // position.+ //+ // In other words, skip rendering the link if it was deleted.+ if (GImNodes->DeletedLinkIdx == link_idx)+ {+ return;+ }++ const ImU32 link_color =+ GImNodes->Style.Colors+ [editor.SelectedLinkIndices.contains(link_idx) ? ImNodesCol_MiniMapLinkSelected+ : ImNodesCol_MiniMapLink];++#if IMGUI_VERSION_NUM < 18000+ GImNodes->CanvasDrawList->AddBezierCurve(+#else+ GImNodes->CanvasDrawList->AddBezierCubic(+#endif+ cubic_bezier.P0,+ cubic_bezier.P1,+ cubic_bezier.P2,+ cubic_bezier.P3,+ link_color,+ GImNodes->Style.LinkThickness * editor.MiniMapScaling,+ cubic_bezier.NumSegments);+}++static void MiniMapUpdate()+{+ ImNodesEditorContext& editor = EditorContextGet();++ ImU32 mini_map_background;++ if (IsMiniMapHovered())+ {+ mini_map_background = GImNodes->Style.Colors[ImNodesCol_MiniMapBackgroundHovered];+ }+ else+ {+ mini_map_background = GImNodes->Style.Colors[ImNodesCol_MiniMapBackground];+ }++ // Create a child window bellow mini-map, so it blocks all mouse interaction on canvas.+ int flags = ImGuiWindowFlags_NoBackground;+ ImGui::SetCursorScreenPos(editor.MiniMapRectScreenSpace.Min);+ ImGui::BeginChild("minimap", editor.MiniMapRectScreenSpace.GetSize(), false, flags);++ const ImRect& mini_map_rect = editor.MiniMapRectScreenSpace;++ // Draw minimap background and border+ GImNodes->CanvasDrawList->AddRectFilled(+ mini_map_rect.Min, mini_map_rect.Max, mini_map_background);++ GImNodes->CanvasDrawList->AddRect(+ mini_map_rect.Min, mini_map_rect.Max, GImNodes->Style.Colors[ImNodesCol_MiniMapOutline]);++ // Clip draw list items to mini-map rect (after drawing background/outline)+ GImNodes->CanvasDrawList->PushClipRect(+ mini_map_rect.Min, mini_map_rect.Max, true /* intersect with editor clip-rect */);++ // Draw links first so they appear under nodes, and we can use the same draw channel+ for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)+ {+ if (editor.Links.InUse[link_idx])+ {+ MiniMapDrawLink(editor, link_idx);+ }+ }++ for (int node_idx = 0; node_idx < editor.Nodes.Pool.size(); ++node_idx)+ {+ if (editor.Nodes.InUse[node_idx])+ {+ MiniMapDrawNode(editor, node_idx);+ }+ }++ // Draw editor canvas rect inside mini-map+ {+ const ImU32 canvas_color = GImNodes->Style.Colors[ImNodesCol_MiniMapCanvas];+ const ImU32 outline_color = GImNodes->Style.Colors[ImNodesCol_MiniMapCanvasOutline];+ const ImRect rect = ScreenSpaceToMiniMapSpace(editor, GImNodes->CanvasRectScreenSpace);++ GImNodes->CanvasDrawList->AddRectFilled(rect.Min, rect.Max, canvas_color);+ GImNodes->CanvasDrawList->AddRect(rect.Min, rect.Max, outline_color);+ }++ // Have to pop mini-map clip rect+ GImNodes->CanvasDrawList->PopClipRect();++ bool mini_map_is_hovered = ImGui::IsWindowHovered();++ ImGui::EndChild();++ bool center_on_click = mini_map_is_hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left) &&+ editor.ClickInteraction.Type == ImNodesClickInteractionType_None &&+ !GImNodes->NodeIdxSubmissionOrder.empty();+ if (center_on_click)+ {+ ImVec2 target = MiniMapSpaceToGridSpace(editor, ImGui::GetMousePos());+ ImVec2 center = GImNodes->CanvasRectScreenSpace.GetSize() * 0.5f;+ editor.Panning = ImFloor(center - target);+ }++ // Reset callback info after use+ editor.MiniMapNodeHoveringCallback = NULL;+ editor.MiniMapNodeHoveringCallbackUserData = NULL;+}++// [SECTION] selection helpers++template<typename T>+void SelectObject(const ImObjectPool<T>& objects, ImVector<int>& selected_indices, const int id)+{+ const int idx = ObjectPoolFind(objects, id);+ IM_ASSERT(idx >= 0);+ IM_ASSERT(selected_indices.find(idx) == selected_indices.end());+ selected_indices.push_back(idx);+}++template<typename T>+void ClearObjectSelection(+ const ImObjectPool<T>& objects,+ ImVector<int>& selected_indices,+ const int id)+{+ const int idx = ObjectPoolFind(objects, id);+ IM_ASSERT(idx >= 0);+ IM_ASSERT(selected_indices.find(idx) != selected_indices.end());+ selected_indices.find_erase_unsorted(idx);+}++template<typename T>+bool IsObjectSelected(const ImObjectPool<T>& objects, ImVector<int>& selected_indices, const int id)+{+ const int idx = ObjectPoolFind(objects, id);+ return selected_indices.find(idx) != selected_indices.end();+}++} // namespace+} // namespace IMNODES_NAMESPACE++// [SECTION] API implementation++ImNodesIO::EmulateThreeButtonMouse::EmulateThreeButtonMouse() : Modifier(NULL) {}++ImNodesIO::LinkDetachWithModifierClick::LinkDetachWithModifierClick() : Modifier(NULL) {}++ImNodesIO::MultipleSelectModifier::MultipleSelectModifier() : Modifier(NULL) {}++ImNodesIO::ImNodesIO()+ : EmulateThreeButtonMouse(), LinkDetachWithModifierClick(),+ AltMouseButton(ImGuiMouseButton_Middle), AutoPanningSpeed(1000.0f)+{+}++ImNodesStyle::ImNodesStyle()+ : GridSpacing(24.f), NodeCornerRounding(4.f), NodePadding(8.f, 8.f), NodeBorderThickness(1.f),+ LinkThickness(3.f), LinkLineSegmentsPerLength(0.1f), LinkHoverDistance(10.f),+ PinCircleRadius(4.f), PinQuadSideLength(7.f), PinTriangleSideLength(9.5),+ PinLineThickness(1.f), PinHoverRadius(10.f), PinOffset(0.f), MiniMapPadding(8.0f, 8.0f),+ MiniMapOffset(4.0f, 4.0f), Flags(ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines),+ Colors()+{+}++namespace IMNODES_NAMESPACE+{+ImNodesContext* CreateContext()+{+ ImNodesContext* ctx = IM_NEW(ImNodesContext)();+ if (GImNodes == NULL)+ SetCurrentContext(ctx);+ Initialize(ctx);+ return ctx;+}++void DestroyContext(ImNodesContext* ctx)+{+ if (ctx == NULL)+ ctx = GImNodes;+ Shutdown(ctx);+ if (GImNodes == ctx)+ SetCurrentContext(NULL);+ IM_DELETE(ctx);+}++ImNodesContext* GetCurrentContext() { return GImNodes; }++void SetCurrentContext(ImNodesContext* ctx) { GImNodes = ctx; }++ImNodesEditorContext* EditorContextCreate()+{+ void* mem = ImGui::MemAlloc(sizeof(ImNodesEditorContext));+ new (mem) ImNodesEditorContext();+ return (ImNodesEditorContext*)mem;+}++void EditorContextFree(ImNodesEditorContext* ctx)+{+ ctx->~ImNodesEditorContext();+ ImGui::MemFree(ctx);+}++void EditorContextSet(ImNodesEditorContext* ctx) { GImNodes->EditorCtx = ctx; }++ImVec2 EditorContextGetPanning()+{+ const ImNodesEditorContext& editor = EditorContextGet();+ return editor.Panning;+}++void EditorContextResetPanning(const ImVec2& pos)+{+ ImNodesEditorContext& editor = EditorContextGet();+ editor.Panning = pos;+}++void EditorContextMoveToNode(const int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);++ editor.Panning.x = -node.Origin.x;+ editor.Panning.y = -node.Origin.y;+}++void SetImGuiContext(ImGuiContext* ctx) { ImGui::SetCurrentContext(ctx); }++ImNodesIO& GetIO() { return GImNodes->Io; }++ImNodesStyle& GetStyle() { return GImNodes->Style; }++void StyleColorsDark(ImNodesStyle* dest)+{+ if (dest == nullptr)+ {+ dest = &GImNodes->Style;+ }++ dest->Colors[ImNodesCol_NodeBackground] = IM_COL32(50, 50, 50, 255);+ dest->Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(75, 75, 75, 255);+ dest->Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(75, 75, 75, 255);+ dest->Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255);+ // title bar colors match ImGui's titlebg colors+ dest->Colors[ImNodesCol_TitleBar] = IM_COL32(41, 74, 122, 255);+ dest->Colors[ImNodesCol_TitleBarHovered] = IM_COL32(66, 150, 250, 255);+ dest->Colors[ImNodesCol_TitleBarSelected] = IM_COL32(66, 150, 250, 255);+ // link colors match ImGui's slider grab colors+ dest->Colors[ImNodesCol_Link] = IM_COL32(61, 133, 224, 200);+ dest->Colors[ImNodesCol_LinkHovered] = IM_COL32(66, 150, 250, 255);+ dest->Colors[ImNodesCol_LinkSelected] = IM_COL32(66, 150, 250, 255);+ // pin colors match ImGui's button colors+ dest->Colors[ImNodesCol_Pin] = IM_COL32(53, 150, 250, 180);+ dest->Colors[ImNodesCol_PinHovered] = IM_COL32(53, 150, 250, 255);++ dest->Colors[ImNodesCol_BoxSelector] = IM_COL32(61, 133, 224, 30);+ dest->Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(61, 133, 224, 150);++ dest->Colors[ImNodesCol_GridBackground] = IM_COL32(40, 40, 50, 200);+ dest->Colors[ImNodesCol_GridLine] = IM_COL32(200, 200, 200, 40);+ dest->Colors[ImNodesCol_GridLinePrimary] = IM_COL32(240, 240, 240, 60);++ // minimap colors+ dest->Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 150);+ dest->Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200);+ dest->Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100);+ dest->Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200);+ dest->Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100);+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered] = IM_COL32(200, 200, 200, 255);+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] =+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered];+ dest->Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100);+ dest->Colors[ImNodesCol_MiniMapLink] = dest->Colors[ImNodesCol_Link];+ dest->Colors[ImNodesCol_MiniMapLinkSelected] = dest->Colors[ImNodesCol_LinkSelected];+ dest->Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25);+ dest->Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200);+}++void StyleColorsClassic(ImNodesStyle* dest)+{+ if (dest == nullptr)+ {+ dest = &GImNodes->Style;+ }++ dest->Colors[ImNodesCol_NodeBackground] = IM_COL32(50, 50, 50, 255);+ dest->Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(75, 75, 75, 255);+ dest->Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(75, 75, 75, 255);+ dest->Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255);+ dest->Colors[ImNodesCol_TitleBar] = IM_COL32(69, 69, 138, 255);+ dest->Colors[ImNodesCol_TitleBarHovered] = IM_COL32(82, 82, 161, 255);+ dest->Colors[ImNodesCol_TitleBarSelected] = IM_COL32(82, 82, 161, 255);+ dest->Colors[ImNodesCol_Link] = IM_COL32(255, 255, 255, 100);+ dest->Colors[ImNodesCol_LinkHovered] = IM_COL32(105, 99, 204, 153);+ dest->Colors[ImNodesCol_LinkSelected] = IM_COL32(105, 99, 204, 153);+ dest->Colors[ImNodesCol_Pin] = IM_COL32(89, 102, 156, 170);+ dest->Colors[ImNodesCol_PinHovered] = IM_COL32(102, 122, 179, 200);+ dest->Colors[ImNodesCol_BoxSelector] = IM_COL32(82, 82, 161, 100);+ dest->Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(82, 82, 161, 255);+ dest->Colors[ImNodesCol_GridBackground] = IM_COL32(40, 40, 50, 200);+ dest->Colors[ImNodesCol_GridLine] = IM_COL32(200, 200, 200, 40);+ dest->Colors[ImNodesCol_GridLinePrimary] = IM_COL32(240, 240, 240, 60);++ // minimap colors+ dest->Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 100);+ dest->Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200);+ dest->Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100);+ dest->Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200);+ dest->Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100);+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] =+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered];+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = IM_COL32(200, 200, 240, 255);+ dest->Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100);+ dest->Colors[ImNodesCol_MiniMapLink] = dest->Colors[ImNodesCol_Link];+ dest->Colors[ImNodesCol_MiniMapLinkSelected] = dest->Colors[ImNodesCol_LinkSelected];+ dest->Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25);+ dest->Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200);+}++void StyleColorsLight(ImNodesStyle* dest)+{+ if (dest == nullptr)+ {+ dest = &GImNodes->Style;+ }++ dest->Colors[ImNodesCol_NodeBackground] = IM_COL32(240, 240, 240, 255);+ dest->Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(240, 240, 240, 255);+ dest->Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(240, 240, 240, 255);+ dest->Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255);+ dest->Colors[ImNodesCol_TitleBar] = IM_COL32(248, 248, 248, 255);+ dest->Colors[ImNodesCol_TitleBarHovered] = IM_COL32(209, 209, 209, 255);+ dest->Colors[ImNodesCol_TitleBarSelected] = IM_COL32(209, 209, 209, 255);+ // original imgui values: 66, 150, 250+ dest->Colors[ImNodesCol_Link] = IM_COL32(66, 150, 250, 100);+ // original imgui values: 117, 138, 204+ dest->Colors[ImNodesCol_LinkHovered] = IM_COL32(66, 150, 250, 242);+ dest->Colors[ImNodesCol_LinkSelected] = IM_COL32(66, 150, 250, 242);+ // original imgui values: 66, 150, 250+ dest->Colors[ImNodesCol_Pin] = IM_COL32(66, 150, 250, 160);+ dest->Colors[ImNodesCol_PinHovered] = IM_COL32(66, 150, 250, 255);+ dest->Colors[ImNodesCol_BoxSelector] = IM_COL32(90, 170, 250, 30);+ dest->Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(90, 170, 250, 150);+ dest->Colors[ImNodesCol_GridBackground] = IM_COL32(225, 225, 225, 255);+ dest->Colors[ImNodesCol_GridLine] = IM_COL32(180, 180, 180, 100);+ dest->Colors[ImNodesCol_GridLinePrimary] = IM_COL32(120, 120, 120, 100);++ // minimap colors+ dest->Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 100);+ dest->Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200);+ dest->Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100);+ dest->Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200);+ dest->Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100);+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] =+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered];+ dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = IM_COL32(200, 200, 240, 255);+ dest->Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100);+ dest->Colors[ImNodesCol_MiniMapLink] = dest->Colors[ImNodesCol_Link];+ dest->Colors[ImNodesCol_MiniMapLinkSelected] = dest->Colors[ImNodesCol_LinkSelected];+ dest->Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25);+ dest->Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200);+}++const char* GetStyleColorName(ImNodesCol idx)+{+ // Create switch-case from enum with regexp: ImNodesCol_(.*), --> case ImNodesCol_\1: return "\1";+ switch (idx)+ {+ case ImNodesCol_NodeBackground: return "NodeBackground";+ case ImNodesCol_NodeBackgroundHovered: return "NodeBackgroundHovered";+ case ImNodesCol_NodeBackgroundSelected: return "NodeBackgroundSelected";+ case ImNodesCol_NodeOutline: return "NodeOutline";+ case ImNodesCol_TitleBar: return "TitleBar";+ case ImNodesCol_TitleBarHovered: return "TitleBarHovered";+ case ImNodesCol_TitleBarSelected: return "TitleBarSelected";+ case ImNodesCol_Link: return "Link";+ case ImNodesCol_LinkHovered: return "LinkHovered";+ case ImNodesCol_LinkSelected: return "LinkSelected";+ case ImNodesCol_Pin: return "Pin";+ case ImNodesCol_PinHovered: return "PinHovered";+ case ImNodesCol_BoxSelector: return "BoxSelector";+ case ImNodesCol_BoxSelectorOutline: return "BoxSelectorOutline";+ case ImNodesCol_GridBackground: return "GridBackground";+ case ImNodesCol_GridLine: return "GridLine";+ case ImNodesCol_GridLinePrimary: return "GridLinePrimary";+ case ImNodesCol_MiniMapBackground: return "MiniMapBackground";+ case ImNodesCol_MiniMapBackgroundHovered: return "MiniMapBackgroundHovered";+ case ImNodesCol_MiniMapOutline: return "MiniMapOutline";+ case ImNodesCol_MiniMapOutlineHovered: return "MiniMapOutlineHovered";+ case ImNodesCol_MiniMapNodeBackground: return "MiniMapNodeBackground";+ case ImNodesCol_MiniMapNodeBackgroundHovered: return "MiniMapNodeBackgroundHovered";+ case ImNodesCol_MiniMapNodeBackgroundSelected: return "MiniMapNodeBackgroundSelected";+ case ImNodesCol_MiniMapNodeOutline: return "MiniMapNodeOutline";+ case ImNodesCol_MiniMapLink: return "MiniMapLink";+ case ImNodesCol_MiniMapLinkSelected: return "MiniMapLinkSelected";+ case ImNodesCol_MiniMapCanvas: return "MiniMapCanvas";+ case ImNodesCol_MiniMapCanvasOutline: return "MiniMapCanvasOutline";+ }+ IM_ASSERT(0);+ return "Unknown";+}++void BeginNodeEditor()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ GImNodes->CurrentScope = ImNodesScope_Editor;++ // Reset state from previous pass++ ImNodesEditorContext& editor = EditorContextGet();+ editor.AutoPanningDelta = ImVec2(0, 0);+ editor.GridContentBounds = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);+ editor.MiniMapEnabled = false;+ ObjectPoolReset(editor.Nodes);+ ObjectPoolReset(editor.Pins);+ ObjectPoolReset(editor.Links);++ GImNodes->HoveredNodeIdx.Reset();+ GImNodes->HoveredLinkIdx.Reset();+ GImNodes->HoveredPinIdx.Reset();+ GImNodes->DeletedLinkIdx.Reset();+ GImNodes->SnapLinkIdx.Reset();++ GImNodes->NodeIndicesOverlappingWithMouse.clear();++ GImNodes->ImNodesUIState = ImNodesUIState_None;++ GImNodes->MousePos = ImGui::GetIO().MousePos;+ GImNodes->LeftMouseClicked = ImGui::IsMouseClicked(0);+ GImNodes->LeftMouseReleased = ImGui::IsMouseReleased(0);+ GImNodes->LeftMouseDragging = ImGui::IsMouseDragging(0, 0.0f);+ GImNodes->AltMouseClicked =+ (GImNodes->Io.EmulateThreeButtonMouse.Modifier != NULL &&+ *GImNodes->Io.EmulateThreeButtonMouse.Modifier && GImNodes->LeftMouseClicked) ||+ ImGui::IsMouseClicked(GImNodes->Io.AltMouseButton);+ GImNodes->AltMouseDragging =+ (GImNodes->Io.EmulateThreeButtonMouse.Modifier != NULL && GImNodes->LeftMouseDragging &&+ (*GImNodes->Io.EmulateThreeButtonMouse.Modifier)) ||+ ImGui::IsMouseDragging(GImNodes->Io.AltMouseButton, 0.0f);+ GImNodes->AltMouseScrollDelta = ImGui::GetIO().MouseWheel;+ GImNodes->MultipleSelectModifier =+ (GImNodes->Io.MultipleSelectModifier.Modifier != NULL+ ? *GImNodes->Io.MultipleSelectModifier.Modifier+ : ImGui::GetIO().KeyCtrl);++ GImNodes->ActiveAttribute = false;++ ImGui::BeginGroup();+ {+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.f, 1.f));+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.f, 0.f));+ ImGui::PushStyleColor(ImGuiCol_ChildBg, GImNodes->Style.Colors[ImNodesCol_GridBackground]);+ ImGui::BeginChild(+ "scrolling_region",+ ImVec2(0.f, 0.f),+ true,+ ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove |+ ImGuiWindowFlags_NoScrollWithMouse);+ GImNodes->CanvasOriginScreenSpace = ImGui::GetCursorScreenPos();++ // NOTE: we have to fetch the canvas draw list *after* we call+ // BeginChild(), otherwise the ImGui UI elements are going to be+ // rendered into the parent window draw list.+ DrawListSet(ImGui::GetWindowDrawList());++ {+ const ImVec2 canvas_size = ImGui::GetWindowSize();+ GImNodes->CanvasRectScreenSpace = ImRect(+ EditorSpaceToScreenSpace(ImVec2(0.f, 0.f)), EditorSpaceToScreenSpace(canvas_size));++ if (GImNodes->Style.Flags & ImNodesStyleFlags_GridLines)+ {+ DrawGrid(editor, canvas_size);+ }+ }+ }+}++void EndNodeEditor()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);+ GImNodes->CurrentScope = ImNodesScope_None;++ ImNodesEditorContext& editor = EditorContextGet();++ bool no_grid_content = editor.GridContentBounds.IsInverted();+ if (no_grid_content)+ {+ editor.GridContentBounds = ScreenSpaceToGridSpace(editor, GImNodes->CanvasRectScreenSpace);+ }++ // Detect ImGui interaction first, because it blocks interaction with the rest of the UI++ if (GImNodes->LeftMouseClicked && ImGui::IsAnyItemActive())+ {+ editor.ClickInteraction.Type = ImNodesClickInteractionType_ImGuiItem;+ }++ // Detect which UI element is being hovered over. Detection is done in a hierarchical fashion,+ // because a UI element being hovered excludes any other as being hovered over.++ // Don't do hovering detection for nodes/links/pins when interacting with the mini-map, since+ // its an *overlay* with its own interaction behavior and must have precedence during mouse+ // interaction.++ if ((editor.ClickInteraction.Type == ImNodesClickInteractionType_None ||+ editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation) &&+ MouseInCanvas() && !IsMiniMapHovered())+ {+ // Pins needs some special care. We need to check the depth stack to see which pins are+ // being occluded by other nodes.+ ResolveOccludedPins(editor, GImNodes->OccludedPinIndices);++ GImNodes->HoveredPinIdx = ResolveHoveredPin(editor.Pins, GImNodes->OccludedPinIndices);++ if (!GImNodes->HoveredPinIdx.HasValue())+ {+ // Resolve which node is actually on top and being hovered using the depth stack.+ GImNodes->HoveredNodeIdx = ResolveHoveredNode(editor.NodeDepthOrder);+ }++ // We don't check for hovered pins here, because if we want to detach a link by clicking and+ // dragging, we need to have both a link and pin hovered.+ if (!GImNodes->HoveredNodeIdx.HasValue())+ {+ GImNodes->HoveredLinkIdx = ResolveHoveredLink(editor.Links, editor.Pins);+ }+ }++ for (int node_idx = 0; node_idx < editor.Nodes.Pool.size(); ++node_idx)+ {+ if (editor.Nodes.InUse[node_idx])+ {+ DrawListActivateNodeBackground(node_idx);+ DrawNode(editor, node_idx);+ }+ }++ // In order to render the links underneath the nodes, we want to first select the bottom draw+ // channel.+ GImNodes->CanvasDrawList->ChannelsSetCurrent(0);++ for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)+ {+ if (editor.Links.InUse[link_idx])+ {+ DrawLink(editor, link_idx);+ }+ }++ // Render the click interaction UI elements (partial links, box selector) on top of everything+ // else.++ DrawListAppendClickInteractionChannel();+ DrawListActivateClickInteractionChannel();++ if (IsMiniMapActive())+ {+ CalcMiniMapLayout();+ MiniMapUpdate();+ }++ // Handle node graph interaction++ if (!IsMiniMapHovered())+ {+ if (GImNodes->LeftMouseClicked && GImNodes->HoveredLinkIdx.HasValue())+ {+ BeginLinkInteraction(editor, GImNodes->HoveredLinkIdx.Value(), GImNodes->HoveredPinIdx);+ }++ else if (GImNodes->LeftMouseClicked && GImNodes->HoveredPinIdx.HasValue())+ {+ BeginLinkCreation(editor, GImNodes->HoveredPinIdx.Value());+ }++ else if (GImNodes->LeftMouseClicked && GImNodes->HoveredNodeIdx.HasValue())+ {+ BeginNodeSelection(editor, GImNodes->HoveredNodeIdx.Value());+ }++ else if (+ GImNodes->LeftMouseClicked || GImNodes->LeftMouseReleased ||+ GImNodes->AltMouseClicked || GImNodes->AltMouseScrollDelta != 0.f)+ {+ BeginCanvasInteraction(editor);+ }++ bool should_auto_pan =+ editor.ClickInteraction.Type == ImNodesClickInteractionType_BoxSelection ||+ editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation ||+ editor.ClickInteraction.Type == ImNodesClickInteractionType_Node;+ if (should_auto_pan && !MouseInCanvas())+ {+ ImVec2 mouse = ImGui::GetMousePos();+ ImVec2 center = GImNodes->CanvasRectScreenSpace.GetCenter();+ ImVec2 direction = (center - mouse);+ direction = direction * ImInvLength(direction, 0.0);++ editor.AutoPanningDelta =+ direction * ImGui::GetIO().DeltaTime * GImNodes->Io.AutoPanningSpeed;+ editor.Panning += editor.AutoPanningDelta;+ }+ }+ ClickInteractionUpdate(editor);++ // At this point, draw commands have been issued for all nodes (and pins). Update the node pool+ // to detect unused node slots and remove those indices from the depth stack before sorting the+ // node draw commands by depth.+ ObjectPoolUpdate(editor.Nodes);+ ObjectPoolUpdate(editor.Pins);++ DrawListSortChannelsByDepth(editor.NodeDepthOrder);++ // After the links have been rendered, the link pool can be updated as well.+ ObjectPoolUpdate(editor.Links);++ // Finally, merge the draw channels+ GImNodes->CanvasDrawList->ChannelsMerge();++ // pop style+ ImGui::EndChild(); // end scrolling region+ ImGui::PopStyleColor(); // pop child window background color+ ImGui::PopStyleVar(); // pop window padding+ ImGui::PopStyleVar(); // pop frame padding+ ImGui::EndGroup();+}++void MiniMap(+ const float minimap_size_fraction,+ const ImNodesMiniMapLocation location,+ const ImNodesMiniMapNodeHoveringCallback node_hovering_callback,+ const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data)+{+ // Check that editor size fraction is sane; must be in the range (0, 1]+ IM_ASSERT(minimap_size_fraction > 0.f && minimap_size_fraction <= 1.f);++ // Remember to call before EndNodeEditor+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);++ ImNodesEditorContext& editor = EditorContextGet();++ editor.MiniMapEnabled = true;+ editor.MiniMapSizeFraction = minimap_size_fraction;+ editor.MiniMapLocation = location;++ // Set node hovering callback information+ editor.MiniMapNodeHoveringCallback = node_hovering_callback;+ editor.MiniMapNodeHoveringCallbackUserData = node_hovering_callback_data;++ // Actual drawing/updating of the MiniMap is done in EndNodeEditor so that+ // mini map is draw over everything and all pin/link positions are updated+ // correctly relative to their respective nodes. Hence, we must store some of+ // of the state for the mini map in GImNodes for the actual drawing/updating+}++void BeginNode(const int node_id)+{+ // Remember to call BeginNodeEditor before calling BeginNode+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);+ GImNodes->CurrentScope = ImNodesScope_Node;++ ImNodesEditorContext& editor = EditorContextGet();++ const int node_idx = ObjectPoolFindOrCreateIndex(editor.Nodes, node_id);+ GImNodes->CurrentNodeIdx = node_idx;++ ImNodeData& node = editor.Nodes.Pool[node_idx];+ node.ColorStyle.Background = GImNodes->Style.Colors[ImNodesCol_NodeBackground];+ node.ColorStyle.BackgroundHovered = GImNodes->Style.Colors[ImNodesCol_NodeBackgroundHovered];+ node.ColorStyle.BackgroundSelected = GImNodes->Style.Colors[ImNodesCol_NodeBackgroundSelected];+ node.ColorStyle.Outline = GImNodes->Style.Colors[ImNodesCol_NodeOutline];+ node.ColorStyle.Titlebar = GImNodes->Style.Colors[ImNodesCol_TitleBar];+ node.ColorStyle.TitlebarHovered = GImNodes->Style.Colors[ImNodesCol_TitleBarHovered];+ node.ColorStyle.TitlebarSelected = GImNodes->Style.Colors[ImNodesCol_TitleBarSelected];+ node.LayoutStyle.CornerRounding = GImNodes->Style.NodeCornerRounding;+ node.LayoutStyle.Padding = GImNodes->Style.NodePadding;+ node.LayoutStyle.BorderThickness = GImNodes->Style.NodeBorderThickness;++ // ImGui::SetCursorPos sets the cursor position, local to the current widget+ // (in this case, the child object started in BeginNodeEditor). Use+ // ImGui::SetCursorScreenPos to set the screen space coordinates directly.+ ImGui::SetCursorPos(GridSpaceToEditorSpace(editor, GetNodeTitleBarOrigin(node)));++ DrawListAddNode(node_idx);+ DrawListActivateCurrentNodeForeground();++ ImGui::PushID(node.Id);+ ImGui::BeginGroup();+}++void EndNode()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);+ GImNodes->CurrentScope = ImNodesScope_Editor;++ ImNodesEditorContext& editor = EditorContextGet();++ // The node's rectangle depends on the ImGui UI group size.+ ImGui::EndGroup();+ ImGui::PopID();++ ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];+ node.Rect = GetItemRect();+ node.Rect.Expand(node.LayoutStyle.Padding);++ editor.GridContentBounds.Add(node.Origin);+ editor.GridContentBounds.Add(node.Origin + node.Rect.GetSize());++ if (node.Rect.Contains(GImNodes->MousePos))+ {+ GImNodes->NodeIndicesOverlappingWithMouse.push_back(GImNodes->CurrentNodeIdx);+ }+}++ImVec2 GetNodeDimensions(int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ const int node_idx = ObjectPoolFind(editor.Nodes, node_id);+ IM_ASSERT(node_idx != -1); // invalid node_id+ const ImNodeData& node = editor.Nodes.Pool[node_idx];+ return node.Rect.GetSize();+}++void BeginNodeTitleBar()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);+ ImGui::BeginGroup();+}++void EndNodeTitleBar()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);+ ImGui::EndGroup();++ ImNodesEditorContext& editor = EditorContextGet();+ ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];+ node.TitleBarContentRect = GetItemRect();++ ImGui::ItemAdd(GetNodeTitleRect(node), ImGui::GetID("title_bar"));++ ImGui::SetCursorPos(GridSpaceToEditorSpace(editor, GetNodeContentOrigin(node)));+}++void BeginInputAttribute(const int id, const ImNodesPinShape shape)+{+ BeginPinAttribute(id, ImNodesAttributeType_Input, shape, GImNodes->CurrentNodeIdx);+}++void EndInputAttribute() { EndPinAttribute(); }++void BeginOutputAttribute(const int id, const ImNodesPinShape shape)+{+ BeginPinAttribute(id, ImNodesAttributeType_Output, shape, GImNodes->CurrentNodeIdx);+}++void EndOutputAttribute() { EndPinAttribute(); }++void BeginStaticAttribute(const int id)+{+ // Make sure to call BeginNode() before calling BeginAttribute()+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);+ GImNodes->CurrentScope = ImNodesScope_Attribute;++ GImNodes->CurrentAttributeId = id;++ ImGui::BeginGroup();+ ImGui::PushID(id);+}++void EndStaticAttribute()+{+ // Make sure to call BeginNode() before calling BeginAttribute()+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Attribute);+ GImNodes->CurrentScope = ImNodesScope_Node;++ ImGui::PopID();+ ImGui::EndGroup();++ if (ImGui::IsItemActive())+ {+ GImNodes->ActiveAttribute = true;+ GImNodes->ActiveAttributeId = GImNodes->CurrentAttributeId;+ }+}++void PushAttributeFlag(const ImNodesAttributeFlags flag)+{+ GImNodes->CurrentAttributeFlags |= flag;+ GImNodes->AttributeFlagStack.push_back(GImNodes->CurrentAttributeFlags);+}++void PopAttributeFlag()+{+ // PopAttributeFlag called without a matching PushAttributeFlag!+ // The bottom value is always the default value, pushed in Initialize().+ IM_ASSERT(GImNodes->AttributeFlagStack.size() > 1);++ GImNodes->AttributeFlagStack.pop_back();+ GImNodes->CurrentAttributeFlags = GImNodes->AttributeFlagStack.back();+}++void Link(const int id, const int start_attr_id, const int end_attr_id)+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);++ ImNodesEditorContext& editor = EditorContextGet();+ ImLinkData& link = ObjectPoolFindOrCreateObject(editor.Links, id);+ link.Id = id;+ link.StartPinIdx = ObjectPoolFindOrCreateIndex(editor.Pins, start_attr_id);+ link.EndPinIdx = ObjectPoolFindOrCreateIndex(editor.Pins, end_attr_id);+ link.ColorStyle.Base = GImNodes->Style.Colors[ImNodesCol_Link];+ link.ColorStyle.Hovered = GImNodes->Style.Colors[ImNodesCol_LinkHovered];+ link.ColorStyle.Selected = GImNodes->Style.Colors[ImNodesCol_LinkSelected];++ // Check if this link was created by the current link event+ if ((editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation &&+ editor.Pins.Pool[link.EndPinIdx].Flags & ImNodesAttributeFlags_EnableLinkCreationOnSnap &&+ editor.ClickInteraction.LinkCreation.StartPinIdx == link.StartPinIdx &&+ editor.ClickInteraction.LinkCreation.EndPinIdx == link.EndPinIdx) ||+ (editor.ClickInteraction.LinkCreation.StartPinIdx == link.EndPinIdx &&+ editor.ClickInteraction.LinkCreation.EndPinIdx == link.StartPinIdx))+ {+ GImNodes->SnapLinkIdx = ObjectPoolFindOrCreateIndex(editor.Links, id);+ }+}++void PushColorStyle(const ImNodesCol item, unsigned int color)+{+ GImNodes->ColorModifierStack.push_back(ImNodesColElement(GImNodes->Style.Colors[item], item));+ GImNodes->Style.Colors[item] = color;+}++void PopColorStyle()+{+ IM_ASSERT(GImNodes->ColorModifierStack.size() > 0);+ const ImNodesColElement elem = GImNodes->ColorModifierStack.back();+ GImNodes->Style.Colors[elem.Item] = elem.Color;+ GImNodes->ColorModifierStack.pop_back();+}++struct ImNodesStyleVarInfo+{+ ImGuiDataType Type;+ ImU32 Count;+ ImU32 Offset;+ void* GetVarPtr(ImNodesStyle* style) const { return (void*)((unsigned char*)style + Offset); }+};++static const ImNodesStyleVarInfo GStyleVarInfo[] = {+ // ImNodesStyleVar_GridSpacing+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, GridSpacing)},+ // ImNodesStyleVar_NodeCornerRounding+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, NodeCornerRounding)},+ // ImNodesStyleVar_NodePadding+ {ImGuiDataType_Float, 2, (ImU32)offsetof(ImNodesStyle, NodePadding)},+ // ImNodesStyleVar_NodeBorderThickness+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, NodeBorderThickness)},+ // ImNodesStyleVar_LinkThickness+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, LinkThickness)},+ // ImNodesStyleVar_LinkLineSegmentsPerLength+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, LinkLineSegmentsPerLength)},+ // ImNodesStyleVar_LinkHoverDistance+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, LinkHoverDistance)},+ // ImNodesStyleVar_PinCircleRadius+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinCircleRadius)},+ // ImNodesStyleVar_PinQuadSideLength+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinQuadSideLength)},+ // ImNodesStyleVar_PinTriangleSideLength+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinTriangleSideLength)},+ // ImNodesStyleVar_PinLineThickness+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinLineThickness)},+ // ImNodesStyleVar_PinHoverRadius+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinHoverRadius)},+ // ImNodesStyleVar_PinOffset+ {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinOffset)},+ // ImNodesStyleVar_MiniMapPadding+ {ImGuiDataType_Float, 2, (ImU32)offsetof(ImNodesStyle, MiniMapPadding)},+ // ImNodesStyleVar_MiniMapOffset+ {ImGuiDataType_Float, 2, (ImU32)offsetof(ImNodesStyle, MiniMapOffset)},+};++static const ImNodesStyleVarInfo* GetStyleVarInfo(ImNodesStyleVar idx)+{+ IM_ASSERT(idx >= 0 && idx < ImNodesStyleVar_COUNT);+ IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImNodesStyleVar_COUNT);+ return &GStyleVarInfo[idx];+}++void PushStyleVar(const ImNodesStyleVar item, const float value)+{+ const ImNodesStyleVarInfo* var_info = GetStyleVarInfo(item);+ if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)+ {+ float& style_var = *(float*)var_info->GetVarPtr(&GImNodes->Style);+ GImNodes->StyleModifierStack.push_back(ImNodesStyleVarElement(item, style_var));+ style_var = value;+ return;+ }+ IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");+}++void PushStyleVar(const ImNodesStyleVar item, const ImVec2& value)+{+ const ImNodesStyleVarInfo* var_info = GetStyleVarInfo(item);+ if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)+ {+ ImVec2& style_var = *(ImVec2*)var_info->GetVarPtr(&GImNodes->Style);+ GImNodes->StyleModifierStack.push_back(ImNodesStyleVarElement(item, style_var));+ style_var = value;+ return;+ }+ IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");+}++void PopStyleVar(int count)+{+ while (count > 0)+ {+ IM_ASSERT(GImNodes->StyleModifierStack.size() > 0);+ const ImNodesStyleVarElement style_backup = GImNodes->StyleModifierStack.back();+ GImNodes->StyleModifierStack.pop_back();+ const ImNodesStyleVarInfo* var_info = GetStyleVarInfo(style_backup.Item);+ void* style_var = var_info->GetVarPtr(&GImNodes->Style);+ if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)+ {+ ((float*)style_var)[0] = style_backup.FloatValue[0];+ }+ else if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)+ {+ ((float*)style_var)[0] = style_backup.FloatValue[0];+ ((float*)style_var)[1] = style_backup.FloatValue[1];+ }+ count--;+ }+}++void SetNodeScreenSpacePos(const int node_id, const ImVec2& screen_space_pos)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);+ node.Origin = ScreenSpaceToGridSpace(editor, screen_space_pos);+}++void SetNodeEditorSpacePos(const int node_id, const ImVec2& editor_space_pos)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);+ node.Origin = EditorSpaceToGridSpace(editor, editor_space_pos);+}++void SetNodeGridSpacePos(const int node_id, const ImVec2& grid_pos)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);+ node.Origin = grid_pos;+}++void SetNodeDraggable(const int node_id, const bool draggable)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);+ node.Draggable = draggable;+}++ImVec2 GetNodeScreenSpacePos(const int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ const int node_idx = ObjectPoolFind(editor.Nodes, node_id);+ IM_ASSERT(node_idx != -1);+ ImNodeData& node = editor.Nodes.Pool[node_idx];+ return GridSpaceToScreenSpace(editor, node.Origin);+}++ImVec2 GetNodeEditorSpacePos(const int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ const int node_idx = ObjectPoolFind(editor.Nodes, node_id);+ IM_ASSERT(node_idx != -1);+ ImNodeData& node = editor.Nodes.Pool[node_idx];+ return GridSpaceToEditorSpace(editor, node.Origin);+}++ImVec2 GetNodeGridSpacePos(const int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ const int node_idx = ObjectPoolFind(editor.Nodes, node_id);+ IM_ASSERT(node_idx != -1);+ ImNodeData& node = editor.Nodes.Pool[node_idx];+ return node.Origin;+}++void SnapNodeToGrid(int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);+ node.Origin = SnapOriginToGrid(node.Origin);+}++bool IsEditorHovered() { return MouseInCanvas(); }++bool IsNodeHovered(int* const node_id)+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ IM_ASSERT(node_id != NULL);++ const bool is_hovered = GImNodes->HoveredNodeIdx.HasValue();+ if (is_hovered)+ {+ const ImNodesEditorContext& editor = EditorContextGet();+ *node_id = editor.Nodes.Pool[GImNodes->HoveredNodeIdx.Value()].Id;+ }+ return is_hovered;+}++bool IsLinkHovered(int* const link_id)+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ IM_ASSERT(link_id != NULL);++ const bool is_hovered = GImNodes->HoveredLinkIdx.HasValue();+ if (is_hovered)+ {+ const ImNodesEditorContext& editor = EditorContextGet();+ *link_id = editor.Links.Pool[GImNodes->HoveredLinkIdx.Value()].Id;+ }+ return is_hovered;+}++bool IsPinHovered(int* const attr)+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ IM_ASSERT(attr != NULL);++ const bool is_hovered = GImNodes->HoveredPinIdx.HasValue();+ if (is_hovered)+ {+ const ImNodesEditorContext& editor = EditorContextGet();+ *attr = editor.Pins.Pool[GImNodes->HoveredPinIdx.Value()].Id;+ }+ return is_hovered;+}++int NumSelectedNodes()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ const ImNodesEditorContext& editor = EditorContextGet();+ return editor.SelectedNodeIndices.size();+}++int NumSelectedLinks()+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ const ImNodesEditorContext& editor = EditorContextGet();+ return editor.SelectedLinkIndices.size();+}++void GetSelectedNodes(int* node_ids)+{+ IM_ASSERT(node_ids != NULL);++ const ImNodesEditorContext& editor = EditorContextGet();+ for (int i = 0; i < editor.SelectedNodeIndices.size(); ++i)+ {+ const int node_idx = editor.SelectedNodeIndices[i];+ node_ids[i] = editor.Nodes.Pool[node_idx].Id;+ }+}++void GetSelectedLinks(int* link_ids)+{+ IM_ASSERT(link_ids != NULL);++ const ImNodesEditorContext& editor = EditorContextGet();+ for (int i = 0; i < editor.SelectedLinkIndices.size(); ++i)+ {+ const int link_idx = editor.SelectedLinkIndices[i];+ link_ids[i] = editor.Links.Pool[link_idx].Id;+ }+}++void ClearNodeSelection()+{+ ImNodesEditorContext& editor = EditorContextGet();+ editor.SelectedNodeIndices.clear();+}++void ClearNodeSelection(int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ClearObjectSelection(editor.Nodes, editor.SelectedNodeIndices, node_id);+}++void ClearLinkSelection()+{+ ImNodesEditorContext& editor = EditorContextGet();+ editor.SelectedLinkIndices.clear();+}++void ClearLinkSelection(int link_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ ClearObjectSelection(editor.Links, editor.SelectedLinkIndices, link_id);+}++void SelectNode(int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ SelectObject(editor.Nodes, editor.SelectedNodeIndices, node_id);+}++void SelectLink(int link_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ SelectObject(editor.Links, editor.SelectedLinkIndices, link_id);+}++bool IsNodeSelected(int node_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ return IsObjectSelected(editor.Nodes, editor.SelectedNodeIndices, node_id);+}++bool IsLinkSelected(int link_id)+{+ ImNodesEditorContext& editor = EditorContextGet();+ return IsObjectSelected(editor.Links, editor.SelectedLinkIndices, link_id);+}++bool IsAttributeActive()+{+ IM_ASSERT((GImNodes->CurrentScope & ImNodesScope_Node) != 0);++ if (!GImNodes->ActiveAttribute)+ {+ return false;+ }++ return GImNodes->ActiveAttributeId == GImNodes->CurrentAttributeId;+}++bool IsAnyAttributeActive(int* const attribute_id)+{+ IM_ASSERT((GImNodes->CurrentScope & (ImNodesScope_Node | ImNodesScope_Attribute)) == 0);++ if (!GImNodes->ActiveAttribute)+ {+ return false;+ }++ if (attribute_id != NULL)+ {+ *attribute_id = GImNodes->ActiveAttributeId;+ }++ return true;+}++bool IsLinkStarted(int* const started_at_id)+{+ // Call this function after EndNodeEditor()!+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ IM_ASSERT(started_at_id != NULL);++ const bool is_started = (GImNodes->ImNodesUIState & ImNodesUIState_LinkStarted) != 0;+ if (is_started)+ {+ const ImNodesEditorContext& editor = EditorContextGet();+ const int pin_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;+ *started_at_id = editor.Pins.Pool[pin_idx].Id;+ }++ return is_started;+}++bool IsLinkDropped(int* const started_at_id, const bool including_detached_links)+{+ // Call this function after EndNodeEditor()!+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);++ const ImNodesEditorContext& editor = EditorContextGet();++ const bool link_dropped =+ (GImNodes->ImNodesUIState & ImNodesUIState_LinkDropped) != 0 &&+ (including_detached_links ||+ editor.ClickInteraction.LinkCreation.Type != ImNodesLinkCreationType_FromDetach);++ if (link_dropped && started_at_id)+ {+ const int pin_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;+ *started_at_id = editor.Pins.Pool[pin_idx].Id;+ }++ return link_dropped;+}++bool IsLinkCreated(+ int* const started_at_pin_id,+ int* const ended_at_pin_id,+ bool* const created_from_snap)+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ IM_ASSERT(started_at_pin_id != NULL);+ IM_ASSERT(ended_at_pin_id != NULL);++ const bool is_created = (GImNodes->ImNodesUIState & ImNodesUIState_LinkCreated) != 0;++ if (is_created)+ {+ const ImNodesEditorContext& editor = EditorContextGet();+ const int start_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;+ const int end_idx = editor.ClickInteraction.LinkCreation.EndPinIdx.Value();+ const ImPinData& start_pin = editor.Pins.Pool[start_idx];+ const ImPinData& end_pin = editor.Pins.Pool[end_idx];++ if (start_pin.Type == ImNodesAttributeType_Output)+ {+ *started_at_pin_id = start_pin.Id;+ *ended_at_pin_id = end_pin.Id;+ }+ else+ {+ *started_at_pin_id = end_pin.Id;+ *ended_at_pin_id = start_pin.Id;+ }++ if (created_from_snap)+ {+ *created_from_snap =+ editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation;+ }+ }++ return is_created;+}++bool IsLinkCreated(+ int* started_at_node_id,+ int* started_at_pin_id,+ int* ended_at_node_id,+ int* ended_at_pin_id,+ bool* created_from_snap)+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);+ IM_ASSERT(started_at_node_id != NULL);+ IM_ASSERT(started_at_pin_id != NULL);+ IM_ASSERT(ended_at_node_id != NULL);+ IM_ASSERT(ended_at_pin_id != NULL);++ const bool is_created = (GImNodes->ImNodesUIState & ImNodesUIState_LinkCreated) != 0;++ if (is_created)+ {+ const ImNodesEditorContext& editor = EditorContextGet();+ const int start_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;+ const int end_idx = editor.ClickInteraction.LinkCreation.EndPinIdx.Value();+ const ImPinData& start_pin = editor.Pins.Pool[start_idx];+ const ImNodeData& start_node = editor.Nodes.Pool[start_pin.ParentNodeIdx];+ const ImPinData& end_pin = editor.Pins.Pool[end_idx];+ const ImNodeData& end_node = editor.Nodes.Pool[end_pin.ParentNodeIdx];++ if (start_pin.Type == ImNodesAttributeType_Output)+ {+ *started_at_pin_id = start_pin.Id;+ *started_at_node_id = start_node.Id;+ *ended_at_pin_id = end_pin.Id;+ *ended_at_node_id = end_node.Id;+ }+ else+ {+ *started_at_pin_id = end_pin.Id;+ *started_at_node_id = end_node.Id;+ *ended_at_pin_id = start_pin.Id;+ *ended_at_node_id = start_node.Id;+ }++ if (created_from_snap)+ {+ *created_from_snap =+ editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation;+ }+ }++ return is_created;+}++bool IsLinkDestroyed(int* const link_id)+{+ IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);++ const bool link_destroyed = GImNodes->DeletedLinkIdx.HasValue();+ if (link_destroyed)+ {+ const ImNodesEditorContext& editor = EditorContextGet();+ const int link_idx = GImNodes->DeletedLinkIdx.Value();+ *link_id = editor.Links.Pool[link_idx].Id;+ }++ return link_destroyed;+}++namespace+{+void NodeLineHandler(ImNodesEditorContext& editor, const char* const line)+{+ int id;+ int x, y;+ if (sscanf(line, "[node.%i", &id) == 1)+ {+ const int node_idx = ObjectPoolFindOrCreateIndex(editor.Nodes, id);+ GImNodes->CurrentNodeIdx = node_idx;+ ImNodeData& node = editor.Nodes.Pool[node_idx];+ node.Id = id;+ }+ else if (sscanf(line, "origin=%i,%i", &x, &y) == 2)+ {+ ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];+ node.Origin = SnapOriginToGrid(ImVec2((float)x, (float)y));+ }+}++void EditorLineHandler(ImNodesEditorContext& editor, const char* const line)+{+ (void)sscanf(line, "panning=%f,%f", &editor.Panning.x, &editor.Panning.y);+}+} // namespace++const char* SaveCurrentEditorStateToIniString(size_t* const data_size)+{+ return SaveEditorStateToIniString(&EditorContextGet(), data_size);+}++const char* SaveEditorStateToIniString(+ const ImNodesEditorContext* const editor_ptr,+ size_t* const data_size)+{+ IM_ASSERT(editor_ptr != NULL);+ const ImNodesEditorContext& editor = *editor_ptr;++ GImNodes->TextBuffer.clear();+ // TODO: check to make sure that the estimate is the upper bound of element+ GImNodes->TextBuffer.reserve(64 * editor.Nodes.Pool.size());++ GImNodes->TextBuffer.appendf(+ "[editor]\npanning=%i,%i\n", (int)editor.Panning.x, (int)editor.Panning.y);++ for (int i = 0; i < editor.Nodes.Pool.size(); i++)+ {+ if (editor.Nodes.InUse[i])+ {+ const ImNodeData& node = editor.Nodes.Pool[i];+ GImNodes->TextBuffer.appendf("\n[node.%d]\n", node.Id);+ GImNodes->TextBuffer.appendf("origin=%i,%i\n", (int)node.Origin.x, (int)node.Origin.y);+ }+ }++ if (data_size != NULL)+ {+ *data_size = GImNodes->TextBuffer.size();+ }++ return GImNodes->TextBuffer.c_str();+}++void LoadCurrentEditorStateFromIniString(const char* const data, const size_t data_size)+{+ LoadEditorStateFromIniString(&EditorContextGet(), data, data_size);+}++void LoadEditorStateFromIniString(+ ImNodesEditorContext* const editor_ptr,+ const char* const data,+ const size_t data_size)+{+ if (data_size == 0u)+ {+ return;+ }++ ImNodesEditorContext& editor = editor_ptr == NULL ? EditorContextGet() : *editor_ptr;++ char* buf = (char*)ImGui::MemAlloc(data_size + 1);+ const char* buf_end = buf + data_size;+ memcpy(buf, data, data_size);+ buf[data_size] = 0;++ void (*line_handler)(ImNodesEditorContext&, const char*);+ line_handler = NULL;+ char* line_end = NULL;+ for (char* line = buf; line < buf_end; line = line_end + 1)+ {+ while (*line == '\n' || *line == '\r')+ {+ line++;+ }+ line_end = line;+ while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')+ {+ line_end++;+ }+ line_end[0] = 0;++ if (*line == ';' || *line == '\0')+ {+ continue;+ }++ if (line[0] == '[' && line_end[-1] == ']')+ {+ line_end[-1] = 0;+ if (strncmp(line + 1, "node", 4) == 0)+ {+ line_handler = NodeLineHandler;+ }+ else if (strcmp(line + 1, "editor") == 0)+ {+ line_handler = EditorLineHandler;+ }+ }++ if (line_handler != NULL)+ {+ line_handler(editor, line);+ }+ }+ ImGui::MemFree(buf);+}++void SaveCurrentEditorStateToIniFile(const char* const file_name)+{+ SaveEditorStateToIniFile(&EditorContextGet(), file_name);+}++void SaveEditorStateToIniFile(const ImNodesEditorContext* const editor, const char* const file_name)+{+ size_t data_size = 0u;+ const char* data = SaveEditorStateToIniString(editor, &data_size);+ FILE* file = ImFileOpen(file_name, "wt");+ if (!file)+ {+ return;+ }++ fwrite(data, sizeof(char), data_size, file);+ fclose(file);+}++void LoadCurrentEditorStateFromIniFile(const char* const file_name)+{+ LoadEditorStateFromIniFile(&EditorContextGet(), file_name);+}++void LoadEditorStateFromIniFile(ImNodesEditorContext* const editor, const char* const file_name)+{+ size_t data_size = 0u;+ char* file_data = (char*)ImFileLoadToMemory(file_name, "rb", &data_size);++ if (!file_data)+ {+ return;+ }++ LoadEditorStateFromIniString(editor, file_data, data_size);+ ImGui::MemFree(file_data);+}+} // namespace IMNODES_NAMESPACE
+ cbits/imnodes/imnodes.h view
@@ -0,0 +1,440 @@+#pragma once++#include <stddef.h>+#include <imgui.h>++#ifdef IMNODES_USER_CONFIG+#include IMNODES_USER_CONFIG+#endif++#ifndef IMNODES_NAMESPACE+#define IMNODES_NAMESPACE ImNodes+#endif++typedef int ImNodesCol; // -> enum ImNodesCol_+typedef int ImNodesStyleVar; // -> enum ImNodesStyleVar_+typedef int ImNodesStyleFlags; // -> enum ImNodesStyleFlags_+typedef int ImNodesPinShape; // -> enum ImNodesPinShape_+typedef int ImNodesAttributeFlags; // -> enum ImNodesAttributeFlags_+typedef int ImNodesMiniMapLocation; // -> enum ImNodesMiniMapLocation_++enum ImNodesCol_+{+ ImNodesCol_NodeBackground = 0,+ ImNodesCol_NodeBackgroundHovered,+ ImNodesCol_NodeBackgroundSelected,+ ImNodesCol_NodeOutline,+ ImNodesCol_TitleBar,+ ImNodesCol_TitleBarHovered,+ ImNodesCol_TitleBarSelected,+ ImNodesCol_Link,+ ImNodesCol_LinkHovered,+ ImNodesCol_LinkSelected,+ ImNodesCol_Pin,+ ImNodesCol_PinHovered,+ ImNodesCol_BoxSelector,+ ImNodesCol_BoxSelectorOutline,+ ImNodesCol_GridBackground,+ ImNodesCol_GridLine,+ ImNodesCol_GridLinePrimary,+ ImNodesCol_MiniMapBackground,+ ImNodesCol_MiniMapBackgroundHovered,+ ImNodesCol_MiniMapOutline,+ ImNodesCol_MiniMapOutlineHovered,+ ImNodesCol_MiniMapNodeBackground,+ ImNodesCol_MiniMapNodeBackgroundHovered,+ ImNodesCol_MiniMapNodeBackgroundSelected,+ ImNodesCol_MiniMapNodeOutline,+ ImNodesCol_MiniMapLink,+ ImNodesCol_MiniMapLinkSelected,+ ImNodesCol_MiniMapCanvas,+ ImNodesCol_MiniMapCanvasOutline,+ ImNodesCol_COUNT+};++enum ImNodesStyleVar_+{+ ImNodesStyleVar_GridSpacing = 0,+ ImNodesStyleVar_NodeCornerRounding,+ ImNodesStyleVar_NodePadding,+ ImNodesStyleVar_NodeBorderThickness,+ ImNodesStyleVar_LinkThickness,+ ImNodesStyleVar_LinkLineSegmentsPerLength,+ ImNodesStyleVar_LinkHoverDistance,+ ImNodesStyleVar_PinCircleRadius,+ ImNodesStyleVar_PinQuadSideLength,+ ImNodesStyleVar_PinTriangleSideLength,+ ImNodesStyleVar_PinLineThickness,+ ImNodesStyleVar_PinHoverRadius,+ ImNodesStyleVar_PinOffset,+ ImNodesStyleVar_MiniMapPadding,+ ImNodesStyleVar_MiniMapOffset,+ ImNodesStyleVar_COUNT+};++enum ImNodesStyleFlags_+{+ ImNodesStyleFlags_None = 0,+ ImNodesStyleFlags_NodeOutline = 1 << 0,+ ImNodesStyleFlags_GridLines = 1 << 2,+ ImNodesStyleFlags_GridLinesPrimary = 1 << 3,+ ImNodesStyleFlags_GridSnapping = 1 << 4+};++enum ImNodesPinShape_+{+ ImNodesPinShape_Circle,+ ImNodesPinShape_CircleFilled,+ ImNodesPinShape_Triangle,+ ImNodesPinShape_TriangleFilled,+ ImNodesPinShape_Quad,+ ImNodesPinShape_QuadFilled+};++// This enum controls the way the attribute pins behave.+enum ImNodesAttributeFlags_+{+ ImNodesAttributeFlags_None = 0,+ // Allow detaching a link by left-clicking and dragging the link at a pin it is connected to.+ // NOTE: the user has to actually delete the link for this to work. A deleted link can be+ // detected by calling IsLinkDestroyed() after EndNodeEditor().+ ImNodesAttributeFlags_EnableLinkDetachWithDragClick = 1 << 0,+ // Visual snapping of an in progress link will trigger IsLink Created/Destroyed events. Allows+ // for previewing the creation of a link while dragging it across attributes. See here for demo:+ // https://github.com/Nelarius/imnodes/issues/41#issuecomment-647132113 NOTE: the user has to+ // actually delete the link for this to work. A deleted link can be detected by calling+ // IsLinkDestroyed() after EndNodeEditor().+ ImNodesAttributeFlags_EnableLinkCreationOnSnap = 1 << 1+};++struct ImNodesIO+{+ struct EmulateThreeButtonMouse+ {+ EmulateThreeButtonMouse();++ // The keyboard modifier to use in combination with mouse left click to pan the editor view.+ // Set to NULL by default. To enable this feature, set the modifier to point to a boolean+ // indicating the state of a modifier. For example,+ //+ // ImNodes::GetIO().EmulateThreeButtonMouse.Modifier = &ImGui::GetIO().KeyAlt;+ const bool* Modifier;+ } EmulateThreeButtonMouse;++ struct LinkDetachWithModifierClick+ {+ LinkDetachWithModifierClick();++ // Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL+ // by default. To enable the feature, set the modifier to point to a boolean indicating the+ // state of a modifier. For example,+ //+ // ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;+ //+ // Left-clicking a link with this modifier pressed will detach that link. NOTE: the user has+ // to actually delete the link for this to work. A deleted link can be detected by calling+ // IsLinkDestroyed() after EndNodeEditor().+ const bool* Modifier;+ } LinkDetachWithModifierClick;++ struct MultipleSelectModifier+ {+ MultipleSelectModifier();++ // Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL+ // by default. To enable the feature, set the modifier to point to a boolean indicating the+ // state of a modifier. For example,+ //+ // ImNodes::GetIO().MultipleSelectModifier.Modifier = &ImGui::GetIO().KeyCtrl;+ //+ // Left-clicking a node with this modifier pressed will add the node to the list of+ // currently selected nodes. If this value is NULL, the Ctrl key will be used.+ const bool* Modifier;+ } MultipleSelectModifier;++ // Holding alt mouse button pans the node area, by default middle mouse button will be used+ // Set based on ImGuiMouseButton values+ int AltMouseButton;++ // Panning speed when dragging an element and mouse is outside the main editor view.+ float AutoPanningSpeed;++ ImNodesIO();+};++struct ImNodesStyle+{+ float GridSpacing;++ float NodeCornerRounding;+ ImVec2 NodePadding;+ float NodeBorderThickness;++ float LinkThickness;+ float LinkLineSegmentsPerLength;+ float LinkHoverDistance;++ // The following variables control the look and behavior of the pins. The default size of each+ // pin shape is balanced to occupy approximately the same surface area on the screen.++ // The circle radius used when the pin shape is either ImNodesPinShape_Circle or+ // ImNodesPinShape_CircleFilled.+ float PinCircleRadius;+ // The quad side length used when the shape is either ImNodesPinShape_Quad or+ // ImNodesPinShape_QuadFilled.+ float PinQuadSideLength;+ // The equilateral triangle side length used when the pin shape is either+ // ImNodesPinShape_Triangle or ImNodesPinShape_TriangleFilled.+ float PinTriangleSideLength;+ // The thickness of the line used when the pin shape is not filled.+ float PinLineThickness;+ // The radius from the pin's center position inside of which it is detected as being hovered+ // over.+ float PinHoverRadius;+ // Offsets the pins' positions from the edge of the node to the outside of the node.+ float PinOffset;++ // Mini-map padding size between mini-map edge and mini-map content.+ ImVec2 MiniMapPadding;+ // Mini-map offset from the screen side.+ ImVec2 MiniMapOffset;++ // By default, ImNodesStyleFlags_NodeOutline and ImNodesStyleFlags_Gridlines are enabled.+ ImNodesStyleFlags Flags;+ // Set these mid-frame using Push/PopColorStyle. You can index this color array with with a+ // ImNodesCol value.+ unsigned int Colors[ImNodesCol_COUNT];++ ImNodesStyle();+};++enum ImNodesMiniMapLocation_+{+ ImNodesMiniMapLocation_BottomLeft,+ ImNodesMiniMapLocation_BottomRight,+ ImNodesMiniMapLocation_TopLeft,+ ImNodesMiniMapLocation_TopRight,+};++struct ImGuiContext;+struct ImVec2;++struct ImNodesContext;++// An editor context corresponds to a set of nodes in a single workspace (created with a single+// Begin/EndNodeEditor pair)+//+// By default, the library creates an editor context behind the scenes, so using any of the imnodes+// functions doesn't require you to explicitly create a context.+struct ImNodesEditorContext;++// Callback type used to specify special behavior when hovering a node in the minimap+#ifndef ImNodesMiniMapNodeHoveringCallback+typedef void (*ImNodesMiniMapNodeHoveringCallback)(int, void*);+#endif++#ifndef ImNodesMiniMapNodeHoveringCallbackUserData+typedef void* ImNodesMiniMapNodeHoveringCallbackUserData;+#endif++namespace IMNODES_NAMESPACE+{+// Call this function if you are compiling imnodes in to a dll, separate from ImGui. Calling this+// function sets the GImGui global variable, which is not shared across dll boundaries.+void SetImGuiContext(ImGuiContext* ctx);++ImNodesContext* CreateContext();+void DestroyContext(ImNodesContext* ctx = NULL); // NULL = destroy current context+ImNodesContext* GetCurrentContext();+void SetCurrentContext(ImNodesContext* ctx);++ImNodesEditorContext* EditorContextCreate();+void EditorContextFree(ImNodesEditorContext*);+void EditorContextSet(ImNodesEditorContext*);+ImVec2 EditorContextGetPanning();+void EditorContextResetPanning(const ImVec2& pos);+void EditorContextMoveToNode(const int node_id);++ImNodesIO& GetIO();++// Returns the global style struct. See the struct declaration for default values.+ImNodesStyle& GetStyle();+// Style presets matching the dear imgui styles of the same name. If dest is NULL, the active+// context's ImNodesStyle instance will be used as the destination.+void StyleColorsDark(ImNodesStyle* dest = NULL); // on by default+void StyleColorsClassic(ImNodesStyle* dest = NULL);+void StyleColorsLight(ImNodesStyle* dest = NULL);+// Get a string corresponding to the enum value (for display, saving, etc.).+const char* GetStyleColorName(ImNodesCol idx);++// The top-level function call. Call this before calling BeginNode/EndNode. Calling this function+// will result the node editor grid workspace being rendered.+void BeginNodeEditor();+void EndNodeEditor();++// Add a navigable minimap to the editor; call before EndNodeEditor after all+// nodes and links have been specified+void MiniMap(+ const float minimap_size_fraction = 0.2f,+ const ImNodesMiniMapLocation location = ImNodesMiniMapLocation_TopLeft,+ const ImNodesMiniMapNodeHoveringCallback node_hovering_callback = NULL,+ const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data = NULL);++// Use PushColorStyle and PopColorStyle to modify ImNodesStyle::Colors mid-frame.+void PushColorStyle(ImNodesCol item, unsigned int color);+void PopColorStyle();+void PushStyleVar(ImNodesStyleVar style_item, float value);+void PushStyleVar(ImNodesStyleVar style_item, const ImVec2& value);+void PopStyleVar(int count = 1);++// id can be any positive or negative integer, but INT_MIN is currently reserved for internal use.+void BeginNode(int id);+void EndNode();++ImVec2 GetNodeDimensions(int id);++// Place your node title bar content (such as the node title, using ImGui::Text) between the+// following function calls. These functions have to be called before adding any attributes, or the+// layout of the node will be incorrect.+void BeginNodeTitleBar();+void EndNodeTitleBar();++// Attributes are ImGui UI elements embedded within the node. Attributes can have pin shapes+// rendered next to them. Links are created between pins.+//+// The activity status of an attribute can be checked via the IsAttributeActive() and+// IsAnyAttributeActive() function calls. This is one easy way of checking for any changes made to+// an attribute's drag float UI, for instance.+//+// Each attribute id must be unique.++// Create an input attribute block. The pin is rendered on left side.+void BeginInputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);+void EndInputAttribute();+// Create an output attribute block. The pin is rendered on the right side.+void BeginOutputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);+void EndOutputAttribute();+// Create a static attribute block. A static attribute has no pin, and therefore can't be linked to+// anything. However, you can still use IsAttributeActive() and IsAnyAttributeActive() to check for+// attribute activity.+void BeginStaticAttribute(int id);+void EndStaticAttribute();++// Push a single AttributeFlags value. By default, only AttributeFlags_None is set.+void PushAttributeFlag(ImNodesAttributeFlags flag);+void PopAttributeFlag();++// Render a link between attributes.+// The attributes ids used here must match the ids used in Begin(Input|Output)Attribute function+// calls. The order of start_attr and end_attr doesn't make a difference for rendering the link.+void Link(int id, int start_attribute_id, int end_attribute_id);++// Enable or disable the ability to click and drag a specific node.+void SetNodeDraggable(int node_id, const bool draggable);++// The node's position can be expressed in three coordinate systems:+// * screen space coordinates, -- the origin is the upper left corner of the window.+// * editor space coordinates -- the origin is the upper left corner of the node editor window+// * grid space coordinates, -- the origin is the upper left corner of the node editor window,+// translated by the current editor panning vector (see EditorContextGetPanning() and+// EditorContextResetPanning())++// Use the following functions to get and set the node's coordinates in these coordinate systems.++void SetNodeScreenSpacePos(int node_id, const ImVec2& screen_space_pos);+void SetNodeEditorSpacePos(int node_id, const ImVec2& editor_space_pos);+void SetNodeGridSpacePos(int node_id, const ImVec2& grid_pos);++ImVec2 GetNodeScreenSpacePos(const int node_id);+ImVec2 GetNodeEditorSpacePos(const int node_id);+ImVec2 GetNodeGridSpacePos(const int node_id);++// If ImNodesStyleFlags_GridSnapping is enabled, snap the specified node's origin to the grid.+void SnapNodeToGrid(int node_id);++// Returns true if the current node editor canvas is being hovered over by the mouse, and is not+// blocked by any other windows.+bool IsEditorHovered();+// The following functions return true if a UI element is being hovered over by the mouse cursor.+// Assigns the id of the UI element being hovered over to the function argument. Use these functions+// after EndNodeEditor() has been called.+bool IsNodeHovered(int* node_id);+bool IsLinkHovered(int* link_id);+bool IsPinHovered(int* attribute_id);++// Use The following two functions to query the number of selected nodes or links in the current+// editor. Use after calling EndNodeEditor().+int NumSelectedNodes();+int NumSelectedLinks();+// Get the selected node/link ids. The pointer argument should point to an integer array with at+// least as many elements as the respective NumSelectedNodes/NumSelectedLinks function call+// returned.+void GetSelectedNodes(int* node_ids);+void GetSelectedLinks(int* link_ids);+// Clears the list of selected nodes/links. Useful if you want to delete a selected node or link.+void ClearNodeSelection();+void ClearLinkSelection();+// Use the following functions to add or remove individual nodes or links from the current editors+// selection. Note that all functions require the id to be an existing valid id for this editor.+// Select-functions has the precondition that the object is currently considered unselected.+// Clear-functions has the precondition that the object is currently considered selected.+// Preconditions listed above can be checked via IsNodeSelected/IsLinkSelected if not already+// known.+void SelectNode(int node_id);+void ClearNodeSelection(int node_id);+bool IsNodeSelected(int node_id);+void SelectLink(int link_id);+void ClearLinkSelection(int link_id);+bool IsLinkSelected(int link_id);++// Was the previous attribute active? This will continuously return true while the left mouse button+// is being pressed over the UI content of the attribute.+bool IsAttributeActive();+// Was any attribute active? If so, sets the active attribute id to the output function argument.+bool IsAnyAttributeActive(int* attribute_id = NULL);++// Use the following functions to query a change of state for an existing link, or new link. Call+// these after EndNodeEditor().++// Did the user start dragging a new link from a pin?+bool IsLinkStarted(int* started_at_attribute_id);+// Did the user drop the dragged link before attaching it to a pin?+// There are two different kinds of situations to consider when handling this event:+// 1) a link which is created at a pin and then dropped+// 2) an existing link which is detached from a pin and then dropped+// Use the including_detached_links flag to control whether this function triggers when the user+// detaches a link and drops it.+bool IsLinkDropped(int* started_at_attribute_id = NULL, bool including_detached_links = true);+// Did the user finish creating a new link?+bool IsLinkCreated(+ int* started_at_attribute_id,+ int* ended_at_attribute_id,+ bool* created_from_snap = NULL);+bool IsLinkCreated(+ int* started_at_node_id,+ int* started_at_attribute_id,+ int* ended_at_node_id,+ int* ended_at_attribute_id,+ bool* created_from_snap = NULL);++// Was an existing link detached from a pin by the user? The detached link's id is assigned to the+// output argument link_id.+bool IsLinkDestroyed(int* link_id);++// Use the following functions to write the editor context's state to a string, or directly to a+// file. The editor context is serialized in the INI file format.++const char* SaveCurrentEditorStateToIniString(size_t* data_size = NULL);+const char* SaveEditorStateToIniString(+ const ImNodesEditorContext* editor,+ size_t* data_size = NULL);++void LoadCurrentEditorStateFromIniString(const char* data, size_t data_size);+void LoadEditorStateFromIniString(ImNodesEditorContext* editor, const char* data, size_t data_size);++void SaveCurrentEditorStateToIniFile(const char* file_name);+void SaveEditorStateToIniFile(const ImNodesEditorContext* editor, const char* file_name);++void LoadCurrentEditorStateFromIniFile(const char* file_name);+void LoadEditorStateFromIniFile(ImNodesEditorContext* editor, const char* file_name);+} // namespace IMNODES_NAMESPACE
+ cbits/imnodes/imnodes_internal.h view
@@ -0,0 +1,500 @@+#pragma once++#define IMGUI_DEFINE_MATH_OPERATORS+#include <imgui.h>+#include <imgui_internal.h>++#include "imnodes.h"++#include <limits.h>++// the structure of this file:+//+// [SECTION] internal enums+// [SECTION] internal data structures+// [SECTION] global and editor context structs+// [SECTION] object pool implementation++struct ImNodesContext;++extern ImNodesContext* GImNodes;++// [SECTION] internal enums++typedef int ImNodesScope;+typedef int ImNodesAttributeType;+typedef int ImNodesUIState;+typedef int ImNodesClickInteractionType;+typedef int ImNodesLinkCreationType;++enum ImNodesScope_+{+ ImNodesScope_None = 1,+ ImNodesScope_Editor = 1 << 1,+ ImNodesScope_Node = 1 << 2,+ ImNodesScope_Attribute = 1 << 3+};++enum ImNodesAttributeType_+{+ ImNodesAttributeType_None,+ ImNodesAttributeType_Input,+ ImNodesAttributeType_Output+};++enum ImNodesUIState_+{+ ImNodesUIState_None = 0,+ ImNodesUIState_LinkStarted = 1 << 0,+ ImNodesUIState_LinkDropped = 1 << 1,+ ImNodesUIState_LinkCreated = 1 << 2+};++enum ImNodesClickInteractionType_+{+ ImNodesClickInteractionType_Node,+ ImNodesClickInteractionType_Link,+ ImNodesClickInteractionType_LinkCreation,+ ImNodesClickInteractionType_Panning,+ ImNodesClickInteractionType_BoxSelection,+ ImNodesClickInteractionType_ImGuiItem,+ ImNodesClickInteractionType_None+};++enum ImNodesLinkCreationType_+{+ ImNodesLinkCreationType_Standard,+ ImNodesLinkCreationType_FromDetach+};++// [SECTION] internal data structures++// The object T must have the following interface:+//+// struct T+// {+// T();+//+// int id;+// };+template<typename T>+struct ImObjectPool+{+ ImVector<T> Pool;+ ImVector<bool> InUse;+ ImVector<int> FreeList;+ ImGuiStorage IdMap;++ ImObjectPool() : Pool(), InUse(), FreeList(), IdMap() {}+};++// Emulates std::optional<int> using the sentinel value `INVALID_INDEX`.+struct ImOptionalIndex+{+ ImOptionalIndex() : _Index(INVALID_INDEX) {}+ ImOptionalIndex(const int value) : _Index(value) {}++ // Observers++ inline bool HasValue() const { return _Index != INVALID_INDEX; }++ inline int Value() const+ {+ IM_ASSERT(HasValue());+ return _Index;+ }++ // Modifiers++ inline ImOptionalIndex& operator=(const int value)+ {+ _Index = value;+ return *this;+ }++ inline void Reset() { _Index = INVALID_INDEX; }++ inline bool operator==(const ImOptionalIndex& rhs) const { return _Index == rhs._Index; }++ inline bool operator==(const int rhs) const { return _Index == rhs; }++ inline bool operator!=(const ImOptionalIndex& rhs) const { return _Index != rhs._Index; }++ inline bool operator!=(const int rhs) const { return _Index != rhs; }++ static const int INVALID_INDEX = -1;++private:+ int _Index;+};++struct ImNodeData+{+ int Id;+ ImVec2 Origin; // The node origin is in editor space+ ImRect TitleBarContentRect;+ ImRect Rect;++ struct+ {+ ImU32 Background, BackgroundHovered, BackgroundSelected, Outline, Titlebar, TitlebarHovered,+ TitlebarSelected;+ } ColorStyle;++ struct+ {+ float CornerRounding;+ ImVec2 Padding;+ float BorderThickness;+ } LayoutStyle;++ ImVector<int> PinIndices;+ bool Draggable;++ ImNodeData(const int node_id)+ : Id(node_id), Origin(0.0f, 0.0f), TitleBarContentRect(),+ Rect(ImVec2(0.0f, 0.0f), ImVec2(0.0f, 0.0f)), ColorStyle(), LayoutStyle(), PinIndices(),+ Draggable(true)+ {+ }++ ~ImNodeData() { Id = INT_MIN; }+};++struct ImPinData+{+ int Id;+ int ParentNodeIdx;+ ImRect AttributeRect;+ ImNodesAttributeType Type;+ ImNodesPinShape Shape;+ ImVec2 Pos; // screen-space coordinates+ int Flags;++ struct+ {+ ImU32 Background, Hovered;+ } ColorStyle;++ ImPinData(const int pin_id)+ : Id(pin_id), ParentNodeIdx(), AttributeRect(), Type(ImNodesAttributeType_None),+ Shape(ImNodesPinShape_CircleFilled), Pos(), Flags(ImNodesAttributeFlags_None),+ ColorStyle()+ {+ }+};++struct ImLinkData+{+ int Id;+ int StartPinIdx, EndPinIdx;++ struct+ {+ ImU32 Base, Hovered, Selected;+ } ColorStyle;++ ImLinkData(const int link_id) : Id(link_id), StartPinIdx(), EndPinIdx(), ColorStyle() {}+};++struct ImClickInteractionState+{+ ImNodesClickInteractionType Type;++ struct+ {+ int StartPinIdx;+ ImOptionalIndex EndPinIdx;+ ImNodesLinkCreationType Type;+ } LinkCreation;++ struct+ {+ ImRect Rect; // Coordinates in grid space+ } BoxSelector;++ ImClickInteractionState() : Type(ImNodesClickInteractionType_None) {}+};++struct ImNodesColElement+{+ ImU32 Color;+ ImNodesCol Item;++ ImNodesColElement(const ImU32 c, const ImNodesCol s) : Color(c), Item(s) {}+};++struct ImNodesStyleVarElement+{+ ImNodesStyleVar Item;+ float FloatValue[2];++ ImNodesStyleVarElement(const ImNodesStyleVar variable, const float value) : Item(variable)+ {+ FloatValue[0] = value;+ }++ ImNodesStyleVarElement(const ImNodesStyleVar variable, const ImVec2 value) : Item(variable)+ {+ FloatValue[0] = value.x;+ FloatValue[1] = value.y;+ }+};++// [SECTION] global and editor context structs++struct ImNodesEditorContext+{+ ImObjectPool<ImNodeData> Nodes;+ ImObjectPool<ImPinData> Pins;+ ImObjectPool<ImLinkData> Links;++ ImVector<int> NodeDepthOrder;++ // ui related fields+ ImVec2 Panning;+ ImVec2 AutoPanningDelta;+ // Minimum and maximum extents of all content in grid space. Valid after final+ // ImNodes::EndNode() call.+ ImRect GridContentBounds;++ ImVector<int> SelectedNodeIndices;+ ImVector<int> SelectedLinkIndices;++ // Relative origins of selected nodes for snapping of dragged nodes+ ImVector<ImVec2> SelectedNodeOffsets;+ // Offset of the primary node origin relative to the mouse cursor.+ ImVec2 PrimaryNodeOffset;++ ImClickInteractionState ClickInteraction;++ // Mini-map state set by MiniMap()++ bool MiniMapEnabled;+ ImNodesMiniMapLocation MiniMapLocation;+ float MiniMapSizeFraction;+ ImNodesMiniMapNodeHoveringCallback MiniMapNodeHoveringCallback;+ ImNodesMiniMapNodeHoveringCallbackUserData MiniMapNodeHoveringCallbackUserData;++ // Mini-map state set during EndNodeEditor() call++ ImRect MiniMapRectScreenSpace;+ ImRect MiniMapContentScreenSpace;+ float MiniMapScaling;++ ImNodesEditorContext()+ : Nodes(), Pins(), Links(), Panning(0.f, 0.f), SelectedNodeIndices(), SelectedLinkIndices(),+ SelectedNodeOffsets(), PrimaryNodeOffset(0.f, 0.f), ClickInteraction(),+ MiniMapEnabled(false), MiniMapSizeFraction(0.0f), MiniMapNodeHoveringCallback(NULL),+ MiniMapNodeHoveringCallbackUserData(NULL), MiniMapScaling(0.0f)+ {+ }+};++struct ImNodesContext+{+ ImNodesEditorContext* DefaultEditorCtx;+ ImNodesEditorContext* EditorCtx;++ // Canvas draw list and helper state+ ImDrawList* CanvasDrawList;+ ImGuiStorage NodeIdxToSubmissionIdx;+ ImVector<int> NodeIdxSubmissionOrder;+ ImVector<int> NodeIndicesOverlappingWithMouse;+ ImVector<int> OccludedPinIndices;++ // Canvas extents+ ImVec2 CanvasOriginScreenSpace;+ ImRect CanvasRectScreenSpace;++ // Debug helpers+ ImNodesScope CurrentScope;++ // Configuration state+ ImNodesIO Io;+ ImNodesStyle Style;+ ImVector<ImNodesColElement> ColorModifierStack;+ ImVector<ImNodesStyleVarElement> StyleModifierStack;+ ImGuiTextBuffer TextBuffer;++ int CurrentAttributeFlags;+ ImVector<int> AttributeFlagStack;++ // UI element state+ int CurrentNodeIdx;+ int CurrentPinIdx;+ int CurrentAttributeId;++ ImOptionalIndex HoveredNodeIdx;+ ImOptionalIndex HoveredLinkIdx;+ ImOptionalIndex HoveredPinIdx;++ ImOptionalIndex DeletedLinkIdx;+ ImOptionalIndex SnapLinkIdx;++ // Event helper state+ // TODO: this should be a part of a state machine, and not a member of the global struct.+ // Unclear what parts of the code this relates to.+ int ImNodesUIState;++ int ActiveAttributeId;+ bool ActiveAttribute;++ // ImGui::IO cache++ ImVec2 MousePos;++ bool LeftMouseClicked;+ bool LeftMouseReleased;+ bool AltMouseClicked;+ bool LeftMouseDragging;+ bool AltMouseDragging;+ float AltMouseScrollDelta;+ bool MultipleSelectModifier;+};++namespace IMNODES_NAMESPACE+{+static inline ImNodesEditorContext& EditorContextGet()+{+ // No editor context was set! Did you forget to call ImNodes::CreateContext()?+ IM_ASSERT(GImNodes->EditorCtx != NULL);+ return *GImNodes->EditorCtx;+}++// [SECTION] ObjectPool implementation++template<typename T>+static inline int ObjectPoolFind(const ImObjectPool<T>& objects, const int id)+{+ const int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);+ return index;+}++template<typename T>+static inline void ObjectPoolUpdate(ImObjectPool<T>& objects)+{+ for (int i = 0; i < objects.InUse.size(); ++i)+ {+ const int id = objects.Pool[i].Id;++ if (!objects.InUse[i] && objects.IdMap.GetInt(id, -1) == i)+ {+ objects.IdMap.SetInt(id, -1);+ objects.FreeList.push_back(i);+ (objects.Pool.Data + i)->~T();+ }+ }+}++template<>+inline void ObjectPoolUpdate(ImObjectPool<ImNodeData>& nodes)+{+ for (int i = 0; i < nodes.InUse.size(); ++i)+ {+ if (nodes.InUse[i])+ {+ nodes.Pool[i].PinIndices.clear();+ }+ else+ {+ const int id = nodes.Pool[i].Id;++ if (nodes.IdMap.GetInt(id, -1) == i)+ {+ // Remove node idx form depth stack the first time we detect that this idx slot is+ // unused+ ImVector<int>& depth_stack = EditorContextGet().NodeDepthOrder;+ const int* const elem = depth_stack.find(i);+ IM_ASSERT(elem != depth_stack.end());+ depth_stack.erase(elem);++ nodes.IdMap.SetInt(id, -1);+ nodes.FreeList.push_back(i);+ (nodes.Pool.Data + i)->~ImNodeData();+ }+ }+ }+}++template<typename T>+static inline void ObjectPoolReset(ImObjectPool<T>& objects)+{+ if (!objects.InUse.empty())+ {+ memset(objects.InUse.Data, 0, objects.InUse.size_in_bytes());+ }+}++template<typename T>+static inline int ObjectPoolFindOrCreateIndex(ImObjectPool<T>& objects, const int id)+{+ int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);++ // Construct new object+ if (index == -1)+ {+ if (objects.FreeList.empty())+ {+ index = objects.Pool.size();+ IM_ASSERT(objects.Pool.size() == objects.InUse.size());+ const int new_size = objects.Pool.size() + 1;+ objects.Pool.resize(new_size);+ objects.InUse.resize(new_size);+ }+ else+ {+ index = objects.FreeList.back();+ objects.FreeList.pop_back();+ }+ IM_PLACEMENT_NEW(objects.Pool.Data + index) T(id);+ objects.IdMap.SetInt(static_cast<ImGuiID>(id), index);+ }++ // Flag it as used+ objects.InUse[index] = true;++ return index;+}++template<>+inline int ObjectPoolFindOrCreateIndex(ImObjectPool<ImNodeData>& nodes, const int node_id)+{+ int node_idx = nodes.IdMap.GetInt(static_cast<ImGuiID>(node_id), -1);++ // Construct new node+ if (node_idx == -1)+ {+ if (nodes.FreeList.empty())+ {+ node_idx = nodes.Pool.size();+ IM_ASSERT(nodes.Pool.size() == nodes.InUse.size());+ const int new_size = nodes.Pool.size() + 1;+ nodes.Pool.resize(new_size);+ nodes.InUse.resize(new_size);+ }+ else+ {+ node_idx = nodes.FreeList.back();+ nodes.FreeList.pop_back();+ }+ IM_PLACEMENT_NEW(nodes.Pool.Data + node_idx) ImNodeData(node_id);+ nodes.IdMap.SetInt(static_cast<ImGuiID>(node_id), node_idx);++ ImNodesEditorContext& editor = EditorContextGet();+ editor.NodeDepthOrder.push_back(node_idx);+ }++ // Flag node as used+ nodes.InUse[node_idx] = true;++ return node_idx;+}++template<typename T>+static inline T& ObjectPoolFindOrCreateObject(ImObjectPool<T>& objects, const int id)+{+ const int index = ObjectPoolFindOrCreateIndex(objects, id);+ return objects.Pool[index];+}+} // namespace IMNODES_NAMESPACE
+ dear-imgui-raw-imnodes.cabal view
@@ -0,0 +1,72 @@+cabal-version: 2.2++-- This file has been generated from package.yaml by hpack version 0.39.6.+--+-- see: https://github.com/sol/hpack++name: dear-imgui-raw-imnodes+version: 1.0.0+synopsis: Raw FFI bindings to imnodes (Nelarius/imnodes) for dear-imgui-raw.+description: Generated with dear_bindings from the bundled imnodes sources, compiled against the Dear ImGui build in dear-imgui-raw.+category: GUI+maintainer: IC Rainbow <aenor.realm@gmail.com>+license: BSD-3-Clause+license-file: LICENSE+build-type: Simple+extra-doc-files:+ README.md+ CHANGELOG.md++library+ exposed-modules:+ DearImGui.ImNodes.Context+ DearImGui.Raw.ImNodes+ DearImGui.Raw.ImNodes.Context+ DearImGui.Raw.ImNodes.EditorContext+ DearImGui.Raw.ImNodes.Enums.AttributeFlags+ DearImGui.Raw.ImNodes.Enums.Col+ DearImGui.Raw.ImNodes.Enums.MiniMapLocation+ DearImGui.Raw.ImNodes.Enums.PinShape+ DearImGui.Raw.ImNodes.Enums.StyleFlags+ DearImGui.Raw.ImNodes.Enums.StyleVar+ DearImGui.Raw.ImNodes.ImNodesIO+ DearImGui.Raw.ImNodes.Style+ other-modules:+ Paths_dear_imgui_raw_imnodes+ autogen-modules:+ Paths_dear_imgui_raw_imnodes+ hs-source-dirs:+ src+ default-extensions:+ BlockArguments+ DataKinds+ DuplicateRecordFields+ LambdaCase+ NoFieldSelectors+ OverloadedRecordDot+ OverloadedStrings+ StrictData+ ghc-options: -Wall -optc-Wno-discarded-qualifiers -optc-Wno-incompatible-pointer-types+ cxx-options: -std=c++11 -fpermissive+ include-dirs:+ cbits+ cbits/imnodes+ install-includes:+ dcimnodes.h+ imnodes/imnodes.h+ imnodes/imnodes_internal.h+ DearImGuiWrappers.h+ cxx-sources:+ cbits/dcimnodes.cpp+ cbits/imnodes/imnodes.cpp+ cbits/DearImGuiWrappers.cpp+ cbits/DearImGuiCtors.cpp+ extra-libraries:+ stdc+++ build-tool-depends:+ hsc2hs:hsc2hs+ build-depends:+ base >=4.16 && <5+ , dear-imgui-raw ==1.0.*+ , unliftio-core+ default-language: GHC2021
+ src/DearImGui/ImNodes/Context.hs view
@@ -0,0 +1,12 @@+-- | Exception-safe scope around 'ImNodes.createContext' / 'ImNodes.destroyContext'.+module DearImGui.ImNodes.Context+ ( withContext+ ) where++import Control.Monad.IO.Unlift (MonadUnliftIO)++import DearImGui.Bracket (withCreated)+import DearImGui.Raw.ImNodes qualified as ImNodes++withContext :: (MonadUnliftIO m) => m a -> m a+withContext = withCreated ImNodes.createContext ImNodes.destroyContext
+ src/DearImGui/Raw/ImNodes.hsc view
@@ -0,0 +1,634 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes+ ( MiniMapNodeHoveringCallback+ , MiniMapNodeHoveringCallbackUserData+ , beginInputAttribute+ , beginNode+ , beginNodeEditor+ , beginNodeTitleBar+ , beginOutputAttribute+ , beginStaticAttribute+ , c_editorContextGetPanning+ , c_editorContextResetPanning+ , c_getNodeDimensions+ , c_getNodeEditorSpacePos+ , c_getNodeGridSpacePos+ , c_getNodeScreenSpacePos+ , c_pushStyleVarImVec2+ , c_setNodeEditorSpacePos+ , c_setNodeGridSpacePos+ , c_setNodeScreenSpacePos+ , clearLinkSelection+ , clearLinkSelectionInt+ , clearNodeSelection+ , clearNodeSelectionInt+ , createContext+ , destroyContext+ , editorContextCreate+ , editorContextFree+ , editorContextGetPanning+ , editorContextMoveToNode+ , editorContextResetPanning+ , editorContextSet+ , endInputAttribute+ , endNode+ , endNodeEditor+ , endNodeTitleBar+ , endOutputAttribute+ , endStaticAttribute+ , getCurrentContext+ , getIO+ , getNodeDimensions+ , getNodeEditorSpacePos+ , getNodeGridSpacePos+ , getNodeScreenSpacePos+ , getSelectedLinks+ , getSelectedNodes+ , getStyle+ , getStyleColorName+ , isAnyAttributeActive+ , isAttributeActive+ , isEditorHovered+ , isLinkCreated+ , isLinkCreatedIntPtr+ , isLinkDestroyed+ , isLinkDropped+ , isLinkHovered+ , isLinkSelected+ , isLinkStarted+ , isNodeHovered+ , isNodeSelected+ , isPinHovered+ , link+ , loadCurrentEditorStateFromIniFile+ , loadCurrentEditorStateFromIniString+ , loadEditorStateFromIniFile+ , loadEditorStateFromIniString+ , miniMap+ , numSelectedLinks+ , numSelectedNodes+ , popAttributeFlag+ , popColorStyle+ , popStyleVar+ , pushAttributeFlag+ , pushColorStyle+ , pushStyleVar+ , pushStyleVarImVec2+ , saveCurrentEditorStateToIniFile+ , saveCurrentEditorStateToIniString+ , saveEditorStateToIniFile+ , saveEditorStateToIniString+ , selectLink+ , selectNode+ , setCurrentContext+ , setImGuiContext+ , setNodeDraggable+ , setNodeEditorSpacePos+ , setNodeGridSpacePos+ , setNodeScreenSpacePos+ , snapNodeToGrid+ , styleColorsClassic+ , styleColorsDark+ , styleColorsLight+ ) where++import DearImGui.Raw.ImGuiContext (ImGuiContext)+import DearImGui.Raw.ImNodes.Context (Context)+import DearImGui.Raw.ImNodes.EditorContext (EditorContext)+import DearImGui.Raw.ImNodes.Enums.AttributeFlags (AttributeFlags)+import DearImGui.Raw.ImNodes.Enums.Col (Col)+import DearImGui.Raw.ImNodes.Enums.MiniMapLocation (MiniMapLocation)+import DearImGui.Raw.ImNodes.Enums.PinShape (PinShape)+import DearImGui.Raw.ImNodes.Enums.StyleVar (StyleVar)+import DearImGui.Raw.ImNodes.ImNodesIO (ImNodesIO)+import DearImGui.Raw.ImNodes.Style (Style)+import DearImGui.Raw.ImVec2 (ImVec2)+import Foreign.C.String (CString)+import Foreign.C.Types+import Foreign.Marshal.Alloc (alloca)+import Foreign.Marshal.Utils (with)+import Foreign.Ptr (FunPtr, Ptr)+import Foreign.Storable (Storable (..))++#include "dcimnodes.h"++-- typedefs++type MiniMapNodeHoveringCallback = FunPtr (CInt -> (Ptr ()) -> IO ())++type MiniMapNodeHoveringCallbackUserData = Ptr ()++-- functions++-- C: void ImNodes::BeginInputAttribute(int id, ImNodesPinShape shape)+foreign import capi unsafe "dcimnodes.h ImNodesBeginInputAttribute"+ beginInputAttribute+ :: CInt -- ^ id+ -> PinShape -- ^ shape+ -> IO ()++-- C: void ImNodes::BeginNode(int id)+foreign import capi unsafe "dcimnodes.h ImNodesBeginNode"+ beginNode+ :: CInt -- ^ id+ -> IO ()++-- C: void ImNodes::BeginNodeEditor()+foreign import capi unsafe "dcimnodes.h ImNodesBeginNodeEditor"+ beginNodeEditor :: IO ()++-- C: void ImNodes::BeginNodeTitleBar()+foreign import capi unsafe "dcimnodes.h ImNodesBeginNodeTitleBar"+ beginNodeTitleBar :: IO ()++-- C: void ImNodes::BeginOutputAttribute(int id, ImNodesPinShape shape)+foreign import capi unsafe "dcimnodes.h ImNodesBeginOutputAttribute"+ beginOutputAttribute+ :: CInt -- ^ id+ -> PinShape -- ^ shape+ -> IO ()++-- C: void ImNodes::BeginStaticAttribute(int id)+foreign import capi unsafe "dcimnodes.h ImNodesBeginStaticAttribute"+ beginStaticAttribute+ :: CInt -- ^ id+ -> IO ()++-- C: void ImNodes::ClearLinkSelection()+foreign import capi unsafe "dcimnodes.h ImNodesClearLinkSelection"+ clearLinkSelection :: IO ()++-- C: void ImNodes::ClearLinkSelection(int link_id)+foreign import capi unsafe "dcimnodes.h ImNodesClearLinkSelectionInt"+ clearLinkSelectionInt+ :: CInt -- ^ link_id+ -> IO ()++-- C: void ImNodes::ClearNodeSelection()+foreign import capi unsafe "dcimnodes.h ImNodesClearNodeSelection"+ clearNodeSelection :: IO ()++-- C: void ImNodes::ClearNodeSelection(int node_id)+foreign import capi unsafe "dcimnodes.h ImNodesClearNodeSelectionInt"+ clearNodeSelectionInt+ :: CInt -- ^ node_id+ -> IO ()++-- C: ImNodesContext* ImNodes::CreateContext()+foreign import capi unsafe "dcimnodes.h ImNodesCreateContext"+ createContext :: IO (Ptr Context)++-- C: void ImNodes::DestroyContext(ImNodesContext* ctx)+foreign import capi unsafe "dcimnodes.h ImNodesDestroyContext"+ destroyContext+ :: (Ptr Context) -- ^ ctx+ -> IO ()++-- C: ImNodesEditorContext* ImNodes::EditorContextCreate()+foreign import capi unsafe "dcimnodes.h ImNodesEditorContextCreate"+ editorContextCreate :: IO (Ptr EditorContext)++-- C: void ImNodes::EditorContextFree(ImNodesEditorContext* __unnamed_arg0__)+foreign import capi unsafe "dcimnodes.h ImNodesEditorContextFree"+ editorContextFree+ :: (Ptr EditorContext) -- ^ __unnamed_arg0__+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesEditorContextGetPanning_wrap"+ c_editorContextGetPanning+ :: (Ptr ImVec2) -- ^ out+ -> IO ()++editorContextGetPanning :: IO ImVec2+editorContextGetPanning =+ alloca $ \outPtr -> c_editorContextGetPanning outPtr >> peek outPtr++-- C: void ImNodes::EditorContextMoveToNode(const int node_id)+foreign import capi unsafe "dcimnodes.h ImNodesEditorContextMoveToNode"+ editorContextMoveToNode+ :: CInt -- ^ node_id+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesEditorContextResetPanning_wrap"+ c_editorContextResetPanning+ :: (Ptr ImVec2) -- ^ pos+ -> IO ()++editorContextResetPanning+ :: ImVec2 -- ^ pos+ -> IO ()+editorContextResetPanning pos =+ with pos $ \posPtr -> c_editorContextResetPanning posPtr++-- C: void ImNodes::EditorContextSet(ImNodesEditorContext* __unnamed_arg0__)+foreign import capi unsafe "dcimnodes.h ImNodesEditorContextSet"+ editorContextSet+ :: (Ptr EditorContext) -- ^ __unnamed_arg0__+ -> IO ()++-- C: void ImNodes::EndInputAttribute()+foreign import capi unsafe "dcimnodes.h ImNodesEndInputAttribute"+ endInputAttribute :: IO ()++-- C: void ImNodes::EndNode()+foreign import capi unsafe "dcimnodes.h ImNodesEndNode"+ endNode :: IO ()++-- C: void ImNodes::EndNodeEditor()+foreign import capi unsafe "dcimnodes.h ImNodesEndNodeEditor"+ endNodeEditor :: IO ()++-- C: void ImNodes::EndNodeTitleBar()+foreign import capi unsafe "dcimnodes.h ImNodesEndNodeTitleBar"+ endNodeTitleBar :: IO ()++-- C: void ImNodes::EndOutputAttribute()+foreign import capi unsafe "dcimnodes.h ImNodesEndOutputAttribute"+ endOutputAttribute :: IO ()++-- C: void ImNodes::EndStaticAttribute()+foreign import capi unsafe "dcimnodes.h ImNodesEndStaticAttribute"+ endStaticAttribute :: IO ()++-- C: ImNodesContext* ImNodes::GetCurrentContext()+foreign import capi unsafe "dcimnodes.h ImNodesGetCurrentContext"+ getCurrentContext :: IO (Ptr Context)++-- C: ImNodesIO* ImNodes::GetIO()+foreign import capi unsafe "dcimnodes.h ImNodesGetIO"+ getIO :: IO (Ptr ImNodesIO)++foreign import capi unsafe "DearImGuiWrappers.h ImNodesGetNodeDimensions_wrap"+ c_getNodeDimensions+ :: CInt -- ^ id+ -> (Ptr ImVec2) -- ^ out+ -> IO ()++getNodeDimensions+ :: CInt -- ^ id+ -> IO ImVec2+getNodeDimensions id_ =+ alloca $ \outPtr -> c_getNodeDimensions id_ outPtr >> peek outPtr++foreign import capi unsafe "DearImGuiWrappers.h ImNodesGetNodeEditorSpacePos_wrap"+ c_getNodeEditorSpacePos+ :: CInt -- ^ node_id+ -> (Ptr ImVec2) -- ^ out+ -> IO ()++getNodeEditorSpacePos+ :: CInt -- ^ node_id+ -> IO ImVec2+getNodeEditorSpacePos node_id =+ alloca $ \outPtr -> c_getNodeEditorSpacePos node_id outPtr >> peek outPtr++foreign import capi unsafe "DearImGuiWrappers.h ImNodesGetNodeGridSpacePos_wrap"+ c_getNodeGridSpacePos+ :: CInt -- ^ node_id+ -> (Ptr ImVec2) -- ^ out+ -> IO ()++getNodeGridSpacePos+ :: CInt -- ^ node_id+ -> IO ImVec2+getNodeGridSpacePos node_id =+ alloca $ \outPtr -> c_getNodeGridSpacePos node_id outPtr >> peek outPtr++foreign import capi unsafe "DearImGuiWrappers.h ImNodesGetNodeScreenSpacePos_wrap"+ c_getNodeScreenSpacePos+ :: CInt -- ^ node_id+ -> (Ptr ImVec2) -- ^ out+ -> IO ()++getNodeScreenSpacePos+ :: CInt -- ^ node_id+ -> IO ImVec2+getNodeScreenSpacePos node_id =+ alloca $ \outPtr -> c_getNodeScreenSpacePos node_id outPtr >> peek outPtr++-- C: void ImNodes::GetSelectedLinks(int* link_ids)+foreign import capi unsafe "dcimnodes.h ImNodesGetSelectedLinks"+ getSelectedLinks+ :: (Ptr CInt) -- ^ link_ids+ -> IO ()++-- C: void ImNodes::GetSelectedNodes(int* node_ids)+foreign import capi unsafe "dcimnodes.h ImNodesGetSelectedNodes"+ getSelectedNodes+ :: (Ptr CInt) -- ^ node_ids+ -> IO ()++-- C: ImNodesStyle* ImNodes::GetStyle()+foreign import capi unsafe "dcimnodes.h ImNodesGetStyle"+ getStyle :: IO (Ptr Style)++-- C: const char* ImNodes::GetStyleColorName(ImNodesCol idx)+foreign import capi unsafe "dcimnodes.h ImNodesGetStyleColorName"+ getStyleColorName+ :: Col -- ^ idx+ -> IO CString++-- C: bool ImNodes::IsAnyAttributeActive(int* attribute_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsAnyAttributeActive"+ isAnyAttributeActive+ :: (Ptr CInt) -- ^ attribute_id+ -> IO CBool++-- C: bool ImNodes::IsAttributeActive()+foreign import capi unsafe "dcimnodes.h ImNodesIsAttributeActive"+ isAttributeActive :: IO CBool++-- C: bool ImNodes::IsEditorHovered()+foreign import capi unsafe "dcimnodes.h ImNodesIsEditorHovered"+ isEditorHovered :: IO CBool++-- C: bool ImNodes::IsLinkCreated(int* started_at_attribute_id, int* ended_at_attribute_id, bool* created_from_snap)+foreign import capi unsafe "dcimnodes.h ImNodesIsLinkCreated"+ isLinkCreated+ :: (Ptr CInt) -- ^ started_at_attribute_id+ -> (Ptr CInt) -- ^ ended_at_attribute_id+ -> (Ptr CBool) -- ^ created_from_snap+ -> IO CBool++-- C: bool ImNodes::IsLinkCreated(int* started_at_node_id, int* started_at_attribute_id, int* ended_at_node_id, int* ended_at_attribute_id, bool* created_from_snap)+foreign import capi unsafe "dcimnodes.h ImNodesIsLinkCreatedIntPtr"+ isLinkCreatedIntPtr+ :: (Ptr CInt) -- ^ started_at_node_id+ -> (Ptr CInt) -- ^ started_at_attribute_id+ -> (Ptr CInt) -- ^ ended_at_node_id+ -> (Ptr CInt) -- ^ ended_at_attribute_id+ -> (Ptr CBool) -- ^ created_from_snap+ -> IO CBool++-- C: bool ImNodes::IsLinkDestroyed(int* link_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsLinkDestroyed"+ isLinkDestroyed+ :: (Ptr CInt) -- ^ link_id+ -> IO CBool++-- C: bool ImNodes::IsLinkDropped(int* started_at_attribute_id, bool including_detached_links)+foreign import capi unsafe "dcimnodes.h ImNodesIsLinkDropped"+ isLinkDropped+ :: (Ptr CInt) -- ^ started_at_attribute_id+ -> CBool -- ^ including_detached_links+ -> IO CBool++-- C: bool ImNodes::IsLinkHovered(int* link_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsLinkHovered"+ isLinkHovered+ :: (Ptr CInt) -- ^ link_id+ -> IO CBool++-- C: bool ImNodes::IsLinkSelected(int link_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsLinkSelected"+ isLinkSelected+ :: CInt -- ^ link_id+ -> IO CBool++-- C: bool ImNodes::IsLinkStarted(int* started_at_attribute_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsLinkStarted"+ isLinkStarted+ :: (Ptr CInt) -- ^ started_at_attribute_id+ -> IO CBool++-- C: bool ImNodes::IsNodeHovered(int* node_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsNodeHovered"+ isNodeHovered+ :: (Ptr CInt) -- ^ node_id+ -> IO CBool++-- C: bool ImNodes::IsNodeSelected(int node_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsNodeSelected"+ isNodeSelected+ :: CInt -- ^ node_id+ -> IO CBool++-- C: bool ImNodes::IsPinHovered(int* attribute_id)+foreign import capi unsafe "dcimnodes.h ImNodesIsPinHovered"+ isPinHovered+ :: (Ptr CInt) -- ^ attribute_id+ -> IO CBool++-- C: void ImNodes::Link(int id, int start_attribute_id, int end_attribute_id)+foreign import capi unsafe "dcimnodes.h ImNodesLink"+ link+ :: CInt -- ^ id+ -> CInt -- ^ start_attribute_id+ -> CInt -- ^ end_attribute_id+ -> IO ()++-- C: void ImNodes::LoadCurrentEditorStateFromIniFile(const char* file_name)+foreign import capi unsafe "dcimnodes.h ImNodesLoadCurrentEditorStateFromIniFile"+ loadCurrentEditorStateFromIniFile+ :: CString -- ^ file_name+ -> IO ()++-- C: void ImNodes::LoadCurrentEditorStateFromIniString(const char* data, size_t data_size)+foreign import capi unsafe "dcimnodes.h ImNodesLoadCurrentEditorStateFromIniString"+ loadCurrentEditorStateFromIniString+ :: CString -- ^ data+ -> CSize -- ^ data_size+ -> IO ()++-- C: void ImNodes::LoadEditorStateFromIniFile(ImNodesEditorContext* editor, const char* file_name)+foreign import capi unsafe "dcimnodes.h ImNodesLoadEditorStateFromIniFile"+ loadEditorStateFromIniFile+ :: (Ptr EditorContext) -- ^ editor+ -> CString -- ^ file_name+ -> IO ()++-- C: void ImNodes::LoadEditorStateFromIniString(ImNodesEditorContext* editor, const char* data, size_t data_size)+foreign import capi unsafe "dcimnodes.h ImNodesLoadEditorStateFromIniString"+ loadEditorStateFromIniString+ :: (Ptr EditorContext) -- ^ editor+ -> CString -- ^ data+ -> CSize -- ^ data_size+ -> IO ()++-- C: void ImNodes::MiniMap(const float minimap_size_fraction, const ImNodesMiniMapLocation location, const ImNodesMiniMapNodeHoveringCallback node_hovering_callback, const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data)+foreign import capi safe "dcimnodes.h ImNodesMiniMap"+ miniMap+ :: Float -- ^ minimap_size_fraction+ -> MiniMapLocation -- ^ location+ -> MiniMapNodeHoveringCallback -- ^ node_hovering_callback+ -> MiniMapNodeHoveringCallbackUserData -- ^ node_hovering_callback_data+ -> IO ()++-- C: int ImNodes::NumSelectedLinks()+foreign import capi unsafe "dcimnodes.h ImNodesNumSelectedLinks"+ numSelectedLinks :: IO CInt++-- C: int ImNodes::NumSelectedNodes()+foreign import capi unsafe "dcimnodes.h ImNodesNumSelectedNodes"+ numSelectedNodes :: IO CInt++-- C: void ImNodes::PopAttributeFlag()+foreign import capi unsafe "dcimnodes.h ImNodesPopAttributeFlag"+ popAttributeFlag :: IO ()++-- C: void ImNodes::PopColorStyle()+foreign import capi unsafe "dcimnodes.h ImNodesPopColorStyle"+ popColorStyle :: IO ()++-- C: void ImNodes::PopStyleVar(int count)+foreign import capi unsafe "dcimnodes.h ImNodesPopStyleVar"+ popStyleVar+ :: CInt -- ^ count+ -> IO ()++-- C: void ImNodes::PushAttributeFlag(ImNodesAttributeFlags flag)+foreign import capi unsafe "dcimnodes.h ImNodesPushAttributeFlag"+ pushAttributeFlag+ :: AttributeFlags -- ^ flag+ -> IO ()++-- C: void ImNodes::PushColorStyle(ImNodesCol item, unsigned int color)+foreign import capi unsafe "dcimnodes.h ImNodesPushColorStyle"+ pushColorStyle+ :: Col -- ^ item+ -> CUInt -- ^ color+ -> IO ()++-- C: void ImNodes::PushStyleVar(ImNodesStyleVar style_item, float value)+foreign import capi unsafe "dcimnodes.h ImNodesPushStyleVar"+ pushStyleVar+ :: StyleVar -- ^ style_item+ -> Float -- ^ value+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesPushStyleVarImVec2_wrap"+ c_pushStyleVarImVec2+ :: StyleVar -- ^ style_item+ -> (Ptr ImVec2) -- ^ value+ -> IO ()++pushStyleVarImVec2+ :: StyleVar -- ^ style_item+ -> ImVec2 -- ^ value+ -> IO ()+pushStyleVarImVec2 style_item value =+ with value $ \valuePtr -> c_pushStyleVarImVec2 style_item valuePtr++-- C: void ImNodes::SaveCurrentEditorStateToIniFile(const char* file_name)+foreign import capi unsafe "dcimnodes.h ImNodesSaveCurrentEditorStateToIniFile"+ saveCurrentEditorStateToIniFile+ :: CString -- ^ file_name+ -> IO ()++-- C: const char* ImNodes::SaveCurrentEditorStateToIniString(size_t* data_size)+foreign import capi unsafe "dcimnodes.h ImNodesSaveCurrentEditorStateToIniString"+ saveCurrentEditorStateToIniString+ :: (Ptr CSize) -- ^ data_size+ -> IO CString++-- C: void ImNodes::SaveEditorStateToIniFile(const ImNodesEditorContext* editor, const char* file_name)+foreign import capi unsafe "dcimnodes.h ImNodesSaveEditorStateToIniFile"+ saveEditorStateToIniFile+ :: (Ptr EditorContext) -- ^ editor+ -> CString -- ^ file_name+ -> IO ()++-- C: const char* ImNodes::SaveEditorStateToIniString(const ImNodesEditorContext* editor, size_t* data_size)+foreign import capi unsafe "dcimnodes.h ImNodesSaveEditorStateToIniString"+ saveEditorStateToIniString+ :: (Ptr EditorContext) -- ^ editor+ -> (Ptr CSize) -- ^ data_size+ -> IO CString++-- C: void ImNodes::SelectLink(int link_id)+foreign import capi unsafe "dcimnodes.h ImNodesSelectLink"+ selectLink+ :: CInt -- ^ link_id+ -> IO ()++-- C: void ImNodes::SelectNode(int node_id)+foreign import capi unsafe "dcimnodes.h ImNodesSelectNode"+ selectNode+ :: CInt -- ^ node_id+ -> IO ()++-- C: void ImNodes::SetCurrentContext(ImNodesContext* ctx)+foreign import capi unsafe "dcimnodes.h ImNodesSetCurrentContext"+ setCurrentContext+ :: (Ptr Context) -- ^ ctx+ -> IO ()++-- C: void ImNodes::SetImGuiContext(ImGuiContext* ctx)+foreign import capi unsafe "dcimnodes.h ImNodesSetImGuiContext"+ setImGuiContext+ :: (Ptr ImGuiContext) -- ^ ctx+ -> IO ()++-- C: void ImNodes::SetNodeDraggable(int node_id, const bool draggable)+foreign import capi unsafe "dcimnodes.h ImNodesSetNodeDraggable"+ setNodeDraggable+ :: CInt -- ^ node_id+ -> CBool -- ^ draggable+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesSetNodeEditorSpacePos_wrap"+ c_setNodeEditorSpacePos+ :: CInt -- ^ node_id+ -> (Ptr ImVec2) -- ^ editor_space_pos+ -> IO ()++setNodeEditorSpacePos+ :: CInt -- ^ node_id+ -> ImVec2 -- ^ editor_space_pos+ -> IO ()+setNodeEditorSpacePos node_id editor_space_pos =+ with editor_space_pos $ \editor_space_posPtr -> c_setNodeEditorSpacePos node_id editor_space_posPtr++foreign import capi unsafe "DearImGuiWrappers.h ImNodesSetNodeGridSpacePos_wrap"+ c_setNodeGridSpacePos+ :: CInt -- ^ node_id+ -> (Ptr ImVec2) -- ^ grid_pos+ -> IO ()++setNodeGridSpacePos+ :: CInt -- ^ node_id+ -> ImVec2 -- ^ grid_pos+ -> IO ()+setNodeGridSpacePos node_id grid_pos =+ with grid_pos $ \grid_posPtr -> c_setNodeGridSpacePos node_id grid_posPtr++foreign import capi unsafe "DearImGuiWrappers.h ImNodesSetNodeScreenSpacePos_wrap"+ c_setNodeScreenSpacePos+ :: CInt -- ^ node_id+ -> (Ptr ImVec2) -- ^ screen_space_pos+ -> IO ()++setNodeScreenSpacePos+ :: CInt -- ^ node_id+ -> ImVec2 -- ^ screen_space_pos+ -> IO ()+setNodeScreenSpacePos node_id screen_space_pos =+ with screen_space_pos $ \screen_space_posPtr -> c_setNodeScreenSpacePos node_id screen_space_posPtr++-- C: void ImNodes::SnapNodeToGrid(int node_id)+foreign import capi unsafe "dcimnodes.h ImNodesSnapNodeToGrid"+ snapNodeToGrid+ :: CInt -- ^ node_id+ -> IO ()++-- C: void ImNodes::StyleColorsClassic(ImNodesStyle* dest)+foreign import capi unsafe "dcimnodes.h ImNodesStyleColorsClassic"+ styleColorsClassic+ :: (Ptr Style) -- ^ dest+ -> IO ()++-- C: void ImNodes::StyleColorsDark(ImNodesStyle* dest)+foreign import capi unsafe "dcimnodes.h ImNodesStyleColorsDark"+ styleColorsDark+ :: (Ptr Style) -- ^ dest+ -> IO ()++-- C: void ImNodes::StyleColorsLight(ImNodesStyle* dest)+foreign import capi unsafe "dcimnodes.h ImNodesStyleColorsLight"+ styleColorsLight+ :: (Ptr Style) -- ^ dest+ -> IO ()
+ src/DearImGui/Raw/ImNodes/Context.hsc view
@@ -0,0 +1,14 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Context+ ( Context+ ) where++#include "dcimnodes.h"++-- structs (opaque)++data Context
+ src/DearImGui/Raw/ImNodes/EditorContext.hsc view
@@ -0,0 +1,14 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.EditorContext+ ( EditorContext+ ) where++#include "dcimnodes.h"++-- structs (opaque)++data EditorContext
+ src/DearImGui/Raw/ImNodes/Enums/AttributeFlags.hsc view
@@ -0,0 +1,39 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Enums.AttributeFlags+ ( AttributeFlags+ , pattern EnableLinkCreationOnSnap+ , pattern EnableLinkDetachWithDragClick+ , pattern None+ ) where++import Foreign.C.Types++#include "dcimnodes.h"++-- typedefs++-- | This enum controls the way the attribute pins behave.+type AttributeFlags = CInt++-- enums++pattern None :: AttributeFlags+pattern None = #{const ImNodesAttributeFlags_None}++-- | Allow detaching a link by left-clicking and dragging the link at a pin it is connected to.+-- NOTE: the user has to actually delete the link for this to work. A deleted link can be+-- detected by calling IsLinkDestroyed() after EndNodeEditor().+pattern EnableLinkDetachWithDragClick :: AttributeFlags+pattern EnableLinkDetachWithDragClick = #{const ImNodesAttributeFlags_EnableLinkDetachWithDragClick}++-- | Visual snapping of an in progress link will trigger IsLink Created/Destroyed events. Allows+-- for previewing the creation of a link while dragging it across attributes. See here for demo:+-- https://github.com/Nelarius/imnodes/issues/41#issuecomment-647132113 NOTE: the user has to+-- actually delete the link for this to work. A deleted link can be detected by calling+-- IsLinkDestroyed() after EndNodeEditor().+pattern EnableLinkCreationOnSnap :: AttributeFlags+pattern EnableLinkCreationOnSnap = #{const ImNodesAttributeFlags_EnableLinkCreationOnSnap}
+ src/DearImGui/Raw/ImNodes/Enums/Col.hsc view
@@ -0,0 +1,139 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Enums.Col+ ( Col+ , pattern BoxSelector+ , pattern BoxSelectorOutline+ , pattern COUNT+ , pattern GridBackground+ , pattern GridLine+ , pattern GridLinePrimary+ , pattern Link+ , pattern LinkHovered+ , pattern LinkSelected+ , pattern MiniMapBackground+ , pattern MiniMapBackgroundHovered+ , pattern MiniMapCanvas+ , pattern MiniMapCanvasOutline+ , pattern MiniMapLink+ , pattern MiniMapLinkSelected+ , pattern MiniMapNodeBackground+ , pattern MiniMapNodeBackgroundHovered+ , pattern MiniMapNodeBackgroundSelected+ , pattern MiniMapNodeOutline+ , pattern MiniMapOutline+ , pattern MiniMapOutlineHovered+ , pattern NodeBackground+ , pattern NodeBackgroundHovered+ , pattern NodeBackgroundSelected+ , pattern NodeOutline+ , pattern Pin+ , pattern PinHovered+ , pattern TitleBar+ , pattern TitleBarHovered+ , pattern TitleBarSelected+ ) where++import Foreign.C.Types++#include "dcimnodes.h"++-- typedefs++-- | -> enum ImNodesCol_+type Col = CInt++-- enums++pattern NodeBackground :: Col+pattern NodeBackground = #{const ImNodesCol_NodeBackground}++pattern NodeBackgroundHovered :: Col+pattern NodeBackgroundHovered = #{const ImNodesCol_NodeBackgroundHovered}++pattern NodeBackgroundSelected :: Col+pattern NodeBackgroundSelected = #{const ImNodesCol_NodeBackgroundSelected}++pattern NodeOutline :: Col+pattern NodeOutline = #{const ImNodesCol_NodeOutline}++pattern TitleBar :: Col+pattern TitleBar = #{const ImNodesCol_TitleBar}++pattern TitleBarHovered :: Col+pattern TitleBarHovered = #{const ImNodesCol_TitleBarHovered}++pattern TitleBarSelected :: Col+pattern TitleBarSelected = #{const ImNodesCol_TitleBarSelected}++pattern Link :: Col+pattern Link = #{const ImNodesCol_Link}++pattern LinkHovered :: Col+pattern LinkHovered = #{const ImNodesCol_LinkHovered}++pattern LinkSelected :: Col+pattern LinkSelected = #{const ImNodesCol_LinkSelected}++pattern Pin :: Col+pattern Pin = #{const ImNodesCol_Pin}++pattern PinHovered :: Col+pattern PinHovered = #{const ImNodesCol_PinHovered}++pattern BoxSelector :: Col+pattern BoxSelector = #{const ImNodesCol_BoxSelector}++pattern BoxSelectorOutline :: Col+pattern BoxSelectorOutline = #{const ImNodesCol_BoxSelectorOutline}++pattern GridBackground :: Col+pattern GridBackground = #{const ImNodesCol_GridBackground}++pattern GridLine :: Col+pattern GridLine = #{const ImNodesCol_GridLine}++pattern GridLinePrimary :: Col+pattern GridLinePrimary = #{const ImNodesCol_GridLinePrimary}++pattern MiniMapBackground :: Col+pattern MiniMapBackground = #{const ImNodesCol_MiniMapBackground}++pattern MiniMapBackgroundHovered :: Col+pattern MiniMapBackgroundHovered = #{const ImNodesCol_MiniMapBackgroundHovered}++pattern MiniMapOutline :: Col+pattern MiniMapOutline = #{const ImNodesCol_MiniMapOutline}++pattern MiniMapOutlineHovered :: Col+pattern MiniMapOutlineHovered = #{const ImNodesCol_MiniMapOutlineHovered}++pattern MiniMapNodeBackground :: Col+pattern MiniMapNodeBackground = #{const ImNodesCol_MiniMapNodeBackground}++pattern MiniMapNodeBackgroundHovered :: Col+pattern MiniMapNodeBackgroundHovered = #{const ImNodesCol_MiniMapNodeBackgroundHovered}++pattern MiniMapNodeBackgroundSelected :: Col+pattern MiniMapNodeBackgroundSelected = #{const ImNodesCol_MiniMapNodeBackgroundSelected}++pattern MiniMapNodeOutline :: Col+pattern MiniMapNodeOutline = #{const ImNodesCol_MiniMapNodeOutline}++pattern MiniMapLink :: Col+pattern MiniMapLink = #{const ImNodesCol_MiniMapLink}++pattern MiniMapLinkSelected :: Col+pattern MiniMapLinkSelected = #{const ImNodesCol_MiniMapLinkSelected}++pattern MiniMapCanvas :: Col+pattern MiniMapCanvas = #{const ImNodesCol_MiniMapCanvas}++pattern MiniMapCanvasOutline :: Col+pattern MiniMapCanvasOutline = #{const ImNodesCol_MiniMapCanvasOutline}++pattern COUNT :: Col+pattern COUNT = #{const ImNodesCol_COUNT}
+ src/DearImGui/Raw/ImNodes/Enums/MiniMapLocation.hsc view
@@ -0,0 +1,35 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Enums.MiniMapLocation+ ( MiniMapLocation+ , pattern BottomLeft+ , pattern BottomRight+ , pattern TopLeft+ , pattern TopRight+ ) where++import Foreign.C.Types++#include "dcimnodes.h"++-- typedefs++-- | -> enum ImNodesMiniMapLocation_+type MiniMapLocation = CInt++-- enums++pattern BottomLeft :: MiniMapLocation+pattern BottomLeft = #{const ImNodesMiniMapLocation_BottomLeft}++pattern BottomRight :: MiniMapLocation+pattern BottomRight = #{const ImNodesMiniMapLocation_BottomRight}++pattern TopLeft :: MiniMapLocation+pattern TopLeft = #{const ImNodesMiniMapLocation_TopLeft}++pattern TopRight :: MiniMapLocation+pattern TopRight = #{const ImNodesMiniMapLocation_TopRight}
+ src/DearImGui/Raw/ImNodes/Enums/PinShape.hsc view
@@ -0,0 +1,43 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Enums.PinShape+ ( PinShape+ , pattern Circle+ , pattern CircleFilled+ , pattern Quad+ , pattern QuadFilled+ , pattern Triangle+ , pattern TriangleFilled+ ) where++import Foreign.C.Types++#include "dcimnodes.h"++-- typedefs++-- | -> enum ImNodesPinShape_+type PinShape = CInt++-- enums++pattern Circle :: PinShape+pattern Circle = #{const ImNodesPinShape_Circle}++pattern CircleFilled :: PinShape+pattern CircleFilled = #{const ImNodesPinShape_CircleFilled}++pattern Triangle :: PinShape+pattern Triangle = #{const ImNodesPinShape_Triangle}++pattern TriangleFilled :: PinShape+pattern TriangleFilled = #{const ImNodesPinShape_TriangleFilled}++pattern Quad :: PinShape+pattern Quad = #{const ImNodesPinShape_Quad}++pattern QuadFilled :: PinShape+pattern QuadFilled = #{const ImNodesPinShape_QuadFilled}
+ src/DearImGui/Raw/ImNodes/Enums/StyleFlags.hsc view
@@ -0,0 +1,39 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Enums.StyleFlags+ ( StyleFlags+ , pattern GridLines+ , pattern GridLinesPrimary+ , pattern GridSnapping+ , pattern NodeOutline+ , pattern None+ ) where++import Foreign.C.Types++#include "dcimnodes.h"++-- typedefs++-- | -> enum ImNodesStyleFlags_+type StyleFlags = CInt++-- enums++pattern None :: StyleFlags+pattern None = #{const ImNodesStyleFlags_None}++pattern NodeOutline :: StyleFlags+pattern NodeOutline = #{const ImNodesStyleFlags_NodeOutline}++pattern GridLines :: StyleFlags+pattern GridLines = #{const ImNodesStyleFlags_GridLines}++pattern GridLinesPrimary :: StyleFlags+pattern GridLinesPrimary = #{const ImNodesStyleFlags_GridLinesPrimary}++pattern GridSnapping :: StyleFlags+pattern GridSnapping = #{const ImNodesStyleFlags_GridSnapping}
+ src/DearImGui/Raw/ImNodes/Enums/StyleVar.hsc view
@@ -0,0 +1,83 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Enums.StyleVar+ ( StyleVar+ , pattern COUNT+ , pattern GridSpacing+ , pattern LinkHoverDistance+ , pattern LinkLineSegmentsPerLength+ , pattern LinkThickness+ , pattern MiniMapOffset+ , pattern MiniMapPadding+ , pattern NodeBorderThickness+ , pattern NodeCornerRounding+ , pattern NodePadding+ , pattern PinCircleRadius+ , pattern PinHoverRadius+ , pattern PinLineThickness+ , pattern PinOffset+ , pattern PinQuadSideLength+ , pattern PinTriangleSideLength+ ) where++import Foreign.C.Types++#include "dcimnodes.h"++-- typedefs++-- | -> enum ImNodesStyleVar_+type StyleVar = CInt++-- enums++pattern GridSpacing :: StyleVar+pattern GridSpacing = #{const ImNodesStyleVar_GridSpacing}++pattern NodeCornerRounding :: StyleVar+pattern NodeCornerRounding = #{const ImNodesStyleVar_NodeCornerRounding}++pattern NodePadding :: StyleVar+pattern NodePadding = #{const ImNodesStyleVar_NodePadding}++pattern NodeBorderThickness :: StyleVar+pattern NodeBorderThickness = #{const ImNodesStyleVar_NodeBorderThickness}++pattern LinkThickness :: StyleVar+pattern LinkThickness = #{const ImNodesStyleVar_LinkThickness}++pattern LinkLineSegmentsPerLength :: StyleVar+pattern LinkLineSegmentsPerLength = #{const ImNodesStyleVar_LinkLineSegmentsPerLength}++pattern LinkHoverDistance :: StyleVar+pattern LinkHoverDistance = #{const ImNodesStyleVar_LinkHoverDistance}++pattern PinCircleRadius :: StyleVar+pattern PinCircleRadius = #{const ImNodesStyleVar_PinCircleRadius}++pattern PinQuadSideLength :: StyleVar+pattern PinQuadSideLength = #{const ImNodesStyleVar_PinQuadSideLength}++pattern PinTriangleSideLength :: StyleVar+pattern PinTriangleSideLength = #{const ImNodesStyleVar_PinTriangleSideLength}++pattern PinLineThickness :: StyleVar+pattern PinLineThickness = #{const ImNodesStyleVar_PinLineThickness}++pattern PinHoverRadius :: StyleVar+pattern PinHoverRadius = #{const ImNodesStyleVar_PinHoverRadius}++pattern PinOffset :: StyleVar+pattern PinOffset = #{const ImNodesStyleVar_PinOffset}++pattern MiniMapPadding :: StyleVar+pattern MiniMapPadding = #{const ImNodesStyleVar_MiniMapPadding}++pattern MiniMapOffset :: StyleVar+pattern MiniMapOffset = #{const ImNodesStyleVar_MiniMapOffset}++pattern COUNT :: StyleVar+pattern COUNT = #{const ImNodesStyleVar_COUNT}
+ src/DearImGui/Raw/ImNodes/ImNodesIO.hsc view
@@ -0,0 +1,163 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.ImNodesIO+ ( EmulateThreeButtonMouse (..)+ , ImNodesIO (..)+ , LinkDetachWithModifierClick (..)+ , MultipleSelectModifier (..)+ , destroy+ , destroyEmulateThreeButtonMouse+ , destroyLinkDetachWithModifierClick+ , destroyMultipleSelectModifier+ , init+ , initEmulateThreeButtonMouse+ , initLinkDetachWithModifierClick+ , initMultipleSelectModifier+ , withDefault+ , withDefaultEmulateThreeButtonMouse+ , withDefaultLinkDetachWithModifierClick+ , withDefaultMultipleSelectModifier+ ) where++import Control.Exception (bracket_)+import Foreign.C.Types+import Foreign.Marshal.Alloc (alloca)+import Foreign.Ptr (Ptr, plusPtr)+import Foreign.Storable (Storable (..))+import GHC.Records (HasField (..))+import Prelude hiding (init)++#include "dcimnodes.h"++-- structs (opaque)++data {-# CTYPE "dcimnodes.h" "ImNodesIO" #-} ImNodesIO = ImNodesIO+ { emulateThreeButtonMouse :: EmulateThreeButtonMouse+ , linkDetachWithModifierClick :: LinkDetachWithModifierClick+ , multipleSelectModifier :: MultipleSelectModifier+ , altMouseButton :: CInt+ , autoPanningSpeed :: Float+ }+ deriving (Eq, Show)+instance Storable ImNodesIO where+ sizeOf _ = #{size ImNodesIO}+ alignment _ = #{alignment ImNodesIO}+ peek p = ImNodesIO <$> #{peek ImNodesIO, EmulateThreeButtonMouse} p <*> #{peek ImNodesIO, LinkDetachWithModifierClick} p <*> #{peek ImNodesIO, MultipleSelectModifier} p <*> #{peek ImNodesIO, AltMouseButton} p <*> #{peek ImNodesIO, AutoPanningSpeed} p+ poke p v = do+ #{poke ImNodesIO, EmulateThreeButtonMouse} p v.emulateThreeButtonMouse+ #{poke ImNodesIO, LinkDetachWithModifierClick} p v.linkDetachWithModifierClick+ #{poke ImNodesIO, MultipleSelectModifier} p v.multipleSelectModifier+ #{poke ImNodesIO, AltMouseButton} p v.altMouseButton+ #{poke ImNodesIO, AutoPanningSpeed} p v.autoPanningSpeed++instance HasField "emulateThreeButtonMouse" (Ptr ImNodesIO) (Ptr EmulateThreeButtonMouse) where+ getField = #{ptr ImNodesIO, EmulateThreeButtonMouse}++instance HasField "linkDetachWithModifierClick" (Ptr ImNodesIO) (Ptr LinkDetachWithModifierClick) where+ getField = #{ptr ImNodesIO, LinkDetachWithModifierClick}++instance HasField "multipleSelectModifier" (Ptr ImNodesIO) (Ptr MultipleSelectModifier) where+ getField = #{ptr ImNodesIO, MultipleSelectModifier}++instance HasField "altMouseButton" (Ptr ImNodesIO) (Ptr CInt) where+ getField = #{ptr ImNodesIO, AltMouseButton}++instance HasField "autoPanningSpeed" (Ptr ImNodesIO) (Ptr Float) where+ getField = #{ptr ImNodesIO, AutoPanningSpeed}++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_Init_wrap"+ init+ :: Ptr ImNodesIO+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_Destroy_wrap"+ destroy+ :: Ptr ImNodesIO+ -> IO ()++withDefault :: (Ptr ImNodesIO -> IO a) -> IO a+withDefault k = alloca $ \p -> bracket_ (init p) (destroy p) (k p)++newtype {-# CTYPE "dcimnodes.h" "ImNodesIO_EmulateThreeButtonMouse" #-} EmulateThreeButtonMouse = EmulateThreeButtonMouse+ { modifier :: Ptr CBool+ }+ deriving (Eq, Show)+instance Storable EmulateThreeButtonMouse where+ sizeOf _ = #{size ImNodesIO_EmulateThreeButtonMouse}+ alignment _ = #{alignment ImNodesIO_EmulateThreeButtonMouse}+ peek p = EmulateThreeButtonMouse <$> #{peek ImNodesIO_EmulateThreeButtonMouse, Modifier} p+ poke p v = do+ #{poke ImNodesIO_EmulateThreeButtonMouse, Modifier} p v.modifier++instance HasField "modifier" (Ptr EmulateThreeButtonMouse) (Ptr (Ptr CBool)) where+ getField = #{ptr ImNodesIO_EmulateThreeButtonMouse, Modifier}++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_EmulateThreeButtonMouse_Init_wrap"+ initEmulateThreeButtonMouse+ :: Ptr EmulateThreeButtonMouse+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_EmulateThreeButtonMouse_Destroy_wrap"+ destroyEmulateThreeButtonMouse+ :: Ptr EmulateThreeButtonMouse+ -> IO ()++withDefaultEmulateThreeButtonMouse :: (Ptr EmulateThreeButtonMouse -> IO a) -> IO a+withDefaultEmulateThreeButtonMouse k = alloca $ \p -> bracket_ (initEmulateThreeButtonMouse p) (destroyEmulateThreeButtonMouse p) (k p)++newtype {-# CTYPE "dcimnodes.h" "ImNodesIO_LinkDetachWithModifierClick" #-} LinkDetachWithModifierClick = LinkDetachWithModifierClick+ { modifier :: Ptr CBool+ }+ deriving (Eq, Show)+instance Storable LinkDetachWithModifierClick where+ sizeOf _ = #{size ImNodesIO_LinkDetachWithModifierClick}+ alignment _ = #{alignment ImNodesIO_LinkDetachWithModifierClick}+ peek p = LinkDetachWithModifierClick <$> #{peek ImNodesIO_LinkDetachWithModifierClick, Modifier} p+ poke p v = do+ #{poke ImNodesIO_LinkDetachWithModifierClick, Modifier} p v.modifier++instance HasField "modifier" (Ptr LinkDetachWithModifierClick) (Ptr (Ptr CBool)) where+ getField = #{ptr ImNodesIO_LinkDetachWithModifierClick, Modifier}++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_LinkDetachWithModifierClick_Init_wrap"+ initLinkDetachWithModifierClick+ :: Ptr LinkDetachWithModifierClick+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_LinkDetachWithModifierClick_Destroy_wrap"+ destroyLinkDetachWithModifierClick+ :: Ptr LinkDetachWithModifierClick+ -> IO ()++withDefaultLinkDetachWithModifierClick :: (Ptr LinkDetachWithModifierClick -> IO a) -> IO a+withDefaultLinkDetachWithModifierClick k = alloca $ \p -> bracket_ (initLinkDetachWithModifierClick p) (destroyLinkDetachWithModifierClick p) (k p)++newtype {-# CTYPE "dcimnodes.h" "ImNodesIO_MultipleSelectModifier" #-} MultipleSelectModifier = MultipleSelectModifier+ { modifier :: Ptr CBool+ }+ deriving (Eq, Show)+instance Storable MultipleSelectModifier where+ sizeOf _ = #{size ImNodesIO_MultipleSelectModifier}+ alignment _ = #{alignment ImNodesIO_MultipleSelectModifier}+ peek p = MultipleSelectModifier <$> #{peek ImNodesIO_MultipleSelectModifier, Modifier} p+ poke p v = do+ #{poke ImNodesIO_MultipleSelectModifier, Modifier} p v.modifier++instance HasField "modifier" (Ptr MultipleSelectModifier) (Ptr (Ptr CBool)) where+ getField = #{ptr ImNodesIO_MultipleSelectModifier, Modifier}++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_MultipleSelectModifier_Init_wrap"+ initMultipleSelectModifier+ :: Ptr MultipleSelectModifier+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesIO_MultipleSelectModifier_Destroy_wrap"+ destroyMultipleSelectModifier+ :: Ptr MultipleSelectModifier+ -> IO ()++withDefaultMultipleSelectModifier :: (Ptr MultipleSelectModifier -> IO a) -> IO a+withDefaultMultipleSelectModifier k = alloca $ \p -> bracket_ (initMultipleSelectModifier p) (destroyMultipleSelectModifier p) (k p)
+ src/DearImGui/Raw/ImNodes/Style.hsc view
@@ -0,0 +1,100 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE PatternSynonyms #-}++-- This file was generated by dear-bindings-ffi. Do not edit by hand.++module DearImGui.Raw.ImNodes.Style+ ( Style+ , colorsLength+ , destroy+ , init+ , withDefault+ ) where++import Control.Exception (bracket_)+import DearImGui.Raw.ImNodes.Enums.StyleFlags (StyleFlags)+import DearImGui.Raw.ImVec2 (ImVec2)+import Foreign.C.Types+import Foreign.Marshal.Alloc (alloca)+import Foreign.Ptr (Ptr, plusPtr)+import Foreign.Storable (Storable (..))+import GHC.Records (HasField (..))+import Prelude hiding (init)++#include "dcimnodes.h"++-- structs (opaque)++data Style+instance Storable Style where+ sizeOf _ = #{size ImNodesStyle}+ alignment _ = #{alignment ImNodesStyle}+ peek _ = error "Style: opaque struct, peek not supported in v0"+ poke _ _ = error "Style: opaque struct, poke not supported in v0"++instance HasField "gridSpacing" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, GridSpacing}++instance HasField "nodeCornerRounding" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, NodeCornerRounding}++instance HasField "nodePadding" (Ptr Style) (Ptr ImVec2) where+ getField = #{ptr ImNodesStyle, NodePadding}++instance HasField "nodeBorderThickness" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, NodeBorderThickness}++instance HasField "linkThickness" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, LinkThickness}++instance HasField "linkLineSegmentsPerLength" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, LinkLineSegmentsPerLength}++instance HasField "linkHoverDistance" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, LinkHoverDistance}++instance HasField "pinCircleRadius" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, PinCircleRadius}++instance HasField "pinQuadSideLength" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, PinQuadSideLength}++instance HasField "pinTriangleSideLength" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, PinTriangleSideLength}++instance HasField "pinLineThickness" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, PinLineThickness}++instance HasField "pinHoverRadius" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, PinHoverRadius}++instance HasField "pinOffset" (Ptr Style) (Ptr Float) where+ getField = #{ptr ImNodesStyle, PinOffset}++instance HasField "miniMapPadding" (Ptr Style) (Ptr ImVec2) where+ getField = #{ptr ImNodesStyle, MiniMapPadding}++instance HasField "miniMapOffset" (Ptr Style) (Ptr ImVec2) where+ getField = #{ptr ImNodesStyle, MiniMapOffset}++instance HasField "flags" (Ptr Style) (Ptr StyleFlags) where+ getField = #{ptr ImNodesStyle, Flags}++instance HasField "colors" (Ptr Style) (Ptr CUInt) where+ getField = #{ptr ImNodesStyle, Colors}++colorsLength :: Int+colorsLength = #{const ImNodesCol_COUNT}++foreign import capi unsafe "DearImGuiWrappers.h ImNodesStyle_Init_wrap"+ init+ :: Ptr Style+ -> IO ()++foreign import capi unsafe "DearImGuiWrappers.h ImNodesStyle_Destroy_wrap"+ destroy+ :: Ptr Style+ -> IO ()++withDefault :: (Ptr Style -> IO a) -> IO a+withDefault k = alloca $ \p -> bracket_ (init p) (destroy p) (k p)