"Instantiating" GUI.Window in Editor

Hi All,

I’m creating a node based editor within Unity and I’m trying to figure out how to create a new window. What I want to do is create a new window, when a button is clicked. So far I’ve only been able to make “preset” windows. You can see my code here,

Thanks!

using UnityEngine;
using UnityEditor;


public class NodeEditor : EditorWindow {

    Rect window1;
    Rect window2;


    [MenuItem("Window/Node editor")]
    static void ShowEditor() {
        NodeEditor editor = EditorWindow.GetWindow<NodeEditor>();
        editor.Init();
    }


    public void Init() {
        window1 = new Rect(10, 10, 100, 100);
        window2 = new Rect(210, 210, 100, 100);
    }


    void OnGUI() {
        DrawNodeCurve(window1, window2); // Here the curve is drawn under the windows
        BeginWindows();

        window1 = GUI.Window(1, window1, DrawNodeWindow, "Window 1");   // Updates the Rect's when these are dragged
        window2 = GUI.Window(2, window2, DrawNodeWindow, "Window 2");

        EndWindows();
    }


    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;
        Color shadowCol = new Color(0, 0, 0, 0.06f);

        for (int i = 0; i < 3; i++) {// Draw a shadow
            Handles.DrawBezier(startPos, endPos, startTan, endTan, shadowCol, null, (i + 1) * 5);
        }

        Handles.DrawBezier(startPos, endPos, startTan, endTan, Color.black, null, 1);
    }
}

You can dynamically add windows by storing the data and then calling it. First thing that pops to my mind is use a Dictionary< int,WindowData >, where WindowData is either a struct or a class that contains the Rect, windowFunction and window name. If your windowfunctions are different, you might have to consider creating an interface and then a class that implements it for each window. Based on your code, you don’t have to worry.

To draw the windows, iterate through the dictionary.

foreach(KeyValuePair<int,WindowData> kvp in windowDictionary){
	kvp.Value.winRect = GUI.Window(kvp.Key, kvp.Value.winRect, kvp.Value.winFunc, kvp.Value.winName);
}

N.B. when using foreach, make sure you don’t change the dictionary while iterating through it. Changes could be done, e.g. in a coroutine that yield return new WaitForEndOfFrame(); in the beginning.

Got it working using lists.

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;


public class NodeEditor : EditorWindow {

    List<Rect> windows = new List<Rect>();


    [MenuItem("Window/Node editor")]
    static void ShowEditor() {
        NodeEditor editor = EditorWindow.GetWindow<NodeEditor>();
        editor.Init();
    }


    public void Init() {
        for (int i = 0; i < windows.Count; i++ ) {
            windows *= new Rect(10, 10, 100, 100);*

}
}

void OnGUI() {
//DrawNodeCurve(window1, window2); // Here the curve is drawn under the windows
BeginWindows();

if (GUILayout.Button(“Create window”)) {
Debug.Log(windows.Count);
windows.Add(new Rect(10, 10, 100, 100));
}

for (int i = 0; i < windows.Count; i++) {
windows = GUI.Window(i, windows*, DrawNodeWindow, "Window " + i);*
}

EndWindows();
}

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;
Color shadowCol = new Color(0, 0, 0, 0.06f);

for (int i = 0; i < 3; i++) {// Draw a shadow
Handles.DrawBezier(startPos, endPos, startTan, endTan, shadowCol, null, (i + 1) * 5);
}

Handles.DrawBezier(startPos, endPos, startTan, endTan, Color.black, null, 1);
}
}