AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
Button.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 
5 using System;
6 using System.Collections;
7 using UnityEngine;
8 
9 namespace HoloToolkit.Unity.Buttons
10 {
15  {
16  #region Public Members and Serialized Fields
17 
18  [Header("Basic Settings")]
19  [SerializeField]
20  [Tooltip("Current State of the Button")]
21  private ButtonStateEnum buttonState = ButtonStateEnum.Observation;
22 
26  public ButtonStateEnum ButtonState
27  {
28  get { return buttonState; }
29  set { buttonState = value; }
30  }
31 
32  [SerializeField]
33  [Tooltip("Filter for press info for click or press event")]
34  private InteractionSourcePressInfo buttonPressFilter = InteractionSourcePressInfo.Select;
35 
39  public InteractionSourcePressInfo ButtonPressFilter
40  {
41  get { return buttonPressFilter; }
42  set { buttonPressFilter = value; }
43  }
44 
45  [SerializeField]
46  [Tooltip("If RequireGaze, then looking away will deselect object")]
47  private bool requireGaze = true;
48 
52  public bool RequireGaze
53  {
54  get { return requireGaze; }
55  set { requireGaze = value; }
56  }
57 
61  public event Action<ButtonStateEnum> StateChange;
62 
66  public event Action<GameObject> OnButtonPressed;
67 
71  public event Action<GameObject> OnButtonReleased;
72 
76  public event Action<GameObject> OnButtonClicked;
77 
81  public event Action<GameObject> OnButtonHeld;
82 
86  public event Action<GameObject> OnButtonCanceled;
87 
88  #endregion Public Members and Serialized Fields
89 
90  #region Private and Protected Members
91 
95  protected string _GizmoIcon;
96 
100  private bool lastHandVisible = false;
101 
105  private bool handVisible { get { return InputManager.Instance.DetectedInputSources.Count > 0; } }
106 
110  private bool focused = false;
111 
115  private bool isDisabled { get { return ButtonState == ButtonStateEnum.Disabled || !enabled; } }
116 
117  #endregion Private and Protected Members
118 
119  #region MonoBehaviour Functions
120 
124  private void LateUpdate()
125  {
126  if (!isDisabled && lastHandVisible != handVisible)
127  {
128  OnHandVisibleChange(handVisible);
129  }
130  }
131 
135  protected virtual void OnDisable()
136  {
137  if (ButtonState != ButtonStateEnum.Disabled)
138  {
139  OnStateChange(ButtonStateEnum.Observation);
140  }
141  }
142 
143  #endregion MonoBehaviour Functions
144 
145  #region Input Interface Functions
146 
151  public void OnInputDown(InputEventData eventData)
152  {
153  if (!isDisabled)
154  {
155  if (ButtonPressFilter == InteractionSourcePressInfo.None || ButtonPressFilter == eventData.PressType)
156  {
157  DoButtonPressed();
158 
159  eventData.Use();
160  }
161  }
162  }
163 
168  public void OnInputUp(InputEventData eventData)
169  {
170  if (!isDisabled)
171  {
172  if (ButtonPressFilter == InteractionSourcePressInfo.None || ButtonPressFilter == eventData.PressType)
173  {
174  DoButtonReleased();
175 
176  eventData.Use();
177  }
178  }
179  }
180 
185  public void OnInputClicked(InputClickedEventData eventData)
186  {
187  if (!isDisabled)
188  {
189  if (ButtonPressFilter == InteractionSourcePressInfo.None || ButtonPressFilter == eventData.PressType)
190  {
191  DoButtonClicked();
192 
193  eventData.Use();
194  }
195  }
196  }
197 
198 
203  public void OnHoldStarted(HoldEventData eventData)
204  {
205  if (!isDisabled)
206  {
207  DoButtonHeld();
208 
209  eventData.Use();
210  }
211  }
212 
217  public void OnHoldCompleted(HoldEventData eventData)
218  {
219  // No button event for OnHoldCompleted. State will be handled in OnInputUp.
220  }
221 
226  public void OnHoldCanceled(HoldEventData eventData)
227  {
228  if (!isDisabled && ButtonState == ButtonStateEnum.Pressed)
229  {
230  DoButtonCanceled();
231 
232  eventData.Use();
233  }
234  }
235 
239  public void OnFocusEnter(PointerSpecificEventData eventData)
240  {
241  if (!isDisabled)
242  {
243  if (ButtonState != ButtonStateEnum.Pressed)
244  {
245  OnStateChange(handVisible ? ButtonStateEnum.Targeted : ButtonStateEnum.ObservationTargeted);
246  }
247 
248  focused = true;
249 
250  eventData.Use();
251  }
252  }
253 
257  public void OnFocusExit(PointerSpecificEventData eventData)
258  {
259  if (!isDisabled)
260  {
261  // If we require gaze, we should always reset the state and send a canceled if currently pressed.
262  if (RequireGaze)
263  {
264  if (ButtonState == ButtonStateEnum.Pressed)
265  {
266  DoButtonCanceled();
267  }
268 
269  OnStateChange(handVisible ? ButtonStateEnum.Interactive : ButtonStateEnum.Observation);
270  }
271  // If we don't require gaze, we should only reset if we aren't currently in a pressed state.
272  else if (ButtonState != ButtonStateEnum.Pressed)
273  {
274  OnStateChange(handVisible ? ButtonStateEnum.Interactive : ButtonStateEnum.Observation);
275  }
276 
277  focused = false;
278 
279  eventData.Use();
280  }
281  }
282 
283  #endregion Input Interface Functions
284 
285  #region Button Functions
286 
290  protected void DoButtonPressed()
291  {
292  OnStateChange(ButtonStateEnum.Pressed);
293 
294  if (OnButtonPressed != null)
295  {
296  OnButtonPressed(gameObject);
297  }
298 
299  if (!RequireGaze)
300  {
301  // Push to the modal stack, so we'll receive a released/clicked event even if focus has left.
302  InputManager.Instance.PushModalInputHandler(gameObject);
303  }
304  }
305 
309  protected void DoButtonReleased()
310  {
311  ResetButtonState();
312 
313  if (OnButtonReleased != null)
314  {
315  OnButtonReleased(gameObject);
316  }
317  }
318 
319  protected void DoButtonClicked()
320  {
321  if (OnButtonClicked != null)
322  {
323  OnButtonClicked(gameObject);
324  }
325  }
326 
330  protected void DoButtonHeld()
331  {
332  if (OnButtonHeld != null)
333  {
334  OnButtonHeld(gameObject);
335  }
336  }
337 
341  protected void DoButtonCanceled()
342  {
343  ResetButtonState();
344 
345  if (OnButtonCanceled != null)
346  {
347  OnButtonCanceled(gameObject);
348  }
349  }
350 
355  public virtual void OnHandVisibleChange(bool visible)
356  {
357  lastHandVisible = visible;
358 
359  ButtonStateEnum newState = ButtonState;
360 
361  switch (ButtonState)
362  {
363  case ButtonStateEnum.Interactive:
364  {
365  newState = visible ? ButtonStateEnum.Interactive : ButtonStateEnum.Observation;
366  break;
367  }
368  case ButtonStateEnum.Targeted:
369  {
370  newState = visible ? ButtonStateEnum.Targeted : ButtonStateEnum.ObservationTargeted;
371  break;
372  }
373  case ButtonStateEnum.Observation:
374  {
375  newState = visible ? ButtonStateEnum.Interactive : ButtonStateEnum.Observation;
376  break;
377  }
378  case ButtonStateEnum.ObservationTargeted:
379  {
380  newState = visible ? ButtonStateEnum.Targeted : ButtonStateEnum.ObservationTargeted;
381  break;
382  }
383  case ButtonStateEnum.Pressed:
384  {
385  newState = visible ? ButtonStateEnum.Pressed : focused ? ButtonStateEnum.ObservationTargeted : ButtonStateEnum.Observation;
386  break;
387  }
388  }
389 
390  OnStateChange(newState);
391  }
392 
399  public virtual void OnStateChange(ButtonStateEnum newState)
400  {
401  ButtonState = newState;
402 
403  // Send out the action/event for the state change.
404  if (StateChange != null)
405  {
406  StateChange(newState);
407  }
408  }
409 
410  #endregion Button Functions
411 
412  #region Helper Functions
413 
417  public void TriggerClicked()
418  {
419  DoButtonPressed();
420 
421  StartCoroutine(DelayedRelease(0.2f));
422  }
423 
429  private IEnumerator DelayedRelease(float delay)
430  {
431  yield return new WaitForSeconds(delay);
432  DoButtonReleased();
433  DoButtonClicked();
434  }
435 
436  private void ResetButtonState()
437  {
438  if (!RequireGaze && ButtonState == ButtonStateEnum.Pressed)
439  {
440  // Pop from the modal stack as long as gaze is not required (if it is, we never pushed)
441  // and the button state is currently pressed (if it isn't, we never pushed).
442  InputManager.Instance.PopModalInputHandler();
443  }
444 
445  ButtonStateEnum newState;
446 
447  if (focused)
448  {
449  newState = handVisible ? ButtonStateEnum.Targeted : ButtonStateEnum.ObservationTargeted;
450  }
451  else
452  {
453  newState = handVisible ? ButtonStateEnum.Interactive : ButtonStateEnum.Observation;
454  }
455 
456  OnStateChange(newState);
457  }
458 
459  #endregion Helper Functions
460  }
461 }
void OnHoldStarted(HoldEventData eventData)
Handle OnHoldStarted events from IHoldHandler.
Definition: Button.cs:203
void OnHoldCanceled(HoldEventData eventData)
Handle on hold canceled events from IHoldHandler.
Definition: Button.cs:226
string _GizmoIcon
Protected string for the current active gizmo icon
Definition: Button.cs:95
ButtonStateEnum
State enum for buttons.
void OnInputUp(InputEventData eventData)
Handle on input up events from IInputHandler.
Definition: Button.cs:168
Action< GameObject > OnButtonHeld
Event fired when hold interaction initiated.
Definition: Button.cs:81
Input Manager is responsible for managing input sources and dispatching relevant events to the approp...
Definition: InputManager.cs:19
Interface to implement to react to per-pointer focus enter/exit.
void OnFocusExit(PointerSpecificEventData eventData)
Handle on focus exit events from IPointerSpecificFocusable.
Definition: Button.cs:257
void OnFocusEnter(PointerSpecificEventData eventData)
Handle on focus enter events from IPointerSpecificFocusable.
Definition: Button.cs:239
void OnInputDown(InputEventData eventData)
Handle on input down events from IInputHandler.
Definition: Button.cs:151
virtual void OnDisable()
Ensures the button returns to a neutral state when disabled
Definition: Button.cs:135
Action< ButtonStateEnum > StateChange
Event to receive button state change.
Definition: Button.cs:61
void DoButtonPressed()
Called when the button is pressed down.
Definition: Button.cs:290
Action< GameObject > OnButtonCanceled
Event fired when button interaction canceled.
Definition: Button.cs:86
virtual void OnHandVisibleChange(bool visible)
Event to fire off when hand/spatial input source visibility changes.
Definition: Button.cs:355
Action< GameObject > OnButtonReleased
Event fired when released interaction received.
Definition: Button.cs:71
void TriggerClicked()
Public function to force a clicked event on a button.
Definition: Button.cs:417
Event dispatched associated with a specific pointer.
void DoButtonReleased()
Called when the button is released.
Definition: Button.cs:309
Interface to implement to react to simple click input.
void OnInputClicked(InputClickedEventData eventData)
Handle clicked events from IInputClickHandler.
Definition: Button.cs:185
static T Instance
Returns the Singleton instance of the classes type. If no instance is found, then we search for an in...
Definition: Singleton.cs:26
Interface to implement to react to hold gestures.
Definition: IHoldHandler.cs:11
void OnHoldCompleted(HoldEventData eventData)
Handle on hold completed events from IHoldHandler.
Definition: Button.cs:217
void DoButtonCanceled()
Called when something interrupts the button pressed state.
Definition: Button.cs:341
InteractionSourcePressInfo PressType
Button type that initiated the event.
Action< GameObject > OnButtonClicked
Event fired when click interaction received.
Definition: Button.cs:76
Describes an input event that involves a tap.
Interface to implement to react to simple pointer-like input.
void DoButtonHeld()
Called once after the button is held down.
Definition: Button.cs:330
Action< GameObject > OnButtonPressed
Event fired when tap interaction received.
Definition: Button.cs:66
Event dispatched when a hold gesture is detected.
virtual void OnStateChange(ButtonStateEnum newState)
Callback virtual function for when the button state changes.
Definition: Button.cs:399
Describes an input event that has a source id and a press kind.