Skip to content

Latest commit

Β 

History

209 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ℹ️ Features

  • Collection of highly versatile, general-use property drawers and decorators.
  • All attributes work as-is without a custom inspector.
  • 🀞 Reasonably lightweight.

πŸ§‘β€πŸ’»πŸ’¬ These attributes are an aggregate of helper attributes I've made over the years for various projects. If I find myself wanting an attribute for multiple projects, it eventually ends up in here.


πŸ“¦ Install

Minimum Unity version: 2022.3

πŸ“¦ Package Manager

  1. Open Package Manager
  2. Install package from Git URL:
    https://github.com/Smidgens/unity-attributes.git#<tag_or_sha>

πŸš€ Overview

Attributes break down into four categories: Drawers, Decorators, Modifiers, and Standalone.

  • Drawers modify how fields are displayed, and in some cases can be chained.
  • Decorators add static elements above fields. Built-in examples include Unity's [Header] and [Space] attributes
  • Modifiers supply additional options to drawers, such as custom labels, indents, or buttons. By themselves they do nothing.
  • Standalone attributes are simple single-purpose property drawers that do not inherit from this project's base drawer.

⚑ Drawers

πŸ”§ Modifiers

⚑ Decorators

⚑ Standalone


πŸš€ Attributes

βš™οΈ Drawers

[DefaultDrawer]

Fields: any

Draws the default property drawer. This attribute exists to allow modifier attributes like buttons to work with regular drawers.


[EditCondition]

Fields: any
🎚️ expression|hide

Toggles field hidden/read-only depending on supplied conditional expression.

[FieldOptions]
public bool hideToggle;

[EditCondition("hideToggle", hide:true)]
[FieldOptions(indent:1)]
public string hiddenOnToggle;

public int intValue;

public TestEnum enumValue;

// show on enum value
[EditCondition("enumValue == Value1")]
public string enableIfValue1;

// show using int field
[EditCondition("intValue > 10")]
public string enableIfInt;


enum TestEnum
{
	None = 0,
	Value1 ,
	Value2,
	Value3,
}

[Expand]

Fields: class|struct
🎚️ innerOnly

Expands all child fields. Label can be optionally hidden.

[Serializable]
public struct ExpandableStruct
{
	public string name;
	public Texture2D icon;
}

// show child props indented
[Expand]
public ExpandableStruct expanded1;

// only show child props
[Expand(innerOnly:true)]
public ExpandableStruct expanded2;


[Inline]

Fields: class|struct

Inlines all child fields in a single row.

  • [InlineWidth] can be used to specify the preferred size of specific fields.

  • [InlineHidden] can be used to exclude fields from being inlined.

[Inline]
public Vector3 inlinedVector;

[InlineWidth("key", 30f)]
[Inline]
public InlinedType inlinedCustom;

[Serializable]
public struct InlinedType
{
	public string key;
	public string name;
	[InlineWidth(40f)]
	public int count;
	[InlineWidth(0.25f)]
	public Texture2D icon1;
	[InlineWidth(0.25f)]
	public Texture2D icon2;
}


[Dropdown]

Fields: any
🎚️ optionFn|boxedValues

Shows a dropdown list of values for field. Values can be supplied directly, or a reference to an options method can be used which returns an IEnumerable of (string,<type>) tuples (label/value).

Has special behaviour when placed on UnityEngine.Object fields where values can be supplied as folder paths or asset GUIDs.

[Dropdown("option1", "option2")]
public string stringValue;

[Dropdown(0.5f, 1.2f, 2.4f)]
public float floatValue;

[Dropdown(0, 10)]
public int intValue;

// load asset options
[Dropdown("Assets/Textures/icons/", "460278ced8f4db444b2b4cd02a08f984")]
public Texture2D icon;

// relative path to options
[Dropdown("GetColorOptions")]
public Color colorValue;

// absolute path to options
[Dropdown("GetColorOptions;MyType, MyModule")]
public Color colorValue2;

public static List<(string, Color)> GetColorOptions()
{
	return new ()
	{
		("White", Color.white),
		("Black", Color.black),
		("Clear", Color.clear),
		("Red", Color.red),
		("Blue", Color.blue),
		("Green", Color.green),
		("Yellow", Color.yellow),
		("Magenta", Color.magenta),
	};
}


[InstancedReference]

Fields: class

Draws a popup list of new-able types on field with [SerializeReference].

[InstancedReference]
[SerializeReference]
public BaseClass instance;

[Serializable]
abstract class BaseClass {}

