diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 2a43ba3f99..ece280659c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsHeader), typeof(DrawableComment), typeof(HeaderButton), - typeof(SortTabControl), + typeof(OverlaySortTabControl<>), typeof(ShowChildrenButton), typeof(DeletedCommentsCounter), typeof(VotePill), diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs index a60f220e4b..c688d600a3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Online { typeof(CommentsHeader), typeof(HeaderButton), - typeof(SortTabControl), + typeof(OverlaySortTabControl<>), }; [Cached] diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSort.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSort.cs new file mode 100644 index 0000000000..a5fa085abf --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSort.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +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 +{ + public class TestSceneBeatmapListingSort : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(BeatmapListingSortTabControl), + typeof(OverlaySortTabControl<>), + }; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + public TestSceneBeatmapListingSort() + { + BeatmapListingSortTabControl control; + OsuSpriteText current; + OsuSpriteText direction; + + Add(control = new BeatmapListingSortTabControl + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + current = new OsuSpriteText(), + direction = new OsuSpriteText() + } + }); + + control.SortDirection.BindValueChanged(sortDirection => direction.Text = $"Sort direction: {sortDirection.NewValue}", true); + control.Current.BindValueChanged(criteria => current.Text = $"Criteria: {criteria.NewValue}", true); + } + } +} diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs new file mode 100644 index 0000000000..cb41b33bc4 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs @@ -0,0 +1,118 @@ +// 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; + }, 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 + { + Title, + Artist, + Difficulty, + Ranked, + Rating, + Plays, + Favourites, + } +} diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index ad80e67330..1aa40201f1 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -16,8 +16,6 @@ namespace osu.Game.Overlays.Comments { public class CommentsHeader : CompositeDrawable { - private const int font_size = 14; - public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); @@ -40,29 +38,11 @@ namespace osu.Game.Overlays.Comments Padding = new MarginPadding { Horizontal = 50 }, Children = new Drawable[] { - new FillFlowContainer + new OverlaySortTabControl { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: font_size), - Text = @"Sort by" - }, - new SortTabControl - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = Sort - } - } + Current = Sort }, new ShowDeletedButton { @@ -106,7 +86,7 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: font_size), + Font = OsuFont.GetFont(size: 12), Text = @"Show deleted" } }, @@ -126,4 +106,11 @@ namespace osu.Game.Overlays.Comments } } } + + public enum CommentsSortCriteria + { + New, + Old, + Top + } } diff --git a/osu.Game/Overlays/Comments/SortTabControl.cs b/osu.Game/Overlays/Comments/SortTabControl.cs deleted file mode 100644 index 700d63351f..0000000000 --- a/osu.Game/Overlays/Comments/SortTabControl.cs +++ /dev/null @@ -1,110 +0,0 @@ -// 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.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osuTK; -using osu.Game.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Framework.Bindables; -using osu.Framework.Allocation; -using osu.Game.Graphics.Sprites; -using osuTK.Graphics; - -namespace osu.Game.Overlays.Comments -{ - public class SortTabControl : OsuTabControl - { - protected override Dropdown CreateDropdown() => null; - - protected override TabItem CreateTabItem(CommentsSortCriteria value) => new SortTabItem(value); - - protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - }; - - public SortTabControl() - { - AutoSizeAxes = Axes.Both; - } - - private class SortTabItem : TabItem - { - public SortTabItem(CommentsSortCriteria value) - : base(value) - { - AutoSizeAxes = Axes.Both; - Child = new TabButton(value) { Active = { BindTarget = Active } }; - } - - protected override void OnActivated() - { - } - - protected override void OnDeactivated() - { - } - - private class TabButton : HeaderButton - { - public readonly BindableBool Active = new BindableBool(); - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - - private readonly SpriteText text; - - public TabButton(CommentsSortCriteria value) - { - Add(text = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14), - Text = value.ToString() - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Active.BindValueChanged(active => - { - updateBackgroundState(); - - text.Font = text.Font.With(weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium); - text.Colour = active.NewValue ? colourProvider.Light1 : Color4.White; - }, true); - } - - protected override bool OnHover(HoverEvent e) - { - updateBackgroundState(); - return true; - } - - protected override void OnHoverLost(HoverLostEvent e) => updateBackgroundState(); - - private void updateBackgroundState() - { - if (Active.Value || IsHovered) - ShowBackground(); - else - HideBackground(); - } - } - } - } - - public enum CommentsSortCriteria - { - New, - Old, - Top - } -} diff --git a/osu.Game/Overlays/OverlaySortTabControl.cs b/osu.Game/Overlays/OverlaySortTabControl.cs new file mode 100644 index 0000000000..5a713ab08e --- /dev/null +++ b/osu.Game/Overlays/OverlaySortTabControl.cs @@ -0,0 +1,168 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osuTK; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Bindables; +using osu.Framework.Allocation; +using osu.Game.Graphics.Sprites; +using osuTK.Graphics; +using osu.Game.Overlays.Comments; +using JetBrains.Annotations; + +namespace osu.Game.Overlays +{ + public class OverlaySortTabControl : CompositeDrawable, IHasCurrentValue + { + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + public OverlaySortTabControl() + { + AutoSizeAxes = Axes.Both; + AddInternal(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = @"Sort by" + }, + CreateControl().With(c => + { + c.Anchor = Anchor.CentreLeft; + c.Origin = Anchor.CentreLeft; + c.Current = current; + }) + } + }); + } + + [NotNull] + protected virtual SortTabControl CreateControl() => new SortTabControl(); + + protected class SortTabControl : OsuTabControl + { + protected override Dropdown CreateDropdown() => null; + + protected override TabItem CreateTabItem(T value) => new SortTabItem(value); + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + }; + + public SortTabControl() + { + AutoSizeAxes = Axes.Both; + } + } + + protected class SortTabItem : TabItem + { + public SortTabItem(T value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Child = CreateTabButton(value); + } + + [NotNull] + protected virtual TabButton CreateTabButton(T value) => new TabButton(value) + { + Active = { BindTarget = Active } + }; + + protected override void OnActivated() + { + } + + protected override void OnDeactivated() + { + } + } + + 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) + { + base.Content.Add(content = new FillFlowContainer + { + 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); + } + + protected override bool OnHover(HoverEvent e) + { + UpdateState(); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) => UpdateState(); + + protected virtual void UpdateState() + { + if (Active.Value || IsHovered) + ShowBackground(); + else + HideBackground(); + + ContentColour = Active.Value && !IsHovered ? colourProvider.Light1 : Color4.White; + + text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium); + } + } + } +}