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

571 lines
19 KiB
C#

using UnityEngine;
using System;
using System.Runtime.InteropServices;
using Rive.Utils;
namespace Rive
{
/// <summary>
/// Represents a Rive Artboard with a File. An Artboard contains StateMachines and Animations.
/// </summary>
public class Artboard : IDisposable
{
private readonly IntPtr m_nativeArtboard;
private string m_artboardName;
private ViewModelInstance m_currentViewModelInstance;
private ViewModel m_defaultViewModel;
private WeakReference<File> m_file;
private bool m_isDisposed = false;
internal IntPtr NativeArtboard
{
get { return m_nativeArtboard; }
}
/// <summary>
/// Returns true if the artboard has been disposed.
/// </summary>
public bool IsDisposed { get => m_isDisposed; }
/// <summary>
/// Constructor for the Artboard class.
/// </summary>
/// <param name="nativeArtboard"> Pointer to the native artboard.</param>
/// <param name="file"> The file that instanced the artboard.</param>
internal Artboard(IntPtr nativeArtboard, File file)
{
m_nativeArtboard = nativeArtboard;
m_file = new WeakReference<File>(file);
}
/// <summary>
/// Dispose of the Artboard and release native resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!m_isDisposed)
{
if (m_nativeArtboard != IntPtr.Zero)
{
unrefArtboard(m_nativeArtboard);
}
m_isDisposed = true;
}
}
~Artboard()
{
Dispose(false);
}
public Vector2 LocalCoordinate(
Vector2 screenPosition,
Rect screen,
Fit fit,
Alignment alignment
)
{
Vec2D vec = screenToRive(
screenPosition.x,
screenPosition.y,
screen.xMin,
screen.yMin,
screen.xMax,
screen.yMax,
(byte)fit,
alignment.X,
alignment.Y,
m_nativeArtboard
);
return new Vector2(vec.x, vec.y);
}
[Obsolete("Component is deprecated and will be removed in a future release. Please use Databinding instead.")]
public Component Component(string name)
{
var ptr = artboardComponentNamed(m_nativeArtboard, name);
if (ptr == IntPtr.Zero)
{
return null;
}
return new Component(ptr);
}
public string Name
{
get
{
if (m_artboardName == null)
{
m_artboardName = Marshal.PtrToStringAnsi(artboardGetName(m_nativeArtboard));
}
return m_artboardName;
}
}
/// <summary>
/// Returns true if the artboard has audio.
/// </summary>
public bool HasAudio
{
get
{
return artboardHasAudio(m_nativeArtboard);
}
}
/// <summary>
/// Sets the value of a text run with the provided name.
/// </summary>
/// <param name="name">The name of the text run.</param>
/// <param name="value"> The new value for the text run.</param>
/// <returns></returns>
public bool SetTextRun(string name, string value)
{
return artboardSetRunValue(m_nativeArtboard, name, value);
}
/// <summary>
/// Gets the value of a text run with the provided name.
/// </summary>
/// <param name="runName">The name of the text run.</param>
/// <returns>The value of the text run, or null if not found.</returns>
public string GetTextRunValue(string runName)
{
return Marshal.PtrToStringAnsi(artboardGetTextRunValue(m_nativeArtboard, runName));
}
/// <summary>
/// Sets the value of a text run with the provided name at the given path.
/// </summary>
/// <param name="runName">The name of the text run.</param>
/// <param name="path">The path to the nested artboard where the text run is located.</param>
/// <param name="value">The new value for the text run.</param>
/// <returns>True if the text run was successfully set, false otherwise.</returns>
public bool SetTextRunValueAtPath(string runName, string path, string value)
{
return artboardSetTextRunValueAtPath(m_nativeArtboard, runName, path, value);
}
/// <summary>
/// Gets the value of a text run with the provided name at the given path.
/// </summary>
/// <param name="runName">The name of the text run.</param>
/// <param name="path">The path to the nested artboard where the text run is located.</param>
/// <returns>The value of the text run, or null if not found.</returns>
public string GetTextRunValueAtPath(string runName, string path)
{
return Marshal.PtrToStringAnsi(artboardGetTextRunValueAtPath(m_nativeArtboard, runName, path));
}
/// <summary>
/// Gets or sets the width of the artboard instance.
/// </summary>
public float Width
{
get => getArtboardWidth(m_nativeArtboard);
set => setArtboardWidth(m_nativeArtboard, value);
}
/// <summary>
/// Gets or sets the height of the artboard instance.
/// </summary>
public float Height
{
get => getArtboardHeight(m_nativeArtboard);
set => setArtboardHeight(m_nativeArtboard, value);
}
/// <summary>
/// Returns true if the artboard has changed since the last draw.
/// </summary>
public bool DidChange()
{
return artboardDidChange(m_nativeArtboard);
}
/// Returns the number of StateMachines stored in the artboard.
public uint StateMachineCount
{
get { return getStateMachineCount(m_nativeArtboard); }
}
/// <summary>
/// The default ViewModel for the artboard.
/// </summary>
public ViewModel DefaultViewModel
{
get
{
if (m_defaultViewModel == null)
{
var file = m_file.TryGetTarget(out var target) ? target : null;
if (file != null)
{
m_defaultViewModel = file.GetDefaultViewModelForArtboard(this.m_nativeArtboard);
}
}
return m_defaultViewModel;
}
}
/// Returns the name of the StateMachine at the given index.
public string StateMachineName(uint index)
{
return Marshal.PtrToStringAnsi(getStateMachineName(m_nativeArtboard, index));
}
/// Instance a StateMachine from the Artboard.
public StateMachine StateMachine(uint index)
{
IntPtr ptr = instanceStateMachineAtIndex(m_nativeArtboard, index);
if (ptr == IntPtr.Zero)
{
DebugLogger.Instance.Log($"No StateMachine at index {index}.");
return null;
}
return new StateMachine(ptr);
}
/// Instance a StateMachine from the Artboard.
public StateMachine StateMachine(string name)
{
IntPtr ptr = instanceStateMachineWithName(m_nativeArtboard, name);
if (ptr == IntPtr.Zero)
{
DebugLogger.Instance.Log($"No StateMachine named \"{name}\".");
return null;
}
return new StateMachine(ptr);
}
/// Instance the default StateMachine from the Artboard.
public StateMachine StateMachine()
{
IntPtr ptr = instanceStateMachineDefault(m_nativeArtboard);
if (ptr == IntPtr.Zero)
{
DebugLogger.Instance.Log($"No default StateMachine found.");
return null;
}
return new StateMachine(ptr);
}
public void SetAudioEngine(AudioEngine audioEngine)
{
setArtboardAudioEngine(m_nativeArtboard, audioEngine.m_nativeAudioEngine);
}
internal IntPtr GetInputAtPath(string inputName, string path)
{
// Validate the input parameters
if (string.IsNullOrEmpty(inputName))
{
DebugLogger.Instance.LogWarning($"No input name provided for path '{path}' .");
return IntPtr.Zero;
}
if (string.IsNullOrEmpty(path))
{
DebugLogger.Instance.LogWarning($"No path provided for input '{inputName}'.");
return IntPtr.Zero;
}
IntPtr ptr = getSMIInputAtPathArtboard(m_nativeArtboard, inputName, path);
return ptr;
}
private void LogMissingInputWarning(string inputName, string path)
{
DebugLogger.Instance.LogWarning($"No input found at path '{path}' with name '{inputName}'.");
}
private void LogIncorrectInputTypeWarning(string inputName, string path, string expectedType)
{
DebugLogger.Instance.LogWarning($"Input '{inputName}' at path: '{path}' is not a {expectedType} input.");
}
// Add this description to the method: Set the boolean input with the provided name at the given path with value
/// <summary>
/// Set the boolean input with the provided name at the given path with value.
/// </summary>
/// <param name="inputName">The name of the input to set.</param>
/// <param name="value">The value to set the input to.</param>
/// <param name="path">The location of the input at an artboard level, detailing nested locations if applicable.</param>
public void SetBooleanInputStateAtPath(string inputName, bool value, string path)
{
var nativeSmi = GetInputAtPath(inputName, path);
if (nativeSmi == IntPtr.Zero)
{
LogMissingInputWarning(inputName, path);
return;
}
if (SMIInput.isSMIBoolean(nativeSmi))
{
SMIBool.setSMIBoolValueStateMachine(nativeSmi, value);
}
else
{
LogIncorrectInputTypeWarning(inputName, path, "boolean");
}
}
/// <summary>
/// Get the boolean input value with the provided name at the given path.
/// </summary>
/// <param name="inputName">The state machine input name</param>
/// <param name="path">The location of the input at an artboard level, detailing nested locations if applicable.</param>
/// <returns>The value of the boolean input.</returns>
public bool? GetBooleanInputStateAtPath(string inputName, string path)
{
var nativeSmi = GetInputAtPath(inputName, path);
if (nativeSmi == IntPtr.Zero)
{
LogMissingInputWarning(inputName, path);
return null;
}
if (SMIInput.isSMIBoolean(nativeSmi))
{
return SMIBool.getSMIBoolValueStateMachine(nativeSmi);
}
else
{
LogIncorrectInputTypeWarning(inputName, path, "boolean");
return null;
}
}
/// <summary>
/// Set the number input with the provided name at the given path with value.
/// </summary>
/// <param name="inputName"The state machine input name</param>
/// <param name="value">The number value to set the input to.</param>
/// <param name="path">The location of the input at an artboard level, detailing nested locations if applicable.</param>
public void SetNumberInputStateAtPath(string inputName, float value, string path)
{
var nativeSmi = GetInputAtPath(inputName, path);
if (nativeSmi == IntPtr.Zero)
{
LogMissingInputWarning(inputName, path);
return;
}
if (SMIInput.isSMINumber(nativeSmi))
{
SMINumber.setSMINumberValueStateMachine(nativeSmi, value);
}
else
{
LogIncorrectInputTypeWarning(inputName, path, "number");
}
}
/// <summary>
/// Get the number input value with the provided name at the given path.
/// </summary>
/// <param name="inputName">The state machine input name</param>
/// <param name="path">The location of the input at an artboard level, detailing nested locations if applicable.</param>
/// <returns>The value of the number input.</returns>
public float? GetNumberInputStateAtPath(string inputName, string path)
{
var nativeSmi = GetInputAtPath(inputName, path);
if (nativeSmi == IntPtr.Zero)
{
LogMissingInputWarning(inputName, path);
return null;
}
if (SMIInput.isSMINumber(nativeSmi))
{
return SMINumber.getSMINumberValueStateMachine(nativeSmi);
}
else
{
LogIncorrectInputTypeWarning(inputName, path, "number");
return null;
}
}
/// <summary>
/// Fire the trigger input with the provided name at the given path
/// </summary>
/// <param name="inputName">The state machine input name</param>
/// <param name="path">The location of the input at an artboard level, detailing nested locations if applicable.</param>
public void FireInputStateAtPath(string inputName, string path)
{
var nativeSmi = GetInputAtPath(inputName, path);
if (nativeSmi == IntPtr.Zero)
{
LogMissingInputWarning(inputName, path);
return;
}
if (SMIInput.isSMITrigger(nativeSmi))
{
SMITrigger.fireSMITriggerStateMachine(nativeSmi);
}
else
{
LogIncorrectInputTypeWarning(inputName, path, "trigger");
}
}
/// <summary>
/// Resets the artboard to its original dimensions.
/// </summary>
public void ResetArtboardSize()
{
Width = getArtboardOriginalWidth(m_nativeArtboard);
Height = getArtboardOriginalHeight(m_nativeArtboard);
}
/// <summary>
/// Sets the data context of the Artboard from the given ViewModelInstance.
/// </summary>
/// <param name="viewModelInstance">The ViewModelInstance to bind to the Artboard.</param>
/// <remarks>
/// This method binds the ViewModelInstance to the Artboard only. If you intend to bind related state machines,
/// you should use the <see cref="StateMachine.BindViewModelInstance(ViewModelInstance)"/> method instead as it automatically binds both the Artboard and the State Machine to the ViewModelInstance.
/// </remarks>
public void BindViewModelInstance(ViewModelInstance viewModelInstance)
{
if (viewModelInstance == null)
{
DebugLogger.Instance.LogError("ViewModelInstance is null.");
return;
}
bindViewModelInstanceToArtboard(NativeArtboard, viewModelInstance.NativeSafeHandle);
m_currentViewModelInstance = viewModelInstance;
}
#region Native Methods
[DllImport(NativeLibrary.name)]
internal static extern void unrefArtboard(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern uint getStateMachineCount(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr getStateMachineName(IntPtr artboard, uint index);
[DllImport(NativeLibrary.name)]
internal static extern float getArtboardWidth(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern float getArtboardHeight(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern bool artboardDidChange(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern float getArtboardOriginalWidth(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern float getArtboardOriginalHeight(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern void setArtboardWidth(IntPtr artboard, float width);
[DllImport(NativeLibrary.name)]
internal static extern void setArtboardHeight(IntPtr artboard, float height);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr instanceStateMachineAtIndex(IntPtr artboard, uint index);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr instanceStateMachineWithName(IntPtr artboard, string name);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr instanceStateMachineDefault(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern Vec2D screenToRive(
float x,
float y,
float screenX,
float screenY,
float screenWidth,
float screenHeight,
byte fit,
float alignX,
float alignY,
IntPtr artboard
);
[DllImport(NativeLibrary.name)]
internal static extern void setArtboardAudioEngine(IntPtr artboard, IntPtr audioEngine);
[DllImport(NativeLibrary.name)]
internal static extern bool artboardHasAudio(IntPtr artboard);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr artboardComponentNamed(IntPtr artboard, string name);
[DllImport(NativeLibrary.name)]
internal static extern bool artboardSetRunValue(
IntPtr artboard,
string runName,
string text
);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr getSMIInputAtPathArtboard(IntPtr artboard, string inputName, string path);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr artboardGetTextRunValue(IntPtr artboard, string runName);
[DllImport(NativeLibrary.name)]
internal static extern bool artboardSetTextRunValueAtPath(IntPtr artboard, string runName, string path, string text);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr artboardGetTextRunValueAtPath(IntPtr artboard, string runName, string path);
[DllImport(NativeLibrary.name)]
internal static extern IntPtr artboardGetName(IntPtr artboard);
// Data binding
[DllImport(NativeLibrary.name)]
internal static extern void bindViewModelInstanceToArtboard(IntPtr artboard, ViewModelInstanceSafeHandle viewModelInstance);
#endregion
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct Vec2D
{
public float x;
public float y;
}