凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Unity のエディタ拡張で FoldOut をかっこよくするのをやってみた

はじめに

Screen Space Reflection の Image Effect を見ていたら次のように FoldOut が格好良かったので調べてみました。

f:id:hecomi:20161012155256p:plain

方法

ScreenSpaceReflectionEditor.cs を読むとパーティクル(Shuriken)で使っているスタイルを流用して作成しているようです。該当箇所をコピーして使えば同じように使えます。

using UnityEngine;
using UnityEditor;

public static class CustomUI
{
    public static bool Foldout(string title, bool display)
    {
        var style = new GUIStyle("ShurikenModuleTitle");
        style.font = new GUIStyle(EditorStyles.label).font;
        style.border = new RectOffset(15, 7, 4, 4);
        style.fixedHeight = 22;
        style.contentOffset = new Vector2(20f, -2f);

        var rect = GUILayoutUtility.GetRect(16f, 22f, style);
        GUI.Box(rect, title, style);

        var e = Event.current;

        var toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
        if (e.type == EventType.Repaint) {
            EditorStyles.foldout.Draw(toggleRect, false, false, display, false);
        }

        if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) {
            display = !display;
            e.Use();
        }

        return display;
    }
}

[CustomEditor(typeof(Hoge))]
public class HogeEditor : Editor
{
    bool fold = false;

    public override void OnInspectorGUI()
    {
        fold = CustomUI.FoldOut("Hoge", fold);
        if (fold) {
            EditorGUILayout.Toggle("hoge", false);
            EditorGUILayout.IntField("fuga", 12345);
            EditorGUILayout.TextField("piyo", "piyopiyo");
        }
    }
}

f:id:hecomi:20161012160039p:plain

解説

GUI の要素は引数に GUIStyle で定義されたスタイルを指定することで見た目をカスタマイズすることが出来ます。

GUIStylestring 型を取るコンストラクタをもっていない & ドキュメントされていないのですが、implicit operatorstring 型を変換でき、内部ではスキンのサーチ(GUISkin.FindStyle())が走ります。

こうするとデフォルトで定義されているスタイルが取得でき、これを IMGUI の描画関数に渡すとそのとおりに描いてくれるわけです。どんなスタイルがあるかはこちらが大変参考になります。

取得したままだと文字が小さかったりマージンが適切でなかったりするため、少しパラメタを書き換えて GUILayoutUtility.GetRect() で描画領域を確保して GUI.Box() でまずは背景を描画します。

このままだとトグルの▶アイコンが描画されないのでそれを描画しないとなりません。そこでもう一つの GUIStyle を取得する方法として、EditorStyles というものがあって、ここにはいくつか基本的な Editor に使う GUIStyle が保存されていて、EditorStyles.foldoutFoldOut 用のスタイルが取得できます。

GUIStyle は引数に渡すだけではなく、Draw() を呼んで自身の持つ画像(Texture2D)やマージンなどの情報を元に描画することが出来ます。最後に、この矩形領域がクリックされたかどうかの処理を書いて、カスタムした FoldOut が完成、という流れです。

おわりに

こういった標準のスタイルは他にも色々と利用できます。各エディタ拡張を覗いてみたり、どんなスタイルがあるか調べてみると面白いかもしれません。