/// <summary> /// Helper function that just ignores a few FI internal types for serialization since the /// backup solution serializes all inspected properties, not just those that are serialized /// </summary> private static bool ShouldIgnoreForPersist(InspectedProperty property) { string name = property.Name; return name.Contains("ISerializedObject.") || name == "_objectReferences" || name == "_serializedStateKeys" || name == "_serializedStateValues" || name == "_restored"; }
/// <summary> /// Reverts the given property on the instance to the prefab value. /// </summary> /// <param name="instance">The prefab instance to revert the value on.</param> /// <param name="property">The property to revert.</param> public static void RevertValue(object instance, InspectedProperty property) { // We only want top-level components if (instance is MonoBehaviour == false) { return; } // Not a prefab var prefabGameObject = (GameObject)PrefabUtility.GetPrefabParent(((MonoBehaviour)instance).gameObject); if (prefabGameObject == null) { return; } // Get all of the property modifications on the object. If there are no property // modifications, then there is nothing to revert. PropertyModification[] mods = PrefabUtility.GetPropertyModifications((UnityObject)instance); if (mods == null) { return; } ISerializedObject serializedInstance = (ISerializedObject)instance; bool removed = false; for (int i = 0; i < mods.Length; ++i) { PropertyModification mod = mods[i]; // A property modification can take one of two forms. It can either be modifying a // Unity serialized value or a Full Inspector serialized value. // Check to see if it's a Full Inspector serialized value. If it is, then we lookup // the key that the modification is associated with and, if we find said key, and // that the key is equal to the property we are checking for, then we return true. string serializedPropertyName; if (TryExtractPropertyName(serializedInstance, mod, out serializedPropertyName) && serializedPropertyName == property.Name) { removed = true; } // Check to see if it is a Unity serialized value. We have to do a dotted comparison // because the propertyPath may be associated with, ie, an array, which in that case // the path is something like "values.Array._items[0]" while property.Name is just // "values". if (ContainsPropertyName(mod.propertyPath, property.Name)) { removed = true; } if (removed) { ArrayUtility.RemoveAt(ref mods, i); PrefabUtility.SetPropertyModifications((UnityObject)instance, mods); break; } } }
private void EditProperty(ref Rect region, object element, InspectedProperty property) { if (!ReflectedPropertyEditor.ShowProperty(property)) { return; } bool flag = ReflectedPropertyEditor.HasPrefabDiff(element, property); if (flag) { UnityInternalReflection.SetBoldDefaultFont(true); } TooltipAttribute attribute = property.MemberInfo.GetAttribute<TooltipAttribute>(); GUIContent label = new GUIContent(DisplayNameMapper.Map(property.Name), (attribute != null) ? attribute.Tooltip : ""); PropertyEditorChain propertyEditorChain = PropertyEditor.Get(property.StorageType, property.MemberInfo); IPropertyEditor firstEditor = propertyEditorChain.FirstEditor; object obj = property.Read(element); float elementHeight = firstEditor.GetElementHeight(label, obj); Rect rect = new Rect(region); rect.height = elementHeight; float num = 0f; ReflectedPropertyEditor.StateObject stateObject = ObjectMetadata<ReflectedPropertyEditor.StateObject>.Get(obj); if (elementHeight > 80f && ReflectedPropertyEditor.CanShowFoldout(property.StorageType)) { GUIContent gUIContent = stateObject.Foldout ? GUIContent.none : firstEditor.GetFoldoutHeader(label, obj); Rect rect2 = rect; rect2.height = EditorStyles.foldout.CalcHeight(gUIContent, 100f); rect2.width = EditorStyles.foldout.CalcSize(gUIContent).x; stateObject.Foldout = EditorGUI.Foldout(rect2, stateObject.Foldout, gUIContent); num = EditorStyles.foldout.CalcHeight(gUIContent, 100f); } if (stateObject.Foldout) { object value = firstEditor.Edit(rect, label, obj); property.Write(element, value); num = elementHeight; } region.y = region.y + num; region.y = region.y + 2f; if (flag) { UnityInternalReflection.SetBoldDefaultFont(false); } }
private static bool ShowProperty(InspectedProperty property) { return property.MemberInfo.GetAttribute<HideInInspector>() == null && (property.MemberInfo.GetAttribute<ShowInInspectorAttribute>() != null || (FullInspectorSettings.InspectorAutomaticallyShowPublicProperties && property.IsPublic)); }
private static bool HasPrefabDiff(object instance, InspectedProperty property) { if (!(instance is MonoBehaviour)) { return false; } GameObject gameObject = (GameObject)PrefabUtility.GetPrefabParent(((MonoBehaviour)instance).gameObject); if (gameObject == null) { return false; } Component component = gameObject.GetComponent(instance.GetType()); if (component == null) { return true; } PropertyModification[] propertyModifications = PrefabUtility.GetPropertyModifications((UnityEngine.Object)instance); if (propertyModifications == null) { return false; } ISerializedObject obj = (ISerializedObject)instance; PropertyModification[] array = propertyModifications; int i = 0; while (i < array.Length) { PropertyModification propertyModification = array[i]; string a; bool result; if (ReflectedPropertyEditor.TryExtractPropertyName(obj, propertyModification, out a) && a == property.Name) { result = true; } else { if (!ReflectedPropertyEditor.ContainsPropertyName(propertyModification.propertyPath, property.Name)) { i++; continue; } result = true; } return result; } return false; }
/// <summary> /// Returns true if the given property on the given object instance has a prefab override. /// </summary> /// <param name="instance">The object instance.</param> /// <param name="property">The property to check.</param> /// <returns>True if the property is prefab override, false otherwise.</returns> /// <remarks> /// Currently, this method only works for MonoBehavior targets. /// </remarks> public static bool HasPrefabDiff(object instance, InspectedProperty property) { // For prefab differences, we rely upon the internal Unity mechanisms for identifying // when an object has a prefab diff. We are able to do this because we only support // top-level prefab differences. // // One of the current issues with this mechanism is when an array is serialized by // Unity, and only part of the array tracks the prefab, then the inspector will show the // entire array in bold (when only the one part should be). // We only want top-level components if (instance is MonoBehaviour == false) { return false; } // If there is no prefab, then we don't show anything in bold. var prefabGameObject = (GameObject)PrefabUtility.GetPrefabParent(((MonoBehaviour)instance).gameObject); if (prefabGameObject == null) { return false; } // If the prefab doesn't have this component, then the entire component should be in // bold. var prefab = prefabGameObject.GetComponent(instance.GetType()); if (prefab == null) { return true; } // Get all of the property modifications on the object. If there are no property // modifications, then nothing should be in bold. PropertyModification[] mods = PrefabUtility.GetPropertyModifications((UnityObject)instance); if (mods == null) { return false; } ISerializedObject serializedInstance = (ISerializedObject)instance; foreach (PropertyModification mod in mods) { // A property modification can take one of two forms. It can either be modifying a // Unity serialized value or a Full Inspector serialized value. // Check to see if it's a Full Inspector serialized value. If it is, then we lookup // the key that the modification is associated with and, if we find said key, and // that the key is equal to the property we are checking for, then we return true. string serializedPropertyName; if (TryExtractPropertyName(serializedInstance, mod, out serializedPropertyName) && serializedPropertyName == property.Name) { return true; } // Check to see if it is a Unity serialized value. We have to do a dotted comparison // because the propertyPath may be associated with, ie, an array, which in that case // the path is something like "values.Array._items[0]" while property.Name is just // "values". if (ContainsPropertyName(mod.propertyPath, property.Name)) { return true; } } return false; }
public static void EditProperty(Rect region, object container, InspectedProperty property, fiGraphMetadataChild metadata) { EditorGUI.BeginChangeCheck(); object propertyValue = property.Read(container); object updatedValue = EditPropertyDirect(region, property, propertyValue, metadata, container); if (EditorGUI.EndChangeCheck()) { property.Write(container, updatedValue); // Make sure we propagate the changes up the edit stack. For // example, if this property is on a struct on a struct, then the // top-level struct will not get modified without propagation of // the change check. GUI.changed = true; } }
private static void RevertPrefabContextMenu(Rect region, object context, InspectedProperty property) { if (Event.current.type == EventType.ContextClick && region.Contains(Event.current.mousePosition) && // This can be a relatively heavy function call, so we check it // last. If the rect bounds check ends up consuming lots of time, // then HasPrefabDiff has a small fast-path section that can // short-circuit the bounds check. fiPrefabTools.HasPrefabDiff(context, property)) { Event.current.Use(); var content = new GUIContent("Revert " + property.DisplayName + " to Prefab Value"); GenericMenu menu = new GenericMenu(); menu.AddItem(content, /*on:*/false, () => { fiPrefabTools.RevertValue(context, property); }); menu.ShowAsContext(); } }
public static float EditPropertyHeightDirect(InspectedProperty property, object propertyValue, fiGraphMetadataChild metadataChild) { fiGraphMetadata metadata = metadataChild.Metadata; var editor = PropertyEditor.Get(property.StorageType, property.MemberInfo).FirstEditor; GUIContent propertyLabel = new GUIContent(property.DisplayName); // Either the foldout is active or we are not displaying a foldout. // Either way, we want to report the full height of the property. return editor.GetElementHeight(propertyLabel, propertyValue, metadata.Enter("EditProperty", metadata.Context)); }
public static float EditPropertyHeight(object container, InspectedProperty property, fiGraphMetadataChild metadata) { object propertyValue = property.Read(container); return EditPropertyHeightDirect(property, propertyValue, metadata); }
/// <summary> /// Draws a GUI for editing the given property and returns the updated /// value. This does /// *not* write the updated value to a container. /// </summary> /// <param name="context"> /// An optional context that the property value came from. If this is not /// given, then a prefab context menu will not be displayable. /// </param> public static object EditPropertyDirect(Rect region, InspectedProperty property, object propertyValue, fiGraphMetadataChild metadataChild, object context) { fiGraphMetadata metadata = metadataChild.Metadata; // Show a "revert to prefab" value context-menu if possible if (context != null) { RevertPrefabContextMenu(region, context, property); } // get the label / tooltip GUIContent label = new GUIContent(property.DisplayName, InspectorTooltipAttribute.GetTooltip(property.MemberInfo)); var editorChain = PropertyEditor.Get(property.StorageType, property.MemberInfo); IPropertyEditor editor = editorChain.FirstEditor; EditorGUI.BeginDisabledGroup(property.CanWrite == false); propertyValue = editor.Edit(region, label, propertyValue, metadata.Enter("EditProperty", metadata.Context)); EditorGUI.EndDisabledGroup(); return propertyValue; }
/// <summary> /// Draws a GUI for editing the given property and returns the updated /// value. This does /// *not* write the updated value to a container. /// </summary> public static object EditPropertyDirect(Rect region, InspectedProperty property, object propertyValue, fiGraphMetadataChild metadataChild) { return EditPropertyDirect(region, property, propertyValue, metadataChild, null); }
/// <summary> /// A helper method that draws the inspector for a field/property at the given location. /// </summary> private void EditProperty(ref Rect region, object element, InspectedProperty property, fiGraphMetadata metadata) { bool hasPrefabDiff = fiPrefabTools.HasPrefabDiff(element, property); if (hasPrefabDiff) fiUnityInternalReflection.SetBoldDefaultFont(true); // edit the property { var childMetadata = metadata.Enter(property.Name); fiGraphMetadataCallbacks.PropertyMetadataCallback(childMetadata.Metadata, property); Rect propertyRect = region; float propertyHeight = fiEditorGUI.EditPropertyHeight(element, property, childMetadata); propertyRect.height = propertyHeight; fiEditorGUI.EditProperty(propertyRect, element, property, childMetadata); region.y += propertyHeight; } if (hasPrefabDiff) fiUnityInternalReflection.SetBoldDefaultFont(false); }
public bool Equals(InspectedProperty p) { return p != null && this.StorageType == p.StorageType && this.Name == p.Name; }