using System; using UnityEngine; namespace Uigenx.Animation { public enum UgxLoopMode { None = 0, Loop = 1, PingPong = 2, } /// How a play request behaves when the same clip is already running. public enum UgxPlayMode { Restart = 0, IgnoreIfPlaying = 1, Queue = 2, } [Serializable] public sealed class UgxKeyframe { [SerializeField] float timeMs; /// Canonical USS value text for the animated property. [SerializeField] string value; [SerializeField] UgxEasingCurve easing; public UgxKeyframe() { } public UgxKeyframe(float timeMs, string value, UgxEasingCurve easing = default) { this.timeMs = timeMs; this.value = value; this.easing = easing; } public float TimeMs => timeMs; public string Value => value; public UgxEasingCurve Easing => easing; } /// /// One animated property on one element. An empty means the screen /// root, so a clip can be reused by any screen that has the named element. /// narrows the target to a sub element the control builds for itself, /// such as the fill of a ProgressBar: those carry a USS class and no name, so a class is the /// only way to reach one. /// [Serializable] public sealed class UgxTrack { [SerializeField] string targetName; [SerializeField] string partClass; [SerializeField] string property; [SerializeField] UgxKeyframe[] keyframes = Array.Empty(); public UgxTrack() { } public UgxTrack(string targetName, string property, params UgxKeyframe[] keyframes) : this(targetName, null, property, keyframes) { } public UgxTrack(string targetName, string partClass, string property, params UgxKeyframe[] keyframes) { this.targetName = targetName; this.partClass = partClass; this.property = property; this.keyframes = keyframes ?? Array.Empty(); } public string TargetName => targetName; /// USS class of the sub element inside the target, null when there is none. public string PartClass => partClass; public string Property => property; public UgxKeyframe[] Keyframes => keyframes; public bool TargetsSelf => string.IsNullOrEmpty(targetName); public bool HasPart => !string.IsNullOrEmpty(partClass); } [Serializable] public sealed class UgxClip { public static readonly UgxClip[] None = Array.Empty(); [SerializeField] string name; [SerializeField] float durationMs = 300f; [SerializeField] UgxLoopMode loop = UgxLoopMode.None; [SerializeField] UgxTrack[] tracks = Array.Empty(); public UgxClip() { } public UgxClip(string name, float durationMs, UgxLoopMode loop, params UgxTrack[] tracks) { this.name = name; this.durationMs = durationMs; this.loop = loop; this.tracks = tracks ?? Array.Empty(); } public string Name => name; public float DurationMs => durationMs; public UgxLoopMode Loop => loop; public UgxTrack[] Tracks => tracks; } }