/// <summary> /// Ends a context around custom handle calls to register undo snapshot and /// set dirty as needed. /// </summary> /// <returns><see langword="true"/> if changes were detected; otherwise, <see langword="false"/>.</returns> public static bool EndHandles() { bool isChangeDetected = EndHandlesChangeCheck(); // see if event was eaten in a hold if (isChangeDetected) { Undo.RecordObjects(s_MostRecentTargetObjects, s_MostRecentUndoMessage); EditorUtilityX.SetDirty(s_MostRecentTargetObjects); } // clean up context s_MostRecentTargetObjects = new Object[0]; return(isChangeDetected); }
/// <summary> /// Invokes the supplied property setter for the supplied hashable serialized property and update its value /// cache. /// </summary> /// <param name="hashableProperty">A hashable representation of the property's serialized backing field.</param> /// <param name="getter">A getter method that takes the provider as its argument.</param> /// <param name="setter">A setter method that takes the provider and new value as its arguments.</param> /// <param name="propertyType">The type returned by the getter and specified in the setter signature.</param> private static void InvokeSetter( HashableSerializedProperty hashableProperty, System.Func <object, object> getter, System.Action <object, object> setter, System.Type propertyType ) { SerializedProperty sp = hashableProperty.SerializedProperty; // mark for undo HashSet <Object> objectsToUndo = new HashSet <Object>(); objectsToUndo.Add(hashableProperty.TargetObject); string undoName = string.Format("Change {0}", sp.GetDisplayName()); // if it's on a monobehaviour, it may affect other objects in the hierarchy if (hashableProperty.TargetObject is MonoBehaviour) { MonoBehaviour monoBehaviour = hashableProperty.TargetObject as MonoBehaviour; foreach (Transform t in monoBehaviour.transform.root.GetComponentsInChildren <Transform>(true)) { foreach (Component c in t.GetComponents <Component>()) { objectsToUndo.Add(c); } } } Undo.RecordObjects(objectsToUndo.ToArray(), undoName); // get the providers FieldInfo fieldInfo; object provider = sp.GetProvider(out fieldInfo); // get the element index of the property being set, if any int elementIndex = hashableProperty.SerializedProperty.GetElementIndex(); // flush inspector changes and store pending values sp.serializedObject.ApplyModifiedProperties(); object pendingValue = null; // ensure IList backing field values are converted to the type expected by the setter if (elementIndex < 0 && typeof(IList).IsAssignableFrom(propertyType) && propertyType != fieldInfo.FieldType) { pendingValue = sp.GetConvertedIListValues(propertyType); } else { pendingValue = sp.GetValue(); } // reset backing field to old values if (elementIndex >= 0) { (fieldInfo.GetValue(provider) as IList)[elementIndex] = valueCache[hashableProperty]; } else { fieldInfo.SetValue(provider, valueCache[hashableProperty]); } // invoke the setter if (elementIndex >= 0) { // clone the result of the getter IList arrayValues = (IList)getter.Invoke(provider); if (typeof(System.Array).IsAssignableFrom(propertyType)) { arrayValues = (IList)((System.ICloneable)arrayValues).Clone(); } else { IList srcValues = arrayValues; arrayValues = (IList)System.Activator.CreateInstance(propertyType); for (int idx = 0; idx < srcValues.Count; ++idx) { arrayValues.Add(srcValues[idx]); } } // assign the pending element value arrayValues[elementIndex] = pendingValue; // invoke setter setter.Invoke(provider, arrayValues); } else { setter.Invoke(provider, pendingValue); } // set dirty EditorUtilityX.SetDirty(objectsToUndo.ToArray()); // update cache valueCache[hashableProperty] = sp.GetValue(); }