Files
BABA_YAGA/Packages/app.rive.rive-unity/Runtime/Components/InputProviders/CanvasPanelInputProvider.cs
2026-05-19 17:39:03 +07:00

159 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using Rive.Utils;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Rive.Components
{
/// <summary>
/// Provides input to a RiveCanvasRenderer and the RivePanel it displays.
/// </summary>
internal class CanvasPanelInputProvider : MonoBehaviour, IPanelInputProvider, ICanvasRaycastFilter, IPointerDownHandler, IPointerUpHandler, IPointerMoveHandler, IPointerExitHandler, IPointerEnterHandler
{
[HideInInspector]
[SerializeField] private RiveCanvasRenderer m_riveCanvasRenderer;
private List<IRiveWidget> m_RaycastResults = new List<IRiveWidget>();
private IRivePanel RivePanel
{
get
{
if (m_riveCanvasRenderer == null)
{
return null;
}
return m_riveCanvasRenderer.RivePanel;
}
}
public event Action<PanelPointerEvent> PointerPressed;
public event Action<PanelPointerEvent> PointerReleased;
public event Action<PanelPointerEvent> PointerMoved;
public event Action<PanelPointerEvent> PointerExited;
public event Action<PanelPointerEvent> PointerEntered;
void OnValidate()
{
FetchPanelRendererIfNeeded();
}
private void OnEnable()
{
FetchPanelRendererIfNeeded();
if (m_riveCanvasRenderer == null)
{
DebugLogger.Instance.LogWarning($"No {nameof(RiveCanvasRenderer)} component found on the GameObject - {gameObject.name}");
}
}
private void FetchPanelRendererIfNeeded()
{
if (m_riveCanvasRenderer == null || !ReferenceEquals(m_riveCanvasRenderer.gameObject, this.gameObject))
{
m_riveCanvasRenderer = GetComponent<RiveCanvasRenderer>();
}
}
private static bool TryGetScreenPointToNormalizedLocalPointInFrame(RectTransform rectTransform, Vector2 screenPoint, Camera eventCamera, out Vector2 normalizedLocalPointInFrame)
{
normalizedLocalPointInFrame = Vector2.zero;
if (rectTransform == null)
{
return false;
}
Vector2 localPoint;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out localPoint))
{
return false;
}
normalizedLocalPointInFrame = Rect.PointToNormalized(rectTransform.rect, localPoint);
return true;
}
// When used in a canvas, we don't want the panel raycast target to block raycasts if there are no widgets to hit so we filter out the raycasts in this case.
// This allows the raycasts to pass through to regular canvas raycast targets outside of the panel.
public bool IsRaycastLocationValid(Vector2 screenPosition, Camera eventCamera)
{
if (RivePanel == null || m_riveCanvasRenderer.PointerInputMode == PointerInputMode.DisablePointerInput)
{
return false;
}
m_RaycastResults.Clear();
Vector2 localNormalizedPointInPanel;
if (!TryGetScreenPointToNormalizedLocalPointInFrame(m_riveCanvasRenderer.RectTransform, screenPosition, eventCamera, out localNormalizedPointInPanel))
{
return false;
}
PanelRaycaster.RaycastAll(RivePanel, localNormalizedPointInPanel, m_RaycastResults);
bool locationIsValid = m_RaycastResults.Count > 0;
return locationIsValid;
}
private void ProcessPointerEvent(PointerEventData eventData, Action<PanelPointerEvent> pointerHandler)
{
if (pointerHandler == null)
{
return;
}
if (RivePanel == null || m_riveCanvasRenderer.PointerInputMode == PointerInputMode.DisablePointerInput || !RivePanel.Enabled)
{
return;
}
Vector2 canvasNormalizedPoint;
if (!TryGetScreenPointToNormalizedLocalPointInFrame(m_riveCanvasRenderer.RectTransform, eventData.position, eventData.enterEventCamera, out canvasNormalizedPoint))
{
return;
}
int pointerId = eventData.pointerId;
pointerHandler(new PanelPointerEvent(canvasNormalizedPoint, pointerId));
}
public void OnPointerDown(PointerEventData eventData)
{
ProcessPointerEvent(eventData, PointerPressed);
}
public void OnPointerUp(PointerEventData eventData)
{
ProcessPointerEvent(eventData, PointerReleased);
}
public void OnPointerMove(PointerEventData eventData)
{
ProcessPointerEvent(eventData, PointerMoved);
}
public void OnPointerExit(PointerEventData eventData)
{
ProcessPointerEvent(eventData, PointerExited);
}
public void OnPointerEnter(PointerEventData eventData)
{
ProcessPointerEvent(eventData, PointerEntered);
}
}
}