/// <summary> /// Returns true if the property type itself is inspectable. This does not necessarily /// mean that the property should be displayed in the inspector -- just that the FI editing /// engine can handle it. /// </summary> private static bool IsPropertyTypeInspectable(InspectedProperty property) { // We never inspect delegates if (typeof(Delegate).IsAssignableFrom(property.StorageType)) { return(false); } if (property.MemberInfo is FieldInfo) { // Don't inspect compiler generated fields (an example would be a backing field // for an automatically generated property). if (property.MemberInfo.IsDefined(typeof(CompilerGeneratedAttribute), /*inherit:*/ false)) { return(false); } } else if (property.MemberInfo is PropertyInfo) { var propertyInfo = (PropertyInfo)property.MemberInfo; // If we cannot read from the property, then there is no sense in displaying it -- // we will have no value to display if (propertyInfo.CanRead == false) { return(false); } // hack?: We only display r/w properties declared on Unity types // note: This may rely on the fact that we collect members locally per inheritance // level (does DeclaringType change? I'm not sure). // note: We also check for UnityEditor since some users use FI in non-standard // ways -- ie, potentially for types that are not available at runtime and // hence may be in the UnityEditor namespace. var @namespace = propertyInfo.DeclaringType.Namespace; if (@namespace != null && (@namespace.StartsWith("UnityEngine") || @namespace.StartsWith("UnityEditor"))) { if (propertyInfo.CanWrite == false) { return(false); } } // If the property is named "Item", it might be the this[int] indexer, which in that // case we don't serialize it We cannot just compare with "Item" because of explicit // interfaces, where the name of the property will be the full method name. if (propertyInfo.Name.EndsWith("Item")) { ParameterInfo[] parameters = propertyInfo.GetIndexParameters(); if (parameters.Length > 0) { return(false); } } } return(true); }
public bool IsInterested(InspectedProperty property) { return (property.CanWrite && InspectedType.IsSerializedByFullInspector(property) && InspectedType.IsSerializedByUnity(property) == false); }
/// <summary> /// Returns true if the given property should be displayed in the inspector. This method /// assumes that the property type is inspectable. /// </summary> private static bool ShouldDisplayProperty(InspectedProperty property) { var memberInfo = property.MemberInfo; // note: we do opt-out before opt-in so that we can still serialize // a field but not display it in the inspector (as the serialize // annotations automatically cause a field to be displayed) if (memberInfo.IsDefined(typeof(HideInInspector), /*inherit:*/ true) || memberInfo.IsDefined(typeof(NotSerializedAttribute), /*inherit:*/ true) || fiInstalledSerializerManager.SerializationOptOutAnnotations.Any(t => memberInfo.IsDefined(t, /*inherit*/ true))) { return(false); } if (memberInfo.IsDefined(typeof(ShowInInspectorAttribute), /*inherit:*/ true) || (property.IsStatic == false && fiInstalledSerializerManager.SerializationOptInAnnotations.Any(t => memberInfo.IsDefined(t, /*inherit*/ true)))) { return(true); } if (property.MemberInfo is PropertyInfo && fiSettings.InspectorRequireShowInInspector) { return(false); } return (InspectedType.IsSerializedByFullInspector(property) || InspectedType.IsSerializedByUnity(property)); }
/// <summary> /// Determines whether the specified object is equal to this one. /// </summary> public bool Equals(InspectedProperty p) { // If parameter is null return false: if ((object)p == null) { return false; } // Return true if the fields match: return (StorageType == p.StorageType) && (Name == p.Name); }
public override float GetElementHeight(GUIContent label, Facade <T> element, fiGraphMetadata metadata) { float height = 0; if (string.IsNullOrEmpty(label.text) == false || TypeOptions.Types.Length > 1) { height = LabelHeight; } var anim = metadata.GetMetadata <fiAnimationMetadata>(); if (anim.IsAnimating) { return(height + anim.AnimationHeight); } if (element == null) { element = new Facade <T>(); } if (element.InstanceType == null) { element.InstanceType = TypeOptions.Types[0]; } InspectedType inspectedType = InspectedType.Get(element.InstanceType); var serializer = (BaseSerializer)fiSingletons.Get(fiInstalledSerializerManager.DefaultMetadata.SerializerType); var deserializationOp = new ListSerializationOperator() { SerializedObjects = element.ObjectReferences }; var properties = inspectedType.GetProperties(InspectedMemberFilters.InspectableMembers); for (int i = 0; i < properties.Count; ++i) { InspectedProperty property = properties[i]; object propertyValue = DeserializeProperty(serializer, deserializationOp, property, element); height += fiEditorGUI.EditPropertyHeightDirect(property, propertyValue, metadata.Enter(property.Name)); height += SplitterHeight; } return(height); }
/// <summary> /// Returns true if the given type can be serialized by Unity. This /// function is conservative and may not return true if the type can be /// serialized by unity. However, it will *not* return true if the type /// cannot be serialized by unity. /// </summary> public static bool IsSerializedByUnity(InspectedProperty property) { // Properties are *not* serialized by Unity if (property.MemberInfo is PropertyInfo) { return(false); } // statics are *not* serialized by Unity if (property.IsStatic) { return(false); } // readonly fields are *not* serialized by Unity FieldInfo fieldInfo = property.MemberInfo as FieldInfo; if (fieldInfo.IsInitOnly) { return(false); } // If the attribute is not public and doesn't have a [SerializeField] // attribute, then Unity will not serialize it, regardless of type. if (property.IsPublic == false && property.MemberInfo.IsDefined(typeof(SerializeField), /*inherit:*/ true) == false) { return(false); } Type type = property.StorageType; return // Basic primitive types (IsSimpleTypeThatUnityCanSerialize(type) || // A non-generic UnityObject derived type (typeof(UnityObject).IsAssignableFrom(type) && type.Resolve().IsGenericType == false) || // Array (but not a multidimensional one) (type.IsArray && type.GetElementType().IsArray == false && IsSimpleTypeThatUnityCanSerialize(type.GetElementType())) || // Lists of already serializable types ( type.Resolve().IsGenericType&& type.GetGenericTypeDefinition() == typeof(List <>) && IsSimpleTypeThatUnityCanSerialize(type.GetGenericArguments()[0]) )); }
/// <summary> /// Determines whether the specified object is equal to this one. /// </summary> public override bool Equals(System.Object obj) { // If parameter is null return false. if (obj == null) { return false; } // If parameter cannot be cast to PropertyMetadata return false. InspectedProperty p = obj as InspectedProperty; if ((System.Object)p == null) { return false; } // Return true if the fields match: return (StorageType == p.StorageType) && (Name == p.Name); }
/// <summary> /// Returns true if the given property should be displayed in the /// inspector. This method assumes that the property type is inspectable. /// </summary> private static bool ShouldDisplayProperty(InspectedProperty property) { var memberInfo = property.MemberInfo; // If ShowInInspector is present, we will *always* display the // attribute. if (memberInfo.IsDefined(typeof(ShowInInspectorAttribute), /*inherit:*/ true)) { return(true); } // note: we do opt-out serialization annotations before opt-in // annotations so that we can still serialize a field but not // display it in the inspector (as the serialize annotations // automatically cause a field to be displayed) if (memberInfo.IsDefined(typeof(HideInInspector), /*inherit:*/ true) || memberInfo.IsDefined(typeof(NotSerializedAttribute), /*inherit:*/ true) || fiInstalledSerializerManager.SerializationOptOutAnnotations.Any(t => memberInfo.IsDefined(t, /*inherit*/ true))) { return(false); } // Show the property if any of the opt-in annotations are present. if (property.IsStatic == false && fiInstalledSerializerManager.SerializationOptInAnnotations.Any(t => memberInfo.IsDefined(t, /*inherit*/ true))) { return(true); } if (property.MemberInfo is PropertyInfo && fiSettings.InspectorRequireShowInInspector) { return(false); } return // IsSerializedByFullInspector will return false for BaseObject // types, so we want to special case support for them being // inspected. (typeof(BaseObject).Resolve().IsAssignableFrom(property.StorageType.Resolve()) || InspectedType.IsSerializedByFullInspector(property) || InspectedType.IsSerializedByUnity(property)); }
/// <summary> /// Populate an pre-constructed instance with the data stored inside of the facade. /// </summary> /// <param name="instance">The object instance to populate.</param> public void PopulateInstance(ref T instance) { if (instance.GetType() != InstanceType) { Debug.LogWarning("PopulateInstance: Actual Facade type is different " + "(instance.GetType() = " + instance.GetType().CSharpName() + ", InstanceType = " + InstanceType.CSharpName() + ")"); } Type defaultSerializer = fiInstalledSerializerManager.DefaultMetadata.SerializerType; var serializer = (BaseSerializer)fiSingletons.Get(defaultSerializer); var serializationOperator = new ListSerializationOperator() { SerializedObjects = ObjectReferences }; InspectedType inspectedType = InspectedType.Get(instance.GetType()); foreach (var tuple in FacadeMembers) { string name = tuple.Key; InspectedProperty property = inspectedType.GetPropertyByName(name); if (property != null) { try { object deserializedMember = serializer.Deserialize( property.StorageType.Resolve(), tuple.Value, serializationOperator); property.Write(instance, deserializedMember); } catch (Exception e) { Debug.LogError("Skipping property " + name + " in facade due to " + "deserialization exception.\n" + e); } } } }
public override Facade <T> Edit(Rect region, GUIContent label, Facade <T> element, fiGraphMetadata metadata) { if (element == null) { element = new Facade <T>(); } if (element.InstanceType == null) { element.InstanceType = TypeOptions.Types[0]; } bool changedTypes; DrawHeader(ref region, label, element, out changedTypes); var facadeMembers = new Dictionary <string, string>(); var facadeReferences = new List <UnityObject>(); InspectedType inspectedType = InspectedType.Get(element.InstanceType); var serializer = (BaseSerializer)fiSingletons.Get(fiInstalledSerializerManager.DefaultMetadata.SerializerType); var deserializationOp = new ListSerializationOperator() { SerializedObjects = element.ObjectReferences }; var serializationOp = new ListSerializationOperator() { SerializedObjects = facadeReferences }; float usedHeight = 0; var anim = metadata.GetMetadata <fiAnimationMetadata>(); if (anim.IsAnimating) { fiEditorGUI.BeginFadeGroupHeight(LabelHeight, ref region, anim.AnimationHeight); fiEditorUtility.RepaintAllEditors(); } var properties = inspectedType.GetProperties(InspectedMemberFilters.InspectableMembers); for (int i = 0; i < properties.Count; ++i) { InspectedProperty property = properties[i]; object propertyValue = DeserializeProperty(serializer, deserializationOp, property, element); float height = fiEditorGUI.EditPropertyHeightDirect(property, propertyValue, metadata.Enter(property.Name)); Rect propertyRect = region; propertyRect.height = height; region.y += height; region.y += SplitterHeight; usedHeight += height + SplitterHeight; object updatedValue = fiEditorGUI.EditPropertyDirect(propertyRect, property, propertyValue, metadata.Enter(property.Name)); string data; if (TrySerializeProperty(serializer, serializationOp, property, updatedValue, out data)) { facadeMembers[property.Name] = data; } } if (anim.IsAnimating) { fiEditorGUI.EndFadeGroup(); } element.FacadeMembers = facadeMembers; element.ObjectReferences = facadeReferences; if (changedTypes && anim.UpdateHeight(usedHeight)) { fiEditorUtility.RepaintAllEditors(); } return(element); }
/// <summary> /// Returns true if the given property should be serialized. /// </summary> /// <remarks>This assumes that the property is r/w!</remarks> public static bool IsSerializedByFullInspector(InspectedProperty property) { if (property.IsStatic) { return(false); } // Do not bother serializing BaseObject derived types - they will // handle it properly themselves. Serializing them will only lead to // wasted storage space. if (typeof(BaseObject).Resolve().IsAssignableFrom(property.StorageType.Resolve())) { return(false); } MemberInfo member = property.MemberInfo; // if it has NonSerialized, then we *don't* serialize it if (fsPortableReflection.HasAttribute <NonSerializedAttribute>(member, /*shouldCache:*/ false) || fsPortableReflection.HasAttribute <NotSerializedAttribute>(member, /*shouldCache:*/ false)) { return(false); } // Don't serialize it if it has one of the custom opt-out annotations // either var optOut = fiInstalledSerializerManager.SerializationOptOutAnnotations; for (int i = 0; i < optOut.Length; ++i) { if (member.IsDefined(optOut[i], true)) { return(false); } } // if we have a [SerializeField] or [Serializable] attribute, then we // *do* serialize if (fsPortableReflection.HasAttribute <SerializeField>(member, /*shouldCache:*/ false) || fsPortableReflection.HasAttribute <SerializableAttribute>(member, /*shouldCache:*/ false)) { return(true); } // Serialize if we have a custom opt-in annotation var optIn = fiInstalledSerializerManager.SerializationOptInAnnotations; for (int i = 0; i < optIn.Length; ++i) { if (member.IsDefined(optIn[i], /*inherit:*/ true)) { return(true); } } if (property.MemberInfo is PropertyInfo) { // perf: property.IsAutoProperty is lazily computed, so if we // have SerializeAutoProperties set to false we can avoid // computing any auto-property checks by putting the // SerializeAutoProperties check before the IsAutoProperty // check // If we're not serializing auto-properties, then we will not // serialize any properties by default if (fiSettings.SerializeAutoProperties == false) { return(false); } // If it's not an auto property, then we are not going to // serialize it by default if (property.IsAutoProperty == false) { return(false); } } return(property.IsPublic); }
/// <summary> /// Construct an either containing a B value. /// </summary> public InspectedMember(InspectedMethod method) { _property = null; _method = method; }
/// <summary> /// Construct an either containing an A value. /// </summary> public InspectedMember(InspectedProperty property) { _property = property; _method = null; }
public bool IsInterested(InspectedProperty property) { return(false); }
public bool IsInterested(InspectedProperty property) { return(IsPropertyTypeInspectable(property) && ShouldDisplayProperty(property)); }
/// <summary> /// Returns true if the given property should be serialized. /// </summary> /// <remarks>This assumes that the property is r/w!</remarks> public static bool IsSerializedByFullInspector(InspectedProperty property) { MemberInfo member = property.MemberInfo; if (property.IsStatic) { return(false); } // if it has NonSerialized, then we *don't* serialize it if (fsPortableReflection.HasAttribute <NonSerializedAttribute>(member) || fsPortableReflection.HasAttribute <NotSerializedAttribute>(member)) { return(false); } // Don't serialize it if it has one of the custom opt-out annotations either var optOut = fiInstalledSerializerManager.SerializationOptOutAnnotations; for (int i = 0; i < optOut.Length; ++i) { if (member.IsDefined(optOut[i], true)) { return(false); } } // if we have a [SerializeField] or [Serializable] attribute, then we *do* serialize if (fsPortableReflection.HasAttribute <SerializeField>(member) || fsPortableReflection.HasAttribute <SerializableAttribute>(member)) { return(true); } // Serialize if we have a custom opt-in annotation var optIn = fiInstalledSerializerManager.SerializationOptInAnnotations; for (int i = 0; i < optIn.Length; ++i) { if (member.IsDefined(optIn[i], /*inherit:*/ true)) { return(true); } } if (property.MemberInfo is PropertyInfo) { // perf: property.IsAutoProperty is lazily computed, so if we have SerializeAutoProperties set // to false we can avoid computing any auto-property checks by putting the // SerializeAutoProperties check before the IsAutoProperty check // If we're not serializing auto-properties, then we will not serialize any properties by default if (fiSettings.SerializeAutoProperties == false) { return(false); } // If it's not an auto property, then we are not going to serialize it by default if (property.IsAutoProperty == false) { return(false); } } return(property.IsPublic); }
public bool IsInterested(InspectedProperty property) { return(typeof(IEnumerable <tkIControl>).IsAssignableFrom(property.StorageType) || typeof(tkIControl).IsAssignableFrom(property.StorageType)); }
/// <summary> /// Deserializes a property on the facade. /// </summary> private static object DeserializeProperty(BaseSerializer serializer, ISerializationOperator serializationOperator, InspectedProperty property, Facade <T> facade) { string data; if (facade.FacadeMembers.TryGetValue(property.Name, out data)) { try { return(serializer.Deserialize(property.StorageType, data, serializationOperator)); } catch { } } return(GetDefault(property.StorageType)); }
/// <summary> /// Serializes a property that will be stored on the facade. /// </summary> public static bool TrySerializeProperty(BaseSerializer serializer, ISerializationOperator serializationOperator, InspectedProperty property, object value, out string data) { try { data = serializer.Serialize(property.StorageType, value, serializationOperator); return(true); } catch { data = string.Empty; return(false); } }
public bool IsInterested(InspectedProperty property) { return(property.IsStatic && IsPropertyTypeInspectable(property)); }