canto/Assets/Scripts/UI/Effect/FadeEffect.cs
2025-07-19 23:42:43 -04:00

91 lines
2.6 KiB
C#

using System.Threading;
using KitsuneCafe.System;
using KitsuneCafe.System.Attributes;
using R3;
using UnityEngine;
using UnityEngine.UIElements;
using KitsuneCafe.Extension;
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 SerializableDuration duration;
[SerializeField, ShowIf("addTransition")]
private EasingMode easing;
[SerializeField, ShowIf("addTransition")]
private SerializableDuration 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);
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 FadeEffectInstance(float from, float to)
{
From = from;
To = to;
}
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);
}
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>())
.Switch()
.Where(evt => evt.stylePropertyNames.Contains("opacity"))
.Take(1)
.TakeUntil(token)
.AsUnitObservable();
}
}
}