using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Rive.Utils;
namespace Rive
{
///
/// A view model instance property that holds a list of view model instances.
///
public sealed class ViewModelInstanceListProperty : ViewModelInstancePrimitiveProperty
{
internal ViewModelInstanceListProperty(IntPtr instanceValuePtr, ViewModelInstance rootInstance)
: base(instanceValuePtr, rootInstance)
{
}
///
/// The number of items in the list.
///
public int Count
{
get
{
ThrowIfOwnerDisposed();
if (InstancePropertyPtr == IntPtr.Zero)
{
DebugLogger.Instance.LogWarning("Trying to get length of a null list property.");
return 0;
}
return (int)getViewModelInstanceListSize(InstancePropertyPtr);
}
}
///
/// Gets the view model instance at the specified index.
///
/// The index of the item to get.
/// The view model instance at the specified index, or null if the index is out of bounds.
public ViewModelInstance GetInstanceAt(int index)
{
ThrowIfOwnerDisposed();
if (InstancePropertyPtr == IntPtr.Zero)
{
DebugLogger.Instance.LogError("Trying to get item from a null list property.");
return null;
}
if (index < 0 || index >= Count)
{
DebugLogger.Instance.LogError($"Index {index} is out of bounds for list of length {Count}.");
return null;
}
IntPtr instancePtr = getViewModelInstanceListItemAt(InstancePropertyPtr, index);
if (instancePtr == IntPtr.Zero)
{
return null;
}
ViewModelInstance vmi = GetOrCreateVMInstanceFromPtr(instancePtr);
return vmi;
}
private ViewModelInstance GetOrCreateVMInstanceFromPtr(IntPtr instancePtr)
{
if (instancePtr == IntPtr.Zero)
{
return null;
}
return ViewModelInstance.GetOrCreateFromPointer(instancePtr, this.RootInstance?.RiveFile, this.RootInstance);
}
///
/// Adds a view model instance to the end of the list.
///
/// The view model instance to add.
public void Add(ViewModelInstance instance)
{
ThrowIfOwnerDisposed();
if (InstancePropertyPtr == IntPtr.Zero)
{
DebugLogger.Instance.LogError("Trying to add to a null list property.");
return;
}
if (instance == null || instance.NativeSafeHandle.IsInvalid)
{
DebugLogger.Instance.LogError("Cannot add null or invalid view model instance to list.");
return;
}
addViewModelInstanceToList(InstancePropertyPtr, instance.NativeSafeHandle.DangerousGetHandle());
instance.AddParent(this.RootInstance);
}
///
/// Inserts a view model instance at the specified index.
///
/// The view model instance to insert.
/// The index at which to insert the instance.
public void Insert(ViewModelInstance instance, int index)
{
ThrowIfOwnerDisposed();
if (instance == null)
{
DebugLogger.Instance.LogError("Cannot insert null or invalid view model instance into list.");
return;
}
if (InstancePropertyPtr == IntPtr.Zero)
{
DebugLogger.Instance.LogError("Trying to insert into a null list property.");
return;
}
if (index < 0)
{
DebugLogger.Instance.LogError($"Index {index} is out of bounds for list of length {Count}.");
return;
}
if (!addViewModelInstanceToListAt(InstancePropertyPtr, instance.NativeSafeHandle.DangerousGetHandle(), index))
{
DebugLogger.Instance.LogError($"Failed to insert view model instance at index {index}.");
return;
}
instance.AddParent(this.RootInstance);
}
///
/// Removes a view model instance from the list.
///
/// The view model instance to remove.
///
/// This method will remove every occurrence of the instance from the list.
///
public void Remove(ViewModelInstance instance)
{
ThrowIfOwnerDisposed();
if (InstancePropertyPtr == IntPtr.Zero)
{
DebugLogger.Instance.LogError("Trying to remove from a null list property.");
return;
}
if (instance == null || instance.NativeSafeHandle.IsInvalid)
{
DebugLogger.Instance.LogError("Cannot remove null or invalid view model instance from list.");
return;
}
removeViewModelInstanceFromList(InstancePropertyPtr, instance.NativeSafeHandle.DangerousGetHandle());
instance.RemoveParent(this.RootInstance);
}
///
/// Removes the view model instance at the specified index.
///
/// The index of the item to remove.
public void RemoveAt(int index)
{
ThrowIfOwnerDisposed();
if (InstancePropertyPtr == IntPtr.Zero)
{
DebugLogger.Instance.LogError("Trying to remove from a null list property.");
return;
}
if (index < 0 || index >= Count)
{
DebugLogger.Instance.LogError($"Index {index} is out of bounds for list of length {Count}.");
return;
}
ViewModelInstance instance = GetInstanceAt(index);
if (instance == null)
{
DebugLogger.Instance.LogError($"No instance found at index {index}.");
return;
}
removeViewModelInstanceFromListAt(InstancePropertyPtr, index);
}
///
/// Swaps the view model instances at the specified indices.
///
/// The index of the first item to swap.
/// The index of the second item to swap.
public void Swap(int indexA, int indexB)
{
ThrowIfOwnerDisposed();
if (InstancePropertyPtr == IntPtr.Zero)
{
DebugLogger.Instance.LogError("Trying to swap instances in a null list property.");
return;
}
if (indexA == indexB)
{
DebugLogger.Instance.LogError("Cannot swap instances at the same index.");
return;
}
if (indexA < 0 || indexA >= Count)
{
DebugLogger.Instance.LogError($"Index {indexA} is out of bounds for list of length {Count}.");
return;
}
if (indexB < 0 || indexB >= Count)
{
DebugLogger.Instance.LogError($"Index {indexB} is out of bounds for list of length {Count}.");
return;
}
swapViewModelInstancesInList(InstancePropertyPtr, indexA, indexB);
}
///
/// Called when the list property value changes.
///
internal override void RaiseChangedEvent()
{
// List changes don't have a specific value, just notify that the list changed
m_onTriggered?.Invoke();
}
///
/// Event that is raised when the list changes.
///
public event Action OnChanged
{
add => AddPropertyCallback(value, ref m_onTriggered);
remove => RemovePropertyCallback(value, ref m_onTriggered);
}
private Action m_onTriggered;
///
/// Clears all callbacks registered with this property.
///
internal override void ClearAllCallbacks()
{
m_onTriggered = null;
base.ClearAllCallbacks();
}
internal override void ClearDelegatesOnly()
{
m_onTriggered = null;
}
[DllImport(NativeLibrary.name)]
private static extern nuint getViewModelInstanceListSize(IntPtr listProperty);
[DllImport(NativeLibrary.name)]
private static extern IntPtr getViewModelInstanceListItemAt(IntPtr listProperty, int index);
[DllImport(NativeLibrary.name)]
private static extern void addViewModelInstanceToList(IntPtr listProperty, IntPtr instance);
[DllImport(NativeLibrary.name)]
private static extern bool addViewModelInstanceToListAt(IntPtr listProperty, IntPtr instance, int index);
[DllImport(NativeLibrary.name)]
private static extern void removeViewModelInstanceFromList(IntPtr listProperty, IntPtr instance);
[DllImport(NativeLibrary.name)]
private static extern void removeViewModelInstanceFromListAt(IntPtr listProperty, int index);
[DllImport(NativeLibrary.name)]
private static extern void swapViewModelInstancesInList(IntPtr listProperty, int indexA, int indexB);
}
}