mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 12:33:01 +08:00
Add different display for mod customisation
This commit is contained in:
parent
3bf742bda2
commit
04efa61156
@ -0,0 +1,47 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Mods;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
|
{
|
||||||
|
public partial class TestSceneModCustomisationPanel : OsuManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
|
{
|
||||||
|
Child = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(20f),
|
||||||
|
Child = new ModCustomisationPanel
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Width = 400f,
|
||||||
|
SelectedMods = { BindTarget = SelectedMods },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDisplay()
|
||||||
|
{
|
||||||
|
AddStep("set DT", () => SelectedMods.Value = new[] { new OsuModDoubleTime() });
|
||||||
|
AddStep("set DA", () => SelectedMods.Value = new Mod[] { new OsuModDifficultyAdjust() });
|
||||||
|
AddStep("set FL+WU+DA+AD", () => SelectedMods.Value = new Mod[] { new OsuModFlashlight(), new ModWindUp(), new OsuModDifficultyAdjust(), new OsuModApproachDifferent() });
|
||||||
|
AddStep("set empty", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -75,6 +75,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString UnrankedExplanation => new TranslatableString(getKey(@"unranked_explanation"), @"Performance points will not be granted due to active mods.");
|
public static LocalisableString UnrankedExplanation => new TranslatableString(getKey(@"unranked_explanation"), @"Performance points will not be granted due to active mods.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Customise"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString CustomisationPanelHeader => new TranslatableString(getKey(@"customisation_panel_header"), @"Customise");
|
||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
86
osu.Game/Overlays/Mods/ModCustomisationHeader.cs
Normal file
86
osu.Game/Overlays/Mods/ModCustomisationHeader.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osuTK;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods
|
||||||
|
{
|
||||||
|
public partial class ModCustomisationHeader : OsuHoverContainer
|
||||||
|
{
|
||||||
|
public override bool HandlePositionalInput => true;
|
||||||
|
|
||||||
|
private Box background = null!;
|
||||||
|
private SpriteIcon icon = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||||
|
|
||||||
|
protected override IEnumerable<Drawable> EffectTargets => new[] { background };
|
||||||
|
|
||||||
|
public readonly BindableBool Expanded = new BindableBool();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
CornerRadius = 10f;
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Text = ModSelectOverlayStrings.CustomisationPanelHeader,
|
||||||
|
UseFullGlyphHeight = false,
|
||||||
|
Font = OsuFont.Torus.With(size: 20f, weight: FontWeight.SemiBold),
|
||||||
|
Margin = new MarginPadding { Left = 20f },
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Size = new Vector2(16f),
|
||||||
|
Margin = new MarginPadding { Right = 20f },
|
||||||
|
Child = icon = new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Icon = FontAwesome.Solid.ChevronDown,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IdleColour = colourProvider.Dark3;
|
||||||
|
HoverColour = colourProvider.Light4;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Expanded.BindValueChanged(v =>
|
||||||
|
{
|
||||||
|
icon.RotateTo(v.NewValue ? 180 : 0);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
Action = Expanded.Toggle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
161
osu.Game/Overlays/Mods/ModCustomisationPanel.cs
Normal file
161
osu.Game/Overlays/Mods/ModCustomisationPanel.cs
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods
|
||||||
|
{
|
||||||
|
public partial class ModCustomisationPanel : VisibilityContainer
|
||||||
|
{
|
||||||
|
private const float header_height = 42f;
|
||||||
|
private const float content_vertical_padding = 20f;
|
||||||
|
|
||||||
|
private Container content = null!;
|
||||||
|
private OsuScrollContainer scrollContainer = null!;
|
||||||
|
private FillFlowContainer sectionsFlow = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||||
|
|
||||||
|
public readonly BindableBool Expanded = new BindableBool();
|
||||||
|
|
||||||
|
public Bindable<IReadOnlyList<Mod>> SelectedMods { get; } = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new ModCustomisationHeader
|
||||||
|
{
|
||||||
|
Depth = float.MinValue,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = header_height,
|
||||||
|
Expanded = { BindTarget = Expanded },
|
||||||
|
},
|
||||||
|
content = new InputBlockingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
BorderColour = colourProvider.Dark3,
|
||||||
|
BorderThickness = 2f,
|
||||||
|
CornerRadius = 10f,
|
||||||
|
Masking = true,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Offset = new Vector2(0f, 5f),
|
||||||
|
Radius = 20f,
|
||||||
|
Roundness = 5f,
|
||||||
|
},
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider.Dark4,
|
||||||
|
},
|
||||||
|
scrollContainer = new OsuScrollContainer(Direction.Vertical)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
ScrollbarOverlapsContent = false,
|
||||||
|
Margin = new MarginPadding { Top = header_height },
|
||||||
|
Child = sectionsFlow = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Spacing = new Vector2(0f, 40f),
|
||||||
|
Margin = new MarginPadding
|
||||||
|
{
|
||||||
|
Top = content_vertical_padding,
|
||||||
|
Bottom = 5f + content_vertical_padding
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Expanded.BindValueChanged(_ => updateDisplay(), true);
|
||||||
|
SelectedMods.BindValueChanged(_ => updateMods(), true);
|
||||||
|
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn() => this.FadeIn(300, Easing.OutQuint);
|
||||||
|
|
||||||
|
protected override void PopOut() => this.FadeOut(300, Easing.OutQuint);
|
||||||
|
|
||||||
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
|
protected override bool OnMouseDown(MouseDownEvent e)
|
||||||
|
{
|
||||||
|
if (Expanded.Value && !content.ReceivePositionalInputAt(e.ScreenSpaceMousePosition))
|
||||||
|
Expanded.Value = false;
|
||||||
|
|
||||||
|
return base.OnMouseDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay()
|
||||||
|
{
|
||||||
|
content.ClearTransforms();
|
||||||
|
|
||||||
|
if (Expanded.Value)
|
||||||
|
{
|
||||||
|
content.AutoSizeDuration = 400;
|
||||||
|
content.AutoSizeEasing = Easing.OutQuint;
|
||||||
|
content.AutoSizeAxes = Axes.Y;
|
||||||
|
content.FadeEdgeEffectTo(0.25f, 120, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content.AutoSizeAxes = Axes.None;
|
||||||
|
content.ResizeHeightTo(header_height, 400, Easing.OutQuint);
|
||||||
|
content.FadeEdgeEffectTo(0f, 400, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMods()
|
||||||
|
{
|
||||||
|
Expanded.Value = false;
|
||||||
|
sectionsFlow.Clear();
|
||||||
|
|
||||||
|
// Importantly, the selected mods bindable is already ordered by the mod select overlay (following the order of mod columns and panels).
|
||||||
|
// Using AsOrdered produces a slightly different order (e.g. DT and NC no longer becoming adjacent),
|
||||||
|
// which breaks user expectations when interacting with the overlay.
|
||||||
|
foreach (var mod in SelectedMods.Value)
|
||||||
|
{
|
||||||
|
var settings = mod.CreateSettingsControls().ToList();
|
||||||
|
|
||||||
|
if (settings.Count > 0)
|
||||||
|
sectionsFlow.Add(new ModCustomisationSection(mod, settings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
scrollContainer.Height = Math.Min(scrollContainer.AvailableContent, DrawHeight - header_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
osu.Game/Overlays/Mods/ModCustomisationSection.cs
Normal file
82
osu.Game/Overlays/Mods/ModCustomisationSection.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods
|
||||||
|
{
|
||||||
|
public partial class ModCustomisationSection : CompositeDrawable
|
||||||
|
{
|
||||||
|
public readonly Mod Mod;
|
||||||
|
|
||||||
|
private readonly IReadOnlyList<Drawable> settings;
|
||||||
|
|
||||||
|
public ModCustomisationSection(Mod mod, IReadOnlyList<Drawable> settings)
|
||||||
|
{
|
||||||
|
Mod = mod;
|
||||||
|
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
FillFlowContainer flow;
|
||||||
|
|
||||||
|
InternalChild = flow = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0f, 8f),
|
||||||
|
Padding = new MarginPadding { Left = 7f },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Left = 20f, Right = 27f },
|
||||||
|
Margin = new MarginPadding { Bottom = 4f },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Text = Mod.Name,
|
||||||
|
Font = OsuFont.TorusAlternate.With(size: 20, weight: FontWeight.SemiBold),
|
||||||
|
},
|
||||||
|
new ModSwitchTiny(Mod)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Active = { Value = true },
|
||||||
|
Scale = new Vector2(0.5f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
flow.AddRange(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user