FloatFieldの作成(Editor拡張)2020/07/11修正

FloatFieldの作成(Editor拡張)2020/07/11修正

 EditorGUILayout.FloatFieldで作成したFloatFieldのラベルの色を変更しようとGUIStyleを変更したところ、テキスト入力部分のスタイルしか変更できませんでした。そこで、FloatFieldを自作することで、自由にラベルの色等を変更できるようにしました。

LabelFieldとFloatFieldを横並びで表示

 FloatFieldを作成すると、ラベル部分(LabelField)と数値入力部分(TextField)が同時に作成されます。これらを、別々に作成し横並びに配置することで、それぞれのスタイルや位置を自由に変更できるようにします。

Script

 EditorGUILayout.BeginHorizontal();とEditorGUILayout.EndHorizontal();の間にあるコントロールは横並びになります。よって、LabelFieldとFloatFieldを以下のように記述すると、ラベルとテキスト部分が分離したFloatFieldを作成することができます。

次に、それぞれのGUIStyleを変更できるようにします。

さらに、それぞれにオプションを設定できるようにします。

これで、ラベルのスタイルを自由に変更できるFloatFieldが作成できました。

実行結果

 作成したFloatFieldをEditorWindowで実行するScriptは以下の通りです。

このScriptを実行すると以下のようになります。ラベルの色及びFloatFieldの大きさの変更が行われていることが分かります。

Focusの追加

 EditorGUILayout.FloatFieldで作成したFloatFieldはラベルをクリックするとラベルの色が変更され、さらにTextFieldへFocusが移ります。また、TextFieldがFocusされると、ラベルの色が変わります。この機能を、先ほど作成したFloatFieldへ追加します。

Script

 Focusを追加したFloatFieldのコードは以下の通りです。

Focusを制御するにあたり、コントロールに名前を付ける必要があります。GUIUtility.GetControlID(FocusType.Passive)によってIDを取得し、名前へ追加することでコントロールごとに名前が変わるように処理を行っています。この名前は後に作成するFloatFieldへ設定します。

GUI.GetNameOfFocusedControlでFocusされているコントロールに設定されている名前を取得することができます。FloatFieldへ設定する名前(control_name)とFocusされているコントロールの名前が一致した場合、ラベルの色を変更する処理を追加しています。その際、Repaintによってウィンドウの再描画を行っています。

ラベルを作成した後に、GUILayoutUtility.GetLastRectによってラベルのRectを取得しています。次に、GUI.SetNextControlNameによってFloatFieldへ先ほど作成した名前(control_name)を設定しています。

rect_label.Contains(ev.mousePosition)でマウスカーソルがラベル上にあるかを、ev.type == EventType.MouseDownによってマウスがクリックされたか、また、ev.button == 0によって左クリックであることを判定しています(ev=Event.current)。これらによってラベル上で左クリックが行われたかを判定し、その結果により、GUI.FocusControl(control_name)でFloatFiledへFocusを移します。

実行結果

 Focusを追加したFloatFieldをEditorWindowで実行するScriptは以下の通りです。

このScriptを実行すると以下のようになります。ラベル及びFloatFieldをクリックすることでラベルの色が変化していることが分かります。

ドラッグによる数値変更

 EditorGUILayout.FloatFieldによって作成されたFloatFieldは、ラベル上で左クリックした後にドラッグを行うことで数値の変更ができます。この機能を追加します。

Script

 ドラッグによる数値変更を追加したFloatFieldのScriptは以下の通りです。

ev.mousePositionでマウスの位置を取得しています。また、ev.button==0で左クリックをされているかを判定しています。さらに、switch文でマウスの状態によって処理を分けています。

マウスが左クリックされている場合、GUIUtility.hotControlへFloatFieldのid(id)を渡し、コントロール権をFloatFieldへ与えます。また、GUI.FocusControlでラベルへFocusを移します。そして、ev.Use()によって他のコントロールが反応しないようにしています。

ドラッグが行われた際の処理です。GUIUtility.hotControlのidがFloatFieldのidと同じ場合に処理が行われるようにしています。ev.delta.xによってマウスカーソルの横方向への移動量を取得し、FloatFieldの数値を100倍(val*100f)した数値へ加算することで数値を増減させています。その後、変更した数値の小数を切り捨てた後に、100で割ることで小数点第2位まで変更できるようにしています。また、FloatFieldをFocusすると変更した数値が反映されないため、GUI.FocusControl(label_name)でラベルへFocusを移しています。その後、Repaint()によってウィンドウの再描画を行っています。

最後に以下のコードでマウスカーソルがラベル上にある場合、カーソルの画像を変更する処理を加えています。

実行結果

 ドラッグによる数値変更を追加したFloatFieldをEditorWindowで実行するScriptは以下の通りです。

このScriptを実行すると以下のようになります。ドラッグによってFloatFieldの数値を変更できていることが分かります。ただ、FloatFieldのBackground用デフォルト画像を取得できなかったため、ラベルへFocusが移ると通常の表示に戻ります。

そこで、以下のコードによりDarkSkinを取得し、FloatFieldのStyleを変更します。

このStyleを利用し、実行すると

となり、ラベルがFocusされた際にもFloatFieldがFocusされている表示になります。

さらに

 自身で作成したFloatFieldなので、ラベルとテキスト部分を逆に表示することもできます。

上記Scriptの実行結果は以下の通りです。

 Inspectorで表示されるShaderPropertiesのTexture部分を作成してみました。

実行結果は以下の通りです。

修正履歴

2020/07/11

 下の画像に示すように、テキスト入力部分をクリックしてフォーカスを移動した際、一番上のテキストフィールドのみテキストが選択された状態になります。

そのため、上記のコードを以下のように修正しました。

実行すると以下のようになります。全てのテキストエリアで、テキストが選択されるようになりました。