using UnityEngine; using System; using System.Runtime.InteropServices; using Rive.Utils; namespace Rive { /// /// Represents a Rive Artboard with a File. An Artboard contains StateMachines and Animations. /// public class Artboard : IDisposable { private readonly IntPtr m_nativeArtboard; private string m_artboardName; private ViewModelInstance m_currentViewModelInstance; private ViewModel m_defaultViewModel; private WeakReference m_file; private bool m_isDisposed = false; internal IntPtr NativeArtboard { get { return m_nativeArtboard; } } /// /// Returns true if the artboard has been disposed. /// public bool IsDisposed { get => m_isDisposed; } /// /// Constructor for the Artboard class. /// /// Pointer to the native artboard. /// The file that instanced the artboard. internal Artboard(IntPtr nativeArtboard, File file) { m_nativeArtboard = nativeArtboard; m_file = new WeakReference(file); } /// /// Dispose of the Artboard and release native resources. /// 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; } } /// /// Returns true if the artboard has audio. /// public bool HasAudio { get { return artboardHasAudio(m_nativeArtboard); } } /// /// Sets the value of a text run with the provided name. /// /// The name of the text run. /// The new value for the text run. /// public bool SetTextRun(string name, string value) { return artboardSetRunValue(m_nativeArtboard, name, value); } /// /// Gets the value of a text run with the provided name. /// /// The name of the text run. /// The value of the text run, or null if not found. public string GetTextRunValue(string runName) { return Marshal.PtrToStringAnsi(artboardGetTextRunValue(m_nativeArtboard, runName)); } /// /// Sets the value of a text run with the provided name at the given path. /// /// The name of the text run. /// The path to the nested artboard where the text run is located. /// The new value for the text run. /// True if the text run was successfully set, false otherwise. public bool SetTextRunValueAtPath(string runName, string path, string value) { return artboardSetTextRunValueAtPath(m_nativeArtboard, runName, path, value); } /// /// Gets the value of a text run with the provided name at the given path. /// /// The name of the text run. /// The path to the nested artboard where the text run is located. /// The value of the text run, or null if not found. public string GetTextRunValueAtPath(string runName, string path) { return Marshal.PtrToStringAnsi(artboardGetTextRunValueAtPath(m_nativeArtboard, runName, path)); } /// /// Gets or sets the width of the artboard instance. /// public float Width { get => getArtboardWidth(m_nativeArtboard); set => setArtboardWidth(m_nativeArtboard, value); } /// /// Gets or sets the height of the artboard instance. /// public float Height { get => getArtboardHeight(m_nativeArtboard); set => setArtboardHeight(m_nativeArtboard, value); } /// /// Returns true if the artboard has changed since the last draw. /// public bool DidChange() { return artboardDidChange(m_nativeArtboard); } /// Returns the number of StateMachines stored in the artboard. public uint StateMachineCount { get { return getStateMachineCount(m_nativeArtboard); } } /// /// The default ViewModel for the artboard. /// 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 /// /// Set the boolean input with the provided name at the given path with value. /// /// The name of the input to set. /// The value to set the input to. /// The location of the input at an artboard level, detailing nested locations if applicable. 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"); } } /// /// Get the boolean input value with the provided name at the given path. /// /// The state machine input name /// The location of the input at an artboard level, detailing nested locations if applicable. /// The value of the boolean input. 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; } } /// /// Set the number input with the provided name at the given path with value. /// /// /// The number value to set the input to. /// The location of the input at an artboard level, detailing nested locations if applicable. 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"); } } /// /// Get the number input value with the provided name at the given path. /// /// The state machine input name /// The location of the input at an artboard level, detailing nested locations if applicable. /// The value of the number input. 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; } } /// /// Fire the trigger input with the provided name at the given path /// /// The state machine input name /// The location of the input at an artboard level, detailing nested locations if applicable. 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"); } } /// /// Resets the artboard to its original dimensions. /// public void ResetArtboardSize() { Width = getArtboardOriginalWidth(m_nativeArtboard); Height = getArtboardOriginalHeight(m_nativeArtboard); } /// /// Sets the data context of the Artboard from the given ViewModelInstance. /// /// The ViewModelInstance to bind to the Artboard. /// /// This method binds the ViewModelInstance to the Artboard only. If you intend to bind related state machines, /// you should use the method instead as it automatically binds both the Artboard and the State Machine to the ViewModelInstance. /// 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; }