From f23ca7c7cfd7bbd752e50464189c2c84546beba2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 4 Feb 2021 18:10:55 +0900 Subject: [PATCH] Centralise selection animation logic --- osu.Game/Overlays/Mods/ModSection.cs | 51 +++++++++++++------ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 1 - .../Overlays/Mods/SoloModSelectOverlay.cs | 2 +- .../OnlinePlay/FreeModSelectOverlay.cs | 25 +++++---- 4 files changed, 48 insertions(+), 31 deletions(-) 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); + } } }