private Texture GetIcon(AutoPopulateAttribute autoPopulate, bool populated) { Texture foundIcon = null; Texture missingIcon = null; switch (autoPopulate.Find) { case AutoPopulateAttribute.FindBehaviour.Self: foundIcon = FindSelfIcon; missingIcon = MissingSelfIcon; break; case AutoPopulateAttribute.FindBehaviour.Children: foundIcon = FindChildrenIcon; missingIcon = MissingChildrenIcon; break; case AutoPopulateAttribute.FindBehaviour.Parent: foundIcon = FindParentsIcon; missingIcon = MissingParentsIcon; break; default: throw new ArgumentOutOfRangeException(); } if (populated) { return(foundIcon); } return(missingIcon); }
private bool CanAutoPopulate(SerializedProperty property, AutoPopulateAttribute autoPopulate) { if (autoPopulate == null) { return(false); } if (property.isArray) { return(false); // Disable array support for now, // Unity doesn't call the drawer for the array, it calls it for the elements in the array :( } if (property.propertyPath.EndsWith("]")) { return(false); // as above, we use the ] char as a sign that Unity is trying to edit an array element } if (property.propertyType == SerializedPropertyType.ObjectReference) { return(true); } if (AutoPopulateUtils.IsInterfaceReference(property, fieldInfo.FieldType)) { return(true); } return(false); }
public static void AutoPopulate(SerializedObject so, bool forceRepopulate = false, IErrorReport report = null) { SerializedProperty prop = so.GetIterator(); if (prop.hasChildren) { while (prop.Next(true)) { FieldInfo fieldInfo = PropertyUtils.GetFieldInfoFromProperty(prop); if (fieldInfo != null) { AutoPopulateAttribute attribute = GetAutoPopulateAttribute(fieldInfo); if (attribute != null) { bool needsPopulating = NeedsPopulating(prop, fieldInfo.FieldType); if (forceRepopulate || needsPopulating) { if (report != null) { report.Log(so.targetObject, "Repopulating {0}.{1}", so.targetObject.FullName(), prop.propertyPath); } PopulateValue(fieldInfo.FieldType, prop, attribute); } else { if (report != null) { report.Log(so.targetObject, "Skipping {0}.{1}", so.targetObject.FullName(), prop.propertyPath); } } } } } } }
private static AutoPopulateAttribute GetAutoPopulateAttribute(FieldInfo fieldInfo) { object[] attribs = fieldInfo.GetCustomAttributes(typeof(AutoPopulateAttribute), true); if (attribs != null && attribs.Length > 0) { AutoPopulateAttribute attribute = attribs[0] as AutoPopulateAttribute; return(attribute); } return(null); }
private void ForceRepopulate(object data) { SerializedProperty property = data as SerializedProperty; AutoPopulateAttribute autoPopulate = attribute as AutoPopulateAttribute; if ((property != null) && (autoPopulate != null)) { property.serializedObject.Update(); AutoPopulateUtils.PopulateValue(fieldInfo.FieldType, property, autoPopulate); property.serializedObject.ApplyModifiedProperties(); } }
private void HandlePopup(Rect position, SerializedProperty property, AutoPopulateAttribute autoPopulate) { Event e = Event.current; if ((e.type == EventType.MouseUp) && (e.button == 1)) { if (position.Contains(e.mousePosition)) { bool editable = false; bool canChangeEditable = false; switch (autoPopulate.Editable) { case AutoPopulateAttribute.EditBehaviour.ReadOnlyUntilUserAction: editable = GetEditable(property, autoPopulate); canChangeEditable = true; break; case AutoPopulateAttribute.EditBehaviour.Never: editable = false; canChangeEditable = false; break; case AutoPopulateAttribute.EditBehaviour.Always: editable = true; canChangeEditable = false; break; default: throw new ArgumentOutOfRangeException(); } GUI.FocusControl(null); GenericMenu menu = new GenericMenu(); if (editable) { menu.AddItem(MakeReadonlyLabel, false, canChangeEditable ? MakeReadonly : (GenericMenu.MenuFunction2)null, property); } else { menu.AddItem(MakeEditableLabel, false, canChangeEditable ? MakeEditable : (GenericMenu.MenuFunction2)null, property); } menu.AddItem(ForceRepopulateLabel, false, ForceRepopulate, property); menu.ShowAsContext(); e.Use(); } } }
public static Type GetSearchType(Type fieldType, AutoPopulateAttribute autoPopulate) { Type searchType = fieldType; Type interfaceType = InterfaceReferenceDrawer.GetInterfaceType(searchType); if (interfaceType != null) { searchType = interfaceType; } if (autoPopulate.TypeOverride != null) { searchType = autoPopulate.TypeOverride; } return(searchType); }
private string GetTooltip(SerializedProperty property, AutoPopulateAttribute autoPopulate) { Type searchType; if (property.isArray) { searchType = AutoPopulateUtils.GetSearchType(fieldInfo.FieldType.GetElementType(), autoPopulate); } else { searchType = AutoPopulateUtils.GetSearchType(fieldInfo.FieldType, autoPopulate); } string relativeTo = ""; if (autoPopulate.FindRelativeTo != null) { string componentName = autoPopulate.FindRelativeTo.Name; string componentArticle; if (IsVowel(componentName[0])) { componentArticle = "an"; } else { componentArticle = "a"; } relativeTo = string.Format(" on the first parent with {0} {1} component", componentArticle, autoPopulate.FindRelativeTo.Name); } switch (autoPopulate.Find) { case AutoPopulateAttribute.FindBehaviour.Self: return(string.Format("Auto-populated by calling gameObject.GetComponent({0}){1}", searchType.Name, relativeTo)); case AutoPopulateAttribute.FindBehaviour.Children: return(string.Format("Auto-populated by calling gameObject.GetComponentInChildren({0}){1}", searchType.Name, relativeTo)); case AutoPopulateAttribute.FindBehaviour.Parent: return(string.Format("Auto-populated by calling gameObject.GetComponentInParent({0}){1}", searchType.Name, relativeTo)); default: throw new ArgumentOutOfRangeException(); } }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { AutoPopulateAttribute autoPopulate = attribute as AutoPopulateAttribute; if (CanAutoPopulate(property, autoPopulate)) { bool wasEnabled = GUI.enabled; GUI.enabled = GetEditable(property, autoPopulate); bool populated = false; if (AutoPopulateUtils.NeedsPopulating(property, fieldInfo.FieldType)) { populated = AutoPopulateUtils.PopulateValue(fieldInfo.FieldType, property, autoPopulate); } else { populated = true; } GUIContent tweakedLabel = new GUIContent(label.text, GetIcon(autoPopulate, populated), GetTooltip(property, autoPopulate)); if (AutoPopulateUtils.IsInterfaceReference(property, fieldInfo.FieldType)) { InterfaceReferenceDrawer.PropertyField(position, property, fieldInfo, tweakedLabel); } else { EditorGUI.PropertyField(position, property, tweakedLabel); } GUI.enabled = wasEnabled; HandlePopup(position, property, autoPopulate); } else { GUIContent tweakedLabel = new GUIContent(label.text, ErrorIcon, GetErrorTooltip()); EditorGUI.PropertyField(position, property, tweakedLabel); } }
private bool GetEditable(SerializedProperty property, AutoPopulateAttribute autoPopulate) { bool editable = true; switch (autoPopulate.Editable) { case AutoPopulateAttribute.EditBehaviour.ReadOnlyUntilUserAction: editable = GetEditableInstance(property); break; case AutoPopulateAttribute.EditBehaviour.Never: editable = false; break; case AutoPopulateAttribute.EditBehaviour.Always: editable = true; break; default: throw new ArgumentOutOfRangeException(); } return(editable); }
private static bool PopulateValueSingle(Type fieldType, SerializedProperty property, AutoPopulateAttribute autoPopulate) { Object value = null; Type searchType = GetSearchType(fieldType, autoPopulate); foreach (Object targetObject in property.serializedObject.targetObjects) { MonoBehaviour behaviour = targetObject as MonoBehaviour; if (behaviour == null) { XDebug.LogWarning(targetObject, "Couldn't find target behaviour on {0}.", targetObject); continue; } SerializedObject singleObject = new SerializedObject(targetObject); SerializedProperty singleProperty = singleObject.FindProperty(property.propertyPath); if (singleProperty == null) { XDebug.LogWarning(behaviour, "Couldn't find {0} property for {1}", property.propertyPath, behaviour); continue; } Transform root = FindRoot(behaviour.gameObject, autoPopulate.FindRelativeTo); if (root == null) { continue; } switch (autoPopulate.Find) { case AutoPopulateAttribute.FindBehaviour.Self: value = FindObjectInSelf(root, searchType); break; case AutoPopulateAttribute.FindBehaviour.Children: value = FindObjectInChildren(root, searchType); break; case AutoPopulateAttribute.FindBehaviour.Parent: value = FindObjectInParent(root, searchType); break; default: throw new ArgumentOutOfRangeException(); } SetValue(singleProperty, fieldType, value); singleObject.ApplyModifiedProperties(); } if (value != null) { property.serializedObject.SetIsDifferentCacheDirty(); } return(value != null); }
private static bool PopulateValueArray(Type fieldType, SerializedProperty property, AutoPopulateAttribute autoPopulate) { Object[] values = null; Type elementType = fieldType.GetElementType(); Type searchType = GetSearchType(elementType, autoPopulate); foreach (Object targetObject in property.serializedObject.targetObjects) { MonoBehaviour behaviour = targetObject as MonoBehaviour; if (behaviour == null) { XDebug.LogWarning(targetObject, "Couldn't find target behaviour on {0}.", targetObject); continue; } SerializedObject singleObject = new SerializedObject(targetObject); SerializedProperty singleProperty = singleObject.FindProperty(property.propertyPath); if (singleProperty == null) { XDebug.LogWarning(behaviour, "Couldn't find {0} property for {1}", property.propertyPath, behaviour); continue; } Transform root = FindRoot(behaviour.gameObject, autoPopulate.FindRelativeTo); if (root == null) { XDebug.LogWarning(behaviour, "Couldn't find root object for {0}.", behaviour.gameObject); continue; } switch (autoPopulate.Find) { case AutoPopulateAttribute.FindBehaviour.Self: values = FindObjectsInSelf(root, searchType); break; case AutoPopulateAttribute.FindBehaviour.Children: values = FindObjectsInChildren(root, searchType); break; case AutoPopulateAttribute.FindBehaviour.Parent: values = FindObjectsInParent(root, searchType); break; default: throw new ArgumentOutOfRangeException(); } singleProperty.arraySize = values.Length; for (int i = 0; i < values.Length; i++) { SerializedProperty element = singleProperty.GetArrayElementAtIndex(i); SetValue(element, elementType, values[i]); element.objectReferenceValue = values[i]; } singleObject.ApplyModifiedProperties(); } if (values != null && values.Length > 0) { property.serializedObject.SetIsDifferentCacheDirty(); } return(values != null && values.Length > 0); }
public static bool PopulateValue(Type fieldType, SerializedProperty property, AutoPopulateAttribute autoPopulate) { bool populated = false; if (!property.hasMultipleDifferentValues) { if (property.isArray) { populated = PopulateValueArray(fieldType, property, autoPopulate); } else if (property.propertyType == SerializedPropertyType.ObjectReference || IsInterfaceReference(property, fieldType)) { populated = PopulateValueSingle(fieldType, property, autoPopulate); } } return(populated); }