diff --git a/imgui.ini b/imgui.ini index cabc0f4..bf4b6e1 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,10 +1,24 @@ [Window][Debug##Default] -Pos=-3,-3 +ViewportPos=1277,2517 +ViewportId=0x9F5F46A1 Size=400,400 Collapsed=0 [Window][viewport_container] -Pos=0,0 Size=1101,598 Collapsed=0 +[Window][Editor] +Pos=8,27 +Size=1118,634 +Collapsed=0 +DockId=0x12F98E09,0 + +[Window][Main] +Pos=0,19 +Size=1134,650 +Collapsed=0 + +[Docking][Data] +DockSpace ID=0x12F98E09 Window=0x1F1A625A Pos=2505,2927 Size=1118,634 CentralNode=1 Selected=0x9F27EDF6 + diff --git a/lib/ImNodeFlow.cpp b/lib/ImNodeFlow.cpp deleted file mode 100755 index 9a8ab63..0000000 --- a/lib/ImNodeFlow.cpp +++ /dev/null @@ -1,378 +0,0 @@ -#include "ImNodeFlow.h" - -namespace ImFlow { -// ----------------------------------------------------------------------------------------------------------------- -// LINK - -void Link::update() { - ImVec2 start = m_left->pinPoint(); - ImVec2 end = m_right->pinPoint(); - float thickness = m_left->getStyle()->extra.link_thickness; - bool mouseClickState = m_inf->getSingleUseClick(); - - if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && - ImGui::IsMouseClicked(ImGuiMouseButton_Left)) - m_selected = false; - - if (smart_bezier_collider(ImGui::GetMousePos(), start, end, 2.5)) { - m_hovered = true; - thickness = m_left->getStyle()->extra.link_hovered_thickness; - if (mouseClickState) { - m_inf->consumeSingleUseClick(); - m_selected = true; - } - } else { - m_hovered = false; - } - - if (m_selected) - smart_bezier(start, end, m_left->getStyle()->extra.outline_color, - thickness + - m_left->getStyle()->extra.link_selected_outline_thickness); - smart_bezier(start, end, m_left->getStyle()->color, thickness); - - if (m_selected && ImGui::IsKeyPressed(ImGuiKey_Delete, false)) - m_right->deleteLink(); -} - -Link::~Link() { m_left->deleteLink(); } - -// ----------------------------------------------------------------------------------------------------------------- -// BASE NODE - -bool BaseNode::isHovered() { - ImVec2 paddingTL = {m_style->padding.x, m_style->padding.y}; - ImVec2 paddingBR = {m_style->padding.z, m_style->padding.w}; - return ImGui::IsMouseHoveringRect( - m_inf->grid2screen(m_pos - paddingTL), - m_inf->grid2screen(m_pos + m_size + paddingBR)); -} - -void BaseNode::update() { - ImDrawList *draw_list = ImGui::GetWindowDrawList(); - ImGui::PushID(this); - bool mouseClickState = m_inf->getSingleUseClick(); - ImVec2 offset = m_inf->grid2screen({0.f, 0.f}); - ImVec2 paddingTL = {m_style->padding.x, m_style->padding.y}; - ImVec2 paddingBR = {m_style->padding.z, m_style->padding.w}; - - draw_list->ChannelsSetCurrent(1); // Foreground - ImGui::SetCursorScreenPos(offset + m_pos); - - ImGui::BeginGroup(); - - // Header - ImGui::BeginGroup(); - ImGui::TextColored(m_style->header_title_color, m_title.c_str()); - ImGui::Spacing(); - ImGui::EndGroup(); - float headerH = ImGui::GetItemRectSize().y; - float titleW = ImGui::GetItemRectSize().x; - - // Inputs - ImGui::BeginGroup(); - for (auto &p : m_ins) { - p->setPos(ImGui::GetCursorPos()); - p->update(); - } - for (auto &p : m_dynamicIns) { - if (p.first == 1) { - p.second->setPos(ImGui::GetCursorPos()); - p.second->update(); - p.first = 0; - } - } - ImGui::EndGroup(); - ImGui::SameLine(); - - // Content - ImGui::BeginGroup(); - draw(); - ImGui::Dummy(ImVec2(0.f, 0.f)); - ImGui::EndGroup(); - ImGui::SameLine(); - - // Outputs - float maxW = 0.0f; - for (auto &p : m_outs) { - float w = p->calcWidth(); - if (w > maxW) - maxW = w; - } - for (auto &p : m_dynamicOuts) { - float w = p.second->calcWidth(); - if (w > maxW) - maxW = w; - } - ImGui::BeginGroup(); - for (auto &p : m_outs) { - // FIXME: This looks horrible - if ((m_pos + ImVec2(titleW, 0) + m_inf->getGrid().scroll()).x < - ImGui::GetCursorPos().x + ImGui::GetWindowPos().x + maxW) - p->setPos(ImGui::GetCursorPos() + ImGui::GetWindowPos() + - ImVec2(maxW - p->calcWidth(), 0.f)); - else - p->setPos(ImVec2((m_pos + ImVec2(titleW - p->calcWidth(), 0) + - m_inf->getGrid().scroll()) - .x, - ImGui::GetCursorPos().y + ImGui::GetWindowPos().y)); - p->update(); - } - for (auto &p : m_dynamicOuts) { - // FIXME: This looks horrible - if ((m_pos + ImVec2(titleW, 0) + m_inf->getGrid().scroll()).x < - ImGui::GetCursorPos().x + ImGui::GetWindowPos().x + maxW) - p.second->setPos(ImGui::GetCursorPos() + ImGui::GetWindowPos() + - ImVec2(maxW - p.second->calcWidth(), 0.f)); - else - p.second->setPos( - ImVec2((m_pos + ImVec2(titleW - p.second->calcWidth(), 0) + - m_inf->getGrid().scroll()) - .x, - ImGui::GetCursorPos().y + ImGui::GetWindowPos().y)); - p.second->update(); - p.first -= 1; - } - - ImGui::EndGroup(); - - ImGui::EndGroup(); - m_size = ImGui::GetItemRectSize(); - ImVec2 headerSize = ImVec2(m_size.x + paddingBR.x, headerH); - - // Background - draw_list->ChannelsSetCurrent(0); - draw_list->AddRectFilled(offset + m_pos - paddingTL, - offset + m_pos + m_size + paddingBR, m_style->bg, - m_style->radius); - draw_list->AddRectFilled(offset + m_pos - paddingTL, - offset + m_pos + headerSize, m_style->header_bg, - m_style->radius, ImDrawFlags_RoundCornersTop); - - ImU32 col = m_style->border_color; - float thickness = m_style->border_thickness; - ImVec2 ptl = paddingTL; - ImVec2 pbr = paddingBR; - if (m_selected) { - col = m_style->border_selected_color; - thickness = m_style->border_selected_thickness; - } - if (thickness < 0.f) { - ptl.x -= thickness / 2; - ptl.y -= thickness / 2; - pbr.x -= thickness / 2; - pbr.y -= thickness / 2; - thickness *= -1.f; - } - draw_list->AddRect(offset + m_pos - ptl, offset + m_pos + m_size + pbr, col, - m_style->radius, 0, thickness); - - if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && - ImGui::IsMouseClicked(ImGuiMouseButton_Left) && - !m_inf->on_selected_node()) - selected(false); - - if (isHovered()) { - m_inf->hoveredNode(this); - if (mouseClickState) { - selected(true); - m_inf->consumeSingleUseClick(); - } - } - - if (ImGui::IsKeyPressed(ImGuiKey_Delete) && !ImGui::IsAnyItemActive() && - isSelected()) - destroy(); - - bool onHeader = ImGui::IsMouseHoveringRect(offset + m_pos - paddingTL, - offset + m_pos + headerSize); - if (onHeader && mouseClickState) { - m_inf->consumeSingleUseClick(); - m_dragged = true; - m_inf->draggingNode(true); - } - if (m_dragged || (m_selected && m_inf->isNodeDragged())) { - float step = - m_inf->getStyle().grid_size / m_inf->getStyle().grid_subdivisions; - m_posTarget += ImGui::GetIO().MouseDelta; - // "Slam" The position - m_pos.x = round(m_posTarget.x / step) * step; - m_pos.y = round(m_posTarget.y / step) * step; - - if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { - m_dragged = false; - m_inf->draggingNode(false); - m_posTarget = m_pos; - } - } - ImGui::PopID(); - - // Resolve output pins values - for (auto &p : m_outs) - p->resolve(); - for (auto &p : m_dynamicOuts) - p.second->resolve(); - - // Deleting dead pins - m_dynamicIns.erase( - std::remove_if(m_dynamicIns.begin(), m_dynamicIns.end(), - [](const std::pair> &p) { - return p.first == 0; - }), - m_dynamicIns.end()); - m_dynamicOuts.erase( - std::remove_if(m_dynamicOuts.begin(), m_dynamicOuts.end(), - [](const std::pair> &p) { - return p.first == 0; - }), - m_dynamicOuts.end()); -} - -// ----------------------------------------------------------------------------------------------------------------- -// HANDLER - -int ImNodeFlow::m_instances = 0; - -bool ImNodeFlow::on_selected_node() { - return std::any_of(m_nodes.begin(), m_nodes.end(), [](const auto &n) { - return n.second->isSelected() && n.second->isHovered(); - }); -} - -bool ImNodeFlow::on_free_space() { - return std::all_of(m_nodes.begin(), m_nodes.end(), - [](const auto &n) { return !n.second->isHovered(); }) && - std::all_of(m_links.begin(), m_links.end(), - [](const auto &l) { return !l.lock()->isHovered(); }); -} - -ImVec2 ImNodeFlow::screen2grid(const ImVec2 &p) { - if (ImGui::GetCurrentContext() == m_context.getRawContext()) - return p - m_context.scroll(); - else - return p - m_context.origin() - m_context.scroll() * m_context.scale(); -} - -ImVec2 ImNodeFlow::grid2screen(const ImVec2 &p) { - if (ImGui::GetCurrentContext() == m_context.getRawContext()) - return p + m_context.scroll(); - else - return p + m_context.origin() + m_context.scroll() * m_context.scale(); -} - -void ImNodeFlow::addLink(std::shared_ptr &link) { - m_links.push_back(link); -} - -void ImNodeFlow::update() { - // Updating looping stuff - m_hovering = nullptr; - m_hoveredNode = nullptr; - m_draggingNode = m_draggingNodeNext; - m_singleUseClick = ImGui::IsMouseClicked(ImGuiMouseButton_Left); - - // Create child canvas - m_context.begin(); - - ImDrawList *draw_list = ImGui::GetWindowDrawList(); - - // Display grid - ImVec2 win_pos = ImGui::GetCursorScreenPos(); - ImVec2 canvas_sz = ImGui::GetWindowSize(); - for (float x = fmodf(m_context.scroll().x, m_style.grid_size); - x < canvas_sz.x; x += m_style.grid_size) - draw_list->AddLine(ImVec2(x, 0.0f) + win_pos, - ImVec2(x, canvas_sz.y) + win_pos, m_style.colors.grid); - for (float y = fmodf(m_context.scroll().y, m_style.grid_size); - y < canvas_sz.y; y += m_style.grid_size) - draw_list->AddLine(ImVec2(0.0f, y) + win_pos, - ImVec2(canvas_sz.x, y) + win_pos, m_style.colors.grid); - for (float x = fmodf(m_context.scroll().x, - m_style.grid_size / m_style.grid_subdivisions); - x < canvas_sz.x; x += m_style.grid_size / m_style.grid_subdivisions) - draw_list->AddLine(ImVec2(x, 0.0f) + win_pos, - ImVec2(x, canvas_sz.y) + win_pos, - m_style.colors.subGrid); - for (float y = fmodf(m_context.scroll().y, - m_style.grid_size / m_style.grid_subdivisions); - y < canvas_sz.y; y += m_style.grid_size / m_style.grid_subdivisions) - draw_list->AddLine(ImVec2(0.0f, y) + win_pos, - ImVec2(canvas_sz.x, y) + win_pos, - m_style.colors.subGrid); - - // Update and draw nodes - // TODO: I don't like this - draw_list->ChannelsSplit(2); - for (auto &node : m_nodes) { - node.second->update(); - } - std::erase_if(m_nodes, [](const auto &n) { return n.second->toDestroy(); }); - draw_list->ChannelsMerge(); - for (auto &node : m_nodes) { - node.second->updatePublicStatus(); - } - - // Update and draw links - for (auto &l : m_links) { - if (!l.expired()) - l.lock()->update(); - } - - // Links drop-off - if (m_dragOut && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { - if (!m_hovering) { - if (on_free_space() && m_droppedLinkPopUp) { - if (m_droppedLinkPupUpComboKey == ImGuiKey_None || - ImGui::IsKeyDown(m_droppedLinkPupUpComboKey)) { - m_droppedLinkLeft = m_dragOut; - ImGui::OpenPopup("DroppedLinkPopUp"); - } - } - } else - m_dragOut->createLink(m_hovering); - } - - // Links drag-out - if (!m_draggingNode && m_hovering && !m_dragOut && - ImGui::IsMouseClicked(ImGuiMouseButton_Left)) - m_dragOut = m_hovering; - if (m_dragOut) { - if (m_dragOut->getType() == PinType_Output) - smart_bezier(m_dragOut->pinPoint(), ImGui::GetMousePos(), - m_dragOut->getStyle()->color, - m_dragOut->getStyle()->extra.link_dragged_thickness); - else - smart_bezier(ImGui::GetMousePos(), m_dragOut->pinPoint(), - m_dragOut->getStyle()->color, - m_dragOut->getStyle()->extra.link_dragged_thickness); - - if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) - m_dragOut = nullptr; - } - - // Right-click PopUp - if (m_rightClickPopUp && ImGui::IsMouseClicked(ImGuiMouseButton_Right) && - ImGui::IsWindowHovered()) { - m_hoveredNodeAux = m_hoveredNode; - ImGui::OpenPopup("RightClickPopUp"); - } - if (ImGui::BeginPopup("RightClickPopUp")) { - m_rightClickPopUp(m_hoveredNodeAux); - ImGui::EndPopup(); - } - - // Dropped Link PopUp - if (ImGui::BeginPopup("DroppedLinkPopUp")) { - m_droppedLinkPopUp(m_droppedLinkLeft); - ImGui::EndPopup(); - } - - // Removing dead Links - m_links.erase( - std::remove_if(m_links.begin(), m_links.end(), - [](const std::weak_ptr &l) { return l.expired(); }), - m_links.end()); - - m_context.end(); -} -} // namespace ImFlow diff --git a/lib/ImNodeFlow.h b/lib/ImNodeFlow.h deleted file mode 100755 index d915ba2..0000000 --- a/lib/ImNodeFlow.h +++ /dev/null @@ -1,1318 +0,0 @@ -#ifndef IM_NODE_FLOW -#define IM_NODE_FLOW -#pragma once - -#include "context_wrapper.h" -#include "imgui.h" -#include "imgui_bezier_math.h" -#include "imgui_internal.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ImFlow { -// ----------------------------------------------------------------------------------------------------------------- -// HELPERS - -/** - * @brief
Draw a sensible bezier between two points - * @param p1 Starting point - * @param p2 Ending point - * @param color Color of the curve - * @param thickness Thickness of the curve - */ -inline static void smart_bezier(const ImVec2 &p1, const ImVec2 &p2, ImU32 color, - float thickness); - -/** - * @brief
Collider checker for smart_bezier - * @details Projects the point "p" orthogonally onto the bezier curve and - * checks if the distance is less than the given radius. - * @param p Point to be tested - * @param p1 Starting point of smart_bezier - * @param p2 Ending point of smart_bezier - * @param radius Lateral width of the hit box - * @return [TRUE] if "p" is inside the collider - * - * Intended to be used in union with smart_bezier(); - */ -inline static bool smart_bezier_collider(const ImVec2 &p, const ImVec2 &p1, - const ImVec2 &p2, float radius); - -// ----------------------------------------------------------------------------------------------------------------- -// CLASSES PRE-DEFINITIONS - -template class InPin; -template class OutPin; -class Pin; -class BaseNode; -class ImNodeFlow; - -// ----------------------------------------------------------------------------------------------------------------- -// PIN'S PROPERTIES - -/** - * @brief
Basic filters - * @details List of, ready to use, basic filters. It's possible to create more - * filters with the help of "ConnectionFilter_MakeCustom". - */ -enum ConnectionFilter_ { - ConnectionFilter_None = 0, - ConnectionFilter_SameNode = 1 << 1, - ConnectionFilter_Bool = 1 << 2, - ConnectionFilter_Int = 1 << 3, - ConnectionFilter_Float = 1 << 4, - ConnectionFilter_Double = 1 << 5, - ConnectionFilter_String = 1 << 6, - ConnectionFilter_MakeCustom = 1 << 7, - ConnectionFilter_Numbers = - ConnectionFilter_Int | ConnectionFilter_Float | ConnectionFilter_Double -}; -typedef long ConnectionFilter; - -typedef unsigned long long int PinUID; - -/** - * @brief Extra pin's style setting - */ -struct PinStyleExtras { - /// @brief Top and bottom spacing - ImVec2 padding = ImVec2(3.f, 1.f); - /// @brief Border and background corner rounding - float bg_radius = 8.f; - /// @brief Border thickness - float border_thickness = 1.f; - /// @brief Background color - ImU32 bg_color = IM_COL32(23, 16, 16, 0); - /// @brief Background color when hovered - ImU32 bg_hover_color = IM_COL32(100, 100, 255, 70); - /// @brief Border color - ImU32 border_color = IM_COL32(255, 255, 255, 0); - - /// @brief Link thickness - float link_thickness = 2.6f; - /// @brief Link thickness when dragged - float link_dragged_thickness = 2.2f; - /// @brief Link thickness when hovered - float link_hovered_thickness = 3.5f; - /// @brief Thickness of the outline of a selected link - float link_selected_outline_thickness = 0.5f; - /// @brief Color of the outline of a selected link - ImU32 outline_color = IM_COL32(80, 20, 255, 200); - - /// @brief Spacing between pin content and socket - float socket_padding = 6.6f; -}; - -/** - * @brief Defines the visual appearance of a pin - */ -class PinStyle { -public: - PinStyle(ImU32 color, int socket_shape, float socket_radius, - float socket_hovered_radius, float socket_connected_radius, - float socket_thickness) - : color(color), socket_shape(socket_shape), socket_radius(socket_radius), - socket_hovered_radius(socket_hovered_radius), - socket_connected_radius(socket_connected_radius), - socket_thickness(socket_thickness) {} - - /// @brief Socket and link color - ImU32 color; - /// @brief Socket shape ID - int socket_shape; - /// @brief Socket radius - float socket_radius; - /// @brief Socket radius when hovered - float socket_hovered_radius; - /// @brief Socket radius when connected - float socket_connected_radius; - /// @brief Socket outline thickness when empty - float socket_thickness; - /// @brief List of less common properties - PinStyleExtras extra; - -public: - /// @brief
Default cyan style - static std::shared_ptr cyan() { - return std::make_shared( - PinStyle(IM_COL32(87, 155, 185, 255), 0, 4.f, 4.67f, 3.7f, 1.f)); - } - /// @brief
Default green style - static std::shared_ptr green() { - return std::make_shared( - PinStyle(IM_COL32(90, 191, 93, 255), 4, 4.f, 4.67f, 4.2f, 1.3f)); - } - /// @brief
Default blue style - static std::shared_ptr blue() { - return std::make_shared( - PinStyle(IM_COL32(90, 117, 191, 255), 0, 4.f, 4.67f, 3.7f, 1.f)); - } - /// @brief
Default brown style - static std::shared_ptr brown() { - return std::make_shared( - PinStyle(IM_COL32(191, 134, 90, 255), 0, 4.f, 4.67f, 3.7f, 1.f)); - } - /// @brief
Default red style - static std::shared_ptr red() { - return std::make_shared( - PinStyle(IM_COL32(191, 90, 90, 255), 0, 4.f, 4.67f, 3.7f, 1.f)); - } - /// @brief
Default white style - static std::shared_ptr white() { - return std::make_shared( - PinStyle(IM_COL32(255, 255, 255, 255), 5, 4.f, 4.67f, 4.2f, 1.f)); - } -}; - -// ----------------------------------------------------------------------------------------------------------------- -// NODE'S PROPERTIES - -typedef uintptr_t NodeUID; - -/** - * @brief Defines the visual appearance of a node - */ -class NodeStyle { -public: - NodeStyle(ImU32 header_bg, ImColor header_title_color, float radius) - : header_bg(header_bg), header_title_color(header_title_color), - radius(radius) {} - - /// @brief Body's background color - ImU32 bg = IM_COL32(55, 64, 75, 255); - /// @brief Header's background color - ImU32 header_bg; - /// @brief Header title color - ImColor header_title_color; - /// @brief Border color - ImU32 border_color = IM_COL32(30, 38, 41, 128); - /// @brief Border color when selected - ImU32 border_selected_color = IM_COL32(170, 190, 205, 255); - - /// @brief Body's content padding (Left Top Right Bottom) - ImVec4 padding = ImVec4(13.7f, 6.f, 13.7f, 2.f); - /// @brief Edges rounding - float radius; - /// @brief Border thickness - float border_thickness = -1.35f; - /// @brief Border thickness when selected - float border_selected_thickness = 2.f; - -public: - /// @brief
Default cyan style - static std::shared_ptr cyan() { - return std::make_shared(IM_COL32(71, 142, 173, 255), - ImColor(233, 241, 244, 255), 6.5f); - } - /// @brief
Default green style - static std::shared_ptr green() { - return std::make_shared(IM_COL32(90, 191, 93, 255), - ImColor(233, 241, 244, 255), 6.5f); - } - /// @brief
Default red style - static std::shared_ptr red() { - return std::make_shared(IM_COL32(191, 90, 90, 255), - ImColor(233, 241, 244, 255), 6.f); - } - /// @brief
Default brown style - static std::shared_ptr brown() { - return std::make_shared(IM_COL32(191, 134, 90, 255), - ImColor(233, 241, 244, 255), 6.5f); - } -}; - -// ----------------------------------------------------------------------------------------------------------------- -// LINK - -/** - * @brief Link between two Pins of two different Nodes - */ -class Link { -public: - /** - * @brief
Construct a link - * @param left Pointer to the output Pin of the Link - * @param right Pointer to the input Pin of the Link - * @param inf Pointer to the Handler that contains the Link - */ - explicit Link(Pin *left, Pin *right, ImNodeFlow *inf) - : m_left(left), m_right(right), m_inf(inf) {} - - /** - * @brief
Destruction of a link - * @details Deletes references of this links form connected pins - */ - ~Link(); - - /** - * @brief
Looping function to update the Link - * @details Draws the Link and updates Hovering and Selected status. - */ - void update(); - - /** - * @brief
Get Left pin of the link - * @return Pointer to the Pin - */ - [[nodiscard]] Pin *left() const { return m_left; } - - /** - * @brief
Get Right pin of the link - * @return Pointer to the Pin - */ - [[nodiscard]] Pin *right() const { return m_right; } - - /** - * @brief
Get hovering status - * @return [TRUE] If the link is hovered in the current frame - */ - [[nodiscard]] bool isHovered() const { return m_hovered; } - - /** - * @brief
Get selected status - * @return [TRUE] If the link is selected in the current frame - */ - [[nodiscard]] bool isSelected() const { return m_selected; } - -private: - ImNodeFlow *m_inf; - Pin *m_left; - Pin *m_right; - bool m_hovered = false; - bool m_selected = false; -}; - -// ----------------------------------------------------------------------------------------------------------------- -// HANDLER - -/** - * @brief Grid's the color parameters - */ -struct InfColors { - /// @brief Background of the grid - ImU32 background = IM_COL32(33, 41, 45, 255); - /// @brief Main lines of the grid - ImU32 grid = IM_COL32(200, 200, 200, 40); - /// @brief Secondary lines - ImU32 subGrid = IM_COL32(200, 200, 200, 10); -}; - -/** - * @brief ALl the grid's appearance parameters. Sizes + Colors - */ -struct InfStyler { - /// @brief Size of main grid - float grid_size = 50.f; - /// @brief Sub-grid divisions for Node snapping - float grid_subdivisions = 5.f; - /// @brief ImNodeFlow colors - InfColors colors; -}; - -/** - * @brief Main node editor - * @details Handles the infinite grid, nodes and links. Also handles all the - * logic. - */ -class ImNodeFlow { -private: - static int m_instances; - -public: - /** - * @brief
Instantiate a new editor with default name. - *
Editor name will be "FlowGrid + the number of editors" - */ - ImNodeFlow() : ImNodeFlow("FlowGrid" + std::to_string(m_instances)) {} - - /** - * @brief
Instantiate a new editor with given name - * @details Creates a new Node Editor with the given name. - * @param name Name of the editor - */ - explicit ImNodeFlow(std::string name) : m_name(std::move(name)) { - m_instances++; - m_context.config().extra_window_wrapper = true; - m_context.config().color = m_style.colors.background; - } - - /** - * @brief
Handler loop - * @details Main update function. Refreshes all the logic and draws - * everything. Must be called every frame. - */ - void update(); - - /** - * @brief
Add a node to the grid - * @tparam T Derived class of to be added - * @tparam Params types of optional args to forward to derived class ctor - * @param pos Position of the Node in grid coordinates - * @param args Optional arguments to be forwarded to derived class ctor - * @return Shared pointer of the pushed type to the newly added node - * - * Inheritance is checked at compile time, \ MUST be derived from BaseNode. - */ - template - std::shared_ptr addNode(const ImVec2 &pos, Params &&...args); - - /** - * @brief
Add a node to the grid - * @tparam T Derived class of to be added - * @tparam Params types of optional args to forward to derived class ctor - * @param pos Position of the Node in screen coordinates - * @param args Optional arguments to be forwarded to derived class ctor - * @return Shared pointer of the pushed type to the newly added node - * - * Inheritance is checked at compile time, \ MUST be derived from BaseNode. - */ - template - std::shared_ptr placeNodeAt(const ImVec2 &pos, Params &&...args); - - /** - * @brief
Add a node to the grid using mouse position - * @tparam T Derived class of to be added - * @tparam Params types of optional args to forward to derived class ctor - * @param args Optional arguments to be forwarded to derived class ctor - * @return Shared pointer of the pushed type to the newly added node - * - * Inheritance is checked at compile time, \ MUST be derived from BaseNode. - */ - template - std::shared_ptr placeNode(Params &&...args); - - /** - * @brief
Add link to the handler internal list - * @param link Reference to the link - */ - void addLink(std::shared_ptr &link); - - /** - * @brief
Pop-up when link is "dropped" - * @details Sets the content of a pop-up that can be displayed when dragging a - * link in the open instead of onto another pin. - * @details If "key = ImGuiKey_None" the pop-up will always open when a link - * is dropped. - * @param content Function or Lambda containing only the contents of the - * pop-up and the subsequent logic - * @param key Optional key required in order to open the pop-up - */ - void droppedLinkPopUpContent(std::function content, - ImGuiKey key = ImGuiKey_None) { - m_droppedLinkPopUp = std::move(content); - m_droppedLinkPupUpComboKey = key; - } - - /** - * @brief
Pop-up when right-clicking - * @details Sets the content of a pop-up that can be displayed when - * right-clicking on the grid. - * @param content Function or Lambda containing only the contents of the - * pop-up and the subsequent logic - */ - void rightClickPopUpContent(std::function content) { - m_rightClickPopUp = std::move(content); - } - - /** - * @brief
Get mouse clicking status - * @return [TRUE] if mouse is clicked and click hasn't been consumed - */ - [[nodiscard]] bool getSingleUseClick() const { return m_singleUseClick; } - - /** - * @brief
Consume the click for the given frame - */ - void consumeSingleUseClick() { m_singleUseClick = false; } - - /** - * @brief
Get editor's name - * @return Const reference to editor's name - */ - const std::string &getName() { return m_name; } - - /** - * @brief
Get editor's position - * @return Const reference to editor's position in screen coordinates - */ - const ImVec2 &getPos() { return m_context.origin(); } - - /** - * @brief
Get editor's grid scroll - * @details Scroll is the offset from the origin of the grid, changes while - * navigating the grid. - * @return Const reference to editor's grid scroll - */ - const ImVec2 &getScroll() { return m_context.scroll(); } - - /** - * @brief
Get editor's list of nodes - * @return Const reference to editor's internal nodes list - */ - std::unordered_map> &getNodes() { - return m_nodes; - } - - /** - * @brief
Get nodes count - * @return Number of nodes present in the editor - */ - uint32_t getNodesCount() { return (uint32_t)m_nodes.size(); } - - /** - * @brief
Get editor's list of links - * @return Const reference to editor's internal links list - */ - const std::vector> &getLinks() { return m_links; } - - /** - * @brief
Get zooming viewport - * @return Const reference to editor's internal viewport for zoom support - */ - ContainedContext &getGrid() { return m_context; } - - /** - * @brief
Get dragging status - * @return [TRUE] if a Node is being dragged around the grid - */ - [[nodiscard]] bool isNodeDragged() const { return m_draggingNode; } - - /** - * @brief
Get current style - * @return Reference to style variables - */ - InfStyler &getStyle() { return m_style; } - - /** - * @brief
Set editor's size - * @param size Editor's size. Set to (0, 0) to auto-fit. - */ - void setSize(const ImVec2 &size) { m_context.config().size = size; } - - /** - * @brief
Set dragging status - * @param state New dragging state - * - * The new state will only be updated one at the start of each frame. - */ - void draggingNode(bool state) { m_draggingNodeNext = state; } - - /** - * @brief
Set what pin is being hovered - * @param hovering Pointer to the hovered pin - */ - void hovering(Pin *hovering) { m_hovering = hovering; } - - /** - * @brief
Set what node is being hovered - * @param hovering Pointer to the hovered node - */ - void hoveredNode(BaseNode *hovering) { m_hoveredNode = hovering; } - - /** - * @brief
Convert coordinates from screen to grid - * @param p Point in screen coordinates to be converted - * @return Point in grid's coordinates - */ - ImVec2 screen2grid(const ImVec2 &p); - - /** - * @brief
Convert coordinates from grid to screen - * @param p Point in grid's coordinates to be converted - * @return Point in screen coordinates - */ - ImVec2 grid2screen(const ImVec2 &p); - - /** - * @brief
Check if mouse is on selected node - * @return [TRUE] if the mouse is hovering a selected node - */ - bool on_selected_node(); - - /** - * @brief
Check if mouse is on a free point on the grid - * @return [TRUE] if the mouse is not hovering a node or a link - */ - bool on_free_space(); - -private: - std::string m_name; - ContainedContext m_context; - - bool m_singleUseClick = false; - - std::unordered_map> m_nodes; - std::vector> m_links; - - std::function m_droppedLinkPopUp; - ImGuiKey m_droppedLinkPupUpComboKey = ImGuiKey_None; - Pin *m_droppedLinkLeft = nullptr; - std::function m_rightClickPopUp; - BaseNode *m_hoveredNodeAux = nullptr; - - BaseNode *m_hoveredNode = nullptr; - bool m_draggingNode = false, m_draggingNodeNext = false; - Pin *m_hovering = nullptr; - Pin *m_dragOut = nullptr; - - InfStyler m_style; -}; - -// ----------------------------------------------------------------------------------------------------------------- -// BASE NODE - -/** - * @brief Parent class for custom nodes - * @details Main class from which custom nodes can be created. All interactions - * with the main grid are handled internally. - */ -class BaseNode { -public: - BaseNode() = default; - - /** - * @brief
Main loop of the node - * @details Updates position, hovering and selected status, and renders the - * node. Must be called each frame. - */ - void update(); - - /** - * @brief
Content of the node - * @details Function to be implemented by derived custom nodes. - * Must contain the body of the node. If left empty the node will - * only have input and output pins. - */ - virtual void draw() {} - - /** - * @brief
Add an Input to the node - * @details Will add an Input pin to the node with the given name and data - * type.

In this case the name of the pin will also be its UID.
- *
The UID must be unique only in the context of the current node's - * inputs. - * @tparam T Type of the data the pin will handle - * @param name Name of the pin - * @param defReturn Default return value when the pin is not connected - * @param filter Connection filter - * @param style Style of the pin - * @return Shared pointer to the newly added pin - */ - template - std::shared_ptr> - addIN(const std::string &name, T defReturn, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Add an Input to the node - * @details Will add an Input pin to the node with the given name and data - * type.

The UID must be unique only in the context of the current - * node's inputs. - * @tparam T Type of the data the pin will handle - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - * @param name Name of the pin - * @param defReturn Default return value when the pin is not connected - * @param filter Connection filter - * @param style Style of the pin - * @return Shared pointer to the newly added pin - */ - template - std::shared_ptr> - addIN_uid(const U &uid, const std::string &name, T defReturn, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Remove input pin - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - */ - template void dropIN(const U &uid); - - /** - * @brief
Remove input pin - * @param uid Unique identifier of the pin - */ - void dropIN(const char *uid); - - /** - * @brief
Show a temporary input pin - * @details Will show an input pin with the given name. - * The pin is created the first time showIN is called and kept alive - * as long as showIN is called each frame.

In this case the name of - * the pin will also be its UID.

The UID must be unique only in the - * context of the current node's inputs. - * @tparam T Type of the data the pin will handle - * @param name Name of the pin - * @param defReturn Default return value when the pin is not connected - * @param filter Connection filter - * @param style Style of the pin - * @return Const reference to the value of the connected link for the current - * frame of defReturn - */ - template - const T &showIN(const std::string &name, T defReturn, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Show a temporary input pin - * @details Will show an input pin with the given name and UID. - * The pin is created the first time showIN_uid is called and kept - * alive as long as showIN_uid is called each frame.

The UID must be - * unique only in the context of the current node's inputs. - * @tparam T Type of the data the pin will handle - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - * @param name Name of the pin - * @param defReturn Default return value when the pin is not connected - * @param filter Connection filter - * @param style Style of the pin - * @return Const reference to the value of the connected link for the current - * frame of defReturn - */ - template - const T &showIN_uid(const U &uid, const std::string &name, T defReturn, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Add an Output to the node - * @details Must be called in the node constructor. WIll add an Output pin to - * the node with the given name and data type.

In this case the name - * of the pin will also be its UID.

The UID must be unique only in - * the context of the current node's outputs. - * @tparam T Type of the data the pin will handle - * @param name Name of the pin - * @param filter Connection filter - * @param style Style of the pin - * @return Shared pointer to the newly added pin. Must be used to set the - * behaviour - */ - template - [[nodiscard]] std::shared_ptr> - addOUT(const std::string &name, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Add an Output to the node - * @details Must be called in the node constructor. WIll add an Output pin to - * the node with the given name and data type.

The UID must be - * unique only in the context of the current node's outputs. - * @tparam T Type of the data the pin will handle - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - * @param name Name of the pin - * @param filter Connection filter - * @param style Style of the pin - * @return Shared pointer to the newly added pin. Must be used to set the - * behaviour - */ - template - [[nodiscard]] std::shared_ptr> - addOUT_uid(const U &uid, const std::string &name, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Remove output pin - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - */ - template void dropOUT(const U &uid); - - /** - * @brief
Remove output pin - * @param uid Unique identifier of the pin - */ - void dropOUT(const char *uid); - - /** - * @brief
Show a temporary output pin - * @details Will show an output pin with the given name. - * The pin is created the first time showOUT is called and kept alive - * as long as showOUT is called each frame.

In this case the name of - * the pin will also be its UID.

The UID must be unique only in the - * context of the current node's outputs. - * @tparam T Type of the data the pin will handle - * @param name Name of the pin - * @param behaviour Function or lambda expression used to calculate output - * value - * @param filter Connection filter - * @param style Style of the pin - */ - template - void showOUT(const std::string &name, std::function behaviour, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Show a temporary output pin - * @details Will show an output pin with the given name. - * The pin is created the first time showOUT_uid is called and kept - * alive as long as showOUT_uid is called each frame.

The UID must - * be unique only in the context of the current node's outputs. - * @tparam T Type of the data the pin will handle - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - * @param name Name of the pin - * @param behaviour Function or lambda expression used to calculate output - * value - * @param filter Connection filter - * @param style Style of the pin - */ - template - void showOUT_uid(const U &uid, const std::string &name, - std::function behaviour, - ConnectionFilter filter = ConnectionFilter_None, - std::shared_ptr style = nullptr); - - /** - * @brief
Get Input value from an InPin - * @details Get a reference to the value of an input pin, the value is stored - * in the output pin at the other end of the link. - * @tparam T Data type - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - * @return Const reference to the value - */ - template const T &getInVal(const U &uid); - - /** - * @brief
Get Input value from an InPin - * @details Get a reference to the value of an input pin, the value is stored - * in the output pin at the other end of the link. - * @tparam T Data type - * @param uid Unique identifier of the pin - * @return Const reference to the value - */ - template const T &getInVal(const char *uid); - - /** - * @brief
Get generic reference to input pin - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - * @return Generic pointer to the pin - */ - template Pin *inPin(const U &uid); - - /** - * @brief
Get generic reference to input pin - * @param uid Unique identifier of the pin - * @return Generic pointer to the pin - */ - Pin *inPin(const char *uid); - - /** - * @brief
Get generic reference to output pin - * @tparam U Type of the UID - * @param uid Unique identifier of the pin - * @return Generic pointer to the pin - */ - template Pin *outPin(const U &uid); - - /** - * @brief
Get generic reference to output pin - * @param uid Unique identifier of the pin - * @return Generic pointer to the pin - */ - Pin *outPin(const char *uid); - - /** - * @brief
Get internal input pins list - * @return Const reference to node's internal list - */ - const std::vector> &getIns() { return m_ins; } - - /** - * @brief
Get internal output pins list - * @return Const reference to node's internal list - */ - const std::vector> &getOuts() { return m_outs; } - - /** - * @brief
Delete itself - */ - void destroy() { m_destroyed = true; } - - /* - * @brief
Get if node must be deleted - */ - [[nodiscard]] bool toDestroy() const { return m_destroyed; } - - /** - * @brief
Get hovered status - * @return [TRUE] if the mouse is hovering the node - */ - bool isHovered(); - - /** - * @brief
Get node's UID - * @return Node's unique identifier - */ - [[nodiscard]] NodeUID getUID() const { return m_uid; } - - /** - * @brief
Get node name - * @return Const reference to the node's name - */ - const std::string &getName() { return m_title; } - - /** - * @brief
Get node size - * @return Const reference to the node's size - */ - const ImVec2 &getSize() { return m_size; } - - /** - * @brief
Get node position - * @return Const reference to the node's position - */ - const ImVec2 &getPos() { return m_pos; } - - /** - * @brief
Get grid handler bound to node - * @return Pointer to the handler - */ - ImNodeFlow *getHandler() { return m_inf; } - - /** - * @brief
Get node's style - * @return Shared pointer to the node's style - */ - const std::shared_ptr &getStyle() { return m_style; } - - /** - * @brief
Get selected status - * @return [TRUE] if the node is selected - */ - [[nodiscard]] bool isSelected() const { return m_selected; } - - /** - * @brief
Get dragged status - * @return [TRUE] if the node is being dragged - */ - [[nodiscard]] bool isDragged() const { return m_dragged; } - - /** - * @brief
Set node's uid - * @param uid Node's unique identifier - */ - BaseNode *setUID(NodeUID uid) { - m_uid = uid; - return this; - } - - /** - * @brief
Set node's name - * @param name New title - */ - BaseNode *setTitle(const std::string &title) { - m_title = title; - return this; - } - - /** - * @brief
Set node's position - * @param pos Position in grid coordinates - */ - BaseNode *setPos(const ImVec2 &pos) { - m_pos = pos; - m_posTarget = pos; - return this; - } - - /** - * @brief
Set ImNodeFlow handler - * @param inf Grid handler for the node - */ - BaseNode *setHandler(ImNodeFlow *inf) { - m_inf = inf; - return this; - } - - /** - * @brief Set node's style - * @param style New style - */ - BaseNode *setStyle(std::shared_ptr style) { - m_style = std::move(style); - return this; - } - - /** - * @brief
Set selected status - * @param state New selected state - * - * Status only updates when updatePublicStatus() is called - */ - BaseNode *selected(bool state) { - m_selectedNext = state; - return this; - } - - /** - * @brief
Update the isSelected status of the node - */ - void updatePublicStatus() { m_selected = m_selectedNext; } - -private: - NodeUID m_uid = 0; - std::string m_title; - ImVec2 m_pos, m_posTarget; - ImVec2 m_size; - ImNodeFlow *m_inf = nullptr; - std::shared_ptr m_style; - bool m_selected = false, m_selectedNext = false; - bool m_dragged = false; - bool m_destroyed = false; - - std::vector> m_ins; - std::vector>> m_dynamicIns; - std::vector> m_outs; - std::vector>> m_dynamicOuts; -}; - -// ----------------------------------------------------------------------------------------------------------------- -// PINS - -/** - * @brief Pins type identifier - */ -enum PinType { PinType_Input, PinType_Output }; - -/** - * @brief Generic base class for pins - */ -class Pin { -public: - /** - * @brief
Generic pin constructor - * @param name Name of the pin - * @param filter Connection filter - * @param kind Specifies Input or Output - * @param parent Pointer to the Node containing the pin - * @param inf Pointer to the Grid Handler the pin is in (same as parent) - * @param style Style of the pin - */ - explicit Pin(PinUID uid, std::string name, ConnectionFilter filter, - PinType kind, BaseNode *parent, ImNodeFlow **inf, - std::shared_ptr style) - : m_uid(uid), m_name(std::move(name)), m_filter(filter), m_type(kind), - m_parent(parent), m_inf(inf), m_style(std::move(style)) { - if (!m_style) - m_style = PinStyle::cyan(); - } - - /** - * @brief
Main loop of the pin - * @details Updates position, hovering and dragging status, and renders the - * pin. Must be called each frame. - */ - void update(); - - /** - * @brief
Draw default pin's socket - */ - void drawSocket(); - - /** - * @brief
Draw default pin's decoration (border, bg, and hover overlay) - */ - void drawDecoration(); - - /** - * @brief
Used by output pins to calculate their values - */ - virtual void resolve() {} - - /** - * @brief
Custom render function to override Pin appearance - * @param r Function or lambda expression with new ImGui rendering - */ - Pin *renderer(std::function r) { - m_renderer = std::move(r); - return this; - } - - /** - * @brief
Create link between pins - * @param other Pointer to the other pin - */ - virtual void createLink(Pin *other) = 0; - - /** - * @brief
Set the reference to a link - * @param link Smart pointer to the link - */ - virtual void setLink(std::shared_ptr &link) {} - - /** - * @brief
Delete link reference - */ - virtual void deleteLink() = 0; - - /** - * @brief
Get connected status - * @return [TRUE] if the pin is connected - */ - virtual bool isConnected() = 0; - - /** - * @brief
Get pin's link - * @return Weak_ptr reference to pin's link - */ - virtual std::weak_ptr getLink() { return std::weak_ptr{}; } - - /** - * @brief
Get pin's UID - * @return Unique identifier of the pin - */ - [[nodiscard]] PinUID getUid() const { return m_uid; } - - /** - * @brief
Get pin's name - * @return Const reference to pin's name - */ - const std::string &getName() { return m_name; } - - /** - * @brief
Get pin's position - * @return Const reference to pin's position in grid coordinates - */ - [[nodiscard]] const ImVec2 &getPos() { return m_pos; } - - /** - * @brief
Get pin's hit-box size - * @return Const reference to pin's hit-box size - */ - [[nodiscard]] const ImVec2 &getSize() { return m_size; } - - /** - * @brief
Get pin's parent node - * @return Generic type pointer to pin's parent node. (Node that contains it) - */ - BaseNode *getParent() { return m_parent; } - - /** - * @brief
Get pin's type - * @return The pin type. Either Input or Output - */ - PinType getType() { return m_type; } - - /** - * @brief
Get pin's connection filter - * @return Pin's connection filter configuration - */ - [[nodiscard]] ConnectionFilter getFilter() const { return m_filter; } - - /** - * @brief
Get pin's style - * @return Smart pointer to pin's style - */ - std::shared_ptr &getStyle() { return m_style; } - - /** - * @brief
Get pin's link attachment point (socket) - * @return Grid coordinates to the attachment point between the link and the - * pin's socket - */ - virtual ImVec2 pinPoint() = 0; - - /** - * @brief
Calculate pin's width pre-rendering - * @return The with of the pin once it will be rendered - */ - float calcWidth() { return ImGui::CalcTextSize(m_name.c_str()).x; } - - /** - * @brief
Set pin's position - * @param pos Position in screen coordinates - */ - void setPos(ImVec2 pos) { m_pos = pos; } - -protected: - PinUID m_uid; - std::string m_name; - ImVec2 m_pos = ImVec2(0.f, 0.f); - ImVec2 m_size = ImVec2(0.f, 0.f); - PinType m_type; - ConnectionFilter m_filter; - std::shared_ptr m_style; - BaseNode *m_parent = nullptr; - ImNodeFlow **m_inf; - std::function m_renderer; -}; - -/** - * @brief Input specific pin - * @details Derived from the generic class Pin. The input pin owns the link - * pointer. - * @tparam T Data type handled by the pin - */ -template class InPin : public Pin { -public: - /** - * @brief
Input pin constructor - * @param name Name of the pin - * @param filter Connection filter - * @param parent Pointer to the Node containing the pin - * @param defReturn Default return value when the pin is not connected - * @param inf Pointer to the Grid Handler the pin is in (same as parent) - * @param style Style of the pin - */ - explicit InPin(PinUID uid, const std::string &name, ConnectionFilter filter, - BaseNode *parent, T defReturn, ImNodeFlow **inf, - std::shared_ptr style) - : Pin(uid, name, filter, PinType_Input, parent, inf, style), - m_emptyVal(defReturn) {} - - /** - * @brief
Create link between pins - * @param other Pointer to the other pin - */ - void createLink(Pin *other) override; - - /** - * @brief
Delete the link connected to the pin - */ - void deleteLink() override { m_link.reset(); } - - /** - * @brief
Get connected status - * @return [TRUE] is pin is connected to a link - */ - bool isConnected() override { return m_link != nullptr; } - - /** - * @brief
Get pin's link - * @return Weak_ptr reference to the link connected to the pin - */ - std::weak_ptr getLink() override { return m_link; } - - /** - * @brief
Get pin's link attachment point (socket) - * @return Grid coordinates to the attachment point between the link and the - * pin's socket - */ - ImVec2 pinPoint() override { - return m_pos + ImVec2(-m_style->extra.socket_padding, m_size.y / 2); - } - - /** - * @brief
Get value carried by the connected link - * @return Reference to the value of the connected OutPin. Or the default - * value if not connected - */ - const T &val(); - -private: - std::shared_ptr m_link; - T m_emptyVal; -}; - -/** - * @brief Output specific pin - * @details Derived from the generic class Pin. The output pin handles the - * logic. - * @tparam T Data type handled by the pin - */ -template class OutPin : public Pin { -public: - /** - * @brief
Output pin constructor - * @param name Name of the pin - * @param filter Connection filter - * @param parent Pointer to the Node containing the pin - * @param inf Pointer to the Grid Handler the pin is in (same as parent) - * @param style Style of the pin - */ - explicit OutPin(PinUID uid, const std::string &name, ConnectionFilter filter, - BaseNode *parent, ImNodeFlow **inf, - std::shared_ptr style) - : Pin(uid, name, filter, PinType_Output, parent, inf, style) {} - - /** - * @brief
When parent gets deleted, remove the links - */ - ~OutPin() { - for (auto &l : m_links) - if (!l.expired()) - l.lock()->right()->deleteLink(); - } - - /** - * @brief
Calculate output value based on set behaviour - */ - void resolve() override { m_val = m_behaviour(); } - - /** - * @brief
Create link between pins - * @param other Pointer to the other pin - */ - void createLink(Pin *other) override; - - /** - * @brief
Add a connected link to the internal list - * @param link Pointer to the link - */ - void setLink(std::shared_ptr &link) override; - - /** - * @brief
Delete any expired weak pointers to a (now deleted) link - */ - void deleteLink() override; - - /** - * @brief
Get connected status - * @return [TRUE] is pin is connected to one or more links - */ - bool isConnected() override { return !m_links.empty(); } - - /** - * @brief
Get pin's link attachment point (socket) - * @return Grid coordinates to the attachment point between the link and the - * pin's socket - */ - ImVec2 pinPoint() override { - return m_pos + - ImVec2(m_size.x + m_style->extra.socket_padding, m_size.y / 2); - } - - /** - * @brief
Get output value - * @return Const reference to the internal value of the pin - */ - const T &val(); - - /** - * @brief
Set logic to calculate output value - * @details Used to define the pin behaviour. This is what gets the data from - * the parent's inputs, and applies the needed logic. - * @param func Function or lambda expression used to calculate output value - */ - OutPin *behaviour(std::function func) { - m_behaviour = std::move(func); - return this; - } - -private: - std::vector> m_links; - std::function m_behaviour; - T m_val; -}; -} // namespace ImFlow - -#include "./ImNodeFlow.inl" - -#endif diff --git a/lib/ImNodeFlow.inl b/lib/ImNodeFlow.inl deleted file mode 100755 index c7ab99e..0000000 --- a/lib/ImNodeFlow.inl +++ /dev/null @@ -1,347 +0,0 @@ -#pragma once - -#include "ImNodeFlow.h" - -namespace ImFlow -{ - inline void smart_bezier(const ImVec2& p1, const ImVec2& p2, ImU32 color, float thickness) - { - ImDrawList* dl = ImGui::GetWindowDrawList(); - float distance = sqrt(pow((p2.x - p1.x), 2.f) + pow((p2.y - p1.y), 2.f)); - float delta = distance * 0.45f; - if (p2.x < p1.x) delta += 0.2f * (p1.x - p2.x); - // float vert = (p2.x < p1.x - 20.f) ? 0.062f * distance * (p2.y - p1.y) * 0.005f : 0.f; - float vert = 0.f; - ImVec2 p22 = p2 - ImVec2(delta, vert); - if (p2.x < p1.x - 50.f) delta *= -1.f; - ImVec2 p11 = p1 + ImVec2(delta, vert); - dl->AddBezierCubic(p1, p11, p22, p2, color, thickness); - } - - inline bool smart_bezier_collider(const ImVec2& p, const ImVec2& p1, const ImVec2& p2, float radius) - { - float distance = sqrt(pow((p2.x - p1.x), 2.f) + pow((p2.y - p1.y), 2.f)); - float delta = distance * 0.45f; - if (p2.x < p1.x) delta += 0.2f * (p1.x - p2.x); - // float vert = (p2.x < p1.x - 20.f) ? 0.062f * distance * (p2.y - p1.y) * 0.005f : 0.f; - float vert = 0.f; - ImVec2 p22 = p2 - ImVec2(delta, vert); - if (p2.x < p1.x - 50.f) delta *= -1.f; - ImVec2 p11 = p1 + ImVec2(delta, vert); - return ImProjectOnCubicBezier(p, p1, p11, p22, p2).Distance < radius; - } - - // ----------------------------------------------------------------------------------------------------------------- - // HANDLER - - template - std::shared_ptr ImNodeFlow::addNode(const ImVec2& pos, Params&&... args) - { - static_assert(std::is_base_of::value, "Pushed type is not a subclass of BaseNode!"); - - std::shared_ptr n = std::make_shared(std::forward(args)...); - n->setPos(pos); - n->setHandler(this); - if (!n->getStyle()) - n->setStyle(NodeStyle::cyan()); - - auto uid = reinterpret_cast(n.get()); - n->setUID(uid); - m_nodes[uid] = n; - return n; - } - - template - std::shared_ptr ImNodeFlow::placeNodeAt(const ImVec2& pos, Params&&... args) - { - return addNode(screen2grid(pos), std::forward(args)...); - } - - template - std::shared_ptr ImNodeFlow::placeNode(Params&&... args) - { - return placeNodeAt(ImGui::GetMousePos(), std::forward(args)...); - } - - // ----------------------------------------------------------------------------------------------------------------- - // BASE NODE - - template - std::shared_ptr> BaseNode::addIN(const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr style) - { - return addIN_uid(name, name, defReturn, filter, std::move(style)); - } - - template - std::shared_ptr> BaseNode::addIN_uid(const U& uid, const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr style) - { - PinUID h = std::hash{}(uid); - auto p = std::make_shared>(h, name, filter, this, defReturn, &m_inf, std::move(style)); - m_ins.emplace_back(p); - return p; - } - - template - void BaseNode::dropIN(const U& uid) - { - PinUID h = std::hash{}(uid); - for (auto it = m_ins.begin(); it != m_ins.end(); it++) - { - if (it->get()->getUid() == h) - { - m_ins.erase(it); - return; - } - } - } - - inline void BaseNode::dropIN(const char* uid) - { - dropIN(uid); - } - - template - const T& BaseNode::showIN(const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr style) - { - return showIN_uid(name, name, defReturn, filter, std::move(style)); - } - - template - const T& BaseNode::showIN_uid(const U& uid, const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr style) - { - PinUID h = std::hash{}(uid); - for (std::pair>& p : m_dynamicIns) - { - if (p.second->getUid() == h) - { - p.first = 1; - return static_cast*>(p.second.get())->val(); - } - } - - m_dynamicIns.emplace_back(std::make_pair(1, std::make_shared>(h, name, filter, this, defReturn, &m_inf, std::move(style)))); - return static_cast*>(m_dynamicIns.back().second.get())->val(); - } - - template - std::shared_ptr> BaseNode::addOUT(const std::string& name, ConnectionFilter filter, std::shared_ptr style) - { - return addOUT_uid(name, name, filter, std::move(style)); - } - - template - std::shared_ptr> BaseNode::addOUT_uid(const U& uid, const std::string& name, ConnectionFilter filter, std::shared_ptr style) - { - PinUID h = std::hash{}(uid); - auto p = std::make_shared>(h, name, filter, this, &m_inf, std::move(style)); - m_outs.emplace_back(p); - return p; - } - - template - void BaseNode::dropOUT(const U& uid) - { - PinUID h = std::hash{}(uid); - for (auto it = m_outs.begin(); it != m_outs.end(); it++) - { - if (it->get()->getUid() == h) - { - m_outs.erase(it); - return; - } - } - } - - inline void BaseNode::dropOUT(const char* uid) - { - dropOUT(uid); - } - - template - void BaseNode::showOUT(const std::string& name, std::function behaviour, ConnectionFilter filter, std::shared_ptr style) - { - showOUT_uid(name, name, std::move(behaviour), filter, std::move(style)); - } - - template - void BaseNode::showOUT_uid(const U& uid, const std::string& name, std::function behaviour, ConnectionFilter filter, std::shared_ptr style) - { - PinUID h = std::hash{}(uid); - for (std::pair>& p : m_dynamicOuts) - { - if (p.second->getUid() == h) - { - p.first = 2; - return; - } - } - - m_dynamicOuts.emplace_back(std::make_pair(2, std::make_shared>(h, name, filter, this, &m_inf, std::move(style)))); - static_cast*>(m_dynamicOuts.back().second.get())->behaviour(std::move(behaviour)); - } - - template - const T& BaseNode::getInVal(const U& uid) - { - PinUID h = std::hash{}(uid); - auto it = std::find_if(m_ins.begin(), m_ins.end(), [&h](std::shared_ptr& p) - { return p->getUid() == h; }); - assert(it != m_ins.end() && "Pin UID not found!"); - return static_cast*>(it->get())->val(); - } - - template - const T& BaseNode::getInVal(const char* uid) - { - return getInVal(uid); - } - - template - Pin* BaseNode::inPin(const U& uid) - { - PinUID h = std::hash{}(uid); - auto it = std::find_if(m_ins.begin(), m_ins.end(), [&h](std::shared_ptr& p) - { return p->getUid() == h; }); - assert(it != m_ins.end() && "Pin UID not found!"); - return it->get(); - } - - inline Pin* BaseNode::inPin(const char* uid) - { - return inPin(uid); - } - - template - Pin* BaseNode::outPin(const U& uid) - { - PinUID h = std::hash{}(uid); - auto it = std::find_if(m_outs.begin(), m_outs.end(), [&h](std::shared_ptr& p) - { return p->getUid() == h; }); - assert(it != m_outs.end() && "Pin UID not found!"); - return it->get(); - } - - inline Pin* BaseNode::outPin(const char* uid) - { - return outPin(uid); - } - - // ----------------------------------------------------------------------------------------------------------------- - // PIN - - inline void Pin::drawSocket() - { - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - ImVec2 tl = pinPoint() - ImVec2(m_style->socket_radius, m_style->socket_radius); - ImVec2 br = pinPoint() + ImVec2(m_style->socket_radius, m_style->socket_radius); - - if (isConnected()) - draw_list->AddCircleFilled(pinPoint(), m_style->socket_connected_radius, m_style->color, m_style->socket_shape); - else - { - if (ImGui::IsItemHovered() || ImGui::IsMouseHoveringRect(tl, br)) - draw_list->AddCircle(pinPoint(), m_style->socket_hovered_radius, m_style->color, m_style->socket_shape, m_style->socket_thickness); - else - draw_list->AddCircle(pinPoint(), m_style->socket_radius, m_style->color, m_style->socket_shape, m_style->socket_thickness); - } - - if (ImGui::IsMouseHoveringRect(tl, br)) - (*m_inf)->hovering(this); - } - - inline void Pin::drawDecoration() - { - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - - if (ImGui::IsItemHovered()) - draw_list->AddRectFilled(m_pos - m_style->extra.padding, m_pos + m_size + m_style->extra.padding, m_style->extra.bg_hover_color, m_style->extra.bg_radius); - else - draw_list->AddRectFilled(m_pos - m_style->extra.padding, m_pos + m_size + m_style->extra.padding, m_style->extra.bg_color, m_style->extra.bg_radius); - draw_list->AddRect(m_pos - m_style->extra.padding, m_pos + m_size + m_style->extra.padding, m_style->extra.border_color, m_style->extra.bg_radius, 0, m_style->extra.border_thickness); - } - - inline void Pin::update() - { - // Custom rendering - if (m_renderer) - { - ImGui::BeginGroup(); - m_renderer(this); - ImGui::EndGroup(); - m_size = ImGui::GetItemRectSize(); - if (ImGui::IsItemHovered()) - (*m_inf)->hovering(this); - return; - } - - ImGui::SetCursorPos(m_pos); - ImGui::Text(m_name.c_str()); - m_size = ImGui::GetItemRectSize(); - - drawDecoration(); - drawSocket(); - - if (ImGui::IsItemHovered()) - (*m_inf)->hovering(this); - } - - // ----------------------------------------------------------------------------------------------------------------- - // IN PIN - - template - const T& InPin::val() - { - if(!m_link) - return m_emptyVal; - - return reinterpret_cast*>(m_link->left())->val(); - } - - template - void InPin::createLink(Pin *other) - { - if (other == this || other->getType() == PinType_Input || (m_parent == other->getParent() && (m_filter & ConnectionFilter_SameNode) == 0)) - return; - - if (!((m_filter & other->getFilter()) != 0 || m_filter == ConnectionFilter_None || other->getFilter() == ConnectionFilter_None)) // Check Filter - return; - - if (m_link && m_link->left() == other) - { - m_link.reset(); - return; - } - - m_link = std::make_shared(other, this, (*m_inf)); - other->setLink(m_link); - (*m_inf)->addLink(m_link); - } - - // ----------------------------------------------------------------------------------------------------------------- - // OUT PIN - - template - const T &OutPin::val() { return m_val; } - - template - void OutPin::createLink(ImFlow::Pin *other) - { - if (other == this || other->getType() == PinType_Output) - return; - - other->createLink(this); - } - - template - void OutPin::setLink(std::shared_ptr& link) - { - m_links.emplace_back(link); - } - - template - void OutPin::deleteLink() - { - m_links.erase(std::remove_if(m_links.begin(), m_links.end(), - [](const std::weak_ptr& l) { return l.expired(); }), m_links.end()); - } -} diff --git a/main.cpp b/main.cpp index eca7f56..290bab3 100644 --- a/main.cpp +++ b/main.cpp @@ -14,7 +14,7 @@ #include "lib/backends/imgui_impl_opengl3.h" #include "lib/backends/imgui_impl_sdl2.h" #include "lib/imgui.h" -#include "lib/nodes/load_image.h" +#include "lib/imgui_internal.h" #include #define STB_IMAGE_IMPLEMENTATION @@ -36,9 +36,6 @@ #endif #endif - -#include "lib/ImNodeFlow.h" - static bool init = true; // Main code @@ -131,7 +128,6 @@ int main(int, char **) { ImGui_ImplOpenGL3_Init(glsl_version); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - ImFlow::ImNodeFlow editor = ImFlow::ImNodeFlow("Nodes"); // Main loop bool done = false; @@ -172,6 +168,7 @@ int main(int, char **) { ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); #endif + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::Begin("Main", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize); @@ -179,6 +176,7 @@ int main(int, char **) { ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode; ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f)); + if (init) { init = false; ImGui::DockBuilderRemoveNode(dockspace_id); @@ -188,22 +186,12 @@ int main(int, char **) { ImGui::DockBuilderDockWindow("Editor", dockspace_id); ImGui::DockBuilderFinish(dockspace_id); } + if (ImGui::BeginMainMenuBar()) { - if (ImGui::BeginMenu("Add")) { - if (ImGui::MenuItem("Load image")) { - editor.addNode(ImVec2(10, 10)); + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("Open")) { } - if (ImGui::MenuItem("Preview")) { - editor.addNode(ImVec2(10, 10)); - } - if (ImGui::MenuItem("Simple Brightness")) { - editor.addNode(ImVec2(10, 10)); - } - if (ImGui::MenuItem("Contrast")) { - editor.addNode(ImVec2(10, 10)); - } - if (ImGui::MenuItem("Exposure")) { - editor.addNode(ImVec2(10, 10)); + if (ImGui::MenuItem("Exit")) { } ImGui::EndMenu(); } @@ -212,7 +200,7 @@ int main(int, char **) { ImGui::Begin("Editor", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize); - editor.update(); + // -- MAIN WINDOW HERE ImGui::End(); ImGui::End(); ImGui::PopStyleVar();