mirror of
https://github.com/ppy/osu.git
synced 2026-05-19 06:31:19 +08:00
199bcd7fdb
This is in response to feedback in https://osu.ppy.sh/community/forums/topics/2056547?n=1. Upon examining the button further, there was indeed some rather weird... almost hysteresis in how the button behaved with respect to the area on the screen that activated it. Because of the following scourge of a method that continues to haunt us to this day: https://github.com/ppy/osu/blob/31487545d0d17c4337d4b4cc5d4afb3ba1dae838/osu.Game/Graphics/Containers/OsuClickableContainer.cs#L24-L25 the button would effectively only be activated by 80% of its drawable area when it was not hovered, because of the scale applied to the `content` container which `Container.Content` redirected to. This is resolved here by various rearrangements of paddings and sizes such that the clickable area of any of the buttons of the card is always the full top or bottom half of the button area. Also included are some cosmetic touch-ups which happened to be convenient like folding the loading spinner into the base `BeatmapCardIconButton`, adding loading support for the favourite button, using BDL more, and resolving some "virtual member call in constructor" inspections.
184 lines
7.0 KiB
C#
184 lines
7.0 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.Graphics;
|
|
using osu.Framework.Graphics.Containers;
|
|
using osu.Framework.Graphics.Shapes;
|
|
using osu.Game.Beatmaps.Drawables.Cards.Buttons;
|
|
using osu.Game.Graphics;
|
|
using osu.Game.Online;
|
|
using osu.Game.Online.API.Requests.Responses;
|
|
using osu.Game.Overlays;
|
|
|
|
namespace osu.Game.Beatmaps.Drawables.Cards
|
|
{
|
|
public partial class CollapsibleButtonContainer : Container
|
|
{
|
|
public Bindable<bool> ShowDetails = new Bindable<bool>();
|
|
public Bindable<BeatmapSetFavouriteState> FavouriteState = new Bindable<BeatmapSetFavouriteState>();
|
|
|
|
private readonly BeatmapDownloadTracker downloadTracker;
|
|
|
|
private float buttonsExpandedWidth;
|
|
|
|
public float ButtonsExpandedWidth
|
|
{
|
|
get => buttonsExpandedWidth;
|
|
set
|
|
{
|
|
buttonsExpandedWidth = value;
|
|
buttonArea.Width = value;
|
|
if (IsLoaded)
|
|
updateState();
|
|
}
|
|
}
|
|
|
|
private float buttonsCollapsedWidth;
|
|
|
|
public float ButtonsCollapsedWidth
|
|
{
|
|
get => buttonsCollapsedWidth;
|
|
set
|
|
{
|
|
buttonsCollapsedWidth = value;
|
|
if (IsLoaded)
|
|
updateState();
|
|
}
|
|
}
|
|
|
|
protected override Container<Drawable> Content => mainContent;
|
|
|
|
private readonly Container background;
|
|
|
|
private readonly Container buttonArea;
|
|
private readonly Container<BeatmapCardIconButton> buttons;
|
|
|
|
private readonly Container mainArea;
|
|
private readonly Container mainContent;
|
|
|
|
[Resolved]
|
|
private OsuColour colours { get; set; } = null!;
|
|
|
|
[Resolved]
|
|
private OverlayColourProvider colourProvider { get; set; } = null!;
|
|
|
|
public CollapsibleButtonContainer(APIBeatmapSet beatmapSet)
|
|
{
|
|
downloadTracker = new BeatmapDownloadTracker(beatmapSet);
|
|
|
|
RelativeSizeAxes = Axes.Y;
|
|
Masking = true;
|
|
CornerRadius = BeatmapCard.CORNER_RADIUS;
|
|
|
|
InternalChildren = new Drawable[]
|
|
{
|
|
downloadTracker,
|
|
background = new Container
|
|
{
|
|
RelativeSizeAxes = Axes.Y,
|
|
Anchor = Anchor.CentreRight,
|
|
Origin = Anchor.CentreRight,
|
|
Child = new Box
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Colour = Colour4.White
|
|
},
|
|
},
|
|
buttonArea = new Container
|
|
{
|
|
Name = @"Right (button) area",
|
|
RelativeSizeAxes = Axes.Y,
|
|
Origin = Anchor.TopRight,
|
|
Anchor = Anchor.TopRight,
|
|
Child = buttons = new Container<BeatmapCardIconButton>
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Children = new BeatmapCardIconButton[]
|
|
{
|
|
new FavouriteButton(beatmapSet)
|
|
{
|
|
Current = FavouriteState,
|
|
Anchor = Anchor.TopCentre,
|
|
Origin = Anchor.TopCentre,
|
|
RelativeSizeAxes = Axes.Both,
|
|
Height = 0.5f,
|
|
},
|
|
new DownloadButton(beatmapSet)
|
|
{
|
|
Anchor = Anchor.BottomCentre,
|
|
Origin = Anchor.BottomCentre,
|
|
State = { BindTarget = downloadTracker.State },
|
|
RelativeSizeAxes = Axes.Both,
|
|
Height = 0.5f,
|
|
},
|
|
new GoToBeatmapButton(beatmapSet)
|
|
{
|
|
Anchor = Anchor.BottomCentre,
|
|
Origin = Anchor.BottomCentre,
|
|
State = { BindTarget = downloadTracker.State },
|
|
RelativeSizeAxes = Axes.Both,
|
|
Height = 0.5f,
|
|
}
|
|
}
|
|
}
|
|
},
|
|
mainArea = new Container
|
|
{
|
|
Name = @"Main content",
|
|
RelativeSizeAxes = Axes.Y,
|
|
CornerRadius = BeatmapCard.CORNER_RADIUS,
|
|
Masking = true,
|
|
Children = new Drawable[]
|
|
{
|
|
new BeatmapCardContentBackground(beatmapSet)
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Dimmed = { BindTarget = ShowDetails }
|
|
},
|
|
mainContent = new Container
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Padding = new MarginPadding
|
|
{
|
|
Horizontal = 10,
|
|
Vertical = 4
|
|
},
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
protected override void LoadComplete()
|
|
{
|
|
base.LoadComplete();
|
|
|
|
downloadTracker.State.BindValueChanged(_ => updateState());
|
|
ShowDetails.BindValueChanged(_ => updateState(), true);
|
|
FinishTransforms(true);
|
|
}
|
|
|
|
private void updateState()
|
|
{
|
|
float buttonAreaWidth = ShowDetails.Value ? ButtonsExpandedWidth : ButtonsCollapsedWidth;
|
|
float mainAreaWidth = Width - buttonAreaWidth;
|
|
|
|
mainArea.ResizeWidthTo(mainAreaWidth, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
|
|
|
// By limiting the width we avoid this box showing up as an outline around the drawables that are on top of it.
|
|
background.ResizeWidthTo(buttonAreaWidth + BeatmapCard.CORNER_RADIUS, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
|
|
|
background.FadeColour(downloadTracker.State.Value == DownloadState.LocallyAvailable ? colours.Lime0 : colourProvider.Background3, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
|
buttons.FadeTo(ShowDetails.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
|
|
|
foreach (var button in buttons)
|
|
{
|
|
button.IdleColour = downloadTracker.State.Value != DownloadState.LocallyAvailable ? colourProvider.Light1 : colourProvider.Background3;
|
|
button.HoverColour = downloadTracker.State.Value != DownloadState.LocallyAvailable ? colourProvider.Content1 : colourProvider.Foreground1;
|
|
}
|
|
}
|
|
}
|
|
}
|