diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSort.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSort.cs index 28549f4306..40c694e224 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSort.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSort.cs @@ -5,8 +5,11 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; +using osuTK; namespace osu.Game.Tests.Visual.UserInterface { @@ -20,14 +23,39 @@ namespace osu.Game.Tests.Visual.UserInterface [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + private readonly FillFlowContainer placeholder; + private readonly BeatmapListingSortTabControl control; public TestSceneBeatmapListingSort() { - Add(new BeatmapListingSortTabControl + Add(control = new BeatmapListingSortTabControl { Anchor = Anchor.Centre, Origin = Anchor.Centre, }); + + Add(placeholder = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + control.SortDirection.BindValueChanged(_ => updateBindablesVisual()); + control.Current.BindValueChanged(_ => updateBindablesVisual(), true); + } + + private void updateBindablesVisual() + { + placeholder.Clear(); + + placeholder.Add(new OsuSpriteText { Text = $"Current: {control.Current.Value}" }); + placeholder.Add(new OsuSpriteText { Text = $"Sort direction: {control.SortDirection.Value}" }); } } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs index 0a002325e7..3f69c76da7 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs @@ -1,14 +1,109 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Bindables; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics; +using osuTK.Graphics; +using osuTK; +using osu.Framework.Input.Events; + namespace osu.Game.Overlays.BeatmapListing { public class BeatmapListingSortTabControl : OverlaySortTabControl { + public readonly Bindable SortDirection = new Bindable(Overlays.SortDirection.Descending); + public BeatmapListingSortTabControl() { Current.Value = BeatmapSortCriteria.Ranked; } + + protected override SortTabControl CreateControl() => new BeatmapSortTabControl + { + SortDirection = { BindTarget = SortDirection } + }; + + private class BeatmapSortTabControl : SortTabControl + { + public readonly Bindable SortDirection = new Bindable(); + + protected override TabItem CreateTabItem(BeatmapSortCriteria value) => new BeatmapSortTabItem(value) + { + SortDirection = { BindTarget = SortDirection } + }; + + private class BeatmapSortTabItem : SortTabItem + { + public readonly Bindable SortDirection = new Bindable(); + + public BeatmapSortTabItem(BeatmapSortCriteria value) + : base(value) + { + } + + protected override TabButton CreateTabButton(BeatmapSortCriteria value) => new BeatmapTabButton(value) + { + Active = { BindTarget = Active }, + SortDirection = { BindTarget = SortDirection } + }; + + private class BeatmapTabButton : TabButton + { + public readonly Bindable SortDirection = new Bindable(); + + protected override Color4 ContentColour + { + set + { + base.ContentColour = value; + icon.Colour = value; + } + } + + private readonly SpriteIcon icon; + + public BeatmapTabButton(BeatmapSortCriteria value) + : base(value) + { + Add(icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AlwaysPresent = true, + Alpha = 0, + Size = new Vector2(6) + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + SortDirection.BindValueChanged(direction => + { + icon.Icon = direction.NewValue == Overlays.SortDirection.Ascending ? FontAwesome.Solid.CaretUp : FontAwesome.Solid.CaretDown; + icon.Margin = direction.NewValue == Overlays.SortDirection.Ascending ? new MarginPadding { Top = 1 } : new MarginPadding { Top = 2 }; + }, true); + } + + protected override void UpdateState() + { + base.UpdateState(); + icon.FadeTo(Active.Value || IsHovered ? 1 : 0, 200, Easing.OutQuint); + } + + protected override bool OnClick(ClickEvent e) + { + if (Active.Value) + SortDirection.Value = SortDirection.Value == Overlays.SortDirection.Ascending ? Overlays.SortDirection.Descending : Overlays.SortDirection.Ascending; + + return base.OnClick(e); + } + } + } + } } public enum BeatmapSortCriteria diff --git a/osu.Game/Overlays/OverlaySortTabControl.cs b/osu.Game/Overlays/OverlaySortTabControl.cs index 0b91de2682..487dd70db9 100644 --- a/osu.Game/Overlays/OverlaySortTabControl.cs +++ b/osu.Game/Overlays/OverlaySortTabControl.cs @@ -82,9 +82,15 @@ namespace osu.Game.Overlays : base(value) { AutoSizeAxes = Axes.Both; - Child = new TabButton(value) { Active = { BindTarget = Active } }; + Child = CreateTabButton(value); } + [NotNull] + protected virtual TabButton CreateTabButton(T value) => new TabButton(value) + { + Active = { BindTarget = Active } + }; + protected override void OnActivated() { } @@ -93,52 +99,67 @@ namespace osu.Game.Overlays { } - private class TabButton : HeaderButton + protected class TabButton : HeaderButton { public readonly BindableBool Active = new BindableBool(); + protected override Container Content => content; + + protected virtual Color4 ContentColour + { + set => text.Colour = value; + } + [Resolved] private OverlayColourProvider colourProvider { get; set; } private readonly SpriteText text; + private readonly FillFlowContainer content; public TabButton(T value) { - Add(text = new OsuSpriteText + base.Content.Add(content = new FillFlowContainer { - Font = OsuFont.GetFont(size: 12), - Text = value.ToString() + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(3, 0), + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 12), + Text = value.ToString() + } + } }); } protected override void LoadComplete() { base.LoadComplete(); - Active.BindValueChanged(_ => updateState(), true); + Active.BindValueChanged(_ => UpdateState(), true); } protected override bool OnHover(HoverEvent e) { - updateHoverState(); + UpdateState(); return true; } - protected override void OnHoverLost(HoverLostEvent e) => updateHoverState(); + protected override void OnHoverLost(HoverLostEvent e) => UpdateState(); - private void updateState() - { - updateHoverState(); - text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium); - } - - private void updateHoverState() + protected virtual void UpdateState() { if (Active.Value || IsHovered) ShowBackground(); else HideBackground(); - text.Colour = Active.Value && !IsHovered ? colourProvider.Light1 : Color4.White; + ContentColour = Active.Value && !IsHovered ? colourProvider.Light1 : Color4.White; + + text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium); } } }