//PUBLIC /// <summary> /// Find the height of a persistent callback object /// </summary> /// <param name="property">The property that is to have the height calculated for</param> /// <returns>Returns the height in pixels that should be reserved for this element</returns> public static float GetElementHeight(SerializedProperty property) { //Get the target objects of the property PersistentCallback[] callbacks; property.GetPropertyValues(out callbacks); //Check that there are values to check if (callbacks.Length == 0) { return(0f); } //Get the height that is used for the object/method selection elements float height = EditorGUIUtility.singleLineHeight * 2 + (BUFFER_SPACE * 2f); //Get the method that is in use by the primary (first) callback PersistentMethod primary = PersistentOptionsUtility.GetPersistentMethodFromCallback(callbacks[0]); //Check if this method is the same across all selections bool isDifferent = false; for (int i = 1; i < callbacks.Length; i++) { if (primary != PersistentOptionsUtility.GetPersistentMethodFromCallback(callbacks[i])) { isDifferent = true; break; } } //If the methods are the same then the parameters can be shown if (!isDifferent && !callbacks[0].IsDynamic && primary != null) { //Calculate the height required for each drawer int ind = 0; foreach (var param in primary.Parameters) { //Get the drawer for the type AParameterDrawer drawer = ParameterDrawers.GetDrawer(primary.ParameterSignature[ind], param.Attribute); //Collate the parameter cache's that are needed for this callback PersistentParameterCache[] current = new PersistentParameterCache[callbacks.Length]; for (int i = 0; i < callbacks.Length; i++) { current[i] = callbacks[i].ParameterInfo[ind].ParameterCache; } //Retrieve the height for the drawer height += drawer.GetDrawerHeight(current, param.DisplayLabel) + BUFFER_SPACE; //Increment the progress ++ind; } } //Return the final completed height return(height); }
/// <summary> /// Display the elements of the property within the designated area on the inspector area /// </summary> /// <param name="position">The position within the inspector that the property should be drawn to</param> /// <param name="property">The property that is to be displayed within the inspector</param> /// <param name="dynamicTypes">Defines the types that are designated as dynamic types for operation</param> /// <param name="forceDirty">An action that can be raised from the generic menus callback to force a dirty of the current elements</param> /// <returns>Returns true if an event occurred that caused changes that need to be saved</returns> public static bool DrawLayoutElements(Rect position, SerializedProperty property, Type[] dynamicTypes, Action forceDirty) { //Get the target objects of the property PersistentCallback[] callbacks; //Check that there are values to check if (!property.GetPropertyValues(out callbacks) || callbacks.Length == 0) { return(false); } //Flag if the height of this object needs to be recalculated bool elementsModified = false; { //Check if the event state is different for the contained callbacks bool isDifferent = false; for (int i = 1; i < callbacks.Length; i++) { if (callbacks[0].EventState != callbacks[i].EventState) { isDifferent = true; break; } } //Display an option to change the event state of the options using (GUIMixer.PushSegment(isDifferent)) { //Begin checking for UI changes EditorGUI.BeginChangeCheck(); //Present the option for changing the event state ERuntimeEventState newState = (ERuntimeEventState)EditorGUI.EnumPopup(GetLineOffsetPosition(position, 0, 1f), GUIContent.none, callbacks[0].EventState); //If the state has changed, apply it to all of the callbacks if (EditorGUI.EndChangeCheck()) { for (int i = 0; i < callbacks.Length; i++) { callbacks[i].EventState = newState; } } } } { //Check if the target object is different for the contained callbacks bool isDifferent = false; //Check there are multiple objects to modify if (callbacks.Length > 1) { //Get the target of the initial object UnityEngine.Object baseTarget = GetBaseTarget(callbacks[0].Target); //Compare the base target against the others for (int i = 1; i < callbacks.Length; i++) { if (baseTarget != GetBaseTarget(callbacks[i].Target)) { isDifferent = true; break; } } } //Display a target field for the callback operations using (GUIMixer.PushSegment(isDifferent)) { //Begin checking for UI changes EditorGUI.BeginChangeCheck(); //Present the option for changing the target object UnityEngine.Object newTarget = EditorGUI.ObjectField(GetLineOffsetPosition(position, 1, .4f), GUIContent.none, callbacks[0].Target, typeof(UnityEngine.Object), true); //If the target changed if (EditorGUI.EndChangeCheck()) { //Apply the new target to all contained elements for (int i = 0; i < callbacks.Length; i++) { callbacks[i].Target = newTarget; } //That can cause massive changes elementsModified = true; } } } //Store the persistent method that is assigned to the primary PersistentMethod primaryMethod = PersistentOptionsUtility.GetPersistentMethodFromCallback(callbacks[0]); //Store a flag that indicates if the callbacks have different methods bool methodsAreDifferent = false; //Allow for the modification of selected function if there is a target set using (GUILocker.PushSegment(callbacks[0].Target)) { //Retrieve the Content that will be displayed for the function selection selected option GUIContent selectedDisplay; //If a method match could be found, use its display label if (primaryMethod != null) { selectedDisplay = primaryMethod.DisplayLabel; } //Otherwise, method may be missing else { //Try to retrieve the label for the callback string generatedLabel = PersistentOptionsUtility.GetPersistentMethodLabelFromCallback(callbacks[0]); //If the string is empty, no function has been set yet selectedDisplay = (string.IsNullOrEmpty(generatedLabel) ? NO_SELECTION_LABEL : new GUIContent(generatedLabel + " " + MISSING_LABEL) ); } //Check there are multiple callbacks to compare against if (callbacks.Length > 1) { //Check if the selected callbacks for the other callbacks is different for (int i = 1; i < callbacks.Length; i++) { if (primaryMethod != PersistentOptionsUtility.GetPersistentMethodFromCallback(callbacks[i])) { methodsAreDifferent = true; break; } } } //Display the dropdown button for selecting the active callback using (GUIMixer.PushSegment(methodsAreDifferent)) { if (EditorGUI.DropdownButton(GetLineOffsetPosition(position, 1, .6f, .4f), selectedDisplay, FocusType.Passive)) { //Retrieve the constructed menu GenericMenu optionsMenu = CreateOptionsSelectionMenu(callbacks[0].Target, callbacks[0].IsValid, callbacks[0].IsDynamic, primaryMethod, dynamicTypes, //Reset function () => { //Loop through and reset all of the callback methods for (int i = 0; i < callbacks.Length; i++) { callbacks[i].ResetMethod(); } //Reset the primary method primaryMethod = null; methodsAreDifferent = false; //Values modified, force the calling object to re-calculate this element forceDirty(); }, //Assign method function (target, method, isDynamic) => { //Apply the new method to the option AssignPersistentCallback(callbacks, target, method, isDynamic); //Methods are now the same primaryMethod = method; methodsAreDifferent = false; //Values modified, force the calling object to re-calculate this element forceDirty(); }); //Display the various options optionsMenu.DropDown(GetLineOffsetPosition(position, 1, .6f, .4f)); } } } //If the primary method is consistent across the multiple objects, display the values if (!methodsAreDifferent && !callbacks[0].IsDynamic && primaryMethod != null) { //Store the rect of the last point Rect displayRect = GetLineOffsetPosition(position, 1, 1f); //Loop through all of the parameters for this method int ind = 0; foreach (var param in primaryMethod.Parameters) { //Retrieve the drawer for this parameter AParameterDrawer drawer = ParameterDrawers.GetDrawer(primaryMethod.ParameterSignature[ind], param.Attribute); //Collate the parameter cache's that are needed for this callback PersistentParameterCache[] current = new PersistentParameterCache[callbacks.Length]; for (int i = 0; i < callbacks.Length; i++) { current[i] = callbacks[i].ParameterInfo[ind].ParameterCache; } //Setup the display rect for displaying values correctly given the values displayRect.y += displayRect.height + BUFFER_SPACE; displayRect.height = drawer.GetDrawerHeight(current, param.DisplayLabel); //Draw the elements to the inspector if (drawer.DisplayParameterValue(displayRect, current, param.DisplayLabel) && !elementsModified) { elementsModified = true; } //Increment the current progress through the parameters ++ind; } } //Return the re-calculate flag return(elementsModified); }