AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SliderGestureControl.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using HoloToolkit.Unity;
5 using UnityEngine;
6 
7 namespace HoloToolkit.Examples.InteractiveElements
8 {
13  {
14  [Tooltip("The main bar of the slider, used to get the actual width of the slider")]
15  public GameObject SliderBar;
16  [Tooltip("The visual marker of the slider value")]
17  public GameObject Knob;
18  [Tooltip("The fill that represents the volume of the shader value")]
19  public GameObject SliderFill;
20  [Tooltip("The text representation of the slider value")]
21  public TextMesh Label;
22 
23  [Tooltip("Used for centered format only, will be turned off if LeftJustified")]
24  public GameObject CenteredDot;
25 
26  [Tooltip("Sends slider event information on Update")]
28 
32  public float SliderValue
33  {
34  private set
35  {
36  if (sliderValue != value)
37  {
38  sliderValue = value;
39  OnUpdateEvent.Invoke(sliderValue);
40  }
41  }
42  get
43  {
44  return sliderValue;
45  }
46  }
47 
48  [SerializeField]
49  [Tooltip("Set the starting value for the slider here.")]
50  private float sliderValue = 0;
51 
52  [Tooltip("Min numeric value to display in the slider label")]
53  public float MinSliderValue = 0;
54 
55  [Tooltip("Max numeric value to display in the slider label")]
56  public float MaxSliderValue = 1;
57 
58  [Tooltip("Switches between a left justified or centered slider")]
59  public bool Centered = false;
60 
61  [Tooltip("Format the slider value and control decimal places if needed")]
62  public string LabelFormat = "#.##";
63 
64  // calculation variables
65  private float mValueSpan;
66  private float mCachedValue;
67  private float mDeltaValue;
68  private Vector3 mStartCenter = new Vector3();
69  private float mSliderMagnitude;
70  private Vector3 mStartSliderPosition;
71 
72  // cached UI values
73  private Vector3 mKnobVector;
74  private Vector3 mSliderFillScale;
75  private float mSliderWidth;
76 
77  private float autoSliderTime = 0.25f;
78  private float autoSliderTimerCounter = 0.5f;
79  private float autoSliderValue = 0;
80 
81  private Vector3 mSliderVector;
82  private Quaternion mCachedRotation;
83 
84  protected override void Awake()
85  {
86  base.Awake();
87 
88  if (MinSliderValue >= MaxSliderValue)
89  {
90  Debug.LogError("Your SliderGestureControl has a min value that's greater than or equal to its max value.");
91  gameObject.SetActive(false);
92  return;
93  }
94 
95  if (Centered && MinSliderValue != -MaxSliderValue)
96  {
97  Debug.LogError("A centered SliderGestureControl requires that the min and max values have the same absolute value, one positive and one negative.");
98  gameObject.SetActive(false);
99  return;
100  }
101 
102  if (Knob != null)
103  {
104  mStartCenter.z = Knob.transform.localPosition.z;
105  }
106 
107  mCachedRotation = SliderBar.transform.rotation;
108 
109  // with some better math below, I may be able to avoid rotating to get the proper size of the component
110 
111  SliderBar.transform.rotation = Quaternion.identity;
112 
113  // set the width of the slider
114  mSliderMagnitude = SliderBar.transform.InverseTransformVector(SliderBar.GetComponent<Renderer>().bounds.size).x;
115 
116  // set the center position
117  mStartSliderPosition = mStartCenter + Vector3.left * mSliderMagnitude / 2;
118 
119  mValueSpan = MaxSliderValue - MinSliderValue;
120  sliderValue = Mathf.Clamp(SliderValue, MinSliderValue, MaxSliderValue);
121 
122  if (!Centered)
123  {
124  mDeltaValue = (SliderValue - MinSliderValue) / mValueSpan;
125  }
126  else
127  {
128  mValueSpan = (MaxSliderValue - MinSliderValue) / 2;
129  mDeltaValue = (SliderValue + mValueSpan) / 2 / mValueSpan;
130  }
131 
132  mSliderFillScale = new Vector3(1, 1, 1);
133  mSliderWidth = mSliderMagnitude;
134  if (SliderFill != null)
135  {
136  mSliderFillScale = SliderFill.transform.localScale;
137  mSliderWidth = SliderFill.transform.InverseTransformVector(SliderFill.GetComponent<Renderer>().bounds.size).x;
138  }
139 
140  if (CenteredDot != null && !Centered)
141  {
142  CenteredDot.SetActive(false);
143  }
144 
145  SliderBar.transform.rotation = mCachedRotation;
146 
147  UpdateVisuals();
148  mCachedValue = mDeltaValue;
149 
150  mSliderVector = SliderBar.transform.InverseTransformPoint(mStartCenter + SliderBar.transform.right * mSliderMagnitude / 2) - SliderBar.transform.InverseTransformPoint(mStartCenter - SliderBar.transform.right * mSliderMagnitude / 2);
151  AlignmentVector = SliderBar.transform.right;
152  AlignmentVector = mSliderVector;
153  }
154 
155  public override void ManipulationUpdate(Vector3 startGesturePosition, Vector3 currentGesturePosition, Vector3 startHeadOrigin, Vector3 startHeadRay, GestureInteractive.GestureManipulationState gestureState)
156  {
157  if (AlignmentVector != SliderBar.transform.right)
158  {
159  mSliderVector = SliderBar.transform.InverseTransformPoint(mStartCenter + SliderBar.transform.right * mSliderMagnitude / 2) - SliderBar.transform.InverseTransformPoint(mStartCenter - SliderBar.transform.right * mSliderMagnitude / 2);
160  AlignmentVector = SliderBar.transform.right;
161 
162  mCachedRotation = SliderBar.transform.rotation;
163  }
164 
165  base.ManipulationUpdate(startGesturePosition, currentGesturePosition, startHeadOrigin, startHeadRay, gestureState);
166 
167  // get the current delta
168  float delta = (CurrentDistance > 0) ? CurrentPercentage : -CurrentPercentage;
169 
170  // combine the delta with the current slider position so the slider does not start over every time
171  mDeltaValue = Mathf.Clamp01(delta + mCachedValue);
172 
173  if (!Centered)
174  {
175  SliderValue = mDeltaValue * mValueSpan + MinSliderValue;
176  }
177  else
178  {
179  SliderValue = mDeltaValue * mValueSpan * 2 - mValueSpan;
180  }
181 
182  UpdateVisuals();
183 
184  if (gestureState == GestureInteractive.GestureManipulationState.None)
185  {
186  // gesture ended - cache the current delta
187  mCachedValue = mDeltaValue;
188  }
189  }
190 
195  public override void setGestureValue(int gestureValue)
196  {
197  //base.setGestureValue(gestureValue);
198 
199  if (GestureStarted)
200  {
201  return;
202  }
203 
204  switch (gestureValue)
205  {
206  case 0:
207  autoSliderValue = 0;
208  break;
209  case 1:
210  autoSliderValue = 0.5f;
211  break;
212  case 2:
213  autoSliderValue = 1;
214  break;
215  }
216  autoSliderTimerCounter = 0;
217  }
218 
224  public void SetSpan(float min, float max)
225  {
226  mValueSpan = max - min;
227  MaxSliderValue = max;
228  MinSliderValue = min;
229  }
230 
235  public void SetSliderValue(float value)
236  {
237  if (GestureStarted)
238  {
239  return;
240  }
241 
242  SliderValue = Mathf.Clamp(value, MinSliderValue, MaxSliderValue);
243  mDeltaValue = SliderValue / MaxSliderValue;
244  UpdateVisuals();
245  mCachedValue = mDeltaValue;
246  }
247 
248  // update visuals
249  private void UpdateVisuals()
250  {
251  // set the knob position
252  mKnobVector = mStartSliderPosition + Vector3.right * mSliderMagnitude * mDeltaValue;
253  mKnobVector.z = mStartCenter.z;
254 
255  // TODO: Add snapping!
256 
257  if (Knob != null)
258  {
259  Knob.transform.localPosition = mKnobVector;
260  }
261 
262  // set the fill scale and position
263  if (SliderFill != null)
264  {
265  Vector3 scale = mSliderFillScale;
266  scale.x = mSliderFillScale.x * mDeltaValue;
267 
268  Vector3 position = Vector3.left * (mSliderWidth * 0.5f - mSliderWidth * mDeltaValue * 0.5f); // left justified;
269 
270  if (Centered)
271  {
272  if (SliderValue < 0)
273  {
274  position = Vector3.left * (mSliderWidth * 0.5f - mSliderWidth * 0.5f * (mDeltaValue + 0.5f)); // pinned to center, going left
275  scale.x = mSliderFillScale.x * (1 - mDeltaValue / 0.5f) * 0.5f;
276  }
277  else
278  {
279  position = Vector3.right * ((mSliderWidth * 0.5f * (mDeltaValue - 0.5f))); // pinned to center, going right
280  scale.x = mSliderFillScale.x * ((mDeltaValue - 0.5f) / 0.5f) * 0.5f;
281  }
282  }
283 
284  SliderFill.transform.localScale = scale;
285  SliderFill.transform.localPosition = position;
286  }
287 
288  // set the label
289  if (Label != null)
290  {
291  if (LabelFormat.IndexOf('.') > -1)
292  {
293  Label.text = SliderValue.ToString(LabelFormat);
294 
295  }
296  else
297  {
298  Label.text = Mathf.Round(SliderValue).ToString(LabelFormat);
299  }
300  }
301  }
302 
306  protected override void Update()
307  {
308  base.Update();
309 
310  if (autoSliderTimerCounter < autoSliderTime)
311  {
312  if (GestureStarted)
313  {
314  autoSliderTimerCounter = autoSliderTime;
315  return;
316  }
317 
318  autoSliderTimerCounter += Time.deltaTime;
319  if (autoSliderTimerCounter >= autoSliderTime)
320  {
321  autoSliderTimerCounter = autoSliderTime;
322  mCachedValue = autoSliderValue;
323  }
324 
325  mDeltaValue = (autoSliderValue - mCachedValue) * autoSliderTimerCounter / autoSliderTime + mCachedValue;
326 
327  if (!Centered)
328  {
329  SliderValue = mDeltaValue * mValueSpan + MinSliderValue;
330  }
331  else
332  {
333  SliderValue = mDeltaValue * mValueSpan * 2 - mValueSpan;
334  }
335 
336  UpdateVisuals();
337  }
338  }
339  }
340 }
void SetSpan(float min, float max)
set the distance of the slider
GestureInteractive extends Interactive and handles more advanced gesture events. On Press a gesture b...
override void ManipulationUpdate(Vector3 startGesturePosition, Vector3 currentGesturePosition, Vector3 startHeadOrigin, Vector3 startHeadRay, GestureInteractive.GestureManipulationState gestureState)
Gesture updates called by GestureInteractive
override void setGestureValue(int gestureValue)
allows the slider to be automated or triggered by a key word
void SetSliderValue(float value)
override the slider value