Skip to content

Commit

Permalink
Merge pull request ppy#18264 from peppy/deselect-all-mods-key
Browse files Browse the repository at this point in the history
Add key binding to deselect all mods
  • Loading branch information
bdach authored May 14, 2022
2 parents 6e74244 + b6575c2 commit 351f5a3
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 30 deletions.
13 changes: 13 additions & 0 deletions osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
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;
Expand Down Expand Up @@ -55,6 +56,18 @@ public void TestCustomisationNotAvailable()
AddAssert("customisation area not expanded", () => this.ChildrenOfType<ModSettingsArea>().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()
{
Expand Down
15 changes: 14 additions & 1 deletion osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
Expand Down Expand Up @@ -416,6 +416,19 @@ public void TestUnimplementedModIsUnselectable()
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<ModPanel>().Count(panel => panel.Active.Value) == 2);

AddStep("press backspace", () => InputManager.Key(Key.BackSpace));
AddUntilStep("all mods deselected", () => !SelectedMods.Value.Any());
}

[Test]
public void TestDeselectAllViaButton()
{
Expand Down
4 changes: 4 additions & 0 deletions osu.Game/Input/Bindings/GlobalActionContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ protected override void LoadComplete()
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<KeyBinding> AudioControlKeyBindings => new[]
Expand Down Expand Up @@ -318,5 +319,8 @@ public enum GlobalAction

[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectNextGroup))]
SelectNextGroup,

[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.DeselectAllMods))]
DeselectAllMods,
}
}
7 changes: 6 additions & 1 deletion osu.Game/Localisation/GlobalActionKeyBindingStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,12 @@ public static class GlobalActionKeyBindingStrings
/// <summary>
/// "Toggle Mod Select"
/// </summary>
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");

/// <summary>
/// "Deselect all mods"
/// </summary>
public static LocalisableString DeselectAllMods => new TranslatableString(getKey(@"deselect_all_mods"), @"Deselect all mods");

/// <summary>
/// "Random"
Expand Down
45 changes: 28 additions & 17 deletions osu.Game/Overlays/Mods/ModSelectOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,32 @@ public Func<Mod, bool> IsValidMod
/// </summary>
protected virtual bool ShowTotalMultiplier => true;

/// <summary>
/// Whether per-mod customisation controls are visible.
/// </summary>
protected virtual bool AllowCustomisation => true;

protected virtual ModColumn CreateModColumn(ModType modType, Key[]? toggleKeys = null) => new ModColumn(modType, false, toggleKeys);

protected virtual IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection) => newSelection;

protected virtual IEnumerable<ShearedButton> CreateFooterButtons() => createDefaultFooterButtons();
protected virtual IEnumerable<ShearedButton> 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<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
private readonly Dictionary<ModType, IReadOnlyList<ModState>> localAvailableMods = new Dictionary<ModType, IReadOnlyList<ModState>>();
Expand All @@ -77,6 +98,7 @@ public Func<Mod, bool> IsValidMod
private DifficultyMultiplierDisplay? multiplierDisplay;

private ShearedToggleButton? customisationButton;
private ShearedButton? deselectAllButton;

protected ModSelectOverlay(OverlayColourScheme colourScheme = OverlayColourScheme.Green)
: base(colourScheme)
Expand Down Expand Up @@ -201,7 +223,7 @@ protected override void LoadComplete()

// 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<IReadOnlyList<Mod>>)modSettingsArea.SelectedMods).BindTo(SelectedMods);

SelectedMods.BindValueChanged(val =>
Expand Down Expand Up @@ -256,21 +278,6 @@ private ColumnDimContainer createModColumnContent(ModType modType, Key[]? toggle
};
}

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();
Expand Down Expand Up @@ -508,6 +515,10 @@ public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
hideOverlay(true);
return true;
}

case GlobalAction.DeselectAllMods:
deselectAllButton?.TriggerClick();
return true;
}

return base.OnPressed(e);
Expand Down
40 changes: 29 additions & 11 deletions osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
using System;
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;
Expand All @@ -13,16 +17,20 @@

namespace osu.Game.Screens.OnlinePlay
{
public class FreeModSelectOverlay : ModSelectOverlay
public class FreeModSelectOverlay : ModSelectOverlay, IKeyBindingHandler<PlatformAction>
{
protected override bool ShowTotalMultiplier => false;

protected override bool AllowCustomisation => false;

public new Func<Mod, bool> IsValidMod
{
get => base.IsValidMod;
set => base.IsValidMod = m => m.UserPlayable && value.Invoke(m);
}

private ShearedButton selectAllButton;

public FreeModSelectOverlay()
: base(OverlayColourScheme.Plum)
{
Expand All @@ -31,22 +39,32 @@ public FreeModSelectOverlay()

protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new ModColumn(modType, true, toggleKeys);

protected override IEnumerable<ShearedButton> CreateFooterButtons() => new[]
{
new ShearedButton(BUTTON_WIDTH)
protected override IEnumerable<ShearedButton> CreateFooterButtons() => base.CreateFooterButtons().Prepend(
selectAllButton = new ShearedButton(BUTTON_WIDTH)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = CommonStrings.SelectAll,
Action = SelectAll
},
new ShearedButton(BUTTON_WIDTH)
});

public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
{
if (e.Repeat)
return false;

switch (e.Action)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = CommonStrings.DeselectAll,
Action = DeselectAll
case PlatformAction.SelectAll:
selectAllButton.TriggerClick();
return true;
}
};

return false;
}

public void OnReleased(KeyBindingReleaseEvent<PlatformAction> e)
{
}
}
}

0 comments on commit 351f5a3

Please sign in to comment.