This commit is contained in:
2026-05-19 17:39:03 +07:00
parent bf0ebe447d
commit 5da832bb57
559 changed files with 69543 additions and 1 deletions

View File

@@ -0,0 +1,20 @@
namespace Rive.Components
{
/// <summary>
/// Controls how often a widget requests a redraw from its panel.
/// </summary>
public enum DrawOptimizationOptions
{
/// <summary>
/// The widget will request a redraw every frame.
/// </summary>
AlwaysDraw = 0,
/// <summary>
/// The widget will only request redraws when its underlying content changes.
/// </summary>
DrawWhenChanged = 1
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 115f6f09fa46e48ebb2d1054898802b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/DrawOptimizationOptions.cs
uploadId: 896810

View File

@@ -0,0 +1,93 @@
using UnityEngine;
namespace Rive.Components
{
/// <summary>
/// Interface for widgets that can be rendered by a Rive Panel.
/// </summary>
public interface IRiveWidget
{
/// <summary>
/// This holds information about the object that will be rendered by the Rive renderer.
/// </summary>
IRenderObject RenderObject { get; }
/// <summary>
/// The RectTransform of the widget.
/// </summary>
public RectTransform RectTransform { get; }
/// <summary>
/// Whether the widget is enabled and its GameObject is active in the hierarchy.
/// </summary>
bool Enabled { get; }
/// <summary>
/// The hit test behavior of the widget.
/// </summary>
HitTestBehavior HitTestBehavior { get; set; }
/// <summary>
/// This controls the RiveWidget's update loop.
/// </summary>
/// <param name="deltaTime"> The time since the last frame.</param>
/// <returns>Returns <c>true</c> if the widget needs to be redrawn as a result of this tick; otherwise, <c>false</c>.</returns>
bool Tick(float deltaTime);
/// <summary>
/// Tests if a given local position within the widget's rectangle hits any interactive elements.
/// </summary>
/// <param name="normalizedPointInRect">
/// The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.
/// </param>
/// <returns>
/// Returns <c>true</c> if the position hits an interactive element; otherwise, <c>false</c>.
/// </returns>
bool HitTest(Vector2 normalizedPointInRect);
/// <summary>
/// Called when a pointer is pressed on the widget.
/// </summary>
/// <param name="normalizedPointInRect">The normalized point of the pointer press in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns>Returns <c>true</c> if the pointer press hits an interactive element; otherwise, <c>false</c>.</returns>
bool OnPointerDown(Vector2 normalizedPointInRect, int pointerId);
/// <summary>
/// Called when a pointer is moved on the widget.
/// </summary>
/// <param name="normalizedPointInRect">The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns>Returns <c>true</c> if the pointer move hits an interactive element; otherwise, <c>false</c>.</returns>
bool OnPointerMove(Vector2 normalizedPointInRect, int pointerId);
/// <summary>
/// Called when a pointer is released on the widget.
/// </summary>
/// <param name="normalizedPointInRect">The normalized point of the pointer release in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns>Returns <c>true</c> if the pointer release hits an interactive element; otherwise, <c>false</c>.</returns>
bool OnPointerUp(Vector2 normalizedPointInRect, int pointerId);
/// <summary>
/// Called when a pointer exits the widget.
/// </summary>
/// <param name="normalizedPointInRect"> The normalized point of the pointer exit in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns> Returns <c>true</c> if the pointer exit hits an interactive element; otherwise, <c>false</c>.</returns>
bool OnPointerExit(Vector2 normalizedPointInRect, int pointerId);
/// <summary>
/// Called when a pointer enters the widget.
/// </summary>
/// <param name="normalizedPointInRect"> The normalized point of the pointer enter in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns> Returns <c>true</c> if the pointer enter hits an interactive element; otherwise, <c>false</c>.</returns>
bool OnPointerEnter(Vector2 normalizedPointInRect, int pointerId);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: daa9d85f269554d7c9749157f1ed0493
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/IRiveWidget.cs
uploadId: 896810

View File

@@ -0,0 +1,138 @@
using Rive.Utils;
using UnityEngine;
namespace Rive.Components
{
/// <summary>
/// Renders a ProceduralDrawing within a RivePanel.
/// </summary>
[AddComponentMenu("Rive/Procedural Rive Widget")]
public sealed class ProceduralRiveWidget : WidgetBehaviour
{
[SerializeField] private ProceduralDrawing m_proceduralDrawing;
[Tooltip("The hit test behavior for the widget.")]
[SerializeField] private HitTestBehavior m_hitTestBehavior = HitTestBehavior.None;
private ProceduralRenderObject m_renderObject;
public override IRenderObject RenderObject => m_renderObject;
public ProceduralDrawing ProceduralDrawing => m_proceduralDrawing;
public override HitTestBehavior HitTestBehavior { get => m_hitTestBehavior; set => m_hitTestBehavior = value; }
void Start()
{
if (m_proceduralDrawing == null)
{
return;
}
Load(m_proceduralDrawing);
}
public override bool Tick(float deltaTime)
{
bool needsRedraw = base.Tick(deltaTime);
if (m_proceduralDrawing == null)
{
return needsRedraw;
}
if (m_proceduralDrawing.Advance(deltaTime))
{
needsRedraw = true;
}
return needsRedraw;
}
public void Load(ProceduralDrawing proceduralDrawing)
{
if (proceduralDrawing == null)
{
DebugLogger.Instance.LogError("Can't load null procedural drawing.");
return;
}
Status = WidgetStatus.Loading;
m_proceduralDrawing = proceduralDrawing;
try
{
m_renderObject = new ProceduralRenderObject(m_proceduralDrawing);
}
catch (System.Exception e)
{
DebugLogger.Instance.LogError($"Error loading procedural drawing: {e.Message}");
Status = WidgetStatus.Error;
return;
}
HandleLoadComplete();
}
public override bool HitTest(Vector2 normalizedPointInRect)
{
if (m_proceduralDrawing == null)
{
return base.HitTest(normalizedPointInRect);
}
return m_proceduralDrawing.HitTest(normalizedPointInRect, RectTransform.rect);
}
public override bool OnPointerDown(Vector2 normalizedPointInRect, int pointerId)
{
base.OnPointerDown(normalizedPointInRect, pointerId);
if (m_proceduralDrawing == null)
{
return false;
}
return m_proceduralDrawing.HandlePointerDown(normalizedPointInRect, RectTransform.rect);
}
public override bool OnPointerMove(Vector2 normalizedPointInRect, int pointerId)
{
base.OnPointerMove(normalizedPointInRect, pointerId);
if (m_proceduralDrawing == null)
{
return false;
}
return m_proceduralDrawing.HandlePointerMove(normalizedPointInRect, RectTransform.rect);
}
public override bool OnPointerUp(Vector2 normalizedPointInRect, int pointerId)
{
base.OnPointerUp(normalizedPointInRect, pointerId);
if (m_proceduralDrawing == null)
{
return false;
}
return m_proceduralDrawing.HandlePointerUp(normalizedPointInRect, RectTransform.rect);
}
public override bool OnPointerExit(Vector2 normalizedPointInRect, int pointerId)
{
base.OnPointerExit(normalizedPointInRect, pointerId);
if (m_proceduralDrawing == null)
{
return false;
}
return m_proceduralDrawing.HandlePointerExit(normalizedPointInRect, RectTransform.rect);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 9cd9a3f8258f648a1baa648cb5116f43
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/ProceduralRiveWidget.cs
uploadId: 896810

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 30b5bc34e03734ee49f044caba90a384
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/RiveWidget.cs
uploadId: 896810

View File

@@ -0,0 +1,405 @@
using System;
using Rive.EditorTools;
using Rive.Utils;
using UnityEngine;
using UnityEngine.Events;
namespace Rive.Components
{
/// <summary>
/// Base class for creating custom RiveWidgets for different contexts.
/// </summary>
[DisallowMultipleComponent]
[InspectorSection(InspectorSections.Advanced, "Advanced", order: 1, style: SectionStyle.Foldout)]
[RequireComponent(typeof(RectTransform))]
public abstract class WidgetBehaviour : MonoBehaviour, IRiveWidget
{
protected static class InspectorSections
{
public const string Advanced = "advanced";
}
[HideInInspector]
[SerializeField] private RivePanel m_rivePanel;
private WidgetStatus m_status = WidgetStatus.Uninitialized;
private int m_cachedSiblingIndex;
private bool m_shouldTriggerRedraw = false;
public abstract IRenderObject RenderObject { get; }
/// <summary>
/// The current loading status of the widget.
/// </summary>
public WidgetStatus Status
{
get => m_status; protected set
{
if (m_status == value)
{
return;
}
m_status = value;
OnWidgetStatusChanged?.Invoke();
}
}
public bool Enabled => this != null && this.enabled && this.gameObject != null && this.gameObject.activeInHierarchy;
// These events are used to notify the RivePanel that the widget's sorting might need to be updated.
public event Action OnSiblingIndexChanged;
public event Action OnParentChanged;
public RivePanel RivePanel
{
get => m_rivePanel; private set
{
if (ReferenceEquals(m_rivePanel, value))
{
return;
}
if (m_rivePanel != null)
{
UnsubscribeFromPanelEvents(m_rivePanel);
}
m_rivePanel = value;
if (m_rivePanel != null)
{
SubscribeToPanelEvents(m_rivePanel);
}
}
}
public RectTransform RectTransform => this.transform as RectTransform;
public abstract HitTestBehavior HitTestBehavior { get; set; }
public event Action OnWidgetStatusChanged;
protected virtual void OnEnable()
{
if (RivePanel == null || !IsDescendantOfPanel(RivePanel))
{
RivePanel = GetComponentInParent<RivePanel>();
}
m_cachedSiblingIndex = this.transform.GetSiblingIndex();
UpdateRenderTransform();
if (RivePanel != null)
{
RivePanel.RegisterWidgetForRendering(this);
}
}
protected virtual void OnDisable()
{
if (m_rivePanel != null)
{
m_rivePanel.UnregisterWidgetFromRendering(this);
}
}
private void SubscribeToPanelEvents(RivePanel panel)
{
if (panel == null)
{
return;
}
panel.OnWidgetRemoved += HandleWidgetRemoved;
}
private void UnsubscribeFromPanelEvents(RivePanel panel)
{
if (panel == null)
{
return;
}
panel.OnWidgetRemoved -= HandleWidgetRemoved;
}
/// <summary>
/// This is called after the RiveWidget has finished loading but before the OnLoad event is triggered. Use this to perform any additional setup after the RiveWidget has loaded.
/// </summary>
protected virtual void HandleLoadComplete()
{
// Do this to account for any changes in the RectTransform that may have occurred before the RiveWidget was loaded.
UpdateRenderTransform();
TriggerRedrawNeededEvent();
Status = WidgetStatus.Loaded;
}
/// <summary>
/// Called when the RectTransform dimensions change. We resize the RenderTexture to match the new dimensions.
/// </summary>
protected virtual void OnRectTransformDimensionsChange()
{
if (m_rivePanel == null || !this.gameObject.activeInHierarchy)
{
return;
}
if (RenderObject == null)
{
return;
}
// Make sure we update the rect in the RenderObject as that is what is used to calculate the dimensions.
UpdateRenderTransform();
TriggerRedrawNeededEvent();
}
protected void TriggerRedrawNeededEvent()
{
m_shouldTriggerRedraw = true;
}
private void HandleWidgetRemoved(IRiveWidget widget)
{
if (!ReferenceEquals(widget, this))
{
return;
}
if (RivePanel != null && !RivePanel.ContainsWidget(this))
{
RivePanel = null;
}
}
private void UpdateRenderTransform()
{
if (RenderObject == null)
{
return;
}
RectTransform panelRectTransform = RivePanel != null ? RivePanel.WidgetContainer : null;
if (panelRectTransform == null)
{
return;
}
RenderObject.RenderTransform = RenderTransform.FromRectTransform(RectTransform, panelRectTransform);
}
public virtual bool Tick(float deltaTime)
{
bool needsRedraw = false;
if (Status != WidgetStatus.Loaded)
{
return needsRedraw;
}
if (RectTransform.hasChanged)
{
RectTransform.hasChanged = false;
UpdateRenderTransform();
OnRectTransformDimensionsChange();
needsRedraw = true;
}
int currentSiblingIndex = this.transform.GetSiblingIndex();
if (currentSiblingIndex != m_cachedSiblingIndex)
{
m_cachedSiblingIndex = currentSiblingIndex;
OnSiblingIndexChanged?.Invoke();
needsRedraw = true;
}
if (m_shouldTriggerRedraw)
{
m_shouldTriggerRedraw = false;
needsRedraw = true;
}
return needsRedraw;
}
/// <summary>
/// This is called when a direct or indirect parent of the transform of the GameObject has changed.
/// </summary>
protected virtual void OnTransformParentChanged()
{
var currentParentPanel = GetComponentInParent<RivePanel>();
// Unregister from the old panel if the widget is not a child of it anymore
// or if the widget is a child of a different panel now.
if (RivePanel != null && !ReferenceEquals(currentParentPanel, RivePanel))
{
RivePanel.UnregisterWidgetFromRendering(this);
}
// Register with the new panel if there is one
if (currentParentPanel != null && !currentParentPanel.ContainsWidget(this))
{
currentParentPanel.RegisterWidgetForRendering(this);
RivePanel = currentParentPanel;
}
OnParentChanged?.Invoke();
}
/// <summary>
/// Tests if a given local position within the widget's rectangle hits any interactive elements.
/// </summary>
/// <param name="normalizedPointInRect">
/// The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.
/// </param>
/// <returns>
/// Returns <c>true</c> if the position hits an interactive element; otherwise, <c>false</c>.
/// </returns>
public virtual bool HitTest(Vector2 normalizedPointInRect)
{
return false;
}
/// <summary>
/// Called when a pointer is pressed on the widget.
/// </summary>
/// <param name="normalizedPointInRect">The normalized point of the pointer press in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns>Returns <c>true</c> if the pointer press hits an interactive element; otherwise, <c>false</c>.</returns>
public virtual bool OnPointerDown(Vector2 normalizedPointInRect, int pointerId)
{
return false;
}
/// <summary>
/// Called when a pointer is released on the widget.
/// </summary>
/// <param name="normalizedPointInRect">The normalized point of the pointer release in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns>Returns <c>true</c> if the pointer release hits an interactive element; otherwise, <c>false</c>.</returns>
public virtual bool OnPointerUp(Vector2 normalizedPointInRect, int pointerId)
{
return false;
}
/// <summary>
/// Called when a pointer is moved on the widget.
/// </summary>
/// <param name="normalizedPointInRect">The normalized point of the pointer position in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns>Returns <c>true</c> if the pointer move hits an interactive element; otherwise, <c>false</c>.</returns>
public virtual bool OnPointerMove(Vector2 normalizedPointInRect, int pointerId)
{
return false;
}
/// <summary>
/// Called when a pointer exits the widget.
/// </summary>
/// <param name="normalizedPointInRect"> The normalized point of the pointer exit in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns> Returns <c>true</c> if the pointer exit hits an interactive element; otherwise, <c>false</c>.</returns>
public virtual bool OnPointerExit(Vector2 normalizedPointInRect, int pointerId)
{
return false;
}
/// <summary>
/// Called when a pointer enters the widget.
/// </summary>
/// <param name="normalizedPointInRect">The normalized point of the pointer enter in the widget's rectangle. The coordinates are in the range [0,1] where (0,0) is the bottom-left corner and (1,1) is the top-right corner.</param>
/// <param name="pointerId">The unique id for the active pointer/touch.</param>
/// <returns> Returns <c>true</c> if the pointer enter hits an interactive element; otherwise, <c>false</c>.</returns>
public virtual bool OnPointerEnter(Vector2 normalizedPointInRect, int pointerId)
{
return false;
}
protected virtual void OnDestroy()
{
}
private bool IsDescendantOfPanel(RivePanel rivePanel)
{
if (rivePanel == null)
{
return false;
}
return this.transform.IsChildOf(rivePanel.WidgetContainer);
}
#if UNITY_EDITOR
protected virtual void OnValidate()
{
if (RivePanel == null || !IsDescendantOfPanel(RivePanel))
{
RivePanel = GetComponentInParent<RivePanel>();
}
}
#endif
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 856e0d19fa5914d6e9fc470ba4d5c2a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetBehaviour.cs
uploadId: 896810

View File

@@ -0,0 +1,32 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Rive.Components
{
/// <summary>
/// Represents the current status of a Rive widget.
/// </summary>
public enum WidgetStatus
{
/// <summary>
/// The widget has not yet been initialized. This is the default state.
/// </summary>
Uninitialized = 0,
/// <summary>
/// The widget is currently setting up the Rive graphic.
/// </summary>
Loading = 1,
/// <summary>
/// The widget is ready to display the Rive graphic.
/// </summary>
Loaded = 2,
/// <summary>
/// An error occurred while loading the Rive graphic.
/// </summary>
Error = 3
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c6ff4924453f8439e9ecdf2548668cfb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 350858
packageName: Rive
packageVersion: 0.4.2
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/Widgets/WidgetStatus.cs
uploadId: 896810