// Initialize a runtime event receiver via the state's event configuration and add it to the event receiver dictionary private BaseEventReceiver InitializeAndAddEventReceiver(string stateName) { InteractionState state = stateManager.GetState(stateName); BaseInteractionEventConfiguration eventConfiguration = (BaseInteractionEventConfiguration)state.EventConfiguration; string subStateName = state.GetSubStateName(); // Find the associated event receiver for the state if it has one var eventReceiverTypes = TypeCacheUtility.GetSubClasses <BaseEventReceiver>(); Type eventReceiver; try { eventReceiver = eventReceiverTypes?.Find((type) => type.Name.StartsWith(subStateName)); } catch { eventReceiver = null; } if (eventReceiver != null) { eventConfiguration.EventReceiver = Activator.CreateInstance(eventReceiver, new object[] { eventConfiguration }) as BaseEventReceiver; } else { eventConfiguration.EventReceiver = Activator.CreateInstance(typeof(StateReceiver), new object[] { eventConfiguration }) as BaseEventReceiver; } EventReceivers.Add(stateName, eventConfiguration.EventReceiver); return(eventConfiguration.EventReceiver); }
// Create an instance of an event configuration for a state private BaseInteractionEventConfiguration CreateEventConfigurationInstance(string stateName) { BaseInteractionEventConfiguration eventConfiguration; string subStateName = stateManager.GetState(stateName).GetSubStateName(); // Check if the state has an associated event configuration by state name. // For example, the Focus state is associated with the FocusEvents class which has BaseInteractionEventConfiguration as its base class. // The FocusEvents class contains unity events with FocusEventData. // This pattern continues with states that have events with specific event data, i.e. the Touch state // is associated with the serialized class TouchEvents which contains unity events with TouchEventData var eventConfigTypes = TypeCacheUtility.GetSubClasses <BaseInteractionEventConfiguration>(); Type eventConfigType = eventConfigTypes.Find((type) => type.Name.StartsWith(subStateName)); if (eventConfigType != null) { eventConfiguration = Activator.CreateInstance(eventConfigType) as BaseInteractionEventConfiguration; } else { // If a state does not have an associated event configuration class, then create an instance of the // StateEvents class which contains the OnStateOn and OnStateOff unity events. These unity events do not have event data. eventConfiguration = Activator.CreateInstance(typeof(StateEvents)) as BaseInteractionEventConfiguration; } eventConfiguration.StateName = stateName; return(eventConfiguration); }
/// <summary> /// Create the event and setup the values from the inspector /// </summary> public static ReceiverBase CreateReceiver(InteractableEvent iEvent) { // Temporary workaround // This is to fix a bug in GA where the AssemblyQualifiedName was never actually saved. Functionality would work in editor...but never on device player if (iEvent.ReceiverType == null) { var correctType = TypeCacheUtility.GetSubClasses <ReceiverBase>().Where(s => s?.Name == iEvent.ClassName).First(); iEvent.ReceiverType = correctType; } ReceiverBase newEvent = (ReceiverBase)Activator.CreateInstance(iEvent.ReceiverType, iEvent.Event); InspectorGenericFields <ReceiverBase> .LoadSettings(newEvent, iEvent.Settings); return(newEvent); }
public override void OnInspectorGUI() { serializedObject.Update(); InspectorUIUtility.DrawTitle("States"); EditorGUILayout.HelpBox("Manage state configurations to drive Interactables or Transitions", MessageType.None); SerializedProperty stateModelClassName = serializedObject.FindProperty("StateModelClassName"); SerializedProperty assemblyQualifiedName = serializedObject.FindProperty("AssemblyQualifiedName"); var stateModelTypes = TypeCacheUtility.GetSubClasses <BaseStateModel>(); var stateModelClassNames = stateModelTypes.Select(t => t?.Name).ToArray(); int id = Array.IndexOf(stateModelClassNames, stateModelClassName.stringValue); Rect stateModelPos = EditorGUILayout.GetControlRect(); using (new EditorGUI.PropertyScope(stateModelPos, new GUIContent("State Model"), stateModelClassName)) { int newId = EditorGUILayout.Popup("State Model", id, stateModelClassNames); if (id != newId) { Type newType = stateModelTypes[newId]; stateModelClassName.stringValue = newType.Name; assemblyQualifiedName.stringValue = newType.AssemblyQualifiedName; } } for (int i = 0; i < stateList.arraySize; i++) { using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { SerializedProperty stateItem = stateList.GetArrayElementAtIndex(i); SerializedProperty name = stateItem.FindPropertyRelative("Name"); SerializedProperty activeIndex = stateItem.FindPropertyRelative("ActiveIndex"); SerializedProperty bit = stateItem.FindPropertyRelative("Bit"); SerializedProperty index = stateItem.FindPropertyRelative("Index"); // assign the bitcount based on location in the list as power of 2 bit.intValue = 1 << i; activeIndex.intValue = i; Rect position = EditorGUILayout.GetControlRect(); using (new EditorGUILayout.HorizontalScope()) { var label = new GUIContent(name.stringValue + " (" + bit.intValue + ")"); using (new EditorGUI.PropertyScope(position, new GUIContent(), name)) { string[] stateEnums = Enum.GetNames(typeof(InteractableStates.InteractableStateEnum)); int enumIndex = Array.IndexOf(stateEnums, name.stringValue); int newEnumIndex = EditorGUILayout.Popup(label, enumIndex, stateEnums); if (newEnumIndex == -1) { newEnumIndex = 0; } name.stringValue = stateEnums[newEnumIndex]; index.intValue = newEnumIndex; } if (InspectorUIUtility.SmallButton(RemoveStateLabel)) { stateList.DeleteArrayElementAtIndex(i); break; } } } } if (InspectorUIUtility.FlexButton(AddStateLabel)) { stateList.InsertArrayElementAtIndex(stateList.arraySize); } serializedObject.ApplyModifiedProperties(); }
public void RenderThemeDefinitions() { GUIStyle box = InspectorUIUtility.HelpBox(EditorGUI.indentLevel * ThemeBoxMargin); // Loop through all InteractableThemePropertySettings of Theme for (int index = 0; index < themeDefinitions.arraySize; index++) { using (new EditorGUILayout.VerticalScope(box)) { SerializedProperty themeDefinition = themeDefinitions.GetArrayElementAtIndex(index); SerializedProperty className = themeDefinition.FindPropertyRelative("ClassName"); string themeDefinition_prefKey = theme.name + "_Definitions" + index; bool show = false; using (new EditorGUILayout.HorizontalScope()) { show = InspectorUIUtility.DrawSectionFoldoutWithKey(className.stringValue, themeDefinition_prefKey, MixedRealityStylesUtility.BoldFoldoutStyle); if (RenderDeleteButton(index)) { return; } } if (show) { EditorGUILayout.Space(); using (new EditorGUI.IndentLevelScope()) { EditorGUILayout.LabelField("General Properties", EditorStyles.boldLabel); using (new EditorGUILayout.HorizontalScope()) { var themeTypes = TypeCacheUtility.GetSubClasses <InteractableThemeBase>(); var themeClassNames = themeTypes.Select(t => t?.Name).ToArray(); int id = Array.IndexOf(themeClassNames, className.stringValue); int newId = EditorGUILayout.Popup("Theme Runtime", id, themeClassNames); // Some old Themes did not properly save a value here SerializedProperty assemblyQualifiedName = themeDefinition.FindPropertyRelative("AssemblyQualifiedName"); if (string.IsNullOrEmpty(assemblyQualifiedName.stringValue) && newId != -1) { assemblyQualifiedName.stringValue = themeTypes[newId].AssemblyQualifiedName; } // If user changed the theme type for current themeDefinition if (id != newId && newId != -1) { Type oldType = id != -1 ? themeTypes[id] : null; Type newType = themeTypes[newId]; ChangeThemeDefinitionType(index, oldType, newType); return; } } var themeType = theme.Definitions[index].ThemeType; if (themeType != null) { SerializedProperty customProperties = themeDefinition.FindPropertyRelative("customProperties"); RenderCustomProperties(customProperties); var themeExample = (InteractableThemeBase)Activator.CreateInstance(themeType); if (themeExample.IsEasingSupported) { RenderEasingProperties(themeDefinition); } if (themeExample.AreShadersSupported) { RenderShaderProperties(themeDefinition); } EditorGUILayout.Space(); RenderThemeStates(themeDefinition); } else { InspectorUIUtility.DrawError("Theme Runtime Type is not valid"); } } } } } // If no theme properties assigned, add a default one if (themeDefinitions.arraySize < 1 || GUILayout.Button(AddThemePropertyLabel)) { AddThemeDefinition(); } }
/// <summary> /// Render event properties for the given event item. If item has been removed, returns true. False otherwise /// </summary> /// <param name="eventItem">serialized property of the event item to render properties from</param> /// <returns>If item has been removed, returns true. False otherwise</returns> public static bool RenderEvent(SerializedProperty eventItem, bool canRemove = true) { using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { SerializedProperty uEvent = eventItem.FindPropertyRelative("Event"); SerializedProperty eventName = eventItem.FindPropertyRelative("Name"); SerializedProperty className = eventItem.FindPropertyRelative("ClassName"); SerializedProperty assemblyQualifiedName = eventItem.FindPropertyRelative("AssemblyQualifiedName"); Type receiverType; InspectorUIUtility.DrawHeader("Event Receiver Type"); using (new EditorGUILayout.HorizontalScope()) { Rect position = EditorGUILayout.GetControlRect(); using (new EditorGUI.PropertyScope(position, SelectEventLabel, className)) { var receiverTypes = TypeCacheUtility.GetSubClasses <ReceiverBase>(); var recevierClassNames = receiverTypes.Select(t => t?.Name).ToArray(); int id = Array.IndexOf(recevierClassNames, className.stringValue); int newId = EditorGUI.Popup(position, id, recevierClassNames); if (newId == -1) { newId = 0; } receiverType = receiverTypes[newId]; // Temporary workaround to fix bug shipped in GA where assemblyQualifiedName was never set if (string.IsNullOrEmpty(assemblyQualifiedName.stringValue)) { assemblyQualifiedName.stringValue = receiverType.AssemblyQualifiedName; } if (id != newId) { EventChanged(receiverType, eventItem); } } if (canRemove) { if (InspectorUIUtility.FlexButton(new GUIContent("Remove Event"))) { return(true); } } } EditorGUILayout.Space(); InspectorUIUtility.DrawHeader("Event Properties"); ReceiverBase receiver = (ReceiverBase)Activator.CreateInstance(receiverType, new UnityEvent()); if (!receiver.HideUnityEvents) { EditorGUILayout.PropertyField(uEvent, new GUIContent(receiver.Name)); } SerializedProperty eventSettings = eventItem.FindPropertyRelative("Settings"); // If fields for given receiver class type have been changed, update the related inspector field data var fieldList = InspectorFieldsUtility.GetInspectorFields(receiver); if (!InspectorFieldsUtility.AreFieldsSame(eventSettings, fieldList)) { InspectorFieldsUtility.UpdateSettingsList(eventSettings, fieldList); } for (int index = 0; index < eventSettings.arraySize; index++) { SerializedProperty propertyField = eventSettings.GetArrayElementAtIndex(index); bool isEvent = InspectorFieldsUtility.IsPropertyType(propertyField, InspectorField.FieldTypes.Event); if (!receiver.HideUnityEvents || !isEvent) { InspectorFieldsUtility.DisplayPropertyField(eventSettings.GetArrayElementAtIndex(index)); } } } return(false); }