From d2ab30e7a69bfe7efda63ae75812207377917bd3 Mon Sep 17 00:00:00 2001
From: miepzerino <o.skotnik@gmail.com>
Date: Sun, 30 Mar 2025 18:50:27 +0000
Subject: [PATCH] Merge branch 'Flexalon-UI-Layouts' into develop

---
 Assets/Flexalon/Runtime/Animators/FlexalonCurveAnimator.cs |  261 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 261 insertions(+), 0 deletions(-)

diff --git a/Assets/Flexalon/Runtime/Animators/FlexalonCurveAnimator.cs b/Assets/Flexalon/Runtime/Animators/FlexalonCurveAnimator.cs
new file mode 100644
index 0000000..50493cd
--- /dev/null
+++ b/Assets/Flexalon/Runtime/Animators/FlexalonCurveAnimator.cs
@@ -0,0 +1,261 @@
+using UnityEngine;
+
+namespace Flexalon
+{
+    /// <summary>
+    /// The curve animator applies a curve the the position, rotation, and scale
+    /// of the object. The curve is restarted each time the layout position changes.
+    /// This is ideal for scenarios in which the layout position does not change often.
+    /// </summary>
+    [AddComponentMenu("Flexalon/Flexalon Curve Animator"), HelpURL("https://www.flexalon.com/docs/animators")]
+    public class FlexalonCurveAnimator : MonoBehaviour, TransformUpdater
+    {
+        private FlexalonNode _node;
+        private RectTransform _rectTransform;
+
+        private bool _animateInWorldSpace = true;
+        /// <summary> Determines if the animation should be performed in world space. </summary>
+        public bool AnimateInWorldSpace
+        {
+            get => _animateInWorldSpace;
+            set { _animateInWorldSpace = value; }
+        }
+
+        [SerializeField]
+        private AnimationCurve _curve = AnimationCurve.Linear(0, 0, 1, 1);
+        /// <summary> The curve to apply. Should begin at 0 and end at 1. </summary>
+        public AnimationCurve Curve
+        {
+            get => _curve;
+            set { _curve = value; }
+        }
+
+        [SerializeField]
+        private bool _animatePosition = true;
+        /// <summary> Determines if the position should be animated. </summary>
+        public bool AnimatePosition
+        {
+            get => _animatePosition;
+            set { _animatePosition = value; }
+        }
+
+        [SerializeField]
+        private bool _animateRotation = true;
+        /// <summary> Determines if the rotation should be animated. </summary>
+        public bool AnimateRotation
+        {
+            get => _animateRotation;
+            set { _animateRotation = value; }
+        }
+
+        [SerializeField]
+        private bool _animateScale = true;
+        /// <summary> Determines if the scale should be animated. </summary>
+        public bool AnimateScale
+        {
+            get => _animateScale;
+            set { _animateScale = value; }
+        }
+
+        private Vector3 _startPosition;
+        private Quaternion _startRotation;
+        private Vector3 _startScale;
+        private Vector2 _startRectSize;
+
+        private Vector3 _endPosition;
+        private Quaternion _endRotation;
+        private Vector3 _endScale;
+        private Vector2 _endRectSize;
+
+        private float _positionTime;
+        private float _rotationTime;
+        private float _scaleTime;
+        private float _rectSizeTime;
+
+        private Vector3 _fromPosition;
+        private Quaternion _fromRotation;
+        private Vector3 _fromScale;
+        private Vector2 _fromRectSize;
+
+        void OnEnable()
+        {
+            _startPosition = _endPosition = new Vector3(float.NaN, float.NaN, float.NaN);
+            _startRotation = _endRotation = new Quaternion(float.NaN, float.NaN, float.NaN, float.NaN);
+            _startScale = _endScale = new Vector3(float.NaN, float.NaN, float.NaN);
+            _positionTime = _rotationTime = _scaleTime = 0;
+            _rectTransform = (transform is RectTransform) ? (RectTransform)transform : null;
+
+            _node = Flexalon.GetOrCreateNode(gameObject);
+            _node.SetTransformUpdater(this);
+        }
+
+        void OnDisable()
+        {
+            _node?.SetTransformUpdater(null);
+            _node = null;
+        }
+
+        /// <inheritdoc />
+        public void PreUpdate(FlexalonNode node)
+        {
+            _fromPosition = transform.position;
+            _fromRotation = transform.rotation;
+            _fromScale = transform.lossyScale;
+            _fromRectSize = _rectTransform?.rect.size ?? Vector2.zero;
+        }
+
+        /// <inheritdoc />
+        public bool UpdatePosition(FlexalonNode node, Vector3 position)
+        {
+            var newEndPosition = position;
+            var newStartPosition = transform.localPosition;
+
+            if (_animateInWorldSpace)
+            {
+                newEndPosition = transform.parent ? transform.parent.localToWorldMatrix.MultiplyPoint(position) : position;;
+                newStartPosition = _fromPosition;
+            }
+
+            if (newEndPosition != _endPosition)
+            {
+                _startPosition = newStartPosition;
+                _endPosition = newEndPosition;
+                _positionTime = 0;
+            }
+
+            _positionTime += Time.smoothDeltaTime;
+
+            if (!_animatePosition || _positionTime > _curve.keys[_curve.keys.Length - 1].time)
+            {
+                transform.localPosition = position;
+                _endPosition = new Vector3(float.NaN, float.NaN, float.NaN);
+                return true;
+            }
+            else
+            {
+                var newPosition = Vector3.Lerp(_startPosition, _endPosition, _curve.Evaluate(_positionTime));
+                if (_animateInWorldSpace)
+                {
+                    transform.position = newPosition;
+                }
+                else
+                {
+                    transform.localPosition = newPosition;
+                }
+
+                return false;
+            }
+        }
+
+        /// <inheritdoc />
+        public bool UpdateRotation(FlexalonNode node, Quaternion rotation)
+        {
+            var newEndRotation = rotation;
+            var newStartRotation = transform.localRotation;
+
+            if (_animateInWorldSpace)
+            {
+                newEndRotation = transform.parent ? transform.parent.rotation * rotation : rotation;;
+                newStartRotation = _fromRotation;
+            }
+
+            if (newEndRotation != _endRotation)
+            {
+                _startRotation = newStartRotation;
+                _endRotation = newEndRotation;
+                _rotationTime = 0;
+            }
+
+            _rotationTime += Time.smoothDeltaTime;
+
+            if (!_animateRotation || _rotationTime > _curve.keys[_curve.keys.Length - 1].time)
+            {
+                transform.localRotation = rotation;
+                _endRotation = new Quaternion(float.NaN, float.NaN, float.NaN, float.NaN);
+                return true;
+            }
+            else
+            {
+                var newRotation = Quaternion.Slerp(_startRotation, _endRotation, _curve.Evaluate(_rotationTime));
+                if (_animateInWorldSpace)
+                {
+                    transform.rotation = newRotation;
+                }
+                else
+                {
+                    transform.localRotation = newRotation;
+                }
+
+                return false;
+            }
+        }
+
+        /// <inheritdoc />
+        public bool UpdateScale(FlexalonNode node, Vector3 scale)
+        {
+            var newEndScale = scale;
+            var newStartScale = transform.localScale;
+
+            if (_animateInWorldSpace)
+            {
+                newEndScale = transform.parent ? Math.Mul(scale, transform.parent.lossyScale) : scale;
+                newStartScale = _fromScale;
+            }
+
+            if (newEndScale != _endScale)
+            {
+                _startScale = newStartScale;
+                _endScale = newEndScale;
+                _scaleTime = 0;
+            }
+
+            _scaleTime += Time.smoothDeltaTime;
+
+            if (!_animateScale || _scaleTime > _curve.keys[_curve.keys.Length - 1].time)
+            {
+                transform.localScale = scale;
+                _endScale = new Vector3(float.NaN, float.NaN, float.NaN);
+                return true;
+            }
+            else
+            {
+                var newScale = Vector3.Lerp(_startScale, _endScale, _curve.Evaluate(_scaleTime));
+
+                if (_animateInWorldSpace)
+                {
+                    transform.localScale = transform.parent ? Math.Div(newScale, transform.parent.lossyScale) : newScale;
+                }
+                else
+                {
+                    transform.localScale = newScale;
+                }
+
+                return false;
+            }
+        }
+
+        /// <inheritdoc />
+        public bool UpdateRectSize(FlexalonNode node, Vector2 size)
+        {
+            if (size != _endRectSize)
+            {
+                _startRectSize = _fromRectSize;
+                _endRectSize = size;
+                _rectSizeTime = 0;
+            }
+
+            _rectSizeTime += Time.smoothDeltaTime;
+            bool done = !_animateScale || _rectSizeTime > _curve.keys[_curve.keys.Length - 1].time;
+            var newSize = done ? size : Vector2.Lerp(_startRectSize, _endRectSize, _curve.Evaluate(_rectSizeTime));
+            _rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, newSize.x);
+            _rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, newSize.y);
+
+            if (done)
+            {
+                _endRectSize = new Vector2(float.NaN, float.NaN);
+            }
+
+            return done;
+        }
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3