├── .gitignore ├── README.md ├── LICENSE └── Plugins └── HideIf ├── HideIfAttribute.cs ├── Editor ├── Utilities.cs └── HideIfAttributeDrawer.cs └── HideIfExampleScript.cs /.gitignore: -------------------------------------------------------------------------------- 1 | #no file interdependence, only scripts 2 | *.meta -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity_HideIf 2 | 3 | This project adds a small set of attributes with attached drawers for use in Unity. They allow you to conditionally hide fields in your MonoBehaviours based on the value of other fields. 4 | 5 | This is usefull when you have scripts with small variations, where only some variations need certain fields. 6 | 7 | ## Installation 8 | 9 | Drop everything in your Assets folder. The code is placed in Plugins/Hideif, and contains one script containing the attribute definitions, one script for the propertyDrawers for those attributes, and an example script. 10 | 11 | ## Example 12 | 13 | There's an example file in Plugins/HideIf/HideIfExampleScript.cs. You can safely delete it. Throw it on a GameObject somewhere to see it in action. 14 | 15 | ## Contributions 16 | 17 | Please. This is not meant to be a generalized editor utility package, but if you have fixes for corner cases or useful extensions you want to add (like HideIfInRange/HideIfOutsideRange for ints), go for it! 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Baste Nesse Buanes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Plugins/HideIf/HideIfAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using System.Collections; 4 | 5 | public class HidingAttribute : PropertyAttribute { } 6 | 7 | /// 8 | /// Hides a field if the bool 'variable' has the state 'state' 9 | /// 10 | [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = true)] 11 | public class HideIfAttribute : HidingAttribute { 12 | 13 | public readonly string variable; 14 | public readonly bool state; 15 | 16 | public HideIfAttribute(string variable, bool state, int order = 0) { 17 | this.variable = variable; 18 | this.state = state; 19 | this.order = order; 20 | } 21 | } 22 | 23 | /// 24 | /// Hides a field if the Object 'variable' is null 25 | /// 26 | [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = true)] 27 | public class HideIfNullAttribute : HidingAttribute { 28 | 29 | public readonly string variable; 30 | 31 | public HideIfNullAttribute(string variable, int order = 0) { 32 | this.variable = variable; 33 | this.order = order; 34 | } 35 | } 36 | 37 | /// 38 | /// Hides a field if the Object 'variable' is not null 39 | /// 40 | [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = true)] 41 | public class HideIfNotNullAttribute : HidingAttribute { 42 | 43 | public readonly string variable; 44 | 45 | public HideIfNotNullAttribute(string variable, int order = 0) { 46 | this.variable = variable; 47 | this.order = order; 48 | } 49 | } 50 | 51 | /// 52 | /// Hides a field based on it's enum value. 53 | /// use hideIf to specify if the variable must be equal to one of the attributes, or if it must be 54 | /// unequal to all of the attributes 55 | /// 56 | [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = true)] 57 | public class HideIfEnumValueAttribute : HidingAttribute { 58 | 59 | public readonly string variable; 60 | public readonly int[] states; 61 | public readonly bool hideIfEqual; 62 | 63 | public HideIfEnumValueAttribute(string variable, HideIf hideIf, params int[] states) { 64 | this.variable = variable; 65 | this.hideIfEqual = hideIf == HideIf.Equal; 66 | this.states = states; 67 | this.order = -1; 68 | } 69 | } 70 | 71 | public enum HideIf { 72 | Equal, 73 | NotEqual 74 | } 75 | -------------------------------------------------------------------------------- /Plugins/HideIf/Editor/Utilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using UnityEditor; 6 | 7 | namespace HideIf_Utilities 8 | { 9 | 10 | public class Utilities 11 | { 12 | public static object GetTargetObjectOfProperty(SerializedProperty prop) 13 | { 14 | var path = prop.propertyPath.Replace(".Array.data[", "["); 15 | object obj = prop.serializedObject.targetObject; 16 | var elements = path.Split('.'); 17 | foreach (var element in elements) 18 | { 19 | if (element.Contains("[")) 20 | { 21 | var elementName = element.Substring(0, element.IndexOf("[")); 22 | var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", "")); 23 | obj = GetValue_Imp(obj, elementName, index); 24 | } 25 | else 26 | { 27 | obj = GetValue_Imp(obj, element); 28 | } 29 | } 30 | return obj; 31 | } 32 | 33 | private static object GetValue_Imp(object source, string name) 34 | { 35 | if (source == null) 36 | return null; 37 | var type = source.GetType(); 38 | 39 | while (type != null) 40 | { 41 | var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); 42 | if (f != null) 43 | return f.GetValue(source); 44 | 45 | var p = type.GetProperty(name, 46 | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | 47 | BindingFlags.IgnoreCase); 48 | if (p != null) 49 | return p.GetValue(source, null); 50 | 51 | type = type.BaseType; 52 | } 53 | return null; 54 | } 55 | 56 | private static object GetValue_Imp(object source, string name, int index) 57 | { 58 | var enumerable = GetValue_Imp(source, name) as IEnumerable; 59 | if (enumerable == null) 60 | return null; 61 | var enm = enumerable.GetEnumerator(); 62 | 63 | for (int i = 0; i <= index; i++) 64 | { 65 | if (!enm.MoveNext()) 66 | return null; 67 | } 68 | return enm.Current; 69 | } 70 | } 71 | 72 | public static class Extensions 73 | { 74 | public static TValue GetOrAdd(this Dictionary dict, TKey key, Func constructor) 75 | { 76 | TValue value; 77 | if (dict.TryGetValue(key, out value)) 78 | { 79 | return value; 80 | } 81 | 82 | value = constructor(); 83 | dict[key] = value; 84 | return value; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Plugins/HideIf/HideIfExampleScript.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEditor; 5 | using UnityEngine; 6 | using Object = UnityEngine.Object; 7 | 8 | public class HideIfExampleScript : MonoBehaviour { 9 | 10 | public bool showS1; 11 | 12 | [HideIf("showS1", false)] 13 | public string s1 = "S1"; 14 | [HideIf("showS1", true)] 15 | public string s2 = "S2 instead"; 16 | 17 | [Space(10f)] 18 | public Object obj; 19 | 20 | [HideIfNotNull("obj")] 21 | public string objIsNull = "Shown as obj is null!"; 22 | 23 | [HideIfNull("obj")] 24 | public string objIsNotNull = "Shown as obj is not null!"; 25 | 26 | [Space(10f)] 27 | public TestEnum testEnum; 28 | 29 | [HideIfEnumValue("testEnum", HideIf.Equal, (int) TestEnum.Val1)] 30 | public string isNotVal1 = "Val 1 not selected"; 31 | 32 | [HideIfEnumValue("testEnum", HideIf.NotEqual, (int) TestEnum.Val1)] 33 | public string isVal1 = "Val 1 selected"; 34 | 35 | [HideIfEnumValue("testEnum", HideIf.Equal, (int) TestEnum.Val2, (int) TestEnum.Val3)] 36 | public string isNotVal2Or3 = "Neither Val 2 nor 3 are selected"; 37 | 38 | [HideIfEnumValue("testEnum", HideIf.NotEqual, (int) TestEnum.Val2, (int) TestEnum.Val3)] 39 | public string isVal2Or3 = "Val 2 or 3 are selected"; 40 | 41 | public enum TestEnum { 42 | Val1, 43 | Val2, 44 | Val3 45 | } 46 | 47 | //Showing that this works for PropertyDrawers, with inheritance 48 | public bool hide; 49 | 50 | public TestData a; 51 | [HideIf("hide", true)] 52 | public TestData b; 53 | [HideIf("hide", true)] 54 | public TestDataParent c; 55 | public TestDataParent d; 56 | 57 | } 58 | 59 | 60 | 61 | [Serializable] 62 | public class TestDataParent { 63 | public int a; 64 | public string b; 65 | } 66 | 67 | [Serializable] 68 | public class TestData : TestDataParent { 69 | 70 | } 71 | 72 | #if UNITY_EDITOR 73 | [CustomPropertyDrawer(typeof(TestDataParent), true)] 74 | public class TestDataDrawer : PropertyDrawer { 75 | 76 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { 77 | var startingX = position.x; 78 | 79 | position.height = EditorGUIUtility.singleLineHeight; 80 | position.width /= 2f; 81 | EditorGUI.LabelField(position, "WOO"); 82 | 83 | position.x = startingX + position.width; 84 | 85 | EditorGUI.PropertyField(position, property.FindPropertyRelative("a")); 86 | 87 | position.x = startingX; 88 | position.y += position.height + EditorGUIUtility.standardVerticalSpacing; 89 | 90 | EditorGUI.LabelField(position, "Hoo"); 91 | position.x = startingX + position.width; 92 | 93 | EditorGUI.PropertyField(position, property.FindPropertyRelative("b")); 94 | } 95 | 96 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { 97 | return base.GetPropertyHeight(property, label) * 2f; 98 | } 99 | } 100 | #endif 101 | -------------------------------------------------------------------------------- /Plugins/HideIf/Editor/HideIfAttributeDrawer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | using UnityEditor; 7 | using HideIf_Utilities; 8 | 9 | public abstract class HidingAttributeDrawer : PropertyDrawer { 10 | 11 | /// 12 | /// Checks if a property is set to be hidden by a HideIfAttribute. 13 | /// 14 | /// Usefull for other property drawers that should respect the HideIfAttribute 15 | /// 16 | public static bool CheckShouldHide(SerializedProperty property) { 17 | try { 18 | bool shouldHide = false; 19 | 20 | HidingAttribute[] attachedAttributes = 21 | (HidingAttribute[]) 22 | property.serializedObject.targetObject.GetType() 23 | .GetField(property.name) 24 | .GetCustomAttributes(typeof (HidingAttribute), false); 25 | 26 | foreach (var hider in attachedAttributes) { 27 | if (!ShouldDraw(property.serializedObject, hider)) { 28 | shouldHide = true; 29 | } 30 | } 31 | 32 | return shouldHide; 33 | } 34 | catch { 35 | return false; 36 | } 37 | } 38 | 39 | /// 40 | /// Type to PropertyDrawer types for that type 41 | /// 42 | private static Dictionary typeToDrawerType; 43 | 44 | /// 45 | /// PropertyDrawer types to instances of that type 46 | /// 47 | private static Dictionary drawerTypeToDrawerInstance; 48 | 49 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { 50 | if (!CheckShouldHide(property)) { 51 | if (typeToDrawerType == null) 52 | PopulateTypeToDrawer(); 53 | 54 | Type drawerType; 55 | var typeOfProp = Utilities.GetTargetObjectOfProperty(property).GetType(); 56 | if (typeToDrawerType.TryGetValue(typeOfProp, out drawerType)) { 57 | var drawer = drawerTypeToDrawerInstance.GetOrAdd(drawerType, () => CreateDrawerInstance(drawerType)); 58 | drawer.OnGUI(position, property, label); 59 | } 60 | else { 61 | EditorGUI.PropertyField(position, property, true); 62 | } 63 | } 64 | } 65 | 66 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { 67 | //Even if the property height is 0, the property gets margins of 1 both up and down. 68 | //So to truly hide it, we have to hack a height of -2 to counteract that! 69 | if (CheckShouldHide(property)) 70 | return -2; 71 | 72 | if (typeToDrawerType == null) 73 | PopulateTypeToDrawer(); 74 | 75 | Type drawerType; 76 | var typeOfProp = Utilities.GetTargetObjectOfProperty(property).GetType(); 77 | if (typeToDrawerType.TryGetValue(typeOfProp, out drawerType)) { 78 | var drawer = drawerTypeToDrawerInstance.GetOrAdd(drawerType, () => CreateDrawerInstance(drawerType)); 79 | return drawer.GetPropertyHeight(property, label); 80 | } 81 | return EditorGUI.GetPropertyHeight(property, label, true); 82 | } 83 | 84 | private PropertyDrawer CreateDrawerInstance(Type drawerType) { 85 | return (PropertyDrawer) Activator.CreateInstance(drawerType); 86 | } 87 | 88 | private void PopulateTypeToDrawer() { 89 | typeToDrawerType = new Dictionary(); 90 | drawerTypeToDrawerInstance = new Dictionary(); 91 | var propertyDrawerType = typeof (PropertyDrawer); 92 | var targetType = typeof (CustomPropertyDrawer).GetField("m_Type", BindingFlags.Instance | BindingFlags.NonPublic); 93 | var useForChildren = typeof (CustomPropertyDrawer).GetField("m_UseForChildren", BindingFlags.Instance | BindingFlags.NonPublic); 94 | 95 | var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()); 96 | 97 | foreach (Type type in types) { 98 | if (propertyDrawerType.IsAssignableFrom(type)) { 99 | var customPropertyDrawers = type.GetCustomAttributes(true).OfType().ToList(); 100 | foreach (var propertyDrawer in customPropertyDrawers) { 101 | var targetedType = (Type) targetType.GetValue(propertyDrawer); 102 | typeToDrawerType[targetedType] = type; 103 | 104 | var useThisForChildren = (bool) useForChildren.GetValue(propertyDrawer); 105 | if (useThisForChildren) { 106 | var childTypes = types.Where(t => targetedType.IsAssignableFrom(t) && t != targetedType); 107 | foreach (var childType in childTypes) { 108 | typeToDrawerType[childType] = type; 109 | } 110 | } 111 | } 112 | 113 | } 114 | } 115 | } 116 | 117 | private static bool ShouldDraw(SerializedObject obj, HidingAttribute hider) { 118 | var hideIf = hider as HideIfAttribute; 119 | if (hideIf != null) { 120 | return HideIfAttributeDrawer.ShouldDraw(obj, hideIf); 121 | } 122 | 123 | var hideIfNull = hider as HideIfNullAttribute; 124 | if (hideIfNull != null) { 125 | return HideIfNullAttributeDrawer.ShouldDraw(obj, hideIfNull); 126 | } 127 | 128 | var hideIfNotNull = hider as HideIfNotNullAttribute; 129 | if (hideIfNotNull != null) { 130 | return HideIfNotNullAttributeDrawer.ShouldDraw(obj, hideIfNotNull); 131 | } 132 | 133 | var hideIfEnum = hider as HideIfEnumValueAttribute; 134 | if (hideIfEnum != null) { 135 | return HideIfEnumValueAttributeDrawer.ShouldDraw(obj, hideIfEnum); 136 | } 137 | 138 | Debug.LogWarning("Trying to check unknown hider loadingType: " + hider.GetType().Name); 139 | return false; 140 | } 141 | 142 | } 143 | 144 | [CustomPropertyDrawer(typeof (HideIfAttribute))] 145 | public class HideIfAttributeDrawer : HidingAttributeDrawer { 146 | public static bool ShouldDraw(SerializedObject obj, HideIfAttribute attribute) { 147 | var prop = obj.FindProperty(attribute.variable); 148 | if (prop == null) { 149 | return true; 150 | } 151 | return prop.boolValue != attribute.state; 152 | } 153 | } 154 | 155 | [CustomPropertyDrawer(typeof (HideIfNullAttribute))] 156 | public class HideIfNullAttributeDrawer : HidingAttributeDrawer { 157 | public static bool ShouldDraw(SerializedObject obj, HideIfNullAttribute hideIfNullAttribute) { 158 | var prop = obj.FindProperty(hideIfNullAttribute.variable); 159 | if (prop == null) { 160 | return true; 161 | } 162 | 163 | return prop.objectReferenceValue != null; 164 | } 165 | } 166 | 167 | [CustomPropertyDrawer(typeof (HideIfNotNullAttribute))] 168 | public class HideIfNotNullAttributeDrawer : HidingAttributeDrawer { 169 | public static bool ShouldDraw(SerializedObject obj, HideIfNotNullAttribute hideIfNotNullAttribute) { 170 | var prop = obj.FindProperty(hideIfNotNullAttribute.variable); 171 | if (prop == null) { 172 | return true; 173 | } 174 | 175 | return prop.objectReferenceValue == null; 176 | } 177 | } 178 | 179 | [CustomPropertyDrawer(typeof (HideIfEnumValueAttribute))] 180 | public class HideIfEnumValueAttributeDrawer : HidingAttributeDrawer { 181 | public static bool ShouldDraw(SerializedObject obj, HideIfEnumValueAttribute hideIfEnumValueAttribute) { 182 | var enumProp = obj.FindProperty(hideIfEnumValueAttribute.variable); 183 | var states = hideIfEnumValueAttribute.states; 184 | 185 | //enumProp.enumValueIndex gives the order in the enum list, not the actual enum value 186 | bool equal = states.Contains(enumProp.intValue); 187 | 188 | return equal != hideIfEnumValueAttribute.hideIfEqual; 189 | } 190 | } 191 | --------------------------------------------------------------------------------