How To Create A Custom Value Drawer

The goal of this guide is to create a simple custom Odin value drawer for a custom struct type.

Value drawers are the most basic types of drawers in Odin, and are often the drawers that actually end up doing the final drawing of a property in the inspector. For this reason, they are often among the last drawers in the drawer chain, and will usually not continue the chain.

The struct for this purpose will contain two public float fields, an X and a Y. Our drawer will draw these two fields, each with its own slider and on a single line.

[Serializable] // The Serializable attributes tells Unity to serialize fields of this type.
public struct MyStruct
{
	public float X;
	public float Y;
}

For the drawer, we will create a new class named MyStructDrawer and inherit from OdinValueDrawer<T>. Since we are making a drawer for MyStruct we will specify MyStruct for the generic argument for the OdinValueDrawer.

public class MyStructDrawer : OdinValueDrawer<MyStruct>
{

Next, let us start implementing the actual drawing. We need to override the DrawPropertyLayout method for this.

protected override void DrawPropertyLayout(GUIContent label)
{
}

The first thing we will need in this drawer is an area to draw in. We can get this by calling into Unity's layout system. This also lets our drawer work with the rest of Unity's IMGUI system.

Rect rect = EditorGUILayout.GetControlRect();

We also want to draw a label for our property. Keep in mind that in Odin labels are optional, and so the label passed to this method might be null.

if (label != null)
{
	rect = EditorGUI.PrefixLabel(rect, label);
}

And, finally, we can draw our struct's fields. We can get the current value of the property from ValueEntry.SmartValue. We can also use this property to assign any changes.

MyStruct value = this.ValueEntry.SmartValue;
GUIHelper.PushLabelWidth(20);
value.X = EditorGUI.Slider(rect.AlignLeft(rect.width * 0.5f), "X", value.X, 0, 1);
value.Y = EditorGUI.Slider(rect.AlignRight(rect.width * 0.5f), "Y", value.Y, 0, 1);
GUIHelper.PopLabelWidth();

this.ValueEntry.SmartValue = value;

And that's pretty much it!


public class MyStructDrawer : OdinValueDrawer<MyStruct>
{
	protected override void DrawPropertyLayout(GUIContent label)
	{
		Rect rect = EditorGUILayout.GetControlRect();

		if (label != null)
		{
			rect = EditorGUI.PrefixLabel(rect, label);
		}

		MyStruct value = this.ValueEntry.SmartValue;
		GUIHelper.PushLabelWidth(20);
		value.X = EditorGUI.Slider(rect.AlignLeft(rect.width * 0.5f), "X", value.X, 0, 1);
		value.Y = EditorGUI.Slider(rect.AlignRight(rect.width * 0.5f), "Y", value.Y, 0, 1);
		GUIHelper.PopLabelWidth();

		this.ValueEntry.SmartValue = value;
	}
}