diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs
index 87a45ebf63..495b1c05cd 100644
--- a/osu.Game/Overlays/Mods/ModSection.cs
+++ b/osu.Game/Overlays/Mods/ModSection.cs
@@ -33,6 +33,8 @@ namespace osu.Game.Overlays.Mods
private CancellationTokenSource modsLoadCts;
+ protected bool SelectionAnimationRunning => pendingSelectionOperations.Count > 0;
+
///
/// True when all mod icons have completed loading.
///
@@ -49,7 +51,11 @@ namespace osu.Game.Overlays.Mods
return new ModButton(m)
{
- SelectionChanged = Action,
+ SelectionChanged = mod =>
+ {
+ ModButtonStateChanged(mod);
+ Action?.Invoke(mod);
+ },
};
}).ToArray();
@@ -78,6 +84,10 @@ namespace osu.Game.Overlays.Mods
}
}
+ protected virtual void ModButtonStateChanged(Mod mod)
+ {
+ }
+
private ModButton[] buttons = Array.Empty();
protected override bool OnKeyDown(KeyDownEvent e)
@@ -94,44 +104,53 @@ namespace osu.Game.Overlays.Mods
return base.OnKeyDown(e);
}
+ private const double initial_multiple_selection_delay = 100;
+
+ private readonly Queue pendingSelectionOperations = new Queue();
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Scheduler.AddDelayed(() =>
+ {
+ if (pendingSelectionOperations.TryDequeue(out var dequeuedAction))
+ dequeuedAction();
+ }, initial_multiple_selection_delay, true);
+ }
+
///
/// Selects all mods.
///
public void SelectAll()
{
+ pendingSelectionOperations.Clear();
+
foreach (var button in buttons.Where(b => !b.Selected))
- button.SelectAt(0);
+ pendingSelectionOperations.Enqueue(() => button.SelectAt(0));
}
///
/// Deselects all mods.
///
- /// Set to true to bypass animations and update selections immediately.
- public void DeselectAll(bool immediate = false) => DeselectTypes(buttons.Select(b => b.SelectedMod?.GetType()).Where(t => t != null), immediate);
+ public void DeselectAll() => DeselectTypes(buttons.Select(b => b.SelectedMod?.GetType()).Where(t => t != null));
///
/// Deselect one or more mods in this section.
///
/// The types of s which should be deselected.
- /// Set to true to bypass animations and update selections immediately.
- public void DeselectTypes(IEnumerable modTypes, bool immediate = false)
+ public void DeselectTypes(IEnumerable modTypes)
{
- int delay = 0;
+ pendingSelectionOperations.Clear();
foreach (var button in buttons)
{
- Mod selected = button.SelectedMod;
- if (selected == null) continue;
+ if (button.SelectedMod == null) continue;
foreach (var type in modTypes)
{
- if (type.IsInstanceOfType(selected))
- {
- if (immediate)
- button.Deselect();
- else
- Scheduler.AddDelayed(button.Deselect, delay += 50);
- }
+ if (type.IsInstanceOfType(button.SelectedMod))
+ pendingSelectionOperations.Enqueue(button.Deselect);
}
}
}
diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
index 97902d1c15..4f65a39ed3 100644
--- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs
+++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
@@ -14,7 +14,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
-using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
diff --git a/osu.Game/Overlays/Mods/SoloModSelectOverlay.cs b/osu.Game/Overlays/Mods/SoloModSelectOverlay.cs
index d039ad1f98..aa0e78c126 100644
--- a/osu.Game/Overlays/Mods/SoloModSelectOverlay.cs
+++ b/osu.Game/Overlays/Mods/SoloModSelectOverlay.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Mods
base.OnModSelected(mod);
foreach (var section in ModSectionsContainer.Children)
- section.DeselectTypes(mod.IncompatibleMods, true);
+ section.DeselectTypes(mod.IncompatibleMods);
}
}
}
diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs
index 180f6079ac..7bc226bb3f 100644
--- a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs
+++ b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
-using System.Reflection.Emit;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
@@ -72,7 +71,7 @@ namespace osu.Game.Screens.OnlinePlay
private void deselectAll()
{
foreach (var section in ModSectionsContainer.Children)
- section.DeselectAll(true);
+ section.DeselectAll();
}
protected override ModSection CreateModSection(ModType type) => new FreeModSection(type);
@@ -99,21 +98,21 @@ namespace osu.Game.Screens.OnlinePlay
private void onCheckboxChanged(bool value)
{
- foreach (var button in ButtonsContainer.OfType())
- {
- if (value)
- button.SelectAt(0);
- else
- button.Deselect();
- }
+ if (value)
+ SelectAll();
+ else
+ DeselectAll();
}
- protected override void Update()
+ protected override void ModButtonStateChanged(Mod mod)
{
- base.Update();
+ base.ModButtonStateChanged(mod);
- var validButtons = ButtonsContainer.OfType().Where(b => b.Mod.HasImplementation);
- checkbox.Current.Value = validButtons.All(b => b.Selected);
+ if (!SelectionAnimationRunning)
+ {
+ var validButtons = ButtonsContainer.OfType().Where(b => b.Mod.HasImplementation);
+ checkbox.Current.Value = validButtons.All(b => b.Selected);
+ }
}
}