mirror of
https://github.com/osukey/osukey.git
synced 2025-05-03 20:57:28 +09:00
Merge pull request #18111 from bdach/mod-overlay/integration
Replace old mod overlay with new design
This commit is contained in:
commit
3bb22dece6
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -283,7 +282,7 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
AddUntilStep("Song select has selection", () => songSelect.Carousel?.SelectedBeatmapInfo != null);
|
AddUntilStep("Song select has selection", () => songSelect.Carousel?.SelectedBeatmapInfo != null);
|
||||||
AddStep("Set default user settings", () =>
|
AddStep("Set default user settings", () =>
|
||||||
{
|
{
|
||||||
SelectedMods.Value = SelectedMods.Value.Concat(new[] { new OsuModNoFail() }).ToArray();
|
SelectedMods.Value = new[] { new OsuModNoFail() };
|
||||||
songSelect.DimLevel.Value = 0.7f;
|
songSelect.DimLevel.Value = 0.7f;
|
||||||
songSelect.BlurLevel.Value = 0.4f;
|
songSelect.BlurLevel.Value = 0.4f;
|
||||||
});
|
});
|
||||||
|
@ -627,7 +627,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
AddStep("invoke on back button", () => multiplayerComponents.OnBackButton());
|
AddStep("invoke on back button", () => multiplayerComponents.OnBackButton());
|
||||||
|
|
||||||
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<UserModSelectOverlay>().Single().State.Value == Visibility.Hidden);
|
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<UserModSelectScreen>().Single().State.Value == Visibility.Hidden);
|
||||||
|
|
||||||
AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden);
|
AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden);
|
||||||
|
|
||||||
|
@ -132,7 +132,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
private void assertHasFreeModButton(Type type, bool hasButton = true)
|
private void assertHasFreeModButton(Type type, bool hasButton = true)
|
||||||
{
|
{
|
||||||
AddAssert($"{type.ReadableName()} {(hasButton ? "displayed" : "not displayed")} in freemod overlay",
|
AddAssert($"{type.ReadableName()} {(hasButton ? "displayed" : "not displayed")} in freemod overlay",
|
||||||
() => songSelect.ChildrenOfType<FreeModSelectOverlay>().Single().ChildrenOfType<ModButton>().All(b => b.Mod.GetType() != type));
|
() => this.ChildrenOfType<FreeModSelectScreen>()
|
||||||
|
.Single()
|
||||||
|
.ChildrenOfType<ModPanel>()
|
||||||
|
.Where(panel => !panel.Filtered.Value)
|
||||||
|
.All(b => b.Mod.GetType() != type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestMultiplayerMatchSongSelect : MultiplayerMatchSongSelect
|
private class TestMultiplayerMatchSongSelect : MultiplayerMatchSongSelect
|
||||||
|
@ -168,8 +168,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
ClickButtonWhenEnabled<RoomSubScreen.UserModSelectButton>();
|
ClickButtonWhenEnabled<RoomSubScreen.UserModSelectButton>();
|
||||||
|
|
||||||
|
AddUntilStep("mod select contents loaded",
|
||||||
|
() => this.ChildrenOfType<ModColumn>().Any() && this.ChildrenOfType<ModColumn>().All(col => col.IsLoaded && col.ItemsLoaded));
|
||||||
AddUntilStep("mod select contains only double time mod",
|
AddUntilStep("mod select contains only double time mod",
|
||||||
() => this.ChildrenOfType<UserModSelectOverlay>().SingleOrDefault()?.ChildrenOfType<ModButton>().SingleOrDefault()?.Mod is OsuModDoubleTime);
|
() => this.ChildrenOfType<UserModSelectScreen>()
|
||||||
|
.SingleOrDefault()?
|
||||||
|
.ChildrenOfType<ModPanel>()
|
||||||
|
.SingleOrDefault(panel => !panel.Filtered.Value)?.Mod is OsuModDoubleTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,12 +253,12 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||||
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
||||||
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
||||||
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
|
|
||||||
|
|
||||||
// BackButton handles hover using its child button, so this checks whether or not any of BackButton's children are hovered.
|
AddStep("Move mouse to dimmed area", () => InputManager.MoveMouseTo(new Vector2(
|
||||||
AddUntilStep("Back button is hovered", () => Game.ChildrenOfType<BackButton>().First().Children.Any(c => c.IsHovered));
|
songSelect.ScreenSpaceDrawQuad.TopLeft.X + 1,
|
||||||
|
songSelect.ScreenSpaceDrawQuad.TopLeft.Y + songSelect.ScreenSpaceDrawQuad.Height / 2)));
|
||||||
|
AddStep("Click left mouse button", () => InputManager.Click(MouseButton.Left));
|
||||||
|
|
||||||
AddStep("Click back button", () => InputManager.Click(MouseButton.Left));
|
|
||||||
AddUntilStep("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
|
AddUntilStep("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
|
||||||
exitViaBackButtonAndConfirm();
|
exitViaBackButtonAndConfirm();
|
||||||
}
|
}
|
||||||
@ -551,7 +551,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
public class TestPlaySongSelect : PlaySongSelect
|
public class TestPlaySongSelect : PlaySongSelect
|
||||||
{
|
{
|
||||||
public ModSelectOverlay ModSelectOverlay => ModSelect;
|
public ModSelectScreen ModSelectOverlay => ModSelect;
|
||||||
|
|
||||||
public BeatmapOptionsOverlay BeatmapOptionsOverlay => BeatmapOptions;
|
public BeatmapOptionsOverlay BeatmapOptionsOverlay => BeatmapOptions;
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -18,6 +19,7 @@ using osu.Game.Extensions;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
@ -918,6 +920,19 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
|
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestModOverlayToggling()
|
||||||
|
{
|
||||||
|
changeRuleset(0);
|
||||||
|
createSongSelect();
|
||||||
|
|
||||||
|
AddStep("toggle mod overlay on", () => InputManager.Key(Key.F1));
|
||||||
|
AddUntilStep("mod overlay shown", () => songSelect.ModSelect.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("toggle mod overlay off", () => InputManager.Key(Key.F1));
|
||||||
|
AddUntilStep("mod overlay hidden", () => songSelect.ModSelect.State.Value == Visibility.Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
private void waitForInitialSelection()
|
private void waitForInitialSelection()
|
||||||
{
|
{
|
||||||
AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
|
AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
|
||||||
@ -993,6 +1008,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
|
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
|
||||||
public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
|
public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
|
||||||
public new BeatmapCarousel Carousel => base.Carousel;
|
public new BeatmapCarousel Carousel => base.Carousel;
|
||||||
|
public new ModSelectScreen ModSelect => base.ModSelect;
|
||||||
|
|
||||||
public new void PresentScore(ScoreInfo score) => base.PresentScore(score);
|
public new void PresentScore(ScoreInfo score) => base.PresentScore(score);
|
||||||
|
|
||||||
|
@ -66,7 +66,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
public class TestShearedOverlayContainer : ShearedOverlayContainer
|
public class TestShearedOverlayContainer : ShearedOverlayContainer
|
||||||
{
|
{
|
||||||
protected override OverlayColourScheme ColourScheme => OverlayColourScheme.Green;
|
public TestShearedOverlayContainer()
|
||||||
|
: base(OverlayColourScheme.Green)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
protected virtual bool DimMainContent => true;
|
protected virtual bool DimMainContent => true;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private OsuGame game { get; set; }
|
private IOverlayManager overlayManager { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private PreviewTrackManager previewTrackManager { get; set; }
|
private PreviewTrackManager previewTrackManager { get; set; }
|
||||||
@ -50,8 +50,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
if (game != null)
|
if (overlayManager != null)
|
||||||
OverlayActivationMode.BindTo(game.OverlayActivationMode);
|
OverlayActivationMode.BindTo(overlayManager.OverlayActivationMode);
|
||||||
|
|
||||||
OverlayActivationMode.BindValueChanged(mode =>
|
OverlayActivationMode.BindValueChanged(mode =>
|
||||||
{
|
{
|
||||||
@ -127,14 +127,14 @@ namespace osu.Game.Graphics.Containers
|
|||||||
if (didChange)
|
if (didChange)
|
||||||
samplePopIn?.Play();
|
samplePopIn?.Play();
|
||||||
|
|
||||||
if (BlockScreenWideMouse && DimMainContent) game?.AddBlockingOverlay(this);
|
if (BlockScreenWideMouse && DimMainContent) overlayManager?.ShowBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Visibility.Hidden:
|
case Visibility.Hidden:
|
||||||
if (didChange)
|
if (didChange)
|
||||||
samplePopOut?.Play();
|
samplePopOut?.Play();
|
||||||
|
|
||||||
if (BlockScreenWideMouse) game?.RemoveBlockingOverlay(this);
|
if (BlockScreenWideMouse) overlayManager?.HideBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
game?.RemoveBlockingOverlay(this);
|
overlayManager?.HideBlockingOverlay(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game
|
|||||||
/// The full osu! experience. Builds on top of <see cref="OsuGameBase"/> to add menus and binding logic
|
/// The full osu! experience. Builds on top of <see cref="OsuGameBase"/> to add menus and binding logic
|
||||||
/// for initial components that are generally retrieved via DI.
|
/// for initial components that are generally retrieved via DI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>, ILocalUserPlayInfo, IPerformFromScreenRunner
|
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications).
|
/// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications).
|
||||||
@ -171,6 +171,7 @@ namespace osu.Game
|
|||||||
private readonly string[] args;
|
private readonly string[] args;
|
||||||
|
|
||||||
private readonly List<OsuFocusedOverlayContainer> focusedOverlays = new List<OsuFocusedOverlayContainer>();
|
private readonly List<OsuFocusedOverlayContainer> focusedOverlays = new List<OsuFocusedOverlayContainer>();
|
||||||
|
private readonly List<OverlayContainer> externalOverlays = new List<OverlayContainer>();
|
||||||
|
|
||||||
private readonly List<OverlayContainer> visibleBlockingOverlays = new List<OverlayContainer>();
|
private readonly List<OverlayContainer> visibleBlockingOverlays = new List<OverlayContainer>();
|
||||||
|
|
||||||
@ -183,22 +184,50 @@ namespace osu.Game
|
|||||||
SentryLogger = new SentryLogger(this);
|
SentryLogger = new SentryLogger(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region IOverlayManager
|
||||||
|
|
||||||
|
IBindable<OverlayActivation> IOverlayManager.OverlayActivationMode => OverlayActivationMode;
|
||||||
|
|
||||||
private void updateBlockingOverlayFade() =>
|
private void updateBlockingOverlayFade() =>
|
||||||
ScreenContainer.FadeColour(visibleBlockingOverlays.Any() ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
|
ScreenContainer.FadeColour(visibleBlockingOverlays.Any() ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
|
||||||
|
|
||||||
public void AddBlockingOverlay(OverlayContainer overlay)
|
IDisposable IOverlayManager.RegisterBlockingOverlay(OverlayContainer overlayContainer)
|
||||||
|
{
|
||||||
|
if (overlayContainer.Parent != null)
|
||||||
|
throw new ArgumentException($@"Overlays registered via {nameof(IOverlayManager.RegisterBlockingOverlay)} should not be added to the scene graph.");
|
||||||
|
|
||||||
|
if (externalOverlays.Contains(overlayContainer))
|
||||||
|
throw new ArgumentException($@"{overlayContainer} has already been registered via {nameof(IOverlayManager.RegisterBlockingOverlay)} once.");
|
||||||
|
|
||||||
|
externalOverlays.Add(overlayContainer);
|
||||||
|
overlayContent.Add(overlayContainer);
|
||||||
|
return new InvokeOnDisposal(() => unregisterBlockingOverlay(overlayContainer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOverlayManager.ShowBlockingOverlay(OverlayContainer overlay)
|
||||||
{
|
{
|
||||||
if (!visibleBlockingOverlays.Contains(overlay))
|
if (!visibleBlockingOverlays.Contains(overlay))
|
||||||
visibleBlockingOverlays.Add(overlay);
|
visibleBlockingOverlays.Add(overlay);
|
||||||
updateBlockingOverlayFade();
|
updateBlockingOverlayFade();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveBlockingOverlay(OverlayContainer overlay) => Schedule(() =>
|
void IOverlayManager.HideBlockingOverlay(OverlayContainer overlay) => Schedule(() =>
|
||||||
{
|
{
|
||||||
visibleBlockingOverlays.Remove(overlay);
|
visibleBlockingOverlays.Remove(overlay);
|
||||||
updateBlockingOverlayFade();
|
updateBlockingOverlayFade();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unregisters a blocking <see cref="OverlayContainer"/> that was not created by <see cref="OsuGame"/> itself.
|
||||||
|
/// </summary>
|
||||||
|
private void unregisterBlockingOverlay(OverlayContainer overlayContainer)
|
||||||
|
{
|
||||||
|
externalOverlays.Remove(overlayContainer);
|
||||||
|
overlayContainer.Expire();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Close all game-wide overlays.
|
/// Close all game-wide overlays.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -31,8 +31,6 @@ namespace osu.Game.Overlays
|
|||||||
[Cached]
|
[Cached]
|
||||||
public class FirstRunSetupOverlay : ShearedOverlayContainer
|
public class FirstRunSetupOverlay : ShearedOverlayContainer
|
||||||
{
|
{
|
||||||
protected override OverlayColourScheme ColourScheme => OverlayColourScheme.Purple;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IPerformFromScreenRunner performer { get; set; } = null!;
|
private IPerformFromScreenRunner performer { get; set; } = null!;
|
||||||
|
|
||||||
@ -70,6 +68,11 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private Container content = null!;
|
private Container content = null!;
|
||||||
|
|
||||||
|
public FirstRunSetupOverlay()
|
||||||
|
: base(OverlayColourScheme.Purple)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
|
44
osu.Game/Overlays/IOverlayManager.cs
Normal file
44
osu.Game/Overlays/IOverlayManager.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
internal interface IOverlayManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether overlays should be able to be opened game-wide. Value is sourced from the current active screen.
|
||||||
|
/// </summary>
|
||||||
|
IBindable<OverlayActivation> OverlayActivationMode { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a blocking <see cref="OverlayContainer"/> that was not created by <see cref="OsuGame"/> itself for later use.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The goal of this method is to allow child screens, like <see cref="SongSelect"/> to register their own full-screen blocking overlays
|
||||||
|
/// with background dim.
|
||||||
|
/// In those cases, for the dim to work correctly, the overlays need to be added at a game level directly, rather as children of the screens.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// An <see cref="IDisposable"/> that should be disposed of when the <paramref name="overlayContainer"/> should be unregistered.
|
||||||
|
/// Disposing of this <see cref="IDisposable"/> will automatically expire the <paramref name="overlayContainer"/>.
|
||||||
|
/// </returns>
|
||||||
|
IDisposable RegisterBlockingOverlay(OverlayContainer overlayContainer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should be called when <paramref name="overlay"/> has been shown and should begin blocking background input.
|
||||||
|
/// </summary>
|
||||||
|
void ShowBlockingOverlay(OverlayContainer overlay);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should be called when a blocking <paramref name="overlay"/> has been hidden and should stop blocking background input.
|
||||||
|
/// </summary>
|
||||||
|
void HideBlockingOverlay(OverlayContainer overlay);
|
||||||
|
}
|
||||||
|
}
|
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
private Func<Mod, bool>? filter;
|
private Func<Mod, bool>? filter;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Function determining whether each mod in the column should be displayed.
|
/// A function determining whether each mod in the column should be displayed.
|
||||||
/// A return value of <see langword="true"/> means that the mod is not filtered and therefore its corresponding panel should be displayed.
|
/// A return value of <see langword="true"/> means that the mod is not filtered and therefore its corresponding panel should be displayed.
|
||||||
/// A return value of <see langword="false"/> means that the mod is filtered out and therefore its corresponding panel should be hidden.
|
/// A return value of <see langword="false"/> means that the mod is filtered out and therefore its corresponding panel should be hidden.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -250,9 +250,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
private void load(OsuGameBase game, OverlayColourProvider colourProvider, OsuColour colours)
|
private void load(OsuGameBase game, OverlayColourProvider colourProvider, OsuColour colours)
|
||||||
{
|
{
|
||||||
availableMods.BindTo(game.AvailableMods);
|
availableMods.BindTo(game.AvailableMods);
|
||||||
// this `BindValueChanged` callback is intentionally here, to ensure that local available mods are constructed as early as possible.
|
updateLocalAvailableMods(asyncLoadContent: false);
|
||||||
// this is needed to make sure no external changes to mods are dropped while mod panels are asynchronously loading.
|
availableMods.BindValueChanged(_ => updateLocalAvailableMods(asyncLoadContent: true));
|
||||||
availableMods.BindValueChanged(_ => updateLocalAvailableMods(), true);
|
|
||||||
|
|
||||||
headerBackground.Colour = accentColour = colours.ForModType(ModType);
|
headerBackground.Colour = accentColour = colours.ForModType(ModType);
|
||||||
|
|
||||||
@ -279,7 +278,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
toggleAllCheckbox.LabelText = toggleAllCheckbox.Current.Value ? CommonStrings.DeselectAll : CommonStrings.SelectAll;
|
toggleAllCheckbox.LabelText = toggleAllCheckbox.Current.Value ? CommonStrings.DeselectAll : CommonStrings.SelectAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLocalAvailableMods()
|
private void updateLocalAvailableMods(bool asyncLoadContent)
|
||||||
{
|
{
|
||||||
var newMods = ModUtils.FlattenMods(availableMods.Value.GetValueOrDefault(ModType) ?? Array.Empty<Mod>())
|
var newMods = ModUtils.FlattenMods(availableMods.Value.GetValueOrDefault(ModType) ?? Array.Empty<Mod>())
|
||||||
.Select(m => m.DeepClone())
|
.Select(m => m.DeepClone())
|
||||||
@ -290,11 +289,10 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
localAvailableMods = newMods;
|
localAvailableMods = newMods;
|
||||||
|
|
||||||
if (!IsLoaded)
|
if (asyncLoadContent)
|
||||||
// if we're coming from BDL, perform the first load synchronously to make sure everything is in place as early as possible.
|
|
||||||
onPanelsLoaded(createPanels());
|
|
||||||
else
|
|
||||||
asyncLoadPanels();
|
asyncLoadPanels();
|
||||||
|
else
|
||||||
|
onPanelsLoaded(createPanels());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CancellationTokenSource? cancellationTokenSource;
|
private CancellationTokenSource? cancellationTokenSource;
|
||||||
|
@ -20,10 +20,10 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
using osu.Game.Localisation;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
@ -31,13 +31,16 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
protected const int BUTTON_WIDTH = 200;
|
protected const int BUTTON_WIDTH = 200;
|
||||||
|
|
||||||
protected override OverlayColourScheme ColourScheme => OverlayColourScheme.Green;
|
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
public Bindable<IReadOnlyList<Mod>> SelectedMods { get; private set; } = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
public Bindable<IReadOnlyList<Mod>> SelectedMods { get; private set; } = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
private Func<Mod, bool> isValidMod = m => true;
|
private Func<Mod, bool> isValidMod = m => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A function determining whether each mod in the column should be displayed.
|
||||||
|
/// A return value of <see langword="true"/> means that the mod is not filtered and therefore its corresponding panel should be displayed.
|
||||||
|
/// A return value of <see langword="false"/> means that the mod is filtered out and therefore its corresponding panel should be hidden.
|
||||||
|
/// </summary>
|
||||||
public Func<Mod, bool> IsValidMod
|
public Func<Mod, bool> IsValidMod
|
||||||
{
|
{
|
||||||
get => isValidMod;
|
get => isValidMod;
|
||||||
@ -57,31 +60,27 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
protected virtual ModColumn CreateModColumn(ModType modType, Key[]? toggleKeys = null) => new ModColumn(modType, false, toggleKeys);
|
protected virtual ModColumn CreateModColumn(ModType modType, Key[]? toggleKeys = null) => new ModColumn(modType, false, toggleKeys);
|
||||||
|
|
||||||
protected virtual IEnumerable<ShearedButton> CreateFooterButtons() => new[]
|
protected virtual IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection) => newSelection;
|
||||||
{
|
|
||||||
customisationButton = new ShearedToggleButton(BUTTON_WIDTH)
|
protected virtual IEnumerable<ShearedButton> CreateFooterButtons() => createDefaultFooterButtons();
|
||||||
{
|
|
||||||
Text = ModSelectScreenStrings.ModCustomisation,
|
|
||||||
Active = { BindTarget = customisationVisible }
|
|
||||||
},
|
|
||||||
new ShearedButton(BUTTON_WIDTH)
|
|
||||||
{
|
|
||||||
Text = CommonStrings.DeselectAll,
|
|
||||||
Action = DeselectAll
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly BindableBool customisationVisible = new BindableBool();
|
private readonly BindableBool customisationVisible = new BindableBool();
|
||||||
|
|
||||||
private DifficultyMultiplierDisplay? multiplierDisplay;
|
|
||||||
private ModSettingsArea modSettingsArea = null!;
|
private ModSettingsArea modSettingsArea = null!;
|
||||||
private ColumnScrollContainer columnScroll = null!;
|
private ColumnScrollContainer columnScroll = null!;
|
||||||
private ColumnFlowContainer columnFlow = null!;
|
private ColumnFlowContainer columnFlow = null!;
|
||||||
|
|
||||||
private FillFlowContainer<ShearedButton> footerButtonFlow = null!;
|
private FillFlowContainer<ShearedButton> footerButtonFlow = null!;
|
||||||
private ShearedButton backButton = null!;
|
private ShearedButton backButton = null!;
|
||||||
|
|
||||||
|
private DifficultyMultiplierDisplay? multiplierDisplay;
|
||||||
|
|
||||||
private ShearedToggleButton? customisationButton;
|
private ShearedToggleButton? customisationButton;
|
||||||
|
|
||||||
|
protected ModSelectScreen(OverlayColourScheme colourScheme = OverlayColourScheme.Green)
|
||||||
|
: base(colourScheme)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
@ -185,14 +184,6 @@ namespace osu.Game.Overlays.Mods
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private ColumnDimContainer createModColumnContent(ModType modType, Key[]? toggleKeys = null)
|
|
||||||
=> new ColumnDimContainer(CreateModColumn(modType, toggleKeys))
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
RequestScroll = column => columnScroll.ScrollIntoView(column, extraScroll: 140)
|
|
||||||
};
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
@ -216,6 +207,47 @@ namespace osu.Game.Overlays.Mods
|
|||||||
updateAvailableMods();
|
updateAvailableMods();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Select all visible mods in all columns.
|
||||||
|
/// </summary>
|
||||||
|
protected void SelectAll()
|
||||||
|
{
|
||||||
|
foreach (var column in columnFlow.Columns)
|
||||||
|
column.SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deselect all visible mods in all columns.
|
||||||
|
/// </summary>
|
||||||
|
protected void DeselectAll()
|
||||||
|
{
|
||||||
|
foreach (var column in columnFlow.Columns)
|
||||||
|
column.DeselectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColumnDimContainer createModColumnContent(ModType modType, Key[]? toggleKeys = null)
|
||||||
|
=> new ColumnDimContainer(CreateModColumn(modType, toggleKeys))
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
RequestScroll = column => columnScroll.ScrollIntoView(column, extraScroll: 140)
|
||||||
|
};
|
||||||
|
|
||||||
|
private ShearedButton[] createDefaultFooterButtons()
|
||||||
|
=> new[]
|
||||||
|
{
|
||||||
|
customisationButton = new ShearedToggleButton(BUTTON_WIDTH)
|
||||||
|
{
|
||||||
|
Text = ModSelectScreenStrings.ModCustomisation,
|
||||||
|
Active = { BindTarget = customisationVisible }
|
||||||
|
},
|
||||||
|
new ShearedButton(BUTTON_WIDTH)
|
||||||
|
{
|
||||||
|
Text = CommonStrings.DeselectAll,
|
||||||
|
Action = DeselectAll
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private void updateMultiplier()
|
private void updateMultiplier()
|
||||||
{
|
{
|
||||||
if (multiplierDisplay == null)
|
if (multiplierDisplay == null)
|
||||||
@ -306,7 +338,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
SelectedMods.Value = ComputeNewModsFromSelection(SelectedMods.Value, candidateSelection);
|
SelectedMods.Value = ComputeNewModsFromSelection(SelectedMods.Value, candidateSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection) => newSelection;
|
#region Transition handling
|
||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
@ -352,20 +384,17 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SelectAll()
|
#endregion
|
||||||
{
|
|
||||||
foreach (var column in columnFlow.Columns)
|
|
||||||
column.SelectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void DeselectAll()
|
#region Input handling
|
||||||
{
|
|
||||||
foreach (var column in columnFlow.Columns)
|
|
||||||
column.DeselectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
{
|
{
|
||||||
|
if (e.Repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// This is handled locally here because this overlay is being registered at the game level
|
||||||
|
// and therefore takes away keyboard focus from the screen stack.
|
||||||
if (e.Action == GlobalAction.Back)
|
if (e.Action == GlobalAction.Back)
|
||||||
{
|
{
|
||||||
if (customisationVisible.Value)
|
if (customisationVisible.Value)
|
||||||
@ -375,9 +404,27 @@ namespace osu.Game.Overlays.Mods
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnPressed(e);
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case GlobalAction.ToggleModSelection:
|
||||||
|
case GlobalAction.Select:
|
||||||
|
{
|
||||||
|
if (customisationVisible.Value)
|
||||||
|
customisationVisible.Value = false;
|
||||||
|
Hide();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return base.OnPressed(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages horizontal scrolling of mod columns, along with the "active" states of each column based on visibility.
|
||||||
|
/// </summary>
|
||||||
internal class ColumnScrollContainer : OsuScrollContainer<ColumnFlowContainer>
|
internal class ColumnScrollContainer : OsuScrollContainer<ColumnFlowContainer>
|
||||||
{
|
{
|
||||||
public ColumnScrollContainer()
|
public ColumnScrollContainer()
|
||||||
@ -416,6 +463,9 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages padding and layout of mod columns.
|
||||||
|
/// </summary>
|
||||||
internal class ColumnFlowContainer : FillFlowContainer<ColumnDimContainer>
|
internal class ColumnFlowContainer : FillFlowContainer<ColumnDimContainer>
|
||||||
{
|
{
|
||||||
public IEnumerable<ModColumn> Columns => Children.Select(dimWrapper => dimWrapper.Column);
|
public IEnumerable<ModColumn> Columns => Children.Select(dimWrapper => dimWrapper.Column);
|
||||||
@ -452,11 +502,21 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encapsulates a column and provides dim and input blocking based on an externally managed "active" state.
|
||||||
|
/// </summary>
|
||||||
internal class ColumnDimContainer : Container
|
internal class ColumnDimContainer : Container
|
||||||
{
|
{
|
||||||
public ModColumn Column { get; }
|
public ModColumn Column { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks whether this column is in an interactive state. Generally only the case when the column is on-screen.
|
||||||
|
/// </summary>
|
||||||
public readonly Bindable<bool> Active = new BindableBool();
|
public readonly Bindable<bool> Active = new BindableBool();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when the column is clicked while not active, requesting a scroll to be performed to bring it on-screen.
|
||||||
|
/// </summary>
|
||||||
public Action<ColumnDimContainer>? RequestScroll { get; set; }
|
public Action<ColumnDimContainer>? RequestScroll { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -511,6 +571,9 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A container which blocks and handles input, managing the "return from customisation" state change.
|
||||||
|
/// </summary>
|
||||||
private class ClickToReturnContainer : Container
|
private class ClickToReturnContainer : Container
|
||||||
{
|
{
|
||||||
public BindableBool HandleMouse { get; } = new BindableBool();
|
public BindableBool HandleMouse { get; } = new BindableBool();
|
||||||
|
@ -51,17 +51,15 @@ namespace osu.Game.Overlays.Mods
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Container FooterContent { get; private set; }
|
protected Container FooterContent { get; private set; }
|
||||||
|
|
||||||
protected abstract OverlayColourScheme ColourScheme { get; }
|
|
||||||
|
|
||||||
protected override bool StartHidden => true;
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
protected override bool BlockNonPositionalInput => true;
|
protected override bool BlockNonPositionalInput => true;
|
||||||
|
|
||||||
protected ShearedOverlayContainer()
|
protected ShearedOverlayContainer(OverlayColourScheme colourScheme)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
ColourProvider = new OverlayColourProvider(ColourScheme);
|
ColourProvider = new OverlayColourProvider(colourScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -12,6 +12,11 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
public class UserModSelectScreen : ModSelectScreen
|
public class UserModSelectScreen : ModSelectScreen
|
||||||
{
|
{
|
||||||
|
public UserModSelectScreen(OverlayColourScheme colourScheme = OverlayColourScheme.Green)
|
||||||
|
: base(colourScheme)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new UserModColumn(modType, false, toggleKeys);
|
protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new UserModColumn(modType, false, toggleKeys);
|
||||||
|
|
||||||
protected override IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection)
|
protected override IReadOnlyList<Mod> ComputeNewModsFromSelection(IReadOnlyList<Mod> oldSelection, IReadOnlyList<Mod> newSelection)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -23,6 +24,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
}
|
}
|
||||||
|
|
||||||
public FreeModSelectScreen()
|
public FreeModSelectScreen()
|
||||||
|
: base(OverlayColourScheme.Plum)
|
||||||
{
|
{
|
||||||
IsValidMod = _ => true;
|
IsValidMod = _ => true;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
@ -57,6 +58,9 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
protected readonly IBindable<long?> RoomId = new Bindable<long?>();
|
protected readonly IBindable<long?> RoomId = new Bindable<long?>();
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private IOverlayManager overlayManager { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private MusicController music { get; set; }
|
private MusicController music { get; set; }
|
||||||
|
|
||||||
@ -77,7 +81,11 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
public readonly Room Room;
|
public readonly Room Room;
|
||||||
private readonly bool allowEdit;
|
private readonly bool allowEdit;
|
||||||
|
|
||||||
private ModSelectOverlay userModsSelectOverlay;
|
private ModSelectScreen userModsSelectOverlay;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
private IDisposable userModsSelectOverlayRegistration;
|
||||||
|
|
||||||
private RoomSettingsOverlay settingsOverlay;
|
private RoomSettingsOverlay settingsOverlay;
|
||||||
private Drawable mainContent;
|
private Drawable mainContent;
|
||||||
|
|
||||||
@ -180,11 +188,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = userModsSelectOverlay = new UserModSelectOverlay
|
|
||||||
{
|
|
||||||
SelectedMods = { BindTarget = UserMods },
|
|
||||||
IsValidMod = _ => false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,6 +230,12 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LoadComponent(userModsSelectOverlay = new UserModSelectScreen(OverlayColourScheme.Plum)
|
||||||
|
{
|
||||||
|
SelectedMods = { BindTarget = UserMods },
|
||||||
|
IsValidMod = _ => false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -254,6 +263,8 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
beatmapAvailabilityTracker.SelectedItem.BindTo(SelectedItem);
|
beatmapAvailabilityTracker.SelectedItem.BindTo(SelectedItem);
|
||||||
beatmapAvailabilityTracker.Availability.BindValueChanged(_ => updateWorkingBeatmap());
|
beatmapAvailabilityTracker.Availability.BindValueChanged(_ => updateWorkingBeatmap());
|
||||||
|
|
||||||
|
userModsSelectOverlayRegistration = overlayManager?.RegisterBlockingOverlay(userModsSelectOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
@ -298,7 +309,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
public override void OnSuspending(ScreenTransitionEvent e)
|
public override void OnSuspending(ScreenTransitionEvent e)
|
||||||
{
|
{
|
||||||
endHandlingTrack();
|
onLeaving();
|
||||||
base.OnSuspending(e);
|
base.OnSuspending(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +327,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
RoomManager?.PartRoom();
|
RoomManager?.PartRoom();
|
||||||
Mods.Value = Array.Empty<Mod>();
|
Mods.Value = Array.Empty<Mod>();
|
||||||
|
|
||||||
endHandlingTrack();
|
onLeaving();
|
||||||
|
|
||||||
return base.OnExiting(e);
|
return base.OnExiting(e);
|
||||||
}
|
}
|
||||||
@ -412,6 +423,12 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
Beatmap.BindValueChanged(applyLoopingToTrack, true);
|
Beatmap.BindValueChanged(applyLoopingToTrack, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onLeaving()
|
||||||
|
{
|
||||||
|
userModsSelectOverlay.Hide();
|
||||||
|
endHandlingTrack();
|
||||||
|
}
|
||||||
|
|
||||||
private void endHandlingTrack()
|
private void endHandlingTrack()
|
||||||
{
|
{
|
||||||
Beatmap.ValueChanged -= applyLoopingToTrack;
|
Beatmap.ValueChanged -= applyLoopingToTrack;
|
||||||
@ -459,5 +476,12 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
public class UserModSelectButton : PurpleTriangleButton
|
public class UserModSelectButton : PurpleTriangleButton
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
userModsSelectOverlayRegistration?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Screens;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -45,7 +46,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
protected readonly Bindable<IReadOnlyList<Mod>> FreeMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
protected readonly Bindable<IReadOnlyList<Mod>> FreeMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
private readonly FreeModSelectOverlay freeModSelectOverlay;
|
|
||||||
private readonly Room room;
|
private readonly Room room;
|
||||||
|
|
||||||
private WorkingBeatmap initialBeatmap;
|
private WorkingBeatmap initialBeatmap;
|
||||||
@ -53,13 +53,16 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
private IReadOnlyList<Mod> initialMods;
|
private IReadOnlyList<Mod> initialMods;
|
||||||
private bool itemSelected;
|
private bool itemSelected;
|
||||||
|
|
||||||
|
private readonly FreeModSelectScreen freeModSelectOverlay;
|
||||||
|
private IDisposable freeModSelectOverlayRegistration;
|
||||||
|
|
||||||
protected OnlinePlaySongSelect(Room room)
|
protected OnlinePlaySongSelect(Room room)
|
||||||
{
|
{
|
||||||
this.room = room;
|
this.room = room;
|
||||||
|
|
||||||
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
|
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
|
||||||
|
|
||||||
freeModSelectOverlay = new FreeModSelectOverlay
|
freeModSelectOverlay = new FreeModSelectScreen
|
||||||
{
|
{
|
||||||
SelectedMods = { BindTarget = FreeMods },
|
SelectedMods = { BindTarget = FreeMods },
|
||||||
IsValidMod = IsValidFreeMod,
|
IsValidMod = IsValidFreeMod,
|
||||||
@ -75,7 +78,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
initialRuleset = Ruleset.Value;
|
initialRuleset = Ruleset.Value;
|
||||||
initialMods = Mods.Value.ToList();
|
initialMods = Mods.Value.ToList();
|
||||||
|
|
||||||
FooterPanels.Add(freeModSelectOverlay);
|
LoadComponent(freeModSelectOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -94,6 +97,8 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
Mods.BindValueChanged(onModsChanged);
|
Mods.BindValueChanged(onModsChanged);
|
||||||
Ruleset.BindValueChanged(onRulesetChanged);
|
Ruleset.BindValueChanged(onRulesetChanged);
|
||||||
|
|
||||||
|
freeModSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(freeModSelectOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
|
private void onModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
|
||||||
@ -150,10 +155,12 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
Mods.Value = initialMods;
|
Mods.Value = initialMods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
freeModSelectOverlay.Hide();
|
||||||
|
|
||||||
return base.OnExiting(e);
|
return base.OnExiting(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay
|
protected override ModSelectScreen CreateModSelectOverlay() => new UserModSelectScreen(OverlayColourScheme.Plum)
|
||||||
{
|
{
|
||||||
IsValidMod = IsValidMod
|
IsValidMod = IsValidMod
|
||||||
};
|
};
|
||||||
@ -182,5 +189,12 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
private bool checkCompatibleFreeMod(Mod mod)
|
private bool checkCompatibleFreeMod(Mod mod)
|
||||||
=> Mods.Value.All(m => m.Acronym != mod.Acronym) // Mod must not be contained in the required mods.
|
=> Mods.Value.All(m => m.Acronym != mod.Acronym) // Mod must not be contained in the required mods.
|
||||||
&& ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()); // Mod must be compatible with all the required mods.
|
&& ModUtils.CheckCompatibleSet(Mods.Value.Append(mod).ToArray()); // Mod must be compatible with all the required mods.
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
freeModSelectOverlayRegistration?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ using osu.Framework.Input.Bindings;
|
|||||||
using osu.Game.Collections;
|
using osu.Game.Collections;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -101,7 +102,7 @@ namespace osu.Game.Screens.Select
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private LegacyImportManager legacyImportManager { get; set; }
|
private LegacyImportManager legacyImportManager { get; set; }
|
||||||
|
|
||||||
protected ModSelectOverlay ModSelect { get; private set; }
|
protected ModSelectScreen ModSelect { get; private set; }
|
||||||
|
|
||||||
protected Sample SampleConfirm { get; private set; }
|
protected Sample SampleConfirm { get; private set; }
|
||||||
|
|
||||||
@ -116,9 +117,15 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private double audioFeedbackLastPlaybackTime;
|
private double audioFeedbackLastPlaybackTime;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
private IDisposable modSelectOverlayRegistration;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private MusicController music { get; set; }
|
private MusicController music { get; set; }
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
internal IOverlayManager OverlayManager { get; private set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(AudioManager audio, IDialogOverlay dialog, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender)
|
private void load(AudioManager audio, IDialogOverlay dialog, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender)
|
||||||
{
|
{
|
||||||
@ -251,19 +258,6 @@ namespace osu.Game.Screens.Select
|
|||||||
if (ShowFooter)
|
if (ShowFooter)
|
||||||
{
|
{
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
|
||||||
new GridContainer // used for max height implementation
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(),
|
|
||||||
new Dimension(GridSizeMode.Relative, 1f, maxSize: ModSelectOverlay.HEIGHT + Footer.HEIGHT),
|
|
||||||
},
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
null,
|
|
||||||
new Drawable[]
|
|
||||||
{
|
{
|
||||||
FooterPanels = new Container
|
FooterPanels = new Container
|
||||||
{
|
{
|
||||||
@ -274,16 +268,16 @@ namespace osu.Game.Screens.Select
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
BeatmapOptions = new BeatmapOptionsOverlay(),
|
BeatmapOptions = new BeatmapOptionsOverlay(),
|
||||||
ModSelect = CreateModSelectOverlay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Footer = new Footer()
|
Footer = new Footer(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// preload the mod select overlay for later use in `LoadComplete()`.
|
||||||
|
// therein it will be registered at the `OsuGame` level to properly function as a blocking overlay.
|
||||||
|
LoadComponent(ModSelect = CreateModSelectOverlay());
|
||||||
|
|
||||||
if (Footer != null)
|
if (Footer != null)
|
||||||
{
|
{
|
||||||
foreach (var (button, overlay) in CreateFooterButtons())
|
foreach (var (button, overlay) in CreateFooterButtons())
|
||||||
@ -317,6 +311,13 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
modSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(ModSelect);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the buttons to be displayed in the footer.
|
/// Creates the buttons to be displayed in the footer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -332,7 +333,7 @@ namespace osu.Game.Screens.Select
|
|||||||
(new FooterButtonOptions(), BeatmapOptions)
|
(new FooterButtonOptions(), BeatmapOptions)
|
||||||
};
|
};
|
||||||
|
|
||||||
protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay();
|
protected virtual ModSelectScreen CreateModSelectOverlay() => new UserModSelectScreen();
|
||||||
|
|
||||||
protected virtual void ApplyFilterToCarousel(FilterCriteria criteria)
|
protected virtual void ApplyFilterToCarousel(FilterCriteria criteria)
|
||||||
{
|
{
|
||||||
@ -658,6 +659,7 @@ namespace osu.Game.Screens.Select
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
beatmapInfoWedge.Hide();
|
beatmapInfoWedge.Hide();
|
||||||
|
ModSelect.Hide();
|
||||||
|
|
||||||
this.FadeOut(100);
|
this.FadeOut(100);
|
||||||
|
|
||||||
@ -716,6 +718,8 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
if (music != null)
|
if (music != null)
|
||||||
music.TrackChanged -= ensureTrackLooping;
|
music.TrackChanged -= ensureTrackLooping;
|
||||||
|
|
||||||
|
modSelectOverlayRegistration?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
|
|
||||||
@ -15,11 +18,12 @@ namespace osu.Game.Tests.Visual
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A test case which can be used to test a screen (that relies on OnEntering being called to execute startup instructions).
|
/// A test case which can be used to test a screen (that relies on OnEntering being called to execute startup instructions).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ScreenTestScene : OsuManualInputManagerTestScene
|
public abstract class ScreenTestScene : OsuManualInputManagerTestScene, IOverlayManager
|
||||||
{
|
{
|
||||||
protected readonly OsuScreenStack Stack;
|
protected readonly OsuScreenStack Stack;
|
||||||
|
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
|
private readonly Container overlayContent;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
@ -36,7 +40,11 @@ namespace osu.Game.Tests.Visual
|
|||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
content = new Container { RelativeSizeAxes = Axes.Both },
|
content = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
DialogOverlay = new DialogOverlay()
|
overlayContent = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = DialogOverlay = new DialogOverlay()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Stack.ScreenPushed += (lastScreen, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed → {newScreen}");
|
Stack.ScreenPushed += (lastScreen, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed → {newScreen}");
|
||||||
@ -65,5 +73,26 @@ namespace osu.Game.Tests.Visual
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region IOverlayManager
|
||||||
|
|
||||||
|
IBindable<OverlayActivation> IOverlayManager.OverlayActivationMode { get; } = new Bindable<OverlayActivation>(OverlayActivation.All);
|
||||||
|
|
||||||
|
// in the blocking methods below it is important to be careful about threading (e.g. use `Expire()` rather than `Remove()`, and schedule transforms),
|
||||||
|
// because in the worst case the clean-up methods could be called from async disposal.
|
||||||
|
|
||||||
|
IDisposable IOverlayManager.RegisterBlockingOverlay(OverlayContainer overlayContainer)
|
||||||
|
{
|
||||||
|
overlayContent.Add(overlayContainer);
|
||||||
|
return new InvokeOnDisposal(() => overlayContainer.Expire());
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOverlayManager.ShowBlockingOverlay(OverlayContainer overlay)
|
||||||
|
=> Schedule(() => Stack.FadeColour(OsuColour.Gray(0.5f), 500, Easing.OutQuint));
|
||||||
|
|
||||||
|
void IOverlayManager.HideBlockingOverlay(OverlayContainer overlay)
|
||||||
|
=> Schedule(() => Stack.FadeColour(Colour4.White, 500, Easing.OutQuint));
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user