using System;
using System.Linq;
using RosettaUI.Builder;
using RosettaUI.UndoSystem;
using UnityEngine;
using UnityEngine.UIElements;
namespace RosettaUI.UIToolkit.AnimationCurveEditor
{
///
/// A visual element that allows you to edit an .
///
public partial class AnimationCurveEditor : ModalEditor
{
#region Static Window Management
private static AnimationCurveEditor _instance;
static AnimationCurveEditor()
{
StaticResourceUtility.AddResetStaticResourceCallback(() =>
{
_instance = null;
});
}
public static void Show(Vector2 position, VisualElement target, AnimationCurve initialCurve, Action onCurveChanged, Action onHide)
{
_instance ??= new AnimationCurveEditor();;
_instance.Show(position, target, onCurveChanged, onHide);
_instance.CopiedValue = initialCurve;
// SetCurve()内のFitViewToCurve()時はまだ表示領域のサイズが確定していないため、
// GeometryChangedEventでFitViewToCurve()を呼び出す
_instance.RegisterCallbackOnce(_ =>
{
_instance.FitViewToCurve();
});
}
#endregion
public const string USSClassName = "rosettaui-animation-curve-editor";
private const string PersistentSizeKey = "RosettaUI_AnimationCurveEditor_Size";
// ReSharper disable MemberCanBePrivate.Global
public static Vector2 DefaultWindowSize { get; set; } = new(800, 500);
public static string VisualTreeAssetName { get; set; } = "RosettaUI_AnimationCurveEditor";
public static RectOffset FitViewPaddingPixel { get; } = new(24, 24, 40, 20);
// ReSharper restore MemberCanBePrivate.Global
private readonly CurveController _curveController;
private VisualElement _curvePreviewElement;
private VisualElementKeyEventHelper _keyEventHelper;
private ToggleButton _snapXButton;
private ToggleButton _snapYButton;
private ScrollerController _scrollerController;
private AxisLabelController _axisLabelController;
private SelectedControlPointsRect _selectedControlPointsRect;
private SelectionRect _selectionRect;
private ControlPointDisplayPositionPopup _controlPointDisplayPositionPopup;
private ControlPointsEditPositionPopup _controlPointsEditPositionPopup;
private PreviewTransform _previewTransform;
private readonly ControlPointsDragManipulatorSource _controlPointsDragManipulatorSource;
private bool _prevSnapX;
private bool _prevSnapY;
private Vector2 _zoomStartPosition;
private float _lastPointerDownTime;
#region ModalEditor
protected override AnimationCurve CopiedValue
{
get => AnimationCurveHelper.Clone(_curveController.Curve);
set => InitializeCurve(AnimationCurveHelper.Clone(value));
}
#endregion
private AnimationCurveEditor() : base(PersistentSizeKey, DefaultWindowSize, VisualTreeAssetName)
{
AddToClassList(USSClassName);
var controlPointContainer = this.Q("control-point-container");
_curveController = new CurveController(controlPointContainer, CreateControlPoint);
_curveController.onCurveChanged += () =>
{
UpdateView();
NotifyEditorValueChanged();
};
_curveController.onControlPointSelectionChanged += () => _selectedControlPointsRect.UpdateView();
_curveController.onApplySnapshot += () =>
{
HidePopups();
UpdateView();
NotifyEditorValueChanged();
};
InitUI();
InitPresetsUI();
SetupKeyBindings();
_controlPointsDragManipulatorSource = new ControlPointsDragManipulatorSource(
_curveController,
_previewTransform,
_controlPointDisplayPositionPopup
);
_selectedControlPointsRect.AddManipulator(_controlPointsDragManipulatorSource.CreateManipulator());
return;
ControlPoint CreateControlPoint(CurveController curveController)
{
var controlPoint = new ControlPoint(
curveController,
_previewTransform,
showPopupMenu: (position, cp) => ControlPointsPopupMenu.Show(
position,
_curveController,
() => ShowControlPointsEditPositionPopup(cp.LocalPosition),
cp)
);
controlPoint.AddManipulator(_controlPointsDragManipulatorSource.CreateManipulator());
return controlPoint;
}
}
///
/// Set the curve to be edited.
///
private void InitializeCurve(AnimationCurve curve)
{
_curveController.SetCurve(curve);
UnselectAllControlPoint();
FitViewToCurve();
}
#region Initialization
private void InitUI()
{
// Buttons
var fitButton = this.Q