Skip to content

Commit

Permalink
Merge pull request #120 from smilediver/auto-panning
Browse files Browse the repository at this point in the history
Add auto-panning when mouse goes outside the editor while dragging stuff
  • Loading branch information
Nelarius authored Sep 12, 2021
2 parents c986af0 + 67c364f commit c36aaa0
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 31 deletions.
81 changes: 51 additions & 30 deletions imnodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1926,7 +1931,7 @@ ImNodesIO::LinkDetachWithModifierClick::LinkDetachWithModifierClick() : Modifier

ImNodesIO::ImNodesIO()
: EmulateThreeButtonMouse(), LinkDetachWithModifierClick(),
AltMouseButton(ImGuiMouseButton_Middle)
AltMouseButton(ImGuiMouseButton_Middle), AutoPanningSpeed(1000.0f)
{
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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())
{
ImVec2 mouse = ImGui::GetMousePos();
ImVec2 center = GImNodes->CanvasRectScreenSpace.GetCenter();
ImVec2 direction = (center - mouse);
direction = direction * ImInvLength(direction, 0.0);

editor.AutoPanningDelta = direction * ImGui::GetIO().DeltaTime * GImNodes->Io.AutoPanningSpeed;
editor.Panning += editor.AutoPanningDelta;
}

ClickInteractionUpdate(editor);
}

Expand Down
3 changes: 3 additions & 0 deletions imnodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,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();
};

Expand Down
3 changes: 2 additions & 1 deletion imnodes_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ struct ImClickInteractionState

struct
{
ImRect Rect;
ImRect Rect; // Coordinates in grid space
} BoxSelector;

ImClickInteractionState() : Type(ImNodesClickInteractionType_None) {}
Expand Down Expand Up @@ -254,6 +254,7 @@ struct ImNodesEditorContext

// ui related fields
ImVec2 Panning;
ImVec2 AutoPanningDelta;

ImVector<int> SelectedNodeIndices;
ImVector<int> SelectedLinkIndices;
Expand Down

0 comments on commit c36aaa0

Please sign in to comment.