osu/osu.Game/Overlays/RevertToDefaultButton.cs
Dean Herbert 03bd6069d8
Add slight animation when revert to default button is displayed
This also fixes the transforms running too often (could make the initial
transform take longer than expected if adjusting a slider bar, for
instance).
2024-07-08 15:50:27 +09:00

162 lines
5.2 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Localisation;
using osuTK;
namespace osu.Game.Overlays
{
public partial class RevertToDefaultButton<T> : OsuClickableContainer, IHasCurrentValue<T>
{
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
// this is done to ensure a click on this button doesn't trigger focus on a parent element which contains the button.
public override bool AcceptsFocus => true;
// this is intentionally not using BindableWithCurrent, as it can use the wrong IsDefault implementation when passed a BindableNumber.
// using GetBoundCopy() ensures that the received bindable is of the exact same type as the source bindable and uses the proper IsDefault implementation.
private Bindable<T>? current;
private SpriteIcon icon = null!;
private Circle circle = null!;
[Resolved]
private OsuColour colours { get; set; } = null!;
[Resolved]
private OverlayColourProvider? colourProvider { get; set; }
public Bindable<T> Current
{
get => current.AsNonNull();
set
{
current?.UnbindAll();
current = value.GetBoundCopy();
current.ValueChanged += _ => UpdateState();
current.DefaultChanged += _ => UpdateState();
current.DisabledChanged += _ => UpdateState();
if (IsLoaded)
UpdateState();
}
}
[BackgroundDependencyLoader]
private void load()
{
Size = new Vector2(14);
AddRange(new Drawable[]
{
circle = new Circle
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
},
icon = new SpriteIcon
{
Icon = FontAwesome.Solid.Undo,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(8),
}
});
Action += () =>
{
if (current?.Disabled == false)
current.SetDefault();
};
}
protected override void LoadComplete()
{
base.LoadComplete();
updateState();
FinishTransforms(true);
}
public override LocalisableString TooltipText => CommonStrings.RevertToDefault.ToLower();
protected override bool OnHover(HoverEvent e)
{
updateHover();
return false;
}
protected override void OnHoverLost(HoverLostEvent e)
{
updateHover();
}
public void UpdateState() => Scheduler.AddOnce(updateState);
private const double fade_duration = 200;
private bool? isDisplayed;
private void updateState()
{
if (current == null)
return;
// Avoid running animations if we are already in an up-to-date state.
if (Enabled.Value == !current.Disabled && isDisplayed == !current.IsDefault)
return;
Enabled.Value = !current.Disabled;
isDisplayed = !current.IsDefault;
updateHover();
if (isDisplayed == false)
this.FadeTo(0, fade_duration, Easing.OutQuint);
else if (current.Disabled)
this.FadeTo(0.2f, fade_duration, Easing.OutQuint);
else
{
icon.RotateTo(150).RotateTo(0, fade_duration * 2, Easing.OutQuint);
icon.ScaleTo(0.7f).ScaleTo(1, fade_duration * 2, Easing.OutQuint);
this.FadeTo(1, fade_duration, Easing.OutQuint);
}
}
private void updateHover()
{
if (IsHovered && Enabled.Value)
{
icon.RotateTo(-40, 500, Easing.OutQuint);
icon.FadeColour(colourProvider?.Light1 ?? colours.YellowLight, 300, Easing.OutQuint);
circle.FadeColour(colourProvider?.Background2 ?? colours.Gray6, 300, Easing.OutQuint);
this.ScaleTo(1.2f, 300, Easing.OutQuint);
}
else
{
icon.RotateTo(0, 100, Easing.OutQuint);
icon.FadeColour(colourProvider?.Colour0 ?? colours.Yellow, 100, Easing.OutQuint);
circle.FadeColour(colourProvider?.Background3 ?? colours.Gray3, 100, Easing.OutQuint);
this.ScaleTo(1f, 100, Easing.OutQuint);
}
}
}
}