Add filtering support to mod column

This commit is contained in:
Bartłomiej Dach 2022-02-20 13:40:52 +01:00
parent fe4e4bf9c5
commit a83f96b026
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
3 changed files with 100 additions and 4 deletions

View File

@ -1,6 +1,7 @@
// 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.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@ -83,5 +84,54 @@ namespace osu.Game.Tests.Visual.UserInterface
InputManager.Click(MouseButton.Left);
});
}
[Test]
public void TestFiltering()
{
TestModColumn column = null;
AddStep("create content", () => Child = new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(30),
Child = column = new TestModColumn(ModType.Fun, true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
}
});
AddStep("set filter", () => column.Filter = mod => mod.Name.Contains("Wind", StringComparison.CurrentCultureIgnoreCase));
AddUntilStep("two panels visible", () => column.ChildrenOfType<ModPanel>().Count(panel => !panel.Filtered.Value) == 2);
clickToggle();
AddUntilStep("wait for animation", () => !column.SelectionAnimationRunning);
AddAssert("only visible items selected", () => column.ChildrenOfType<ModPanel>().Where(panel => panel.Active.Value).All(panel => !panel.Filtered.Value));
AddStep("unset filter", () => column.Filter = null);
AddUntilStep("all panels visible", () => column.ChildrenOfType<ModPanel>().All(panel => !panel.Filtered.Value));
AddAssert("checkbox not selected", () => !column.ChildrenOfType<OsuCheckbox>().Single().Current.Value);
AddStep("set filter", () => column.Filter = mod => mod.Name.Contains("Wind", StringComparison.CurrentCultureIgnoreCase));
AddUntilStep("two panels visible", () => column.ChildrenOfType<ModPanel>().Count(panel => !panel.Filtered.Value) == 2);
AddAssert("checkbox selected", () => column.ChildrenOfType<OsuCheckbox>().Single().Current.Value);
void clickToggle() => AddStep("click toggle", () =>
{
var checkbox = this.ChildrenOfType<OsuCheckbox>().Single();
InputManager.MoveMouseTo(checkbox);
InputManager.Click(MouseButton.Left);
});
}
private class TestModColumn : ModColumn
{
public new bool SelectionAnimationRunning => base.SelectionAnimationRunning;
public TestModColumn(ModType modType, bool allowBulkSelection)
: base(modType, allowBulkSelection)
{
}
}
}
}

View File

@ -28,6 +28,18 @@ namespace osu.Game.Overlays.Mods
{
public class ModColumn : CompositeDrawable
{
private Func<Mod, bool>? filter;
public Func<Mod, bool>? Filter
{
get => filter;
set
{
filter = value;
updateFilter();
}
}
private readonly ModType modType;
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
@ -220,9 +232,12 @@ namespace osu.Game.Overlays.Mods
LoadComponentsAsync(panels, loaded =>
{
panelFlow.ChildrenEnumerable = loaded;
foreach (var panel in panelFlow)
panel.Active.BindValueChanged(_ => updateToggleState());
updateToggleState();
updateFilter();
}, (cancellationTokenSource = new CancellationTokenSource()).Token);
}
@ -235,6 +250,8 @@ namespace osu.Game.Overlays.Mods
private readonly Queue<Action> pendingSelectionOperations = new Queue<Action>();
protected bool SelectionAnimationRunning => pendingSelectionOperations.Count > 0;
protected override void Update()
{
base.Update();
@ -260,8 +277,8 @@ namespace osu.Game.Overlays.Mods
private void updateToggleState()
{
if (toggleAllCheckbox != null && pendingSelectionOperations.Count == 0)
toggleAllCheckbox.Current.Value = panelFlow.All(panel => panel.Active.Value);
if (toggleAllCheckbox != null && !SelectionAnimationRunning)
toggleAllCheckbox.Current.Value = panelFlow.Where(panel => !panel.Filtered.Value).All(panel => panel.Active.Value);
}
/// <summary>
@ -271,7 +288,7 @@ namespace osu.Game.Overlays.Mods
{
pendingSelectionOperations.Clear();
foreach (var button in panelFlow.Where(b => !b.Active.Value))
foreach (var button in panelFlow.Where(b => !b.Active.Value && !b.Filtered.Value))
pendingSelectionOperations.Enqueue(() => button.Active.Value = true);
}
@ -282,7 +299,7 @@ namespace osu.Game.Overlays.Mods
{
pendingSelectionOperations.Clear();
foreach (var button in panelFlow.Where(b => b.Active.Value))
foreach (var button in panelFlow.Where(b => b.Active.Value && !b.Filtered.Value))
pendingSelectionOperations.Enqueue(() => button.Active.Value = false);
}
@ -349,5 +366,17 @@ namespace osu.Game.Overlays.Mods
}
#endregion
#region Filtering support
private void updateFilter()
{
foreach (var modPanel in panelFlow)
modPanel.ApplyFilter(Filter);
updateToggleState();
}
#endregion
}
}

View File

@ -1,6 +1,7 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@ -28,6 +29,7 @@ namespace osu.Game.Overlays.Mods
{
public Mod Mod { get; }
public BindableBool Active { get; } = new BindableBool();
public BindableBool Filtered { get; } = new BindableBool();
protected readonly Box Background;
protected readonly Container SwitchContainer;
@ -157,6 +159,7 @@ namespace osu.Game.Overlays.Mods
playStateChangeSamples();
UpdateState();
});
Filtered.BindValueChanged(_ => updateFilterState());
UpdateState();
FinishTransforms(true);
@ -235,5 +238,19 @@ namespace osu.Game.Overlays.Mods
TextBackground.FadeColour(textBackgroundColour, transitionDuration, Easing.OutQuint);
TextFlow.FadeColour(textColour, transitionDuration, Easing.OutQuint);
}
#region Filtering support
public void ApplyFilter(Func<Mod, bool>? filter)
{
Filtered.Value = filter != null && !filter.Invoke(Mod);
}
private void updateFilterState()
{
this.FadeTo(Filtered.Value ? 0 : 1);
}
#endregion
}
}