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