Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】複数選択式プルダウンメニューに区切り線を表示する【エディター拡張】

Unity Editor の拡張機能には,ドロップダウンメニューの作成方法が複数用意されています。

このドロップダウンメニューには独自の仕様があり,水平区切り線を加える事も出来ます。

本稿では,その方法について御説明いたします。

(Unity 2018.3.0f2)

EditorGUILayout.MaskField

今回は,こちらの関数で確認します。

docs.unity3d.com

文字列配列string[]から項目を選択し,フラグを10進数intで返します。

(もちろん,ToString()関数によって文字列stringを取得する事も出来ます。)

using UnityEngine;
// Regex クラスを使用
using System.Text.RegularExpressions;

// ここからエディター上でのみ有効
#if UNITY_EDITOR
using UnityEditor;

// エディター拡張クラス
[CustomEditor(typeof(Extend))]
public class ExtendedEditor : Editor
{// Editor クラスを継承
    // Extend クラスの変数を扱うために宣言
    Extend extend;

    void OnEnable()
    {// 最初に実行
        // Extend クラスに target を代入
        extend = (Extend)target;
    }

    public override void OnInspectorGUI()
    {// Inspector に表示
        // これ以降の要素に関してエディタによる変更を記録
        EditorGUI.BeginChangeCheck();

        // ラベルの作成
        var label = "List";
        // 初期値として表示する項目のインデックス番号
        var selectedIndex = extend.index;
        // プルダウンメニューに登録する文字列配列
        var displayOptions = Extend.list;
        // プルダウンメニューの作成
        var index = EditorGUILayout.MaskField(label, selectedIndex, displayOptions);

        // 区切り線のフラグを表す10進数
        var divider = 0;
        // 底
        const int Base = 2;
        // 指数
        int exponent;
        // 文頭から文末まで半角スペースのみで構成されるパターン
        var onlyHalfSpaces = @"^ *$";
        for (exponent = 0; exponent < Extend.list.Length; exponent++)
        {// 区切り線のあるインデックスをフラグに追加
            divider += Extend.list[exponent] == null ? (int)Mathf.Pow(Base, exponent)
                : Regex.IsMatch(Extend.list[exponent], onlyHalfSpaces) ? (int)Mathf.Pow(Base, exponent)
                : 0;
        }

        // 要素数を指数に代入
        exponent = Extend.list.Length;
        // 全選択状態
        const int Everything = -1;
        // 未選択状態
        const int Nothing = 0;
        // 区切り線以外が選択状態
        var exceptDivider = Mathf.Pow(Base, exponent) == index + divider + 1;
        // 区切り線のみが選択状態
        var onlyDivider = index == divider;
        // 区切り線を考慮して"Everything"や"Nothing"に切り替え
        index = exceptDivider ? Everything
            : onlyDivider ? Nothing
            : index;

        if (EditorGUI.EndChangeCheck())
        {// 操作を Undo に登録
            // Extend クラスの変更を記録
            var objectToUndo = extend;
            // Undo メニューに表示する項目名
            var name = "Extend";
            // 記録準備
            Undo.RecordObject(objectToUndo, name);
            // インデックス番号を登録
            extend.index = index;
        }
        // インデックス番号をログ出力
        Debug.Log(extend.index);
    }
}
// ここまでエディター上でのみ有効
#endif

// 同一オブジェクトへの複数追加を禁止
[DisallowMultipleComponent]
public class Extend : MonoBehaviour
{// エディター拡張の中身
    // リスト
    public static readonly string[] list = {
        "1",
        "",
        "2",
        " ",
        "3",
        "  ",//半角スペース2つ
        "4",
        string.Empty,
        "5",
        null,
        "6",
        "",//重複
        "7",
        " ",//重複
        "8",
        string.Empty,//重複
        "9",
        null,//重複
        " ",//全角スペース
    };

    // 初期値は“3”
    public int index = 16;
}

上記のスクリプトから生成したプルダウンメニューは,次の画像のようになります。

プルダウンメニューに区切り線が含まれている画像
区切り線が含まれるドロップダウンリスト

半角スペースのみで構成された要素,または空白文字が区切り線に変化します。

この区切り線は表示されるのみで,選択する事が出来ません。

全角スペースは,そのまま全角スペースとして項目に表示されます(見えませんが)。

重複する文字列string要素は表示されませんが,区切り線は例外のようです。

tsu-games.hatenablog.com

列挙型enumから生成するプルダウンメニューは1つしか区切り線を表示できませんでしたが,今回の方法では複数の区切り線を表示できます。

tsu-games.hatenablog.com

区切り線のフラグをインスペクター上では切り替えられないため,2のべき乗を利用して全選択や未選択を検知する方法を採りました。

また今回は「半角スペースのみで構成されている要素」を取得する必要があったため,正規表現との一致を判定するisMatch関数を使用しました。

docs.microsoft.com

以上,プルダウンメニューに区切り線を表示する方法でした。

択一選択式プルダウンメニューの場合は,こちらの記事をお読みください。

tsu-games.hatenablog.com