From 9ba356f2c65754785dc151f48e22726117fcc82b Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Wed, 17 May 2017 05:58:34 -0300 Subject: [PATCH] Added osu!direct header and filter control --- .../Tests/TestCaseDirect.cs | 27 +++ .../osu.Desktop.VisualTests.csproj | 1 + .../Graphics/UserInterface/OsuDropdown.cs | 2 +- .../Graphics/UserInterface/OsuEnumDropdown.cs | 32 +++ .../Graphics/UserInterface/OsuTabControl.cs | 12 +- osu.Game/OsuGame.cs | 8 + osu.Game/Overlays/Direct/FilterControl.cs | 188 ++++++++++++++++++ osu.Game/Overlays/Direct/Header.cs | 123 ++++++++++++ osu.Game/Overlays/Direct/SortTabControl.cs | 117 +++++++++++ osu.Game/Overlays/DirectOverlay.cs | 89 +++++++++ osu.Game/Screens/Menu/MainMenu.cs | 1 + osu.Game/osu.Game.csproj | 8 + 12 files changed, 601 insertions(+), 7 deletions(-) create mode 100644 osu.Desktop.VisualTests/Tests/TestCaseDirect.cs create mode 100644 osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs create mode 100644 osu.Game/Overlays/Direct/FilterControl.cs create mode 100644 osu.Game/Overlays/Direct/Header.cs create mode 100644 osu.Game/Overlays/Direct/SortTabControl.cs create mode 100644 osu.Game/Overlays/DirectOverlay.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseDirect.cs b/osu.Desktop.VisualTests/Tests/TestCaseDirect.cs new file mode 100644 index 0000000000..8e2e88dd00 --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseDirect.cs @@ -0,0 +1,27 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; + +namespace osu.Desktop.VisualTests.Tests +{ + public class TestCaseDirect : TestCase + { + public override string Description => @"osu!direct overlay"; + + private DirectOverlay direct; + + public override void Reset() + { + base.Reset(); + + Add(direct = new DirectOverlay()); + + AddStep(@"Toggle", direct.ToggleVisibility); + } + } +} diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index dbb1750b72..8ec0fc83db 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -220,6 +220,7 @@ + diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 4f286ba7b5..9c1799c04c 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -113,7 +113,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected class OsuDropdownHeader : DropdownHeader + public class OsuDropdownHeader : DropdownHeader { private readonly SpriteText label; protected override string Label diff --git a/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs new file mode 100644 index 0000000000..fe828ca65b --- /dev/null +++ b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.ComponentModel; +using System.Reflection; +using System.Collections.Generic; + +namespace osu.Game.Graphics.UserInterface +{ + public class OsuEnumDropdown : OsuDropdown + { + public OsuEnumDropdown() + { + if (!typeof(T).IsEnum) + throw new InvalidOperationException("SettingsDropdown only supports enums as the generic type argument"); + + List> items = new List>(); + foreach(var val in (T[])Enum.GetValues(typeof(T))) + { + var field = typeof(T).GetField(Enum.GetName(typeof(T), val)); + items.Add( + new KeyValuePair( + field.GetCustomAttribute()?.Description ?? Enum.GetName(typeof(T), val), + val + ) + ); + } + Items = items; + } + } +} diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index a9fad0c739..4bbae4efd1 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -57,9 +57,9 @@ namespace osu.Game.Graphics.UserInterface } } - private class OsuTabItem : TabItem + public class OsuTabItem : TabItem { - private readonly SpriteText text; + protected readonly SpriteText Text; private readonly Box box; private Color4? accentColour; @@ -70,7 +70,7 @@ namespace osu.Game.Graphics.UserInterface { accentColour = value; if (!Active) - text.Colour = value; + Text.Colour = value; } } @@ -94,13 +94,13 @@ namespace osu.Game.Graphics.UserInterface private void fadeActive() { box.FadeIn(transition_length, EasingTypes.OutQuint); - text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint); + Text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint); } private void fadeInactive() { box.FadeOut(transition_length, EasingTypes.OutQuint); - text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint); + Text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint); } protected override bool OnHover(InputState state) @@ -130,7 +130,7 @@ namespace osu.Game.Graphics.UserInterface Children = new Drawable[] { - text = new OsuSpriteText + Text = new OsuSpriteText { Margin = new MarginPadding { Top = 5, Bottom = 5 }, Origin = Anchor.BottomLeft, diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4cf436a8e4..5bbf28e2ef 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -41,6 +41,8 @@ namespace osu.Game private DialogOverlay dialogOverlay; + private DirectOverlay direct; + private Intro intro { get @@ -70,6 +72,8 @@ namespace osu.Game public void ToggleSettings() => settings.ToggleVisibility(); + public void ToggleDirect() => direct.ToggleVisibility(); + [BackgroundDependencyLoader] private void load() { @@ -160,6 +164,7 @@ namespace osu.Game }); //overlay elements + LoadComponentAsync(direct = new DirectOverlay { Depth = -1 }, overlayContent.Add); LoadComponentAsync(chat = new ChatOverlay { Depth = -1 }, mainContent.Add); LoadComponentAsync(settings = new SettingsOverlay { Depth = -1 }, overlayContent.Add); LoadComponentAsync(musicController = new MusicController @@ -249,6 +254,9 @@ namespace osu.Game case Key.O: settings.ToggleVisibility(); return true; + case Key.D: + direct.ToggleVisibility(); + return true; } } diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs new file mode 100644 index 0000000000..9990681024 --- /dev/null +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -0,0 +1,188 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.ComponentModel; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Database; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +using Container = osu.Framework.Graphics.Containers.Container; + +namespace osu.Game.Overlays.Direct +{ + public class FilterControl : Container + { + private readonly Box tabStrip; + private readonly FillFlowContainer modeButtons; + private readonly OsuDropdown rankStatusDropdown; + + public readonly SearchTextBox Search; + + public enum RankStatus + { + Any, + [Description("Ranked & Approved")] + RankedApproved, + Approved, + Loved, + Favourites, + [Description("Mod Requests")] + ModRequests, + Pending, + Graveyard, + [Description("My Maps")] + MyMaps, + } + + protected override bool InternalContains(Vector2 screenSpacePos) => true; + + public FilterControl() + { + RelativeSizeAxes = Axes.X; + //AutoSizeAxes = Axes.Y; + Height = 127; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex(@"384552"), + }, + tabStrip = new Box + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Position = new Vector2(0f, 1f), + RelativeSizeAxes = Axes.X, + Height = 1, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING, Top = 10 }, + Spacing = new Vector2(0f, 10f), + Children = new Drawable[] + { + Search = new DirectSearchTextBox + { + RelativeSizeAxes = Axes.X, + }, + modeButtons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(10f, 0f), + }, + new SortTabControl + { + RelativeSizeAxes = Axes.X, + }, + }, + }, + rankStatusDropdown = new SlimEnumDropdown + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.None, + Margin = new MarginPadding { Top = 93, Bottom = 5, Right = DirectOverlay.WIDTH_PADDING }, //todo: sort of hacky positioning + Width = 160f, + }, + }; + + rankStatusDropdown.Current.Value = RankStatus.RankedApproved; + } + + [BackgroundDependencyLoader(true)] + private void load(OsuGame game, RulesetDatabase rulesets, OsuColour colours) + { + tabStrip.Colour = colours.Yellow; + rankStatusDropdown.AccentColour = colours.BlueDark; + + foreach (var r in rulesets.AllRulesets) + { + modeButtons.Add(new ModeToggleButton(game?.Ruleset ?? new Bindable(), r)); + } + } + + private class DirectSearchTextBox : SearchTextBox + { + protected override Color4 BackgroundUnfocused => OsuColour.FromHex(@"222222"); + protected override Color4 BackgroundFocused => OsuColour.FromHex(@"222222"); + } + + private class ModeToggleButton : ClickableContainer + { + private TextAwesome icon; + + private RulesetInfo ruleset; + public RulesetInfo Ruleset + { + get { return ruleset; } + set + { + ruleset = value; + icon.Icon = Ruleset.CreateInstance().Icon; + } + } + + private Bindable bindable; + + void Bindable_ValueChanged(RulesetInfo obj) + { + icon.FadeTo((Ruleset == obj) ? 1f : 0.5f, 100); + } + + public ModeToggleButton(Bindable bindable, RulesetInfo ruleset) + { + this.bindable = bindable; + AutoSizeAxes = Axes.Both; + + Children = new[] + { + icon = new TextAwesome + { + Origin = Anchor.TopLeft, + Anchor = Anchor.TopLeft, + TextSize = 32, + } + }; + + Ruleset = ruleset; + bindable.ValueChanged += Bindable_ValueChanged; + Bindable_ValueChanged(null); + Action = () => bindable.Value = Ruleset; + } + + protected override void Dispose(bool isDisposing) + { + if (bindable != null) + bindable.ValueChanged -= Bindable_ValueChanged; + base.Dispose(isDisposing); + } + } + + private class SlimEnumDropdown : OsuEnumDropdown + { + protected override DropdownHeader CreateHeader() => new SlimDropdownHeader { AccentColour = AccentColour }; + + private class SlimDropdownHeader : OsuDropdownHeader + { + public SlimDropdownHeader() + { + Height = 25; + Icon.TextSize = 16; + Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4, }; + } + } + } + } +} diff --git a/osu.Game/Overlays/Direct/Header.cs b/osu.Game/Overlays/Direct/Header.cs new file mode 100644 index 0000000000..dfcb0c038f --- /dev/null +++ b/osu.Game/Overlays/Direct/Header.cs @@ -0,0 +1,123 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.ComponentModel; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + +using Container = osu.Framework.Graphics.Containers.Container; + +namespace osu.Game.Overlays.Direct +{ + public class Header : Container + { + private readonly Box tabStrip; + private readonly DirectTabControl tabs; + + public Action OnSelectTab; + + public Header() + { + Height = 90; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex(@"252f3a"), + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING }, + Children = new Drawable[] + { + new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.BottomLeft, + Position = new Vector2(-35f, 5f), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10f, 0f), + Children = new Drawable[] + { + new TextAwesome + { + TextSize = 25, + Icon = FontAwesome.fa_osu_chevron_down_o, + }, + new OsuSpriteText + { + TextSize = 25, + Text = @"osu!direct", + }, + }, + }, + tabStrip = new Box + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Width = 282, //todo: make this actually match the tab control's width instead of hardcoding + Height = 1, + }, + tabs = new DirectTabControl + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + }, + }, + }, + }; + + tabs.Current.ValueChanged += (newValue) => OnSelectTab?.Invoke(newValue); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + tabStrip.Colour = colours.Green; + } + + private class DirectTabControl : OsuTabControl + { + protected override TabItem CreateTabItem(DirectTab value) => new DirectTabItem(value); + + public DirectTabControl() + { + Height = 25; + AccentColour = Color4.White; + } + + private class DirectTabItem : OsuTabControl.OsuTabItem + { + public DirectTabItem(DirectTab value) : base(value) + { + Text.TextSize = 15; + } + } + } + } + + public enum DirectTab + { + Search, + [Description("Newest Maps")] + New, + [Description("Top Rated")] + Top, + [Description("Most Played")] + MostP + } +} diff --git a/osu.Game/Overlays/Direct/SortTabControl.cs b/osu.Game/Overlays/Direct/SortTabControl.cs new file mode 100644 index 0000000000..5da41e5fc5 --- /dev/null +++ b/osu.Game/Overlays/Direct/SortTabControl.cs @@ -0,0 +1,117 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Direct +{ + public class SortTabControl : OsuTabControl + { + protected override TabItem CreateTabItem(SortCriteria value) => new SortTabItem(value); + + public SortTabControl() + { + Height = 30; + } + + private class SortTabItem : TabItem + { + private readonly float transition_duration = 100; + + private Box box; + + public override bool Active + { + get { return base.Active; } + set + { + if (Active == value) return; + + if (value) + slideActive(); + else + slideInactive(); + base.Active = value; + } + } + + public SortTabItem(SortCriteria value) : base(value) + { + AutoSizeAxes = Axes.X; + RelativeSizeAxes = Axes.Y; + + Children = new Drawable[] + { + new OsuSpriteText + { + Margin = new MarginPadding { Top = 8, Bottom = 8 }, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + Text = (value as Enum)?.GetDescription() ?? value.ToString(), + TextSize = 14, + Font = @"Exo2.0-Bold", + }, + box = new Box + { + RelativeSizeAxes = Axes.X, + Height = 5, + Scale = new Vector2(1f, 0f), + Colour = Color4.White, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + box.Colour = colours.Yellow; + } + + protected override bool OnHover(InputState state) + { + if (!Active) + slideActive(); + return true; + } + + protected override void OnHoverLost(InputState state) + { + if (!Active) + slideInactive(); + } + + private void slideActive() + { + box.ScaleTo(new Vector2(1f), transition_duration); + } + + private void slideInactive() + { + box.ScaleTo(new Vector2(1f, 0f), transition_duration); + } + } + } + + public enum SortCriteria + { + Title, + Artist, + Creator, + Difficulty, + Ranked, + Rating, + } +} diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs new file mode 100644 index 0000000000..09b45431d6 --- /dev/null +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -0,0 +1,89 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Overlays.Direct; + +namespace osu.Game.Overlays +{ + public class DirectOverlay : WaveOverlayContainer + { + public static readonly int WIDTH_PADDING = 80; + + private readonly Box background; + private readonly FilterControl filter; + + public DirectOverlay() + { + RelativeSizeAxes = Axes.Both; + + // osu!direct colours are not part of the standard palette + + FirstWaveColour = OsuColour.FromHex(@"19b0e2"); + SecondWaveColour = OsuColour.FromHex(@"2280a2"); + ThirdWaveColour = OsuColour.FromHex(@"005774"); + FourthWaveColour = OsuColour.FromHex(@"003a4e"); + + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex(@"485e74"), + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new[] + { + new Triangles + { + RelativeSizeAxes = Axes.Both, + TriangleScale = 5, + ColourLight = OsuColour.FromHex(@"465b71"), + ColourDark = OsuColour.FromHex(@"3f5265"), + }, + }, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new Drawable[] + { + new Header + { + RelativeSizeAxes = Axes.X, + }, + filter = new FilterControl + { + RelativeSizeAxes = Axes.X, + }, + }, + }, + }; + + filter.Search.Exit = Hide; + } + + protected override void PopIn() + { + base.PopIn(); + + filter.Search.HoldFocus = true; + Schedule(() => filter.Search.TriggerFocus()); + } + + protected override void PopOut() + { + base.PopOut(); + + filter.Search.HoldFocus = false; + } + } +} diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 71d020b0f2..61e1ee0832 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -85,6 +85,7 @@ namespace osu.Game.Screens.Menu } buttons.OnSettings = game.ToggleSettings; + buttons.OnDirect = game.ToggleDirect; preloadSongSelect(); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 63acdb1914..96a823c9e7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -428,6 +428,11 @@ + + + + + @@ -450,6 +455,9 @@ + + +