1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 11:35:35 +08:00

Manually implement @bdach prototype

This commit is contained in:
Cootz 2023-05-02 14:15:33 +03:00
parent b795e8ac5a
commit a6ca049739
11 changed files with 112 additions and 34 deletions

View File

@ -291,7 +291,7 @@ namespace osu.Game.Tests.Visual.UserInterface
private void setFilter(Func<Mod, bool>? filter)
{
foreach (var modState in this.ChildrenOfType<ModColumn>().Single().AvailableMods)
modState.Filtered.Value = filter?.Invoke(modState.Mod) == false;
modState.MatchingFilter.Value = filter?.Invoke(modState.Mod) == false;
}
private partial class TestModColumn : ModColumn

View File

@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Mods.Input
if (!mod_type_lookup.TryGetValue(e.Key, out var typesToMatch))
return false;
var matchingMods = availableMods.Where(modState => matches(modState, typesToMatch) && !modState.Filtered.Value).ToArray();
var matchingMods = availableMods.Where(modState => matches(modState, typesToMatch) && modState.MatchingFilter.Value).ToArray();
if (matchingMods.Length == 0)
return false;

View File

@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Mods.Input
if (index < 0)
return false;
var modState = availableMods.Where(modState => !modState.Filtered.Value).ElementAtOrDefault(index);
var modState = availableMods.Where(modState => modState.MatchingFilter.Value).ElementAtOrDefault(index);
if (modState == null)
return false;

View File

@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Mods
foreach (var mod in availableMods)
{
mod.Active.BindValueChanged(_ => updateState());
mod.Filtered.BindValueChanged(_ => updateState());
mod.MatchingFilter.BindValueChanged(_ => updateState());
}
updateState();
@ -145,12 +145,12 @@ namespace osu.Game.Overlays.Mods
private void updateState()
{
Alpha = availableMods.All(mod => mod.Filtered.Value) ? 0 : 1;
Alpha = availableMods.All(mod => !mod.MatchingFilter.Value) ? 0 : 1;
if (toggleAllCheckbox != null && !SelectionAnimationRunning)
{
toggleAllCheckbox.Alpha = availableMods.Any(panel => !panel.Filtered.Value) ? 1 : 0;
toggleAllCheckbox.Current.Value = availableMods.Where(panel => !panel.Filtered.Value).All(panel => panel.Active.Value);
toggleAllCheckbox.Alpha = availableMods.Any(panel => panel.MatchingFilter.Value) ? 1 : 0;
toggleAllCheckbox.Current.Value = availableMods.Where(panel => panel.MatchingFilter.Value).All(panel => panel.Active.Value);
}
}
@ -195,7 +195,7 @@ namespace osu.Game.Overlays.Mods
{
pendingSelectionOperations.Clear();
foreach (var button in availableMods.Where(b => !b.Active.Value && !b.Filtered.Value))
foreach (var button in availableMods.Where(b => !b.Active.Value && b.MatchingFilter.Value))
pendingSelectionOperations.Enqueue(() => button.Active.Value = true);
}
@ -206,7 +206,7 @@ namespace osu.Game.Overlays.Mods
{
pendingSelectionOperations.Clear();
foreach (var button in availableMods.Where(b => b.Active.Value && !b.Filtered.Value))
foreach (var button in availableMods.Where(b => b.Active.Value && b.MatchingFilter.Value))
pendingSelectionOperations.Enqueue(() => button.Active.Value = false);
}

View File

@ -1,9 +1,12 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
@ -11,11 +14,10 @@ using osuTK;
namespace osu.Game.Overlays.Mods
{
public partial class ModPanel : ModSelectPanel
public partial class ModPanel : ModSelectPanel, IConditionalFilterable
{
public Mod Mod => modState.Mod;
public override BindableBool Active => modState.Active;
public BindableBool Filtered => modState.Filtered;
protected override float IdleSwitchWidth => 54;
protected override float ExpandedSwitchWidth => 70;
@ -54,7 +56,7 @@ namespace osu.Game.Overlays.Mods
{
base.LoadComplete();
Filtered.BindValueChanged(_ => updateFilterState(), true);
canBeShown.BindTo(modState.ValidForSelection);
}
protected override void Select()
@ -71,11 +73,29 @@ namespace osu.Game.Overlays.Mods
#region Filtering support
private void updateFilterState()
public override IEnumerable<LocalisableString> FilterTerms => new[]
{
this.FadeTo(Filtered.Value ? 0 : 1);
Mod.Name,
Mod.Acronym,
Mod.Description
};
public override bool MatchingFilter
{
get => modState.MatchingFilter.Value;
set
{
if (modState.MatchingFilter.Value == value)
return;
modState.MatchingFilter.Value = value;
this.FadeTo(value ? 1 : 0);
}
}
private readonly BindableBool canBeShown = new BindableBool(true);
IBindable<bool> IConditionalFilterable.CanBeShown => canBeShown;
#endregion
}
}

View File

@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
@ -80,6 +81,16 @@ namespace osu.Game.Overlays.Mods
Active.Value = new HashSet<Mod>(Preset.Value.Mods).SetEquals(selectedMods.Value);
}
#region Filtering support
public override IEnumerable<LocalisableString> FilterTerms => new LocalisableString[]
{
Preset.Value.Name,
Preset.Value.Description
};
#endregion
#region IHasCustomTooltip
public ModPreset TooltipContent => Preset.Value;

View File

