Commit 29de0c28 authored by BlackAngle233's avatar BlackAngle233
Browse files

10.19 learned

parent 912976bb
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input.Editor
{
[CustomEditor(typeof(MixedRealityGesturesProfile))]
public class MixedRealityGesturesProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private static readonly GUIContent MinusButtonContent = new GUIContent("-", "Remove defined Gesture");
private static readonly GUIContent AddButtonContent = new GUIContent("+ Add a New defined Gesture");
private static readonly GUIContent DescriptionContent = new GUIContent("Description", "The human readable description of the Gesture.");
private static readonly GUIContent GestureTypeContent = new GUIContent("Gesture Type", "The type of Gesture that will trigger the action.");
private static readonly GUIContent ActionContent = new GUIContent("Action", "The action to trigger when a Gesture is recognized.");
private const string ProfileTitle = "Gesture Settings";
private const string ProfileDescription = "This gesture map is any and all movements of part the user's body, especially a hand or the head, that raise actions through the input system.\n\n" +
"Note: Defined controllers can look up the list of gestures and raise the events based on specific criteria.";
private SerializedProperty gestures;
private SerializedProperty windowsManipulationGestureSettings;
private SerializedProperty useRailsNavigation;
private SerializedProperty windowsNavigationGestureSettings;
private SerializedProperty windowsRailsNavigationGestures;
private SerializedProperty windowsGestureAutoStart;
private MixedRealityGesturesProfile thisProfile;
private static GUIContent[] allGestureLabels;
private static int[] allGestureIds;
private static GUIContent[] actionLabels = Array.Empty<GUIContent>();
private static int[] actionIds = Array.Empty<int>();
private bool isInitialized = false;
protected override void OnEnable()
{
base.OnEnable();
isInitialized = false;
gestures = serializedObject.FindProperty("gestures");
windowsManipulationGestureSettings = serializedObject.FindProperty("manipulationGestures");
useRailsNavigation = serializedObject.FindProperty("useRailsNavigation");
windowsNavigationGestureSettings = serializedObject.FindProperty("navigationGestures");
windowsRailsNavigationGestures = serializedObject.FindProperty("railsNavigationGestures");
windowsGestureAutoStart = serializedObject.FindProperty("windowsGestureAutoStart");
thisProfile = target as MixedRealityGesturesProfile;
Debug.Assert(thisProfile != null);
UpdateGestureLabels();
if (!IsProfileInActiveInstance()
|| MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile == null)
{
return;
}
var inputActions = MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile.InputActions;
actionLabels = inputActions.Select(action => new GUIContent(action.Description)).Prepend(new GUIContent("None")).ToArray();
actionIds = inputActions.Select(action => (int)action.Id).Prepend(0).ToArray();
isInitialized = true;
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile != null &&
profile == MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.GesturesProfile;
}
private void UpdateGestureLabels()
{
var allGestureTypeNames = Enum.GetNames(typeof(GestureInputType));
var tempIds = new List<int>();
var tempContent = new List<GUIContent>();
for (int i = 0; i < allGestureTypeNames.Length; i++)
{
if (allGestureTypeNames[i].Equals("None") ||
thisProfile.Gestures.All(mapping => !allGestureTypeNames[i].Equals(mapping.GestureType.ToString())))
{
tempContent.Add(new GUIContent(allGestureTypeNames[i]));
tempIds.Add(i);
}
}
allGestureIds = tempIds.ToArray();
allGestureLabels = tempContent.ToArray();
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, isInitialized, BackProfileType.Input))
{
return;
}
CheckMixedRealityInputActions();
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Windows Gesture Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(windowsManipulationGestureSettings);
EditorGUILayout.PropertyField(windowsNavigationGestureSettings);
EditorGUILayout.PropertyField(useRailsNavigation);
EditorGUILayout.PropertyField(windowsRailsNavigationGestures);
EditorGUILayout.PropertyField(windowsGestureAutoStart);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Defined Recognizable Gestures", EditorStyles.boldLabel);
RenderList(gestures);
serializedObject.ApplyModifiedProperties();
}
}
private void RenderList(SerializedProperty list)
{
// Disable gestures list if we could not initialize successfully
using (new EditorGUI.DisabledGroupScope(!isInitialized))
{
EditorGUILayout.Space();
using (new EditorGUILayout.VerticalScope())
{
if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
{
list.arraySize += 1;
var speechCommand = list.GetArrayElementAtIndex(list.arraySize - 1);
var keyword = speechCommand.FindPropertyRelative("description");
keyword.stringValue = string.Empty;
var gestureType = speechCommand.FindPropertyRelative("gestureType");
gestureType.intValue = (int)GestureInputType.None;
var action = speechCommand.FindPropertyRelative("action");
var actionId = action.FindPropertyRelative("id");
actionId.intValue = 0;
var actionDescription = action.FindPropertyRelative("description");
actionDescription.stringValue = string.Empty;
var actionConstraint = action.FindPropertyRelative("axisConstraint");
actionConstraint.intValue = 0;
}
if (list == null || list.arraySize == 0)
{
EditorGUILayout.HelpBox("Define a new Gesture.", MessageType.Warning);
UpdateGestureLabels();
return;
}
using (new EditorGUILayout.HorizontalScope())
{
var labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 24f;
EditorGUILayout.LabelField(DescriptionContent, GUILayout.ExpandWidth(true));
EditorGUILayout.LabelField(GestureTypeContent, GUILayout.Width(80f));
EditorGUILayout.LabelField(ActionContent, GUILayout.Width(64f));
EditorGUILayout.LabelField(string.Empty, GUILayout.Width(24f));
EditorGUIUtility.labelWidth = labelWidth;
}
var inputActions = GetInputActions();
for (int i = 0; i < list.arraySize; i++)
{
using (new EditorGUILayout.HorizontalScope())
{
SerializedProperty gesture = list.GetArrayElementAtIndex(i);
var keyword = gesture.FindPropertyRelative("description");
var gestureType = gesture.FindPropertyRelative("gestureType");
var action = gesture.FindPropertyRelative("action");
var actionId = action.FindPropertyRelative("id");
var actionDescription = action.FindPropertyRelative("description");
var actionConstraint = action.FindPropertyRelative("axisConstraint");
EditorGUILayout.PropertyField(keyword, GUIContent.none, GUILayout.ExpandWidth(true));
Debug.Assert(allGestureLabels.Length == allGestureIds.Length);
var gestureLabels = new GUIContent[allGestureLabels.Length + 1];
var gestureIds = new int[allGestureIds.Length + 1];
gestureLabels[0] = new GUIContent(((GestureInputType)gestureType.intValue).ToString());
gestureIds[0] = gestureType.intValue;
for (int j = 0; j < allGestureLabels.Length; j++)
{
gestureLabels[j + 1] = allGestureLabels[j];
gestureIds[j + 1] = allGestureIds[j];
}
EditorGUI.BeginChangeCheck();
gestureType.intValue = EditorGUILayout.IntPopup(GUIContent.none, gestureType.intValue, gestureLabels, gestureIds, GUILayout.Width(80f));
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
UpdateGestureLabels();
}
EditorGUI.BeginChangeCheck();
actionId.intValue = EditorGUILayout.IntPopup(GUIContent.none, actionId.intValue, actionLabels, actionIds, GUILayout.Width(64f));
if (EditorGUI.EndChangeCheck())
{
MixedRealityInputAction inputAction = MixedRealityInputAction.None;
int idx = actionId.intValue - 1;
if (idx >= 0 && idx < inputActions.Length)
{
inputAction = inputActions[idx];
}
actionDescription.stringValue = inputAction.Description;
actionConstraint.enumValueIndex = (int)inputAction.AxisConstraint;
serializedObject.ApplyModifiedProperties();
}
if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
{
list.DeleteArrayElementAtIndex(i);
serializedObject.ApplyModifiedProperties();
UpdateGestureLabels();
}
}
}
}
}
}
private static MixedRealityInputAction[] GetInputActions()
{
if (!MixedRealityToolkit.IsInitialized ||
!MixedRealityToolkit.Instance.HasActiveProfile ||
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile == null ||
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile == null)
{
return Array.Empty<MixedRealityInputAction>();
}
return MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile.InputActions;
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using UnityEditor;
namespace Microsoft.MixedReality.Toolkit.Inspectors
{
[CustomEditor(typeof(MixedRealityHandTrackingProfile))]
public class MixedRealityHandTrackingProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private SerializedProperty jointPrefab;
private SerializedProperty palmPrefab;
private SerializedProperty fingertipPrefab;
private SerializedProperty handMeshPrefab;
private SerializedProperty handMeshVisualizationModes;
private SerializedProperty handJointVisualizationModes;
private const string ProfileTitle = "Hand Tracking Settings";
private const string ProfileDescription = "Use this for hand tracking settings.";
protected override void OnEnable()
{
base.OnEnable();
jointPrefab = serializedObject.FindProperty("jointPrefab");
fingertipPrefab = serializedObject.FindProperty("fingertipPrefab");
palmPrefab = serializedObject.FindProperty("palmPrefab");
handMeshPrefab = serializedObject.FindProperty("handMeshPrefab");
handMeshVisualizationModes = serializedObject.FindProperty("handMeshVisualizationModes");
handJointVisualizationModes = serializedObject.FindProperty("handJointVisualizationModes");
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, true, BackProfileType.Input))
{
return;
}
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
EditorGUILayout.LabelField("General settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(jointPrefab);
EditorGUILayout.PropertyField(palmPrefab);
EditorGUILayout.PropertyField(fingertipPrefab);
EditorGUILayout.PropertyField(handMeshPrefab);
EditorGUILayout.PropertyField(handMeshVisualizationModes);
EditorGUILayout.PropertyField(handJointVisualizationModes);
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile != null &&
profile == MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.HandTrackingProfile;
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using Microsoft.MixedReality.Toolkit.Utilities;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input.Editor
{
[CustomEditor(typeof(MixedRealityInputActionRulesProfile))]
public class MixedRealityInputActionRulesInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private static readonly GUIContent RuleAddButtonContent = new GUIContent("+ Add a New Rule Definition");
private static readonly GUIContent RuleMinusButtonContent = new GUIContent("-", "Remove Rule Definition");
private static readonly GUIContent BaseActionContent = new GUIContent("Base Input Action:", "The Action that will raise new actions based on the criteria met");
private static readonly GUIContent RuleActionContent = new GUIContent("Rule Input Action:", "The Action that will be raised when the criteria is met");
private static readonly GUIContent CriteriaContent = new GUIContent("Action Criteria:", "The Criteria that must be met in order to raise the new Action");
private const string ProfileTitle = "Input Action Rule Settings";
private const string ProfileDescription = "Input Action Rules help define alternative Actions that will be raised based on specific criteria.\n\n" +
"You can create new rules by assigning a base Input Action below, then assigning the criteria you'd like to meet. When the criteria is met, the Rule's Action will be raised with the criteria value.\n\n" +
"Note: Rules can only be created for the same axis constraints.";
private SerializedProperty inputActionRulesDigital;
private SerializedProperty inputActionRulesSingleAxis;
private SerializedProperty inputActionRulesDualAxis;
private SerializedProperty inputActionRulesVectorAxis;
private SerializedProperty inputActionRulesQuaternionAxis;
private SerializedProperty inputActionRulesPoseAxis;
private int[] baseActionIds = System.Array.Empty<int>();
private string[] baseActionLabels = System.Array.Empty<string>();
// These are marked as static because this inspector will reset itself every refresh
// because it can be rendered as a sub-profile and thus OnEnable() is called every time
private static int[] ruleActionIds = System.Array.Empty<int>();
private static string[] ruleActionLabels = System.Array.Empty<string>();
private static int selectedBaseActionId = 0;
private static int selectedRuleActionId = 0;
private static MixedRealityInputAction currentBaseAction = MixedRealityInputAction.None;
private static MixedRealityInputAction currentRuleAction = MixedRealityInputAction.None;
private static bool currentBoolCriteria;
private static float currentSingleAxisCriteria;
private static Vector2 currentDualAxisCriteria;
private static Vector3 currentVectorCriteria;
private static Quaternion currentQuaternionCriteria;
private static MixedRealityPose currentPoseCriteria;
private static bool[] digitalFoldouts;
private static bool[] singleAxisFoldouts;
private static bool[] dualAxisFoldouts;
private static bool[] vectorFoldouts;
private static bool[] quaternionFoldouts;
private static bool[] poseFoldouts;
private MixedRealityInputActionRulesProfile thisProfile;
private bool isInitialized = false;
protected override void OnEnable()
{
base.OnEnable();
isInitialized = false;
inputActionRulesDigital = serializedObject.FindProperty("inputActionRulesDigital");
inputActionRulesSingleAxis = serializedObject.FindProperty("inputActionRulesSingleAxis");
inputActionRulesDualAxis = serializedObject.FindProperty("inputActionRulesDualAxis");
inputActionRulesVectorAxis = serializedObject.FindProperty("inputActionRulesVectorAxis");
inputActionRulesQuaternionAxis = serializedObject.FindProperty("inputActionRulesQuaternionAxis");
inputActionRulesPoseAxis = serializedObject.FindProperty("inputActionRulesPoseAxis");
thisProfile = target as MixedRealityInputActionRulesProfile;
// Only reset if we haven't get done so
if (digitalFoldouts == null)
{
ResetCriteria();
}
if (!IsProfileInActiveInstance()
|| MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile == null)
{
return;
}
var inputActions = GetInputActions();
baseActionLabels = inputActions.Where(action => action.AxisConstraint != AxisType.None && action.AxisConstraint != AxisType.Raw)
.Select(action => action.Description).ToArray();
baseActionIds = inputActions.Where(action => action.AxisConstraint != AxisType.None && action.AxisConstraint != AxisType.Raw)
.Select(action => (int)action.Id).ToArray();
isInitialized = true;
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, isInitialized, BackProfileType.Input))
{
return;
}
CheckMixedRealityInputActions();
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
selectedBaseActionId = RenderBaseInputAction(selectedBaseActionId, out currentBaseAction);
using (new EditorGUI.DisabledGroupScope(currentBaseAction == MixedRealityInputAction.None))
{
RenderCriteriaField(currentBaseAction);
if (selectedBaseActionId == selectedRuleActionId)
{
selectedRuleActionId = 0;
}
selectedRuleActionId = RenderRuleInputAction(selectedRuleActionId, out currentRuleAction);
EditorGUILayout.Space();
}
bool addButtonEnable = !RuleExists() &&
currentBaseAction != MixedRealityInputAction.None &&
currentRuleAction != MixedRealityInputAction.None &&
currentBaseAction.AxisConstraint != AxisType.None &&
currentBaseAction.AxisConstraint != AxisType.Raw;
using (new EditorGUI.DisabledGroupScope(!addButtonEnable))
{
if (InspectorUIUtility.RenderIndentedButton(RuleAddButtonContent, EditorStyles.miniButton))
{
AddRule();
ResetCriteria();
}
}
EditorGUILayout.Space();
var isWideMode = EditorGUIUtility.wideMode;
EditorGUIUtility.wideMode = true;
RenderList(inputActionRulesDigital, digitalFoldouts);
RenderList(inputActionRulesSingleAxis, singleAxisFoldouts);
RenderList(inputActionRulesDualAxis, dualAxisFoldouts);
RenderList(inputActionRulesVectorAxis, vectorFoldouts);
RenderList(inputActionRulesQuaternionAxis, quaternionFoldouts);
RenderList(inputActionRulesPoseAxis, poseFoldouts);
EditorGUIUtility.wideMode = isWideMode;
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile != null &&
profile == MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionRulesProfile;
}
private bool RuleExists()
{
switch (currentBaseAction.AxisConstraint)
{
default:
return false;
case AxisType.Digital:
return thisProfile.InputActionRulesDigital.Any(digitalRule => digitalRule.BaseAction == currentBaseAction && digitalRule.RuleAction == currentRuleAction && digitalRule.Criteria == currentBoolCriteria);
case AxisType.SingleAxis:
return thisProfile.InputActionRulesSingleAxis.Any(singleAxisRule => singleAxisRule.BaseAction == currentBaseAction && singleAxisRule.RuleAction == currentRuleAction && singleAxisRule.Criteria.Equals(currentSingleAxisCriteria));
case AxisType.DualAxis:
return thisProfile.InputActionRulesDualAxis.Any(dualAxisRule => dualAxisRule.BaseAction == currentBaseAction && dualAxisRule.RuleAction == currentRuleAction && dualAxisRule.Criteria == currentDualAxisCriteria);
case AxisType.ThreeDofPosition:
return thisProfile.InputActionRulesVectorAxis.Any(vectorAxisRule => vectorAxisRule.BaseAction == currentBaseAction && vectorAxisRule.RuleAction == currentRuleAction && vectorAxisRule.Criteria == currentVectorCriteria);
case AxisType.ThreeDofRotation:
return thisProfile.InputActionRulesQuaternionAxis.Any(quaternionRule => quaternionRule.BaseAction == currentBaseAction && quaternionRule.RuleAction == currentRuleAction && quaternionRule.Criteria == currentQuaternionCriteria);
case AxisType.SixDof:
return thisProfile.InputActionRulesPoseAxis.Any(poseRule => poseRule.BaseAction == currentBaseAction && poseRule.RuleAction == currentRuleAction && poseRule.Criteria == currentPoseCriteria);
}
}
private void ResetCriteria()
{
selectedBaseActionId = 0;
selectedRuleActionId = 0;
currentBaseAction = MixedRealityInputAction.None;
currentRuleAction = MixedRealityInputAction.None;
currentBoolCriteria = false;
currentSingleAxisCriteria = 0f;
currentDualAxisCriteria = Vector2.zero;
currentVectorCriteria = Vector3.zero;
currentQuaternionCriteria = Quaternion.identity;
currentPoseCriteria = MixedRealityPose.ZeroIdentity;
digitalFoldouts = new bool[inputActionRulesDigital.arraySize];
singleAxisFoldouts = new bool[inputActionRulesSingleAxis.arraySize];
dualAxisFoldouts = new bool[inputActionRulesDualAxis.arraySize];
vectorFoldouts = new bool[inputActionRulesVectorAxis.arraySize];
quaternionFoldouts = new bool[inputActionRulesQuaternionAxis.arraySize];
poseFoldouts = new bool[inputActionRulesPoseAxis.arraySize];
}
private static void GetCompatibleActions(MixedRealityInputAction baseAction)
{
var inputActions = GetInputActions();
ruleActionLabels = inputActions.Where(inputAction => inputAction.AxisConstraint == baseAction.AxisConstraint && inputAction.Id != baseAction.Id)
.Select(action => action.Description).ToArray();
ruleActionIds = inputActions.Where(inputAction => inputAction.AxisConstraint == baseAction.AxisConstraint && inputAction.Id != baseAction.Id)
.Select(action => (int)action.Id).ToArray();
}
private void RenderCriteriaField(MixedRealityInputAction action, SerializedProperty criteriaValue = null)
{
var isWideMode = EditorGUIUtility.wideMode;
EditorGUIUtility.wideMode = true;
if (action != MixedRealityInputAction.None)
{
switch (action.AxisConstraint)
{
default:
EditorGUILayout.HelpBox("Base rule must have a valid axis constraint.", MessageType.Warning);
break;
case AxisType.Digital:
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(CriteriaContent, GUILayout.Width(128));
EditorGUI.BeginChangeCheck();
var boolValue = EditorGUILayout.Toggle(GUIContent.none, criteriaValue?.boolValue ?? currentBoolCriteria, GUILayout.Width(64), GUILayout.ExpandWidth(true));
if (EditorGUI.EndChangeCheck())
{
if (criteriaValue != null)
{
criteriaValue.boolValue = boolValue;
}
else
{
currentBoolCriteria = boolValue;
}
}
}
break;
case AxisType.SingleAxis:
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(CriteriaContent, GUILayout.Width(128));
EditorGUI.BeginChangeCheck();
var floatValue = EditorGUILayout.FloatField(GUIContent.none, criteriaValue?.floatValue ?? currentSingleAxisCriteria, GUILayout.Width(64), GUILayout.ExpandWidth(true));
if (EditorGUI.EndChangeCheck())
{
if (criteriaValue != null)
{
criteriaValue.floatValue = floatValue;
}
else
{
currentSingleAxisCriteria = floatValue;
}
}
}
break;
case AxisType.DualAxis:
EditorGUILayout.LabelField(CriteriaContent, GUILayout.Width(128));
using (new EditorGUI.IndentLevelScope())
{
EditorGUI.BeginChangeCheck();
var dualAxisValue = EditorGUILayout.Vector2Field("Position", criteriaValue?.vector2Value ?? currentDualAxisCriteria, GUILayout.Width(64), GUILayout.ExpandWidth(true));
if (EditorGUI.EndChangeCheck())
{
if (criteriaValue != null)
{
criteriaValue.vector2Value = dualAxisValue;
}
else
{
currentDualAxisCriteria = dualAxisValue;
}
}
}
break;
case AxisType.ThreeDofPosition:
EditorGUILayout.LabelField(CriteriaContent, GUILayout.Width(128));
using (new EditorGUI.IndentLevelScope())
{
EditorGUI.BeginChangeCheck();
var positionValue = EditorGUILayout.Vector3Field("Position", criteriaValue?.vector3Value ?? currentVectorCriteria, GUILayout.ExpandWidth(true));
if (EditorGUI.EndChangeCheck())
{
if (criteriaValue != null)
{
criteriaValue.vector3Value = positionValue;
}
else
{
currentVectorCriteria = positionValue;
}
}
}
break;
case AxisType.ThreeDofRotation:
EditorGUILayout.LabelField(CriteriaContent, GUILayout.Width(128));
using (new EditorGUI.IndentLevelScope())
{
EditorGUI.BeginChangeCheck();
var rotationValue = EditorGUILayout.Vector3Field("Rotation", criteriaValue?.quaternionValue.eulerAngles ?? currentQuaternionCriteria.eulerAngles, GUILayout.ExpandWidth(true));
if (EditorGUI.EndChangeCheck())
{
if (criteriaValue != null)
{
criteriaValue.quaternionValue = Quaternion.Euler(rotationValue);
}
else
{
currentQuaternionCriteria = Quaternion.Euler(rotationValue);
}
}
}
break;
case AxisType.SixDof:
EditorGUILayout.LabelField(CriteriaContent, GUILayout.Width(128));
using (new EditorGUI.IndentLevelScope())
{
var posePosition = currentPoseCriteria.Position;
var poseRotation = currentPoseCriteria.Rotation;
if (criteriaValue != null)
{
posePosition = criteriaValue.FindPropertyRelative("position").vector3Value;
poseRotation = criteriaValue.FindPropertyRelative("rotation").quaternionValue;
}
EditorGUI.BeginChangeCheck();
posePosition = EditorGUILayout.Vector3Field("Position", posePosition);
poseRotation.eulerAngles = EditorGUILayout.Vector3Field("Rotation", poseRotation.eulerAngles);
if (EditorGUI.EndChangeCheck())
{
if (criteriaValue != null)
{
criteriaValue.FindPropertyRelative("position").vector3Value = posePosition;
criteriaValue.FindPropertyRelative("rotation").quaternionValue = poseRotation;
}
else
{
currentPoseCriteria.Position = posePosition;
currentPoseCriteria.Rotation = poseRotation;
}
}
}
break;
}
EditorGUIUtility.wideMode = isWideMode;
}
}
private void AddRule()
{
SerializedProperty rule;
switch (currentBaseAction.AxisConstraint)
{
case AxisType.Digital:
inputActionRulesDigital.arraySize += 1;
rule = inputActionRulesDigital.GetArrayElementAtIndex(inputActionRulesDigital.arraySize - 1);
rule.FindPropertyRelative("criteria").boolValue = currentBoolCriteria;
break;
case AxisType.SingleAxis:
inputActionRulesSingleAxis.arraySize += 1;
rule = inputActionRulesSingleAxis.GetArrayElementAtIndex(inputActionRulesSingleAxis.arraySize - 1);
rule.FindPropertyRelative("criteria").floatValue = currentSingleAxisCriteria;
break;
case AxisType.DualAxis:
inputActionRulesDualAxis.arraySize += 1;
rule = inputActionRulesDualAxis.GetArrayElementAtIndex(inputActionRulesDualAxis.arraySize - 1);
rule.FindPropertyRelative("criteria").vector2Value = currentDualAxisCriteria;
break;
case AxisType.ThreeDofPosition:
inputActionRulesVectorAxis.arraySize += 1;
rule = inputActionRulesVectorAxis.GetArrayElementAtIndex(inputActionRulesVectorAxis.arraySize - 1);
rule.FindPropertyRelative("criteria").vector3Value = currentVectorCriteria;
break;
case AxisType.ThreeDofRotation:
inputActionRulesQuaternionAxis.arraySize += 1;
rule = inputActionRulesQuaternionAxis.GetArrayElementAtIndex(inputActionRulesQuaternionAxis.arraySize - 1);
rule.FindPropertyRelative("criteria").quaternionValue = currentQuaternionCriteria;
break;
case AxisType.SixDof:
inputActionRulesPoseAxis.arraySize += 1;
rule = inputActionRulesPoseAxis.GetArrayElementAtIndex(inputActionRulesPoseAxis.arraySize - 1);
var criteria = rule.FindPropertyRelative("criteria");
criteria.FindPropertyRelative("position").vector3Value = currentPoseCriteria.Position;
criteria.FindPropertyRelative("rotation").quaternionValue = currentPoseCriteria.Rotation;
break;
default:
Debug.LogError("Invalid Axis Constraint!");
return;
}
var baseAction = rule.FindPropertyRelative("baseAction");
var baseActionId = baseAction.FindPropertyRelative("id");
var baseActionDescription = baseAction.FindPropertyRelative("description");
var baseActionConstraint = baseAction.FindPropertyRelative("axisConstraint");
baseActionId.intValue = (int)currentBaseAction.Id;
baseActionDescription.stringValue = currentBaseAction.Description;
baseActionConstraint.intValue = (int)currentBaseAction.AxisConstraint;
var ruleAction = rule.FindPropertyRelative("ruleAction");
var ruleActionId = ruleAction.FindPropertyRelative("id");
var ruleActionDescription = ruleAction.FindPropertyRelative("description");
var ruleActionConstraint = ruleAction.FindPropertyRelative("axisConstraint");
ruleActionId.intValue = (int)currentRuleAction.Id;
ruleActionDescription.stringValue = currentRuleAction.Description;
ruleActionConstraint.intValue = (int)currentRuleAction.AxisConstraint;
}
private int RenderBaseInputAction(int baseActionId, out MixedRealityInputAction action, bool isLocked = false)
{
using (new EditorGUI.DisabledGroupScope(!isInitialized))
{
action = MixedRealityInputAction.None;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(BaseActionContent);
EditorGUI.BeginChangeCheck();
if (!isLocked)
{
baseActionId = EditorGUILayout.IntPopup(baseActionId, baseActionLabels, baseActionIds, GUILayout.ExpandWidth(true));
}
var inputActions = GetInputActions();
for (int i = 0; i < inputActions.Length; i++)
{
if (baseActionId == (int)inputActions[i].Id)
{
action = inputActions[i];
}
}
if (action != MixedRealityInputAction.None)
{
GetCompatibleActions(action);
}
if (isLocked)
{
EditorGUILayout.LabelField(action.Description, EditorStyles.boldLabel, GUILayout.ExpandWidth(true));
}
EditorGUILayout.EndHorizontal();
}
return baseActionId;
}
private int RenderRuleInputAction(int ruleActionId, out MixedRealityInputAction action)
{
action = MixedRealityInputAction.None;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(RuleActionContent, GUILayout.Width(128));
EditorGUI.BeginChangeCheck();
ruleActionId = EditorGUILayout.IntPopup(ruleActionId, ruleActionLabels, ruleActionIds, GUILayout.ExpandWidth(true));
var inputActions = GetInputActions();
for (int i = 0; i < inputActions.Length; i++)
{
if (ruleActionId == (int)inputActions[i].Id)
{
action = inputActions[i];
}
}
EditorGUILayout.EndHorizontal();
return ruleActionId;
}
private void RenderList(SerializedProperty list, bool[] foldouts)
{
for (int i = 0; i < list?.arraySize; i++)
{
var rule = list.GetArrayElementAtIndex(i);
var criteria = rule.FindPropertyRelative("criteria");
var baseAction = rule.FindPropertyRelative("baseAction");
var baseActionId = baseAction.FindPropertyRelative("id");
var baseActionDescription = baseAction.FindPropertyRelative("description");
var baseActionConstraint = baseAction.FindPropertyRelative("axisConstraint");
var ruleAction = rule.FindPropertyRelative("ruleAction");
var ruleActionId = ruleAction.FindPropertyRelative("id");
var ruleActionDescription = ruleAction.FindPropertyRelative("description");
var ruleActionConstraint = ruleAction.FindPropertyRelative("axisConstraint");
using (new EditorGUILayout.HorizontalScope())
{
foldouts[i] = EditorGUILayout.Foldout(foldouts[i], new GUIContent($"{baseActionDescription.stringValue} -> {ruleActionDescription.stringValue}"), true);
if (GUILayout.Button(RuleMinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
{
list.DeleteArrayElementAtIndex(i);
return;
}
}
if (foldouts[i])
{
EditorGUI.indentLevel++;
MixedRealityInputAction newBaseAction;
baseActionId.intValue = RenderBaseInputAction(baseActionId.intValue, out newBaseAction, true);
baseActionDescription.stringValue = newBaseAction.Description;
baseActionConstraint.intValue = (int)newBaseAction.AxisConstraint;
if (baseActionId.intValue == ruleActionId.intValue || newBaseAction == MixedRealityInputAction.None || baseActionConstraint.intValue != ruleActionConstraint.intValue)
{
criteria.Reset();
ruleActionId.intValue = (int)MixedRealityInputAction.None.Id;
ruleActionDescription.stringValue = MixedRealityInputAction.None.Description;
ruleActionConstraint.intValue = (int)MixedRealityInputAction.None.AxisConstraint;
}
RenderCriteriaField(newBaseAction, criteria);
MixedRealityInputAction newRuleAction;
ruleActionId.intValue = RenderRuleInputAction(ruleActionId.intValue, out newRuleAction);
ruleActionDescription.stringValue = newRuleAction.Description;
ruleActionConstraint.intValue = (int)newRuleAction.AxisConstraint;
EditorGUI.indentLevel--;
}
EditorGUILayout.Space();
}
}
private static MixedRealityInputAction[] GetInputActions()
{
if (!MixedRealityToolkit.IsInitialized ||
!MixedRealityToolkit.Instance.HasActiveProfile ||
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile == null ||
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile == null)
{
return System.Array.Empty<MixedRealityInputAction>();
}
return MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile.InputActions;
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input.Editor
{
[CustomEditor(typeof(MixedRealityInputActionsProfile))]
public class MixedRealityInputActionsProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private static readonly GUIContent MinusButtonContent = new GUIContent("-", "Remove Action");
private static readonly GUIContent AddButtonContent = new GUIContent("+ Add a New Action", "Add New Action");
private static readonly GUIContent ActionContent = new GUIContent("Action", "The Name of the Action.");
private static readonly GUIContent AxisConstraintContent = new GUIContent("Axis Constraint", "Optional Axis Constraint for this input source.");
private const string ProfileTitle = "Input Action Settings";
private const string ProfileDescription = "Input Actions are any/all actions your users will be able to make when interacting with your application.\n\n" +
"After defining all your actions, you can then wire up these actions to hardware sensors, controllers, and other input devices.";
private static Vector2 scrollPosition = Vector2.zero;
private SerializedProperty inputActionList;
protected override void OnEnable()
{
base.OnEnable();
inputActionList = serializedObject.FindProperty("inputActions");
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, true, BackProfileType.Input))
{
return;
}
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
RenderList(inputActionList);
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile != null &&
profile == MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile;
}
private static void RenderList(SerializedProperty list)
{
using (new EditorGUILayout.VerticalScope())
{
if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
{
list.arraySize += 1;
var inputAction = list.GetArrayElementAtIndex(list.arraySize - 1);
var inputActionId = inputAction.FindPropertyRelative("id");
var inputActionDescription = inputAction.FindPropertyRelative("description");
var inputActionConstraint = inputAction.FindPropertyRelative("axisConstraint");
inputActionConstraint.intValue = 0;
inputActionDescription.stringValue = $"New Action {inputActionId.intValue = list.arraySize}";
}
using (new EditorGUILayout.HorizontalScope())
{
var labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 36f;
EditorGUILayout.LabelField(ActionContent, GUILayout.ExpandWidth(true));
EditorGUILayout.LabelField(AxisConstraintContent, GUILayout.Width(96f));
EditorGUILayout.LabelField(string.Empty, GUILayout.Width(24f));
EditorGUIUtility.labelWidth = labelWidth;
}
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(100f));
for (int i = 0; i < list.arraySize; i++)
{
using (new EditorGUILayout.HorizontalScope())
{
var previousLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 64f;
SerializedProperty inputAction = list.GetArrayElementAtIndex(i);
SerializedProperty inputActionDescription = inputAction.FindPropertyRelative("description");
var inputActionConstraint = inputAction.FindPropertyRelative("axisConstraint");
EditorGUILayout.PropertyField(inputActionDescription, GUIContent.none);
EditorGUILayout.PropertyField(inputActionConstraint, GUIContent.none, GUILayout.Width(96f));
EditorGUIUtility.labelWidth = previousLabelWidth;
if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
{
list.DeleteArrayElementAtIndex(i);
}
}
}
EditorGUILayout.EndScrollView();
}
EditorGUILayout.Space();
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input.Editor
{
/// <summary>
/// Class handles rendering inspector view of MixedRealityInputSystemProfile object
/// </summary>
[CustomEditor(typeof(MixedRealityInputSystemProfile))]
public class MixedRealityInputSystemProfileInspector : BaseDataProviderServiceInspector
{
private const string DataProviderErrorMsg = "The Mixed Reality Input System requires one or more data providers.";
private static readonly GUIContent AddProviderContent = new GUIContent("+ Add Data Provider", "Add Data Provider");
private static readonly GUIContent RemoveProviderContent = new GUIContent("-", "Remove Data Provider");
private static bool showDataProviders = false;
private const string ShowInputSystem_DataProviders_PreferenceKey = "ShowInputSystem_DataProviders_PreferenceKey";
private SerializedProperty focusProviderType;
private SerializedProperty focusQueryBufferSize;
private SerializedProperty raycastProviderType;
private SerializedProperty focusIndividualCompoundCollider;
private static bool showPointerProperties = false;
private const string ShowInputSystem_Pointers_PreferenceKey = "ShowInputSystem_Pointers_PreferenceKey";
private SerializedProperty pointerProfile;
private static bool showActionsProperties = false;
private const string ShowInputSystem_Actions_PreferenceKey = "ShowInputSystem_Actions_PreferenceKey";
private SerializedProperty inputActionsProfile;
private SerializedProperty inputActionRulesProfile;
private static bool showControllerProperties = false;
private const string ShowInputSystem_Controller_PreferenceKey = "ShowInputSystem_Controller_PreferenceKey";
private SerializedProperty enableControllerMapping;
private SerializedProperty controllerMappingProfile;
private SerializedProperty controllerVisualizationProfile;
private static bool showGestureProperties = false;
private const string ShowInputSystem_Gesture_PreferenceKey = "ShowInputSystem_Gesture_PreferenceKey";
private SerializedProperty gesturesProfile;
private static bool showSpeechCommandsProperties = false;
private const string ShowInputSystem_Speech_PreferenceKey = "ShowInputSystem_Speech_PreferenceKey";
private SerializedProperty speechCommandsProfile;
private static bool showHandTrackingProperties = false;
private const string ShowInputSystem_HandTracking_PreferenceKey = "ShowInputSystem_HandTracking_PreferenceKey";
private SerializedProperty handTrackingProfile;
private const string ProfileTitle = "Input System Settings";
private const string ProfileDescription = "The Input System Profile helps developers configure input for cross-platform applications.";
/// <inheritdoc/>
protected override void OnEnable()
{
base.OnEnable();
focusProviderType = serializedObject.FindProperty("focusProviderType");
focusQueryBufferSize = serializedObject.FindProperty("focusQueryBufferSize");
raycastProviderType = serializedObject.FindProperty("raycastProviderType");
focusIndividualCompoundCollider = serializedObject.FindProperty("focusIndividualCompoundCollider");
inputActionsProfile = serializedObject.FindProperty("inputActionsProfile");
inputActionRulesProfile = serializedObject.FindProperty("inputActionRulesProfile");
pointerProfile = serializedObject.FindProperty("pointerProfile");
gesturesProfile = serializedObject.FindProperty("gesturesProfile");
speechCommandsProfile = serializedObject.FindProperty("speechCommandsProfile");
controllerMappingProfile = serializedObject.FindProperty("controllerMappingProfile");
enableControllerMapping = serializedObject.FindProperty("enableControllerMapping");
controllerVisualizationProfile = serializedObject.FindProperty("controllerVisualizationProfile");
handTrackingProfile = serializedObject.FindProperty("handTrackingProfile");
}
/// <inheritdoc/>
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target))
{
return;
}
bool changed = false;
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(focusProviderType);
EditorGUILayout.PropertyField(focusQueryBufferSize);
EditorGUILayout.PropertyField(raycastProviderType);
EditorGUILayout.PropertyField(focusIndividualCompoundCollider);
changed |= EditorGUI.EndChangeCheck();
EditorGUILayout.Space();
bool isSubProfile = RenderAsSubProfile;
if (!isSubProfile)
{
EditorGUI.indentLevel++;
}
RenderFoldout(ref showDataProviders, "Input Data Providers", () =>
{
using (new EditorGUI.IndentLevelScope())
{
changed |= RenderDataProviderList(AddProviderContent, RemoveProviderContent, DataProviderErrorMsg);
}
}, ShowInputSystem_DataProviders_PreferenceKey);
RenderFoldout(ref showPointerProperties, "Pointers", () =>
{
using (new EditorGUI.IndentLevelScope())
{
changed |= RenderProfile(pointerProfile, typeof(MixedRealityPointerProfile), true, false);
}
}, ShowInputSystem_Pointers_PreferenceKey);
RenderFoldout(ref showActionsProperties, "Input Actions", () =>
{
using (new EditorGUI.IndentLevelScope())
{
changed |= RenderProfile(inputActionsProfile, typeof(MixedRealityInputActionsProfile), true, false);
EditorGUILayout.Space();
EditorGUILayout.Space();
changed |= RenderProfile(inputActionRulesProfile, typeof(MixedRealityInputActionRulesProfile), true, false);
}
}, ShowInputSystem_Actions_PreferenceKey);
RenderFoldout(ref showControllerProperties, "Controllers", () =>
{
using (new EditorGUI.IndentLevelScope())
{
EditorGUILayout.PropertyField(enableControllerMapping);
changed |= RenderProfile(controllerMappingProfile, typeof(MixedRealityControllerMappingProfile), true, false);
EditorGUILayout.Space();
changed |= RenderProfile(controllerVisualizationProfile, null, true, false, typeof(IMixedRealityControllerVisualizer));
}
}, ShowInputSystem_Controller_PreferenceKey);
RenderFoldout(ref showGestureProperties, "Gestures", () =>
{
using (new EditorGUI.IndentLevelScope())
{
changed |= RenderProfile(gesturesProfile, typeof(MixedRealityGesturesProfile), true, false);
}
}, ShowInputSystem_Gesture_PreferenceKey);
RenderFoldout(ref showSpeechCommandsProperties, "Speech", () =>
{
using (new EditorGUI.IndentLevelScope())
{
changed |= RenderProfile(speechCommandsProfile, typeof(MixedRealitySpeechCommandsProfile), true, false);
}
}, ShowInputSystem_Speech_PreferenceKey);
RenderFoldout(ref showHandTrackingProperties, "Hand Tracking", () =>
{
using (new EditorGUI.IndentLevelScope())
{
changed |= RenderProfile(handTrackingProfile, typeof(MixedRealityHandTrackingProfile), true, false);
}
}, ShowInputSystem_HandTracking_PreferenceKey);
if (!isSubProfile)
{
EditorGUI.indentLevel--;
}
serializedObject.ApplyModifiedProperties();
}
if (changed && MixedRealityToolkit.IsInitialized)
{
EditorApplication.delayCall += () => MixedRealityToolkit.Instance.ResetConfiguration(MixedRealityToolkit.Instance.ActiveProfile);
}
}
/// <inheritdoc/>
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
profile == MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile;
}
#region DataProvider Inspector Utilities
/// <inheritdoc/>
protected override SerializedProperty GetDataProviderConfigurationList()
{
return serializedObject.FindProperty("dataProviderConfigurations");
}
/// <inheritdoc/>
protected override ServiceConfigurationProperties GetDataProviderConfigurationProperties(SerializedProperty providerEntry)
{
return new ServiceConfigurationProperties()
{
componentName = providerEntry.FindPropertyRelative("componentName"),
componentType = providerEntry.FindPropertyRelative("componentType"),
providerProfile = providerEntry.FindPropertyRelative("deviceManagerProfile"),
runtimePlatform = providerEntry.FindPropertyRelative("runtimePlatform"),
};
}
/// <inheritdoc/>
protected override IMixedRealityServiceConfiguration GetDataProviderConfiguration(int index)
{
MixedRealityInputSystemProfile targetProfile = target as MixedRealityInputSystemProfile;
if (targetProfile != null)
{
var configurations = targetProfile.DataProviderConfigurations;
if (configurations != null && index >= 0 && index < configurations.Length)
{
return configurations[index];
}
}
return null;
}
#endregion
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using Microsoft.MixedReality.Toolkit.Input.UnityInput;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using UnityEditor;
namespace Microsoft.MixedReality.Toolkit.Input
{
[CustomEditor(typeof(MixedRealityMouseInputProfile))]
public class MixedRealityMouseInputProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private const string ProfileTitle = "Mouse Input Settings";
private const string ProfileDescription = "Settings used to configure the behavior of mouse controllers.";
private SerializedProperty cursorSpeed;
private SerializedProperty wheelSpeed;
protected override void OnEnable()
{
base.OnEnable();
cursorSpeed = serializedObject.FindProperty("cursorSpeed");
wheelSpeed = serializedObject.FindProperty("wheelSpeed");
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, true, BackProfileType.Input))
{
return;
}
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
EditorGUILayout.PropertyField(cursorSpeed);
EditorGUILayout.PropertyField(wheelSpeed);
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
if (!MixedRealityToolkit.IsInitialized || profile == null)
{
return false;
}
var mouseManager = MixedRealityToolkit.Instance.GetService<IMixedRealityMouseDeviceManager>(null, false);
return mouseManager != null && profile == mouseManager.ConfigurationProfile;
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using Microsoft.MixedReality.Toolkit.Utilities;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input.Editor
{
[CustomEditor(typeof(MixedRealityPointerProfile))]
public class MixedRealityPointerProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private static readonly GUIContent ControllerTypeContent = new GUIContent("Controller Type", "The type of Controller this pointer will attach itself to at runtime.");
private static readonly GUIContent MinusButtonContent = new GUIContent("-", "Remove Pointer Option");
private static readonly GUIContent AddButtonContent = new GUIContent("+ Add a New Pointer Option", "Add Pointer Option");
private const string ProfileTitle = "Pointer Settings";
private const string ProfileDescription = "Pointers attach themselves onto controllers as they are initialized.";
private SerializedProperty pointingExtent;
private SerializedProperty pointingRaycastLayerMasks;
private static bool showPointerOptionProperties = true;
private SerializedProperty pointerOptions;
private SerializedProperty debugDrawPointingRays;
private SerializedProperty debugDrawPointingRayColors;
private SerializedProperty gazeCursorPrefab;
private SerializedProperty gazeProviderType;
private SerializedProperty useHeadGazeOverride;
private SerializedProperty isEyeTrackingEnabled;
private SerializedProperty showCursorWithEyeGaze;
private SerializedProperty pointerMediator;
private SerializedProperty primaryPointerSelector;
protected override void OnEnable()
{
base.OnEnable();
pointingExtent = serializedObject.FindProperty("pointingExtent");
pointingRaycastLayerMasks = serializedObject.FindProperty("pointingRaycastLayerMasks");
pointerOptions = serializedObject.FindProperty("pointerOptions");
debugDrawPointingRays = serializedObject.FindProperty("debugDrawPointingRays");
debugDrawPointingRayColors = serializedObject.FindProperty("debugDrawPointingRayColors");
gazeCursorPrefab = serializedObject.FindProperty("gazeCursorPrefab");
gazeProviderType = serializedObject.FindProperty("gazeProviderType");
useHeadGazeOverride = serializedObject.FindProperty("useHeadGazeOverride");
isEyeTrackingEnabled = serializedObject.FindProperty("isEyeTrackingEnabled");
showCursorWithEyeGaze = serializedObject.FindProperty("showCursorWithEyeGaze");
pointerMediator = serializedObject.FindProperty("pointerMediator");
primaryPointerSelector = serializedObject.FindProperty("primaryPointerSelector");
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, true, BackProfileType.Input))
{
return;
}
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Gaze Settings", EditorStyles.boldLabel);
{
EditorGUILayout.Space();
EditorGUILayout.PropertyField(gazeCursorPrefab);
EditorGUILayout.PropertyField(gazeProviderType);
EditorGUILayout.PropertyField(useHeadGazeOverride);
EditorGUILayout.PropertyField(isEyeTrackingEnabled);
EditorGUILayout.Space();
if (InspectorUIUtility.RenderIndentedButton("Customize Gaze Provider Settings"))
{
Selection.activeObject = CameraCache.Main.gameObject;
}
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Pointer Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(pointingExtent);
EditorGUILayout.PropertyField(pointingRaycastLayerMasks, true);
EditorGUILayout.PropertyField(pointerMediator);
EditorGUILayout.PropertyField(primaryPointerSelector);
EditorGUILayout.Space();
showPointerOptionProperties = EditorGUILayout.Foldout(showPointerOptionProperties, "Pointer Options", true);
if (showPointerOptionProperties)
{
using (new EditorGUI.IndentLevelScope())
{
RenderPointerList(pointerOptions);
}
}
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Debug Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(debugDrawPointingRays);
EditorGUILayout.PropertyField(debugDrawPointingRayColors, true);
}
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile != null &&
profile == MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.PointerProfile;
}
private void RenderPointerList(SerializedProperty list)
{
if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
{
pointerOptions.arraySize += 1;
var newPointerOption = list.GetArrayElementAtIndex(list.arraySize - 1);
var controllerType = newPointerOption.FindPropertyRelative("controllerType");
var handedness = newPointerOption.FindPropertyRelative("handedness");
var prefab = newPointerOption.FindPropertyRelative("pointerPrefab");
// Reset new entry
controllerType.intValue = 0;
handedness.intValue = 0;
prefab.objectReferenceValue = null;
}
if (list == null || list.arraySize == 0)
{
EditorGUILayout.HelpBox("Create a new Pointer Option entry.", MessageType.Warning);
return;
}
for (int i = 0; i < list.arraySize; i++)
{
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
{
var pointerOption = list.GetArrayElementAtIndex(i);
var controllerType = pointerOption.FindPropertyRelative("controllerType");
var handedness = pointerOption.FindPropertyRelative("handedness");
var prefab = pointerOption.FindPropertyRelative("pointerPrefab");
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.PropertyField(prefab);
if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
{
list.DeleteArrayElementAtIndex(i);
break;
}
}
EditorGUILayout.PropertyField(controllerType, ControllerTypeContent);
EditorGUILayout.PropertyField(handedness);
}
EditorGUILayout.Space();
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Editor
{
public class MixedRealityProfileCloneWindow : EditorWindow
{
public enum ProfileCloneBehavior
{
UseExisting, // Use the existing reference
CloneExisting, // Create a clone of the sub-profile
UseSubstitution, // Manually select a profile
LeaveEmpty, // Set the reference to null
}
private struct SubProfileAction
{
public SubProfileAction(
ProfileCloneBehavior behavior,
SerializedProperty property,
Object substitutionReference,
System.Type profileType)
{
Behavior = behavior;
Property = property;
SubstitutionReference = substitutionReference;
ProfileType = profileType;
TargetFolder = null;
CloneName = (SubstitutionReference != null) ? "New " + SubstitutionReference.name : "New " + profileType.Name;
}
public ProfileCloneBehavior Behavior;
public SerializedProperty Property;
public string CloneName;
public Object SubstitutionReference;
public System.Type ProfileType;
internal Object TargetFolder;
}
private const string AdvancedModeKey = "MRTK_ProfileCloneWindow_AdvancedMode_Key";
private static bool AdvancedMode = false;
protected static string DefaultCustomProfileFolder => Path.Combine(MixedRealityToolkitFiles.MapModulePath(MixedRealityToolkitModuleType.Generated), "CustomProfiles");
private const string IsCustomProfileProperty = "isCustomProfile";
private static readonly Vector2 MinWindowSizeBasic = new Vector2(500, 180);
private const float SubProfileSizeMultiplier = 95f;
private static MixedRealityProfileCloneWindow cloneWindow;
private BaseMixedRealityProfile parentProfile;
private BaseMixedRealityProfile childProfile;
private SerializedProperty childProperty;
private SerializedObject childSerializedObject;
private Object targetFolder;
private Object selectionTarget;
private string childProfileTypeName;
private string childProfileAssetName;
private List<SubProfileAction> subProfileActions = new List<SubProfileAction>();
public static void OpenWindow(BaseMixedRealityProfile parentProfile, BaseMixedRealityProfile childProfile, SerializedProperty childProperty, Object selectionTarget = null)
{
if (cloneWindow != null)
{
cloneWindow.Close();
}
cloneWindow = (MixedRealityProfileCloneWindow)GetWindow<MixedRealityProfileCloneWindow>(true, "Clone Profile", true);
cloneWindow.Initialize(parentProfile, childProfile, childProperty, selectionTarget);
cloneWindow.Show(true);
}
private void Initialize(BaseMixedRealityProfile parentProfile, BaseMixedRealityProfile childProfile, SerializedProperty childProperty, Object selectionTarget)
{
this.childProperty = childProperty;
this.parentProfile = parentProfile;
this.childProfile = childProfile;
this.selectionTarget = selectionTarget;
childSerializedObject = new SerializedObject(childProfile);
childProfileTypeName = childProfile.GetType().Name;
childProfileAssetName = "New " + childProfileTypeName;
// Find all the serialized properties for sub-profiles
SerializedProperty iterator = childSerializedObject.GetIterator();
System.Type basePropertyType = typeof(BaseMixedRealityProfile);
while (iterator.Next(true))
{
SerializedProperty subProfileProperty = childSerializedObject.FindProperty(iterator.name);
if (subProfileProperty == null)
{
continue;
}
if (!subProfileProperty.type.Contains("PPtr<$")) // Not an object reference type
{
continue;
}
string subProfileTypeName = subProfileProperty.type.Replace("PPtr<$", string.Empty).Replace(">", string.Empty).Trim();
System.Type subProfileType = FindProfileType(subProfileTypeName);
if (subProfileType == null)
{
continue;
}
if (!basePropertyType.IsAssignableFrom(subProfileType))
{
continue;
}
subProfileActions.Add(new SubProfileAction(
ProfileCloneBehavior.UseExisting,
subProfileProperty,
subProfileProperty.objectReferenceValue,
subProfileType));
}
cloneWindow.maxSize = MinWindowSizeBasic;
targetFolder = EnsureTargetFolder(targetFolder);
}
private void OnGUI()
{
if (cloneWindow == null || childProfile == null)
{
Close();
return;
}
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.ObjectField("Cloning profile", childProfile, typeof(BaseMixedRealityProfile), false);
if (parentProfile != null)
{ // Only show this if we're initiating this from a parent profile
EditorGUILayout.ObjectField("from parent profile", parentProfile, typeof(BaseMixedRealityProfile), false);
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
if (subProfileActions.Count > 0)
{
AdvancedMode = EditorGUILayout.Foldout(SessionState.GetBool(AdvancedModeKey, false), "Advanced Options", true, MixedRealityStylesUtility.BoldFoldoutStyle);
SessionState.SetBool(AdvancedModeKey, AdvancedMode);
if (AdvancedMode)
{
EditorGUILayout.HelpBox("This profile has sub-profiles. By default your clone will reference the existing profiles. If you want to specify a different profile, or if you want to clone the sub-profile, use the options below.", MessageType.Info);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
for (int i = 0; i < subProfileActions.Count; i++)
{
GUI.color = Color.white;
EditorGUILayout.Space();
SubProfileAction action = subProfileActions[i];
action.Behavior = (ProfileCloneBehavior)EditorGUILayout.EnumPopup(action.Property.displayName, action.Behavior);
switch (action.Behavior)
{
case ProfileCloneBehavior.UseExisting:
GUI.color = Color.Lerp(Color.white, Color.clear, 0.5f);
EditorGUILayout.ObjectField("Existing", action.Property.objectReferenceValue, action.ProfileType, false);
break;
case ProfileCloneBehavior.UseSubstitution:
action.SubstitutionReference = EditorGUILayout.ObjectField("Substitution", action.SubstitutionReference, action.ProfileType, false);
break;
case ProfileCloneBehavior.CloneExisting:
if (action.Property.objectReferenceValue == null)
{
EditorGUILayout.LabelField("Can't clone profile - none is set.");
}
else
{
action.CloneName = EditorGUILayout.TextField("Clone name", action.CloneName);
}
using (new EditorGUILayout.HorizontalScope())
{
if (action.TargetFolder == null)
{
action.TargetFolder = targetFolder;
}
action.TargetFolder = EditorGUILayout.ObjectField("Target Folder", action.TargetFolder, typeof(DefaultAsset), false);
if (GUILayout.Button("Put in original folder", EditorStyles.miniButton, GUILayout.MaxWidth(120)))
{
string profilePath = AssetDatabase.GetAssetPath(action.Property.objectReferenceValue);
action.TargetFolder = AssetDatabase.LoadAssetAtPath<Object>(System.IO.Path.GetDirectoryName(profilePath));
}
}
break;
case ProfileCloneBehavior.LeaveEmpty:
// Add one line for formatting reasons
EditorGUILayout.LabelField(" ");
break;
}
subProfileActions[i] = action;
}
EditorGUILayout.EndVertical();
}
}
GUI.color = Color.white;
// Space between props and buttons at bottom
GUILayout.FlexibleSpace();
// Get the selected folder in the project window
using (new EditorGUILayout.HorizontalScope())
{
targetFolder = EditorGUILayout.ObjectField("Target Folder", targetFolder, typeof(DefaultAsset), false);
if (GUILayout.Button("Put in original folder", EditorStyles.miniButton, GUILayout.MaxWidth(120)))
{
string profilePath = AssetDatabase.GetAssetPath(childProfile);
targetFolder = AssetDatabase.LoadAssetAtPath<Object>(System.IO.Path.GetDirectoryName(profilePath));
}
}
EditorGUILayout.HelpBox("If no folder is provided, the profile will be cloned to the Assets/MixedRealityToolkit.Generated/CustomProfiles folder.", MessageType.Info);
childProfileAssetName = EditorGUILayout.TextField("Profile Name", childProfileAssetName);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Clone"))
{
targetFolder = EnsureTargetFolder(targetFolder);
CloneMainProfile();
}
if (GUILayout.Button("Cancel"))
{
cloneWindow.Close();
}
}
// If there are no sub profiles, limit the max so the window isn't spawned too large
if (subProfileActions.Count <= 0 || !AdvancedMode)
{
cloneWindow.minSize = MinWindowSizeBasic;
cloneWindow.maxSize = MinWindowSizeBasic;
}
else
{
Vector2 minWindowSize = MinWindowSizeBasic;
minWindowSize.y = Mathf.Max(minWindowSize.y, subProfileActions.Count * SubProfileSizeMultiplier);
cloneWindow.minSize = minWindowSize;
cloneWindow.maxSize = minWindowSize;
}
Repaint();
}
private void CloneMainProfile()
{
var newChildProfile = CloneProfile(parentProfile, childProfile, childProfileTypeName, childProperty, targetFolder, childProfileAssetName);
SerializedObject newChildSerializedObject = new SerializedObject(newChildProfile);
// First paste all values outright
PasteProfileValues(parentProfile, childProfile, newChildSerializedObject);
// Then over-write with substitutions or clones
foreach (SubProfileAction action in subProfileActions)
{
SerializedProperty actionProperty = newChildSerializedObject.FindProperty(action.Property.name);
switch (action.Behavior)
{
case ProfileCloneBehavior.UseExisting:
// Do nothing
break;
case ProfileCloneBehavior.UseSubstitution:
// Apply the chosen reference to the new property
actionProperty.objectReferenceValue = action.SubstitutionReference;
break;
case ProfileCloneBehavior.CloneExisting:
// Clone the profile, then apply the new reference
// If the property reference is null, skip this step, the user was warned
if (action.Property.objectReferenceValue == null)
{
break;
}
// If for some reason it's the wrong type, bail now
BaseMixedRealityProfile subProfileToClone = (BaseMixedRealityProfile)action.Property.objectReferenceValue;
if (subProfileToClone == null)
{
break;
}
// Clone the sub profile
Object subTargetFolder = (action.TargetFolder == null) ? targetFolder : action.TargetFolder;
var newSubProfile = CloneProfile(newChildProfile, subProfileToClone, action.ProfileType.Name, actionProperty, subTargetFolder, action.CloneName);
SerializedObject newSubProfileSerializedObject = new SerializedObject(newSubProfile);
// Paste values from existing profile
PasteProfileValues(newChildProfile, subProfileToClone, newSubProfileSerializedObject);
newSubProfileSerializedObject.ApplyModifiedProperties();
break;
case ProfileCloneBehavior.LeaveEmpty:
actionProperty.objectReferenceValue = null;
break;
}
}
newChildSerializedObject.ApplyModifiedProperties();
// If we're not working with a parent profile, select the newly created profile
// UNLESS we've been given a selection target
if (selectionTarget != null)
{
Selection.activeObject = selectionTarget;
}
else
{
if (parentProfile == null)
{
Selection.activeObject = newChildProfile;
}
}
cloneWindow.Close();
}
private static BaseMixedRealityProfile CloneProfile(BaseMixedRealityProfile parentProfile, BaseMixedRealityProfile profileToClone, string childProfileTypeName, SerializedProperty childProperty, Object targetFolder, string profileName)
{
ScriptableObject instance = CreateInstance(childProfileTypeName);
instance.name = string.IsNullOrEmpty(profileName) ? childProfileTypeName : profileName;
string fileName = instance.name;
string path = AssetDatabase.GetAssetPath(targetFolder);
Debug.Log("Creating asset in path " + targetFolder);
var newChildProfile = instance.CreateAsset(path, fileName) as BaseMixedRealityProfile;
if (childProperty != null)
{
childProperty.objectReferenceValue = newChildProfile;
childProperty.serializedObject.ApplyModifiedProperties();
}
return newChildProfile;
}
private static void PasteProfileValues(BaseMixedRealityProfile parentProfile, BaseMixedRealityProfile profileToCopy, SerializedObject targetProfile)
{
if (parentProfile != null)
{
Undo.RecordObject(parentProfile, "Paste Profile Values");
}
bool targetIsCustom = targetProfile.FindProperty(IsCustomProfileProperty).boolValue;
string originalName = targetProfile.targetObject.name;
EditorUtility.CopySerialized(profileToCopy, targetProfile.targetObject);
targetProfile.Update();
targetProfile.FindProperty(IsCustomProfileProperty).boolValue = targetIsCustom;
targetProfile.ApplyModifiedProperties();
targetProfile.targetObject.name = originalName;
AssetDatabase.SaveAssets();
}
private static System.Type FindProfileType(string profileTypeName)
{
System.Type type = null;
foreach (Assembly assembly in System.AppDomain.CurrentDomain.GetAssemblies())
{
foreach (System.Type checkType in assembly.GetLoadableTypes())
{
if (checkType.Name == profileTypeName)
{
type = checkType;
break;
}
}
}
return type;
}
/// <summary>
/// If the targetFolder is invalid asset folder, this will create the CustomProfiles
/// folder and use that as the default target.
/// </summary>
private static Object EnsureTargetFolder(Object targetFolder)
{
if (targetFolder != null && AssetDatabase.IsValidFolder(AssetDatabase.GetAssetPath(targetFolder)))
{
return targetFolder;
}
string customProfilesFolderPath = DefaultCustomProfileFolder;
if (!AssetDatabase.IsValidFolder(customProfilesFolderPath))
{
// AssetDatabase.CreateFolder must be called to create each child of the asset folder
// path individually.
// If the packages have been imported via NugetForUnity, MixedRealityToolkitFiles.GetGeneratedFolder
// will also create the MixedRealityToolkit.Generated Folder and return the path to the folder.
AssetDatabase.CreateFolder(MixedRealityToolkitFiles.GetGeneratedFolder, "CustomProfiles");
}
return AssetDatabase.LoadAssetAtPath(DefaultCustomProfileFolder, typeof(Object));
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using System;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Editor
{
[CustomEditor(typeof(MixedRealityRegisteredServiceProvidersProfile))]
public class MixedRealityRegisteredServiceProviderProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private static readonly GUIContent MinusButtonContent = new GUIContent("-", "Unregister");
private static readonly GUIContent AddButtonContent = new GUIContent("+ Register a new Service Provider");
private SerializedProperty configurations;
private static bool[] configFoldouts;
private const string ProfileTitle = "Registered Services Settings";
private const string ProfileDescription = "This profile defines any additional Services like systems, features, and managers to register with the Mixed Reality Toolkit.";
protected override void OnEnable()
{
base.OnEnable();
configurations = serializedObject.FindProperty("configurations");
configFoldouts = new bool[configurations.arraySize];
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target))
{
return;
}
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
RenderList(configurations);
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
MixedRealityToolkit.Instance.ActiveProfile.RegisteredServiceProvidersProfile == profile;
}
private void RenderList(SerializedProperty list)
{
bool changed = false;
EditorGUILayout.Space();
using (new EditorGUILayout.VerticalScope())
{
if (GUILayout.Button(AddButtonContent, EditorStyles.miniButton))
{
list.InsertArrayElementAtIndex(list.arraySize);
SerializedProperty managerConfig = list.GetArrayElementAtIndex(list.arraySize - 1);
var componentName = managerConfig.FindPropertyRelative("componentName");
componentName.stringValue = $"New Configuration {list.arraySize - 1}";
var priority = managerConfig.FindPropertyRelative("priority");
priority.intValue = 10;
var runtimePlatform = managerConfig.FindPropertyRelative("runtimePlatform");
runtimePlatform.intValue = -1;
var configurationProfile = managerConfig.FindPropertyRelative("configurationProfile");
configurationProfile.objectReferenceValue = null;
serializedObject.ApplyModifiedProperties();
var componentType = ((MixedRealityRegisteredServiceProvidersProfile)serializedObject.targetObject).Configurations[list.arraySize - 1].ComponentType;
componentType.Type = null;
configFoldouts = new bool[list.arraySize];
return;
}
EditorGUILayout.Space();
if (list == null || list.arraySize == 0)
{
EditorGUILayout.HelpBox("Register a new Service Provider.", MessageType.Warning);
return;
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Configurations", EditorStyles.boldLabel, GUILayout.ExpandWidth(true));
}
EditorGUILayout.Space();
for (int i = 0; i < list.arraySize; i++)
{
SerializedProperty managerConfig = list.GetArrayElementAtIndex(i);
var componentName = managerConfig.FindPropertyRelative("componentName");
var componentType = managerConfig.FindPropertyRelative("componentType");
var priority = managerConfig.FindPropertyRelative("priority");
var runtimePlatform = managerConfig.FindPropertyRelative("runtimePlatform");
var configurationProfile = managerConfig.FindPropertyRelative("configurationProfile");
using (new EditorGUILayout.VerticalScope())
{
using (new EditorGUILayout.HorizontalScope())
{
configFoldouts[i] = EditorGUILayout.Foldout(configFoldouts[i], componentName.stringValue, true);
if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
{
list.DeleteArrayElementAtIndex(i);
serializedObject.ApplyModifiedProperties();
changed = true;
break;
}
}
SystemType serviceType = (target as MixedRealityRegisteredServiceProvidersProfile).Configurations[i].ComponentType;
if (configFoldouts[i] || RenderAsSubProfile)
{
using (new EditorGUI.IndentLevelScope())
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(componentName);
changed |= EditorGUI.EndChangeCheck();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(componentType);
if (EditorGUI.EndChangeCheck())
{
// Try to assign default configuration profile when type changes.
serializedObject.ApplyModifiedProperties();
AssignDefaultConfigurationValues(
((MixedRealityRegisteredServiceProvidersProfile)serializedObject.targetObject).Configurations[i].ComponentType,
componentName,
configurationProfile,
runtimePlatform);
changed = true;
break;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(priority);
EditorGUILayout.PropertyField(runtimePlatform);
changed |= EditorGUI.EndChangeCheck();
changed |= RenderProfile(configurationProfile, null, true, true, serviceType);
}
serializedObject.ApplyModifiedProperties();
}
if (IsProfileRequired(serviceType) &&
(configurationProfile.objectReferenceValue == null))
{
EditorGUILayout.HelpBox("This service requires a profile to be selected.", MessageType.Warning);
}
}
EditorGUILayout.Space();
}
}
if (changed && MixedRealityToolkit.IsInitialized)
{
EditorApplication.delayCall += () => MixedRealityToolkit.Instance.ResetConfiguration(MixedRealityToolkit.Instance.ActiveProfile);
}
}
private void AssignDefaultConfigurationValues(
System.Type componentType,
SerializedProperty componentName,
SerializedProperty configurationProfile,
SerializedProperty runtimePlatform)
{
configurationProfile.objectReferenceValue = null;
runtimePlatform.intValue = -1;
if (componentType != null)
{
MixedRealityExtensionServiceAttribute attr = MixedRealityExtensionServiceAttribute.Find(componentType) as MixedRealityExtensionServiceAttribute;
if (attr != null)
{
componentName.stringValue = !string.IsNullOrWhiteSpace(attr.Name) ? attr.Name : componentType.Name;
configurationProfile.objectReferenceValue = attr.DefaultProfile;
runtimePlatform.intValue = (int)attr.RuntimePlatforms;
}
else
{
componentName.stringValue = componentType.Name;
}
}
serializedObject.ApplyModifiedProperties();
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.SceneSystem;
using Microsoft.MixedReality.Toolkit.Utilities;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using System.Linq;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Editor
{
[CustomEditor(typeof(MixedRealitySceneSystemProfile))]
public class MixedRealitySceneSystemProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
const float DragAreaWidth = 0;
const float DragAreaHeight = 30;
const float DragAreaOffset = 10;
const float LightingSceneTypesLabelWidth = 45;
private static string managerSceneContent =
"The Manager scene is loaded first and remains loaded for the duration of the app. Only one Manager scene is ever loaded, and no scene operation will ever unload it.";
private static string lightingSceneContent =
"The Lighting scene controls lighting settings such as ambient light, skybox and sun direction. A Lighting scene's content is restricted based on the types defined in your editor settings. A default lighting scene is loaded on initialization. Only one lighting scene will ever be loaded at a time.";
private static string contentSceneContent =
"Content scenes are everything else. You can load and unload any number of content scenes in any combination, and their content is unrestricted.";
private static bool showEditorProperties = true;
private const string ShowSceneSystem_Editor_PreferenceKey = "ShowSceneSystem_Editor_PreferenceKey";
private SerializedProperty editorManageBuildSettings;
private SerializedProperty editorManageLoadedScenes;
private SerializedProperty editorEnforceSceneOrder;
private SerializedProperty editorEnforceLightingSceneTypes;
private SerializedProperty permittedLightingSceneComponentTypes;
private static bool showManagerProperties = true;
private const string ShowSceneSystem_Manager_PreferenceKey = "ShowSceneSystem_Manager_PreferenceKey";
private SerializedProperty useManagerScene;
private SerializedProperty managerScene;
private static bool showContentProperties = true;
private const string ShowSceneSystem_Content_PreferenceKey = "ShowSceneSystem_Content_PreferenceKey";
private SerializedProperty contentScenes;
private static bool showLightingProperties = true;
private const string ShowSceneSystem_Lighting_PreferenceKey = "ShowSceneSystem_Lighting_PreferenceKey";
private SerializedProperty useLightingScene;
private SerializedProperty defaultLightingSceneIndex;
private SerializedProperty lightingScenes;
private const string ProfileTitle = "Scene System Settings";
private const string ProfileDescription = "The Scene System helps developers manage additive scene loading at runtime and in editor.";
protected override void OnEnable()
{
base.OnEnable();
if (!MixedRealityToolkit.IsInitialized)
{
return;
}
editorManageBuildSettings = serializedObject.FindProperty("editorManageBuildSettings");
editorManageLoadedScenes = serializedObject.FindProperty("editorManageLoadedScenes");
editorEnforceSceneOrder = serializedObject.FindProperty("editorEnforceSceneOrder");
editorEnforceLightingSceneTypes = serializedObject.FindProperty("editorEnforceLightingSceneTypes");
permittedLightingSceneComponentTypes = serializedObject.FindProperty("permittedLightingSceneComponentTypes");
useManagerScene = serializedObject.FindProperty("useManagerScene");
managerScene = serializedObject.FindProperty("managerScene");
useLightingScene = serializedObject.FindProperty("useLightingScene");
defaultLightingSceneIndex = serializedObject.FindProperty("defaultLightingSceneIndex");
lightingScenes = serializedObject.FindProperty("lightingScenes");
contentScenes = serializedObject.FindProperty("contentScenes");
}
public override void OnInspectorGUI()
{
if (!MixedRealityToolkit.IsInitialized)
{
return;
}
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target))
{
return;
}
MixedRealityInspectorUtility.CheckMixedRealityConfigured(true);
serializedObject.Update();
MixedRealitySceneSystemProfile profile = (MixedRealitySceneSystemProfile)target;
RenderFoldout(ref showEditorProperties, "Editor Settings", () =>
{
using (new EditorGUI.IndentLevelScope())
{
EditorGUILayout.PropertyField(editorManageBuildSettings);
EditorGUILayout.PropertyField(editorManageLoadedScenes);
EditorGUILayout.PropertyField(editorEnforceSceneOrder);
EditorGUILayout.PropertyField(editorEnforceLightingSceneTypes);
if (editorEnforceLightingSceneTypes.boolValue)
{
EditorGUILayout.Space();
EditorGUILayout.HelpBox("Below are the component types that will be allowed in lighting scenes. Types not found in this list will be moved to another scene.", MessageType.Info);
EditorGUIUtility.labelWidth = LightingSceneTypesLabelWidth;
EditorGUILayout.PropertyField(permittedLightingSceneComponentTypes, true);
EditorGUIUtility.labelWidth = 0;
}
}
}, ShowSceneSystem_Editor_PreferenceKey);
RenderFoldout(ref showManagerProperties, "Manager Scene Settings", () =>
{
using (new EditorGUI.IndentLevelScope())
{
EditorGUILayout.HelpBox(managerSceneContent, MessageType.Info);
// Disable the tag field since we're drawing manager scenes
SceneInfoDrawer.DrawTagProperty = false;
EditorGUILayout.PropertyField(useManagerScene);
if (useManagerScene.boolValue && profile.ManagerScene.IsEmpty && !Application.isPlaying)
{
EditorGUILayout.HelpBox("You haven't created a manager scene yet. Click the button below to create one.", MessageType.Warning);
var buttonRect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(System.Array.Empty<GUILayoutOption>()));
if (GUI.Button(buttonRect, "Create Manager Scene", EditorStyles.miniButton))
{
// Create a new manager scene and add it to build settings
SceneInfo newManagerScene = EditorSceneUtils.CreateAndSaveScene("ManagerScene");
SerializedObjectUtils.SetStructValue<SceneInfo>(managerScene, newManagerScene);
EditorSceneUtils.AddSceneToBuildSettings(newManagerScene, EditorBuildSettings.scenes, EditorSceneUtils.BuildIndexTarget.First);
}
EditorGUILayout.Space();
}
if (useManagerScene.boolValue)
{
EditorGUILayout.PropertyField(managerScene, includeChildren: true);
}
}
}, ShowSceneSystem_Manager_PreferenceKey);
RenderFoldout(ref showLightingProperties, "Lighting Scene Settings", () =>
{
using (new EditorGUI.IndentLevelScope())
{
EditorGUILayout.HelpBox(lightingSceneContent, MessageType.Info);
EditorGUILayout.PropertyField(useLightingScene);
if (useLightingScene.boolValue && profile.NumLightingScenes < 1 && !Application.isPlaying)
{
EditorGUILayout.HelpBox("You haven't created a lighting scene yet. Click the button below to create one.", MessageType.Warning);
var buttonRect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(System.Array.Empty<GUILayoutOption>()));
if (GUI.Button(buttonRect, "Create Lighting Scene", EditorStyles.miniButton))
{
// Create a new lighting scene and add it to build settings
SceneInfo newLightingScene = EditorSceneUtils.CreateAndSaveScene("LightingScene");
// Create an element in the array
lightingScenes.arraySize = 1;
serializedObject.ApplyModifiedProperties();
SerializedObjectUtils.SetStructValue<SceneInfo>(lightingScenes.GetArrayElementAtIndex(0), newLightingScene);
EditorSceneUtils.AddSceneToBuildSettings(newLightingScene, EditorBuildSettings.scenes, EditorSceneUtils.BuildIndexTarget.Last);
}
EditorGUILayout.Space();
}
if (useLightingScene.boolValue)
{
// Disable the tag field since we're drawing lighting scenes
SceneInfoDrawer.DrawTagProperty = false;
if (profile.NumLightingScenes > 0)
{
string[] lightingSceneNames = profile.LightingScenes.Select(l => l.Name).ToArray<string>();
defaultLightingSceneIndex.intValue = EditorGUILayout.Popup("Default Lighting Scene", defaultLightingSceneIndex.intValue, lightingSceneNames);
}
EditorGUILayout.PropertyField(lightingScenes, includeChildren: true);
EditorGUILayout.Space();
if (profile.NumLightingScenes > 0)
{
if (profile.EditorLightingCacheOutOfDate)
{
EditorGUILayout.HelpBox("Your cached lighting settings may be out of date. This could result in unexpected appearances at runtime.", MessageType.Warning);
}
if (InspectorUIUtility.RenderIndentedButton(new GUIContent("Update Cached Lighting Settings"), EditorStyles.miniButton))
{
profile.EditorLightingCacheUpdateRequested = true;
}
}
EditorGUILayout.Space();
}
}
}, ShowSceneSystem_Lighting_PreferenceKey);
RenderFoldout(ref showContentProperties, "Content Scene Settings", () =>
{
using (new EditorGUI.IndentLevelScope())
{
EditorGUILayout.HelpBox(contentSceneContent, MessageType.Info);
// Enable the tag field since we're drawing content scenes
SceneInfoDrawer.DrawTagProperty = true;
EditorGUILayout.PropertyField(contentScenes, includeChildren: true);
}
}, ShowSceneSystem_Content_PreferenceKey);
serializedObject.ApplyModifiedProperties();
// Keep this inspector perpetually refreshed
EditorUtility.SetDirty(target);
}
protected override bool IsProfileInActiveInstance()
{
return MixedRealityToolkit.IsInitialized
&& MixedRealityToolkit.Instance.HasActiveProfile
&& MixedRealityToolkit.Instance.ActiveProfile.CameraProfile == this;
}
/// <summary>
/// Used to drag-drop scene objects into scene lists. (Currently unused.)
/// </summary>
private void DrawSceneInfoDragAndDrop(SerializedProperty arrayProperty)
{
if (!Application.isPlaying)
{
Rect dropArea = GUILayoutUtility.GetRect(DragAreaWidth, DragAreaHeight, GUILayout.ExpandWidth(true));
dropArea.width -= DragAreaOffset * 2;
dropArea.x += DragAreaOffset;
GUI.Box(dropArea, "Drag-and-drop new " + arrayProperty.displayName, EditorStyles.helpBox);
switch (Event.current.type)
{
case EventType.DragUpdated:
case EventType.DragPerform:
if (!dropArea.Contains(Event.current.mousePosition))
{
break;
}
DragAndDrop.visualMode = DragAndDropVisualMode.Link;
if (Event.current.type == EventType.DragPerform)
{
SerializedProperty arrayElement = null;
SerializedProperty assetProperty = null;
DragAndDrop.AcceptDrag();
foreach (UnityEngine.Object draggedObject in DragAndDrop.objectReferences)
{
if (draggedObject.GetType() != typeof(SceneAsset))
{ // Skip anything that isn't a scene asset
continue;
}
bool isDuplicate = false;
for (int i = 0; i < arrayProperty.arraySize; i++)
{
arrayElement = arrayProperty.GetArrayElementAtIndex(i);
assetProperty = arrayElement.FindPropertyRelative("Asset");
if (assetProperty.objectReferenceValue != null && assetProperty.objectReferenceValue == draggedObject)
{
isDuplicate = true;
break;
}
}
if (isDuplicate)
{ // Skip any duplicates
Debug.LogWarning("Skipping " + draggedObject.name + " - it's already in the " + arrayProperty.displayName + " list.");
continue;
}
// Create the new element at 0
arrayProperty.InsertArrayElementAtIndex(0);
arrayProperty.serializedObject.ApplyModifiedProperties();
// Get the new element and assign the dragged object
arrayElement = arrayProperty.GetArrayElementAtIndex(0);
assetProperty = arrayElement.FindPropertyRelative("Asset");
assetProperty.objectReferenceValue = draggedObject;
arrayProperty.serializedObject.ApplyModifiedProperties();
// Move the new element to end of list
arrayProperty.MoveArrayElement(0, arrayProperty.arraySize - 1);
arrayProperty.serializedObject.ApplyModifiedProperties();
}
}
break;
}
}
}
private void OnSelecteContentScene(ReorderableList list)
{
// Do nothing.
}
private void DrawContentSceneElement(Rect rect, int index, bool isActive, bool isFocused)
{
SceneInfoDrawer.DrawProperty(rect, contentScenes.GetArrayElementAtIndex(index), GUIContent.none, isActive, isFocused);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using Microsoft.MixedReality.Toolkit.Utilities;
using UnityEditor;
using UnityEngine;
using Microsoft.MixedReality.Toolkit.SpatialAwareness;
using System.Linq;
namespace Microsoft.MixedReality.Toolkit.Editor.SpatialAwareness
{
[CustomEditor(typeof(MixedRealitySpatialAwarenessMeshObserverProfile))]
public class MixedRealitySpatialAwarenessMeshObserverProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
// General settings
private SerializedProperty startupBehavior;
private SerializedProperty observationExtents;
private SerializedProperty observerVolumeType;
private SerializedProperty isStationaryObserver;
private SerializedProperty updateInterval;
// Physics settings
private SerializedProperty meshPhysicsLayer;
private SerializedProperty recalculateNormals;
private SerializedProperty physicsMaterial;
// Level of Detail settings
private SerializedProperty levelOfDetail;
private SerializedProperty trianglesPerCubicMeter;
// Display settings
private SerializedProperty displayOption;
private SerializedProperty visibleMaterial;
private SerializedProperty occlusionMaterial;
private readonly GUIContent displayOptionContent = new GUIContent("Display Option");
private readonly GUIContent lodContent = new GUIContent("Level of Detail");
private readonly GUIContent volumeTypeContent = new GUIContent("Observer Shape");
private readonly GUIContent physicsLayerContent = new GUIContent("Physics Layer");
private readonly GUIContent trianglesPerCubicMeterContent = new GUIContent("Triangles/Cubic Meter");
private const string ProfileTitle = "Spatial Mesh Observer Settings";
private const string ProfileDescription = "Configuration settings for how the real-world environment will be perceived and displayed.";
protected override void OnEnable()
{
base.OnEnable();
// General settings
startupBehavior = serializedObject.FindProperty("startupBehavior");
observationExtents = serializedObject.FindProperty("observationExtents");
observerVolumeType = serializedObject.FindProperty("observerVolumeType");
isStationaryObserver = serializedObject.FindProperty("isStationaryObserver");
updateInterval = serializedObject.FindProperty("updateInterval");
// Mesh settings
meshPhysicsLayer = serializedObject.FindProperty("meshPhysicsLayer");
physicsMaterial = serializedObject.FindProperty("physicsMaterial");
recalculateNormals = serializedObject.FindProperty("recalculateNormals");
levelOfDetail = serializedObject.FindProperty("levelOfDetail");
trianglesPerCubicMeter = serializedObject.FindProperty("trianglesPerCubicMeter");
displayOption = serializedObject.FindProperty("displayOption");
visibleMaterial = serializedObject.FindProperty("visibleMaterial");
occlusionMaterial = serializedObject.FindProperty("occlusionMaterial");
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, true, BackProfileType.SpatialAwareness))
{
return;
}
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
EditorGUILayout.LabelField("General Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(startupBehavior);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(updateInterval);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(isStationaryObserver);
EditorGUILayout.PropertyField(observerVolumeType, volumeTypeContent);
string message = string.Empty;
if (observerVolumeType.intValue == (int)VolumeType.AxisAlignedCube)
{
message = "Observed meshes will be aligned to the world coordinate space.";
}
else if (observerVolumeType.intValue == (int)VolumeType.UserAlignedCube)
{
message = "Observed meshes will be aligned to the user's coordinate space.";
}
else if (observerVolumeType.intValue == (int)VolumeType.Sphere)
{
message = "The X value of the Observation Extents will be used as the sphere radius.";
}
EditorGUILayout.HelpBox(message, MessageType.Info);
EditorGUILayout.PropertyField(observationExtents);
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Physics Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(meshPhysicsLayer, physicsLayerContent);
EditorGUILayout.PropertyField(recalculateNormals);
EditorGUILayout.PropertyField(physicsMaterial);
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Level of Detail Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(levelOfDetail, lodContent);
EditorGUILayout.PropertyField(trianglesPerCubicMeter, trianglesPerCubicMeterContent);
EditorGUILayout.HelpBox("The value of Triangles per Cubic Meter is ignored unless Level of Detail is set to Custom.", MessageType.Info);
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Display Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(displayOption, displayOptionContent);
EditorGUILayout.PropertyField(visibleMaterial);
EditorGUILayout.PropertyField(occlusionMaterial);
}
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
MixedRealityToolkit.Instance.ActiveProfile.SpatialAwarenessSystemProfile != null &&
MixedRealityToolkit.Instance.ActiveProfile.SpatialAwarenessSystemProfile.ObserverConfigurations != null &&
MixedRealityToolkit.Instance.ActiveProfile.SpatialAwarenessSystemProfile.ObserverConfigurations.Any(s => s.ObserverProfile == profile);
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.SpatialAwareness.Editor
{
/// <summary>
/// Class handles rendering inspector view of MixedRealitySpatialAwarenessSystemProfile object
/// </summary>
[CustomEditor(typeof(MixedRealitySpatialAwarenessSystemProfile))]
public class MixedRealitySpatialAwarenessSystemProfileInspector : BaseDataProviderServiceInspector
{
private const string ObserverErrorMsg = "The Mixed Reality Spatial Awareness System requires one or more observers.";
private static readonly GUIContent AddObserverContent = new GUIContent("+ Add Spatial Observer", "Add Spatial Observer");
private static readonly GUIContent RemoveObserverContent = new GUIContent("-", "Remove Spatial Observer");
private const string ProfileTitle = "Spatial Awareness System Settings";
private const string ProfileDescription = "The Spatial Awareness System profile allows developers to configure cross-platform environmental awareness.";
/// <inheritdoc/>
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target))
{
return;
}
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
using (new EditorGUI.IndentLevelScope())
{
RenderDataProviderList(AddObserverContent, RemoveObserverContent, ObserverErrorMsg, typeof(BaseSpatialAwarenessObserverProfile));
}
serializedObject.ApplyModifiedProperties();
}
}
/// <inheritdoc/>
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
profile == MixedRealityToolkit.Instance.ActiveProfile.SpatialAwarenessSystemProfile;
}
#region DataProvider Inspector Utilities
/// <inheritdoc/>
protected override SerializedProperty GetDataProviderConfigurationList()
{
return serializedObject.FindProperty("observerConfigurations");
}
/// <inheritdoc/>
protected override ServiceConfigurationProperties GetDataProviderConfigurationProperties(SerializedProperty providerEntry)
{
return new ServiceConfigurationProperties()
{
componentName = providerEntry.FindPropertyRelative("componentName"),
componentType = providerEntry.FindPropertyRelative("componentType"),
providerProfile = providerEntry.FindPropertyRelative("observerProfile"),
runtimePlatform = providerEntry.FindPropertyRelative("runtimePlatform"),
};
}
/// <inheritdoc/>
protected override IMixedRealityServiceConfiguration GetDataProviderConfiguration(int index)
{
var configurations = (target as MixedRealitySpatialAwarenessSystemProfile)?.ObserverConfigurations;
if (configurations != null && index >= 0 && index < configurations.Length)
{
return configurations[index];
}
return null;
}
#endregion
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Editor
{
[CustomEditor(typeof(MixedRealitySpeechCommandsProfile))]
public class MixedRealitySpeechCommandsProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private static readonly GUIContent MinusButtonContent = new GUIContent("-", "Remove Speech Command");
private static readonly GUIContent AddButtonContent = new GUIContent("+ Add a New Speech Command", "Add Speech Command");
private static readonly GUIContent LocalizationContent = new GUIContent("LocalizationKey", "An optional key to lookup a localized value for keyword");
private static readonly GUIContent KeywordContent = new GUIContent("Keyword", "Spoken word that will trigger the action. Overridden by a localized version if LocalizationKey is specified and found");
private static readonly GUIContent KeyCodeContent = new GUIContent("KeyCode", "The keyboard key that will trigger the action.");
private static readonly GUIContent ActionContent = new GUIContent("Action", "The action to trigger when a keyboard key is pressed or keyword is recognized.");
private const string ProfileTitle = "Speech Settings";
private const string ProfileDescription = "Speech Commands are any/all spoken keywords your users will be able say to raise an Input Action in your application.";
private SerializedProperty recognizerStartBehaviour;
private SerializedProperty recognitionConfidenceLevel;
private static bool showSpeechCommands = true;
private SerializedProperty speechCommands;
private static GUIContent[] actionLabels = System.Array.Empty<GUIContent>();
private static int[] actionIds = System.Array.Empty<int>();
private bool isInitialized = false;
protected override void OnEnable()
{
base.OnEnable();
isInitialized = false;
recognizerStartBehaviour = serializedObject.FindProperty("startBehavior");
recognitionConfidenceLevel = serializedObject.FindProperty("recognitionConfidenceLevel");
speechCommands = serializedObject.FindProperty("speechCommands");
var thisProfile = target as BaseMixedRealityProfile;
if (!MixedRealityToolkit.IsInitialized ||
!MixedRealityToolkit.Instance.ActiveProfile.IsInputSystemEnabled ||
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile == null ||
thisProfile != MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.SpeechCommandsProfile)
{
return;
}
var inputActions = MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile.InputActions;
actionLabels = inputActions.Select(action => new GUIContent(action.Description)).Prepend(new GUIContent("None")).ToArray();
actionIds = inputActions.Select(action => (int)action.Id).Prepend(0).ToArray();
isInitialized = true;
}
public override void OnInspectorGUI()
{
if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, isInitialized, BackProfileType.Input))
{
return;
}
CheckMixedRealityInputActions();
using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
{
serializedObject.Update();
EditorGUILayout.LabelField("General Settings", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(recognizerStartBehaviour);
EditorGUILayout.PropertyField(recognitionConfidenceLevel);
}
EditorGUILayout.Space();
showSpeechCommands = EditorGUILayout.Foldout(showSpeechCommands, "Speech Commands", true, MixedRealityStylesUtility.BoldFoldoutStyle);
if (showSpeechCommands)
{
using (new EditorGUI.IndentLevelScope())
{
RenderList(speechCommands);
}
}
serializedObject.ApplyModifiedProperties();
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
MixedRealityToolkit.Instance.HasActiveProfile &&
MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile != null &&
profile == MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.SpeechCommandsProfile;
}
private void RenderList(SerializedProperty list)
{
// Disable speech commands if we could not initialize successfully
using (new EditorGUI.DisabledGroupScope(!isInitialized))
{
EditorGUILayout.Space();
using (new EditorGUILayout.VerticalScope())
{
if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
{
list.arraySize += 1;
var speechCommand = list.GetArrayElementAtIndex(list.arraySize - 1);
var localizationKey = speechCommand.FindPropertyRelative("localizationKey");
localizationKey.stringValue = string.Empty;
var keyword = speechCommand.FindPropertyRelative("keyword");
keyword.stringValue = string.Empty;
var keyCode = speechCommand.FindPropertyRelative("keyCode");
keyCode.intValue = (int)KeyCode.None;
var action = speechCommand.FindPropertyRelative("action");
var actionId = action.FindPropertyRelative("id");
actionId.intValue = 0;
}
EditorGUILayout.Space();
if (list == null || list.arraySize == 0)
{
EditorGUILayout.HelpBox("Create a new Speech Command.", MessageType.Warning);
return;
}
for (int i = 0; i < list.arraySize; i++)
{
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
{
SerializedProperty speechCommand = list.GetArrayElementAtIndex(i);
using (new EditorGUILayout.HorizontalScope())
{
var keyword = speechCommand.FindPropertyRelative("keyword");
EditorGUILayout.PropertyField(keyword, KeywordContent);
if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
{
list.DeleteArrayElementAtIndex(i);
break;
}
}
var localizationKey = speechCommand.FindPropertyRelative("localizationKey");
EditorGUILayout.PropertyField(localizationKey, LocalizationContent);
var keyCode = speechCommand.FindPropertyRelative("keyCode");
EditorGUILayout.PropertyField(keyCode, KeyCodeContent);
var action = speechCommand.FindPropertyRelative("action");
var actionId = action.FindPropertyRelative("id");
var actionDescription = action.FindPropertyRelative("description");
var actionConstraint = action.FindPropertyRelative("axisConstraint");
EditorGUI.BeginChangeCheck();
actionId.intValue = EditorGUILayout.IntPopup(ActionContent, actionId.intValue, actionLabels, actionIds);
if (EditorGUI.EndChangeCheck())
{
MixedRealityInputAction inputAction = actionId.intValue == 0 ? MixedRealityInputAction.None : MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile.InputActions[actionId.intValue - 1];
actionDescription.stringValue = inputAction.Description;
actionConstraint.enumValueIndex = (int)inputAction.AxisConstraint;
}
}
EditorGUILayout.Space();
}
}
}
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Boundary;
using Microsoft.MixedReality.Toolkit.Diagnostics;
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Rendering;
using Microsoft.MixedReality.Toolkit.SceneSystem;
using Microsoft.MixedReality.Toolkit.SpatialAwareness;
using Microsoft.MixedReality.Toolkit.Utilities;
using Microsoft.MixedReality.Toolkit.Utilities.Editor;
using System;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Editor
{
[CustomEditor(typeof(MixedRealityToolkitConfigurationProfile))]
public class MixedRealityToolkitConfigurationProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{
private static readonly GUIContent TargetScaleContent = new GUIContent("Target Scale:");
// Experience properties
private SerializedProperty targetExperienceScale;
// Camera properties
private SerializedProperty enableCameraSystem;
private SerializedProperty cameraSystemType;
private SerializedProperty cameraProfile;
// Input system properties
private SerializedProperty enableInputSystem;
private SerializedProperty inputSystemType;
private SerializedProperty inputSystemProfile;
// Boundary system properties
private SerializedProperty enableBoundarySystem;
private SerializedProperty boundarySystemType;
private SerializedProperty boundaryVisualizationProfile;
// Teleport system properties
private SerializedProperty enableTeleportSystem;
private SerializedProperty teleportSystemType;
// Spatial Awareness system properties
private SerializedProperty enableSpatialAwarenessSystem;
private SerializedProperty spatialAwarenessSystemType;
private SerializedProperty spatialAwarenessSystemProfile;
// Diagnostic system properties
private SerializedProperty enableDiagnosticsSystem;
private SerializedProperty enableVerboseLogging;
private SerializedProperty diagnosticsSystemType;
private SerializedProperty diagnosticsSystemProfile;
// Scene system properties
private SerializedProperty enableSceneSystem;
private SerializedProperty sceneSystemType;
private SerializedProperty sceneSystemProfile;
// Additional registered components profile
private SerializedProperty registeredServiceProvidersProfile;
// Editor settings
private SerializedProperty useServiceInspectors;
private SerializedProperty renderDepthBuffer;
private Func<bool>[] renderProfileFuncs;
private static readonly string[] ProfileTabTitles = {
"Camera",
"Input",
"Boundary",
"Teleport",
"Spatial Awareness",
"Diagnostics",
"Scene System",
"Extensions",
"Editor",
};
private static int SelectedProfileTab = 0;
private const string SelectedTabPreferenceKey = "SelectedProfileTab";
protected override void OnEnable()
{
base.OnEnable();
if (target == null)
{
// Either when we are recompiling, or the inspector window is hidden behind another one, the target can get destroyed (null) and thereby will raise an ArgumentException when accessing serializedObject. For now, just return.
return;
}
MixedRealityToolkitConfigurationProfile mrtkConfigProfile = target as MixedRealityToolkitConfigurationProfile;
// Experience configuration
targetExperienceScale = serializedObject.FindProperty("targetExperienceScale");
// Camera configuration
enableCameraSystem = serializedObject.FindProperty("enableCameraSystem");
cameraSystemType = serializedObject.FindProperty("cameraSystemType");
cameraProfile = serializedObject.FindProperty("cameraProfile");
// Input system configuration
enableInputSystem = serializedObject.FindProperty("enableInputSystem");
inputSystemType = serializedObject.FindProperty("inputSystemType");
inputSystemProfile = serializedObject.FindProperty("inputSystemProfile");
// Boundary system configuration
enableBoundarySystem = serializedObject.FindProperty("enableBoundarySystem");
boundarySystemType = serializedObject.FindProperty("boundarySystemType");
boundaryVisualizationProfile = serializedObject.FindProperty("boundaryVisualizationProfile");
// Teleport system configuration
enableTeleportSystem = serializedObject.FindProperty("enableTeleportSystem");
teleportSystemType = serializedObject.FindProperty("teleportSystemType");
// Spatial Awareness system configuration
enableSpatialAwarenessSystem = serializedObject.FindProperty("enableSpatialAwarenessSystem");
spatialAwarenessSystemType = serializedObject.FindProperty("spatialAwarenessSystemType");
spatialAwarenessSystemProfile = serializedObject.FindProperty("spatialAwarenessSystemProfile");
// Diagnostics system configuration
enableDiagnosticsSystem = serializedObject.FindProperty("enableDiagnosticsSystem");
enableVerboseLogging = serializedObject.FindProperty("enableVerboseLogging");
diagnosticsSystemType = serializedObject.FindProperty("diagnosticsSystemType");
diagnosticsSystemProfile = serializedObject.FindProperty("diagnosticsSystemProfile");
// Scene system configuration
enableSceneSystem = serializedObject.FindProperty("enableSceneSystem");
sceneSystemType = serializedObject.FindProperty("sceneSystemType");
sceneSystemProfile = serializedObject.FindProperty("sceneSystemProfile");
// Additional registered components configuration
registeredServiceProvidersProfile = serializedObject.FindProperty("registeredServiceProvidersProfile");
// Editor settings
useServiceInspectors = serializedObject.FindProperty("useServiceInspectors");
renderDepthBuffer = serializedObject.FindProperty("renderDepthBuffer");
SelectedProfileTab = SessionState.GetInt(SelectedTabPreferenceKey, SelectedProfileTab);
if (renderProfileFuncs == null)
{
renderProfileFuncs = new Func<bool>[]
{
() => {
bool changed = false;
using (var c = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(enableCameraSystem);
const string service = "Camera System";
if (enableCameraSystem.boolValue)
{
CheckSystemConfiguration(service, mrtkConfigProfile.CameraSystemType, mrtkConfigProfile.CameraProfile != null);
EditorGUILayout.PropertyField(cameraSystemType);
changed |= RenderProfile(cameraProfile, typeof(MixedRealityCameraProfile), true, false);
}
else
{
RenderSystemDisabled(service);
}
changed |= c.changed;
}
return changed;
},
() => {
bool changed = false;
using (var c = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(enableInputSystem);
const string service = "Input System";
if (enableInputSystem.boolValue)
{
CheckSystemConfiguration(service, mrtkConfigProfile.InputSystemType, mrtkConfigProfile.InputSystemProfile != null);
EditorGUILayout.PropertyField(inputSystemType);
changed |= RenderProfile(inputSystemProfile, null, true, false, typeof(IMixedRealityInputSystem));
}
else
{
RenderSystemDisabled(service);
}
changed |= c.changed;
}
return changed;
},
() => {
var experienceScale = (ExperienceScale)targetExperienceScale.intValue;
if (experienceScale != ExperienceScale.Room)
{
// Alert the user if the experience scale does not support boundary features.
GUILayout.Space(6f);
EditorGUILayout.HelpBox("Boundaries are only supported in Room scale experiences.", MessageType.Warning);
GUILayout.Space(6f);
}
bool changed = false;
using (var c = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(enableBoundarySystem);
const string service = "Boundary System";
if (enableBoundarySystem.boolValue)
{
CheckSystemConfiguration(service, mrtkConfigProfile.BoundarySystemSystemType, mrtkConfigProfile.BoundaryVisualizationProfile != null);
EditorGUILayout.PropertyField(boundarySystemType);
changed |= RenderProfile(boundaryVisualizationProfile, null, true, false, typeof(IMixedRealityBoundarySystem));
}
else
{
RenderSystemDisabled(service);
}
changed |= c.changed;
}
return changed;
},
() => {
const string service = "Teleport System";
using (var c = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(enableTeleportSystem);
if (enableTeleportSystem.boolValue)
{
// Teleport System does not have a profile scriptableobject so auto to true
CheckSystemConfiguration(service, mrtkConfigProfile.TeleportSystemSystemType,true);
EditorGUILayout.PropertyField(teleportSystemType);
}
else
{
RenderSystemDisabled(service);
}
return c.changed;
}
},
() => {
bool changed = false;
using (var c = new EditorGUI.ChangeCheckScope())
{
const string service = "Spatial Awareness System";
EditorGUILayout.PropertyField(enableSpatialAwarenessSystem);
if (enableSpatialAwarenessSystem.boolValue)
{
CheckSystemConfiguration(service, mrtkConfigProfile.SpatialAwarenessSystemSystemType, mrtkConfigProfile.SpatialAwarenessSystemProfile != null);
EditorGUILayout.PropertyField(spatialAwarenessSystemType);
EditorGUILayout.HelpBox("Spatial Awareness settings are configured per observer.", MessageType.Info);
changed |= RenderProfile(spatialAwarenessSystemProfile, null, true, false, typeof(IMixedRealitySpatialAwarenessSystem));
}
else
{
RenderSystemDisabled(service);
}
changed |= c.changed;
}
return changed;
},
() => {
EditorGUILayout.HelpBox("It is recommended to enable the Diagnostics system during development. Be sure to disable prior to building your shipping product.", MessageType.Warning);
bool changed = false;
using (var c = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(enableVerboseLogging);
EditorGUILayout.PropertyField(enableDiagnosticsSystem);
const string service = "Diagnostics System";
if (enableDiagnosticsSystem.boolValue)
{
CheckSystemConfiguration(service, mrtkConfigProfile.DiagnosticsSystemSystemType, mrtkConfigProfile.DiagnosticsSystemProfile != null);
EditorGUILayout.PropertyField(diagnosticsSystemType);
changed |= RenderProfile(diagnosticsSystemProfile, typeof(MixedRealityDiagnosticsProfile));
}
else
{
RenderSystemDisabled(service);
}
changed |= c.changed;
}
return changed;
},
() => {
bool changed = false;
using (var c = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(enableSceneSystem);
const string service = "Scene System";
if (enableSceneSystem.boolValue)
{
CheckSystemConfiguration(service, mrtkConfigProfile.SceneSystemSystemType, mrtkConfigProfile.SceneSystemProfile != null);
EditorGUILayout.PropertyField(sceneSystemType);
changed |= RenderProfile(sceneSystemProfile, typeof(MixedRealitySceneSystemProfile), true, true, typeof(IMixedRealitySceneSystem));
}
changed |= c.changed;
}
return changed;
},
() => {
return RenderProfile(registeredServiceProvidersProfile, typeof(MixedRealityRegisteredServiceProvidersProfile), true, false);
},
() => {
EditorGUILayout.PropertyField(useServiceInspectors);
using (var c = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(renderDepthBuffer);
if (c.changed)
{
if (renderDepthBuffer.boolValue)
{
CameraCache.Main.gameObject.AddComponent<DepthBufferRenderer>();
}
else
{
foreach (var dbr in FindObjectsOfType<DepthBufferRenderer>())
{
UnityObjectExtensions.DestroyObject(dbr);
}
}
}
}
return false;
},
};
}
}
public override void OnInspectorGUI()
{
var configurationProfile = (MixedRealityToolkitConfigurationProfile)target;
serializedObject.Update();
if (!RenderMRTKLogoAndSearch())
{
CheckEditorPlayMode();
return;
}
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.None);
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 = SessionState.GetInt(SelectedTabPreferenceKey, 0);
SelectedProfileTab = GUILayout.SelectionGrid(prefsSelectedTab, ProfileTabTitles, 1, GUILayout.MaxWidth(125));
if (SelectedProfileTab != prefsSelectedTab)
{
SessionState.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);
}
}
protected override bool IsProfileInActiveInstance()
{
var profile = target as BaseMixedRealityProfile;
return MixedRealityToolkit.IsInitialized && profile != null &&
profile == MixedRealityToolkit.Instance.ActiveProfile;
}
/// <summary>
/// Checks if a system is enabled and the service type or validProfile is null, then displays warning message to the user
/// </summary>
/// <param name="service">name of service being tested</param>
/// <param name="systemType">Selected implementation type for service</param>
/// <param name="validProfile">true if profile scriptableobject property is not null, false otherwise</param>
protected void CheckSystemConfiguration(string service, SystemType systemType, bool validProfile)
{
if (systemType?.Type == null || !validProfile)
{
EditorGUILayout.HelpBox($"{service} is enabled but will not be initialized because the System Type and/or Profile is not set.", MessageType.Warning);
}
}
/// <summary>
/// Render helpbox that provided service string is disabled and none of its functionality will be loaded at runtime
/// </summary>
protected static void RenderSystemDisabled(string service)
{
EditorGUILayout.Space();
EditorGUILayout.HelpBox($"The {service} is disabled.\n\nThis module will not be loaded and thus none of its features will be available at runtime.", MessageType.Info);
EditorGUILayout.Space();
}
private static string GetExperienceDescription(ExperienceScale experienceScale)
{
switch (experienceScale)
{
case ExperienceScale.OrientationOnly:
return "The user is stationary. Position data does not change.";
case ExperienceScale.Seated:
return "The user is stationary and seated. The origin of the world is at a neutral head-level position.";
case ExperienceScale.Standing:
return "The user is stationary and standing. The origin of the world is on the floor, facing forward.";
case ExperienceScale.Room:
return "The user is free to move about the room. The origin of the world is on the floor, facing forward. Boundaries are available.";
case ExperienceScale.World:
return "The user is free to move about the world. Relies upon knowledge of the environment (Spatial Anchors and Spatial Mapping).";
}
return null;
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Editor
{
/// <summary>
/// Renders enum flags on fields with the attribute.
/// From https://answers.unity.com/questions/486694/default-editor-enum-as-flags-.html
/// </summary>
[CustomPropertyDrawer(typeof(EnumFlagsAttribute))]
public class EnumFlagsAttributeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
property.intValue = EditorGUI.MaskField(position, label, property.intValue, property.enumDisplayNames);
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using UnityEngine;
using UnityEditor;
namespace Microsoft.MixedReality.Toolkit.Editor
{
/// <summary>
/// Draws a customer decorator drawer that displays a help box with rich text tagging implementation as experimental.
/// </summary>
[CustomPropertyDrawer(typeof(ExperimentalAttribute))]
public class ExperimentalDrawer : DecoratorDrawer
{
/// <summary>
/// Unity calls this function to draw the GUI.
/// </summary>
/// <param name="position">Rectangle to display the GUI in</param>
public override void OnGUI(Rect position)
{
var experimental = attribute as ExperimentalAttribute;
if (experimental != null)
{
var defaultValue = EditorStyles.helpBox.richText;
EditorStyles.helpBox.richText = true;
EditorGUI.HelpBox(position, experimental.Text, MessageType.Warning);
EditorStyles.helpBox.richText = defaultValue;
}
}
/// <summary>
/// Returns the height required to display UI elements drawn by OnGUI.
/// </summary>
/// <returns>The height required by OnGUI.</returns>
public override float GetHeight()
{
var experimental = attribute as ExperimentalAttribute;
if (experimental != null)
{
return EditorStyles.helpBox.CalcHeight(new GUIContent(experimental.Text), EditorGUIUtility.currentViewWidth);
}
return base.GetHeight();
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using UnityEngine;
using UnityEditor;
namespace Microsoft.MixedReality.Toolkit.Editor
{
/// <summary>
/// Custom property drawer to show an optionally collapsible foldout help section in the Inspector
/// </summary>
/// <example>
/// <code>
/// [Help("This is a multiline optionally collapsable help section.\n • Great for providing simple instructions in Inspector.\n • Easy to use.\n • Saves space.")]
/// </code>
/// </example>
[CustomPropertyDrawer(typeof(HelpAttribute))]
public class HelpDrawer : DecoratorDrawer
{
/// <summary>
/// Unity calls this function to draw the GUI
/// </summary>
/// <param name="position">Rectangle to display the GUI in</param>
public override void OnGUI(Rect position)
{
HelpAttribute help = attribute as HelpAttribute;
if (help.Collapsible)
{
HelpFoldOut = EditorGUI.Foldout(position, HelpFoldOut, help.Header);
if (HelpFoldOut)
{
EditorGUI.HelpBox(position, help.Text, MessageType.Info);
}
}
else
{
EditorGUI.HelpBox(position, help.Text, MessageType.Info);
}
cachedPosition = position;
}
/// <summary>
/// Gets the height of the decorator
/// </summary>
public override float GetHeight()
{
HelpAttribute help = attribute as HelpAttribute;
// Computing the actual height requires the cachedPosition because
// CalcSize doesn't factor in word-wrapped height, and CalcHeight
// requires a pre-determined width.
GUIStyle helpStyle = EditorStyles.helpBox;
GUIContent helpContent = new GUIContent(help.Text);
float wrappedHeight = helpStyle.CalcHeight(helpContent, cachedPosition.width);
// The height of the help box should be the content if expanded, or
// just the header text if not expanded.
float contentHeight = !help.Collapsible || HelpFoldOut ?
wrappedHeight :
helpStyle.lineHeight;
return helpStyle.margin.top + helpStyle.margin.bottom + contentHeight;
}
#region Private
/// <summary>
/// The "help" foldout state
/// </summary>
private bool HelpFoldOut = false;
private Rect cachedPosition = new Rect();
#endregion
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Input.Editor
{
[CustomPropertyDrawer(typeof(MixedRealityInputAction))]
public class InputActionPropertyDrawer : PropertyDrawer
{
private static MixedRealityInputActionsProfile profile = null;
private static GUIContent[] actionLabels = { new GUIContent("Missing Input Action Profile") };
private static int[] actionIds = { 0 };
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent content)
{
if (!MixedRealityToolkit.IsInitialized || !MixedRealityToolkit.Instance.HasActiveProfile)
{
profile = null;
actionLabels = new[] { new GUIContent("Missing Mixed Reality Toolkit") };
actionIds = new[] { 0 };
}
else
{
if (profile == null ||
(MixedRealityToolkit.Instance.ActiveProfile.IsInputSystemEnabled &&
profile.InputActions != null &&
profile.InputActions != MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile.InputActions))
{
profile = MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile;
if (profile != null)
{
actionLabels = profile.InputActions.Select(action => new GUIContent(action.Description)).Prepend(new GUIContent("None")).ToArray();
actionIds = profile.InputActions.Select(action => (int)action.Id).Prepend(0).ToArray();
}
else
{
actionLabels = new[] { new GUIContent("No input action profile found") };
actionIds = new[] { 0 };
}
}
if (!MixedRealityToolkit.Instance.ActiveProfile.IsInputSystemEnabled)
{
profile = null;
actionLabels = new[] { new GUIContent("Input System Disabled") };
actionIds = new[] { 0 };
}
}
var label = EditorGUI.BeginProperty(rect, content, property);
var inputActionId = property.FindPropertyRelative("id");
if (profile == null || actionLabels == null || actionIds == null)
{
GUI.enabled = false;
EditorGUI.IntPopup(rect, label, inputActionId.intValue.ResetIfGreaterThan(0), actionLabels, actionIds);
GUI.enabled = true;
}
else
{
EditorGUI.BeginChangeCheck();
inputActionId.intValue = EditorGUI.IntPopup(rect, label, inputActionId.intValue.ResetIfGreaterThan(profile.InputActions.Length), actionLabels, actionIds);
if (EditorGUI.EndChangeCheck())
{
var description = property.FindPropertyRelative("description");
var axisConstraint = property.FindPropertyRelative("axisConstraint");
if (inputActionId.intValue > 0)
{
description.stringValue = profile.InputActions[inputActionId.intValue - 1].Description;
axisConstraint.intValue = (int)profile.InputActions[inputActionId.intValue - 1].AxisConstraint;
}
else
{
description.stringValue = "None";
axisConstraint.intValue = 0;
}
}
}
EditorGUI.EndProperty();
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Editor
{
[CustomPropertyDrawer(typeof(MixedRealityPose))]
public class MixedRealityPosePropertyDrawer : PropertyDrawer
{
private readonly GUIContent positionContent = new GUIContent("Position");
private readonly GUIContent rotationContent = new GUIContent("Rotation");
private const int NumberOfLines = 3;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight * NumberOfLines;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
bool lastMode = EditorGUIUtility.wideMode;
EditorGUIUtility.wideMode = true;
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
EditorGUI.indentLevel++;
var fieldHeight = position.height / NumberOfLines;
var positionRect = new Rect(position.x, position.y + fieldHeight, position.width, fieldHeight);
var rotationRect = new Rect(position.x, position.y + fieldHeight * 2, position.width, fieldHeight);
EditorGUI.PropertyField(positionRect, property.FindPropertyRelative("position"), positionContent);
EditorGUI.BeginChangeCheck();
var rotationProperty = property.FindPropertyRelative("rotation");
var newEulerRotation = EditorGUI.Vector3Field(rotationRect, rotationContent, rotationProperty.quaternionValue.eulerAngles);
if (EditorGUI.EndChangeCheck())
{
rotationProperty.quaternionValue = Quaternion.Euler(newEulerRotation);
}
EditorGUI.indentLevel--;
EditorGUIUtility.wideMode = lastMode;
EditorGUI.EndProperty();
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Editor;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Physics.Editor
{
/// <summary>
/// Renders the physics layer dropdown based on the current layers set in the Tag Manager.
/// </summary>
[CustomPropertyDrawer(typeof(PhysicsLayerAttribute))]
public sealed class PhysicsLayerAttributeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var guiContents = new List<GUIContent>();
var layerIds = new List<int>();
for (int i = 0; i < EditorLayerExtensions.TagManagerLayers.arraySize; i++)
{
var layer = EditorLayerExtensions.TagManagerLayers.GetArrayElementAtIndex(i);
if (!string.IsNullOrWhiteSpace(layer.stringValue))
{
guiContents.Add(new GUIContent($"{i}: {layer.stringValue}"));
layerIds.Add(i);
}
}
property.intValue = EditorGUI.IntPopup(position, label, property.intValue, guiContents.ToArray(), layerIds.ToArray());
}
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment