- Home /
How do I implement Draggable Properties with custom Labels in Editor or PropertyDrawer?
For the sake of simplicity I will explain this on a simple example. I'm having a Monobehaviour or a custom [Serializable] class that holds multiple ints:
class HoldingInts : MonoBehaviour {
public int A;
public int B;
public int C;
}
The default Inspector puts a label in front of those three properties that I can click and drag to change the number without having to type.
Now, these take a lot of space, so I want to have an Editor or PropertyDrawer that put them side by side, like the X,Y,Z components of a Vector3 for example, so I do this:
GUIStyle overflowStyle = new GUIStyle();
overflowStyle.clipping = TextClipping.Overflow;
GUILayoutOption w8 = GUILayout.Width(8);
GUILayoutOption w25 = GUILayout.Width(25);
GUILayoutOption xw = GUILayout.ExpandWidth(true);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("My Ints");
EditorGUILayout.LabelField("A", overflowStyle, w8);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("A"), GUIContent.none, w25, xw);
EditorGUILayout.LabelField("B", overflowStyle, w8);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("B"), GUIContent.none, w25, xw);
EditorGUILayout.LabelField("C", overflowStyle, w8);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("C"), GUIContent.none, w25, xw);
EditorGUILayout.EndHorizontal();
Which gives me what I want visually, but my custom labels are not connected to the properties, so I can't click and drag them to change the numbers.
Is it possible to connect those custom labels to the properties?
Answer by ArkaneX · Jan 03, 2014 at 01:58 AM
After some tinkering, I came to the following solution:
[CustomPropertyDrawer(typeof(HoldingInts))]
public class HoldingIntsInspector : PropertyDrawer
{
private float a = 17;
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
float width = position.width * 0.25f;
Rect rect = new Rect(position);
rect.width = width;
EditorGUI.LabelField(rect, label);
rect.x += width;
float labelWidthTmp = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 24f; // your label width (8) x3
EditorGUI.PropertyField(rect, prop.FindPropertyRelative("A"), new GUIContent("A"));
rect.x += width;
EditorGUI.PropertyField(rect, prop.FindPropertyRelative("B"), new GUIContent("B"));
rect.x += width;
EditorGUI.PropertyField(rect, prop.FindPropertyRelative("C"), new GUIContent("C"));
EditorGUIUtility.labelWidth = labelWidthTmp;
}
}
You will probably need to tune this a bit to get perfect effect, but this should be a decent starting point. I went PropertyDrawer way, as I never used it before, so I was able to learn something new as well ;)
Oh wow... there's a static labelWidth... not even a GUIStyle or a List of GUILayoutOptions... just a float labelWidth...
The Design of this GUI system is scary.
Thanks a lot!
This is my current solution:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Segments");
// keep the originals
float lw = EditorGUIUtility.labelWidth;
TextClipping tc = EditorStyles.label.clipping;
RectOffset bord = EditorStyles.label.border;
RectOffset pad = EditorStyles.label.padding;
// alter values
EditorGUIUtility.labelWidth = 8f;
EditorStyles.label.clipping = TextClipping.Overflow;
EditorStyles.label.border = new RectOffset(0, 0, 0, 0);
EditorStyles.label.padding = new RectOffset(0, 0, 0, 0);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("xSegments"), new GUIContent("X"), w25, xw);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("ySegments"), new GUIContent("Y"), w25, xw);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("zSegments"), new GUIContent("Z"), w25, xw);
// no one saw something
EditorGUIUtility.labelWidth = lw;
EditorStyles.label.clipping = tc;
EditorStyles.label.border = bord;
EditorStyles.label.padding = pad;
EditorGUILayout.EndHorizontal();
And it's still a bit off. Looks like it's another debugging session to diff two GUIStyles manually.
But... they can be dragged!!! :D
Thanks again!