@ -43,10 +43,15 @@ namespace osu.Game.Overlays.Mods
/// </summary>
public readonly Bindable<bool> Active = new BindableBool(true);
public string SearchTerm
{
set => ItemsFlow.SearchTerm = value;
}
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => base.ReceivePositionalInputAtSubTree(screenSpacePos) && Active.Value;
protected readonly Container ControlContainer;
protected readonly FillFlowContainer ItemsFlow;
protected readonly SearchContainer ItemsFlow;
private readonly TextFlowContainer headerText;
private readonly Box headerBackground;
@ -150,7 +155,7 @@ namespace osu.Game.Overlays.Mods
RelativeSizeAxes = Axes.Both,
ClampExtension = 100,
ScrollbarOverlapsContent = false,
Child = ItemsFlow = new FillFlowContainer
Child = ItemsFlow = new SearchContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,

View File

@ -108,6 +108,8 @@ namespace osu.Game.Overlays.Mods
private ColumnFlowContainer columnFlow = null!;
private FillFlowContainer<ShearedButton> footerButtonFlow = null!;
private Container aboveColumnsContent = null!;
private ShearedSearchTextBox searchTextBox = null!;
private DifficultyMultiplierDisplay? multiplierDisplay;
private ModSearch? modSearch;
@ -148,6 +150,17 @@ namespace osu.Game.Overlays.Mods
MainAreaContent.AddRange(new Drawable[]
{
aboveColumnsContent = new Container
{
RelativeSizeAxes = Axes.X,
Height = ModsEffectDisplay.HEIGHT,
Padding = new MarginPadding { Horizontal = 100 },
Child = searchTextBox = new ShearedSearchTextBox
{
HoldFocus = false,
Width = 300
}
},
new OsuContextMenuContainer
{
RelativeSizeAxes = Axes.Both,
@ -188,18 +201,10 @@ namespace osu.Game.Overlays.Mods
if (ShowTotalMultiplier)
{
MainAreaContent.Add(new Container
aboveColumnsContent.Add(multiplierDisplay = new DifficultyMultiplierDisplay
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
AutoSizeAxes = Axes.X,
Height = ModsEffectDisplay.HEIGHT,
Margin = new MarginPadding { Horizontal = 100 },
Child = multiplierDisplay = new DifficultyMultiplierDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
}
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});
}
@ -271,6 +276,12 @@ namespace osu.Game.Overlays.Mods
customisationVisible.BindValueChanged(_ => updateCustomisationVisualState(), true);
searchTextBox.Current.BindValueChanged(query =>
{
foreach (var column in columnFlow.Columns)
column.SearchTerm = query.NewValue;
}, true);
// Start scrolled slightly to the right to give the user a sense that
// there is more horizontal content available.
ScheduleAfterChildren(() =>
@ -352,7 +363,7 @@ namespace osu.Game.Overlays.Mods
private void filterMods()
{
foreach (var modState in allAvailableMods)
modState.Filtered.Value = !modState.Mod.HasImplementation || !IsValidMod.Invoke(modState.Mod);
modState.ValidForSelection.Value = modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
}
private void updateMultiplier()
@ -487,7 +498,7 @@ namespace osu.Game.Overlays.Mods
{
var column = columnFlow[i].Column;
bool allFiltered = column is ModColumn modColumn && modColumn.AvailableMods.All(modState => modState.Filtered.Value);
bool allFiltered = column is ModColumn modColumn && modColumn.AvailableMods.All(modState => !modState.MatchingFilter.Value);
double delay = allFiltered ? 0 : nonFilteredColumnCount * 30;
double duration = allFiltered ? 0 : fade_in_duration;
@ -549,7 +560,7 @@ namespace osu.Game.Overlays.Mods
if (column is ModColumn modColumn)
{
allFiltered = modColumn.AvailableMods.All(modState => modState.Filtered.Value);
allFiltered = modColumn.AvailableMods.All(modState => !modState.MatchingFilter.Value);
modColumn.FlushPendingSelections();
}

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.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@ -24,7 +25,7 @@ using osuTK.Input;
namespace osu.Game.Overlays.Mods
{
public abstract partial class ModSelectPanel : OsuClickableContainer, IHasAccentColour
public abstract partial class ModSelectPanel : OsuClickableContainer, IHasAccentColour, IFilterable
{
public abstract BindableBool Active { get; }
@ -263,5 +264,28 @@ namespace osu.Game.Overlays.Mods
TextBackground.FadeColour(foregroundColour, transitionDuration, Easing.OutQuint);
TextFlow.FadeColour(textColour, transitionDuration, Easing.OutQuint);
}
#region IFilterable
public abstract IEnumerable<LocalisableString> FilterTerms { get; }
private bool matchingFilter;
public virtual bool MatchingFilter
{
get => matchingFilter;
set
{
if (matchingFilter == value)
return;
matchingFilter = value;
this.FadeTo(value ? 1 : 0);
}
}
public bool FilteringActive { set { } }
#endregion
}
}

View File

@ -32,9 +32,16 @@ namespace osu.Game.Overlays.Mods
public bool PendingConfiguration { get; set; }
/// <summary>
/// Whether the mod is currently filtered out due to not matching imposed criteria.
/// Whether the mod is currently valid for selection.
/// This can be <see langword="false"/> in scenarios such as the free mod select overlay, where not all mods are selectable
/// regardless of search criteria imposed by the user selecting.
/// </summary>
public BindableBool Filtered { get; } = new BindableBool();
public BindableBool ValidForSelection { get; } = new BindableBool(true);
/// <summary>
/// Whether the mod is matching the current filter, i.e. it is available for user selection.
/// </summary>
public BindableBool MatchingFilter { get; } = new BindableBool(true);
public ModState(Mod mod)
{

View File

@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Mods
{
Enabled.Value = availableMods.Value
.SelectMany(pair => pair.Value)
.Any(modState => !modState.Active.Value && !modState.Filtered.Value);
.Any(modState => !modState.Active.Value && !modState.MatchingFilter.Value);
}
public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)