From a7fa1582880001b43e2db931261f546deeff5750 Mon Sep 17 00:00:00 2001 From: Julius Trinkunas Date: Mon, 30 Aug 2021 17:43:44 +0300 Subject: [PATCH 1/2] Add auto-panning when mouse goes outside the editor while dragging stuff --- imnodes.cpp | 81 +++++++++++++++++++++++++++++----------------- imnodes.h | 3 ++ imnodes_internal.h | 3 +- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/imnodes.cpp b/imnodes.cpp index 9692de0..9e5c7c7 100644 --- a/imnodes.cpp +++ b/imnodes.cpp @@ -252,6 +252,33 @@ inline bool RectangleOverlapsLink( return false; } +// [SECTION] coordinate space conversion helpers + +inline ImVec2 ScreenSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v) +{ + return v - GImNodes->CanvasOriginScreenSpace - editor.Panning; +} + +inline ImVec2 GridSpaceToScreenSpace(const ImNodesEditorContext& editor, const ImVec2& v) +{ + return v + GImNodes->CanvasOriginScreenSpace + editor.Panning; +} + +inline ImVec2 GridSpaceToEditorSpace(const ImNodesEditorContext& editor, const ImVec2& v) +{ + return v + editor.Panning; +} + +inline ImVec2 EditorSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v) +{ + return v - editor.Panning; +} + +inline ImVec2 EditorSpaceToScreenSpace(const ImVec2& v) +{ + return GImNodes->CanvasOriginScreenSpace + v; +} + // [SECTION] draw list helper void ImDrawListGrowChannels(ImDrawList* draw_list, const int num_channels) @@ -664,7 +691,7 @@ void BeginCanvasInteraction(ImNodesEditorContext& editor) else if (GImNodes->LeftMouseClicked) { editor.ClickInteraction.Type = ImNodesClickInteractionType_BoxSelection; - editor.ClickInteraction.BoxSelector.Rect.Min = GImNodes->MousePos; + editor.ClickInteraction.BoxSelector.Rect.Min = ScreenSpaceToGridSpace(editor, GImNodes->MousePos); } } } @@ -743,7 +770,7 @@ void TranslateSelectedNodes(ImNodesEditorContext& editor) ImNodeData& node = editor.Nodes.Pool[node_idx]; if (node.Draggable) { - node.Origin += io.MouseDelta; + node.Origin += io.MouseDelta - editor.AutoPanningDelta; } } } @@ -835,8 +862,11 @@ void ClickInteractionUpdate(ImNodesEditorContext& editor) { case ImNodesClickInteractionType_BoxSelection: { - ImRect& box_rect = editor.ClickInteraction.BoxSelector.Rect; - box_rect.Max = GImNodes->MousePos; + editor.ClickInteraction.BoxSelector.Rect.Max = ScreenSpaceToGridSpace(editor, GImNodes->MousePos); + + ImRect box_rect = editor.ClickInteraction.BoxSelector.Rect; + box_rect.Min = GridSpaceToScreenSpace(editor, box_rect.Min); + box_rect.Max = GridSpaceToScreenSpace(editor, box_rect.Max); BoxSelectorUpdateSelection(editor, box_rect); @@ -1225,31 +1255,6 @@ ImOptionalIndex ResolveHoveredLink( // [SECTION] render helpers -inline ImVec2 ScreenSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v) -{ - return v - GImNodes->CanvasOriginScreenSpace - editor.Panning; -} - -inline ImVec2 GridSpaceToScreenSpace(const ImNodesEditorContext& editor, const ImVec2& v) -{ - return v + GImNodes->CanvasOriginScreenSpace + editor.Panning; -} - -inline ImVec2 GridSpaceToEditorSpace(const ImNodesEditorContext& editor, const ImVec2& v) -{ - return v + editor.Panning; -} - -inline ImVec2 EditorSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v) -{ - return v - editor.Panning; -} - -inline ImVec2 EditorSpaceToScreenSpace(const ImVec2& v) -{ - return GImNodes->CanvasOriginScreenSpace + v; -} - inline ImRect GetItemRect() { return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); } inline ImVec2 GetNodeTitleBarOrigin(const ImNodeData& node) @@ -1926,7 +1931,7 @@ ImNodesIO::LinkDetachWithModifierClick::LinkDetachWithModifierClick() : Modifier ImNodesIO::ImNodesIO() : EmulateThreeButtonMouse(), LinkDetachWithModifierClick(), - AltMouseButton(ImGuiMouseButton_Middle) + AltMouseButton(ImGuiMouseButton_Middle), AutoPanningSpeed(1000.0f) { } @@ -2125,6 +2130,7 @@ void BeginNodeEditor() // Reset state from previous pass ImNodesEditorContext& editor = EditorContextGet(); + editor.AutoPanningDelta = ImVec2(0, 0); ObjectPoolReset(editor.Nodes); ObjectPoolReset(editor.Pins); ObjectPoolReset(editor.Links); @@ -2283,6 +2289,21 @@ void EndNodeEditor() BeginCanvasInteraction(editor); } + bool shouldAutoPan = + editor.ClickInteraction.Type == ImNodesClickInteractionType_BoxSelection || + editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation || + editor.ClickInteraction.Type == ImNodesClickInteractionType_Node; + if (shouldAutoPan && !MouseInCanvas()) + { + auto mouse = ImGui::GetMousePos(); + auto center = GImNodes->CanvasRectScreenSpace.GetCenter(); + auto direction = (center - mouse); + direction = direction * ImInvLength(direction, 0.0); + + editor.AutoPanningDelta = direction * ImGui::GetIO().DeltaTime * GImNodes->Io.AutoPanningSpeed; + editor.Panning += editor.AutoPanningDelta; + } + ClickInteractionUpdate(editor); } diff --git a/imnodes.h b/imnodes.h index edabdbf..81dc806 100644 --- a/imnodes.h +++ b/imnodes.h @@ -125,6 +125,9 @@ struct ImNodesIO // Set based on ImGuiMouseButton values int AltMouseButton; + // Panning speed when dragging an element and mouse is outside the main editor view. + float AutoPanningSpeed; + ImNodesIO(); }; diff --git a/imnodes_internal.h b/imnodes_internal.h index 6a21628..8f24ad9 100644 --- a/imnodes_internal.h +++ b/imnodes_internal.h @@ -215,7 +215,7 @@ struct ImClickInteractionState struct { - ImRect Rect; + ImRect Rect; // Coordinates in grid space } BoxSelector; ImClickInteractionState() : Type(ImNodesClickInteractionType_None) {} @@ -252,6 +252,7 @@ struct ImNodesEditorContext // ui related fields ImVec2 Panning; + ImVec2 AutoPanningDelta; ImVector SelectedNodeIndices; ImVector SelectedLinkIndices; From 67c364ff6fd4e3135af2e15b1e6c3cab8550b7fa Mon Sep 17 00:00:00 2001 From: Julius Trinkunas Date: Tue, 31 Aug 2021 19:36:56 +0300 Subject: [PATCH 2/2] Remove usage of 'auto' keyword --- imnodes.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imnodes.cpp b/imnodes.cpp index 9e5c7c7..40f2a85 100644 --- a/imnodes.cpp +++ b/imnodes.cpp @@ -2295,9 +2295,9 @@ void EndNodeEditor() editor.ClickInteraction.Type == ImNodesClickInteractionType_Node; if (shouldAutoPan && !MouseInCanvas()) { - auto mouse = ImGui::GetMousePos(); - auto center = GImNodes->CanvasRectScreenSpace.GetCenter(); - auto direction = (center - mouse); + ImVec2 mouse = ImGui::GetMousePos(); + ImVec2 center = GImNodes->CanvasRectScreenSpace.GetCenter(); + ImVec2 direction = (center - mouse); direction = direction * ImInvLength(direction, 0.0); editor.AutoPanningDelta = direction * ImGui::GetIO().DeltaTime * GImNodes->Io.AutoPanningSpeed;