/*----------Functions----------*/ //PRIVATE /// <summary> /// Create a reorderable list that will be cached for the displaying of persistent callback elements /// </summary> /// <param name="eventBase">The object actual that is described by the runtimeEventProp</param> /// <param name="runtimeEventProp">The property that contains the base runtime event information that is being used for display</param> /// <param name="label">The label that is attached to the property that is to be displayed</param> private void CreateCachedList(RuntimeEventBase eventBase, SerializedProperty runtimeEventProp, GUIContent label) { //Get the property that stores the persistent callback elements that need to be displayed SerializedProperty persistentsProp = runtimeEventProp.FindPropertyRelative("persistents"); //Create the cache element that will be stored ReorderableList list = new ReorderableList( runtimeEventProp.serializedObject, persistentsProp, true, //Drag-able true, //Header true, //Add Button true //Remove Button ); //Create a label that has the display elements GUIContent displayLabel = new GUIContent( (eventBase.DYNAMIC_TYPES.Length > 0 ? label.text + " " + PersistentOptionsUtility.GenerateSignatureLabelString(eventBase.DYNAMIC_TYPES) : label.text ), label.tooltip ); //Setup the callback functions for calculating and displaying element values list.elementHeightCallback += index => PersistentCallbackDrawer.GetElementHeight(persistentsProp.GetArrayElementAtIndex(index)); list.drawHeaderCallback += rect => EditorGUI.LabelField(rect, displayLabel); list.drawElementCallback += (rect, index, active, focused) => { //Flag if the height needs to be regenerated if (PersistentCallbackDrawer.DrawLayoutElements( rect, persistentsProp.GetArrayElementAtIndex(index), eventBase.DYNAMIC_TYPES, () => { eventBase.DirtyPersistent(); runtimeEventProp.serializedObject.Update(); } )) { //Persistent events need to be dirtied so that they will be updated if changes occurred eventBase.DirtyPersistent(); //Force this element to need to redraw runtimeEventProp.serializedObject.Update(); } }; list.onAddCallback = dynamicList => { //If this is the first object value, reset the object to its default state if (++dynamicList.serializedProperty.arraySize == 1) { //Apply the new values to the object runtimeEventProp.serializedObject.ApplyModifiedProperties(); //Get the new property element in the array SerializedProperty firstProp = persistentsProp.GetArrayElementAtIndex(0); //Retrieve all of the objects at this point PersistentCallback[] firsts; firstProp.GetPropertyValues(out firsts); //Reset the values of this object to the default values for (int i = 0; i < firsts.Length; i++) { if (firsts[i] != null) { firsts[i].ResetAll(); } } } }; //Add this option to the cache listCache[eventBase] = list; }
/// <summary> /// Populate a Generic Menu with the available persistent methods on the supplied target /// </summary> /// <param name="target">The target object that should be scanned for raisable methods</param> /// <param name="currentIsValid">Flags if the current callback is valid</param> /// <param name="currentIsDynamic">Flags if the current persistent callback is a dynamic one</param> /// <param name="selectedMethod">The previous method that has been selected for use</param> /// <param name="dynamicTypes">The types that are able to be dynamic in their raising of the callback</param> /// <param name="resetCallback">A callback that is raised when the no function option is selected for callback(s)</param> /// <param name="assignCallback">The callback that will be used to assign the callback values to the callback object</param> /// <returns>Returns a Generic Menu that can be displayed to list the available options</returns> private static GenericMenu CreateOptionsSelectionMenu(UnityEngine.Object target, bool currentIsValid, bool currentIsDynamic, PersistentMethod selectedMethod, Type[] dynamicTypes, GenericMenu.MenuFunction resetCallback, AssignCallbackDel assignCallback) { //Create a generic menu that can be used to display possible options GenericMenu optionsMenu = new GenericMenu(); #if UNITY_2018_2_OR_NEWER //Toggle the option to allow for the method to be raised on specific components if there are multiple of the same type optionsMenu.allowDuplicateNames = true; #endif //Store a list of the elements that are to have their values displayed List <UnityEngine.Object> searchTargets = new List <UnityEngine.Object>(1); //Store a reference to the Game Object to show options for GameObject searchObject = GetBaseTarget(target) as GameObject; //If there is a search object, use that if (searchObject != null) { //Add the search object itself searchTargets.Add(searchObject); //Grab all of the components attached to the object searchTargets.AddRange(searchObject.GetComponents <Component>()); } //Otherwise, just use the target (Scriptable Assets etc.) else { searchTargets.Add(target); } //Add a label for the target object optionsMenu.AddDisabledItem(new GUIContent(searchTargets[0].name + " ")); optionsMenu.AddSeparator(string.Empty); //Add the clear option to the menu optionsMenu.AddItem(NO_SELECTION_LABEL, !currentIsValid, resetCallback); optionsMenu.AddSeparator(string.Empty); //Store the signature string for dynamic elements string dynamicSignature = (dynamicTypes.Length > 0 ? PersistentOptionsUtility.GenerateSignatureLabelString(dynamicTypes) : string.Empty); //Process all of the elements to be searched foreach (UnityEngine.Object search in searchTargets) { //Retrieve the methods that can be used at this level PersistentMethod[] methods = PersistentOptionsUtility.RetrieveObjectMethods(search); //If there are no methods, skip if (methods.Length == 0) { continue; } //Sort the methods based on their display labels Array.Sort(methods, (left, right) => { //If the property flag differs, sort based on that if (left.IsProperty != right.IsProperty) { return(right.IsProperty.CompareTo(left.IsProperty)); } //Otherwise, go alphabetical return(left.DisplayLabel.text.CompareTo(right.DisplayLabel.text)); }); //Store the starting directory label that will be used for creating the sub directories of options string labelPrefix = search.GetType().Name + "/"; //Use a string builder to construct the display names for the different method options StringBuilder sb = new StringBuilder(); //Store the target that will be operated on if this option is selected UnityEngine.Object objTarget = search; //Loop through the options to add the dynamic methods if (dynamicTypes.Length > 0) { //Flag if an option was found bool foundOne = false; //Check if any of the options can be used as dynamic types for (int i = 0; i < methods.Length; i++) { //Check the parameter length is the same if (methods[i].ParameterSignature.Length != dynamicTypes.Length) { continue; } //Flag if this is a valid candidate bool valid = true; for (int j = 0; j < dynamicTypes.Length; j++) { if (methods[i].ParameterSignature[j] != dynamicTypes[j]) { valid = false; break; } } //If the method isn't valid, don't bother if (!valid) { continue; } //Check if this is the first valid option found if (!foundOne) { //Add the initial header element optionsMenu.AddDisabledItem(new GUIContent(labelPrefix + "Dynamic Methods " + dynamicSignature)); //Flag one as found foundOne = true; } //Store a collective index for the lambda int ind = i; //Add the option to the menu optionsMenu.AddItem( new GUIContent( labelPrefix + (methods[i].IsProperty ? methods[i].MethodName.Substring(PersistentOptionsUtility.SETTER_PROPERTY_PREFIX.Length) : methods[i].MethodName) + " ", methods[i].DisplayLabel.tooltip ), currentIsDynamic && methods[i] == selectedMethod, () => assignCallback(objTarget, methods[ind], true) ); } //If an option was found add the ending buffer elements if (foundOne) { optionsMenu.AddDisabledItem(new GUIContent(labelPrefix + " ")); optionsMenu.AddDisabledItem(new GUIContent(labelPrefix + "Constant Methods")); } } //Loop through the options to add the persistent options for (int i = 0; i < methods.Length; i++) { //Store a collectible index for the lambda int ind = i; //Clear out the previous string value sb.Length = 0; //Add the current prefix to the entry sb.Append(labelPrefix); //Add the display text to the entry sb.Append(methods[i].DisplayLabel.text); //Check to see if all of the contained entries have drawers bool found = false; //Check if a missing drawer was found for (int j = 0; j < methods[i].Parameters.Length; j++) { if (!ParameterDrawers.HasDrawer(methods[i].ParameterSignature[j], methods[i].Parameters[j].Attribute)) { found = true; break; } } //Check for a missing drawer if (found) { sb.Append("\t*"); } //Add the option to the menu optionsMenu.AddItem( new GUIContent(sb.ToString(), methods[i].DisplayLabel.tooltip), !currentIsDynamic && methods[i] == selectedMethod, () => assignCallback(objTarget, methods[ind], false) ); } } //Return the constructed menu return(optionsMenu); }