// Controller Tooltips|Prefabs|0070 namespace VRTK { using UnityEngine; /// /// Event Payload /// /// The tooltip element being affected. public struct ControllerTooltipsEventArgs { public VRTK_ControllerTooltips.TooltipButtons element; } /// /// Event Payload /// /// this object /// public delegate void ControllerTooltipsEventHandler(object sender, ControllerTooltipsEventArgs e); /// /// Adds a collection of Object Tooltips to the Controller providing information to what the controller buttons may do. /// /// /// **Prefab Usage:** /// * Place the `VRTK/Prefabs/ControllerTooltips/ControllerTooltips` prefab as a child of the relevant controller script alias GameObject in the scene hierarchy. /// * If no `Button Transform Settings` are provided in the inspector at Edit time then the button transforms will attempt to be set to the transforms of the current SDK default controller model. /// * If one of the `Button Text Settings` text options are not provided, then the tooltip for that specific button will be hidden. /// /// > There are a number of parameters that can be set on the Prefab which are provided by the `VRTK_ControllerTooltips` script which is applied to the prefab. /// /// /// `VRTK/Examples/029_Controller_Tooltips` displays two cubes that have an object tooltip added to them along with tooltips that have been added to the controllers. /// public class VRTK_ControllerTooltips : MonoBehaviour { public enum TooltipButtons { None, TriggerTooltip, GripTooltip, TouchpadTooltip, TouchpadTwoTooltip, ButtonOneTooltip, ButtonTwoTooltip, StartMenuTooltip } [Header("Button Text Settings")] [Tooltip("The text to display for the trigger button action.")] public string triggerText; [Tooltip("The text to display for the grip button action.")] public string gripText; [Tooltip("The text to display for the touchpad action.")] public string touchpadText; [Tooltip("The text to display for the touchpad two action.")] public string touchpadTwoText; [Tooltip("The text to display for button one action.")] public string buttonOneText; [Tooltip("The text to display for button two action.")] public string buttonTwoText; [Tooltip("The text to display for the start menu action.")] public string startMenuText; [Header("Tooltip Colour Settings")] [Tooltip("The colour to use for the tooltip background container.")] public Color tipBackgroundColor = Color.black; [Tooltip("The colour to use for the text within the tooltip.")] public Color tipTextColor = Color.white; [Tooltip("The colour to use for the line between the tooltip and the relevant controller button.")] public Color tipLineColor = Color.black; [Header("Button Transform Settings")] [Tooltip("The transform for the position of the trigger button on the controller.")] public Transform trigger; [Tooltip("The transform for the position of the grip button on the controller.")] public Transform grip; [Tooltip("The transform for the position of the touchpad button on the controller.")] public Transform touchpad; [Tooltip("The transform for the position of the touchpad two button on the controller.")] public Transform touchpadTwo; [Tooltip("The transform for the position of button one on the controller.")] public Transform buttonOne; [Tooltip("The transform for the position of button two on the controller.")] public Transform buttonTwo; [Tooltip("The transform for the position of the start menu on the controller.")] public Transform startMenu; [Header("Custom Settings")] [Tooltip("The controller to read the controller events from. If this is blank then it will attempt to get a controller events script from the same or parent GameObject.")] public VRTK_ControllerEvents controllerEvents; [Tooltip("The headset controller aware script to use to see if the headset is looking at the controller. If this is blank then it will attempt to get a controller events script from the same or parent GameObject.")] public VRTK_HeadsetControllerAware headsetControllerAware; [Tooltip("If this is checked then the tooltips will be hidden when the headset is not looking at the controller.")] public bool hideWhenNotInView = true; [Header("Obsolete Settings")] [System.Obsolete("`VRTK_ControllerTooltips.retryInitMaxTries` has been deprecated as tooltip initialisation now uses the `VRTK_TrackedController.ControllerModelAvailable` event.")] [ObsoleteInspector] public int retryInitMaxTries = 10; [System.Obsolete("`VRTK_ControllerTooltips.retryInitCounter` has been deprecated as tooltip initialisation now uses the `VRTK_TrackedController.ControllerModelAvailable` event.")] [ObsoleteInspector] public float retryInitCounter = 0.1f; /// /// Emitted when the controller tooltip is turned on. /// public event ControllerTooltipsEventHandler ControllerTooltipOn; /// /// Emitted when the controller tooltip is turned off. /// public event ControllerTooltipsEventHandler ControllerTooltipOff; protected TooltipButtons[] availableButtons = new TooltipButtons[0]; protected VRTK_ObjectTooltip[] buttonTooltips = new VRTK_ObjectTooltip[0]; protected bool[] tooltipStates = new bool[0]; protected bool overallState = true; protected VRTK_TrackedController trackedController; public virtual void OnControllerTooltipOn(ControllerTooltipsEventArgs e) { if (ControllerTooltipOn != null) { ControllerTooltipOn(this, e); } } public virtual void OnControllerTooltipOff(ControllerTooltipsEventArgs e) { if (ControllerTooltipOff != null) { ControllerTooltipOff(this, e); } } /// /// The Reset method reinitalises the tooltips on all of the controller elements. /// public virtual void ResetTooltip() { InitialiseTips(); } /// /// The UpdateText method allows the tooltip text on a specific controller element to be updated at runtime. /// /// The specific controller element to change the tooltip text on. /// A string containing the text to update the tooltip to display. public virtual void UpdateText(TooltipButtons element, string newText) { switch (element) { case TooltipButtons.ButtonOneTooltip: buttonOneText = newText; break; case TooltipButtons.ButtonTwoTooltip: buttonTwoText = newText; break; case TooltipButtons.StartMenuTooltip: startMenuText = newText; break; case TooltipButtons.GripTooltip: gripText = newText; break; case TooltipButtons.TouchpadTooltip: touchpadText = newText; break; case TooltipButtons.TouchpadTwoTooltip: touchpadTwoText = newText; break; case TooltipButtons.TriggerTooltip: triggerText = newText; break; } ResetTooltip(); } /// /// The ToggleTips method will display the controller tooltips if the state is `true` and will hide the controller tooltips if the state is `false`. An optional `element` can be passed to target a specific controller tooltip to toggle otherwise all tooltips are toggled. /// /// The state of whether to display or hide the controller tooltips, true will display and false will hide. /// The specific element to hide the tooltip on, if it is `TooltipButtons.None` then it will hide all tooltips. Optional parameter defaults to `TooltipButtons.None` public virtual void ToggleTips(bool state, TooltipButtons element = TooltipButtons.None) { if (element == TooltipButtons.None) { overallState = state; for (int i = 1; i < buttonTooltips.Length; i++) { if (buttonTooltips[i].displayText.Length > 0) { buttonTooltips[i].gameObject.SetActive(state); } } } else { if (buttonTooltips[(int)element].displayText.Length > 0) { buttonTooltips[(int)element].gameObject.SetActive(state); } } EmitEvent(state, element); } protected virtual void Awake() { VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this); InitButtonsArray(); } protected virtual void OnEnable() { controllerEvents = (controllerEvents != null ? controllerEvents : GetComponentInParent()); InitButtonsArray(); InitListeners(); ResetTooltip(); } protected virtual void OnDisable() { if (controllerEvents != null) { controllerEvents.ControllerEnabled -= DoControllerEnabled; controllerEvents.ControllerVisible -= DoControllerVisible; controllerEvents.ControllerHidden -= DoControllerInvisible; controllerEvents.ControllerModelAvailable -= DoControllerModelAvailable; } else if (trackedController != null) { trackedController.ControllerModelAvailable -= TrackedControllerDoControllerModelAvailable; } if (headsetControllerAware != null) { headsetControllerAware.ControllerGlanceEnter -= DoGlanceEnterController; headsetControllerAware.ControllerGlanceExit -= DoGlanceExitController; } } protected virtual void OnDestroy() { VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this); } protected virtual void EmitEvent(bool state, TooltipButtons element) { ControllerTooltipsEventArgs e; e.element = element; if (state) { OnControllerTooltipOn(e); } else { OnControllerTooltipOff(e); } } protected virtual void InitButtonsArray() { availableButtons = new TooltipButtons[] { TooltipButtons.None, TooltipButtons.TriggerTooltip, TooltipButtons.GripTooltip, TooltipButtons.TouchpadTooltip, TooltipButtons.TouchpadTwoTooltip, TooltipButtons.ButtonOneTooltip, TooltipButtons.ButtonTwoTooltip, TooltipButtons.StartMenuTooltip }; buttonTooltips = new VRTK_ObjectTooltip[availableButtons.Length]; tooltipStates = new bool[availableButtons.Length]; for (int i = 1; i < availableButtons.Length; i++) { buttonTooltips[i] = transform.Find(availableButtons[i].ToString()).GetComponent(); } } protected virtual void InitListeners() { if (controllerEvents != null) { controllerEvents.ControllerEnabled += DoControllerEnabled; controllerEvents.ControllerVisible += DoControllerVisible; controllerEvents.ControllerHidden += DoControllerInvisible; controllerEvents.ControllerModelAvailable += DoControllerModelAvailable; } else { trackedController = GetComponentInParent(); if (trackedController != null) { trackedController.ControllerModelAvailable += TrackedControllerDoControllerModelAvailable; } } headsetControllerAware = (headsetControllerAware != null ? headsetControllerAware : FindObjectOfType()); if (headsetControllerAware != null) { headsetControllerAware.ControllerGlanceEnter += DoGlanceEnterController; headsetControllerAware.ControllerGlanceExit += DoGlanceExitController; ToggleTips(false); } } protected virtual void DoControllerEnabled(object sender, ControllerInteractionEventArgs e) { if (controllerEvents != null) { GameObject actualController = VRTK_DeviceFinder.GetActualController(controllerEvents.gameObject); if (actualController != null && actualController.activeInHierarchy) { ResetTooltip(); } } } protected virtual void DoControllerVisible(object sender, ControllerInteractionEventArgs e) { for (int i = 0; i < availableButtons.Length; i++) { ToggleTips(tooltipStates[i], availableButtons[i]); } } protected virtual void DoControllerInvisible(object sender, ControllerInteractionEventArgs e) { for (int i = 1; i < buttonTooltips.Length; i++) { tooltipStates[i] = buttonTooltips[i].gameObject.activeSelf; } ToggleTips(false); } protected virtual void DoControllerModelAvailable(object sender, ControllerInteractionEventArgs e) { ResetTooltip(); } protected virtual void TrackedControllerDoControllerModelAvailable(object sender, VRTKTrackedControllerEventArgs e) { ResetTooltip(); } protected virtual void DoGlanceEnterController(object sender, HeadsetControllerAwareEventArgs e) { if (controllerEvents != null && hideWhenNotInView) { VRTK_ControllerReference checkControllerReference = VRTK_ControllerReference.GetControllerReference(controllerEvents.gameObject); if (checkControllerReference == e.controllerReference) { ToggleTips(true); } } } protected virtual void DoGlanceExitController(object sender, HeadsetControllerAwareEventArgs e) { if (controllerEvents != null && hideWhenNotInView) { VRTK_ControllerReference checkControllerReference = VRTK_ControllerReference.GetControllerReference(controllerEvents.gameObject); if (checkControllerReference == e.controllerReference) { ToggleTips(false); } } } protected virtual void InitialiseTips() { VRTK_ObjectTooltip[] tooltips = GetComponentsInChildren(true); for (int i = 0; i < tooltips.Length; i++) { VRTK_ObjectTooltip tooltip = tooltips[i]; string tipText = ""; Transform tipTransform = null; switch (tooltip.name.Replace("Tooltip", "").ToLower()) { case "trigger": tipText = triggerText; tipTransform = GetTransform(trigger, SDK_BaseController.ControllerElements.Trigger); break; case "grip": tipText = gripText; tipTransform = GetTransform(grip, SDK_BaseController.ControllerElements.GripLeft); break; case "touchpad": tipText = touchpadText; tipTransform = GetTransform(touchpad, SDK_BaseController.ControllerElements.Touchpad); break; case "touchpadtwo": tipText = touchpadTwoText; tipTransform = GetTransform(touchpadTwo, SDK_BaseController.ControllerElements.TouchpadTwo); break; case "buttonone": tipText = buttonOneText; tipTransform = GetTransform(buttonOne, SDK_BaseController.ControllerElements.ButtonOne); break; case "buttontwo": tipText = buttonTwoText; tipTransform = GetTransform(buttonTwo, SDK_BaseController.ControllerElements.ButtonTwo); break; case "startmenu": tipText = startMenuText; tipTransform = GetTransform(startMenu, SDK_BaseController.ControllerElements.StartMenu); break; } tooltip.displayText = tipText; tooltip.drawLineTo = tipTransform; tooltip.containerColor = tipBackgroundColor; tooltip.fontColor = tipTextColor; tooltip.lineColor = tipLineColor; tooltip.ResetTooltip(); if (tipTransform == null || tipText.Trim().Length == 0) { tooltip.gameObject.SetActive(false); } } if (headsetControllerAware == null || !hideWhenNotInView) { ToggleTips(overallState); } } protected virtual Transform GetTransform(Transform setTransform, SDK_BaseController.ControllerElements findElement) { Transform returnTransform = null; if (setTransform != null) { returnTransform = setTransform; } else if (controllerEvents != null) { GameObject modelController = VRTK_DeviceFinder.GetModelAliasController(controllerEvents.gameObject); if (modelController != null && modelController.activeInHierarchy) { SDK_BaseController.ControllerHand controllerHand = VRTK_DeviceFinder.GetControllerHand(controllerEvents.gameObject); string elementPath = VRTK_SDK_Bridge.GetControllerElementPath(findElement, controllerHand, true); returnTransform = (elementPath != null ? modelController.transform.Find(elementPath) : null); } } return returnTransform; } } }