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