// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
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
{
///
/// Component that, added to a with a 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 ().
///
[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
///
/// Initializes the component.
///
protected override void Awake()
{
base.Awake();
_image = GetComponent();
_controlInput = GetComponent();
_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).");
}
}
}
///
/// Subscribes to events.
///
protected override void OnEnable()
{
base.OnEnable();
_controlInput.CursorEntered += Input_Entered;
_controlInput.CursorExited += Input_Exited;
}
///
/// Unsubscribes from events.
///
protected override void OnDisable()
{
base.OnDisable();
_controlInput.CursorEntered -= Input_Entered;
_controlInput.CursorExited -= Input_Exited;
}
///
/// Updates the progress and checks whether to generate the Click event.
///
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
///
/// Called whenever the pointer entered the control's Rect.
///
/// Control input
/// Event data
private void Input_Entered(UxrControlInput controlInput, PointerEventData eventData)
{
_timer = _lookAtSecondsToClick;
}
///
/// Called whenever the pointer exited the control's Rect.
///
/// Control input
/// Event data
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
}
}