[Serializable]
class ClassA : BaseClass
{
	public int myValueFromA;
}

[Serializable]
class ClassB : BaseClass
{
	public int myValueFromB;
}


[Box]

Fields: any

Wraps field in outlined box.

Tips:

  • Combine with [Expand(innerOnly:true)].
[Box]
[Expand(innerOnly:true)]
public GroupedFields fieldGroup;

[Serializable]
public struct GroupedFields
{
	public int count;
	public string name;
}


[Foldout]

Fields: any
🎚️ label|iconGUID|iconCoords

Wraps field in foldout box.

Tips:

  • Combine with [Expand(innerOnly:true)].
[Foldout(iconGUID:"b4508e266a1d41445a0cb18bd9acf8d6")]
[Expand(innerOnly:true)]
public FoldableStruct foldedStruct;

[Serializable]
public struct FoldableStruct
{
	public int count;
	public string name;
}


[Reorderable]

Fields: Array|List
🎚️ flags|fieldName

Draws an array as a reorderable drag list with various customization options and helpers.

In Unity 6 and later the attribute can be placed directly on arrays.

For older versions, a wrapper type needs to be used.

Unity 6+:

// draws collapsed list of colliders
[Reorderable((EReorderable.Minimal|EReorderable.Foldable))]
public Collider[] foldableList;

// hide size input
[Reorderable(EReorderable.Minimal & ~EReorderable.Resizable)]
public string[] nonResizeable;

// draws standard-looking list
[Reorderable(EReorderable.Standard)]
public string[] standardList;

Pre-Unity 6

// wrapped array, requires reference to field
[Reorderable("array", EReorderable.Minimal|EReorderable.Foldable)]
public WrappedArray<Collider> wrappedList;

// array wrapper
[Serializable]
public struct WrappedArray<T>
{
	public T[] array;
}


[StableGUID]

Fields: string

Shows helper for generating stable GUID for the serialized object. Uses GlobalObjectId to verify uniqueness and warns about clashes. The GUID and the serialized object's global ID are concatenated and saved to string. Can be leveraged to implement stable IDs for scene objects added at editor time.

[StableGUID]
public string guid;


[GlobalObjectID]

Fields: string

Simpler version of StableGUID that automatically sets the field value to the serialized object's Global ID

[GlobalObjectID]
public string objectID;


[ObjectMethodReference]

Fields: string
🎚️ field|delegateType|delegateTypeFn|flags

Shows a dropdown of instance methods available on referenced UnityEngine.Object. If the target object is either a GameObject or Component, the displayed options will include any Components on the referenced GameObject, same as UnityEvent.

The method referenced is stringified on the following form:

