【Unity】【UI Toolkit】Unity EditorでContextual Menu(右クリックメニュー)を使う

UI Toolkitで、Unity EditorのContextual Menu(右クリックメニュー)を使う方法についてまとめました。

Unity 2022.2.17

Contextual Menuとは?

Contextual Menuとは、Unity Editor上で右クリックを行った時に出現するメニューのことです。

Contextual Menu

UI Toolkitでは独自のUIに対してContextual Menuを追加する仕組みが用意されています。

本記事ではこれの使い方について紹介します。

Contextual Menuを実装する

それでは早速Contextual Menuを実装してみます。

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public sealed class ExampleWindow : EditorWindow
{
    public void CreateGUI()
    {
        var element = new VisualElement();
        element.style.backgroundColor = Color.red;
        element.style.width = 100;
        element.style.height = 100;

        // ContextualMenuManipulatorを生成
        var manipulator = new ContextualMenuManipulator(evt =>
        {
            // メニュー
            evt.menu.AppendAction("Example Menu", action => Debug.Log("Execute Example"));
            // 無効化状態のメニュー
            evt.menu.AppendAction("Disabled Menu", action => Debug.Log("Disabled Menu"),
                DropdownMenuAction.Status.Disabled);
            // セパレータ
            evt.menu.AppendSeparator();
            // チェック付きメニュー
            evt.menu.AppendAction("Checked Menu", action => Debug.Log("Checked Menu"),
                DropdownMenuAction.Status.Checked);
            // ユーザーデータ(任意のデータ)の使い方
            evt.menu.AppendAction("Menu with User Data",
                action => Debug.Log(action.userData),
                action => DropdownMenuAction.Status.Normal
                , "This is user data");
        });
        // ManipulatorのtargetにVisualElementを設定すると、
        // このVisualElementが右クリックされたときにコンテキストメニューが表示される
        manipulator.target = element;

        rootVisualElement.Add(element);
    }

    [MenuItem("Window/Example")]
    private static void Open()
    {
        GetWindow<ExampleWindow>();
    }
}

説明はコメントに書いた通りです。

ContextualMenuManipulatorを生成し、そのtargetプロパティに任意のVisual Elementをアサインすることで、そのVisual Elementが右クリックされた時にContextual Menuが表示されます。

動作確認

次に前節で作ったウィンドウの動作確認を行います。
Window > Exampleからウィンドウを開いて赤い要素を右クリックすると、以下の結果が得られます。

動作確認
正常にメニューが作成できていることを確認できました。

動的にメニューを追加する

ContextualMenuPopulateEventを使うと、登録先のUIが右クリックされてContextual Menuが開く時のコールバックを受け取れます。
これを利用して以下のように記述すると、登録先のUIのContextual Menuに対して動的にメニューを追加したり、上書きしたりできます。

element.RegisterCallback<ContextualMenuPopulateEvent>(evt =>
{
    // elementが開いたContextualMenuに対してメニューを追加する
    evt.menu.AppendAction("Runtime Example Menu", action => Debug.Log("Execute Example"));
    
    // メニューを削除して上書きことも
    //evt.menu.ClearItems();
    //evt.menu.RemoveItemAt(0);
});

参考

docs.unity3d.com

【Unity】OSSのハイパフォーマンスメッセージングシステム「Vital Router」の使い方まとめ

Unityで使えるメッセージングシステムVital Routerの使い方についてまとめました。

  • Vital Routerの概要と本記事の範囲
  • セットアップ
  • 基本的な使い方
    • コマンドを定義する
    • コマンドを発行する
    • コマンドを購読する
    • 依存性注入する
    • シーン構築と実行確認
    • VContainerと組み合わせるメリットについて
  • 非同期な購読処理とその実行順
  • 購読側の処理の前後に処理を挟むInterceptor
  • VContainerで子のスコープ専用のRouterを作る
  • コマンドをプーリングする
  • 関連
  • 参考
続きを読む

【Unity】【UI Toolkit】コピー&ペーストなどのショートカットをハンドリングするCommand Eventの使い方

