diff --git a/3rdparty/imnodes/imnodes.cpp b/3rdparty/imnodes/imnodes.cpp index 4e9d0aa..b6156cb 100644 --- a/3rdparty/imnodes/imnodes.cpp +++ b/3rdparty/imnodes/imnodes.cpp @@ -5,12 +5,8 @@ // [SECTION] ui state logic // [SECTION] render helpers // [SECTION] API implementation -#define IMGUI_DEFINE_MATH_OPERATORS -#include "imnodes.h" -#include "imnodes_internal.h" - -#include +#include "imnodes_internal.h" // Check minimum ImGui version #define MINIMUM_COMPATIBLE_IMGUI_VERSION 17400 @@ -18,7 +14,6 @@ #error "Minimum ImGui version requirement not met -- please use a newer version!" #endif -#include #include #include #include @@ -27,6 +22,11 @@ #include #include // 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 @@ -115,7 +115,7 @@ inline CubicBezier GetCubicBezier( const ImNodesAttributeType start_type, const float line_segments_per_length) { - assert( + IM_ASSERT( (start_type == ImNodesAttributeType_Input) || (start_type == ImNodesAttributeType_Output)); if (start_type == ImNodesAttributeType_Input) { @@ -287,20 +287,20 @@ inline ImVec2 MiniMapSpaceToGridSpace(const ImNodesEditorContext& editor, const { 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 @@ -350,7 +350,11 @@ void ImDrawListGrowChannels(ImDrawList* draw_list, const int num_channels) { 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); } } @@ -366,8 +370,8 @@ void ImDrawListSplitterSwapChannels( return; } - assert(lhs_idx >= 0 && lhs_idx < splitter._Count); - assert(rhs_idx >= 0 && rhs_idx < splitter._Count); + 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]; @@ -463,7 +467,7 @@ void DrawListActivateNodeBackground(const int node_idx) // * SetNodeGridSpacePos // * SetNodeDraggable // after the BeginNode/EndNode function calls? - assert(submission_idx != -1); + IM_ASSERT(submission_idx != -1); const int background_channel_idx = DrawListSubmissionIdxToBackgroundChannelIdx(submission_idx); GImNodes->CanvasDrawList->_Splitter.SetCurrentChannel( GImNodes->CanvasDrawList, background_channel_idx); @@ -471,7 +475,7 @@ void DrawListActivateNodeBackground(const int node_idx) void DrawListSwapSubmissionIndices(const int lhs_idx, const int rhs_idx) { - assert(lhs_idx != 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); @@ -495,7 +499,7 @@ void DrawListSortChannelsByDepth(const ImVector& node_idx_depth_order) return; } - assert(node_idx_depth_order.Size == GImNodes->NodeIdxSubmissionOrder.Size); + IM_ASSERT(node_idx_depth_order.Size == GImNodes->NodeIdxSubmissionOrder.Size); int start_idx = node_idx_depth_order.Size - 1; @@ -525,7 +529,7 @@ void DrawListSortChannelsByDepth(const ImVector& node_idx_depth_order) break; } } - assert(submission_idx >= 0); + IM_ASSERT(submission_idx >= 0); if (submission_idx == depth_idx) { @@ -547,7 +551,7 @@ ImVec2 GetScreenSpacePinCoordinates( const ImRect& attribute_rect, const ImNodesAttributeType type) { - assert(type == ImNodesAttributeType_Input || type == ImNodesAttributeType_Output); + 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); @@ -583,21 +587,50 @@ void BeginNodeSelection(ImNodesEditorContext& editor, const int node_idx) // 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.SelectedNodeIndices.clear(); 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& depth_stack = editor.NodeDepthOrder; const int* const elem = depth_stack.find(node_idx); - assert(elem != depth_stack.end()); + 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) @@ -773,18 +806,44 @@ void BoxSelectorUpdateSelection(ImNodesEditorContext& editor, ImRect box_rect) } } +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) { - const ImGuiIO& io = ImGui::GetIO(); + // 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 int node_idx = editor.SelectedNodeIndices[i]; - ImNodeData& node = editor.Nodes.Pool[node_idx]; - if (node.Draggable) + 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 += io.MouseDelta - editor.AutoPanningDelta; + node.Origin = origin + node_rel + editor.AutoPanningDelta; } } } @@ -1058,7 +1117,7 @@ void ClickInteractionUpdate(ImNodesEditorContext& editor) case ImNodesClickInteractionType_None: break; default: - assert(!"Unreachable code!"); + IM_ASSERT(!"Unreachable code!"); break; } } @@ -1166,7 +1225,7 @@ ImOptionalIndex ResolveHoveredNode(const ImVector& depth_stack) } } - assert(node_idx_on_top != -1); + IM_ASSERT(node_idx_on_top != -1); return ImOptionalIndex(node_idx_on_top); } @@ -1270,6 +1329,9 @@ inline ImRect GetNodeTitleRect(const ImNodeData& node) 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) @@ -1277,7 +1339,7 @@ void DrawGrid(ImNodesEditorContext& editor, const ImVec2& canvas_size) GImNodes->CanvasDrawList->AddLine( EditorSpaceToScreenSpace(ImVec2(x, 0.0f)), EditorSpaceToScreenSpace(ImVec2(x, canvas_size.y)), - GImNodes->Style.Colors[ImNodesCol_GridLine]); + 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; @@ -1286,7 +1348,7 @@ void DrawGrid(ImNodesEditorContext& editor, const ImVec2& canvas_size) GImNodes->CanvasDrawList->AddLine( EditorSpaceToScreenSpace(ImVec2(0.0f, y)), EditorSpaceToScreenSpace(ImVec2(canvas_size.x, y)), - GImNodes->Style.Colors[ImNodesCol_GridLine]); + offset.y - y == 0.f && draw_primary ? line_color_prim : line_color); } } @@ -1411,7 +1473,7 @@ void DrawPinShape(const ImVec2& pin_pos, const ImPinData& pin, const ImU32 pin_c } break; default: - assert(!"Invalid PinShape value!"); + IM_ASSERT(!"Invalid PinShape value!"); break; } } @@ -1577,7 +1639,7 @@ void BeginPinAttribute( { // Make sure to call BeginNode() before calling // BeginAttribute() - assert(GImNodes->CurrentScope == ImNodesScope_Node); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node); GImNodes->CurrentScope = ImNodesScope_Attribute; ImGui::BeginGroup(); @@ -1601,7 +1663,7 @@ void BeginPinAttribute( void EndPinAttribute() { - assert(GImNodes->CurrentScope == ImNodesScope_Attribute); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Attribute); GImNodes->CurrentScope = ImNodesScope_Node; ImGui::PopID(); @@ -1630,12 +1692,12 @@ void Initialize(ImNodesContext* context) context->CurrentNodeIdx = INT_MAX; context->DefaultEditorCtx = EditorContextCreate(); - EditorContextSet(GImNodes->DefaultEditorCtx); + context->EditorCtx = context->DefaultEditorCtx; context->CurrentAttributeFlags = ImNodesAttributeFlags_None; context->AttributeFlagStack.push_back(GImNodes->CurrentAttributeFlags); - StyleColorsDark(); + StyleColorsDark(&context->Style); } void Shutdown(ImNodesContext* ctx) { EditorContextFree(ctx->DefaultEditorCtx); } @@ -1888,8 +1950,8 @@ template void SelectObject(const ImObjectPool& objects, ImVector& selected_indices, const int id) { const int idx = ObjectPoolFind(objects, id); - assert(idx >= 0); - assert(selected_indices.find(idx) == selected_indices.end()); + IM_ASSERT(idx >= 0); + IM_ASSERT(selected_indices.find(idx) == selected_indices.end()); selected_indices.push_back(idx); } @@ -1900,8 +1962,8 @@ void ClearObjectSelection( const int id) { const int idx = ObjectPoolFind(objects, id); - assert(idx >= 0); - assert(selected_indices.find(idx) != selected_indices.end()); + IM_ASSERT(idx >= 0); + IM_ASSERT(selected_indices.find(idx) != selected_indices.end()); selected_indices.find_erase_unsorted(idx); } @@ -1921,6 +1983,8 @@ 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) @@ -1928,7 +1992,7 @@ ImNodesIO::ImNodesIO() } ImNodesStyle::ImNodesStyle() - : GridSpacing(32.f), NodeCornerRounding(4.f), NodePadding(8.f, 8.f), NodeBorderThickness(1.f), + : 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), @@ -2004,132 +2068,147 @@ ImNodesIO& GetIO() { return GImNodes->Io; } ImNodesStyle& GetStyle() { return GImNodes->Style; } -void StyleColorsDark() +void StyleColorsDark(ImNodesStyle* dest) { - GImNodes->Style.Colors[ImNodesCol_NodeBackground] = IM_COL32(50, 50, 50, 255); - GImNodes->Style.Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(75, 75, 75, 255); - GImNodes->Style.Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(75, 75, 75, 255); - GImNodes->Style.Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255); + 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 - GImNodes->Style.Colors[ImNodesCol_TitleBar] = IM_COL32(41, 74, 122, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBarHovered] = IM_COL32(66, 150, 250, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBarSelected] = IM_COL32(66, 150, 250, 255); + 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 - GImNodes->Style.Colors[ImNodesCol_Link] = IM_COL32(61, 133, 224, 200); - GImNodes->Style.Colors[ImNodesCol_LinkHovered] = IM_COL32(66, 150, 250, 255); - GImNodes->Style.Colors[ImNodesCol_LinkSelected] = IM_COL32(66, 150, 250, 255); + 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 - GImNodes->Style.Colors[ImNodesCol_Pin] = IM_COL32(53, 150, 250, 180); - GImNodes->Style.Colors[ImNodesCol_PinHovered] = IM_COL32(53, 150, 250, 255); + dest->Colors[ImNodesCol_Pin] = IM_COL32(53, 150, 250, 180); + dest->Colors[ImNodesCol_PinHovered] = IM_COL32(53, 150, 250, 255); - GImNodes->Style.Colors[ImNodesCol_BoxSelector] = IM_COL32(61, 133, 224, 30); - GImNodes->Style.Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(61, 133, 224, 150); + dest->Colors[ImNodesCol_BoxSelector] = IM_COL32(61, 133, 224, 30); + dest->Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(61, 133, 224, 150); - GImNodes->Style.Colors[ImNodesCol_GridBackground] = IM_COL32(40, 40, 50, 200); - GImNodes->Style.Colors[ImNodesCol_GridLine] = IM_COL32(200, 200, 200, 40); + 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 - GImNodes->Style.Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 150); - GImNodes->Style.Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200); - GImNodes->Style.Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundHovered] = IM_COL32(200, 200, 200, 255); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundHovered]; - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapLink] = GImNodes->Style.Colors[ImNodesCol_Link]; - GImNodes->Style.Colors[ImNodesCol_MiniMapLinkSelected] = - GImNodes->Style.Colors[ImNodesCol_LinkSelected]; - GImNodes->Style.Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25); - GImNodes->Style.Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200); -} - -void StyleColorsClassic() -{ - GImNodes->Style.Colors[ImNodesCol_NodeBackground] = IM_COL32(50, 50, 50, 255); - GImNodes->Style.Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(75, 75, 75, 255); - GImNodes->Style.Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(75, 75, 75, 255); - GImNodes->Style.Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBar] = IM_COL32(69, 69, 138, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBarHovered] = IM_COL32(82, 82, 161, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBarSelected] = IM_COL32(82, 82, 161, 255); - GImNodes->Style.Colors[ImNodesCol_Link] = IM_COL32(255, 255, 255, 100); - GImNodes->Style.Colors[ImNodesCol_LinkHovered] = IM_COL32(105, 99, 204, 153); - GImNodes->Style.Colors[ImNodesCol_LinkSelected] = IM_COL32(105, 99, 204, 153); - GImNodes->Style.Colors[ImNodesCol_Pin] = IM_COL32(89, 102, 156, 170); - GImNodes->Style.Colors[ImNodesCol_PinHovered] = IM_COL32(102, 122, 179, 200); - GImNodes->Style.Colors[ImNodesCol_BoxSelector] = IM_COL32(82, 82, 161, 100); - GImNodes->Style.Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(82, 82, 161, 255); - GImNodes->Style.Colors[ImNodesCol_GridBackground] = IM_COL32(40, 40, 50, 200); - GImNodes->Style.Colors[ImNodesCol_GridLine] = IM_COL32(200, 200, 200, 40); + 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 - GImNodes->Style.Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200); - GImNodes->Style.Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundHovered]; - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = IM_COL32(200, 200, 240, 255); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapLink] = GImNodes->Style.Colors[ImNodesCol_Link]; - GImNodes->Style.Colors[ImNodesCol_MiniMapLinkSelected] = - GImNodes->Style.Colors[ImNodesCol_LinkSelected]; - GImNodes->Style.Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25); - GImNodes->Style.Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200); -} - -void StyleColorsLight() -{ - GImNodes->Style.Colors[ImNodesCol_NodeBackground] = IM_COL32(240, 240, 240, 255); - GImNodes->Style.Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(240, 240, 240, 255); - GImNodes->Style.Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(240, 240, 240, 255); - GImNodes->Style.Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBar] = IM_COL32(248, 248, 248, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBarHovered] = IM_COL32(209, 209, 209, 255); - GImNodes->Style.Colors[ImNodesCol_TitleBarSelected] = IM_COL32(209, 209, 209, 255); + 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 - GImNodes->Style.Colors[ImNodesCol_Link] = IM_COL32(66, 150, 250, 100); + dest->Colors[ImNodesCol_Link] = IM_COL32(66, 150, 250, 100); // original imgui values: 117, 138, 204 - GImNodes->Style.Colors[ImNodesCol_LinkHovered] = IM_COL32(66, 150, 250, 242); - GImNodes->Style.Colors[ImNodesCol_LinkSelected] = IM_COL32(66, 150, 250, 242); + 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 - GImNodes->Style.Colors[ImNodesCol_Pin] = IM_COL32(66, 150, 250, 160); - GImNodes->Style.Colors[ImNodesCol_PinHovered] = IM_COL32(66, 150, 250, 255); - GImNodes->Style.Colors[ImNodesCol_BoxSelector] = IM_COL32(90, 170, 250, 30); - GImNodes->Style.Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(90, 170, 250, 150); - GImNodes->Style.Colors[ImNodesCol_GridBackground] = IM_COL32(225, 225, 225, 255); - GImNodes->Style.Colors[ImNodesCol_GridLine] = IM_COL32(180, 180, 180, 100); + 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 - GImNodes->Style.Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200); - GImNodes->Style.Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundHovered]; - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = IM_COL32(200, 200, 240, 255); - GImNodes->Style.Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100); - GImNodes->Style.Colors[ImNodesCol_MiniMapLink] = GImNodes->Style.Colors[ImNodesCol_Link]; - GImNodes->Style.Colors[ImNodesCol_MiniMapLinkSelected] = - GImNodes->Style.Colors[ImNodesCol_LinkSelected]; - GImNodes->Style.Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25); - GImNodes->Style.Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200); + 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 BeginNodeEditor() { - assert(GImNodes->CurrentScope == ImNodesScope_None); + 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_MIN, FLT_MIN); + editor.GridContentBounds = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); editor.MiniMapEnabled = false; ObjectPoolReset(editor.Nodes); ObjectPoolReset(editor.Pins); @@ -2148,16 +2227,20 @@ void BeginNodeEditor() 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->LeftMouseDragging = ImGui::IsMouseDragging(0, 0.0f); 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; @@ -2194,7 +2277,7 @@ void BeginNodeEditor() void EndNodeEditor() { - assert(GImNodes->CurrentScope == ImNodesScope_Editor); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor); GImNodes->CurrentScope = ImNodesScope_None; ImNodesEditorContext& editor = EditorContextGet(); @@ -2349,10 +2432,10 @@ void MiniMap( const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data) { // Check that editor size fraction is sane; must be in the range (0, 1] - assert(minimap_size_fraction > 0.f && minimap_size_fraction <= 1.f); + IM_ASSERT(minimap_size_fraction > 0.f && minimap_size_fraction <= 1.f); // Remember to call before EndNodeEditor - assert(GImNodes->CurrentScope == ImNodesScope_Editor); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor); ImNodesEditorContext& editor = EditorContextGet(); @@ -2373,7 +2456,7 @@ void MiniMap( void BeginNode(const int node_id) { // Remember to call BeginNodeEditor before calling BeginNode - assert(GImNodes->CurrentScope == ImNodesScope_Editor); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor); GImNodes->CurrentScope = ImNodesScope_Node; ImNodesEditorContext& editor = EditorContextGet(); @@ -2407,7 +2490,7 @@ void BeginNode(const int node_id) void EndNode() { - assert(GImNodes->CurrentScope == ImNodesScope_Node); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node); GImNodes->CurrentScope = ImNodesScope_Editor; ImNodesEditorContext& editor = EditorContextGet(); @@ -2433,20 +2516,20 @@ ImVec2 GetNodeDimensions(int node_id) { ImNodesEditorContext& editor = EditorContextGet(); const int node_idx = ObjectPoolFind(editor.Nodes, node_id); - assert(node_idx != -1); // invalid node_id + IM_ASSERT(node_idx != -1); // invalid node_id const ImNodeData& node = editor.Nodes.Pool[node_idx]; return node.Rect.GetSize(); } void BeginNodeTitleBar() { - assert(GImNodes->CurrentScope == ImNodesScope_Node); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node); ImGui::BeginGroup(); } void EndNodeTitleBar() { - assert(GImNodes->CurrentScope == ImNodesScope_Node); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node); ImGui::EndGroup(); ImNodesEditorContext& editor = EditorContextGet(); @@ -2475,7 +2558,7 @@ void EndOutputAttribute() { EndPinAttribute(); } void BeginStaticAttribute(const int id) { // Make sure to call BeginNode() before calling BeginAttribute() - assert(GImNodes->CurrentScope == ImNodesScope_Node); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node); GImNodes->CurrentScope = ImNodesScope_Attribute; GImNodes->CurrentAttributeId = id; @@ -2487,7 +2570,7 @@ void BeginStaticAttribute(const int id) void EndStaticAttribute() { // Make sure to call BeginNode() before calling BeginAttribute() - assert(GImNodes->CurrentScope == ImNodesScope_Attribute); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Attribute); GImNodes->CurrentScope = ImNodesScope_Node; ImGui::PopID(); @@ -2510,7 +2593,7 @@ void PopAttributeFlag() { // PopAttributeFlag called without a matching PushAttributeFlag! // The bottom value is always the default value, pushed in Initialize(). - assert(GImNodes->AttributeFlagStack.size() > 1); + IM_ASSERT(GImNodes->AttributeFlagStack.size() > 1); GImNodes->AttributeFlagStack.pop_back(); GImNodes->CurrentAttributeFlags = GImNodes->AttributeFlagStack.back(); @@ -2518,7 +2601,7 @@ void PopAttributeFlag() void Link(const int id, const int start_attr_id, const int end_attr_id) { - assert(GImNodes->CurrentScope == ImNodesScope_Editor); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor); ImNodesEditorContext& editor = EditorContextGet(); ImLinkData& link = ObjectPoolFindOrCreateObject(editor.Links, id); @@ -2549,7 +2632,7 @@ void PushColorStyle(const ImNodesCol item, unsigned int color) void PopColorStyle() { - assert(GImNodes->ColorModifierStack.size() > 0); + IM_ASSERT(GImNodes->ColorModifierStack.size() > 0); const ImNodesColElement elem = GImNodes->ColorModifierStack.back(); GImNodes->Style.Colors[elem.Item] = elem.Color; GImNodes->ColorModifierStack.pop_back(); @@ -2565,35 +2648,35 @@ struct ImNodesStyleVarInfo static const ImNodesStyleVarInfo GStyleVarInfo[] = { // ImNodesStyleVar_GridSpacing - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, GridSpacing)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, GridSpacing)}, // ImNodesStyleVar_NodeCornerRounding - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, NodeCornerRounding)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, NodeCornerRounding)}, // ImNodesStyleVar_NodePadding - {ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImNodesStyle, NodePadding)}, + {ImGuiDataType_Float, 2, (ImU32)offsetof(ImNodesStyle, NodePadding)}, // ImNodesStyleVar_NodeBorderThickness - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, NodeBorderThickness)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, NodeBorderThickness)}, // ImNodesStyleVar_LinkThickness - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, LinkThickness)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, LinkThickness)}, // ImNodesStyleVar_LinkLineSegmentsPerLength - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, LinkLineSegmentsPerLength)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, LinkLineSegmentsPerLength)}, // ImNodesStyleVar_LinkHoverDistance - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, LinkHoverDistance)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, LinkHoverDistance)}, // ImNodesStyleVar_PinCircleRadius - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinCircleRadius)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinCircleRadius)}, // ImNodesStyleVar_PinQuadSideLength - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinQuadSideLength)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinQuadSideLength)}, // ImNodesStyleVar_PinTriangleSideLength - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinTriangleSideLength)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinTriangleSideLength)}, // ImNodesStyleVar_PinLineThickness - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinLineThickness)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinLineThickness)}, // ImNodesStyleVar_PinHoverRadius - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinHoverRadius)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinHoverRadius)}, // ImNodesStyleVar_PinOffset - {ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinOffset)}, + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImNodesStyle, PinOffset)}, // ImNodesStyleVar_MiniMapPadding - {ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImNodesStyle, MiniMapPadding)}, + {ImGuiDataType_Float, 2, (ImU32)offsetof(ImNodesStyle, MiniMapPadding)}, // ImNodesStyleVar_MiniMapOffset - {ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImNodesStyle, MiniMapOffset)}, + {ImGuiDataType_Float, 2, (ImU32)offsetof(ImNodesStyle, MiniMapOffset)}, }; static const ImNodesStyleVarInfo* GetStyleVarInfo(ImNodesStyleVar idx) @@ -2633,7 +2716,7 @@ void PopStyleVar(int count) { while (count > 0) { - assert(GImNodes->StyleModifierStack.size() > 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); @@ -2683,7 +2766,7 @@ ImVec2 GetNodeScreenSpacePos(const int node_id) { ImNodesEditorContext& editor = EditorContextGet(); const int node_idx = ObjectPoolFind(editor.Nodes, node_id); - assert(node_idx != -1); + IM_ASSERT(node_idx != -1); ImNodeData& node = editor.Nodes.Pool[node_idx]; return GridSpaceToScreenSpace(editor, node.Origin); } @@ -2692,7 +2775,7 @@ ImVec2 GetNodeEditorSpacePos(const int node_id) { ImNodesEditorContext& editor = EditorContextGet(); const int node_idx = ObjectPoolFind(editor.Nodes, node_id); - assert(node_idx != -1); + IM_ASSERT(node_idx != -1); ImNodeData& node = editor.Nodes.Pool[node_idx]; return GridSpaceToEditorSpace(editor, node.Origin); } @@ -2701,17 +2784,24 @@ ImVec2 GetNodeGridSpacePos(const int node_id) { ImNodesEditorContext& editor = EditorContextGet(); const int node_idx = ObjectPoolFind(editor.Nodes, node_id); - assert(node_idx != -1); + 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) { - assert(GImNodes->CurrentScope == ImNodesScope_None); - assert(node_id != NULL); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(node_id != NULL); const bool is_hovered = GImNodes->HoveredNodeIdx.HasValue(); if (is_hovered) @@ -2724,8 +2814,8 @@ bool IsNodeHovered(int* const node_id) bool IsLinkHovered(int* const link_id) { - assert(GImNodes->CurrentScope == ImNodesScope_None); - assert(link_id != NULL); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(link_id != NULL); const bool is_hovered = GImNodes->HoveredLinkIdx.HasValue(); if (is_hovered) @@ -2738,8 +2828,8 @@ bool IsLinkHovered(int* const link_id) bool IsPinHovered(int* const attr) { - assert(GImNodes->CurrentScope == ImNodesScope_None); - assert(attr != NULL); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(attr != NULL); const bool is_hovered = GImNodes->HoveredPinIdx.HasValue(); if (is_hovered) @@ -2752,21 +2842,21 @@ bool IsPinHovered(int* const attr) int NumSelectedNodes() { - assert(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); const ImNodesEditorContext& editor = EditorContextGet(); return editor.SelectedNodeIndices.size(); } int NumSelectedLinks() { - assert(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); const ImNodesEditorContext& editor = EditorContextGet(); return editor.SelectedLinkIndices.size(); } void GetSelectedNodes(int* node_ids) { - assert(node_ids != NULL); + IM_ASSERT(node_ids != NULL); const ImNodesEditorContext& editor = EditorContextGet(); for (int i = 0; i < editor.SelectedNodeIndices.size(); ++i) @@ -2778,7 +2868,7 @@ void GetSelectedNodes(int* node_ids) void GetSelectedLinks(int* link_ids) { - assert(link_ids != NULL); + IM_ASSERT(link_ids != NULL); const ImNodesEditorContext& editor = EditorContextGet(); for (int i = 0; i < editor.SelectedLinkIndices.size(); ++i) @@ -2838,7 +2928,7 @@ bool IsLinkSelected(int link_id) bool IsAttributeActive() { - assert((GImNodes->CurrentScope & ImNodesScope_Node) != 0); + IM_ASSERT((GImNodes->CurrentScope & ImNodesScope_Node) != 0); if (!GImNodes->ActiveAttribute) { @@ -2850,7 +2940,7 @@ bool IsAttributeActive() bool IsAnyAttributeActive(int* const attribute_id) { - assert((GImNodes->CurrentScope & (ImNodesScope_Node | ImNodesScope_Attribute)) == 0); + IM_ASSERT((GImNodes->CurrentScope & (ImNodesScope_Node | ImNodesScope_Attribute)) == 0); if (!GImNodes->ActiveAttribute) { @@ -2868,8 +2958,8 @@ bool IsAnyAttributeActive(int* const attribute_id) bool IsLinkStarted(int* const started_at_id) { // Call this function after EndNodeEditor()! - assert(GImNodes->CurrentScope == ImNodesScope_None); - assert(started_at_id != NULL); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(started_at_id != NULL); const bool is_started = (GImNodes->ImNodesUIState & ImNodesUIState_LinkStarted) != 0; if (is_started) @@ -2885,7 +2975,7 @@ bool IsLinkStarted(int* const started_at_id) bool IsLinkDropped(int* const started_at_id, const bool including_detached_links) { // Call this function after EndNodeEditor()! - assert(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); const ImNodesEditorContext& editor = EditorContextGet(); @@ -2908,9 +2998,9 @@ bool IsLinkCreated( int* const ended_at_pin_id, bool* const created_from_snap) { - assert(GImNodes->CurrentScope == ImNodesScope_None); - assert(started_at_pin_id != NULL); - assert(ended_at_pin_id != NULL); + 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; @@ -2950,11 +3040,11 @@ bool IsLinkCreated( int* ended_at_pin_id, bool* created_from_snap) { - assert(GImNodes->CurrentScope == ImNodesScope_None); - assert(started_at_node_id != NULL); - assert(started_at_pin_id != NULL); - assert(ended_at_node_id != NULL); - assert(ended_at_pin_id != NULL); + 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; @@ -2995,7 +3085,7 @@ bool IsLinkCreated( bool IsLinkDestroyed(int* const link_id) { - assert(GImNodes->CurrentScope == ImNodesScope_None); + IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None); const bool link_destroyed = GImNodes->DeletedLinkIdx.HasValue(); if (link_destroyed) @@ -3024,7 +3114,7 @@ void NodeLineHandler(ImNodesEditorContext& editor, const char* const line) else if (sscanf(line, "origin=%i,%i", &x, &y) == 2) { ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx]; - node.Origin = ImVec2((float)x, (float)y); + node.Origin = SnapOriginToGrid(ImVec2((float)x, (float)y)); } } @@ -3043,7 +3133,7 @@ const char* SaveEditorStateToIniString( const ImNodesEditorContext* const editor_ptr, size_t* const data_size) { - assert(editor_ptr != NULL); + IM_ASSERT(editor_ptr != NULL); const ImNodesEditorContext& editor = *editor_ptr; GImNodes->TextBuffer.clear(); @@ -3172,4 +3262,4 @@ void LoadEditorStateFromIniFile(ImNodesEditorContext* const editor, const char* LoadEditorStateFromIniString(editor, file_data, data_size); ImGui::MemFree(file_data); } -} // namespace IMNODES_NAMESPACE +} // namespace IMNODES_NAMESPACE \ No newline at end of file diff --git a/3rdparty/imnodes/imnodes.h b/3rdparty/imnodes/imnodes.h index b4fe93a..9f5920c 100644 --- a/3rdparty/imnodes/imnodes.h +++ b/3rdparty/imnodes/imnodes.h @@ -36,6 +36,7 @@ enum ImNodesCol_ ImNodesCol_BoxSelectorOutline, ImNodesCol_GridBackground, ImNodesCol_GridLine, + ImNodesCol_GridLinePrimary, ImNodesCol_MiniMapBackground, ImNodesCol_MiniMapBackgroundHovered, ImNodesCol_MiniMapOutline, @@ -75,7 +76,9 @@ enum ImNodesStyleFlags_ { ImNodesStyleFlags_None = 0, ImNodesStyleFlags_NodeOutline = 1 << 0, - ImNodesStyleFlags_GridLines = 1 << 2 + ImNodesStyleFlags_GridLines = 1 << 2, + ImNodesStyleFlags_GridLinesPrimary = 1 << 3, + ImNodesStyleFlags_GridSnapping = 1 << 4 }; enum ImNodesPinShape_ @@ -134,6 +137,21 @@ struct ImNodesIO 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; @@ -241,10 +259,11 @@ 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. -void StyleColorsDark(); // on by default -void StyleColorsClassic(); -void StyleColorsLight(); +// 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); // The top-level function call. Call this before calling BeginNode/EndNode. Calling this function // will result the node editor grid workspace being rendered. @@ -328,6 +347,9 @@ 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(); @@ -413,4 +435,4 @@ void SaveEditorStateToIniFile(const ImNodesEditorContext* editor, const char* fi void LoadCurrentEditorStateFromIniFile(const char* file_name); void LoadEditorStateFromIniFile(ImNodesEditorContext* editor, const char* file_name); -} // namespace IMNODES_NAMESPACE +} // namespace IMNODES_NAMESPACE \ No newline at end of file diff --git a/3rdparty/imnodes/imnodes_internal.h b/3rdparty/imnodes/imnodes_internal.h index d77c953..d2d7041 100644 --- a/3rdparty/imnodes/imnodes_internal.h +++ b/3rdparty/imnodes/imnodes_internal.h @@ -1,12 +1,11 @@ #pragma once -#include "imnodes.h" - -#include #define IMGUI_DEFINE_MATH_OPERATORS +#include #include -#include +#include "imnodes.h" + #include // the structure of this file: @@ -101,7 +100,7 @@ struct ImOptionalIndex inline int Value() const { - assert(HasValue()); + IM_ASSERT(HasValue()); return _Index; } @@ -153,7 +152,7 @@ struct ImNodeData bool Draggable; ImNodeData(const int node_id) - : Id(node_id), Origin(100.0f, 100.0f), TitleBarContentRect(), + : 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) { @@ -262,6 +261,11 @@ struct ImNodesEditorContext ImVector SelectedNodeIndices; ImVector SelectedLinkIndices; + // Relative origins of selected nodes for snapping of dragged nodes + ImVector SelectedNodeOffsets; + // Offset of the primary node origin relative to the mouse cursor. + ImVec2 PrimaryNodeOffset; + ImClickInteractionState ClickInteraction; // Mini-map state set by MiniMap() @@ -280,9 +284,9 @@ struct ImNodesEditorContext ImNodesEditorContext() : Nodes(), Pins(), Links(), Panning(0.f, 0.f), SelectedNodeIndices(), SelectedLinkIndices(), - ClickInteraction(), MiniMapEnabled(false), MiniMapSizeFraction(0.0f), - MiniMapNodeHoveringCallback(NULL), MiniMapNodeHoveringCallbackUserData(NULL), - MiniMapScaling(0.0f) + SelectedNodeOffsets(), PrimaryNodeOffset(0.f, 0.f), ClickInteraction(), + MiniMapEnabled(false), MiniMapSizeFraction(0.0f), MiniMapNodeHoveringCallback(NULL), + MiniMapNodeHoveringCallbackUserData(NULL), MiniMapScaling(0.0f) { } }; @@ -346,6 +350,7 @@ struct ImNodesContext bool LeftMouseDragging; bool AltMouseDragging; float AltMouseScrollDelta; + bool MultipleSelectModifier; }; namespace IMNODES_NAMESPACE @@ -353,7 +358,7 @@ namespace IMNODES_NAMESPACE static inline ImNodesEditorContext& EditorContextGet() { // No editor context was set! Did you forget to call ImNodes::CreateContext()? - assert(GImNodes->EditorCtx != NULL); + IM_ASSERT(GImNodes->EditorCtx != NULL); return *GImNodes->EditorCtx; } @@ -401,7 +406,7 @@ inline void ObjectPoolUpdate(ImObjectPool& nodes) // unused ImVector& depth_stack = EditorContextGet().NodeDepthOrder; const int* const elem = depth_stack.find(i); - assert(elem != depth_stack.end()); + IM_ASSERT(elem != depth_stack.end()); depth_stack.erase(elem); nodes.IdMap.SetInt(id, -1); @@ -492,4 +497,4 @@ static inline T& ObjectPoolFindOrCreateObject(ImObjectPool& objects, const in const int index = ObjectPoolFindOrCreateIndex(objects, id); return objects.Pool[index]; } -} // namespace IMNODES_NAMESPACE +} // namespace IMNODES_NAMESPACE \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0774eff..46822ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,14 @@ cmake_minimum_required(VERSION 3.11.0) project(implot_demos VERSION 0.1.0) +# Workaround for the cmake generation stage: +# https://github.com/libsdl-org/SDL/issues/6454 + +enable_language(OBJC) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + ############################################################################### # 3RD PARTY LIBS ############################################################################### @@ -82,7 +90,10 @@ add_library(imgui ${IMGUI_HEADERS} ${IMGUI_SRC}) if(MSVC) target_compile_options(imgui PRIVATE /W4 /WX /arch:AVX2 /fp:fast) endif() -target_link_libraries(imgui PUBLIC glfw glad OpenGL::GL imm32) +target_link_libraries(imgui PUBLIC glfw glad OpenGL::GL) +if(MSVC) + target_link_libraries(imgui PUBLIC imm32) +endif() target_compile_definitions(imgui PRIVATE IMGUI_DLL_EXPORT) include_directories(../imgui/ ../imgui/examples ../imgui/examples/libs/gl3w ../imgui/backends ../imgui/misc/cpp) @@ -110,10 +121,13 @@ target_compile_definitions(implot PUBLIC IMPLOT_DEBUG IMPLOT_DLL_EXPORT IMPLOT_B set_property(TARGET implot PROPERTY CXX_STANDARD 11) if(MSVC) target_compile_options(implot PRIVATE /W4 /WX /arch:AVX2 /fp:fast /permissive-) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_compile_options(implot PRIVATE -Wall -Wextra -pedantic -Werror -O3) else() target_compile_options(implot PRIVATE -Wall -Wextra -pedantic -Werror -mavx2 -Ofast) endif() + include_directories(../implot/) ############################################################################### @@ -158,13 +172,13 @@ add_executable(perlin "demos/perlin.cpp") target_link_libraries(perlin app) target_include_directories(perlin PRIVATE "3rdparty") -# mandel demo -add_executable(mandel "demos/mandel.cpp") -target_link_libraries(mandel app) -target_include_directories(mandel PRIVATE "3rdparty") -if (MSVC) - target_compile_options(mandel PRIVATE /arch:AVX2 /fp:fast /openmp) -endif() +# # mandel demo +# add_executable(mandel "demos/mandel.cpp") +# target_link_libraries(mandel app) +# target_include_directories(mandel PRIVATE "3rdparty") +# if (MSVC) +# target_compile_options(mandel PRIVATE /arch:AVX2 /fp:fast /openmp) +# endif() # graph demo add_executable(graph "demos/graph.cpp") diff --git a/README.md b/README.md index 9d33f95..fdfc435 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,8 @@ git clone https://github.com/ocornut/imgui 2. Build with CMake, e.g.: ```shell cd implot_demos -mkdir build -cd build -cmake .. -cmake --build . --config Release +cmake -G"Unix Makefiles" -B build -S . +cmake --build build --config Release --parallel 8 ``` ## Demos diff --git a/common/App.cpp b/common/App.cpp index 3f18023..3764707 100644 --- a/common/App.cpp +++ b/common/App.cpp @@ -149,8 +149,10 @@ App::App(std::string title, int w, int h, int argc, char const *argv[]) const bool no_vsync = result["vsync"].as(); const bool use_msaa = result["msaa"].as(); const bool im_style = result["imgui"].as(); +#if defined(_WIN32) NvOptimusEnablement = AmdPowerXpressRequestHighPerformance = result["gpu"].as(); UsingDGPU = result["gpu"].as(); +#endif #ifdef _DEBUG title += " - OpenGL - Debug"; diff --git a/demos/filter.cpp b/demos/filter.cpp index c5628de..06adeeb 100644 --- a/demos/filter.cpp +++ b/demos/filter.cpp @@ -70,7 +70,7 @@ struct ImFilter : public App { ImGui::SetNextWindowPos(ImVec2(0,0), ImGuiCond_Always); ImGui::SetNextWindowSize(GetWindowSize(), ImGuiCond_Always); ImGui::Begin("Filter",nullptr, ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoTitleBar); - ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, -1)); + ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowWidth() * 0.5f, -1)); ImGui::Text("Input: x(t) = A1*sin(2*pi*F1*t) + A2*sin(2*pi*F1*t) + noise"); ImGui::Separator(); diff --git a/demos/maps.cpp b/demos/maps.cpp index 89840b5..37de7ae 100644 --- a/demos/maps.cpp +++ b/demos/maps.cpp @@ -319,7 +319,7 @@ struct ImMaps : public App { void Update() override { static int renders = 0; static bool debug = false; - if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_A))) + if (ImGui::IsKeyPressed(ImGuiKey_A)) debug = !debug; ImGui::SetNextWindowPos({0,0}); @@ -355,7 +355,7 @@ struct ImMaps : public App { auto [bmin,bmax] = coord.bounds(); if (tile != nullptr) { auto col = debug ? ((coord.x % 2 == 0 && coord.y % 2 != 0) || (coord.x % 2 != 0 && coord.y % 2 == 0))? ImVec4(1,0,1,1) : ImVec4(1,1,0,1) : ImVec4(1,1,1,1); - ImPlot::PlotImage("##Tiles",(void*)(intptr_t)tile->image.ID,bmin,bmax,{0,0},{1,1},col); + ImPlot::PlotImage("##Tiles",tile->image.ID,bmin,bmax,{0,0},{1,1},col); } if (debug) ImPlot::PlotText(coord.label().c_str(),(bmin.x+bmax.x)/2,(bmin.y+bmax.y)/2);