mirror of
https://github.com/ppy/osu
synced 2024-12-25 16:22:23 +00:00
Migrate mod select overlay footer content
This commit is contained in:
parent
467d7c4f54
commit
48bf3f1385
@ -24,6 +24,7 @@ using osu.Game.Rulesets.Mods;
|
|||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Taiko.Mods;
|
using osu.Game.Rulesets.Taiko.Mods;
|
||||||
|
using osu.Game.Screens.Footer;
|
||||||
using osu.Game.Tests.Mods;
|
using osu.Game.Tests.Mods;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -93,12 +94,28 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private void createScreen()
|
private void createScreen()
|
||||||
{
|
{
|
||||||
AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay
|
AddStep("create screen", () =>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
var receptor = new ScreenFooter.BackReceptor();
|
||||||
State = { Value = Visibility.Visible },
|
var footer = new ScreenFooter(receptor);
|
||||||
Beatmap = Beatmap.Value,
|
|
||||||
SelectedMods = { BindTarget = SelectedMods }
|
Child = new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = new[] { (typeof(ScreenFooter), (object)footer) },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
receptor,
|
||||||
|
modSelectOverlay = new TestModSelectOverlay
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
State = { Value = Visibility.Visible },
|
||||||
|
Beatmap = { Value = Beatmap.Value },
|
||||||
|
SelectedMods = { BindTarget = SelectedMods },
|
||||||
|
},
|
||||||
|
footer,
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
waitForColumnLoad();
|
waitForColumnLoad();
|
||||||
}
|
}
|
||||||
@ -119,7 +136,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddAssert("mod multiplier correct", () =>
|
AddAssert("mod multiplier correct", () =>
|
||||||
{
|
{
|
||||||
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
|
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
|
||||||
return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
|
return Precision.AlmostEquals(multiplier, this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
|
||||||
});
|
});
|
||||||
assertCustomisationToggleState(disabled: false, active: false);
|
assertCustomisationToggleState(disabled: false, active: false);
|
||||||
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType<ISettingsItem>().Any());
|
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType<ISettingsItem>().Any());
|
||||||
@ -134,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddAssert("mod multiplier correct", () =>
|
AddAssert("mod multiplier correct", () =>
|
||||||
{
|
{
|
||||||
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
|
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
|
||||||
return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
|
return Precision.AlmostEquals(multiplier, this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value);
|
||||||
});
|
});
|
||||||
assertCustomisationToggleState(disabled: false, active: false);
|
assertCustomisationToggleState(disabled: false, active: false);
|
||||||
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType<ISettingsItem>().Any());
|
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType<ISettingsItem>().Any());
|
||||||
@ -756,7 +773,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep("click back button", () =>
|
AddStep("click back button", () =>
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(modSelectOverlay.BackButton);
|
InputManager.MoveMouseTo(this.ChildrenOfType<ScreenBackButton>().Single());
|
||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
AddAssert("mod select hidden", () => modSelectOverlay.State.Value == Visibility.Hidden);
|
AddAssert("mod select hidden", () => modSelectOverlay.State.Value == Visibility.Hidden);
|
||||||
@ -884,7 +901,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
AddAssert("difficulty multiplier display shows correct value",
|
AddAssert("difficulty multiplier display shows correct value",
|
||||||
() => modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(0.1).Within(Precision.DOUBLE_EPSILON));
|
() => this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(0.1).Within(Precision.DOUBLE_EPSILON));
|
||||||
|
|
||||||
// this is highly unorthodox in a test, but because the `ModSettingChangeTracker` machinery heavily leans on events and object disposal and re-creation,
|
// this is highly unorthodox in a test, but because the `ModSettingChangeTracker` machinery heavily leans on events and object disposal and re-creation,
|
||||||
// it is instrumental in the reproduction of the failure scenario that this test is supposed to cover.
|
// it is instrumental in the reproduction of the failure scenario that this test is supposed to cover.
|
||||||
@ -894,7 +911,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddStep("reset half time speed to default", () => modSelectOverlay.ChildrenOfType<ModCustomisationPanel>().Single()
|
AddStep("reset half time speed to default", () => modSelectOverlay.ChildrenOfType<ModCustomisationPanel>().Single()
|
||||||
.ChildrenOfType<RevertToDefaultButton<double>>().Single().TriggerClick());
|
.ChildrenOfType<RevertToDefaultButton<double>>().Single().TriggerClick());
|
||||||
AddUntilStep("difficulty multiplier display shows correct value",
|
AddUntilStep("difficulty multiplier display shows correct value",
|
||||||
() => modSelectOverlay.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(0.3).Within(Precision.DOUBLE_EPSILON));
|
() => this.ChildrenOfType<RankingInformationDisplay>().Single().ModMultiplier.Value, () => Is.EqualTo(0.3).Within(Precision.DOUBLE_EPSILON));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -1014,8 +1031,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
private partial class TestModSelectOverlay : UserModSelectOverlay
|
private partial class TestModSelectOverlay : UserModSelectOverlay
|
||||||
{
|
{
|
||||||
protected override bool ShowPresets => true;
|
protected override bool ShowPresets => true;
|
||||||
|
|
||||||
public new ShearedButton BackButton => base.BackButton;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestUnimplementedMod : Mod
|
private class TestUnimplementedMod : Mod
|
||||||
|
177
osu.Game/Overlays/Mods/ModSelectFooterContent.cs
Normal file
177
osu.Game/Overlays/Mods/ModSelectFooterContent.cs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
// 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 System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods
|
||||||
|
{
|
||||||
|
public partial class ModSelectFooterContent : VisibilityContainer
|
||||||
|
{
|
||||||
|
private readonly ModSelectOverlay overlay;
|
||||||
|
|
||||||
|
private RankingInformationDisplay? rankingInformationDisplay;
|
||||||
|
private BeatmapAttributesDisplay? beatmapAttributesDisplay;
|
||||||
|
private FillFlowContainer<ShearedButton> buttonFlow = null!;
|
||||||
|
private FillFlowContainer contentFlow = null!;
|
||||||
|
|
||||||
|
public DeselectAllModsButton? DeselectAllModsButton { get; set; }
|
||||||
|
|
||||||
|
public readonly IBindable<WorkingBeatmap?> Beatmap = new Bindable<WorkingBeatmap?>();
|
||||||
|
public readonly IBindable<IReadOnlyList<Mod>> ActiveMods = new Bindable<IReadOnlyList<Mod>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the effects (on score multiplier, on or beatmap difficulty) of the current selected set of mods should be shown.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool ShowModEffects => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the ranking information and beatmap attributes displays are stacked vertically due to small space.
|
||||||
|
/// </summary>
|
||||||
|
public bool DisplaysStackedVertically { get; private set; }
|
||||||
|
|
||||||
|
public ModSelectFooterContent(ModSelectOverlay overlay)
|
||||||
|
{
|
||||||
|
this.overlay = overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChild = buttonFlow = new FillFlowContainer<ShearedButton>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Padding = new MarginPadding { Horizontal = 20 },
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
ChildrenEnumerable = CreateButtons(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ShowModEffects)
|
||||||
|
{
|
||||||
|
AddInternal(contentFlow = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(30, 10),
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight,
|
||||||
|
Margin = new MarginPadding { Horizontal = 20 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rankingInformationDisplay = new RankingInformationDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight
|
||||||
|
},
|
||||||
|
beatmapAttributesDisplay = new BeatmapAttributesDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight,
|
||||||
|
BeatmapInfo = { Value = Beatmap.Value?.BeatmapInfo },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModSettingChangeTracker? modSettingChangeTracker;
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Beatmap.BindValueChanged(b =>
|
||||||
|
{
|
||||||
|
if (beatmapAttributesDisplay != null)
|
||||||
|
beatmapAttributesDisplay.BeatmapInfo.Value = b.NewValue?.BeatmapInfo;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
ActiveMods.BindValueChanged(m =>
|
||||||
|
{
|
||||||
|
updateInformation();
|
||||||
|
|
||||||
|
modSettingChangeTracker?.Dispose();
|
||||||
|
|
||||||
|
// Importantly, use ActiveMods.Value here (and not the ValueChanged NewValue) as the latter can
|
||||||
|
// potentially be stale, due to complexities in the way change trackers work.
|
||||||
|
//
|
||||||
|
// See https://github.com/ppy/osu/pull/23284#issuecomment-1529056988
|
||||||
|
modSettingChangeTracker = new ModSettingChangeTracker(ActiveMods.Value);
|
||||||
|
modSettingChangeTracker.SettingChanged += _ => updateInformation();
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInformation()
|
||||||
|
{
|
||||||
|
if (rankingInformationDisplay != null)
|
||||||
|
{
|
||||||
|
double multiplier = 1.0;
|
||||||
|
|
||||||
|
foreach (var mod in ActiveMods.Value)
|
||||||
|
multiplier *= mod.ScoreMultiplier;
|
||||||
|
|
||||||
|
rankingInformationDisplay.ModMultiplier.Value = multiplier;
|
||||||
|
rankingInformationDisplay.Ranked.Value = ActiveMods.Value.All(m => m.Ranked);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beatmapAttributesDisplay != null)
|
||||||
|
beatmapAttributesDisplay.Mods.Value = ActiveMods.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (beatmapAttributesDisplay != null)
|
||||||
|
{
|
||||||
|
float rightEdgeOfLastButton = buttonFlow[^1].ScreenSpaceDrawQuad.TopRight.X;
|
||||||
|
|
||||||
|
// this is cheating a bit; the 640 value is hardcoded based on how wide the expanded panel _generally_ is.
|
||||||
|
// due to the transition applied, the raw screenspace quad of the panel cannot be used, as it will trigger an ugly feedback cycle of expanding and collapsing.
|
||||||
|
float projectedLeftEdgeOfExpandedBeatmapAttributesDisplay = buttonFlow.ToScreenSpace(buttonFlow.DrawSize - new Vector2(640, 0)).X;
|
||||||
|
|
||||||
|
DisplaysStackedVertically = rightEdgeOfLastButton > projectedLeftEdgeOfExpandedBeatmapAttributesDisplay;
|
||||||
|
|
||||||
|
// only update preview panel's collapsed state after we are fully visible, to ensure all the buttons are where we expect them to be.
|
||||||
|
if (Alpha == 1)
|
||||||
|
beatmapAttributesDisplay.Collapsed.Value = DisplaysStackedVertically;
|
||||||
|
|
||||||
|
contentFlow.LayoutDuration = 200;
|
||||||
|
contentFlow.LayoutEasing = Easing.OutQuint;
|
||||||
|
contentFlow.Direction = DisplaysStackedVertically ? FillDirection.Vertical : FillDirection.Horizontal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual IEnumerable<ShearedButton> CreateButtons() => new[]
|
||||||
|
{
|
||||||
|
DeselectAllModsButton = new DeselectAllModsButton(overlay)
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
this.MoveToY(0, 400, Easing.OutQuint)
|
||||||
|
.FadeIn(400, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
this.MoveToY(-20f, 200, Easing.OutQuint)
|
||||||
|
.FadeOut(200, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Screens.Footer;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -87,11 +88,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
public ShearedSearchTextBox SearchTextBox { get; private set; } = null!;
|
public ShearedSearchTextBox SearchTextBox { get; private set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the effects (on score multiplier, on or beatmap difficulty) of the current selected set of mods should be shown.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual bool ShowModEffects => true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether per-mod customisation controls are visible.
|
/// Whether per-mod customisation controls are visible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -108,11 +104,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
protected virtual IReadOnlyList<Mod> ComputeActiveMods() => SelectedMods.Value;
|
protected virtual IReadOnlyList<Mod> ComputeActiveMods() => SelectedMods.Value;
|
||||||
|
|
||||||
protected virtual IEnumerable<ShearedButton> CreateFooterButtons()
|
|
||||||
{
|
|
||||||
yield return deselectAllModsButton = new DeselectAllModsButton(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> globalAvailableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
|
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> globalAvailableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
|
||||||
|
|
||||||
public IEnumerable<ModState> AllAvailableMods => AvailableMods.Value.SelectMany(pair => pair.Value);
|
public IEnumerable<ModState> AllAvailableMods => AvailableMods.Value.SelectMany(pair => pair.Value);
|
||||||
@ -121,34 +112,18 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
private ColumnScrollContainer columnScroll = null!;
|
private ColumnScrollContainer columnScroll = null!;
|
||||||
private ColumnFlowContainer columnFlow = null!;
|
private ColumnFlowContainer columnFlow = null!;
|
||||||
private FillFlowContainer<ShearedButton> footerButtonFlow = null!;
|
|
||||||
private FillFlowContainer footerContentFlow = null!;
|
|
||||||
private DeselectAllModsButton deselectAllModsButton = null!;
|
|
||||||
|
|
||||||
private Container aboveColumnsContent = null!;
|
private Container aboveColumnsContent = null!;
|
||||||
private RankingInformationDisplay? rankingInformationDisplay;
|
|
||||||
private BeatmapAttributesDisplay? beatmapAttributesDisplay;
|
|
||||||
private ModCustomisationPanel customisationPanel = null!;
|
private ModCustomisationPanel customisationPanel = null!;
|
||||||
|
|
||||||
protected ShearedButton BackButton { get; private set; } = null!;
|
protected virtual SelectAllModsButton? SelectAllModsButton => null;
|
||||||
protected SelectAllModsButton? SelectAllModsButton { get; set; }
|
|
||||||
|
|
||||||
private Sample? columnAppearSample;
|
private Sample? columnAppearSample;
|
||||||
|
|
||||||
private WorkingBeatmap? beatmap;
|
public readonly Bindable<WorkingBeatmap?> Beatmap = new Bindable<WorkingBeatmap?>();
|
||||||
|
|
||||||
public WorkingBeatmap? Beatmap
|
[Resolved]
|
||||||
{
|
private ScreenFooter? footer { get; set; }
|
||||||
get => beatmap;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (beatmap == value) return;
|
|
||||||
|
|
||||||
beatmap = value;
|
|
||||||
if (IsLoaded && beatmapAttributesDisplay != null)
|
|
||||||
beatmapAttributesDisplay.BeatmapInfo.Value = beatmap?.BeatmapInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ModSelectOverlay(OverlayColourScheme colourScheme = OverlayColourScheme.Green)
|
protected ModSelectOverlay(OverlayColourScheme colourScheme = OverlayColourScheme.Green)
|
||||||
: base(colourScheme)
|
: base(colourScheme)
|
||||||
@ -226,59 +201,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
FooterContent.Add(footerButtonFlow = new FillFlowContainer<ShearedButton>
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Padding = new MarginPadding
|
|
||||||
{
|
|
||||||
Vertical = PADDING,
|
|
||||||
Horizontal = 70
|
|
||||||
},
|
|
||||||
Spacing = new Vector2(10),
|
|
||||||
ChildrenEnumerable = CreateFooterButtons().Prepend(BackButton = new ShearedButton(BUTTON_WIDTH)
|
|
||||||
{
|
|
||||||
Text = CommonStrings.Back,
|
|
||||||
Action = Hide,
|
|
||||||
DarkerColour = colours.Pink2,
|
|
||||||
LighterColour = colours.Pink1
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (ShowModEffects)
|
|
||||||
{
|
|
||||||
FooterContent.Add(footerContentFlow = new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Spacing = new Vector2(30, 10),
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight,
|
|
||||||
Margin = new MarginPadding
|
|
||||||
{
|
|
||||||
Vertical = PADDING,
|
|
||||||
Horizontal = 20
|
|
||||||
},
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
rankingInformationDisplay = new RankingInformationDisplay
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight
|
|
||||||
},
|
|
||||||
beatmapAttributesDisplay = new BeatmapAttributesDisplay
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight,
|
|
||||||
BeatmapInfo = { Value = Beatmap?.BeatmapInfo },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
globalAvailableMods.BindTo(game.AvailableMods);
|
globalAvailableMods.BindTo(game.AvailableMods);
|
||||||
|
|
||||||
textSearchStartsActive = configManager.GetBindable<bool>(OsuSetting.ModSelectTextSearchStartsActive);
|
textSearchStartsActive = configManager.GetBindable<bool>(OsuSetting.ModSelectTextSearchStartsActive);
|
||||||
@ -292,8 +214,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
SearchTextBox.Current.Value = string.Empty;
|
SearchTextBox.Current.Value = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModSettingChangeTracker? modSettingChangeTracker;
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
// this is called before base call so that the mod state is populated early, and the transition in `PopIn()` can play out properly.
|
// this is called before base call so that the mod state is populated early, and the transition in `PopIn()` can play out properly.
|
||||||
@ -316,23 +236,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
ActiveMods.Value = ComputeActiveMods();
|
ActiveMods.Value = ComputeActiveMods();
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
ActiveMods.BindValueChanged(_ =>
|
|
||||||
{
|
|
||||||
updateOverlayInformation();
|
|
||||||
|
|
||||||
modSettingChangeTracker?.Dispose();
|
|
||||||
|
|
||||||
if (AllowCustomisation)
|
|
||||||
{
|
|
||||||
// Importantly, use ActiveMods.Value here (and not the ValueChanged NewValue) as the latter can
|
|
||||||
// potentially be stale, due to complexities in the way change trackers work.
|
|
||||||
//
|
|
||||||
// See https://github.com/ppy/osu/pull/23284#issuecomment-1529056988
|
|
||||||
modSettingChangeTracker = new ModSettingChangeTracker(ActiveMods.Value);
|
|
||||||
modSettingChangeTracker.SettingChanged += _ => updateOverlayInformation();
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
customisationPanel.Expanded.BindValueChanged(_ => updateCustomisationVisualState(), true);
|
customisationPanel.Expanded.BindValueChanged(_ => updateCustomisationVisualState(), true);
|
||||||
|
|
||||||
SearchTextBox.Current.BindValueChanged(query =>
|
SearchTextBox.Current.BindValueChanged(query =>
|
||||||
@ -350,6 +253,16 @@ namespace osu.Game.Overlays.Mods
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ModSelectFooterContent? currentFooterContent;
|
||||||
|
|
||||||
|
public override bool UseNewFooter => true;
|
||||||
|
|
||||||
|
public override Drawable CreateFooterContent() => currentFooterContent = new ModSelectFooterContent(this)
|
||||||
|
{
|
||||||
|
Beatmap = { BindTarget = Beatmap },
|
||||||
|
ActiveMods = { BindTarget = ActiveMods },
|
||||||
|
};
|
||||||
|
|
||||||
private static readonly LocalisableString input_search_placeholder = Resources.Localisation.Web.CommonStrings.InputSearch;
|
private static readonly LocalisableString input_search_placeholder = Resources.Localisation.Web.CommonStrings.InputSearch;
|
||||||
private static readonly LocalisableString tab_to_search_placeholder = ModSelectOverlayStrings.TabToSearch;
|
private static readonly LocalisableString tab_to_search_placeholder = ModSelectOverlayStrings.TabToSearch;
|
||||||
|
|
||||||
@ -358,26 +271,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
SearchTextBox.PlaceholderText = SearchTextBox.HasFocus ? input_search_placeholder : tab_to_search_placeholder;
|
SearchTextBox.PlaceholderText = SearchTextBox.HasFocus ? input_search_placeholder : tab_to_search_placeholder;
|
||||||
|
aboveColumnsContent.Padding = aboveColumnsContent.Padding with { Bottom = currentFooterContent?.DisplaysStackedVertically == true ? 75f : 15f };
|
||||||
if (beatmapAttributesDisplay != null)
|
|
||||||
{
|
|
||||||
float rightEdgeOfLastButton = footerButtonFlow[^1].ScreenSpaceDrawQuad.TopRight.X;
|
|
||||||
|
|
||||||
// this is cheating a bit; the 640 value is hardcoded based on how wide the expanded panel _generally_ is.
|
|
||||||
// due to the transition applied, the raw screenspace quad of the panel cannot be used, as it will trigger an ugly feedback cycle of expanding and collapsing.
|
|
||||||
float projectedLeftEdgeOfExpandedBeatmapAttributesDisplay = footerButtonFlow.ToScreenSpace(footerButtonFlow.DrawSize - new Vector2(640, 0)).X;
|
|
||||||
|
|
||||||
bool screenIsntWideEnough = rightEdgeOfLastButton > projectedLeftEdgeOfExpandedBeatmapAttributesDisplay;
|
|
||||||
|
|
||||||
// only update preview panel's collapsed state after we are fully visible, to ensure all the buttons are where we expect them to be.
|
|
||||||
if (Alpha == 1)
|
|
||||||
beatmapAttributesDisplay.Collapsed.Value = screenIsntWideEnough;
|
|
||||||
|
|
||||||
footerContentFlow.LayoutDuration = 200;
|
|
||||||
footerContentFlow.LayoutEasing = Easing.OutQuint;
|
|
||||||
footerContentFlow.Direction = screenIsntWideEnough ? FillDirection.Vertical : FillDirection.Horizontal;
|
|
||||||
aboveColumnsContent.Padding = aboveColumnsContent.Padding with { Bottom = screenIsntWideEnough ? 70f : 15f };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -455,27 +349,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
modState.ValidForSelection.Value = modState.Mod.Type != ModType.System && modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
|
modState.ValidForSelection.Value = modState.Mod.Type != ModType.System && modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates any information displayed on the overlay regarding the effects of the active mods.
|
|
||||||
/// This reads from <see cref="ActiveMods"/> instead of <see cref="SelectedMods"/>.
|
|
||||||
/// </summary>
|
|
||||||
private void updateOverlayInformation()
|
|
||||||
{
|
|
||||||
if (rankingInformationDisplay != null)
|
|
||||||
{
|
|
||||||
double multiplier = 1.0;
|
|
||||||
|
|
||||||
foreach (var mod in ActiveMods.Value)
|
|
||||||
multiplier *= mod.ScoreMultiplier;
|
|
||||||
|
|
||||||
rankingInformationDisplay.ModMultiplier.Value = multiplier;
|
|
||||||
rankingInformationDisplay.Ranked.Value = ActiveMods.Value.All(m => m.Ranked);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beatmapAttributesDisplay != null)
|
|
||||||
beatmapAttributesDisplay.Mods.Value = ActiveMods.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCustomisation()
|
private void updateCustomisation()
|
||||||
{
|
{
|
||||||
if (!AllowCustomisation)
|
if (!AllowCustomisation)
|
||||||
@ -701,7 +574,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
if (!SearchTextBox.HasFocus && !customisationPanel.Expanded.Value)
|
if (!SearchTextBox.HasFocus && !customisationPanel.Expanded.Value)
|
||||||
{
|
{
|
||||||
deselectAllModsButton.TriggerClick();
|
currentFooterContent?.DeselectAllModsButton?.TriggerClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -732,7 +605,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
return base.OnPressed(e);
|
return base.OnPressed(e);
|
||||||
|
|
||||||
void hideOverlay() => BackButton.TriggerClick();
|
void hideOverlay() => footer?.BackButton.TriggerClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IKeyBindingHandler{PlatformAction}"/>
|
/// <inheritdoc cref="IKeyBindingHandler{PlatformAction}"/>
|
||||||
@ -740,7 +613,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
/// This is handled locally here due to conflicts in input handling between the search text box and the select all mods button.
|
/// This is handled locally here due to conflicts in input handling between the search text box and the select all mods button.
|
||||||
/// Attempting to handle this action locally in both places leads to a possible scenario
|
/// Attempting to handle this action locally in both places leads to a possible scenario
|
||||||
/// wherein activating the "select all" platform binding will both select all text in the search box and select all mods.
|
/// wherein activating the "select all" platform binding will both select all text in the search box and select all mods.
|
||||||
/// </remarks>>
|
/// </remarks>
|
||||||
public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
|
public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
|
||||||
{
|
{
|
||||||
if (e.Repeat || e.Action != PlatformAction.SelectAll || SelectAllModsButton == null)
|
if (e.Repeat || e.Action != PlatformAction.SelectAll || SelectAllModsButton == null)
|
||||||
|
@ -14,8 +14,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
{
|
{
|
||||||
public partial class FreeModSelectOverlay : ModSelectOverlay
|
public partial class FreeModSelectOverlay : ModSelectOverlay
|
||||||
{
|
{
|
||||||
protected override bool ShowModEffects => false;
|
|
||||||
|
|
||||||
protected override bool AllowCustomisation => false;
|
protected override bool AllowCustomisation => false;
|
||||||
|
|
||||||
public new Func<Mod, bool> IsValidMod
|
public new Func<Mod, bool> IsValidMod
|
||||||
@ -24,6 +22,10 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
set => base.IsValidMod = m => m.UserPlayable && value.Invoke(m);
|
set => base.IsValidMod = m => m.UserPlayable && value.Invoke(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FreeModSelectFooterContent? currentFooterContent;
|
||||||
|
|
||||||
|
protected override SelectAllModsButton? SelectAllModsButton => currentFooterContent?.SelectAllModsButton;
|
||||||
|
|
||||||
public FreeModSelectOverlay()
|
public FreeModSelectOverlay()
|
||||||
: base(OverlayColourScheme.Plum)
|
: base(OverlayColourScheme.Plum)
|
||||||
{
|
{
|
||||||
@ -32,12 +34,33 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
protected override ModColumn CreateModColumn(ModType modType) => new ModColumn(modType, true);
|
protected override ModColumn CreateModColumn(ModType modType) => new ModColumn(modType, true);
|
||||||
|
|
||||||
protected override IEnumerable<ShearedButton> CreateFooterButtons()
|
public override Drawable CreateFooterContent() => currentFooterContent = new FreeModSelectFooterContent(this)
|
||||||
=> base.CreateFooterButtons()
|
{
|
||||||
.Prepend(SelectAllModsButton = new SelectAllModsButton(this)
|
Beatmap = { BindTarget = Beatmap },
|
||||||
{
|
ActiveMods = { BindTarget = ActiveMods },
|
||||||
Anchor = Anchor.BottomLeft,
|
};
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
});
|
private partial class FreeModSelectFooterContent : ModSelectFooterContent
|
||||||
|
{
|
||||||
|
private readonly FreeModSelectOverlay overlay;
|
||||||
|
|
||||||
|
protected override bool ShowModEffects => false;
|
||||||
|
|
||||||
|
public SelectAllModsButton? SelectAllModsButton;
|
||||||
|
|
||||||
|
public FreeModSelectFooterContent(FreeModSelectOverlay overlay)
|
||||||
|
: base(overlay)
|
||||||
|
{
|
||||||
|
this.overlay = overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<ShearedButton> CreateButtons()
|
||||||
|
=> base.CreateButtons()
|
||||||
|
.Prepend(SelectAllModsButton = new SelectAllModsButton(overlay)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,7 +453,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
|
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
|
||||||
var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineID == beatmap.OnlineID);
|
var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineID == beatmap.OnlineID);
|
||||||
|
|
||||||
UserModsSelectOverlay.Beatmap = Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
UserModsSelectOverlay.Beatmap.Value = Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateMods()
|
protected virtual void UpdateMods()
|
||||||
|
@ -851,7 +851,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
BeatmapDetails.Beatmap = beatmap;
|
BeatmapDetails.Beatmap = beatmap;
|
||||||
|
|
||||||
ModSelect.Beatmap = beatmap;
|
ModSelect.Beatmap.Value = beatmap;
|
||||||
|
|
||||||
advancedStats.BeatmapInfo = beatmap.BeatmapInfo;
|
advancedStats.BeatmapInfo = beatmap.BeatmapInfo;
|
||||||
|
|
||||||
|
@ -658,7 +658,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private partial class TestModSelectOverlay : UserModSelectOverlay
|
private partial class TestModSelectOverlay : UserModSelectOverlay
|
||||||
{
|
{
|
||||||
protected override bool ShowModEffects => true;
|
|
||||||
protected override bool ShowPresets => false;
|
protected override bool ShowPresets => false;
|
||||||
|
|
||||||
public TestModSelectOverlay()
|
public TestModSelectOverlay()
|
||||||
|
Loading…
Reference in New Issue
Block a user