mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 09:32:55 +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>
|
||||
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}";
|
||||
}
|
||||
}
|
||||
|
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