コード例 #1
0
        private void DrawProviderBox(string field, ProviderId provider)
        {
            bool isEditorDefault  = _editorProvider.enumValueIndex == (int)provider;
            bool isRuntimeDefault = _runtimeProvider.enumValueIndex == (int)provider;

            if (isEditorDefault || isRuntimeDefault)
            {
                GUILayoutTools.LineSeparator();

                StringBuilder titleBuilder = new StringBuilder();
                titleBuilder.Append(Enum.GetName(typeof(ProviderId), provider));

                if (isEditorDefault)
                {
                    titleBuilder.Append(TITLE_SEPARATOR);
                    titleBuilder.Append(EDITOR_DEFAULT_TITLE);
                }

                if (isRuntimeDefault)
                {
                    titleBuilder.Append(TITLE_SEPARATOR);
                    titleBuilder.Append(RUNTIME_DEFAULT_TITLE);
                }

                EditorGUILayout.LabelField(titleBuilder.ToString(), WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);

                EditorGUILayout.PropertyField(serializedObject.FindProperty(field), WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
            }
        }
コード例 #2
0
        private void OnGUI()
        {
            GUILayout.Label(_boseArSdkLogo);

            GUILayoutTools.LineSeparator();

            // Draw SDK version
            EditorGUILayout.BeginHorizontal(GUILayout.Width(300f));
            EditorGUILayout.LabelField(UNITY_SDK_VERSION_LABEL, EditorStyles.boldLabel, GUILayout.Width(200f));
            EditorGUILayout.LabelField(WearableVersion.UnitySdkVersion);
            EditorGUILayout.EndHorizontal();
        }
コード例 #3
0
        public override void OnInspectorGUI()
        {
            var listProp            = serializedObject.FindProperty(LIST_PROPERTY_NAME);
            var originalIndentLevel = EditorGUI.indentLevel;

            GUI.changed           = false;
            EditorGUI.indentLevel = 0;
            for (var i = 0; i < listProp.arraySize; i++)
            {
                var entryProp = listProp.GetArrayElementAtIndex(i);
                EditorGUI.BeginDisabledGroup(true);
                EditorGUILayout.PropertyField(entryProp.FindPropertyRelative(GESTURE_ID_PROPERTY_NAME));
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.PropertyField(entryProp.FindPropertyRelative(GESTURE_ICON_PROPERTY_NAME));
                GUILayoutTools.LineSeparator();
            }
            EditorGUI.indentLevel = originalIndentLevel;

            if (GUI.changed)
            {
                serializedObject.ApplyModifiedProperties();
            }
        }
コード例 #4
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            // Update mode
            EditorGUILayout.PropertyField(serializedObject.FindProperty(UPDATE_MODE_FIELD), WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);

            // Provider defaults
            using (new EditorGUI.DisabledScope(Application.isPlaying))
            {
                // Editor Default Provider
                string editorProviderName = GetNameForProvider((ProviderId)_editorProvider.intValue);
                int    optionIndex        = Array.IndexOf(_editorProviderOptions, editorProviderName);
                _editorProviderIndex = EditorGUILayout.Popup(
                    ObjectNames.NicifyVariableName(EDITOR_DEFAULT_PROVIDER_FIELD),
                    optionIndex >= 0 ? optionIndex : (int)WearableConstants.EDITOR_DEFAULT_PROVIDER,
                    _editorProviderOptions
                    );

                _editorProvider.intValue = (int)_editorProviderMap[_editorProviderOptions[_editorProviderIndex]];

                // Runtime Default Provider
                string runtimeProviderName = GetNameForProvider((ProviderId)_runtimeProvider.intValue);
                optionIndex           = Array.IndexOf(_runtimeProviderOptions, runtimeProviderName);
                _runtimeProviderIndex = EditorGUILayout.Popup(
                    ObjectNames.NicifyVariableName(RUNTIME_DEFAULT_PROVIDER_FIELD),
                    optionIndex >= 0 ? optionIndex : (int)WearableConstants.RUNTIME_DEFAULT_PROVIDER,
                    _runtimeProviderOptions
                    );

                _runtimeProvider.intValue = (int)_runtimeProviderMap[_runtimeProviderOptions[_runtimeProviderIndex]];
            }

            // Intent profile
            GUILayoutTools.LineSeparator();
            DrawIntentsSection();

            // Providers
            DrawProviderBox(DEBUG_PROVIDER_FIELD, ProviderId.DebugProvider);
            DrawProviderBox(USB_PROVIDER_FIELD, ProviderId.USBProvider);
            DrawProviderBox(BLUETOOTH_PROVIDER_FIELD, ProviderId.BluetoothProvider);

            if (Application.isPlaying)
            {
                GUILayoutTools.LineSeparator();

                if (_wearableControl.IsOverridingDeviceConfig)
                {
                    EditorGUILayout.LabelField(OVERRIDE_DEVICE_CONFIG_TITLE, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    EditorGUILayout.HelpBox(OVERRIDE_CONFIG_PRESENT_WARNING, MessageType.Warning);
                    using (new EditorGUI.DisabledScope(true))
                    {
                        EditorGUILayout.PropertyField(
                            serializedObject.FindProperty(OVERRIDE_WEARABLE_DEVICE_CONFIG_FIELD),
                            WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    }
                }
                else
                {
                    EditorGUILayout.LabelField(RESOLVED_DEVICE_CONFIG_TITLE, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    using (new EditorGUI.DisabledScope(true))
                    {
                        EditorGUILayout.PropertyField(
                            serializedObject.FindProperty(FINAL_WEARABLE_DEVICE_CONFIG_FIELD),
                            WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    }
                }
            }

            serializedObject.ApplyModifiedProperties();
        }
コード例 #5
0
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            WearableDebugProvider provider = (WearableDebugProvider)fieldInfo.GetValue(property.serializedObject.targetObject);

            EditorGUI.BeginProperty(position, label, property);

            EditorGUILayout.HelpBox(DESCRIPTION_BOX, MessageType.None);
            EditorGUILayout.Space();

            // Virtual device config
            if (provider.ConnectedDevice.HasValue)
            {
                EditorGUILayout.HelpBox(string.Format(DEVICE_CONFIG_FIELDS_DISABLED_BOX_FORMAT, DISCONNECT_LABEL), MessageType.Info);
            }

            using (new EditorGUI.DisabledScope(provider.ConnectedDevice.HasValue))
            {
                // Device properties
                EditorGUILayout.IntSlider(
                    property.FindPropertyRelative(RSSI_FIELD),
                    WearableConstants.MINIMUM_RSSI_VALUE,
                    WearableConstants.MAXIMUM_RSSI_VALUE,
                    WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);

                EditorGUILayout.Separator();
                EditorGUILayout.PropertyField(
                    property.FindPropertyRelative(DEVICE_NAME_FIELD),
                    WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                EditorGUILayout.PropertyField(
                    property.FindPropertyRelative(UID_FIELD),
                    WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);

                // draw product and variant types based on ids
                var productIdProp = property.FindPropertyRelative(PRODUCT_ID_FIELD);
                _productType = WearableTools.GetProductType((ProductId)productIdProp.intValue);
                var variantProp = property.FindPropertyRelative(VARIANT_ID_FIELD);

                EditorGUI.BeginChangeCheck();
                _productType = (ProductType)EditorGUILayout.EnumPopup(
                    PRODUCT_TYPE_LABEL,
                    _productType
                    );
                if (EditorGUI.EndChangeCheck())
                {
                    // if we have changed the product, we need to reset the variants
                    productIdProp.intValue        = (int)WearableTools.GetProductId(_productType);
                    variantProp.intValue          = 0;
                    _editorVariantOptionsAreDirty = true;
                }

                if (_editorVariantOptionsAreDirty)
                {
                    _editorVariantMap             = GetVariantMap(_productType);
                    _editorVariantOptions         = _editorVariantMap.Keys.ToArray();
                    _editorVariantOptionsAreDirty = false;
                }

                string variantName = GetNameForProductAndVariantId(_productType, (byte)variantProp.intValue);
                var    optionIndex = Array.IndexOf(_editorVariantOptions, variantName);
                _editorVariantIndex = EditorGUILayout.Popup(
                    VARIANT_TYPE_LABEL,
                    optionIndex >= 0 ? optionIndex : 0,
                    _editorVariantOptions
                    );

                variantProp.intValue = _editorVariantMap[_editorVariantOptions[_editorVariantIndex]];

                GUILayoutTools.LineSeparator();

                // Permissions and services
                var permissionsProperty  = property.FindPropertyRelative(GRANTED_PERMISSIONS_FIELD);
                var permissionsEnumValue = EditorGUILayout.EnumFlagsField(
                    new GUIContent(GRANTED_PERMISSIONS_LABEL),
                    provider.GrantedPermissions);
                var permissionFlags = (OSPermissionFlags)Convert.ChangeType(permissionsEnumValue, typeof(OSPermissionFlags));
                permissionsProperty.intValue = (int)permissionFlags;

                var allPermissionsGranted = true;
                var allPermissionFlags    = ((OSPermissionFlags[])Enum.GetValues(typeof(OSPermissionFlags)))
                                            .Where(x => x != OSPermissionFlags.None);
                foreach (var flag in allPermissionFlags)
                {
                    if ((permissionFlags & flag) != flag)
                    {
                        allPermissionsGranted = false;
                        break;
                    }
                }

                EditorGUILayout.PropertyField(
                    property.FindPropertyRelative(GRANT_PERMISSIONS_FIELD),
                    new GUIContent(USER_GRANTED_PERMISSIONS_LABEL));

                if (allPermissionsGranted)
                {
                    EditorGUILayout.HelpBox(ALL_PERMISSIONS_GRANTED_BOX, MessageType.Info);
                }
                else if (provider.GrantPermissions)
                {
                    EditorGUILayout.HelpBox(SOME_PERMISSIONS_MISSING_BOX, MessageType.Warning);
                }
                else
                {
                    EditorGUILayout.HelpBox(SOME_PERMISSIONS_MISSING_FAIL_BOX, MessageType.Error);
                }

                var servicesProperty  = property.FindPropertyRelative(ENABLED_SERVICES_FIELD);
                var servicesEnumValue = EditorGUILayout.EnumFlagsField(
                    new GUIContent(ENABLED_SERVICES_LABEL),
                    provider.EnabledServices);
                var servicesFlag = (OSServiceFlags)Convert.ChangeType(servicesEnumValue, typeof(OSServiceFlags));
                servicesProperty.intValue = (int)servicesFlag;

                var allServicesEnabled = true;
                var allServicesFlags   = ((OSServiceFlags[])Enum.GetValues(typeof(OSServiceFlags)))
                                         .Where(x => x != OSServiceFlags.None);
                foreach (var flag in allServicesFlags)
                {
                    if ((servicesFlag & flag) != flag)
                    {
                        allServicesEnabled = false;
                        break;
                    }
                }

                if (allServicesEnabled)
                {
                    EditorGUILayout.HelpBox(ALL_SERVICES_GRANTED_BOX, MessageType.Info);
                }
                else
                {
                    EditorGUILayout.HelpBox(SOME_SERVICES_MISSING_FAIL_BOX, MessageType.Error);
                }

                GUILayoutTools.LineSeparator();

                // Firmware simulation
                EditorGUILayout.PropertyField(
                    property.FindPropertyRelative(FIRMWARE_VERSION_FIELD),
                    WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                var firmwareSufficient = property.FindPropertyRelative(BOSE_AR_ENABLED_FIELD);
                var firmwareAvailable  = property.FindPropertyRelative(FIRMWARE_UPDATE_AVAILABLE_FIELD);
                EditorGUILayout.PropertyField(firmwareSufficient, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                EditorGUILayout.PropertyField(firmwareAvailable, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);

                if (firmwareSufficient.boolValue)
                {
                    if (firmwareAvailable.boolValue)
                    {
                        EditorGUILayout.HelpBox(FIRMWARE_UPDATE_AVAILABLE_BOX, MessageType.Info);
                    }
                    else
                    {
                        EditorGUILayout.HelpBox(FIRMWARE_GOOD_BOX, MessageType.Info);
                    }
                }
                else
                {
                    if (firmwareAvailable.boolValue)
                    {
                        EditorGUILayout.HelpBox(FIRMWARE_UPDATE_REQUIRED_BOX, MessageType.Warning);
                    }
                    else
                    {
                        EditorGUILayout.HelpBox(FIRMWARE_DEVICE_NOT_SUPPORTED_BOX, MessageType.Error);
                    }
                }

                // Secure pairing
                var acceptSecurePairing = property.FindPropertyRelative(ACCEPT_SECURE_PAIRING_FIELD);
                EditorGUILayout.PropertyField(acceptSecurePairing, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                if (acceptSecurePairing.boolValue)
                {
                    EditorGUILayout.HelpBox(SECURE_PAIRING_ACCEPTED_BOX, MessageType.Info);
                }
                else
                {
                    EditorGUILayout.HelpBox(SECURE_PAIRING_REJECTED_BOX, MessageType.Error);
                }

                // Sensor and gesture availability
                var sensorFlagsProp      = property.FindPropertyRelative(SENSOR_FLAGS_FIELD);
                var sensorFlagsEnumValue = EditorGUILayout.EnumFlagsField(sensorFlagsProp.displayName, provider.AvailableSensors);
                sensorFlagsProp.intValue = (int)Convert.ChangeType(sensorFlagsEnumValue, typeof(SensorFlags));

                var gestureFlagsProp      = property.FindPropertyRelative(GESTURE_FLAGS_FIELD);
                var gestureFlagsEnumValue = EditorGUILayout.EnumFlagsField(gestureFlagsProp.displayName, provider.AvailableGestures);
                gestureFlagsProp.intValue = (int)Convert.ChangeType(gestureFlagsEnumValue, typeof(GestureFlags));
            }
            EditorGUILayout.Space();

            // Simulated delay
            var delayProp = property.FindPropertyRelative(DELAY_TIME_FIELD);

            EditorGUILayout.PropertyField(delayProp, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
            if (delayProp.floatValue < 0.0f)
            {
                delayProp.floatValue = 0.0f;
            }

            EditorGUILayout.Space();

            // Device status, ANR, and CNC via dynamic info
            GUILayoutTools.LineSeparator();
            EditorGUILayout.PropertyField(property.FindPropertyRelative(DYNAMIC_DEVICE_INFO_FIELD), WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
            GUILayoutTools.LineSeparator();

            DynamicDeviceInfo dynamicDeviceInfo = provider.GetDynamicDeviceInfo();
            DeviceStatus      status            = dynamicDeviceInfo.deviceStatus;

            using (new EditorGUI.DisabledScope(!provider.ConnectedDevice.HasValue))
            {
                bool serviceSuspended = status.GetFlagValue(DeviceStatusFlags.SensorServiceSuspended);

                // Service suspended
                using (new EditorGUI.DisabledScope(serviceSuspended))
                {
                    // Only allow selecting a reason if the service isn't suspended
                    _sensorServiceSuspendedReason = (SensorServiceSuspendedReason)EditorGUILayout.EnumPopup(
                        SENSOR_SERVICE_SUSPENSION_REASON_LABEL,
                        _sensorServiceSuspendedReason,
                        WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                }

                if (serviceSuspended)
                {
                    bool shouldResume = GUILayout.Button(RESUME_SENSOR_SERVICE_LABEL, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    if (shouldResume)
                    {
                        provider.SimulateSensorServiceResumed();
                    }
                }
                else
                {
                    bool shouldSuspend = GUILayout.Button(SUSPEND_SENSOR_SERVICE_LABEL, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    if (shouldSuspend)
                    {
                        provider.SimulateSensorServiceSuspended(_sensorServiceSuspendedReason);
                    }
                }
            }

            EditorGUILayout.Space();

            // Configuration results
            var sensorConfigResultProperty = property.FindPropertyRelative(SENSOR_CONFIG_RESULT_FIELD);

            EditorGUILayout.PropertyField(sensorConfigResultProperty);
            var gestureConfigResultProperty = property.FindPropertyRelative(GESTURE_CONFIG_RESULT_FIELD);

            EditorGUILayout.PropertyField(gestureConfigResultProperty);

            var sensorConfigResult  = (Result)sensorConfigResultProperty.enumValueIndex;
            var gestureConfigResult = (Result)gestureConfigResultProperty.enumValueIndex;

            if (sensorConfigResult == Result.Failure &&
                gestureConfigResult == Result.Failure)
            {
                EditorGUILayout.HelpBox(BOTH_CONFIG_WILL_FAIL_BOX, MessageType.Warning);
            }
            else if (sensorConfigResult == Result.Failure)
            {
                EditorGUILayout.HelpBox(SENSOR_CONFIG_WILL_FAIL_BOX, MessageType.Warning);
            }
            else if (gestureConfigResult == Result.Failure)
            {
                EditorGUILayout.HelpBox(GESTURE_CONFIG_WILL_FAIL_BOX, MessageType.Warning);
            }
            EditorGUILayout.Space();


            // Movement simulation
            SerializedProperty simulateMovementProperty = property.FindPropertyRelative(MOVEMENT_SIMULATION_MODE_FIELD);

            EditorGUILayout.PropertyField(simulateMovementProperty, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
            var simulatedMovementMode = (WearableDebugProvider.MovementSimulationMode)simulateMovementProperty.enumValueIndex;

            if (simulatedMovementMode == WearableDebugProvider.MovementSimulationMode.ConstantRate)
            {
                SerializedProperty rotationTypeProperty = property.FindPropertyRelative(ROTATION_TYPE_FIELD);
                EditorGUILayout.PropertyField(rotationTypeProperty, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);

                string rotationType = rotationTypeProperty.enumNames[rotationTypeProperty.enumValueIndex];
                if (rotationType == ROTATION_TYPE_EULER)
                {
                    EditorGUILayout.HelpBox(EULER_RATE_BOX, MessageType.None);
                    EditorGUILayout.PropertyField(property.FindPropertyRelative(EULER_SPIN_RATE_FIELD), WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                }
                else if (rotationType == ROTATION_TYPE_AXIS_ANGLE)
                {
                    EditorGUILayout.HelpBox(AXIS_ANGLE_BOX, MessageType.None);
                    SerializedProperty axisAngleProperty = property.FindPropertyRelative(AXIS_ANGLE_SPIN_RATE_FIELD);
                    Vector4            previousValue     = axisAngleProperty.vector4Value;
                    Vector4            newValue          = EditorGUILayout.Vector3Field(
                        AXIS_LABEL,
                        new Vector3(previousValue.x, previousValue.y, previousValue.z),
                        WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    if (newValue.sqrMagnitude < float.Epsilon)
                    {
                        newValue.x = 1.0f;
                    }

                    newValue.w = EditorGUILayout.FloatField(RATE_LABEL, previousValue.w, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    axisAngleProperty.vector4Value = newValue;
                }
            }
            else if (simulatedMovementMode == WearableDebugProvider.MovementSimulationMode.MobileDevice)
            {
                EditorGUILayout.HelpBox(USE_SIMULATED_MOVEMENT_MOBILE_DEVICE_HELP_BOX, MessageType.Info);
            }

            // Gesture triggers
            GUILayout.Label(GESTURES_LABEL, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
            for (int i = 0; i < WearableConstants.GESTURE_IDS.Length; i++)
            {
                GestureId gesture = WearableConstants.GESTURE_IDS[i];

                if (gesture == GestureId.None)
                {
                    continue;
                }

                using (new EditorGUI.DisabledScope(
                           !(provider.GetCachedDeviceConfiguration().GetGestureConfig(gesture).isEnabled&&
                             EditorApplication.isPlaying)))
                {
                    bool shouldTrigger = GUILayout.Button(Enum.GetName(typeof(GestureId), gesture), WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                    if (shouldTrigger)
                    {
                        provider.SimulateGesture(gesture);
                    }
                }
            }

            // Disconnect button
            EditorGUILayout.Space();
            using (new EditorGUI.DisabledScope(!provider.ConnectedDevice.HasValue))
            {
                bool shouldDisconnect = GUILayout.Button(DISCONNECT_LABEL, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                if (shouldDisconnect)
                {
                    provider.SimulateDisconnect();
                }
            }

            // Debug Logging
            GUI.changed = false;
            var debugLoggingProp = property.FindPropertyRelative(DEBUG_LOGGING_FIELD);

            EditorGUILayout.PropertyField(debugLoggingProp, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
            if (Application.isPlaying && GUI.changed)
            {
                var activeProvider = WearableControl.Instance.ActiveProvider;
                if (activeProvider != null)
                {
                    activeProvider.ConfigureDebugLogging();
                }
            }

            EditorGUI.EndProperty();
        }
コード例 #6
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            GUI.changed = false;

            AppIntentProfile profile = target as AppIntentProfile;

            if (profile == null)
            {
                // Nothing we can do, so give up.
                return;
            }

            // Sensors
            EditorGUILayout.LabelField(SENSORS_LABEL, EditorStyles.boldLabel);
            _newSensors.Clear();
            bool sensorsChanged = false;

            for (int i = 0; i < WearableConstants.SENSOR_IDS.Length; i++)
            {
                SensorId id = WearableConstants.SENSOR_IDS[i];

                bool prior = profile.GetSensorInProfile(id);
                bool post  = EditorGUILayout.Toggle(id.ToString(), prior, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                sensorsChanged |= prior != post;

                if (post)
                {
                    _newSensors.Add(id);
                }
            }

            if (sensorsChanged)
            {
                profile.SetSensorIntent(_newSensors);
            }

            // Intervals
            GUILayoutTools.LineSeparator();
            EditorGUILayout.LabelField(INTERVALS_LABEL, EditorStyles.boldLabel);
            _newIntervals.Clear();
            bool intervalsChanged = false;

            for (int i = 0; i < WearableConstants.UPDATE_INTERVALS.Length; i++)
            {
                SensorUpdateInterval interval = WearableConstants.UPDATE_INTERVALS[i];
                string label = string.Format(
                    INTERVAL_FORMAT,
                    ((int)WearableTools.SensorUpdateIntervalToMilliseconds(interval)).ToString());
                bool prior = profile.GetIntervalInProfile(interval);
                bool post  = EditorGUILayout.Toggle(label, prior, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                intervalsChanged |= prior != post;

                if (post)
                {
                    _newIntervals.Add(interval);
                }
            }

            if (intervalsChanged)
            {
                profile.SetIntervalIntent(_newIntervals);
            }


            // Gestures
            GUILayoutTools.LineSeparator();
            EditorGUILayout.LabelField(GESTURES_LABEL, EditorStyles.boldLabel);

            _newGestures.Clear();
            bool gesturesChanged = false;

            for (int i = 0; i < WearableConstants.GESTURE_IDS.Length; i++)
            {
                GestureId id = WearableConstants.GESTURE_IDS[i];

                if (id == GestureId.None)
                {
                    continue;
                }

                bool prior = profile.GetGestureInProfile(id);
                bool post  = EditorGUILayout.Toggle(id.ToString(), prior, WearableEditorConstants.EMPTY_LAYOUT_OPTIONS);
                gesturesChanged |= prior != post;

                if (post)
                {
                    _newGestures.Add(id);
                }
            }

            if (gesturesChanged)
            {
                profile.SetGestureIntent(_newGestures);
            }

            if (HasDeviceSpecificGesturesEnabled(profile))
            {
                EditorGUILayout.HelpBox(WearableEditorConstants.DEVICE_SPECIFIC_GESTURE_DISCOURAGED_WARNING, MessageType.Warning);
            }

            if (GUI.changed)
            {
                serializedObject.ApplyModifiedProperties();
                EditorUtility.SetDirty(target);
            }
        }