packages feed

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 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)