102 lines
2.9 KiB
C#
102 lines
2.9 KiB
C#
using System;
|
|
using System.Threading;
|
|
using KitsuneCafe.Extension;
|
|
using KitsuneCafe.Sys;
|
|
using KitsuneCafe.Sys.Attributes;
|
|
using R3;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using Unit = R3.Unit;
|
|
|
|
namespace KitsuneCafe.UI
|
|
{
|
|
[CreateAssetMenu(menuName = KitsuneCafeMenu.UiEffect + "Fade")]
|
|
public class FadeEffect : BaseUiEffect
|
|
{
|
|
[SerializeField]
|
|
private bool addTransition = false;
|
|
|
|
[SerializeField, ShowIf("addTransition")]
|
|
private string propertyName = "opacity";
|
|
|
|
[SerializeField, ShowIf("addTransition")]
|
|
private Duration duration;
|
|
|
|
[SerializeField, ShowIf("addTransition")]
|
|
private EasingMode easing;
|
|
|
|
[SerializeField, ShowIf("addTransition")]
|
|
private Duration delay;
|
|
|
|
[SerializeField, Range(0f, 1f)]
|
|
private float from;
|
|
|
|
[SerializeField, Range(0f, 1f)]
|
|
private float to;
|
|
|
|
public override IUiEffect Instantiate()
|
|
{
|
|
var fade = new FadeEffectInstance(from, to, duration + delay);
|
|
|
|
if (addTransition)
|
|
{
|
|
return new AddTransitionEffect(propertyName, duration, easing, delay, fade);
|
|
}
|
|
|
|
return fade;
|
|
}
|
|
}
|
|
|
|
public readonly struct FadeEffectInstance : IUiEffect
|
|
{
|
|
public readonly float From;
|
|
public readonly float To;
|
|
|
|
public readonly TimeSpan Timeout;
|
|
|
|
public FadeEffectInstance(float from, float to, TimeSpan timeout)
|
|
{
|
|
From = from;
|
|
To = to;
|
|
Timeout = timeout;
|
|
}
|
|
|
|
private Observable<Unit> ObserveGeometryChange(VisualElement target, CancellationToken token)
|
|
{
|
|
return target.ObserveEvent<GeometryChangedEvent>(token)
|
|
.OnErrorResumeAsFailure()
|
|
.AsUnitObservable();
|
|
}
|
|
|
|
private Observable<Unit> Defer(VisualElement target, CancellationToken token)
|
|
{
|
|
return Observable.Merge(
|
|
ObserveGeometryChange(target, token),
|
|
Observable.EveryUpdate(UnityFrameProvider.PostLateUpdate, token)
|
|
)
|
|
.Where(_ => target.resolvedStyle.width > 0 && target.resolvedStyle.height > 0)
|
|
.Take(1);
|
|
}
|
|
|
|
private bool IsOpacityEvent(TransitionEndEvent evt)
|
|
{
|
|
return evt.stylePropertyNames.Contains("opacity");
|
|
}
|
|
|
|
public Observable<Unit> Execute(VisualElement target, CancellationToken token)
|
|
{
|
|
target.style.opacity = From;
|
|
|
|
var to = To;
|
|
return Defer(target, token)
|
|
.Do(_ => target.style.opacity = to)
|
|
.Select(_ => target.ObserveEvent<TransitionEndEvent>(token))
|
|
.Switch()
|
|
.Where(IsOpacityEvent)
|
|
.Take(1)
|
|
.TakeUntil(token)
|
|
.AsUnitObservable()
|
|
.Race(Observable.Timer(Timeout));
|
|
}
|
|
}
|
|
}
|