/// <summary> /// Helper function to render header correctly for all profiles /// </summary> /// <param name="title">Title of profile</param> /// <param name="description">profile tooltip describing purpose</param> /// <param name="selectionObject">The profile object. Used to re-select the object after MRTK instance is created.</param> /// <param name="isProfileInitialized">profile properties are full initialized for rendering</param> /// <param name="backText">Text for back button if not rendering as sub-profile</param> /// <param name="backProfile">Target profile to return to if not rendering as sub-profile</param> protected void RenderProfileHeader(string title, string description, Object selectionObject, bool isProfileInitialized = true, BackProfileType returnProfileTarget = BackProfileType.Configuration) { RenderMRTKLogo(); var profile = target as BaseMixedRealityProfile; if (!RenderAsSubProfile) { CheckEditorPlayMode(); if (!profile.IsCustomProfile) { EditorGUILayout.HelpBox("Default MRTK profiles cannot be edited. Create a clone of this profile to modify settings.", MessageType.Warning); if (GUILayout.Button(new GUIContent("Clone"))) { MixedRealityProfileCloneWindow.OpenWindow(null, (BaseMixedRealityProfile)target, null); } } if (IsProfileInActiveInstance()) { DrawBacktrackProfileButton(returnProfileTarget); } if (!isProfileInitialized) { if (!MixedRealityToolkit.IsInitialized) { EditorGUILayout.HelpBox("There is not a MRTK instance in your scene. Some properties may not be editable", MessageType.Error); if (InspectorUIUtility.RenderIndentedButton(new GUIContent("Add Mixed Reality Toolkit instance to scene"), EditorStyles.miniButton)) { MixedRealityInspectorUtility.AddMixedRealityToolkitToScene(MixedRealityInspectorUtility.GetDefaultConfigProfile()); // After the toolkit has been created, set the selection back to this item so the user doesn't get lost Selection.activeObject = selectionObject; } } else if (!MixedRealityToolkit.Instance.HasActiveProfile) { EditorGUILayout.HelpBox("There is no active profile assigned in the current MRTK instance. Some properties may not be editable.", MessageType.Error); } } } else { if (!isProfileInitialized && profile.IsCustomProfile) { EditorGUILayout.HelpBox("Some properties may not be editable in this profile. Please refer to the error messages below to resolve editing.", MessageType.Warning); } } using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField(new GUIContent(title, description), EditorStyles.boldLabel, GUILayout.ExpandWidth(true)); RenderDocumentation(selectionObject); } EditorGUILayout.LabelField(string.Empty, GUI.skin.horizontalSlider); }
public override void OnInspectorGUI() { var configurationProfile = (MixedRealityToolkitConfigurationProfile)target; serializedObject.Update(); RenderMRTKLogo(); CheckEditorPlayMode(); if (!MixedRealityToolkit.IsInitialized) { EditorGUILayout.HelpBox("No Mixed Reality Toolkit found in scene.", MessageType.Warning); if (InspectorUIUtility.RenderIndentedButton("Add Mixed Reality Toolkit instance to scene")) { MixedRealityInspectorUtility.AddMixedRealityToolkitToScene(configurationProfile); } } if (!configurationProfile.IsCustomProfile) { EditorGUILayout.HelpBox("The Mixed Reality Toolkit's core SDK profiles can be used to get up and running quickly.\n\n" + "You can use the default profiles provided, copy and customize the default profiles, or create your own.", MessageType.Warning); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Copy & Customize")) { SerializedProperty targetProperty = null; UnityEngine.Object selectionTarget = null; // If we have an active MRTK instance, find its config profile serialized property if (MixedRealityToolkit.IsInitialized) { selectionTarget = MixedRealityToolkit.Instance; SerializedObject mixedRealityToolkitObject = new SerializedObject(MixedRealityToolkit.Instance); targetProperty = mixedRealityToolkitObject.FindProperty("activeProfile"); } MixedRealityProfileCloneWindow.OpenWindow(null, target as BaseMixedRealityProfile, targetProperty, selectionTarget); } if (MixedRealityToolkit.IsInitialized) { if (GUILayout.Button("Create new profiles")) { ScriptableObject profile = CreateInstance(nameof(MixedRealityToolkitConfigurationProfile)); var newProfile = profile.CreateAsset("Assets/MixedRealityToolkit.Generated/CustomProfiles") as MixedRealityToolkitConfigurationProfile; UnityEditor.Undo.RecordObject(MixedRealityToolkit.Instance, "Create new profiles"); MixedRealityToolkit.Instance.ActiveProfile = newProfile; Selection.activeObject = newProfile; } } EditorGUILayout.EndHorizontal(); EditorGUILayout.LabelField(string.Empty, GUI.skin.horizontalSlider); } bool isGUIEnabled = !IsProfileLock((BaseMixedRealityProfile)target) && GUI.enabled; GUI.enabled = isGUIEnabled; EditorGUI.BeginChangeCheck(); bool changed = false; // Experience configuration ExperienceScale experienceScale = (ExperienceScale)targetExperienceScale.intValue; EditorGUILayout.PropertyField(targetExperienceScale, TargetScaleContent); string scaleDescription = GetExperienceDescription(experienceScale); if (!string.IsNullOrEmpty(scaleDescription)) { EditorGUILayout.HelpBox(scaleDescription, MessageType.Info); EditorGUILayout.Space(); } changed |= EditorGUI.EndChangeCheck(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(100)); GUI.enabled = true; // Force enable so we can view profile defaults int prefsSelectedTab = EditorPrefs.GetInt(SelectedTabPreferenceKey); SelectedProfileTab = GUILayout.SelectionGrid(prefsSelectedTab, ProfileTabTitles, 1, EditorStyles.boldLabel, GUILayout.MaxWidth(125)); if (SelectedProfileTab != prefsSelectedTab) { EditorPrefs.SetInt(SelectedTabPreferenceKey, SelectedProfileTab); } GUI.enabled = isGUIEnabled; EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); using (new EditorGUI.IndentLevelScope()) { changed |= RenderProfileFuncs[SelectedProfileTab](); } EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); serializedObject.ApplyModifiedProperties(); GUI.enabled = true; if (changed && MixedRealityToolkit.IsInitialized) { EditorApplication.delayCall += () => MixedRealityToolkit.Instance.ResetConfiguration(configurationProfile); } }
private static bool RenderProfileInternal(SerializedProperty property, GUIContent guiContent, bool showAddButton, Type serviceType = null) { profile = property.serializedObject.targetObject as BaseMixedRealityProfile; bool changed = false; var oldObject = property.objectReferenceValue; // If we're constraining this to a service type, check whether the profile is valid // If it isn't, issue a warning. if (serviceType != null && oldObject != null) { bool profileTypeIsValid = false; foreach (MixedRealityServiceProfileAttribute serviceProfileAttribute in oldObject.GetType().GetCustomAttributes(typeof(MixedRealityServiceProfileAttribute), true)) { if (serviceProfileAttribute.ServiceType.IsAssignableFrom(serviceType)) { profileTypeIsValid = true; break; } } if (!profileTypeIsValid) { EditorGUILayout.HelpBox("This profile is not supported for " + serviceType.Name + ". Using an unsupported service may result in unexpected behavior.", MessageType.Warning); } } EditorGUILayout.BeginHorizontal(); if (guiContent == null) { EditorGUILayout.PropertyField(property); } else { EditorGUILayout.PropertyField(property, guiContent); } if (property.objectReferenceValue == null) { if (showAddButton) { if (GUILayout.Button(NewProfileContent, EditorStyles.miniButton, GUILayout.Width(20f))) { var profileTypeName = property.type.Replace("PPtr<$", string.Empty).Replace(">", string.Empty); Debug.Assert(profileTypeName != null, "No Type Found"); ScriptableObject instance = CreateInstance(profileTypeName); var newProfile = instance.CreateAsset(AssetDatabase.GetAssetPath(Selection.activeObject)) as BaseMixedRealityProfile; property.objectReferenceValue = newProfile; property.serializedObject.ApplyModifiedProperties(); changed = true; } } } else { var renderedProfile = property.objectReferenceValue as BaseMixedRealityProfile; Debug.Assert(renderedProfile != null); Debug.Assert(profile != null, "No profile was set in OnEnable. Did you forget to call base.OnEnable in a derived profile class?"); if (GUILayout.Button(new GUIContent("Clone", "Replace with a copy of the default profile."), EditorStyles.miniButton, GUILayout.Width(42f))) { MixedRealityProfileCloneWindow.OpenWindow(profile, renderedProfile, property); } } EditorGUILayout.EndHorizontal(); // Check fields within profile for other nested profiles // Draw them when found if (property.objectReferenceValue != null) { Type profileType = property.objectReferenceValue.GetType(); if (typeof(BaseMixedRealityProfile).IsAssignableFrom(profileType)) { string showFoldoutKey = GetSubProfileDropdownKey(property); bool showFoldout = SessionState.GetBool(showFoldoutKey, false); showFoldout = EditorGUILayout.Foldout(showFoldout, showFoldout ? "Hide " + property.displayName + " contents" : "Show " + property.displayName + " contents", true); if (showFoldout) { UnityEditor.Editor subProfileEditor = UnityEditor.Editor.CreateEditor(property.objectReferenceValue); // If this is a default MRTK configuration profile, ask it to render as a sub-profile if (typeof(BaseMixedRealityToolkitConfigurationProfileInspector).IsAssignableFrom(subProfileEditor.GetType())) { BaseMixedRealityToolkitConfigurationProfileInspector configProfile = (BaseMixedRealityToolkitConfigurationProfileInspector)subProfileEditor; configProfile.RenderAsSubProfile = true; } EditorGUI.indentLevel++; EditorGUILayout.BeginVertical(EditorStyles.helpBox); subProfileEditor.OnInspectorGUI(); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.EndVertical(); EditorGUI.indentLevel--; } SessionState.SetBool(showFoldoutKey, showFoldout); } } return(changed); }
/// <summary> /// Renders a <see cref="Microsoft.MixedReality.Toolkit.BaseMixedRealityProfile"/>. /// </summary> /// <param name="property">the <see cref="Microsoft.MixedReality.Toolkit.BaseMixedRealityProfile"/> property.</param> /// <param name="showAddButton">If true, draw the clone button, if false, don't</param> /// <param name="renderProfileInBox">if true, render box around profile content, if false, don't</param> /// <param name="serviceType">Optional service type to limit available profile types.</param> /// <returns>True, if the profile changed.</returns> private static bool RenderProfileInternal(SerializedProperty property, Type profileType, bool showAddButton, bool renderProfileInBox, Type serviceType = null) { var profile = property.serializedObject.targetObject as BaseMixedRealityProfile; bool changed = false; var oldObject = property.objectReferenceValue; if (profileType != null && !profileType.IsSubclassOf(typeof(BaseMixedRealityProfile)) && profileType != typeof(BaseMixedRealityProfile)) { // If they've drag-and-dropped a non-profile scriptable object, set it to null. profileType = null; } // If we're constraining this to a service type, check whether the profile is valid // If it isn't, issue a warning. if (serviceType != null && oldObject != null) { if (!IsProfileForService(oldObject.GetType(), serviceType)) { EditorGUILayout.HelpBox("This profile is not supported for " + serviceType.Name + ". Using an unsupported service may result in unexpected behavior.", MessageType.Warning); } } // Find the profile type so we can limit the available object field options if (serviceType != null) { // If GetProfileTypesForService has a count greater than one, then it won't be possible to use // EditorGUILayout.ObjectField to restrict the set of profiles to a single type - in this // case all profiles of BaseMixedRealityProfile will be visible in the picker. // // However in the case where there is just a single profile type for the service, we can improve // upon the user experience by limiting the set of things that show in the picker by restricting // the set of profiles listed to only that type. profileType = GetProfileTypesForService(serviceType).FirstOrDefault(); } // If the profile type is still null, just set it to base profile type if (profileType == null) { profileType = typeof(BaseMixedRealityProfile); } // Begin the horizontal group EditorGUILayout.BeginHorizontal(); // Draw the object field with an empty label - label is kept in the foldout property.objectReferenceValue = EditorGUILayout.ObjectField(oldObject != null ? "" : property.displayName, oldObject, profileType, false, GUILayout.ExpandWidth(true)); changed = (property.objectReferenceValue != oldObject); // Draw the clone button if (property.objectReferenceValue == null) { var profileTypeName = property.type.Replace("PPtr<$", string.Empty).Replace(">", string.Empty); if (showAddButton && IsConcreteProfileType(profileTypeName)) { if (GUILayout.Button(NewProfileContent, EditorStyles.miniButton, GUILayout.Width(20f))) { Debug.Assert(profileTypeName != null, "No Type Found"); ScriptableObject instance = CreateInstance(profileTypeName); var newProfile = instance.CreateAsset(AssetDatabase.GetAssetPath(Selection.activeObject)) as BaseMixedRealityProfile; property.objectReferenceValue = newProfile; property.serializedObject.ApplyModifiedProperties(); changed = true; } } } else { var renderedProfile = property.objectReferenceValue as BaseMixedRealityProfile; Debug.Assert(renderedProfile != null); Debug.Assert(profile != null, "No profile was set in OnEnable. Did you forget to call base.OnEnable in a derived profile class?"); if (GUILayout.Button(new GUIContent("Clone", "Replace with a copy of the default profile."), EditorStyles.miniButton, GUILayout.Width(42f))) { MixedRealityProfileCloneWindow.OpenWindow(profile, renderedProfile, property); } } EditorGUILayout.EndHorizontal(); if (property.objectReferenceValue != null) { UnityEditor.Editor subProfileEditor = UnityEditor.Editor.CreateEditor(property.objectReferenceValue); // If this is a default MRTK configuration profile, ask it to render as a sub-profile if (typeof(BaseMixedRealityToolkitConfigurationProfileInspector).IsAssignableFrom(subProfileEditor.GetType())) { BaseMixedRealityToolkitConfigurationProfileInspector configProfile = (BaseMixedRealityToolkitConfigurationProfileInspector)subProfileEditor; configProfile.RenderAsSubProfile = true; } var subProfile = property.objectReferenceValue as BaseMixedRealityProfile; if (subProfile != null && !subProfile.IsCustomProfile) { EditorGUILayout.HelpBox("Clone this default profile to edit properties below", MessageType.Warning); } if (renderProfileInBox) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); } else { EditorGUILayout.BeginVertical(); } EditorGUILayout.Space(); subProfileEditor.OnInspectorGUI(); EditorGUILayout.Space(); EditorGUILayout.EndVertical(); } return(changed); }