【Untiy】エディタ拡張でポップアップウィンドウを表示する

投稿者: | 2023-05-11

エディタウィンドウのボタンをクリックしてその下にポップアップウィンドウを表示してみました。

ポップアップウィンドウは普通のエディタウィンドウと違って、ウィンドウの外をクリックした時などフォーカスが失われると自動的に閉じられます。

今回は、エディタウィンドウのボタンからポップアップウィンドウを表示し、ポップアップウィンドウに表示されたトグルを使って、元のエディタウィンドウのbool値を変更してみます。

エディタウィンドウを作る

using UnityEngine;
using UnityEditor;

public class EditorWindowWithPopup : EditorWindow
{
    // ポップアップで値を変更するbool値
    bool toggle1;
    bool toggle2;
    bool toggle3;

    // Add menu item
    [MenuItem("Example/Popup Example")]
    static void Init()
    {
        EditorWindow window = EditorWindow.CreateInstance<EditorWindowWithPopup>();
        window.Show();
    }

    PopupExample popup;

    // ボタンの表示範囲
    Rect buttonRect;

    void OnGUI()
    {
        GUILayout.Label("Editor window with Popup example", EditorStyles.boldLabel);

        // ボタンを押す
        if (GUILayout.Button("Popup Options", GUILayout.Width(200)))
        {
            // ポップアップウィンドウコンテンツのインスタンスが無い時
            if (popup == null)
            {
                // ポップアップウィンドウコンテンツのインスタンスを作成
                popup = PopupExample.Create(OnPopupClosed, toggle1, toggle2, toggle3);
            }

            // ポップアップを表示
            PopupWindow.Show(buttonRect, popup);
        }
        // 再描画のときに直前のGUIレイアウト要素の矩形を取得
        if (Event.current.type == EventType.Repaint) buttonRect = GUILayoutUtility.GetLastRect();

        // bool値を表示
        if (toggle1) GUILayout.Label("toggle1");
        if (toggle2) GUILayout.Label("toggle2");
        if (toggle3) GUILayout.Label("toggle3");

    }

    // ポップアップが閉じた時
    void OnPopupClosed(bool toggle1, bool toggle2, bool toggle3)
    {
        // 値を変更する
        this.toggle1 = toggle1;
        this.toggle2 = toggle2;
        this.toggle3 = toggle3;

        // ウィンドウの再描画をする
        Repaint();
    }
}
参考:https://docs.unity3d.com/ja/2021.1/ScriptReference/PopupWindow.html

まずポップアップで変更するbool値の変数やポップアップウィンドウのコンテンツのインスタンス、ボタンの矩形範囲などを宣言して、このエディタウィンドウを表示するための静的メソッドも定義しています。

using UnityEngine;
using UnityEditor;

public class EditorWindowWithPopup : EditorWindow
{
    // ポップアップで値を変更するbool値
    bool toggle1;
    bool toggle2;
    bool toggle3;

    // Add menu item
    [MenuItem("Example/Popup Example")]
    static void Init()
    {
        EditorWindow window = EditorWindow.CreateInstance<EditorWindowWithPopup>();
        window.Show();
    }

    PopupExample popup;

    // ボタンの表示範囲
    Rect buttonRect;

静的メソッドにはMenuItem属性を付けているので、メインメニューから実行できます。

ウィンドウに表示するものをOnGUIメソッドに実装します。まずボタンを表示し、そのボタンをクリックするとポップアップが表示されます。

 void OnGUI()
    {
        GUILayout.Label("Editor window with Popup example", EditorStyles.boldLabel);

        // ボタンを押す
        if (GUILayout.Button("Popup Options", GUILayout.Width(200)))
        {
            // ポップアップウィンドウコンテンツのインスタンスが無い時
            if (popup == null)
            {
                // ポップアップウィンドウコンテンツのインスタンスを作成
                popup = PopupExample.Create(OnPopupClosed, toggle1, toggle2, toggle3);
            }

            // ポップアップを表示
            PopupWindow.Show(buttonRect, popup);
        }

ポップアップを表示するには、PopupWindow.Showメソッドの引数にポップアップを開くためのボタンの矩形範囲と、ポップアップのコンテンツを実装するためのPopupWindowContentクラスのインスタンスを渡します。

PopupWindow.Show(buttonRect, popup);

PopupWindowContentのインスタンスはnewキーワードで作成できますが、ポップアップのトグルの状態や、ポップアップを閉じたときのコールバック関数を渡せるように、静的メソッドを使っています。

popup = PopupExample.Create(OnPopupClosed, toggle1, toggle2, toggle3);

ウィンドウやボタンにマウスカーソルがのったときや、ボタンをクリックしたときなどにウィンドウの再描画が行われるので、そのときにGUILayoutUtility.GetLastRectメソッドを使って、ボタンの矩形範囲を取得します。

        if (Event.current.type == EventType.Repaint) buttonRect = GUILayoutUtility.GetLastRect();

これをしないと、ポップアップがエディタウィンドウのタイトルの下に表示されました。

ポップアップを表示するときにボタンの矩形範囲を渡すと、そのボタンの下にポップアップが表示されます。

ボタンの下に表示

最後にbool値がtrueなら変数名をエディタウィンドウに表示しています。

        if (toggle1) GUILayout.Label("toggle1");
        if (toggle2) GUILayout.Label("toggle2");
        if (toggle3) GUILayout.Label("toggle3");

    }

ポップアップを閉じたときには、引数の値を変数に入れて、エディタウィンドウの再描画を行います。

