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:
parent
b795e8ac5a
commit
a6ca049739
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user