diff --git a/osu-framework b/osu-framework index 5dbb4a5134..798409058a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 5dbb4a5134dacb2e98ab8f2af219039a72bd32e6 +Subproject commit 798409058a421307b5a92aeea4cd60a065f5a0d4 diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatmapOptionsOverlay.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapOptionsOverlay.cs new file mode 100644 index 0000000000..e1914d4b8c --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapOptionsOverlay.cs @@ -0,0 +1,28 @@ +// 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.Screens.Testing; +using osu.Game.Graphics; +using osu.Game.Overlays; +using osu.Game.Screens.Select.Options; + +namespace osu.Desktop.VisualTests +{ + class TestCaseBeatmapOptionsOverlay : TestCase + { + public override string Name => @"Beatmap Options"; + public override string Description => @"Beatmap options in song select"; + + public override void Reset() + { + base.Reset(); + + var overlay = new BeatmapOptionsOverlay(); + + Add(overlay); + + AddButton(@"Toggle", overlay.ToggleVisibility); + } + } +} diff --git a/osu.Desktop.VisualTests/Tests/TestCasePauseOverlay.cs b/osu.Desktop.VisualTests/Tests/TestCasePauseOverlay.cs index 990b8b3775..8545e50c69 100644 --- a/osu.Desktop.VisualTests/Tests/TestCasePauseOverlay.cs +++ b/osu.Desktop.VisualTests/Tests/TestCasePauseOverlay.cs @@ -2,8 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Logging; -using osu.Game.Overlays.Pause; using osu.Framework.Screens.Testing; +using osu.Game.Screens.Play; namespace osu.Desktop.VisualTests.Tests { diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 85d6d7055e..2aca6694ef 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -195,6 +195,7 @@ + diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index 36cbebf8de..0a1fc5f331 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -52,7 +52,6 @@ namespace osu.Game.Beatmaps.Drawables }, artist = new OsuSpriteText { - Margin = new MarginPadding { Top = -1 }, Font = @"Exo2.0-SemiBoldItalic", Text = beatmap.BeatmapSetInfo.Metadata.Artist, TextSize = 17, diff --git a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs index 85b1a1a338..df48694249 100644 --- a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs @@ -14,6 +14,8 @@ namespace osu.Game.Graphics.UserInterface { protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize); + public override bool AllowClipboardExport => false; + public class PasswordMaskChar : Container { private CircularContainer circle; diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index bd3574b625..25bc7037eb 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -57,10 +57,7 @@ namespace osu.Game.Graphics.UserInterface c1.Origin = c1.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopLeft : Anchor.TopRight; c2.Origin = c2.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopRight : Anchor.TopLeft; - Margin = new MarginPadding - { - Right = (value & Anchor.x2) > 0 ? -SIZE_RETRACTED.X * shear * 0.5f : 0 - }; + X = (value & Anchor.x2) > 0 ? SIZE_RETRACTED.X * shear * 0.5f : 0; c1.Depth = (value & Anchor.x2) > 0 ? 0 : 1; c2.Depth = (value & Anchor.x2) > 0 ? 1 : 0; diff --git a/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs b/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs index b06644facd..db799ccae2 100644 --- a/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs +++ b/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs @@ -117,7 +117,8 @@ namespace osu.Game.Overlays.Options.Sections.General { PlaceholderText = "Password", RelativeSizeAxes = Axes.X, - TabbableContentContainer = this + TabbableContentContainer = this, + OnCommit = (TextBox sender, bool newText) => performLogin() }, new OsuCheckbox { diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 74cfc10e75..948b9c96fc 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -55,7 +55,10 @@ namespace osu.Game.Overlays.Toolbar }, modeSelector = new ToolbarModeSelector { - OnPlayModeChange = OnPlayModeChange + OnPlayModeChange = (PlayMode mode) => + { + OnPlayModeChange?.Invoke(mode); + } } } }, diff --git a/osu.Game/Overlays/Pause/PauseProgressBar.cs b/osu.Game/Screens/Play/Pause/PauseProgressBar.cs similarity index 96% rename from osu.Game/Overlays/Pause/PauseProgressBar.cs rename to osu.Game/Screens/Play/Pause/PauseProgressBar.cs index bd32147e35..8d124706b1 100644 --- a/osu.Game/Overlays/Pause/PauseProgressBar.cs +++ b/osu.Game/Screens/Play/Pause/PauseProgressBar.cs @@ -1,15 +1,15 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using OpenTK.Graphics; -namespace osu.Game.Overlays.Pause +namespace osu.Game.Screens.Play.Pause { public class PauseProgressBar : Container { diff --git a/osu.Game/Overlays/Pause/PauseProgressGraph.cs b/osu.Game/Screens/Play/Pause/PauseProgressGraph.cs similarity index 86% rename from osu.Game/Overlays/Pause/PauseProgressGraph.cs rename to osu.Game/Screens/Play/Pause/PauseProgressGraph.cs index faee80a863..89b9b42b86 100644 --- a/osu.Game/Overlays/Pause/PauseProgressGraph.cs +++ b/osu.Game/Screens/Play/Pause/PauseProgressGraph.cs @@ -3,7 +3,7 @@ using osu.Framework.Graphics.Containers; -namespace osu.Game.Overlays.Pause +namespace osu.Game.Screens.Play.Pause { public class PauseProgressGraph : Container { diff --git a/osu.Game/Overlays/Pause/QuitButton.cs b/osu.Game/Screens/Play/Pause/QuitButton.cs similarity index 90% rename from osu.Game/Overlays/Pause/QuitButton.cs rename to osu.Game/Screens/Play/Pause/QuitButton.cs index 18b7c4eda9..7b71b4b2fc 100644 --- a/osu.Game/Overlays/Pause/QuitButton.cs +++ b/osu.Game/Screens/Play/Pause/QuitButton.cs @@ -1,13 +1,12 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using OpenTK.Graphics; -namespace osu.Game.Overlays.Pause +namespace osu.Game.Screens.Play.Pause { public class QuitButton : DialogButton { diff --git a/osu.Game/Overlays/Pause/ResumeButton.cs b/osu.Game/Screens/Play/Pause/ResumeButton.cs similarity index 91% rename from osu.Game/Overlays/Pause/ResumeButton.cs rename to osu.Game/Screens/Play/Pause/ResumeButton.cs index a5179cb58a..d4f7555d3c 100644 --- a/osu.Game/Overlays/Pause/ResumeButton.cs +++ b/osu.Game/Screens/Play/Pause/ResumeButton.cs @@ -6,7 +6,7 @@ using osu.Framework.Audio; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Overlays.Pause +namespace osu.Game.Screens.Play.Pause { public class ResumeButton : DialogButton { diff --git a/osu.Game/Overlays/Pause/RetryButton.cs b/osu.Game/Screens/Play/Pause/RetryButton.cs similarity index 91% rename from osu.Game/Overlays/Pause/RetryButton.cs rename to osu.Game/Screens/Play/Pause/RetryButton.cs index ceab835915..8f660525c3 100644 --- a/osu.Game/Overlays/Pause/RetryButton.cs +++ b/osu.Game/Screens/Play/Pause/RetryButton.cs @@ -6,7 +6,7 @@ using osu.Framework.Audio; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Overlays.Pause +namespace osu.Game.Screens.Play.Pause { public class RetryButton : DialogButton { diff --git a/osu.Game/Overlays/Pause/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs similarity index 96% rename from osu.Game/Overlays/Pause/PauseOverlay.cs rename to osu.Game/Screens/Play/PauseOverlay.cs index 5c85f3db9e..8004f967ad 100644 --- a/osu.Game/Overlays/Pause/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -2,19 +2,20 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using OpenTK; -using OpenTK.Input; -using OpenTK.Graphics; -using osu.Game.Graphics; -using osu.Framework.Input; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Transforms; +using osu.Framework.Input; +using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Play.Pause; +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Input; -namespace osu.Game.Overlays.Pause +namespace osu.Game.Screens.Play { public class PauseOverlay : OverlayContainer { diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0a094d2050..4dc6db7aac 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -16,7 +16,6 @@ using osu.Framework.Screens; using osu.Game.Modes.UI; using osu.Game.Screens.Ranking; using osu.Game.Configuration; -using osu.Game.Overlays.Pause; using osu.Framework.Configuration; using System; using System.Linq; diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index a8216d3e4e..49f864d4e0 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs @@ -8,7 +8,7 @@ using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Overlays.Dialog; -namespace osu.Game +namespace osu.Game.Screens.Select { public class BeatmapDeleteDialog : PopupDialog { diff --git a/osu.Game/Screens/Select/CarouselContainer.cs b/osu.Game/Screens/Select/CarouselContainer.cs index bb391c2eb7..5d8c11d223 100644 --- a/osu.Game/Screens/Select/CarouselContainer.cs +++ b/osu.Game/Screens/Select/CarouselContainer.cs @@ -192,8 +192,10 @@ namespace osu.Game.Screens.Select ScrollTo(selectedY, animated); } - public void Sort(FilterControl.SortMode mode) { - switch (mode) { + public void Sort(FilterControl.SortMode mode) + { + switch (mode) + { case FilterControl.SortMode.Artist: groups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Artist, y.BeatmapSet.Metadata.Artist)); break; @@ -206,15 +208,17 @@ namespace osu.Game.Screens.Select case FilterControl.SortMode.Difficulty: groups.Sort((x, y) => { - float xAverage=0, yAverage=0; - int counter=0; - foreach (BeatmapInfo set in x.BeatmapSet.Beatmaps) { + float xAverage = 0, yAverage = 0; + int counter = 0; + foreach (BeatmapInfo set in x.BeatmapSet.Beatmaps) + { xAverage += set.StarDifficulty; counter++; } xAverage /= counter; counter = 0; - foreach (BeatmapInfo set in y.BeatmapSet.Beatmaps) { + foreach (BeatmapInfo set in y.BeatmapSet.Beatmaps) + { yAverage += set.StarDifficulty; counter++; } @@ -241,7 +245,7 @@ namespace osu.Game.Screens.Select scrollableContent.Add(panel); } } - SelectGroup(groups.FirstOrDefault(), groups.First().BeatmapPanels.FirstOrDefault()); + } private static float offsetX(float dist, float halfHeight) @@ -344,7 +348,7 @@ namespace osu.Game.Screens.Select public void SelectNext(int direction = 1, bool skipDifficulties = true) { - if (!skipDifficulties) + if (!skipDifficulties && SelectedGroup != null) { int i = SelectedGroup.BeatmapPanels.IndexOf(SelectedPanel) + direction; diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs new file mode 100644 index 0000000000..6e68b7917b --- /dev/null +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -0,0 +1,152 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Select.Options +{ + public class BeatmapOptionsButton : ClickableContainer + { + private static readonly float width = 130; + + private Box background, flash; + private TextAwesome iconText; + private OsuSpriteText firstLine, secondLine; + private Container box; + + public Color4 ButtonColour + { + get { return background.Colour; } + set { background.Colour = value; } + } + + public FontAwesome Icon + { + get { return iconText.Icon; } + set { iconText.Icon = value; } + } + + public string FirstLineText + { + get { return firstLine.Text; } + set { firstLine.Text = value; } + } + + public string SecondLineText + { + get { return secondLine.Text; } + set { secondLine.Text = value; } + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + flash.FadeTo(0.1f, 1000, EasingTypes.OutQuint); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + flash.FadeTo(0, 1000, EasingTypes.OutQuint); + return base.OnMouseUp(state, args); + } + + protected override bool OnClick(InputState state) + { + flash.ClearTransforms(); + flash.Alpha = 0.9f; + flash.FadeOut(800, EasingTypes.OutExpo); + + return base.OnClick(state); + } + + public override bool Contains(Vector2 screenSpacePos) => box.Contains(screenSpacePos); + + public BeatmapOptionsButton() + { + Width = width; + RelativeSizeAxes = Axes.Y; + + Children = new Drawable[] + { + box = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Shear = new Vector2(0.2f, 0f), + Masking = true, + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.2f), + Roundness = 5, + Radius = 8, + }, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + EdgeSmoothness = new Vector2(1.5f, 0), + Colour = Color4.Black, + }, + flash = new Box + { + RelativeSizeAxes = Axes.Both, + EdgeSmoothness = new Vector2(1.5f, 0), + BlendingMode = BlendingMode.Additive, + Colour = Color4.White, + Alpha = 0, + }, + }, + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Down, + Children = new Drawable[] + { + iconText = new TextAwesome + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + TextSize = 30, + Shadow = true, + Icon = FontAwesome.fa_close, + Margin = new MarginPadding + { + Bottom = 5, + }, + }, + firstLine = new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Font = @"Exo2.0-Bold", + Text = @"", + }, + secondLine = new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Font = @"Exo2.0-Bold", + Text = @"", + }, + }, + }, + }; + } + } +} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsClearLocalScoresButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsClearLocalScoresButton.cs new file mode 100644 index 0000000000..66a6dac358 --- /dev/null +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsClearLocalScoresButton.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Select.Options +{ + public class BeatmapOptionsClearLocalScoresButton : BeatmapOptionsButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + ButtonColour = colour.Purple; + } + + public BeatmapOptionsClearLocalScoresButton() + { + Icon = FontAwesome.fa_eraser; + FirstLineText = @"Clear"; + SecondLineText = @"local scores"; + } + } +} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsDeleteButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsDeleteButton.cs new file mode 100644 index 0000000000..563cf41a87 --- /dev/null +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsDeleteButton.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Select.Options +{ + public class BeatmapOptionsDeleteButton : BeatmapOptionsButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + ButtonColour = colour.Pink; + } + + public BeatmapOptionsDeleteButton() + { + Icon = FontAwesome.fa_trash; + FirstLineText = @"Delete"; + SecondLineText = @"Beatmap"; + } + } +} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsEditButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsEditButton.cs new file mode 100644 index 0000000000..f88c0df168 --- /dev/null +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsEditButton.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Select.Options +{ + public class BeatmapOptionsEditButton : BeatmapOptionsButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + ButtonColour = colour.Yellow; + } + + public BeatmapOptionsEditButton() + { + Icon = FontAwesome.fa_pencil; + FirstLineText = @"Edit"; + SecondLineText = @"Beatmap"; + } + } +} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs new file mode 100644 index 0000000000..47152dc165 --- /dev/null +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -0,0 +1,139 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Select.Options +{ + public class BeatmapOptionsOverlay : FocusedOverlayContainer + { + private const float transition_duration = 500; + private const float x_position = 290; + + private const float height = 100; + + private Box holder; + private FillFlowContainer buttonsContainer; + + public Action OnRemoveFromUnplayed; + public Action OnClearLocalScores; + public Action OnEdit; + public Action OnDelete; + + protected override void PopIn() + { + base.PopIn(); + + if (buttonsContainer.Position.X >= DrawWidth || buttonsContainer.Alpha <= 0) + buttonsContainer.MoveToX(-buttonsContainer.DrawWidth); + + buttonsContainer.Alpha = 1; + + holder.ScaleTo(new Vector2(1, 1), transition_duration / 2, EasingTypes.OutQuint); + + buttonsContainer.MoveToX(x_position, transition_duration, EasingTypes.OutQuint); + buttonsContainer.TransformSpacingTo(Vector2.Zero, transition_duration, EasingTypes.OutQuint); + } + + protected override void PopOut() + { + base.PopOut(); + + holder.ScaleTo(new Vector2(1, 0), transition_duration / 2, EasingTypes.InSine); + + buttonsContainer.MoveToX(DrawWidth, transition_duration, EasingTypes.InSine); + buttonsContainer.TransformSpacingTo(new Vector2(200f, 0f), transition_duration, EasingTypes.InSine); + + Delay(transition_duration); + Schedule(() => + { + if (State == Visibility.Hidden) + buttonsContainer.Alpha = 0; + }); + } + + public BeatmapOptionsOverlay() + { + AutoSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.X; + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + + Children = new Drawable[] + { + holder = new Box + { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Scale = new Vector2(1, 0), + Colour = Color4.Black.Opacity(0.5f), + }, + buttonsContainer = new ButtonFlow + { + Height = height, + AutoSizeAxes = Axes.X, + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + Children = new BeatmapOptionsButton[] + { + new BeatmapOptionsRemoveFromUnplayedButton + { + Action = () => + { + Hide(); + OnRemoveFromUnplayed?.Invoke(); + }, + }, + new BeatmapOptionsClearLocalScoresButton + { + Action = () => + { + Hide(); + OnClearLocalScores?.Invoke(); + }, + }, + new BeatmapOptionsEditButton + { + Action = () => + { + Hide(); + OnEdit?.Invoke(); + }, + }, + new BeatmapOptionsDeleteButton + { + Action = () => + { + Hide(); + OnDelete?.Invoke(); + }, + }, + }, + }, + }; + } + + class ButtonFlow : FillFlowContainer + { + protected override IComparer DepthComparer => new ReverseCreationOrderDepthComparer(); + protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); + + public ButtonFlow() + { + Direction = FillDirection.Right; + } + } + } +} diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsRemoveFromUnplayedButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsRemoveFromUnplayedButton.cs new file mode 100644 index 0000000000..eeab78ef02 --- /dev/null +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsRemoveFromUnplayedButton.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Select.Options +{ + public class BeatmapOptionsRemoveFromUnplayedButton : BeatmapOptionsButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + ButtonColour = colour.Purple; + } + + public BeatmapOptionsRemoveFromUnplayedButton() + { + Icon = FontAwesome.fa_times_circle_o; + FirstLineText = @"Remove"; + SecondLineText = @"from Unplayed"; + } + } +} diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 4252de2978..a60c39d61b 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -28,12 +28,13 @@ using OpenTK.Input; using System.Collections.Generic; using osu.Framework.Threading; using osu.Game.Overlays; +using osu.Game.Screens.Select.Options; namespace osu.Game.Screens.Select { public class PlaySongSelect : OsuScreen { - private Bindable playMode; + private Bindable playMode = new Bindable(); private BeatmapDatabase database; protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); @@ -52,6 +53,7 @@ namespace osu.Game.Screens.Select private List beatmapGroups; + private BeatmapOptionsOverlay beatmapOptions; private Footer footer; OsuScreen player; @@ -75,7 +77,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader(permitNulls: true)] private void load(BeatmapDatabase beatmaps, AudioManager audio, DialogOverlay dialog, Framework.Game game, - OsuGame osuGame, OsuColour colours) + OsuGame osu, OsuColour colours) { const float carousel_width = 640; const float filter_height = 100; @@ -111,7 +113,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.X, Height = filter_height, - FilterChanged = filterChanged, + FilterChanged = () => filterChanged(), Exit = Exit, }, beatmapInfoWedge = new BeatmapInfoWedge @@ -125,6 +127,17 @@ namespace osu.Game.Screens.Select Right = 20, }, }, + beatmapOptions = new BeatmapOptionsOverlay + { + OnRemoveFromUnplayed = null, + OnClearLocalScores = null, + OnEdit = null, + OnDelete = promptDelete, + Margin = new MarginPadding + { + Bottom = 50, + }, + }, footer = new Footer { OnBack = Exit, @@ -144,13 +157,11 @@ namespace osu.Game.Screens.Select footer.AddButton(@"mods", colours.Yellow, null); footer.AddButton(@"random", colours.Green, carousel.SelectRandom); - footer.AddButton(@"options", colours.Blue, null); + footer.AddButton(@"options", colours.Blue, beatmapOptions.ToggleVisibility); - if (osuGame != null) - { - playMode = osuGame.PlayMode; - playMode.ValueChanged += playMode_ValueChanged; - } + if (osu != null) + playMode.BindTo(osu.PlayMode); + playMode.ValueChanged += playMode_ValueChanged; if (database == null) database = beatmaps; @@ -171,7 +182,7 @@ namespace osu.Game.Screens.Select private ScheduledDelegate filterTask; - private void filterChanged() + private void filterChanged(bool debounce = true, bool eagerSelection = true) { filterTask?.Cancel(); filterTask = Scheduler.AddDelayed(() => @@ -183,25 +194,42 @@ namespace osu.Game.Screens.Select foreach (var beatmapGroup in carousel) { var set = beatmapGroup.BeatmapSet; - bool match = string.IsNullOrEmpty(search) + + bool hasCurrentMode = set.Beatmaps.Any(bm => bm.Mode == playMode); + + bool match = hasCurrentMode; + + match &= string.IsNullOrEmpty(search) || (set.Metadata.Artist ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1 || (set.Metadata.ArtistUnicode ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1 || (set.Metadata.Title ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1 || (set.Metadata.TitleUnicode ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1; + if (match) { - beatmapGroup.State = BeatmapGroupState.Collapsed; if (newSelection == null || beatmapGroup.BeatmapSet.OnlineBeatmapSetID == Beatmap.BeatmapSetInfo.OnlineBeatmapSetID) + { + if (newSelection != null) + newSelection.State = BeatmapGroupState.Collapsed; newSelection = beatmapGroup; + } + else + beatmapGroup.State = BeatmapGroupState.Collapsed; } else { beatmapGroup.State = BeatmapGroupState.Hidden; } } + if (newSelection != null) - carousel.SelectBeatmap(newSelection.BeatmapSet.Beatmaps[0], false); - }, 250); + { + if (newSelection.BeatmapPanels.Any(b => b.Beatmap.ID == Beatmap.BeatmapInfo.ID)) + carousel.SelectBeatmap(Beatmap.BeatmapInfo, false); + else if (eagerSelection) + carousel.SelectBeatmap(newSelection.BeatmapSet.Beatmaps[0], false); + } + }, debounce ? 250 : 0); } private void onBeatmapSetAdded(BeatmapSetInfo s) => Schedule(() => addBeatmapSet(s, Game, true)); @@ -262,8 +290,6 @@ namespace osu.Game.Screens.Select protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - if (playMode != null) - playMode.ValueChanged -= playMode_ValueChanged; database.BeatmapSetAdded -= onBeatmapSetAdded; database.BeatmapSetRemoved -= onBeatmapSetRemoved; @@ -273,6 +299,7 @@ namespace osu.Game.Screens.Select private void playMode_ValueChanged(object sender, EventArgs e) { + filterChanged(false); } private void changeBackground(WorkingBeatmap beatmap) @@ -358,6 +385,8 @@ namespace osu.Game.Screens.Select carousel.AddGroup(group); + filterChanged(false, false); + if (Beatmap == null || select) carousel.SelectBeatmap(beatmapSet.Beatmaps.First()); else @@ -391,7 +420,12 @@ namespace osu.Game.Screens.Select if (token.IsCancellationRequested) return; addBeatmapSet(beatmapSet, game); } - filterChanged(); + } + + private void promptDelete() + { + if (Beatmap != null) + dialogOverlay?.Push(new BeatmapDeleteDialog(Beatmap)); } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) @@ -404,9 +438,7 @@ namespace osu.Game.Screens.Select case Key.Delete: if (state.Keyboard.ShiftPressed) { - if (Beatmap != null) - dialogOverlay?.Push(new BeatmapDeleteDialog(Beatmap)); - + promptDelete(); return true; } break; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1c5996b51e..5b15f71d6a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -274,12 +274,12 @@ - - - - - - + + + + + + @@ -287,6 +287,12 @@ + + + + + + @@ -307,9 +313,7 @@ - - - +