mirror of
https://github.com/ppy/osu
synced 2025-02-04 04:11:54 +00:00
Initial implementation of freemod selection overlay
This commit is contained in:
parent
4019cc38e5
commit
45e41aaeac
@ -0,0 +1,24 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneFreeModSelectOverlay : MultiplayerTestScene
|
||||
{
|
||||
private ModSelectOverlay overlay;
|
||||
|
||||
[SetUp]
|
||||
public new void Setup() => Schedule(() =>
|
||||
{
|
||||
Child = overlay = new FreeModSelectOverlay
|
||||
{
|
||||
State = { Value = Visibility.Visible }
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
@ -174,7 +174,7 @@ namespace osu.Game.Overlays.Mods
|
||||
switch (e.Button)
|
||||
{
|
||||
case MouseButton.Right:
|
||||
SelectNext(-1);
|
||||
OnRightClick(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -183,10 +183,14 @@ namespace osu.Game.Overlays.Mods
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
SelectNext(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void OnRightClick(MouseUpEvent e)
|
||||
{
|
||||
SelectNext(-1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select the next available mod in a specified direction.
|
||||
/// </summary>
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public class ModSection : Container
|
||||
{
|
||||
private readonly OsuSpriteText headerLabel;
|
||||
private readonly Drawable header;
|
||||
|
||||
public FillFlowContainer<ModButtonEmpty> ButtonsContainer { get; }
|
||||
|
||||
@ -47,10 +47,7 @@ namespace osu.Game.Overlays.Mods
|
||||
if (m == null)
|
||||
return new ModButtonEmpty();
|
||||
|
||||
return new ModButton(m)
|
||||
{
|
||||
SelectionChanged = Action,
|
||||
};
|
||||
return CreateModButton(m).With(b => b.SelectionChanged = Action);
|
||||
}).ToArray();
|
||||
|
||||
modsLoadCts?.Cancel();
|
||||
@ -58,7 +55,7 @@ namespace osu.Game.Overlays.Mods
|
||||
if (modContainers.Length == 0)
|
||||
{
|
||||
ModIconsLoaded = true;
|
||||
headerLabel.Hide();
|
||||
header.Hide();
|
||||
Hide();
|
||||
return;
|
||||
}
|
||||
@ -73,7 +70,7 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
buttons = modContainers.OfType<ModButton>().ToArray();
|
||||
|
||||
headerLabel.FadeIn(200);
|
||||
header.FadeIn(200);
|
||||
this.FadeIn(200);
|
||||
}
|
||||
}
|
||||
@ -160,16 +157,9 @@ namespace osu.Game.Overlays.Mods
|
||||
Origin = Anchor.TopCentre;
|
||||
Anchor = Anchor.TopCentre;
|
||||
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
headerLabel = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.TopLeft,
|
||||
Anchor = Anchor.TopLeft,
|
||||
Position = new Vector2(0f, 0f),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Text = type.Humanize(LetterCasing.Title)
|
||||
},
|
||||
header = CreateHeader(type.Humanize(LetterCasing.Title)),
|
||||
ButtonsContainer = new FillFlowContainer<ModButtonEmpty>
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
@ -185,5 +175,13 @@ namespace osu.Game.Overlays.Mods
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected virtual ModButton CreateModButton(Mod mod) => new ModButton(mod);
|
||||
|
||||
protected virtual Drawable CreateHeader(string text) => new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Text = text
|
||||
};
|
||||
}
|
||||
}
|
||||
|
101
osu.Game/Screens/OnlinePlay/Multiplayer/FreeModSelectOverlay.cs
Normal file
101
osu.Game/Screens/OnlinePlay/Multiplayer/FreeModSelectOverlay.cs
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
{
|
||||
public class FreeModSelectOverlay : ModSelectOverlay
|
||||
{
|
||||
protected override ModSection CreateModSection(ModType type) => new FreeModSection(type);
|
||||
|
||||
private class FreeModSection : ModSection
|
||||
{
|
||||
private HeaderCheckbox checkbox;
|
||||
|
||||
public FreeModSection(ModType type)
|
||||
: base(type)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ModButton CreateModButton(Mod mod) => new FreeModButton(mod);
|
||||
|
||||
protected override Drawable CreateHeader(string text) => new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 175,
|
||||
Child = checkbox = new HeaderCheckbox
|
||||
{
|
||||
LabelText = text,
|
||||
Changed = onCheckboxChanged
|
||||
}
|
||||
};
|
||||
|
||||
private void onCheckboxChanged(bool value)
|
||||
{
|
||||
foreach (var button in ButtonsContainer.OfType<ModButton>())
|
||||
{
|
||||
if (value)
|
||||
// Note: Buttons where only part of the group has an implementation are not fully supported.
|
||||
button.SelectAt(0);
|
||||
else
|
||||
button.Deselect();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// If any of the buttons aren't selected, deselect the checkbox.
|
||||
foreach (var button in ButtonsContainer.OfType<ModButton>())
|
||||
{
|
||||
if (button.Mods.Any(m => m.HasImplementation) && !button.Selected)
|
||||
checkbox.Current.Value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HeaderCheckbox : OsuCheckbox
|
||||
{
|
||||
public Action<bool> Changed;
|
||||
|
||||
protected override void OnUserChange(bool value)
|
||||
{
|
||||
base.OnUserChange(value);
|
||||
Changed?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
private class FreeModButton : ModButton
|
||||
{
|
||||
public FreeModButton(Mod mod)
|
||||
: base(mod)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
onClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnRightClick(MouseUpEvent e) => onClick();
|
||||
|
||||
private void onClick()
|
||||
{
|
||||
if (Selected)
|
||||
Deselect();
|
||||
else
|
||||
SelectNext(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,17 +6,23 @@ using System.Linq;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Select;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
{
|
||||
@ -33,6 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
private StatefulMultiplayerClient client { get; set; }
|
||||
|
||||
private LoadingLayer loadingLayer;
|
||||
private FreeModSelectOverlay freeModSelectOverlay;
|
||||
|
||||
private WorkingBeatmap initialBeatmap;
|
||||
private RulesetInfo initialRuleset;
|
||||
@ -43,6 +50,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
public MultiplayerMatchSongSelect()
|
||||
{
|
||||
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING };
|
||||
|
||||
freeModSelectOverlay = new FreeModSelectOverlay();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -52,6 +61,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
initialBeatmap = Beatmap.Value;
|
||||
initialRuleset = Ruleset.Value;
|
||||
initialMods = Mods.Value.ToList();
|
||||
|
||||
FooterPanels.Add(freeModSelectOverlay);
|
||||
}
|
||||
|
||||
protected override bool OnStart()
|
||||
@ -111,8 +122,61 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
|
||||
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
|
||||
|
||||
protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay(isValidMod);
|
||||
protected override ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(isValidMod);
|
||||
|
||||
protected override IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons()
|
||||
{
|
||||
var buttons = base.CreateFooterButtons().ToList();
|
||||
buttons.Insert(buttons.FindIndex(b => b.Item1 is FooterButtonMods) + 1, (new FooterButtonFreeMods(), freeModSelectOverlay));
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private bool isValidMod(Mod mod) => !(mod is ModAutoplay) && (mod as MultiMod)?.Mods.Any(mm => mm is ModAutoplay) != true;
|
||||
}
|
||||
|
||||
public class FooterButtonFreeMods : FooterButton, IHasCurrentValue<IReadOnlyList<Mod>>
|
||||
{
|
||||
public Bindable<IReadOnlyList<Mod>> Current
|
||||
{
|
||||
get => modDisplay.Current;
|
||||
set => modDisplay.Current = value;
|
||||
}
|
||||
|
||||
private readonly ModDisplay modDisplay;
|
||||
|
||||
public FooterButtonFreeMods()
|
||||
{
|
||||
ButtonContentContainer.Add(modDisplay = new ModDisplay
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
DisplayUnrankedText = false,
|
||||
Scale = new Vector2(0.8f),
|
||||
ExpansionMode = ExpansionMode.AlwaysContracted,
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
SelectedColour = colours.Yellow;
|
||||
DeselectedColour = SelectedColour.Opacity(0.5f);
|
||||
Text = @"freemods";
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Current.BindValueChanged(_ => updateModDisplay(), true);
|
||||
}
|
||||
|
||||
private void updateModDisplay()
|
||||
{
|
||||
if (Current.Value?.Count > 0)
|
||||
modDisplay.FadeIn();
|
||||
else
|
||||
modDisplay.FadeOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,19 +28,16 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
|
||||
|
||||
/// <param name="button">THe button to be added.</param>
|
||||
/// <param name="button">The button to be added.</param>
|
||||
/// <param name="overlay">The <see cref="OverlayContainer"/> to be toggled by this button.</param>
|
||||
public void AddButton(FooterButton button, OverlayContainer overlay)
|
||||
{
|
||||
overlays.Add(overlay);
|
||||
button.Action = () => showOverlay(overlay);
|
||||
if (overlay != null)
|
||||
{
|
||||
overlays.Add(overlay);
|
||||
button.Action = () => showOverlay(overlay);
|
||||
}
|
||||
|
||||
AddButton(button);
|
||||
}
|
||||
|
||||
/// <param name="button">Button to be added.</param>
|
||||
public void AddButton(FooterButton button)
|
||||
{
|
||||
button.Hovered = updateModeLight;
|
||||
button.HoverLost = updateModeLight;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user