XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.Desktop;

[Flags]
public enum DesktopChromeAnimationChanges { None = 0, Minimize = 1, Close = 2, TitleHint = 4, Resize = 8 }

/// <summary>Monotonic reversible window affordances. Stable states never request another frame.</summary>
public sealed class DesktopChromeAnimation
{
    public const int DurationMilliseconds = 180;
    private readonly Channel _minimize = new(), _close = new(), _title = new(), _resize = new();
    public double MinimizeProgress => _minimize.Progress;
    public double CloseProgress => _close.Progress;
    public double TitleHintProgress => _title.Progress;
    public double ResizeProgress => _resize.Progress;
    public bool IsAnimating => _minimize.IsAnimating || _close.IsAnimating || _title.IsAnimating || _resize.IsAnimating;

    public DesktopChromeAnimationChanges SetTargets(long monotonicMs, bool minimize, bool close, bool titleHint, bool resize)
    {
        var changed = Advance(monotonicMs);
        _minimize.SetTarget(minimize); _close.SetTarget(close); _title.SetTarget(titleHint); _resize.SetTarget(resize);
        return changed;
    }

    public DesktopChromeAnimationChanges Advance(long monotonicMs)
    {
        var changed = DesktopChromeAnimationChanges.None;
        if (_minimize.Advance(monotonicMs)) changed |= DesktopChromeAnimationChanges.Minimize;
        if (_close.Advance(monotonicMs)) changed |= DesktopChromeAnimationChanges.Close;
        if (_title.Advance(monotonicMs)) changed |= DesktopChromeAnimationChanges.TitleHint;
        if (_resize.Advance(monotonicMs)) changed |= DesktopChromeAnimationChanges.Resize;
        return changed;
    }

    private sealed class Channel
    {
        private double _phase;
        private bool _target, _initialized;
        private long _lastMs;
        public double Progress => _phase * _phase * (3 - 2 * _phase);
        public bool IsAnimating => _target ? _phase < 1 : _phase > 0;
        public void SetTarget(bool target) => _target = target;
        public bool Advance(long nowMs)
        {
            if (!_initialized) { _initialized = true; _lastMs = nowMs; return false; }
            if (nowMs <= _lastMs) return false;
            long elapsed = unchecked(nowMs - _lastMs);
            _lastMs = nowMs;
            double step = (elapsed < 0 ? DurationMilliseconds : Math.Min(elapsed, DurationMilliseconds)) / (double)DurationMilliseconds;
            double previous = _phase;
            _phase = Math.Clamp(_phase + (_target ? step : -step), 0, 1);
            return previous != _phase;
        }
    }
}