Skip to content

Commit

Permalink
Implement skinnable mod display
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Tom94 and bdach committed Dec 7, 2024
1 parent 7592813 commit 5da21d8
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 24 deletions.
6 changes: 6 additions & 0 deletions osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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;
Expand Down Expand Up @@ -53,6 +54,11 @@ public override void SetUpSteps()
{
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);

Expand Down
13 changes: 12 additions & 1 deletion osu.Game/Rulesets/UI/ModIcon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,18 @@ public partial class ModIcon : Container, IHasTooltip
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
{
Expand Down
80 changes: 58 additions & 22 deletions osu.Game/Screens/Play/HUD/ModDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,30 @@ 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

Check failure on line 24 in osu.Game/Screens/Play/HUD/ModDisplay.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Blank lines are missing, expected minimum 1 instead of 0 in osu.Game\Screens\Play\HUD\ModDisplay.cs on line 24
{
get
{
return expansionMode;

Check failure on line 28 in osu.Game/Screens/Play/HUD/ModDisplay.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Code body does not conform to code style settings: use expression body in osu.Game\Screens\Play\HUD\ModDisplay.cs on line 28
}

public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover;
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>());

Expand All @@ -37,7 +58,19 @@ public Bindable<IReadOnlyList<Mod>> Current
}
}

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)
Expand All @@ -59,10 +92,23 @@ protected override void LoadComplete()

Current.BindValueChanged(updateDisplay, true);

iconsContainer.FadeInFromZero(fade_duration, Easing.OutQuint);

if (ExpansionMode == ExpansionMode.AlwaysExpanded || ExpansionMode == ExpansionMode.AlwaysContracted)
FinishTransforms(true);
switch (expansionMode)
{
case ExpansionMode.AlwaysExpanded:
expand(0);
break;

case ExpansionMode.AlwaysContracted:
contract(0);
break;

case ExpansionMode.ExpandOnHover:
if (IsHovered)
expand(0);
else
contract(0);
break;
}
}

private void updateDisplay(ValueChangedEvent<IReadOnlyList<Mod>> mods)
Expand All @@ -71,28 +117,18 @@ private void updateDisplay(ValueChangedEvent<IReadOnlyList<Mod>> mods)

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)
Expand Down Expand Up @@ -123,6 +159,6 @@ public enum ExpansionMode
/// <summary>
/// The <see cref="ModDisplay"/> will always be contracted.
/// </summary>
AlwaysContracted
AlwaysContracted,
}
}
55 changes: 55 additions & 0 deletions osu.Game/Screens/Play/HUD/SkinnableModDisplay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. 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);

public SkinnableModDisplay()

Check failure on line 31 in osu.Game/Screens/Play/HUD/SkinnableModDisplay.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Empty constructor is redundant. The compiler generates the same by default. in osu.Game\Screens\Play\HUD\SkinnableModDisplay.cs on line 31
{
}

[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; }
}
}
11 changes: 10 additions & 1 deletion osu.Game/Screens/Play/HUDOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public partial class HUDOverlay : Container, IKeyBindingHandler<GlobalAction>
{
public const float FADE_DURATION = 300;

private const float mods_fade_duration = 1000;

public const Easing FADE_EASING = Easing.OutQuint;

/// <summary>
Expand Down Expand Up @@ -85,7 +87,6 @@ protected override bool ShouldBeConsideredForInput(Drawable child)
private readonly BindableBool replayLoaded = new BindableBool();

private static bool hasShownNotificationOnce;

private readonly FillFlowContainer bottomRightElements;
private readonly FillFlowContainer topRightElements;

Expand Down Expand Up @@ -248,6 +249,14 @@ protected override void LoadComplete()

updateVisibility();
}, true);

ModDisplay.ExpansionMode = ExpansionMode.AlwaysExpanded;
Scheduler.AddDelayed(() =>
{
ModDisplay.ExpansionMode = ExpansionMode.ExpandOnHover;
}, 1200);

ModDisplay.FadeInFromZero(mods_fade_duration, FADE_EASING);
}

protected override void Update()
Expand Down

0 comments on commit 5da21d8

Please sign in to comment.