Files
dungeons/Assets/UltimateXR/Runtime/Scripts/UI/UnityInputModule/Utils/UxrHoverTimerClick.cs
2024-08-06 21:58:35 +02:00

155 lines
5.7 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHoverTimerClick.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UltimateXR.Core.Components;
using UltimateXR.Core.Settings;
using UltimateXR.UI.UnityInputModule.Controls;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace UltimateXR.UI.UnityInputModule.Utils
{
/// <summary>
/// Component that, added to a <see cref="GameObject" /> with a <see cref="UxrControlInput" /> component, will
/// automatically generate a Click event on the control whenever the cursor spends a given amount of time over it.
/// It can be used to implement clicks using the gaze pointer (<see cref="UxrCameraPointer" />).
/// </summary>
[RequireComponent(typeof(UxrControlInput))]
public class UxrHoverTimerClick : UxrComponent
{
#region Inspector Properties/Serialized Fields
[SerializeField] [Tooltip("Number of seconds the user will need to hover over this element to trigger the Click event")] private float _lookAtSecondsToClick = 2.0f;
[SerializeField] [Tooltip("Unscaled time will use the real device timer. If this parameter is unchecked it will use the scaled timer affected by pauses, bullet-times etc.")] private bool _useUnscaledTime = true;
[SerializeField] [Tooltip("Will update the fill value of the Image component on this same GameObject to represent the timer progress. Needs an Image component.")] private bool _useFillImage = true;
#endregion
#region Unity
/// <summary>
/// Initializes the component.
/// </summary>
protected override void Awake()
{
base.Awake();
_image = GetComponent<Image>();
_controlInput = GetComponent<UxrControlInput>();
_timer = _lookAtSecondsToClick;
if (_useFillImage && _image == null)
{
if (UxrGlobalSettings.Instance.LogLevelUI >= UxrLogLevel.Warnings)
{
Debug.LogWarning($"{UxrConstants.UiModule} UseFillImage was specified on {GetType().Name} component of GameObject {name} but there is no Image component on it to update fill.");
}
}
else if (_useFillImage && _image != null && _image.type != Image.Type.Filled)
{
if (UxrGlobalSettings.Instance.LogLevelUI >= UxrLogLevel.Warnings)
{
Debug.LogWarning($"{UxrConstants.UiModule} UseFillImage was specified on {GetType().Name} component of GameObject {name} but the Image component is not of a filled type (Image Type property).");
}
}
}
/// <summary>
/// Subscribes to events.
/// </summary>
protected override void OnEnable()
{
base.OnEnable();
_controlInput.CursorEntered += Input_Entered;
_controlInput.CursorExited += Input_Exited;
}
/// <summary>
/// Unsubscribes from events.
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
_controlInput.CursorEntered -= Input_Entered;
_controlInput.CursorExited -= Input_Exited;
}
/// <summary>
/// Updates the progress and checks whether to generate the Click event.
/// </summary>
private void Update()
{
if (_timer > 0.0f)
{
_timer -= _useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
if (_timer <= 0.0f)
{
_timer = -1.0f;
if (_useFillImage && _image)
{
_image.fillAmount = 1.0f;
}
ExecuteEvents.ExecuteHierarchy(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
}
else
{
if (_useFillImage && _image)
{
_image.fillAmount = Mathf.Clamp01(1.0f - _timer / _lookAtSecondsToClick);
}
}
}
else
{
if (_useFillImage && _image)
{
_image.fillAmount = 0.0f;
}
}
}
#endregion
#region Event Handling Methods
/// <summary>
/// Called whenever the pointer entered the control's Rect.
/// </summary>
/// <param name="controlInput">Control input</param>
/// <param name="eventData">Event data</param>
private void Input_Entered(UxrControlInput controlInput, PointerEventData eventData)
{
_timer = _lookAtSecondsToClick;
}
/// <summary>
/// Called whenever the pointer exited the control's Rect.
/// </summary>
/// <param name="controlInput">Control input</param>
/// <param name="eventData">Event data</param>
private void Input_Exited(UxrControlInput controlInput, PointerEventData eventData)
{
_timer = -1.0f;
}
#endregion
#region Private Types & Data
private Image _image;
private UxrControlInput _controlInput;
private float _timer;
#endregion
}
}