diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index f52fecfd02..ee66f53ddc 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -65,17 +65,19 @@ namespace osu.Game.Tests.Visual foreach (var rulesetInfo in rulesets.AvailableRulesets) { - var ruleset = rulesetInfo.CreateInstance(); + var instance = rulesetInfo.CreateInstance(); var testBeatmap = createTestBeatmap(rulesetInfo); beatmaps.Add(testBeatmap); + AddStep("set ruleset", () => Ruleset.Value = rulesetInfo); + selectBeatmap(testBeatmap); - testBeatmapLabels(ruleset); + testBeatmapLabels(instance); // TODO: adjust cases once more info is shown for other gamemodes - switch (ruleset) + switch (instance) { case OsuRuleset _: testInfoLabels(5); diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index 3255478bea..73c37348d5 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual foreach (var rulesetInfo in rulesets.AvailableRulesets) { Ruleset ruleset = rulesetInfo.CreateInstance(); - AddStep($"switch to {ruleset.Description}", () => modSelect.Ruleset.Value = rulesetInfo); + AddStep($"switch to {ruleset.Description}", () => Ruleset.Value = rulesetInfo); switch (ruleset) { diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index 5f57fb76b0..0bb33930b0 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -11,9 +11,9 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Game.Configuration; using System; -using System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Graphics.Textures; +using OpenTK.Input; namespace osu.Game.Graphics.Cursor { @@ -25,9 +25,8 @@ namespace osu.Game.Graphics.Cursor protected override Drawable CreateCursor() => new Cursor(); private Bindable cursorRotate; - private bool dragging; - - private bool startRotation; + private DragRotationState dragRotationState; + private Vector2 positionMouseDown; [BackgroundDependencyLoader(true)] private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager) @@ -40,18 +39,18 @@ namespace osu.Game.Graphics.Cursor protected override bool OnMouseMove(InputState state) { - if (cursorRotate && dragging) + if (dragRotationState != DragRotationState.NotDragging) { - Debug.Assert(state.Mouse.PositionMouseDown != null); - + var position = state.Mouse.Position; + var distance = Vector2Extensions.Distance(position, positionMouseDown); // don't start rotating until we're moved a minimum distance away from the mouse down location, // else it can have an annoying effect. - // ReSharper disable once PossibleInvalidOperationException - startRotation |= Vector2Extensions.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30; - - if (startRotation) + if (dragRotationState == DragRotationState.DragStarted && distance > 30) + dragRotationState = DragRotationState.Rotating; + // don't rotate when distance is zero to avoid NaN + if (dragRotationState == DragRotationState.Rotating && distance > 0) { - Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value; + Vector2 offset = state.Mouse.Position - positionMouseDown; float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f; // Always rotate in the direction of least distance @@ -67,12 +66,6 @@ namespace osu.Game.Graphics.Cursor return base.OnMouseMove(state); } - protected override bool OnDragStart(InputState state) - { - dragging = true; - return base.OnDragStart(state); - } - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { ActiveCursor.Scale = new Vector2(1); @@ -80,6 +73,12 @@ namespace osu.Game.Graphics.Cursor ((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0; ((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint); + + if (args.Button == MouseButton.Left && cursorRotate) + { + dragRotationState = DragRotationState.DragStarted; + positionMouseDown = state.Mouse.Position; + } return base.OnMouseDown(state, args); } @@ -87,14 +86,16 @@ namespace osu.Game.Graphics.Cursor { if (!state.Mouse.HasMainButtonPressed) { - dragging = false; - startRotation = false; - ((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint); - ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf); ActiveCursor.ScaleTo(1, 500, Easing.OutElastic); } + if (args.Button == MouseButton.Left) + { + if (dragRotationState == DragRotationState.Rotating) + ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf); + dragRotationState = DragRotationState.NotDragging; + } return base.OnMouseUp(state, args); } @@ -160,5 +161,12 @@ namespace osu.Game.Graphics.Cursor cursorScale.TriggerChange(); } } + + private enum DragRotationState + { + NotDragging, + DragStarted, + Rotating, + } } } diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index fced2e5d95..83ffd415ae 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -45,7 +45,9 @@ namespace osu.Game.Input.Bindings public IEnumerable InGameKeyBindings => new[] { new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene), - new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry) + new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry), + new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed), + new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed), }; protected override IEnumerable KeyBindingInputQueue => @@ -85,6 +87,12 @@ namespace osu.Game.Input.Bindings ToggleGameplayMouseButtons, [Description("Go back")] - Back + Back, + + [Description("Increase scroll speed")] + IncreaseScrollSpeed, + + [Description("Decrease scroll speed")] + DecreaseScrollSpeed, } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 3b6bb565b0..bbaaa0c756 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -49,7 +49,7 @@ namespace osu.Game.Online.API.Requests.Responses private DateTimeOffset submitted { get; set; } [JsonProperty(@"ranked_date")] - private DateTimeOffset ranked { get; set; } + private DateTimeOffset? ranked { get; set; } [JsonProperty(@"last_updated")] private DateTimeOffset lastUpdated { get; set; } diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 5f90ec67ad..d90a850f4a 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -6,16 +6,16 @@ using System.Linq; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using OpenTK; using OpenTK.Graphics; using OpenTK.Input; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Dialog { @@ -23,6 +23,9 @@ namespace osu.Game.Overlays.Dialog { public static readonly float ENTER_DURATION = 500; public static readonly float EXIT_DURATION = 200; + + protected override bool BlockPassThroughMouse => false; + private readonly Vector2 ringSize = new Vector2(100f); private readonly Vector2 ringMinifiedSize = new Vector2(20f); private readonly Vector2 buttonsEnterSpacing = new Vector2(0f, 50f); @@ -34,26 +37,28 @@ namespace osu.Game.Overlays.Dialog private readonly SpriteText header; private readonly TextFlowContainer body; + private bool actionInvoked; + public FontAwesome Icon { - get { return icon.Icon; } - set { icon.Icon = value; } + get => icon.Icon; + set => icon.Icon = value; } public string HeaderText { - get { return header.Text; } - set { header.Text = value; } + get => header.Text; + set => header.Text = value; } public string BodyText { - set { body.Text = value; } + set => body.Text = value; } public IEnumerable Buttons { - get { return buttonsContainer.Children; } + get => buttonsContainer.Children; set { buttonsContainer.ChildrenEnumerable = value; @@ -62,71 +67,17 @@ namespace osu.Game.Overlays.Dialog var action = b.Action; b.Action = () => { + if (actionInvoked) return; + Hide(); + + actionInvoked = true; action?.Invoke(); }; } } } - private void pressButtonAtIndex(int index) - { - if (index < Buttons.Count()) - Buttons.Skip(index).First().TriggerOnClick(); - } - - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) - { - if (args.Repeat) return false; - - if (args.Key == Key.Enter || args.Key == Key.KeypadEnter) - { - Buttons.OfType().FirstOrDefault()?.TriggerOnClick(); - return true; - } - - // press button at number if 1-9 on number row or keypad are pressed - var k = args.Key; - if (k >= Key.Number1 && k <= Key.Number9) - { - pressButtonAtIndex(k - Key.Number1); - return true; - } - - if (k >= Key.Keypad1 && k <= Key.Keypad9) - { - pressButtonAtIndex(k - Key.Keypad1); - return true; - } - - return base.OnKeyDown(state, args); - } - - protected override void PopIn() - { - base.PopIn(); - - // Reset various animations but only if the dialog animation fully completed - if (content.Alpha == 0) - { - buttonsContainer.TransformSpacingTo(buttonsEnterSpacing); - buttonsContainer.MoveToY(buttonsEnterSpacing.Y); - ring.ResizeTo(ringMinifiedSize); - } - - content.FadeIn(ENTER_DURATION, Easing.OutQuint); - ring.ResizeTo(ringSize, ENTER_DURATION, Easing.OutQuint); - buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, Easing.OutQuint); - buttonsContainer.MoveToY(0, ENTER_DURATION, Easing.OutQuint); - } - - protected override void PopOut() - { - base.PopOut(); - - content.FadeOut(EXIT_DURATION, Easing.InSine); - } - public PopupDialog() { RelativeSizeAxes = Axes.Both; @@ -136,9 +87,6 @@ namespace osu.Game.Overlays.Dialog content = new Container { RelativeSizeAxes = Axes.Both, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Width = 0.4f, Alpha = 0f, Children = new Drawable[] { @@ -243,5 +191,69 @@ namespace osu.Game.Overlays.Dialog }, }; } + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Repeat) return false; + + if (args.Key == Key.Enter || args.Key == Key.KeypadEnter) + { + Buttons.OfType().FirstOrDefault()?.TriggerOnClick(); + return true; + } + + // press button at number if 1-9 on number row or keypad are pressed + var k = args.Key; + if (k >= Key.Number1 && k <= Key.Number9) + { + pressButtonAtIndex(k - Key.Number1); + return true; + } + + if (k >= Key.Keypad1 && k <= Key.Keypad9) + { + pressButtonAtIndex(k - Key.Keypad1); + return true; + } + + return base.OnKeyDown(state, args); + } + + protected override void PopIn() + { + base.PopIn(); + + actionInvoked = false; + + // Reset various animations but only if the dialog animation fully completed + if (content.Alpha == 0) + { + buttonsContainer.TransformSpacingTo(buttonsEnterSpacing); + buttonsContainer.MoveToY(buttonsEnterSpacing.Y); + ring.ResizeTo(ringMinifiedSize); + } + + content.FadeIn(ENTER_DURATION, Easing.OutQuint); + ring.ResizeTo(ringSize, ENTER_DURATION, Easing.OutQuint); + buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, Easing.OutQuint); + buttonsContainer.MoveToY(0, ENTER_DURATION, Easing.OutQuint); + } + + protected override void PopOut() + { + if (!actionInvoked) + // In the case a user did not choose an action before a hide was triggered, press the last button. + // This is presumed to always be a sane default "cancel" action. + buttonsContainer.Last().TriggerOnClick(); + + base.PopOut(); + content.FadeOut(EXIT_DURATION, Easing.InSine); + } + + private void pressButtonAtIndex(int index) + { + if (index < Buttons.Count()) + Buttons.Skip(index).First().TriggerOnClick(); + } } } diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index e26a3cba2f..c40f517023 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -1,12 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Overlays.Dialog; -using OpenTK.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; namespace osu.Game.Overlays @@ -16,6 +13,20 @@ namespace osu.Game.Overlays private readonly Container dialogContainer; private PopupDialog currentDialog; + public DialogOverlay() + { + RelativeSizeAxes = Axes.Both; + + Child = dialogContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }; + + Width = 0.4f; + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + } + public void Push(PopupDialog dialog) { if (dialog == currentDialog) return; @@ -32,6 +43,8 @@ namespace osu.Game.Overlays protected override bool PlaySamplesOnStateChange => false; + protected override bool BlockPassThroughKeyboard => true; + private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v) { if (v != Visibility.Hidden) return; @@ -52,32 +65,14 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine); - } - public DialogOverlay() - { - RelativeSizeAxes = Axes.Both; - - Children = new Drawable[] + if (currentDialog?.State == Visibility.Visible) { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.5f), - }, - }, - }, - dialogContainer = new Container - { - RelativeSizeAxes = Axes.Both, - }, - }; + currentDialog.Hide(); + return; + } + + this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine); } } } diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 48b7907572..c584a32a82 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Mods public readonly Bindable> SelectedMods = new Bindable>(); - public readonly Bindable Ruleset = new Bindable(); + public readonly IBindable Ruleset = new Bindable(); private void rulesetChanged(RulesetInfo newRuleset) { @@ -51,8 +51,8 @@ namespace osu.Game.Overlays.Mods refreshSelectedMods(); } - [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuColour colours, Bindable ruleset, RulesetStore rulesets, AudioManager audio) + [BackgroundDependencyLoader] + private void load(OsuColour colours, IBindable ruleset, AudioManager audio) { SelectedMods.ValueChanged += selectedModsChanged; @@ -60,13 +60,8 @@ namespace osu.Game.Overlays.Mods HighMultiplierColour = colours.Green; UnrankedLabel.Colour = colours.Blue; - if (ruleset != null) - Ruleset.BindTo(ruleset); - else - Ruleset.Value = rulesets.AvailableRulesets.First(); - - Ruleset.ValueChanged += rulesetChanged; - Ruleset.TriggerChange(); + Ruleset.BindTo(ruleset); + Ruleset.BindValueChanged(rulesetChanged, true); sampleOn = audio.Sample.Get(@"UI/check-on"); sampleOff = audio.Sample.Get(@"UI/check-off"); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 930b3c1eaa..18a371e904 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -56,7 +56,13 @@ namespace osu.Game.Overlays.Settings.Sections reloadSkins(); - skinDropdown.Bindable = config.GetBindable(OsuSetting.Skin); + var skinBindable = config.GetBindable(OsuSetting.Skin); + + // Todo: This should not be necessary when OsuConfigManager is databased + if (skinDropdown.Items.All(s => s.Value != skinBindable.Value)) + skinBindable.Value = 0; + + skinDropdown.Bindable = skinBindable; } private void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair(s.ToString(), s.ID)); diff --git a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs index 6926502d9b..dae4f84b1a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Toolbar }; } - [BackgroundDependencyLoader(true)] + [BackgroundDependencyLoader] private void load(RulesetStore rulesets, Bindable parentRuleset) { this.rulesets = rulesets; @@ -82,11 +82,7 @@ namespace osu.Game.Overlays.Toolbar ruleset.ValueChanged += rulesetChanged; ruleset.DisabledChanged += disabledChanged; - - if (parentRuleset != null) - ruleset.BindTo(parentRuleset); - else - ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault(); + ruleset.BindTo(parentRuleset); } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 172b866505..cfcfca157b 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -4,30 +4,33 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Input; +using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using osu.Game.Rulesets.Objects.Drawables; -using OpenTK.Input; namespace osu.Game.Rulesets.UI.Scrolling { /// /// A type of specialized towards scrolling s. /// - public abstract class ScrollingPlayfield : Playfield + public abstract class ScrollingPlayfield : Playfield, IKeyBindingHandler { /// /// The default span of time visible by the length of the scrolling axes. /// This is clamped between and . /// private const double time_span_default = 1500; + /// /// The minimum span of time that may be visible by the length of the scrolling axes. /// private const double time_span_min = 50; + /// /// The maximum span of time that may be visible by the length of the scrolling axes. /// private const double time_span_max = 10000; + /// /// The step increase/decrease of the span of time visible by the length of the scrolling axes. /// @@ -78,27 +81,26 @@ namespace osu.Game.Rulesets.UI.Scrolling HitObjects.TimeRange.BindTo(VisibleTimeRange); } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + public bool OnPressed(GlobalAction action) { if (!UserScrollSpeedAdjustment) return false; - if (state.Keyboard.ControlPressed) + switch (action) { - switch (args.Key) - { - case Key.Minus: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 600, Easing.OutQuint); - break; - case Key.Plus: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 600, Easing.OutQuint); - break; - } + case GlobalAction.IncreaseScrollSpeed: + this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 200, Easing.OutQuint); + return true; + case GlobalAction.DecreaseScrollSpeed: + this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 200, Easing.OutQuint); + return true; } return false; } + public bool OnReleased(GlobalAction action) => false; + protected sealed override HitObjectContainer CreateHitObjectContainer() { var container = new ScrollingHitObjectContainer(); diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index a75bbbce87..2a7daff3d0 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -82,11 +82,8 @@ namespace osu.Game.Screens [BackgroundDependencyLoader(true)] private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable ruleset) { - if (beatmap != null) - Beatmap.BindTo(beatmap); - - if (ruleset != null) - Ruleset.BindTo(ruleset); + Beatmap.BindTo(beatmap); + Ruleset.BindTo(ruleset); if (osu != null) { diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 27089311f2..d26702fcf9 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -55,8 +55,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader(true)] private void load([CanBeNull] Bindable parentRuleset) { - if (parentRuleset != null) - ruleset.BindTo(parentRuleset); + ruleset.BindTo(parentRuleset); ruleset.ValueChanged += _ => updateDisplay(); } diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 39f1a523ea..278d32b2d5 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -29,6 +29,7 @@ namespace osu.Game.Screens.Select private readonly TabControl groupTabs; private SortMode sort = SortMode.Title; + public SortMode Sort { get { return sort; } @@ -43,6 +44,7 @@ namespace osu.Game.Screens.Select } private GroupMode group = GroupMode.All; + public GroupMode Group { get { return group; } @@ -69,7 +71,8 @@ namespace osu.Game.Screens.Select private readonly SearchTextBox searchTextBox; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => base.ReceiveMouseInputAt(screenSpacePos) || groupTabs.ReceiveMouseInputAt(screenSpacePos) || sortTabs.ReceiveMouseInputAt(screenSpacePos); + public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => + base.ReceiveMouseInputAt(screenSpacePos) || groupTabs.ReceiveMouseInputAt(screenSpacePos) || sortTabs.ReceiveMouseInputAt(screenSpacePos); public FilterControl() { @@ -177,8 +180,7 @@ namespace osu.Game.Screens.Select showConverted = config.GetBindable(OsuSetting.ShowConvertedBeatmaps); showConverted.ValueChanged += val => updateCriteria(); - if (parentRuleset != null) - ruleset.BindTo(parentRuleset); + ruleset.BindTo(parentRuleset); ruleset.BindValueChanged(val => updateCriteria(), true); } diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index ac6154369d..c171e791d2 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -40,7 +40,10 @@ namespace osu.Game.Screens.Select.Leaderboards private ScheduledDelegate showScoresDelegate; + private bool scoresLoadedOnce; + private IEnumerable scores; + public IEnumerable Scores { get { return scores; } @@ -48,6 +51,8 @@ namespace osu.Game.Screens.Select.Leaderboards { scores = value; + scoresLoadedOnce = true; + scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire(); scrollFlow = null; @@ -196,9 +201,7 @@ namespace osu.Game.Screens.Select.Leaderboards { this.api = api; - if (parentRuleset != null) - ruleset.BindTo(parentRuleset); - + ruleset.BindTo(parentRuleset); ruleset.ValueChanged += _ => updateScores(); if (api != null) @@ -227,6 +230,10 @@ namespace osu.Game.Screens.Select.Leaderboards private void updateScores() { + // don't display any scores or placeholder until the first Scores_Set has been called. + // this avoids scope changes flickering a "no scores" placeholder before initialisation of song select is finished. + if (!scoresLoadedOnce) return; + getScoresRequest?.Cancel(); getScoresRequest = null; diff --git a/osu.Game/Tests/Visual/OsuTestCase.cs b/osu.Game/Tests/Visual/OsuTestCase.cs index 1740658da6..5f70055021 100644 --- a/osu.Game/Tests/Visual/OsuTestCase.cs +++ b/osu.Game/Tests/Visual/OsuTestCase.cs @@ -1,10 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Configuration; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Rulesets; namespace osu.Game.Tests.Visual { @@ -13,6 +16,8 @@ namespace osu.Game.Tests.Visual private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap()); protected BindableBeatmap Beatmap => beatmap; + protected readonly Bindable Ruleset = new Bindable(); + protected DependencyContainer Dependencies { get; private set; } protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) @@ -22,13 +27,18 @@ namespace osu.Game.Tests.Visual Dependencies.CacheAs(beatmap); Dependencies.CacheAs(beatmap); + Dependencies.CacheAs(Ruleset); + Dependencies.CacheAs>(Ruleset); + return Dependencies; } [BackgroundDependencyLoader] - private void load(AudioManager audioManager) + private void load(AudioManager audioManager, RulesetStore rulesets) { beatmap.SetAudioManager(audioManager); + + Ruleset.Value = rulesets.AvailableRulesets.First(); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 20c9646aa3..9afb1dd6cd 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -86,7 +86,11 @@ namespace osu.Game.Tests.Visual private readonly WeakList workingWeakReferences = new WeakList(); private readonly WeakList playerWeakReferences = new WeakList(); - private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); + private Player loadPlayerFor(RulesetInfo ri) + { + Ruleset.Value = ri; + return loadPlayerFor(ri.CreateInstance()); + } private Player loadPlayerFor(Ruleset r) {