mirror of
https://github.com/ppy/osu.git
synced 2026-06-04 01:08:12 +08:00
Implement skinnable mod display
Also makes the mod display initialization sequence (start expanded, then unexpand) controlled by HUDOverlay rather than mod display itself. This enabled different treatment depending on whether the mod display is viewed in the skin editor or in the player. Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
This commit is contained in:
@@ -20,6 +20,7 @@ using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Overlays.SkinEditor;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
||||
@@ -53,6 +54,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("Add DT and HD", () =>
|
||||
{
|
||||
LoadPlayer([new OsuModDoubleTime { SpeedChange = { Value = 1.337 } }, new OsuModHidden()]);
|
||||
});
|
||||
|
||||
AddStep("reset skin", () => skins.CurrentSkinInfo.SetDefault());
|
||||
AddUntilStep("wait for hud load", () => targetContainer.ComponentsLoaded);
|
||||
|
||||
|
||||
@@ -39,7 +39,18 @@ namespace osu.Game.Rulesets.UI
|
||||
private IMod mod;
|
||||
|
||||
private readonly bool showTooltip;
|
||||
private readonly bool showExtendedInformation;
|
||||
|
||||
private bool showExtendedInformation;
|
||||
|
||||
public bool ShowExtendedInformation
|
||||
{
|
||||
get => showExtendedInformation;
|
||||
set
|
||||
{
|
||||
showExtendedInformation = value;
|
||||
updateExtendedInformation();
|
||||
}
|
||||
}
|
||||
|
||||
public IMod Mod
|
||||
{
|
||||
|
||||
@@ -20,9 +20,27 @@ namespace osu.Game.Screens.Play.HUD
|
||||
/// </summary>
|
||||
public partial class ModDisplay : CompositeDrawable, IHasCurrentValue<IReadOnlyList<Mod>>
|
||||
{
|
||||
private const int fade_duration = 1000;
|
||||
private ExpansionMode expansionMode = ExpansionMode.ExpandOnHover;
|
||||
|
||||
public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover;
|
||||
public ExpansionMode ExpansionMode
|
||||
{
|
||||
get => expansionMode;
|
||||
set
|
||||
{
|
||||
if (expansionMode == value)
|
||||
return;
|
||||
|
||||
expansionMode = value;
|
||||
|
||||
if (IsLoaded)
|
||||
{
|
||||
if (expansionMode == ExpansionMode.AlwaysExpanded || (expansionMode == ExpansionMode.ExpandOnHover && IsHovered))
|
||||
expand();
|
||||
else if (expansionMode == ExpansionMode.AlwaysContracted || (expansionMode == ExpansionMode.ExpandOnHover && !IsHovered))
|
||||
contract();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly BindableWithCurrent<IReadOnlyList<Mod>> current = new BindableWithCurrent<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||
|
||||
@@ -37,7 +55,19 @@ namespace osu.Game.Screens.Play.HUD
|
||||
}
|
||||
}
|
||||
|
||||
private readonly bool showExtendedInformation;
|
||||
private bool showExtendedInformation;
|
||||
|
||||
public bool ShowExtendedInformation
|
||||
{
|
||||
get => showExtendedInformation;
|
||||
set
|
||||
{
|
||||
showExtendedInformation = value;
|
||||
foreach (var icon in iconsContainer)
|
||||
icon.ShowExtendedInformation = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly FillFlowContainer<ModIcon> iconsContainer;
|
||||
|
||||
public ModDisplay(bool showExtendedInformation = true)
|
||||
@@ -59,10 +89,23 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
Current.BindValueChanged(updateDisplay, true);
|
||||
|
||||
iconsContainer.FadeInFromZero(fade_duration, Easing.OutQuint);
|
||||
switch (expansionMode)
|
||||
{
|
||||
case ExpansionMode.AlwaysExpanded:
|
||||
expand(0);
|
||||
break;
|
||||
|
||||
if (ExpansionMode == ExpansionMode.AlwaysExpanded || ExpansionMode == ExpansionMode.AlwaysContracted)
|
||||
FinishTransforms(true);
|
||||
case ExpansionMode.AlwaysContracted:
|
||||
contract(0);
|
||||
break;
|
||||
|
||||
case ExpansionMode.ExpandOnHover:
|
||||
if (IsHovered)
|
||||
expand(0);
|
||||
else
|
||||
contract(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDisplay(ValueChangedEvent<IReadOnlyList<Mod>> mods)
|
||||
@@ -71,28 +114,18 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
foreach (Mod mod in mods.NewValue.AsOrdered())
|
||||
iconsContainer.Add(new ModIcon(mod, showExtendedInformation: showExtendedInformation) { Scale = new Vector2(0.6f) });
|
||||
|
||||
appearTransform();
|
||||
}
|
||||
|
||||
private void appearTransform()
|
||||
{
|
||||
expand();
|
||||
|
||||
using (iconsContainer.BeginDelayedSequence(1200))
|
||||
contract();
|
||||
}
|
||||
|
||||
private void expand()
|
||||
private void expand(double duration = 500)
|
||||
{
|
||||
if (ExpansionMode != ExpansionMode.AlwaysContracted)
|
||||
iconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, Easing.OutQuint);
|
||||
iconsContainer.TransformSpacingTo(new Vector2(5, 0), duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void contract()
|
||||
private void contract(double duration = 500)
|
||||
{
|
||||
if (ExpansionMode != ExpansionMode.AlwaysExpanded)
|
||||
iconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint);
|
||||
iconsContainer.TransformSpacingTo(new Vector2(-25, 0), duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
@@ -123,6 +156,6 @@ namespace osu.Game.Screens.Play.HUD
|
||||
/// <summary>
|
||||
/// The <see cref="ModDisplay"/> will always be contracted.
|
||||
/// </summary>
|
||||
AlwaysContracted
|
||||
AlwaysContracted,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays a single-line horizontal auto-sized flow of mods. For cases where wrapping is required, use <see cref="ModFlowDisplay"/> instead.
|
||||
/// </summary>
|
||||
public partial class SkinnableModDisplay : CompositeDrawable, ISerialisableDrawable
|
||||
{
|
||||
private ModDisplay modDisplay = null!;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
|
||||
|
||||
[SettingSource("Show extended info", "Whether to show extended information for each mod.")]
|
||||
public Bindable<bool> ShowExtendedInformation { get; } = new Bindable<bool>(true);
|
||||
|
||||
[SettingSource("Expansion mode", "How the mod display expands when interacted with.")]
|
||||
public Bindable<ExpansionMode> ExpansionModeSetting { get; } = new Bindable<ExpansionMode>(ExpansionMode.ExpandOnHover);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = modDisplay = new ModDisplay();
|
||||
modDisplay.Current = mods;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
ShowExtendedInformation.BindValueChanged(_ => modDisplay.ShowExtendedInformation = ShowExtendedInformation.Value, true);
|
||||
ExpansionModeSetting.BindValueChanged(_ => modDisplay.ExpansionMode = ExpansionModeSetting.Value, true);
|
||||
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
public bool UsesFixedAnchor { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,8 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
public const float FADE_DURATION = 300;
|
||||
|
||||
private const float mods_fade_duration = 1000;
|
||||
|
||||
public const Easing FADE_EASING = Easing.OutQuint;
|
||||
|
||||
/// <summary>
|
||||
@@ -85,7 +87,6 @@ namespace osu.Game.Screens.Play
|
||||
private readonly BindableBool replayLoaded = new BindableBool();
|
||||
|
||||
private static bool hasShownNotificationOnce;
|
||||
|
||||
private readonly FillFlowContainer bottomRightElements;
|
||||
private readonly FillFlowContainer topRightElements;
|
||||
|
||||
@@ -248,6 +249,14 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
updateVisibility();
|
||||
}, true);
|
||||
|
||||
ModDisplay.ExpansionMode = ExpansionMode.AlwaysExpanded;
|
||||
Scheduler.AddDelayed(() =>
|
||||
{
|
||||
ModDisplay.ExpansionMode = ExpansionMode.ExpandOnHover;
|
||||
}, 1200);
|
||||
|
||||
ModDisplay.FadeInFromZero(mods_fade_duration, FADE_EASING);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
|
||||
Reference in New Issue
Block a user