    void OnPopupClosed(bool toggle1, bool toggle2, bool toggle3)
    {
        // 値を変更する
        this.toggle1 = toggle1;
        this.toggle2 = toggle2;
        this.toggle3 = toggle3;

        // ウィンドウの再描画をする
        Repaint();
    }
}

再描画を行わないと、ウィンドウの外をクリックしてポップアップを閉じた場合に、カーソルがウィンドウに再度乗るまで、表示が切り替わりませんでした。

ポップアップウィンドウのコンテンツを作る

次にポップアップウィンドウのコンテンツを実装するためのクラスを作ります。このクラスはPopupWindowContentクラスを継承させます。

using UnityEngine;
using UnityEditor;

public class PopupExample : PopupWindowContent
{
    bool toggle1;
    bool toggle2;
    bool toggle3;

    // デリゲート
    public delegate void OnClosed(bool toggle1, bool toggle2, bool toggle3);
    OnClosed onClosed;

    // ポップアップウィンドウを作成
    public static PopupExample Create(OnClosed onClosed, bool toggle1, bool toggle2, bool toggle3)
    { 
        var p = new PopupExample();
        p.onClosed = onClosed;
        p.toggle1 = toggle1;
        p.toggle2 = toggle2;
        p.toggle3 = toggle3;
        return p;
    }

    public override Vector2 GetWindowSize()
    {
        return new Vector2(200, 150);
    }

    public override void OnGUI(Rect rect)
    {
        GUILayout.Label("Popup Options Example", EditorStyles.boldLabel);
        toggle1 = EditorGUILayout.Toggle("Toggle 1", toggle1);
        toggle2 = EditorGUILayout.Toggle("Toggle 2", toggle2);
        toggle3 = EditorGUILayout.Toggle("Toggle 3", toggle3);
    }

    public override void OnOpen()
    {
        Debug.Log("Popup opened: " + this);
    }

    // ポップアップが閉じたとき
    public override void OnClose()
    {
        Debug.Log("Popup closed: " + this);

        if(onClosed != null) onClosed(toggle1, toggle2, toggle3);
    }
}

まずbool値やポップアップが閉じたときのデリゲート型の変数などを宣言します。また、このクラスのインスタンスを返す静的メソッドの引数の値をこれらの変数にいれています。

using UnityEngine;
using UnityEditor;

public class PopupExample : PopupWindowContent
{
    bool toggle1;
    bool toggle2;
    bool toggle3;

    // デリゲート
    public delegate void OnClosed(bool toggle1, bool toggle2, bool toggle3);
    OnClosed onClosed;

    // ポップアップウィンドウを作成
    public static PopupExample Create(OnClosed onClosed, bool toggle1, bool toggle2, bool toggle3)
    { 
        var p = new PopupExample();
        p.onClosed = onClosed;
        p.toggle1 = toggle1;
        p.toggle2 = toggle2;
        p.toggle3 = toggle3;
        return p;
    }

また、GetWindowSizeメソッドをオーバーライドして、ポップアップウィンドウのサイズを返します。

    public override Vector2 GetWindowSize()
    {
        return new Vector2(200, 150);
    }
new Vector2(100, 150) のとき

ポップアップウィンドウには、bool値を変更するための3つのトグルを表示しています。

    public override void OnGUI(Rect rect)
    {
        GUILayout.Label("Popup Options Example", EditorStyles.boldLabel);
        toggle1 = EditorGUILayout.Toggle("Toggle 1", toggle1);
        toggle2 = EditorGUILayout.Toggle("Toggle 2", toggle2);
        toggle3 = EditorGUILayout.Toggle("Toggle 3", toggle3);
    }

ポップアップウィンドウの開閉時には、OnOpenとOnCloseメソッドが自動的に呼ばれます。これらをオーバーライドして開閉時の処理を追加します。

今回は閉じたときにデリゲートを実行して、変更された値を元のエディタウィンドウに知らせています。

    public override void OnOpen()
    {
        Debug.Log("Popup opened: " + this);
    }

    // ポップアップが閉じたとき
    public override void OnClose()
    {
        Debug.Log("Popup closed: " + this);

        if(onClosed != null) onClosed(toggle1, toggle2, toggle3);
    }
}

これで、ポップアップウィンドウを使って元のエディタウィンドウの値を変更できました。

コメントを残す

メールアドレスが公開されることはありません。