├── .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 |
--------------------------------------------------------------------------------