Editor implementations for Foundation inspector attributes. Each drawer is registered with [CustomPropertyDrawer(typeof(...), true)] and lives in namespace FronkonGames.GameWork.Foundation.
Apply attributes on runtime fields; drawers run automatically in the default Unity inspector (no custom Editor class required). For fully custom layouts, combine attributes with the Custom Inspector base class.
See the live demo: AttributesDemo.unity and AttributesDemo.cs.
Unity draws [SerializeField] fields with generic controls. Foundation attributes add validation, layout, conditionals, and pickers while keeping runtime types clean.
Drawers handle the Editor side:
- Type-safe UI, sliders, min/max ranges, scene index popups, folder/file pickers.
- Reset buttons, numeric drawers expose
Styles.RefreshIconto restore configured defaults. - Conditionals, show, hide, enable, or disable fields based on a sibling
bool. - Visual feedback, error coloring for wrong types, null references, or invalid passwords.
Attribute definitions and usage examples are in Runtime/Attributes/README.md. This document maps each attribute to its drawer and describes Editor behavior.
| Base class | Used for | Example |
|---|---|---|
PropertyDrawer |
Replaces or wraps a serialized field | SliderPropertyDrawer |
DecoratorDrawer |
Draws extra UI without owning a field value | MessageBoxDecoratorDrawer |
Most drawers call EditorGUI.PropertyField after adjusting layout, labels, or GUI.enabled. Numeric and slider drawers reserve 18px on the right for the reset icon button.
Shared resources:
Styles.RefreshIcon, reset button glyphSettings.Editor, spacing, error color, file-button width, title metrics
All drawers use true in CustomPropertyDrawer so attributes apply to derived attribute types as well.
| Attribute | Drawer | Field type | Behavior |
|---|---|---|---|
Title |
TitlePropertyDrawer.cs | Any | Bold heading, gray rule, then default field |
MessageBox |
MessageBoxDecoratorDrawer.cs | Decorator | EditorGUI.HelpBox above the next field |
Label |
LabelPropertyDrawer.cs | Any | Custom label and tooltip |
Indent |
IndentPropertyDrawer.cs | Any | Adds indentAttribute.level to EditorGUI.indentLevel |
All numeric drawers show a reset button. Wrong types render a red error label.
| Attribute | Drawer | Notes |
|---|---|---|
Field |
FieldPropertyDrawer.cs | Plain field + reset |
FieldLess |
FieldLessPropertyDrawer.cs | Only accepts values < threshold |
FieldLessEqual |
FieldLessEqualPropertyDrawer.cs | Only accepts values ≤ threshold |
FieldGreat |
FieldGreaterPropertyDrawer.cs | Only accepts values > threshold |
FieldGreatEqual |
FieldGreaterEqualPropertyDrawer.cs | Only accepts values ≥ threshold |
Slider |
SliderPropertyDrawer.cs | Slider with clamp and optional snap step |
MinMaxSlider |
MinMaxSliderPropertyDrawer.cs | Dual-handle range on min + next field (see below) |
MinMaxSlider reads the decorated property as min and property.GetEndProperty(true) as max. The max field must be the next serialized field of the same type (often [HideInInspector]).
[MinMaxSlider(0, 100, 0, 100), SerializeField]
private int minLevel = 0;
[HideInInspector, SerializeField]
private int maxLevel = 100;| Attribute | Drawer | Field type | Behavior |
|---|---|---|---|
Password |
PasswordPropertyDrawer.cs | string |
Masked field; red when outside min/max length |
Tag |
TagPropertyDrawer.cs | string |
EditorGUI.TagField; defaults empty to "Untagged" |
KeyCode |
KeyCodePropertyDrawer.cs | KeyCode |
Enum popup + capture-next-key button |
| Attribute | Drawer | Field type | Behavior |
|---|---|---|---|
File |
FilePropertyDrawer.cs | string |
Text field + project icon opens OpenFilePanel |
Folder |
FolderPropertyDrawer.cs | string |
Text field + button opens OpenFolderPanel |
Scene |
ScenePropertyDrawer.cs | int |
Popup of scenes in Build Settings (name [index]) |
File and Folder support relativeToProject on the attribute to store paths under Assets/… via ToRelativePath / ToAbsolutePath.
| Attribute | Drawer | Behavior |
|---|---|---|
NotEditable |
NotEditablePropertyDrawer.cs | Field visible, GUI.enabled = false |
OnlyEditableInEditor |
OnlyEnableInEditPropertyDrawer.cs | Enabled when not playing |
OnlyEditableInPlay |
OnlyEnableInPlayPropertyDrawer.cs | Enabled during Play mode |
All conditionals reference a bool field on the same component by name (nameof recommended). The drawer resolves the path by replacing the current property name in property.propertyPath.
| Attribute | Drawer | When active |
|---|---|---|
EnableIf |
EnableIfPropertyDrawer.cs | Enabled if condition is true |
DisableIf |
DisableIfPropertyDrawer.cs | Disabled if condition is true |
ShowIf |
ShowIfPropertyDrawer.cs | Visible if condition is true; height 0 when hidden |
HideIf |
HideIfPropertyDrawer.cs | Hidden if condition is true |
Missing condition fields log a warning and fall back to visible/enabled.
| Attribute | Drawer | Behavior |
|---|---|---|
NotNull |
NotNullPropertyDrawer.cs | Red tint when objectReferenceValue is null |
Button |
ButtonPropertyDrawer.cs | Inspector button; invokes parameterless method via reflection |
Button replaces the field UI entirely. The serialized field is a dummy holder; only the button is shown. Methods must be parameterless (public or non-public).
[NotEditable, SerializeField]
private int counter;
[Button(nameof(Reset)), SerializeField]
private string resetButton;
private void Reset() => counter = 0;These runtime attributes exist but are not implemented in Editor/Drawers/:
| Attribute | Notes |
|---|---|
ProgressBar |
Documented in Attributes README; no drawer in this folder yet |
AssetOnly |
Documented in Attributes README; no drawer in this folder yet |
ShowInInspector |
Used with Custom Inspector, not a property drawer |
Attributes compose on a single field. Order on the field matters for layout decorators (MessageBox, Title) and for MinMaxSlider pairing.
[MessageBox("Tune combat values for this enemy tier.", MessageBoxAttribute.MessageType.Info)]
[Title("Combat")]
[Indent, Label("Damage multiplier"), Slider(0.0f, 5.0f, 1.0f, 0.1f), SerializeField]
private float damageMultiplier = 1.0f;
[SerializeField]
private bool useCustomGravity;
[Indent, EnableIf(nameof(useCustomGravity)), SerializeField]
private float gravityScale;Open Demos/Attributes/AttributesDemo in the Editor to see every drawer in one inspector.
- Default inspector only, drawers apply when Unity draws
SerializedPropertyfields. A fully customEditorthat never callsPropertyFieldwill not run these drawers unless you draw properties explicitly. - Condition field scope,
EnableIf/ShowIfresolve sibling fields on the sameSerializedObject. Nested structs use property paths; condition names must match the bool field name at that nesting level. - Bool conditions only, conditional drawers read
sourcePropertyValue.boolValue. Other types are not supported. - Type errors, mismatched types (e.g.
Slideronstring) show a red inline error instead of crashing. - Button field hidden, the
Buttonattribute field is not shown as a text field; decorate a dummystringfield solely to host the attribute. - Scene index,
ScenelistsEditorBuildSettings.scenes; scenes not in Build Settings do not appear.
| Item | Location |
|---|---|
| Attribute API and examples | Runtime/Attributes/README.md |
| Custom inspector base (alternative to drawers) | Editor/Inspector/README.md |
| Shared editor styles | Editor/Inspector/Styles.cs |
Path helpers (ToRelativePath, Snap, …) |
Runtime/Extensions |