osu/osu.Game/Overlays/SettingsToolboxGroup.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

200 lines
7.0 KiB
C#
Raw Normal View History

// 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.
2022-10-13 07:04:38 +00:00
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Caching;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Layout;
using osu.Game.Graphics;
2022-02-14 08:51:39 +00:00
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays
{
public partial class SettingsToolboxGroup : Container, IExpandable
{
2022-10-13 07:04:38 +00:00
private readonly string title;
public const int CONTAINER_WIDTH = 270;
private const float transition_duration = 250;
private const int header_height = 30;
private const int corner_radius = 5;
private readonly Cached headerTextVisibilityCache = new Cached();
2022-10-13 07:04:38 +00:00
protected override Container<Drawable> Content => content;
private readonly FillFlowContainer content = new FillFlowContainer
{
Name = @"Content",
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = 10, Top = 5, Bottom = 10 },
Spacing = new Vector2(0, 15),
};
public BindableBool Expanded { get; } = new BindableBool(true);
2022-10-13 07:04:38 +00:00
private OsuSpriteText headerText = null!;
2022-10-13 07:04:38 +00:00
private Container headerContent = null!;
private Box background = null!;
private IconButton expandButton = null!;
/// <summary>
/// Create a new instance.
/// </summary>
/// <param name="title">The title to be displayed in the header of this group.</param>
public SettingsToolboxGroup(string title)
{
2022-10-13 07:04:38 +00:00
this.title = title;
AutoSizeAxes = Axes.Y;
Width = CONTAINER_WIDTH;
Masking = true;
2022-10-13 07:04:38 +00:00
}
[BackgroundDependencyLoader(true)]
private void load(OverlayColourProvider? colourProvider)
2022-10-13 07:04:38 +00:00
{
CornerRadius = corner_radius;
InternalChildren = new Drawable[]
{
2022-10-13 07:04:38 +00:00
background = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.1f,
Colour = colourProvider?.Background4 ?? Color4.Black,
},
new FillFlowContainer
{
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
headerContent = new Container
{
Name = @"Header",
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Height = header_height,
Children = new Drawable[]
{
headerText = new OsuSpriteText
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Text = title.ToUpperInvariant(),
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 17),
Padding = new MarginPadding { Left = 10, Right = 30 },
},
2022-10-13 07:04:38 +00:00
expandButton = new IconButton
{
Origin = Anchor.Centre,
Anchor = Anchor.CentreRight,
Position = new Vector2(-15, 0),
Icon = FontAwesome.Solid.Bars,
Scale = new Vector2(0.75f),
Action = () => Expanded.Toggle(),
},
}
},
2022-10-13 07:04:38 +00:00
content
}
},
};
}
protected override void LoadComplete()
{
base.LoadComplete();
Fix settings toolbox toggle button starting in incorrect state While displaying replays, the colour of the toolbox toggle button would not match the actual state of the rest of the toolbox, i.e. both buttons would be white, even though the "playback settings" section was expanded and as such should have a yellow toggle button. In the case of the replay player, the failure scenario was as follows: 1. `SettingsToolboxGroup` calls `updateExpanded()` in its BDL to update the initial state of the toolbox, including the toggle button colour, by adding a colour fade transform. 2. An ancestor of both the toolbox groups - `PlayerSettingsOverlay`, which is a `VisibilityContainer` - calls `FinishTransforms(true)` in its `LoadCompleteAsync()`, therefore instantly applying the colour from point (1) to the toggle button instantly. 3. However, `IconButton` inherits from `OsuAnimatedButton`. And `OsuAnimatedButton` changes its colour in `LoadComplete()`, therefore undoing the instant application from point (2). This conjunction of circumstances is instrumental to reproducing the bug, because if the `FinishTransforms(true)` call wasn't there, point (3) wouldn't matter - the transform would get applied at some indeterminate point in the future, ignoring the write from `OsuAnimatedButton`. As for the fix, move the `updateExpanded()` call in `SettingsToolboxGroup` to `LoadComplete()` to avoid the above unfortunate order. Applying initial visual state in `LoadComplete()` is the idiomatic style of doing things these days anyhow.
2022-01-06 19:25:03 +00:00
Expanded.BindValueChanged(_ => updateExpandedState(true));
updateExpandedState(false);
this.Delay(600).Schedule(updateFadeState);
}
protected override bool OnHover(HoverEvent e)
{
updateFadeState();
updateExpandedState(true);
return false;
}
protected override void OnHoverLost(HoverLostEvent e)
{
updateFadeState();
updateExpandedState(true);
base.OnHoverLost(e);
}
protected override void Update()
{
base.Update();
if (!headerTextVisibilityCache.IsValid)
{
// These toolbox grouped may be contracted to only show icons.
// For now, let's hide the header to avoid text truncation weirdness in such cases.
headerText.FadeTo(headerText.DrawWidth < DrawWidth ? 1 : 0, 150, Easing.OutQuint);
headerTextVisibilityCache.Validate();
}
}
protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source)
{
if (invalidation.HasFlagFast(Invalidation.DrawSize))
headerTextVisibilityCache.Invalidate();
return base.OnInvalidate(invalidation, source);
}
private void updateExpandedState(bool animate)
{
2022-05-09 20:49:05 +00:00
// clearing transforms is necessary to avoid a previous height transform
// potentially continuing to get processed while content has changed to autosize.
content.ClearTransforms();
if (Expanded.Value || IsHovered)
{
content.AutoSizeAxes = Axes.Y;
content.AutoSizeDuration = animate ? transition_duration : 0;
content.AutoSizeEasing = Easing.OutQuint;
}
else
{
content.AutoSizeAxes = Axes.None;
content.ResizeHeightTo(0, animate ? transition_duration : 0, Easing.OutQuint);
}
headerContent.FadeColour(Expanded.Value ? Color4.White : OsuColour.Gray(0.5f), 200, Easing.OutQuint);
}
private void updateFadeState()
{
2022-10-13 07:04:38 +00:00
const float fade_duration = 500;
background.FadeTo(IsHovered ? 1 : 0.1f, fade_duration, Easing.OutQuint);
2022-10-13 07:04:38 +00:00
expandButton.FadeTo(IsHovered ? 1 : 0, fade_duration, Easing.OutQuint);
}
}
}