From a759cf2dabd9a5cc4fd4fad57789007845d3699c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 May 2022 02:39:54 +0900 Subject: [PATCH 1/5] Add key binding to deselect all mods Defaults to `Backspace`. --- .../UserInterface/TestSceneModSelectOverlay.cs | 18 +++++++++++++++++- .../Input/Bindings/GlobalActionContainer.cs | 4 ++++ .../GlobalActionKeyBindingStrings.cs | 5 +++++ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 0b037a10cd..e946524a4b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -416,6 +416,22 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("unimplemented mod panel is filtered", () => getPanelForMod(typeof(TestUnimplementedMod)).Filtered.Value); } + [Test] + public void TestDeselectAllViaKey() + { + createScreen(); + changeRuleset(0); + + AddStep("select DT + HD", () => SelectedMods.Value = new Mod[] { new OsuModDoubleTime(), new OsuModHidden() }); + AddAssert("DT + HD selected", () => modSelectOverlay.ChildrenOfType().Count(panel => panel.Active.Value) == 2); + + AddStep("press bakcspace", () => + { + InputManager.Key(Key.BackSpace); + }); + AddUntilStep("all mods deselected", () => !SelectedMods.Value.Any()); + } + [Test] public void TestDeselectAllViaButton() { diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 13a3f006fb..69ea6b00ca 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -109,6 +109,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.F2, GlobalAction.SelectNextRandom), new KeyBinding(new[] { InputKey.Shift, InputKey.F2 }, GlobalAction.SelectPreviousRandom), new KeyBinding(InputKey.F3, GlobalAction.ToggleBeatmapOptions), + new KeyBinding(InputKey.BackSpace, GlobalAction.DeselectAllMods), }; public IEnumerable AudioControlKeyBindings => new[] @@ -318,5 +319,8 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectNextGroup))] SelectNextGroup, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.DeselectAllMods))] + DeselectAllMods, } } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index b2f25de7f2..399e286478 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -209,6 +209,11 @@ namespace osu.Game.Localisation /// public static LocalisableString ToggleModSelection => new TranslatableString(getKey(@"toggle_mod_selection"), @"Toggle Mod Select"); + /// + /// "Deselect all mods" + /// + public static LocalisableString DeselectAllMods => new TranslatableString(getKey(@"deselect_all_mods"), @"Deselect all mods"); + /// /// "Random" /// diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index d068839ab0..fb988b5bfe 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -508,6 +508,10 @@ namespace osu.Game.Overlays.Mods hideOverlay(true); return true; } + + case GlobalAction.DeselectAllMods: + DeselectAll(); + return true; } return base.OnPressed(e); From 6c3a4375c529ff4940c37fa376b17b1eff1a2a99 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 May 2022 02:40:35 +0900 Subject: [PATCH 2/5] Fix case of "toggle mod select" string --- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 399e286478..e392ae619f 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -207,7 +207,7 @@ namespace osu.Game.Localisation /// /// "Toggle Mod Select" /// - public static LocalisableString ToggleModSelection => new TranslatableString(getKey(@"toggle_mod_selection"), @"Toggle Mod Select"); + public static LocalisableString ToggleModSelection => new TranslatableString(getKey(@"toggle_mod_selection"), @"Toggle mod select"); /// /// "Deselect all mods" From 282c8aec867ad5adb889bd4b7f7bb488051b8098 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 May 2022 03:09:15 +0900 Subject: [PATCH 3/5] Fix typo in test step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index e946524a4b..2cc9a451a8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -425,7 +425,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("select DT + HD", () => SelectedMods.Value = new Mod[] { new OsuModDoubleTime(), new OsuModHidden() }); AddAssert("DT + HD selected", () => modSelectOverlay.ChildrenOfType().Count(panel => panel.Active.Value) == 2); - AddStep("press bakcspace", () => + AddStep("press backspace", () => { InputManager.Key(Key.BackSpace); }); From 8a01050168038c41c6f8fc33d77848b91b85ccbb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 May 2022 03:16:33 +0900 Subject: [PATCH 4/5] Refactor mod select button initialisation to allow shared usage of deselect button --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 43 +++++++++++-------- .../OnlinePlay/FreeModSelectOverlay.cs | 16 +++---- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index fb988b5bfe..1dad185b78 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -56,11 +56,32 @@ namespace osu.Game.Overlays.Mods /// protected virtual bool ShowTotalMultiplier => true; + /// + /// Whether per-mod customisation controls are visible. + /// + protected virtual bool AllowCustomisation => true; + protected virtual ModColumn CreateModColumn(ModType modType, Key[]? toggleKeys = null) => new ModColumn(modType, false, toggleKeys); protected virtual IReadOnlyList ComputeNewModsFromSelection(IReadOnlyList oldSelection, IReadOnlyList newSelection) => newSelection; - protected virtual IEnumerable CreateFooterButtons() => createDefaultFooterButtons(); + protected virtual IEnumerable CreateFooterButtons() + { + if (AllowCustomisation) + { + yield return customisationButton = new ShearedToggleButton(BUTTON_WIDTH) + { + Text = ModSelectOverlayStrings.ModCustomisation, + Active = { BindTarget = customisationVisible } + }; + } + + yield return deselectAllButton = new ShearedButton(BUTTON_WIDTH) + { + Text = CommonStrings.DeselectAll, + Action = DeselectAll + }; + } private readonly Bindable>> availableMods = new Bindable>>(); private readonly Dictionary> localAvailableMods = new Dictionary>(); @@ -77,6 +98,7 @@ namespace osu.Game.Overlays.Mods private DifficultyMultiplierDisplay? multiplierDisplay; private ShearedToggleButton? customisationButton; + private ShearedButton? deselectAllButton; protected ModSelectOverlay(OverlayColourScheme colourScheme = OverlayColourScheme.Green) : base(colourScheme) @@ -201,7 +223,7 @@ namespace osu.Game.Overlays.Mods // This is an optimisation to prevent refreshing the available settings controls when it can be // reasonably assumed that the settings panel is never to be displayed (e.g. FreeModSelectOverlay). - if (customisationButton != null) + if (AllowCustomisation) ((IBindable>)modSettingsArea.SelectedMods).BindTo(SelectedMods); SelectedMods.BindValueChanged(val => @@ -256,21 +278,6 @@ namespace osu.Game.Overlays.Mods }; } - private ShearedButton[] createDefaultFooterButtons() - => new[] - { - customisationButton = new ShearedToggleButton(BUTTON_WIDTH) - { - Text = ModSelectOverlayStrings.ModCustomisation, - Active = { BindTarget = customisationVisible } - }, - new ShearedButton(BUTTON_WIDTH) - { - Text = CommonStrings.DeselectAll, - Action = DeselectAll - } - }; - private void createLocalMods() { localAvailableMods.Clear(); @@ -510,7 +517,7 @@ namespace osu.Game.Overlays.Mods } case GlobalAction.DeselectAllMods: - DeselectAll(); + deselectAllButton?.TriggerClick(); return true; } diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs index 6e1c9b7a59..790333ea5b 100644 --- a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs @@ -4,6 +4,7 @@ using System; using osu.Game.Overlays; using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; @@ -17,6 +18,8 @@ namespace osu.Game.Screens.OnlinePlay { protected override bool ShowTotalMultiplier => false; + protected override bool AllowCustomisation => false; + public new Func IsValidMod { get => base.IsValidMod; @@ -31,22 +34,13 @@ namespace osu.Game.Screens.OnlinePlay protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new ModColumn(modType, true, toggleKeys); - protected override IEnumerable CreateFooterButtons() => new[] - { + protected override IEnumerable CreateFooterButtons() => base.CreateFooterButtons().Prepend( new ShearedButton(BUTTON_WIDTH) { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = CommonStrings.SelectAll, Action = SelectAll - }, - new ShearedButton(BUTTON_WIDTH) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Text = CommonStrings.DeselectAll, - Action = DeselectAll - } - }; + }); } } From b6575c216b8945bceee462216d87b4ac79d7e0a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 May 2022 03:18:44 +0900 Subject: [PATCH 5/5] Allow selecting all mods at free mod select using `ctrl`+`a` --- .../TestSceneFreeModSelectOverlay.cs | 13 +++++++++ .../TestSceneModSelectOverlay.cs | 5 +--- .../OnlinePlay/FreeModSelectOverlay.cs | 28 +++++++++++++++++-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs index f40c31b07f..c37bff2066 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; @@ -55,6 +56,18 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("customisation area not expanded", () => this.ChildrenOfType().Single().Height == 0); } + [Test] + public void TestSelectDeselectAllViaKeyboard() + { + createFreeModSelect(); + + AddStep("press ctrl+a", () => InputManager.Keys(PlatformAction.SelectAll)); + AddUntilStep("all mods selected", assertAllAvailableModsSelected); + + AddStep("press backspace", () => InputManager.Key(Key.BackSpace)); + AddUntilStep("all mods deselected", () => !freeModSelectOverlay.SelectedMods.Value.Any()); + } + [Test] public void TestSelectDeselectAll() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 2cc9a451a8..75e30f76c3 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -425,10 +425,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("select DT + HD", () => SelectedMods.Value = new Mod[] { new OsuModDoubleTime(), new OsuModHidden() }); AddAssert("DT + HD selected", () => modSelectOverlay.ChildrenOfType().Count(panel => panel.Active.Value) == 2); - AddStep("press backspace", () => - { - InputManager.Key(Key.BackSpace); - }); + AddStep("press backspace", () => InputManager.Key(Key.BackSpace)); AddUntilStep("all mods deselected", () => !SelectedMods.Value.Any()); } diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs index 790333ea5b..f494f9799a 100644 --- a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs @@ -6,6 +6,9 @@ using osu.Game.Overlays; using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; +using osu.Framework.Input; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; @@ -14,7 +17,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.OnlinePlay { - public class FreeModSelectOverlay : ModSelectOverlay + public class FreeModSelectOverlay : ModSelectOverlay, IKeyBindingHandler { protected override bool ShowTotalMultiplier => false; @@ -26,6 +29,8 @@ namespace osu.Game.Screens.OnlinePlay set => base.IsValidMod = m => m.UserPlayable && value.Invoke(m); } + private ShearedButton selectAllButton; + public FreeModSelectOverlay() : base(OverlayColourScheme.Plum) { @@ -35,12 +40,31 @@ namespace osu.Game.Screens.OnlinePlay protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new ModColumn(modType, true, toggleKeys); protected override IEnumerable CreateFooterButtons() => base.CreateFooterButtons().Prepend( - new ShearedButton(BUTTON_WIDTH) + selectAllButton = new ShearedButton(BUTTON_WIDTH) { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Text = CommonStrings.SelectAll, Action = SelectAll }); + + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Repeat) + return false; + + switch (e.Action) + { + case PlatformAction.SelectAll: + selectAllButton.TriggerClick(); + return true; + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } } }