Tools, custom attributes, drawers, hierarchy overlay, and other extensions for the Unity Editor.
Tools, custom attributes, drawers, hierarchy overlay, and other extensions for the Unity Editor.
Improve usability and clarity of key features in Unity Editor for better workflow!
This Toolbox not only extends functionalities, it does so with the user in mind. Written to be as flexible and optimized as possible. Now you and other programming professionals will be able to create a readable and useful component editor simply by using attributes. You’ll get fast and clear access to data from GameObjects placed in the Scene. Lastly, you’ll gain more control over the Project window. Go ahead, customize those folder icons.
It's worth to mention that prepared drawers are based on the custom, layout-based system. Additionally, I’m leaving you some useful scripts, classes, and functions that facilitate Editor extensions development.
Learn all the details about the main features below.
Unity 2018.x or newer
https://github.com/arimger/Unity-Editor-Toolbox.git#upm
Assets/Editor Toolbox directory into your project (Assets/...) + add dependenciesopenupm add com.browar.editor-toolbox
[!IMPORTANT]
This package is fully IMGUI-based, which means it may conflict with pure UI Toolkit features in your project. Additionally, Toolbox overwrites the 'base' custom Editor for allUnityEngine.Objects, it's a common solution but means that you can't combine other Inspector extensions/plugins.
The most important file, allows the user to manage all available features. Can be accessed from the Project Settings window (Edit/Project Settings.../Editor Toolbox) or directly inside the Project window. Make sure to have one valid settings file per project.
Available features are divided into four groups:
Each module is described in its respective section.
If you want to keep your custom settings between UET versions, create your own settings file:
Create/Editor Toolbox/Settings
[!IMPORTANT]
If you are getting warnings related to the current settings state, it most likely means that some features are not present in your Unity version. I suggest creating your own settings file and adjusting potential issues. Generally, it's always better to use a custom settings file rather than the default one. I'm planning to replace the ScriptableObject-based solution in the future, so it won't be a problem anymore.
Drawers based on built-in classes PropertyDrawer/DecoratorDrawer and associated PropertyAttribute. Regular drawers have priority over Toolbox drawers and they cannot be mixed.
Supported types: string.
[TagSelector]
public string var1;
Supported types: int, float, double.
[ProgressBar("Name", minValue: 0.0f, maxValue: 100.0f, HexColor = "#EB7D34", IsInteractable = true)]
public float var1 = 80.0f;
\
Supported types: Vector2, Vector2Int.
[MinMaxSlider(0.5f, 71.7f)]
public Vector2 var1;
Supported types: UnityEngine.Object.
[AssetPreview]
public GameObject var1;
[AssetPreview(useLabel: false)]
public Component var2;
Supported types: all.
[Suffix("cm")]
public string var1;
Supported types: Enums.
[System.Flags]
public enum FlagExample
{
Nothing = 0,
Flag1 = 1,
Flag2 = 2,
Flag3 = 4,
Flag4 = 8,
Flag5 = 16,
Flag6 = 32,
Flag7 = 64,
Flag8 = 128,
Flag9 = 256,
Everything = ~0
}
[EnumToggles]
public FlagExample enumFlag = FlagExample.Flag1 | FlagExample.Flag2 | FlagExample.Flag6;
Supported types: UnityEngine.Object.
[NotNull]
public GameObject var1;
\
Supported types: string.
[Directory]
public string var1;
\
Supported types: string.
[SceneName]
public string sceneName;
\
Supported types: all.
Remark: can be used only within classes, structs are not supported.
private readonly int[] presetValues = new[] { 1, 2, 3, 4, 5 };
[Preset(nameof(presetValues))]
public int presetTarget;
private readonly int[] presetValues = new[] { 1, 2, 3, 4, 5 };
private readonly string[] optionLabels = new[] { "a", "b", "c", "d", "e" };
[Preset(nameof(presetValues), nameof(optionLabels))]
public int presetTarget;
Supported types: Enums.
[SearchableEnum]
public KeyCode enumSearch;
Supported types: int, float, double.
[Clamp(minValue = 1.5f, maxValue = 11.3f)]
public double var1;
Supported types: string.
[Password]
public string password;
Supported types: bool.
[LeftToggle]
public bool var1;
Supported types: int, float, double.
[FormattedNumber]
public int bigNumber;
Supported types: int.
[Layer]
public int layer;
Supported types: AnimationCurve.
[AnimationCurveSettings(-2, -2, 2, 2, HexColor = "#FFD666")]
public AnimationCurve animationCurve
Supported types: GameObject, Component.
[ChildObjectOnlyAttribute]
public GameObject var1
Supported types: GameObject, Component.
[SceneObjectOnlyAttribute]
public GameObject var1
Supported types: GameObject, Component.
[PrefabObjectOnlyAttribute]
public GameObject var1
Supported types: GameObject, Component.
[NotPrefabObjectOnlyAttribute]
public GameObject var1
Drawers are based on classes inherited from the ToolboxDrawer class and associated ToolboxAttribute. With this powerful custom system you are able to create really flexible drawers. You can use them without limitations (they work with sub-classes and as array children). Every ToolboxDrawer is layout-based. For proper work they need at least one settings file located in your project. You can find predefined one here - Editor Toolbox/EditorSettings.asset.
Examples 'How to' create custom ToolboxDrawers you can find HERE.
Display/create something before and after property in the desired order (using Order property).
In fact ToolboxDecoratorDrawers are like extended version of built-in DecoratorDrawers.
Unfortunately, standard decorators won't always work with ToolboxDrawers so try to use this replacement instead.
Each ToolboxDecoratorAttribute has two basic properties Order (indicates the drawing order) and ApplyCondition (determines if decorator will be disabled/hidden along with associated property).
[BeginGroup("Group1", Style = GroupStyle.Round)]
public int var1;
[EndGroup]
public int var2;
//NOTE: you can use [SpaceArea] to adjust positions between layout elements
[BeginHorizontal(LabelWidth = 50.0f)]
public int var1;
[EndHorizontal]
public int var2;
[BeginHorizontalGroup(Label = "Horizontal Group", ControlFieldWidth = true, ElementsInLayout = 2)]
public GameObject gameObject;
[SpaceArea]
[EndHorizontalGroup]
[ReorderableList]
public int[] ints;
[BeginIndent]
public int var1;
[EndIndent]
public int var2;
[IndentArea(4)]
public int var1;
[SpaceArea(spaceBefore = 10.0f, spaceAfter = 5.0f, Order = 1)]
public int var1;
[Label("My Custom Header", skinStyle: SkinStyle.Box, Alignment = TextAnchor.MiddleCenter)]
public int var1;
[Highlight(0, 1, 0)]
public int var1;
[EditorButton(nameof(MyMethod), "<b>My</b> Custom Label", activityType: ButtonActivityType.OnPlayMode, ValidateMethodName = nameof(ValidationMethod), PositionType = ButtonPositionType.Above)]
public int var1;
private void MyMethod()
{
Debug.Log("MyMethod is invoked");
}
private bool ValidationMethod()
{
return var1 == 0;
}
[Help("Help information", UnityMessageType.Warning, Order = -1)]
public int var1;
[DynamicHelp(nameof(Message), UnityMessageType.Error)]
public int var2;
public string Message => "Dynamic Message";
[ImageArea("https://img.itch.zone/aW1nLzE5Mjc3NzUucG5n/original/Viawjm.png", 150.0f)]
public int var1;
[LabelWidth(220.0f)]
public int veryVeryVeryVeryVeryLongName;
[BeginTabGroup(groupId: "main_group")]
[Tab(tab: "General")]
public string characterName;
[Tab(tab: "Movement")]
public float moveSpeed;
[Tab(tab: "Movement")]
public float jumpForce;
[Tab(tab: "Attack")]
public Vector2 attackForce;
[Tab(tab: "Attack")]
[EndTabGroup]
public int attackDamage;
Enable/disable or show/hide properties using custom conditions. You can use them together with any other type of drawer. Every ToolboxConditionDrawer supports boolean, int, string, UnityEngine.Object and enum types and works even with array/list properties. You are able to pass values from fields, properties, and methods.
public string StringValue => "Sho";
[ShowIf(nameof(StringValue), "show")]
public int var1;
public GameObject objectValue;
[HideIf(nameof(objectValue), false)]
public int var2;
public KeyCode enumValue = KeyCode.A;
[EnableIf(nameof(enumValue), KeyCode.A)]
public int var1;
[DisableIf(nameof(GetFloatValue), 2.0f, Comparison = UnityComparisonMethod.GreaterEqual)]
public int var2;
public float GetFloatValue()
{
return 1.6f;
}
[DisableInPlayMode]
public int var1;
No open issues yet, or sync has not completed.