PropertyDrawerのGUI配置前夜?
前回はコレ。
前回サラッと流しましたが、PropertyDrawer.GetPropertyHeight()は
- 非Layout処理をする時はきちんと高さ計算して返す
- Layout処理する時はゼロを返す
ようにします。前者について、このケースでは面倒くさいけど私は次の設計パターンでやってます。
「レンダリング関数をつくり、boolパラメータで実際に描画するかを指定する。レンダリング関数の戻り値はGUIを描くのに必要だった高さの累計。」
// 実際のレンダリング関数 // 戻り値:非Layout処理ではRect決定にCalcSize()を繰り返すことになるが、それによって表示に必要となった高さの合計を返す。 // isDrawをfalseに設定する時は、パラメータの表示や更新は行わない。ただし戻り値の計算は行う。 float DrawGUI(Rect position, SerializedProperty prop, GUIContent label, bool isDraw) { float height: // CalcSize()の都度サイズを加算していく。 // <略> return height; }
この関数をGetPropertyHeight()とOnGUI()でboolパラメータを切り替えて呼び出します。
なお後者についてですが、オーバーライドしないでデフォルトの値(とりあえず1行分?)を返すままにしとくと、無駄に1行スペースが開いてしまいます。
インデントとラベル幅制御のアレコレ
前置きが長くなりましたが今回のトピック。インスペクタにGUI部品を配置構成する上で重要なのは次の2つ。
- EditorGUI.indentLevel
- EditorGUIUtility.LookLikeControls
さらにRectを生計算する場合次を使用。
- EditorGUI.IndentedRect
EditorGUI.indentLevelについて
インデントレベルはグローバル変数的に存在してます。想像力重要。つまり「全てのGUI部品描画は強制的に右にオフセットするよ」って事ですね。例えBeginHorizontal()して1行で横に並べようとも、横に並ぶGUI部品の左には全てタブスペースが生じます。で、まず見切れます。なので、横にGUIを並べる場合は以下のフローが基本です。
- EditorGUI.indentLevelをバックアップ
- EditorGUI.indentLevelをゼロに設定
- 横並びに描画
- バックアップからEditorGUI.indentLevelを復元
EditorGUIUtility.LookLikeControlsについて
ラベル幅設定ってゲーム画面用のGUI設計に全く関係ないので、EditorGUIUtilityにコッソリあります。デフォルトのラベル幅設定はやたら長く、制限しないとやはり見切れます。EditorStylesからGUIStyleを取得してCalcSizeすればラベルに必要な幅が計算できます。ちなみにEditorGUIUtility.LookLikeInspectorもありますがこちらはラベル幅設定がないので実質出番ナシ…。
EditorGUI.IndentedRectについて
インデントサイズはコレ以外取得するインターフェースが公開されてません。この関数もまた気の利かない仕様。ILSpyするとわかりますが本当にただ単に引数のpositionに条件反射的に下駄を履かせるだけの計算です。中身は下記。
// UnityEditor.EditorGUI internal static float indent { get { if (EditorGUIUtility.lookLikeInspector) { return (float)EditorGUI.indentLevel * 15f; } return (EditorGUI.indentLevel > 0) ? (9f + (float)(EditorGUI.indentLevel - 1) * 15f) : 0f; } } // UnityEditor.EditorGUI public static Rect IndentedRect(Rect source) { float indent = EditorGUI.indent; return new Rect(source.x + indent, source.y, source.width - indent, source.height); }
インデント量はEditorGUI.indentLevelがそのまま使用されてます。だからEditorGUI.IndentedRectを使う時はEditorGUI.indentLevelのゼロリセットより手前である必要があります(ぶっちゃけこんな仕様ならindentLevelはパラメータ渡しの方が分かりやすいと思うの)。それと、IndentedRectしたRectを元に座標計算して配置する時は、そのRectは既にインデントが適用されてるんだから、描画を開始する前にはEditorGUI.indentLevelをゼロにセットしとかないとおかしくなるのにも注意。