UnityのUI Toolkitでコピー&ペーストなどのショートカットをハンドリングするCommand Eventの使い方についてまとめました。

  • Command Eventとは
  • コピー&ペーストをハンドリングする
  • 動作確認
  • 対応しているコマンド
  • 参考
続きを読む

【Unity】【UI Toolkit】Unityエディタ上でドラッグ&ドロップをハンドリングするイベントまとめ

UnityのUI Toolkitで、Unityエディタ上でドラッグ&ドロップをハンドリングするイベントについてまとめました。

続きを読む

【Unity】【UI Toolkit】マウス操作やジェスチャに関する処理を切り離して実装できるManipulatorの使い方

UnityのUI Toolkitでマウス操作やジェスチャに関する処理を切り離して実装できるManipulatorの使い方についてまとめました。

  • はじめに
  • Clickableマニピュレータ
  • 独自のManipulatorを作る
  • 独自のManipulatorの動作確認
  • 参考
続きを読む

【Unity】【UI Toolkit】Visual Elementのマウスによるクリック判定・範囲を制御する

UnityのUI ToolkitでVisual Elementのマウスによるクリック判定・範囲を制御する方法です。

Unity 2022.2.19

マウスイベントに反応しないようにする

VisualElement.pickingModePickingMode.Ignoreに設定すると、そのVisualElementはマウスイベントに反応しなくなります。
この挙動を確かめるために以下のように、マウスイベントに反応した場合にログ出力を行う、PickingModeIgnoreVisualElementを作成します。

using UnityEngine;
using UnityEngine.UIElements;

public sealed class ExampleElement : VisualElement
{
    public ExampleElement()
    {
        // マウスイベントに反応しないようにする
        pickingMode = PickingMode.Ignore;
    }

    protected override void ExecuteDefaultActionAtTarget(EventBase evt)
    {
        base.ExecuteDefaultActionAtTarget(evt);

        // クリックイベントが来たらログを出力
        if (evt.eventTypeId == MouseDownEvent.TypeId())
            Debug.Log("Mouse Down");
    }
}

これを以下のように適当なEditorWindowに表示します。
わかりやすいように赤い色をつけています。

using UnityEditor;
using UnityEngine;

public sealed class ExampleWindow : EditorWindow
{
    private void OnEnable()
    {
        var element = new ExampleElement();
        element.style.backgroundColor = Color.red;
        element.style.width = 100;
        element.style.height = 100;
        rootVisualElement.Add(element);
    }

    [MenuItem("Window/Example")]
    private static void Open()
    {
        GetWindow<ExampleWindow>();
    }
}

Window > Exampleからウィンドウを開き、赤いVisual Elementをクリックすると、クリックイベントに反応しないことを確認できます。

反応しない

マウスイベントに反応する範囲を指定する

VisualElement.ContainsPointをオーバーライドすると、マウスイベントに反応する範囲をカスタムすることができます。
以下は、Paddingを除いた領域(ContentRect)のみマウスイベントに反応するVisualElementの例です。

using UnityEngine;
using UnityEngine.UIElements;

public sealed class ExampleElement : VisualElement
{
    public ExampleElement()
    {
        style.paddingLeft = 25;
        style.paddingRight = 25;
        style.paddingTop = 25;
        style.paddingBottom = 25;
    }

    protected override void ExecuteDefaultActionAtTarget(EventBase evt)
    {
        base.ExecuteDefaultActionAtTarget(evt);

        // クリックイベントが来たらログを出力
        if (evt.eventTypeId == MouseDownEvent.TypeId())
            Debug.Log("Mouse Down");
    }

    public override bool ContainsPoint(Vector2 localPoint)
    {
        // contentRect (paddingを除いた領域) のみをクリック判定に含める
        return contentRect.Contains(localPoint);
    }
}

Window > Exampleからウィンドウを開き、赤いVisual Elementをクリックすると、Paddingを除いた中央に近い部分のみクリックに反応することを確認できます。

参考

docs.unity3d.com