<name>;<return_type>;<arg_type1>|<arg_type2>...;<target_type>`

Example:

set_name;System.Void,mscorlib;System.String,mscorlib;UnityEngine.Transform,UnityEngine.CoreModule

Notes:

  • Properties are referenced via their backing methods whose names are prefixed with get_/set_.
  • Types referenced use assembly qualified names.
  • To allow generic delegates to be supplied to attribute, the delegateTypeFn option can be used.
public GameObject objectField;
	
[ObjectMethodReference("objectField", typeof(Action<string>))]
public string method;

// use type getter if we're in templated type
[ObjectMethodReference("objectField", "GetDelegateType"))]
public string method;

// return the type of our generic delegate
Type GetDelegateType()
{
	return typeof(Action<T>);
}


[SearchType]

Fields: string
🎚️ flags|baseType|assemblies|namespaces

Provides a searchable popup for assembly types with various filtering options.

[SearchType]
public string anyType;

// only show component types
[SearchType(baseType: typeof(Component))]
public string componentType;

// only show system module types
[SearchType(assemblies: new string[]{ "mscorlib" })]
public string systemType;


[SearchEnum]

Fields: enum

Shows a searchable popup of values in enum.

[SearchEnum]
public KeyCode someKey;


[NavMeshAgentID]

Fields: int

Draws popup of NavMesh agent types in project.

[NavMeshAgentID]
public int agentID;


[NavMeshAreaID]

Fields: int

Draws popup of NavMesh area types in project.

[NavMeshAreaID]
public int areaID;


[ProjectLayer]

Fields: int

Dropdown of project layer indices.

[ProjectLayer]
public int layerIndex;

[ProjectSortLayer]

Fields: int

Dropdown of project sorting layer indices.

[ProjectSortLayer]
public int sortLayer;

[ProjectTag]

Fields: string

Dropdown of project tags.

[ProjectTag]
public string pTag;

[ProjectScene]

Fields: int|string
🎚️ buildOnly

Shows dropdown of scenes in project and saves value as scene path or index in build settings.

[ProjectScene]
public string scenePath;

[ProjectScene(buildOnly:true)]
public int sceneIndex;

[ProjectPath]

Fields: string
🎚️ mode|pattern

Draws popup of paths relative to project root directory. Can be set to either folder or file paths.

// show blender files
[ProjectPath(pattern:"*.blend")]
public string filePath;

// show folder paths
[ProjectPath(EProjectPath.Folder)]
public string folderPath;

[BlendShape]

Fields: int|string

Shows dropdown of blend shapes in referenced skinned mesh renderer. Saves value as either string (shape name) or int (index in renderer array).

public SkinnedMeshRenderer myRenderer;

[AnimatorParameter("myRenderer")]
public string blendShapeName

[AnimatorParameter("myRenderer")]
public int blendShapeIndex

[AnimatorParameter]

Fields: int|string
🎚️ field|types

Shows dropdown of parameters in referenced animator. Saves value as either string (param name) or int (param index).

public Animator animator;

[AnimatorParameter("animator")]
public string paramName;

[AnimatorParameter("animator")]
public int paramIndex;

// restrict to float or int params
[AnimatorParameter("animator", EAnimatorParameter.Float|EAnimatorParameter.Int)]
public string floatParam;

[RendererMaterial]

Fields: int
🎚️ field

Shows dropdown of materials in referenced renderer. Saves value as int index to material in renderer material array.

public Renderer myRenderer;

[RendererMaterial("myRenderer")]
public int materialIndex

[HexColor]

Fields: string
🎚️ showAlpha|hdr

Draws color picker for string field and saves as hex color value.

[HexColor]
public string hexColor = "#f00";

[Slider]

Fields: numeric
🎚️ min|max|step|precision

Identical to [Range] attribute, but provides options for step and precision.

[Slider(1f,10f,1)]
public float sliderPrecision;

[Slider(1f,10f,0.5f)]
public float sliderStep;

[Slider(1,10)]
public int sliderInt;

[IntervalSlider]

Fields: class|struct
🎚️ min|max|fMin|fMax|step

Draws Min/Max slider and saves values to two separate child fields.

// default saves to x/y
[IntervalSlider(0f, 1f)]
public Vector2 vectorInterval;

// custom min/max fields
[IntervalSlider(0f, 1f, fMin:"min", fMax:"max", step:0.25f)]
public MyInterval interval; 

[Serializable]
public struct MyInterval
{
	public float min,max;
}

[Progress]

Fields: numeric
🎚️ min|max|label

Draws numeric field as a progress bar.

[Progress(0, 100)]
public float health = 50;

[Progress(0, 100, "Status")]
public float health = 50;


[Switch]

Fields: enum|flags|bool|LayerMask
🎚️ offLabel|onLabel

Draws a toggle switch.

For flag and layermask fields, a switch will be drawn for every value.

[Switch]
public bool switch;

[Switch("Off", "On")]
public bool switchLabeled;

[FieldOptions(label:null)]
[Foldout,Switch]
public LayerMask switchLayers;

[FieldOptions(label:null)]
[Foldout,Switch]
public EnumFlags switchFlags;

[Flags]
enum EnumFlags
{
	Item1 = 1,
	Item2 = 2,
	Item3 = 4,
}


[Tabs]

Fields: enum|flags|bool
🎚️ vertical

Draws a toolbar of buttons.

[Flags]
enum Options
{
	Value1 = 1,
	Value2 = 2,
	Value3 = 4,
}

[Tabs]
public Options flagTabs;

[Tabs]
public bool boolTabs;

[Tabs(vertical:true)]
public Options verticalTabs;


[TextBox]

Fields: string
🎚️ minLines

Draws text area that resizes automatically.

[TextBox(minLines:3)]
public string textArea;

πŸ”§ Modifiers

Modifiers work in conjunction with property drawers in that they modify their drawing in some way.

⚠️ Modifiers only work if at least one attribute from this project is present. [DefaultDrawer] can be used to get them to work with regular drawers.


[FieldButton]

Targets: field
🎚️ width|label|flags

Draws a button above field. Can reference method on field object, its owner, or any static method.

  • Static methods can be referenced with the form <name>;<assembly_type>.
  • Method on field itself can be referenced by prefixing the supplied name with . .
  • Note: Methods cannot change values of struct types as their current contents get copied when invoking the function.
[FieldButton("OwnerMethod", width:0.5f)] 
[FieldButton(".SetMyValue", label:"Set=100",  args:new object[]{ 100 }, flags:EFieldUsable.Play, width:0.5f)] // inner
[FieldButton("LogValue;StaticClass, MyModule", args:new object[]{ 42 }, width:1f)]
[DefaultDrawer]
public OwnerOfFunctions fieldWithButtons;

private void OwnerMethod()
{
	Debug.Log("Outer method called!");
}

[Serializable]
public class OwnerOfFunctions
{
	public int myValue = 10;

	public void SetMyValue(int v)
	{
		myValue = v;
	}
}

class StaticClass
{
	public static void LogValue(int v)
	{
		Debug.Log(v);
	}
}


[FieldOptions]

Targets: field
🎚️ label|useFlags|indent

Allows overrides to be specified for given field.

// custom label
[FieldOptions(label:"Bojack")]
[DefaultDrawer]
public float nameYouWontSee;

// indented
[FieldOptions(indent:1)]
[DefaultDrawer]
public float horseman;

// hidden label
[FieldOptions(label:null)]
[DefaultDrawer]
public float unlabeledValue;

// use flags
[FieldOptions(useFLags:EFieldUsable.Play)]
[DefaultDrawer]
public float editableInPlayMode;

[InlineWidth]

Targets: field
🎚️ field|width

Supplies desired field width to [Inline] attribute. Can be placed on inlined field with name of child field, or on child field itself.

[InlineWidth("count", 40f)] // specific inner field
[Inline]
public InlineType inlined;

[Serializable]
struct InlineType
{
	public int count;
	public string text;
	[InlineWidth(40f)]
	public bool check;
}

[InlineHidden]

Targets: field

Marks specific field to be excluded from being inlined, effectively hiding it when [Inline] is used.

[Inline]
public InlineType inlined;

[Serializable]
struct InlineType
{
	public int count;
	public string text;
	[InlineHidden]
	public bool hideMe;
}

[DisplayIcon]

Targets: class|struct
🎚️ iconGUID|x|y|w|h

Declares display icon to be shown for type in drawers. Used for example by InstancedReference.


⚑ Decorators

Decorators are simple static elements drawn above fields.


[BoxHeader]

Draws large label inside outlined box above field.

[BoxHeader("My Section")]
public string documentedField1;

[BoxHeader("My Other Section", alignment:TextAnchor.MiddleCenter, style:FontStyle.Normal)]
public string documentedField2;


[Comment]

Draws comment paragraph above field.

[Comment("Something informative")]
public string documentedField;


[Alert]

Draws tinted alert with icon over field.

(Uses CSS Bootstrap-inspired colors.)

[Alert("I'm important!", EAlert.Error)]
[Alert("I'm mildly important.", EAlert.Warning)]
[Alert("I'm noteworthy.", EAlert.Info)]
public string documentedValue;


[Link]

🎚️ url|text

Draws link to external site above field.

[Link("https://www.reddit.com/r/lotrmemes/", "Serious Documentation")]
public string documentedField;


[Texture]

🎚️ guid

Draws image texture above field.

[Texture("3ccb9ff0b1390bf4e99bf4e25bb72ddc")]
public string documentedField;

[Divider]

🎚️ marginTop|marginBottom|color

Draws horizontal divider above field.

public string text;

[Divider]
public bool check;


[StaticButton]

🎚️ method|label|args

Draws button above field.

[StaticButton] works almost exactly as [FieldButton] with some limitations. Because it's a decorator, which has no knowledge of the field it's placed on, the method reference must be an absolute path to its type

[StaticButton("SayHi;StaticGreets, MyModule")]
[StaticButton("LogValue;StaticGreets, MyModule", label: "Log", args: new object[]{ 10 })]
public string buttonedField;

class StaticGreets
{
	public static void SayHi()
	{
		Debug.Log("Hello, wurst!");
	}

	public static void LogValue(int v)
	{
		Debug.Log("Your value is: " + v);
	}
}


⚑ Standalone

[FieldLabel]

Fields: any
🎚️ label

Overrides default label for field. Supplying null will hide it.

[FieldLabel("Custom Label")]
public string someField;

// hide label
[FieldLabel(null)]
public string fullWidthField;

[FieldIndent]

Fields: any
🎚️ indent

Adds extra indent to field.

[FieldIndent(1)]
public string indentedField;

Releases

Used by

Contributors

Languages