EditorWindow, draggable GUI.Window and dragging to pan [SOLVED]

User unimechanic posted a couple years ago a snippet of C# code to create a simple Node Editor, which he later updated to add a simple pan functionality. The thread is here: Simple node editor - Unity Engine - Unity Discussions

I’ve been trying to figure out a way to drag the EditorWindow background instead of using buttons to pan. This little snippet seemed to do the trick:

        if (Event.current.button == 1 && Event.current.type == EventType.MouseDrag) {
            panX += Event.current.delta.x;
            panY += Event.current.delta.y;
        }

…except when we attempt to drag the GUI.Windows that we use as the nodes, both the window and the whole group will drag.

I’ve been trying to figure out a way to detect if the GUI.Window is being dragged, or if the mouse is within the rect of the windows, but after a lot of browsing in the documentation I can’t figure out how to achieve either.

The whole script for testing:

using UnityEngine;
using UnityEditor;

public class NodeEditor : EditorWindow {

    Rect window1;
    Rect window2;
    float panX = 0;
    float panY = 0;
   
    [MenuItem("Window/Node Editor")]
    static void ShowEditor() {
        NodeEditor editor = EditorWindow.GetWindow<NodeEditor>();
        editor.Show();
    }
   
    public void Awake() {
        window1 = new Rect(10, 10, 100, 100); 
        window2 = new Rect(210, 210, 100, 100);
    }
   
    void OnGUI() {
        bool didPan = false;
        if (Event.current.type == EventType.MouseDrag) {
            panX += Event.current.delta.x;
            panY += Event.current.delta.y;
            didPan = true;
        }
       
        GUI.BeginGroup(new Rect(panX, panY, 100000, 100000));
       
        DrawNodeCurve(window1, window2); // Here the curve is drawn under the windows
       
        BeginWindows();
        window1 = GUI.Window(2, window1, DrawNodeWindow, "Node A");   // Updates the Rect's when these are dragged
        window2 = GUI.Window(3, window2, DrawNodeWindow, "Node B");
        EndWindows();
       
        GUI.EndGroup();
       
        if (didPan) Repaint();
    }
   
    void DrawNodeWindow(int id) {
        GUI.DragWindow();
    }
   
    void DrawNodeCurve(Rect start, Rect end) {
        Vector3 startPos = new Vector3(start.x + start.width, start.y + start.height / 2, 0);
        Vector3 endPos = new Vector3(end.x, end.y + end.height / 2, 0);
        Vector3 startTan = startPos + Vector3.right * 50;
        Vector3 endTan = endPos + Vector3.left * 50;
        Handles.DrawBezier(startPos, endPos, startTan, endTan, Color.white, null, 4);
    }
}

Derp! I figured it out! I’m very new to Unity, so I didn’t realize that GUI.Window returns the window Rect - the current one, accounting for the windows being dragged.

With that, I simply need to check each window rect for Rect.Contain(Event.Current.mousePosition). If neither window rect contains the mouse position, that means the user is dragging the background.

1 Like

I know this is more than a year old and it’s probably way irrelevant to you by now but you can simply move the panning code below GUI.EndGroup ().

I don’t quite understand why it works, maybe something to do with the windows already being serialized before the panning code, I will try to look into it. Anyways, this should simplify the code and I hope this helps.

P.S. no need for the didPan bool check simply replace it with repaint.

1 Like

yes you are right! simple way to solve it