using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
namespace RosettaUI.UIToolkit.AnimationCurveEditor
{
///
/// Manage AnimationCurve and ControlPoints
///
public class CurvePointContainer : IEnumerable<(Keyframe key, ControlPoint point)>
{
public AnimationCurve Curve => _curve;
public List ControlPoints => _controlPoints;
public bool IsEmpty => _curve == null || _curve.keys.Length == 0;
public int Count => _curve?.keys.Length ?? 0;
public (Keyframe key, ControlPoint point) this [int index]
{
get {
if (_curve == null || index < 0 || index >= _curve.keys.Length) return (default, default);
return (_curve.keys[index], _controlPoints[index]);
}
}
private AnimationCurve _curve;
private readonly List _controlPoints = new();
private readonly VisualElement _parent;
private readonly Func _getNewControlPoint;
public CurvePointContainer(VisualElement parent, Func getNewControlPoint)
{
_parent = parent;
_getNewControlPoint = getNewControlPoint;
}
public void SetCurve(AnimationCurve curve)
{
_curve = curve;
ResetControlPoints();
}
public int AddKey(Keyframe key)
{
if (IsEmpty) return -1;
int idx = _curve.AddKey(key);
if (idx < 0) return idx;
// Add control point
var controlPoint = _getNewControlPoint();
_parent.Add(controlPoint);
controlPoint.SetKeyframe(_curve, idx);
controlPoint.SetActive(true);
_controlPoints.Insert(idx, controlPoint);
return idx;
}
public int MoveKey(int index, Keyframe key)
{
if (IsEmpty || index < 0) return index;
for (var i = 0; i < _curve.keys.Length; i++)
{
if (i == index) continue;
if (_curve.keys[i].time == key.time) return index;
}
int newIdx = _curve.MoveKey(index, key);
if (newIdx != index)
{
// Swap control points
var temp = _controlPoints[index];
_controlPoints.RemoveAt(index);
_controlPoints.Insert(newIdx, temp);
index = newIdx;
}
return index;
}
public void RemoveKey(int index)
{
if (IsEmpty || index < 0 || index >= _curve.keys.Length || _curve.keys.Length <= 1) return;
_curve.RemoveKey(index);
var controlPoint = _controlPoints[index];
_controlPoints.RemoveAt(index);
_parent.Remove(controlPoint);
}
public void UpdateControlPoints()
{
if (IsEmpty) return;
AnimationCurveEditorUtility.ApplyTangentMode(this);
for (var i = 0; i < _curve.keys.Length; i++)
{
_controlPoints[i].SetKeyframe(_curve, i);
}
}
public void SelectControlPoint(int index)
{
if (index < 0 || index >= _controlPoints.Count) return;
for (var i = 0; i < _controlPoints.Count; i++)
{
_controlPoints[i].SetActive(i == index);
}
}
public void UnselectAllControlPoints()
{
foreach (var cp in _controlPoints)
{
cp.SetActive(false);
}
}
public IEnumerator<(Keyframe key, ControlPoint point)> GetEnumerator()
{
return _curve.keys.Select((t, i) => (t, _controlPoints[i])).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private void ResetControlPoints()
{
if (_curve == null) return;
foreach (var cp in _controlPoints)
{
_parent.Remove(cp);
}
_controlPoints.Clear();
for (var i = 0; i < _curve.keys.Length; i++)
{
var key = _curve.keys[i];
var controlPoint = _getNewControlPoint();
_controlPoints.Add(controlPoint);
_parent.Insert(0, controlPoint);
controlPoint.SetKeyframe(_curve, i);
controlPoint.SetPointMode(key.GetPointMode());
controlPoint.SetTangentMode(_curve.GetInTangentMode(i), _curve.GetOutTangentMode(i));
controlPoint.SetWeightedMode(key.weightedMode);
}
}
}
}