mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 18:12:56 +08:00
Encapsulate mod hotkey selection logic in strategy pattern
This commit is contained in:
parent
b7b7de115f
commit
73124d2b1f
@ -139,7 +139,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding(30),
|
Padding = new MarginPadding(30),
|
||||||
Child = column = new ModColumn(ModType.DifficultyReduction, true, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P })
|
Child = column = new ModColumn(ModType.DifficultyReduction, true)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
22
osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs
Normal file
22
osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encapsulates strategies of handling mod hotkeys on the <see cref="ModSelectOverlay"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface IModHotkeyHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to handle a press of the supplied <paramref name="hotkey"/> as a selection of one of the mods in <paramref name="availableMods"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hotkey">The key that was pressed by the user.</param>
|
||||||
|
/// <param name="availableMods">The list of currently available mods.</param>
|
||||||
|
/// <returns>Whether the <paramref name="hotkey"/> was handled as a mod selection/deselection.</returns>
|
||||||
|
bool HandleHotkeyPressed(Key hotkey, IEnumerable<ModState> availableMods);
|
||||||
|
}
|
||||||
|
}
|
30
osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs
Normal file
30
osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// 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 osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Static factory class for <see cref="IModHotkeyHandler"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public static class ModHotkeyHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an appropriate <see cref="IModHotkeyHandler"/> for the given <paramref name="modType"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static IModHotkeyHandler Create(ModType modType)
|
||||||
|
{
|
||||||
|
switch (modType)
|
||||||
|
{
|
||||||
|
case ModType.DifficultyReduction:
|
||||||
|
case ModType.DifficultyIncrease:
|
||||||
|
case ModType.Automation:
|
||||||
|
return SequentialModHotkeyHandler.Create(modType);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return new NoopModHotkeyHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs
Normal file
17
osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A no-op implementation of <see cref="IModHotkeyHandler"/>.
|
||||||
|
/// Used when a column is not handling any hotkeys at all.
|
||||||
|
/// </summary>
|
||||||
|
public class NoopModHotkeyHandler : IModHotkeyHandler
|
||||||
|
{
|
||||||
|
public bool HandleHotkeyPressed(Key hotkey, IEnumerable<ModState> availableMods) => false;
|
||||||
|
}
|
||||||
|
}
|
58
osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs
Normal file
58
osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This implementation of <see cref="IModHotkeyHandler"/> receives a sequence of <see cref="Key"/>s,
|
||||||
|
/// and maps the sequence of keys onto the items it is provided in <see cref="HandleHotkeyPressed"/>.
|
||||||
|
/// In this case, particular mods are not bound to particular keys, the hotkeys are a byproduct of mod ordering.
|
||||||
|
/// </summary>
|
||||||
|
public class SequentialModHotkeyHandler : IModHotkeyHandler
|
||||||
|
{
|
||||||
|
public static SequentialModHotkeyHandler Create(ModType modType)
|
||||||
|
{
|
||||||
|
switch (modType)
|
||||||
|
{
|
||||||
|
case ModType.DifficultyReduction:
|
||||||
|
return new SequentialModHotkeyHandler(new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P });
|
||||||
|
|
||||||
|
case ModType.DifficultyIncrease:
|
||||||
|
return new SequentialModHotkeyHandler(new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L });
|
||||||
|
|
||||||
|
case ModType.Automation:
|
||||||
|
return new SequentialModHotkeyHandler(new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M });
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(modType), modType, $"Cannot create {nameof(SequentialModHotkeyHandler)} for provided mod type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Key[] toggleKeys;
|
||||||
|
|
||||||
|
private SequentialModHotkeyHandler(Key[] keys)
|
||||||
|
{
|
||||||
|
toggleKeys = keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HandleHotkeyPressed(Key hotkey, IEnumerable<ModState> availableMods)
|
||||||
|
{
|
||||||
|
int index = Array.IndexOf(toggleKeys, hotkey);
|
||||||
|
if (index < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var modState = availableMods.ElementAtOrDefault(index);
|
||||||
|
if (modState == null || modState.Filtered.Value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
modState.Active.Toggle();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,10 +21,10 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
|
using osu.Game.Overlays.Mods.Input;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
@ -70,7 +70,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
protected virtual ModPanel CreateModPanel(ModState mod) => new ModPanel(mod);
|
protected virtual ModPanel CreateModPanel(ModState mod) => new ModPanel(mod);
|
||||||
|
|
||||||
private readonly Key[]? toggleKeys;
|
private readonly IModHotkeyHandler hotkeyHandler;
|
||||||
|
|
||||||
private readonly TextFlowContainer headerText;
|
private readonly TextFlowContainer headerText;
|
||||||
private readonly Box headerBackground;
|
private readonly Box headerBackground;
|
||||||
@ -86,10 +86,10 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
private const float header_height = 42;
|
private const float header_height = 42;
|
||||||
|
|
||||||
public ModColumn(ModType modType, bool allowBulkSelection, Key[]? toggleKeys = null)
|
public ModColumn(ModType modType, bool allowBulkSelection)
|
||||||
{
|
{
|
||||||
ModType = modType;
|
ModType = modType;
|
||||||
this.toggleKeys = toggleKeys;
|
hotkeyHandler = ModHotkeyHandler.Create(modType);
|
||||||
|
|
||||||
Width = 320;
|
Width = 320;
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
@ -425,17 +425,10 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
if (e.ControlPressed || e.AltPressed || e.SuperPressed) return false;
|
if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.Repeat)
|
||||||
if (toggleKeys == null) return false;
|
return false;
|
||||||
|
|
||||||
int index = Array.IndexOf(toggleKeys, e.Key);
|
return hotkeyHandler.HandleHotkeyPressed(e.Key, availableMods);
|
||||||
if (index < 0) return false;
|
|
||||||
|
|
||||||
var modState = availableMods.ElementAtOrDefault(index);
|
|
||||||
if (modState == null || modState.Filtered.Value) return false;
|
|
||||||
|
|
||||||
modState.Active.Toggle();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -21,7 +21,6 @@ using osu.Game.Localisation;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
@ -68,7 +67,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool AllowCustomisation => true;
|
protected virtual bool AllowCustomisation => true;
|
||||||
|
|
||||||
protected virtual ModColumn CreateModColumn(ModType modType, Key[]? toggleKeys = null) => new ModColumn(modType, false, toggleKeys);
|
protected virtual ModColumn CreateModColumn(ModType modType) => new ModColumn(modType, false);
|
||||||
|
|
||||||
protected virtual IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection) => newSelection;
|
protected virtual IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection) => newSelection;
|
||||||
|
|
||||||
@ -160,9 +159,9 @@ namespace osu.Game.Overlays.Mods
|
|||||||
Padding = new MarginPadding { Bottom = 10 },
|
Padding = new MarginPadding { Bottom = 10 },
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
createModColumnContent(ModType.DifficultyReduction, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }),
|
createModColumnContent(ModType.DifficultyReduction),
|
||||||
createModColumnContent(ModType.DifficultyIncrease, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }),
|
createModColumnContent(ModType.DifficultyIncrease),
|
||||||
createModColumnContent(ModType.Automation, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }),
|
createModColumnContent(ModType.Automation),
|
||||||
createModColumnContent(ModType.Conversion),
|
createModColumnContent(ModType.Conversion),
|
||||||
createModColumnContent(ModType.Fun)
|
createModColumnContent(ModType.Fun)
|
||||||
}
|
}
|
||||||
@ -264,9 +263,9 @@ namespace osu.Game.Overlays.Mods
|
|||||||
column.DeselectAll();
|
column.DeselectAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ColumnDimContainer createModColumnContent(ModType modType, Key[]? toggleKeys = null)
|
private ColumnDimContainer createModColumnContent(ModType modType)
|
||||||
{
|
{
|
||||||
var column = CreateModColumn(modType, toggleKeys).With(column =>
|
var column = CreateModColumn(modType).With(column =>
|
||||||
{
|
{
|
||||||
// spacing applied here rather than via `columnFlow.Spacing` to avoid uneven gaps when some of the columns are hidden.
|
// spacing applied here rather than via `columnFlow.Spacing` to avoid uneven gaps when some of the columns are hidden.
|
||||||
column.Margin = new MarginPadding { Right = 10 };
|
column.Margin = new MarginPadding { Right = 10 };
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
@ -19,7 +15,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new UserModColumn(modType, false, toggleKeys);
|
protected override ModColumn CreateModColumn(ModType modType) => new UserModColumn(modType, false);
|
||||||
|
|
||||||
protected override IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection)
|
protected override IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection)
|
||||||
{
|
{
|
||||||
@ -44,8 +40,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
private class UserModColumn : ModColumn
|
private class UserModColumn : ModColumn
|
||||||
{
|
{
|
||||||
public UserModColumn(ModType modType, bool allowBulkSelection, [CanBeNull] Key[] toggleKeys = null)
|
public UserModColumn(ModType modType, bool allowBulkSelection)
|
||||||
: base(modType, allowBulkSelection, toggleKeys)
|
: base(modType, allowBulkSelection)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osuTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay
|
namespace osu.Game.Screens.OnlinePlay
|
||||||
{
|
{
|
||||||
@ -33,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
IsValidMod = _ => true;
|
IsValidMod = _ => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new ModColumn(modType, true, toggleKeys);
|
protected override ModColumn CreateModColumn(ModType modType) => new ModColumn(modType, true);
|
||||||
|
|
||||||
protected override IEnumerable<ShearedButton> CreateFooterButtons() => base.CreateFooterButtons().Prepend(
|
protected override IEnumerable<ShearedButton> CreateFooterButtons() => base.CreateFooterButtons().Prepend(
|
||||||
new SelectAllModsButton(this)
|
new SelectAllModsButton(this)
|
||||||
|
Loading…
Reference in New Issue
Block a user