예제 #1
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(DescriptionBox, MessageType.None);
            EditorGUILayout.Space();

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

            using (new EditorGUI.DisabledScope(provider.ConnectedDevice.HasValue))
            {
                // Device properties
                EditorGUILayout.IntSlider(
                    property.FindPropertyRelative(RSSIField),
                    WearableConstants.MinimumRSSIValue,
                    WearableConstants.MaximumRSSIValue,
                    WearableConstants.EmptyLayoutOptions);

                EditorGUILayout.Separator();
                EditorGUILayout.PropertyField(property.FindPropertyRelative(DeviceNameField), WearableConstants.EmptyLayoutOptions);
                EditorGUILayout.PropertyField(property.FindPropertyRelative(UIDField), WearableConstants.EmptyLayoutOptions);

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

                EditorGUI.BeginChangeCheck();
                _productType = (ProductType)EditorGUILayout.EnumPopup(
                    ProductTypeLabel,
                    _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(
                    VariantTypeLabel,
                    optionIndex >= 0 ? optionIndex : 0,
                    _editorVariantOptions
                    );

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

                // Firmware simulation
                EditorGUILayout.PropertyField(property.FindPropertyRelative(FirmwareVersionField), WearableConstants.EmptyLayoutOptions);
                var firmwareSufficient = property.FindPropertyRelative(BoseArEnabledField);
                var firmwareAvailable  = property.FindPropertyRelative(FirmwareUpdateAvailableField);
                EditorGUILayout.PropertyField(firmwareSufficient, WearableConstants.EmptyLayoutOptions);
                EditorGUILayout.PropertyField(firmwareAvailable, WearableConstants.EmptyLayoutOptions);

                if (firmwareSufficient.boolValue)
                {
                    if (firmwareAvailable.boolValue)
                    {
                        EditorGUILayout.HelpBox(FirmwareUpdateAvailableBox, MessageType.Info);
                    }
                    else
                    {
                        EditorGUILayout.HelpBox(FirmwareGoodBox, MessageType.Info);
                    }
                }
                else
                {
                    if (firmwareAvailable.boolValue)
                    {
                        EditorGUILayout.HelpBox(FirmwareUpdateRequiredBox, MessageType.Warning);
                    }
                    else
                    {
                        EditorGUILayout.HelpBox(FirmwareDeviceNotSupportedBox, MessageType.Error);
                    }
                }

                // Secure pairing
                var acceptSecurePairing = property.FindPropertyRelative(AcceptSecurePairingField);
                EditorGUILayout.PropertyField(acceptSecurePairing, WearableConstants.EmptyLayoutOptions);
                if (acceptSecurePairing.boolValue)
                {
                    EditorGUILayout.HelpBox(SecurePairingAcceptedBox, MessageType.Info);
                }
                else
                {
                    EditorGUILayout.HelpBox(SecurePairingRejectedBox, MessageType.Error);
                }

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

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

            // Verbose mode
            EditorGUILayout.PropertyField(property.FindPropertyRelative(VerboseField), WearableConstants.EmptyLayoutOptions);

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

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

            EditorGUILayout.Space();

            // Device status
            EditorGUILayout.LabelField(DeviceStatusHeading);
            EditorGUILayout.PropertyField(property.FindPropertyRelative(DynamicDeviceInfoField));

            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(
                        SensorServiceSuspensionReasonLabel,
                        _sensorServiceSuspendedReason);
                }

                if (serviceSuspended)
                {
                    bool shouldResume = GUILayout.Button(ResumeSensorServiceLabel, WearableConstants.EmptyLayoutOptions);
                    if (shouldResume)
                    {
                        provider.SimulateSensorServiceResumed();
                    }
                }
                else
                {
                    bool shouldSuspend = GUILayout.Button(SuspendSensorServiceLabel, WearableConstants.EmptyLayoutOptions);
                    if (shouldSuspend)
                    {
                        provider.SimulateSensorServiceSuspended(_sensorServiceSuspendedReason);
                    }
                }
            }

            EditorGUILayout.Space();

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

            EditorGUILayout.PropertyField(simulateMovementProperty, WearableConstants.EmptyLayoutOptions);
            var simulatedMovementMode = (WearableDebugProvider.MovementSimulationMode)simulateMovementProperty.enumValueIndex;

            if (simulatedMovementMode == WearableDebugProvider.MovementSimulationMode.ConstantRate)
            {
                SerializedProperty rotationTypeProperty = property.FindPropertyRelative(RotationTypeField);
                EditorGUILayout.PropertyField(rotationTypeProperty, WearableConstants.EmptyLayoutOptions);

                string rotationType = rotationTypeProperty.enumNames[rotationTypeProperty.enumValueIndex];
                if (rotationType == RotationTypeEuler)
                {
                    EditorGUILayout.HelpBox(EulerRateBox, MessageType.None);
                    EditorGUILayout.PropertyField(property.FindPropertyRelative(EulerSpinRateField), WearableConstants.EmptyLayoutOptions);
                }
                else if (rotationType == RotationTypeAxisAngle)
                {
                    EditorGUILayout.HelpBox(AxisAngleBox, MessageType.None);
                    SerializedProperty axisAngleProperty = property.FindPropertyRelative(AxisAngleSpinRateField);
                    Vector4            previousValue     = axisAngleProperty.vector4Value;
                    Vector4            newValue          = EditorGUILayout.Vector3Field(
                        AxisLabel,
                        new Vector3(previousValue.x, previousValue.y, previousValue.z),
                        WearableConstants.EmptyLayoutOptions);
                    if (newValue.sqrMagnitude < float.Epsilon)
                    {
                        newValue.x = 1.0f;
                    }

                    newValue.w = EditorGUILayout.FloatField(RateLabel, previousValue.w, WearableConstants.EmptyLayoutOptions);
                    axisAngleProperty.vector4Value = newValue;
                }
            }
            else if (simulatedMovementMode == WearableDebugProvider.MovementSimulationMode.MobileDevice)
            {
                EditorGUILayout.HelpBox(UseSimulatedMovementMobileDeviceHelpBox, MessageType.Info);
            }

            // Gesture triggers
            GUILayout.Label(GesturesLabel, WearableConstants.EmptyLayoutOptions);
            for (int i = 0; i < WearableConstants.GestureIds.Length; i++)
            {
                GestureId gesture = WearableConstants.GestureIds[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), WearableConstants.EmptyLayoutOptions);
                    if (shouldTrigger)
                    {
                        provider.SimulateGesture(gesture);
                    }
                }
            }

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

            EditorGUI.EndProperty();
        }
        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();
        }