From 8bc1f6851b8ae01671e77c0a1f067df31b5e39b3 Mon Sep 17 00:00:00 2001 From: Daniel Goodnow Date: Thu, 17 Oct 2024 00:20:22 -0700 Subject: [PATCH] Fixed for sliders with min-max values outside range \[0-1\] when slider is configured for grab interaction (IsTouchable = false) --- org.mixedrealitytoolkit.uxcore/CHANGELOG.md | 4 + .../Slider/Slider.cs | 13 +- .../Runtime/Prefabs/GrabSliderTest.prefab | 223 ++++++++++++++++++ .../Prefabs/GrabSliderTest.prefab.meta | 7 + .../Runtime/Prefabs/TouchSliderTest.prefab | 199 ++++++++++++++++ .../Prefabs/TouchSliderTest.prefab.meta | 7 + .../Tests/Runtime/SliderTests.cs | 177 ++++++++++++++ .../Tests/Runtime/SliderTests.cs.meta | 11 + 8 files changed, 635 insertions(+), 6 deletions(-) create mode 100644 org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab create mode 100644 org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab.meta create mode 100644 org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab create mode 100644 org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab.meta create mode 100644 org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs create mode 100644 org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs.meta diff --git a/org.mixedrealitytoolkit.uxcore/CHANGELOG.md b/org.mixedrealitytoolkit.uxcore/CHANGELOG.md index 8fc18f1e8..b002395dd 100644 --- a/org.mixedrealitytoolkit.uxcore/CHANGELOG.md +++ b/org.mixedrealitytoolkit.uxcore/CHANGELOG.md @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). * StateVisualizer: Modified access modifiers of State, stateContainers and UpdateStateValue to protected internal to allow adding states through subclassing. [PR #926](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/926) +### Fixed + +* Fixed for sliders with min-max values outside range \[0-1\] when slider is configured for grab interaction (IsTouchable = false) [Issue 944](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/issues/944) + ## [3.2.2-development] - 2024-08-29 ### Changed diff --git a/org.mixedrealitytoolkit.uxcore/Slider/Slider.cs b/org.mixedrealitytoolkit.uxcore/Slider/Slider.cs index e75e64296..b5b7f55e6 100644 --- a/org.mixedrealitytoolkit.uxcore/Slider/Slider.cs +++ b/org.mixedrealitytoolkit.uxcore/Slider/Slider.cs @@ -285,7 +285,7 @@ protected override void Reset() /// /// A Unity event function that is called on the frame when a script is enabled just before any of the update methods are called the first time. - /// + /// protected virtual void Start() { // Turn on/off colliders at Start() to avoid bugs with @@ -331,7 +331,7 @@ private void OnValidate() #region Protected Methods /// - /// Invoked on , , and to apply required + /// Invoked on , , and to apply required /// settings to this instance. /// /// @@ -347,7 +347,7 @@ protected virtual void ApplyRequiredSettings() #endregion Protected Methods #region Private Methods - /// + /// /// Private method used to adjust initial slider value to stepwise values /// private void InitializeStepDivisions() @@ -370,7 +370,8 @@ private void UpdateSliderValue() var handDelta = Vector3.Dot(SliderTrackDirection.normalized, interactorDelta); - float normalizedValue = Mathf.Clamp(StartSliderValue + handDelta / SliderTrackDirection.magnitude, 0f, 1.0f); + var normalizedStartValue = (StartSliderValue - MinValue) / (MaxValue - MinValue); + float normalizedValue = Mathf.Clamp(normalizedStartValue + handDelta / SliderTrackDirection.magnitude, 0f, 1.0f); var unsnappedValue = normalizedValue * (MaxValue - MinValue) + MinValue; Value = useSliderStepDivisions ? SnapSliderToStepPositions(unsnappedValue) : unsnappedValue; @@ -386,12 +387,12 @@ protected override void OnSelectEntered(SelectEnterEventArgs args) base.OnSelectEntered(args); // Snap to position by setting the startPosition - // to the slider start, and start value to zero. + // to the slider start, and start value to MinValue. // However, don't snap when using grabs. if (snapToPosition && !(args.interactorObject is IGrabInteractor)) { StartInteractionPoint = SliderStart.position; - StartSliderValue = 0.0f; + StartSliderValue = MinValue; } else { diff --git a/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab new file mode 100644 index 000000000..2dc1cc8ff --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab @@ -0,0 +1,223 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1110146781791029298 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6995764633665568835} + - component: {fileID: 225870791008350227} + - component: {fileID: 2620194905356491814} + m_Layer: 0 + m_Name: GrabSliderTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6995764633665568835 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1110146781791029298} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 1} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3903447421959142264} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 1.6} + m_SizeDelta: {x: 200, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!223 &225870791008350227 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1110146781791029298} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 30 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &2620194905356491814 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1110146781791029298} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!1001 &8710701791544316266 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 6995764633665568835} + m_Modifications: + - target: {fileID: 4270209841583229004, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Size.x + value: 200 + objectReference: {fileID: 0} + - target: {fileID: 5677198131096132917, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMax.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132670553562, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMax.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132670553562, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMin.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132670553562, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132670553562, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834573, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: value + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834573, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: maxValue + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834573, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: isTouchable + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMax.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMax.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMin.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMin.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_SizeDelta.x + value: 200 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834579, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Name + value: CanvasSlider + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f64620d502cdf0f429efa27703913cb7, type: 3} +--- !u!224 &3903447421959142264 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + m_PrefabInstance: {fileID: 8710701791544316266} + m_PrefabAsset: {fileID: 0} diff --git a/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab.meta b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab.meta new file mode 100644 index 000000000..1a1ba4e9d --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 963b272467be8374a819a30f8613ff0a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab new file mode 100644 index 000000000..04447cfc4 --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab @@ -0,0 +1,199 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3047717518764935770 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4915204746499457579} + - component: {fileID: 2738705601465610875} + - component: {fileID: 107927030599081550} + m_Layer: 0 + m_Name: TouchSliderTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4915204746499457579 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3047717518764935770} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 1} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1371476713296591120} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 1.6} + m_SizeDelta: {x: 200, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!223 &2738705601465610875 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3047717518764935770} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 30 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &107927030599081550 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3047717518764935770} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 1 +--- !u!1001 &6755684569402381058 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 4915204746499457579} + m_Modifications: + - target: {fileID: 4270209841583229004, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Size.x + value: 200 + objectReference: {fileID: 0} + - target: {fileID: 5677198132670553562, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132670553562, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMax.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMax.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMin.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchorMin.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_SizeDelta.x + value: 200 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5677198132984834579, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + propertyPath: m_Name + value: CanvasSlider + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f64620d502cdf0f429efa27703913cb7, type: 3} +--- !u!224 &1371476713296591120 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 5677198132984834578, guid: f64620d502cdf0f429efa27703913cb7, type: 3} + m_PrefabInstance: {fileID: 6755684569402381058} + m_PrefabAsset: {fileID: 0} diff --git a/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab.meta b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab.meta new file mode 100644 index 000000000..08353249d --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1374e50c73ead974790c738f942ed65a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs new file mode 100644 index 000000000..68f4dada7 --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs @@ -0,0 +1,177 @@ +// Copyright (c) Mixed Reality Toolkit Contributors +// Licensed under the BSD 3-Clause + +using MixedReality.Toolkit.Input.Tests; +using NUnit.Framework; + +namespace MixedReality.Toolkit.UX.Runtime.Tests +{ + using Core.Tests; + using Input; + using System; + using System.Collections; + using UnityEditor; + using UnityEngine; + using UnityEngine.TestTools; + using Object = UnityEngine.Object; + + public class SliderTests : BaseRuntimeInputTests + { + private const string TouchSliderPrefabPath = + "Packages/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/TouchSliderTest.prefab"; + + private const string GrabSliderPrefabPath = + "Packages/org.mixedrealitytoolkit.uxcore/Tests/Runtime/Prefabs/GrabSliderTest.prefab"; + + private const int HandMovementFrames = 10; + + private TestHand hand; + + [SetUp] + public void SetUp() + { + hand = new TestHand(Handedness.Right); + } + + [UnityTest] + public IEnumerator TouchSlider_MoveRight_ValueIncreasesCorrectly([ValueSource(nameof(MoveRightTestCases))] TestCase testCase) + { + InputTestUtilities.InitializeCameraToOriginAndForward(); + + var testPrefab = InstantiateSlider(TouchSliderPrefabPath); + testPrefab.transform.position = InputTestUtilities.InFrontOfUser(new Vector3(0, 0, 1)); + + var slider = testPrefab.GetComponentInChildren(); + slider.MinValue = testCase.MinValue; + slider.MaxValue = testCase.MaxValue; + slider.Value = ((testCase.MaxValue - testCase.MinValue) / 2) + testCase.MinValue; + + yield return ShowHand(); + yield return hand.MoveTo(testPrefab.transform.position - new Vector3(0, 0, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.MoveTo(testPrefab.transform.position - new Vector3(-0.04f, 0f, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + Assert.That(slider.Value, Is.EqualTo(testCase.Expected).Within(0.00001f)); + + Object.Destroy(testPrefab); + } + + [UnityTest] + public IEnumerator GrabSlider_MoveRight_ValueIncreasesCorrectly([ValueSource(nameof(MoveRightTestCases))] TestCase testCase) + { + InputTestUtilities.InitializeCameraToOriginAndForward(); + + var testPrefab = InstantiateSlider(GrabSliderPrefabPath); + testPrefab.transform.position = InputTestUtilities.InFrontOfUser(new Vector3(0, 0, 1)); + + var slider = testPrefab.GetComponentInChildren(); + slider.MinValue = testCase.MinValue; + slider.MaxValue = testCase.MaxValue; + slider.Value = ((testCase.MaxValue - testCase.MinValue) / 2) + testCase.MinValue; + + yield return ShowHand(); + yield return hand.MoveTo(testPrefab.transform.position - new Vector3(0, 0, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.SetHandshape(HandshapeTypes.HandshapeId.Grab); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.MoveTo(testPrefab.transform.position - new Vector3(-0.04f, 0f, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.SetHandshape(HandshapeTypes.HandshapeId.Open); + yield return RuntimeTestUtilities.WaitForUpdates(); + + Assert.That(slider.Value, Is.EqualTo(testCase.Expected).Within(0.00001f)); + + Object.Destroy(testPrefab); + } + [UnityTest] + public IEnumerator TouchSlider_MoveLeft_ValueIncreasesCorrectly([ValueSource(nameof(MoveLeftTestCases))] TestCase testCase) + { + InputTestUtilities.InitializeCameraToOriginAndForward(); + + var testPrefab = InstantiateSlider(TouchSliderPrefabPath); + testPrefab.transform.position = InputTestUtilities.InFrontOfUser(new Vector3(0, 0, 1)); + + var slider = testPrefab.GetComponentInChildren(); + slider.MinValue = testCase.MinValue; + slider.MaxValue = testCase.MaxValue; + slider.Value = ((testCase.MaxValue - testCase.MinValue) / 2) + testCase.MinValue; + + yield return ShowHand(); + yield return hand.MoveTo(testPrefab.transform.position - new Vector3(0, 0, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.MoveTo(testPrefab.transform.position + new Vector3(-0.04f, 0f, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + Assert.That(slider.Value, Is.EqualTo(testCase.Expected).Within(0.00001f)); + + Object.Destroy(testPrefab); + } + + [UnityTest] + public IEnumerator GrabSlider_MoveLeft_ValueIncreasesCorrectly([ValueSource(nameof(MoveLeftTestCases))] TestCase testCase) + { + InputTestUtilities.InitializeCameraToOriginAndForward(); + + var testPrefab = InstantiateSlider(GrabSliderPrefabPath); + testPrefab.transform.position = InputTestUtilities.InFrontOfUser(new Vector3(0, 0, 1)); + + var slider = testPrefab.GetComponentInChildren(); + slider.MinValue = testCase.MinValue; + slider.MaxValue = testCase.MaxValue; + slider.Value = ((testCase.MaxValue - testCase.MinValue) / 2) + testCase.MinValue; + + yield return ShowHand(); + yield return hand.MoveTo(testPrefab.transform.position - new Vector3(0, 0, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.SetHandshape(HandshapeTypes.HandshapeId.Grab); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.MoveTo(testPrefab.transform.position + new Vector3(-0.04f, 0f, 0.00f), HandMovementFrames); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return hand.SetHandshape(HandshapeTypes.HandshapeId.Open); + yield return RuntimeTestUtilities.WaitForUpdates(); + + Assert.That(slider.Value, Is.EqualTo(testCase.Expected).Within(0.00001f)); + + Object.Destroy(testPrefab); + } + + public struct TestCase + { + public float MinValue; + public float MaxValue; + public float Expected; + } + + private static IEnumerable MoveRightTestCases() + { + yield return new TestCase { MinValue = 0, MaxValue = 1, Expected = 0.7f }; + yield return new TestCase { MinValue = 0, MaxValue = 10, Expected = 7 }; + yield return new TestCase { MinValue = 0, MaxValue = 0.1f, Expected = 0.07f }; + yield return new TestCase { MinValue = -1, MaxValue = 1, Expected = 0.4f }; + yield return new TestCase { MinValue = -1, MaxValue = 0, Expected = -0.3f }; + } + + private static IEnumerable MoveLeftTestCases() + { + yield return new TestCase { MinValue = 0, MaxValue = 1, Expected = 0.3f }; + yield return new TestCase { MinValue = 0, MaxValue = 10, Expected = 3 }; + yield return new TestCase { MinValue = 0, MaxValue = 0.1f, Expected = 0.03f }; + yield return new TestCase { MinValue = -1, MaxValue = 1, Expected = -0.4f }; + yield return new TestCase { MinValue = -1, MaxValue = 0, Expected = -0.7f }; + } + + private IEnumerator ShowHand() + { + Vector3 initialHandPosition = InputTestUtilities.InFrontOfUser(new Vector3(0.05f, -0.05f, 0.3f)); + yield return hand.Show(initialHandPosition); + yield return RuntimeTestUtilities.WaitForUpdates(); + } + + private GameObject InstantiateSlider(string prefabPath) + { + + GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath); + GameObject obj = GameObject.Instantiate(prefab); + return obj; + } + } +} diff --git a/org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs.meta b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs.meta new file mode 100644 index 000000000..30c04f669 --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/Tests/Runtime/SliderTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32287a005eb5f72449ea29262d9d660f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: