mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 09:07:52 +08:00
Merge pull request #24801 from peppy/mod-select-diff-multiplier-visual-matching
Simplify multiplier display implementation
This commit is contained in:
commit
bb32368426
@ -1,68 +0,0 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public partial class TestSceneModsEffectDisplay : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
[Test]
|
||||
public void TestModsEffectDisplay()
|
||||
{
|
||||
TestDisplay testDisplay = null!;
|
||||
Box background = null!;
|
||||
|
||||
AddStep("add display", () =>
|
||||
{
|
||||
Add(testDisplay = new TestDisplay
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
});
|
||||
var boxes = testDisplay.ChildrenOfType<Box>();
|
||||
background = boxes.First();
|
||||
});
|
||||
|
||||
AddStep("set value to default", () => testDisplay.Current.Value = 50);
|
||||
AddUntilStep("colours are correct", () => testDisplay.Container.Colour == Color4.White && background.Colour == colourProvider.Background3);
|
||||
|
||||
AddStep("set value to less", () => testDisplay.Current.Value = 40);
|
||||
AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyReduction));
|
||||
|
||||
AddStep("set value to bigger", () => testDisplay.Current.Value = 60);
|
||||
AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyIncrease));
|
||||
}
|
||||
|
||||
private partial class TestDisplay : ModCounterDisplay
|
||||
{
|
||||
public Container<Drawable> Container => Content;
|
||||
|
||||
protected override LocalisableString Label => "Test display";
|
||||
|
||||
public TestDisplay()
|
||||
{
|
||||
Current.Default = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,9 +7,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
@ -18,7 +15,6 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using System.Threading;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Configuration;
|
||||
@ -29,36 +25,24 @@ namespace osu.Game.Overlays.Mods
|
||||
/// On the mod select overlay, this provides a local updating view of BPM, star rating and other
|
||||
/// difficulty attributes so the user can have a better insight into what mods are changing.
|
||||
/// </summary>
|
||||
public partial class BeatmapAttributesDisplay : CompositeDrawable
|
||||
public partial class BeatmapAttributesDisplay : ModFooterInformationDisplay
|
||||
{
|
||||
private Container content = null!;
|
||||
private Container innerContent = null!;
|
||||
|
||||
private Box background = null!;
|
||||
private Box innerBackground = null!;
|
||||
|
||||
private StarRatingDisplay starRatingDisplay = null!;
|
||||
private BPMDisplay bpmDisplay = null!;
|
||||
|
||||
private FillFlowContainer<VerticalAttributeDisplay> outerContent = null!;
|
||||
private VerticalAttributeDisplay circleSizeDisplay = null!;
|
||||
private VerticalAttributeDisplay drainRateDisplay = null!;
|
||||
private VerticalAttributeDisplay approachRateDisplay = null!;
|
||||
private VerticalAttributeDisplay overallDifficultyDisplay = null!;
|
||||
|
||||
private const float transition_duration = 250;
|
||||
|
||||
public Bindable<IBeatmapInfo?> BeatmapInfo { get; } = new Bindable<IBeatmapInfo?>();
|
||||
|
||||
public BindableBool Collapsed { get; } = new BindableBool(true);
|
||||
|
||||
[Resolved]
|
||||
private Bindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
|
||||
|
||||
private ModSettingChangeTracker? modSettingChangeTracker;
|
||||
public BindableBool Collapsed { get; } = new BindableBool(true);
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||
private ModSettingChangeTracker? modSettingChangeTracker;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapDifficultyCache difficultyCache { get; set; } = null!;
|
||||
@ -66,106 +50,44 @@ namespace osu.Game.Overlays.Mods
|
||||
private CancellationTokenSource? cancellationSource;
|
||||
private IBindable<StarDifficulty?> starDifficulty = null!;
|
||||
|
||||
private const float transition_duration = 250;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
const float shear = ShearedOverlayContainer.SHEAR;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = content = new Container
|
||||
LeftContent.AddRange(new Drawable[]
|
||||
{
|
||||
Origin = Anchor.BottomRight,
|
||||
Anchor = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Height = ShearedButton.HEIGHT,
|
||||
Shear = new Vector2(shear, 0),
|
||||
CornerRadius = ShearedButton.CORNER_RADIUS,
|
||||
BorderThickness = ShearedButton.BORDER_THICKNESS,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
starRatingDisplay = new StarRatingDisplay(default, animated: true)
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new FillFlowContainer // divide inner and outer content
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
innerContent = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
BorderThickness = ShearedButton.BORDER_THICKNESS,
|
||||
CornerRadius = ShearedButton.CORNER_RADIUS,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
innerBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new Container // actual inner content
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Width = 140,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Horizontal = 15 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
starRatingDisplay = new StarRatingDisplay(default, animated: true)
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Shear = new Vector2(-shear, 0),
|
||||
},
|
||||
bpmDisplay = new BPMDisplay
|
||||
{
|
||||
Origin = Anchor.CentreRight,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Shear = new Vector2(-shear, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
outerContent = new FillFlowContainer<VerticalAttributeDisplay>
|
||||
{
|
||||
Alpha = 0,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new[]
|
||||
{
|
||||
circleSizeDisplay = new VerticalAttributeDisplay("CS") { Shear = new Vector2(-shear, 0), },
|
||||
drainRateDisplay = new VerticalAttributeDisplay("HP") { Shear = new Vector2(-shear, 0), },
|
||||
approachRateDisplay = new VerticalAttributeDisplay("AR") { Shear = new Vector2(-shear, 0), },
|
||||
overallDifficultyDisplay = new VerticalAttributeDisplay("OD") { Shear = new Vector2(-shear, 0), },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Shear = new Vector2(-shear, 0),
|
||||
},
|
||||
bpmDisplay = new BPMDisplay
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Shear = new Vector2(-shear, 0),
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 75,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
RightContent.Alpha = 0;
|
||||
RightContent.AddRange(new Drawable[]
|
||||
{
|
||||
circleSizeDisplay = new VerticalAttributeDisplay("CS") { Shear = new Vector2(-shear, 0), },
|
||||
drainRateDisplay = new VerticalAttributeDisplay("HP") { Shear = new Vector2(-shear, 0), },
|
||||
approachRateDisplay = new VerticalAttributeDisplay("AR") { Shear = new Vector2(-shear, 0), },
|
||||
overallDifficultyDisplay = new VerticalAttributeDisplay("OD") { Shear = new Vector2(-shear, 0), },
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
background.Colour = colourProvider.Background4;
|
||||
innerBackground.Colour = colourProvider.Background3;
|
||||
Color4 glowColour = colourProvider.Background1;
|
||||
|
||||
content.BorderColour = ColourInfo.GradientVertical(background.Colour, glowColour);
|
||||
innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glowColour);
|
||||
base.LoadComplete();
|
||||
|
||||
mods.BindValueChanged(_ =>
|
||||
{
|
||||
@ -176,15 +98,16 @@ namespace osu.Game.Overlays.Mods
|
||||
updateValues();
|
||||
}, true);
|
||||
|
||||
BeatmapInfo.BindValueChanged(_ => updateValues(), true);
|
||||
|
||||
Collapsed.BindValueChanged(_ =>
|
||||
{
|
||||
// Only start autosize animations on first collapse toggle. This avoids an ugly initial presentation.
|
||||
startAnimating();
|
||||
|
||||
updateCollapsedState();
|
||||
});
|
||||
|
||||
BeatmapInfo.BindValueChanged(_ => updateValues(), true);
|
||||
updateCollapsedState();
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
@ -206,8 +129,13 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
private void startAnimating()
|
||||
{
|
||||
content.AutoSizeEasing = Easing.OutQuint;
|
||||
content.AutoSizeDuration = transition_duration;
|
||||
Content.AutoSizeEasing = Easing.OutQuint;
|
||||
Content.AutoSizeDuration = transition_duration;
|
||||
}
|
||||
|
||||
private void updateCollapsedState()
|
||||
{
|
||||
RightContent.FadeTo(Collapsed.Value && !IsHovered ? 0 : 1, transition_duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void updateValues() => Scheduler.AddOnce(() =>
|
||||
@ -242,11 +170,6 @@ namespace osu.Game.Overlays.Mods
|
||||
overallDifficultyDisplay.Current.Value = adjustedDifficulty.OverallDifficulty;
|
||||
});
|
||||
|
||||
private void updateCollapsedState()
|
||||
{
|
||||
outerContent.FadeTo(Collapsed.Value && !IsHovered ? 0 : 1, transition_duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private partial class BPMDisplay : RollingCounter<double>
|
||||
{
|
||||
protected override double RollingDuration => 500;
|
||||
@ -255,6 +178,8 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Font = OsuFont.Default.With(size: 20, weight: FontWeight.SemiBold),
|
||||
UseFullGlyphHeight = false,
|
||||
};
|
||||
|
@ -1,16 +1,46 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public sealed partial class DifficultyMultiplierDisplay : ModCounterDisplay
|
||||
/// <summary>
|
||||
/// On the mod select overlay, this provides a local updating view of the aggregate score multiplier coming from mods.
|
||||
/// </summary>
|
||||
public partial class DifficultyMultiplierDisplay : ModFooterInformationDisplay, IHasCurrentValue<double>
|
||||
{
|
||||
protected override LocalisableString Label => DifficultyMultiplierDisplayStrings.DifficultyMultiplier;
|
||||
public const float HEIGHT = 42;
|
||||
|
||||
protected override string CounterFormat => @"0.0x";
|
||||
public Bindable<double> Current
|
||||
{
|
||||
get => current.Current;
|
||||
set => current.Current = value;
|
||||
}
|
||||
|
||||
private readonly BindableWithCurrent<double> current = new BindableWithCurrent<double>();
|
||||
|
||||
private const float transition_duration = 200;
|
||||
|
||||
private RollingCounter<double> counter = null!;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||
|
||||
public DifficultyMultiplierDisplay()
|
||||
{
|
||||
@ -18,13 +48,110 @@ namespace osu.Game.Overlays.Mods
|
||||
Current.Value = 1d;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
LeftContent.AddRange(new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||
Text = DifficultyMultiplierDisplayStrings.DifficultyMultiplier,
|
||||
Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
|
||||
}
|
||||
});
|
||||
|
||||
RightContent.Add(counter = new EffectCounter
|
||||
{
|
||||
Margin = new MarginPadding(10),
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 40,
|
||||
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Current = { BindTarget = Current }
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Current.BindValueChanged(e =>
|
||||
{
|
||||
var effect = calculateEffectForComparison(e.NewValue.CompareTo(Current.Default));
|
||||
setColours(effect);
|
||||
}, true);
|
||||
|
||||
// required to prevent the counter initially rolling up from 0 to 1
|
||||
// due to `Current.Value` having a nonstandard default value of 1.
|
||||
Counter.SetCountWithoutRolling(Current.Value);
|
||||
counter.SetCountWithoutRolling(Current.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fades colours of text and its background according to displayed value.
|
||||
/// </summary>
|
||||
/// <param name="effect">Effect of the value.</param>
|
||||
private void setColours(ModEffect effect)
|
||||
{
|
||||
switch (effect)
|
||||
{
|
||||
case ModEffect.NotChanged:
|
||||
MainBackground.FadeColour(colourProvider.Background4, transition_duration, Easing.OutQuint);
|
||||
counter.FadeColour(Colour4.White, transition_duration, Easing.OutQuint);
|
||||
break;
|
||||
|
||||
case ModEffect.DifficultyReduction:
|
||||
MainBackground.FadeColour(colours.ForModType(ModType.DifficultyReduction), transition_duration, Easing.OutQuint);
|
||||
counter.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint);
|
||||
break;
|
||||
|
||||
case ModEffect.DifficultyIncrease:
|
||||
MainBackground.FadeColour(colours.ForModType(ModType.DifficultyIncrease), transition_duration, Easing.OutQuint);
|
||||
counter.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(effect));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts signed integer into <see cref="ModEffect"/>. Negative values are counted as difficulty reduction, positive as increase.
|
||||
/// </summary>
|
||||
/// <param name="comparison">Value to convert. Will arrive from comparison between <see cref="Current"/> bindable once it changes and it's <see cref="Bindable{T}.Default"/>.</param>
|
||||
/// <returns>Effect of the value.</returns>
|
||||
private static ModEffect calculateEffectForComparison(int comparison)
|
||||
{
|
||||
if (comparison == 0)
|
||||
return ModEffect.NotChanged;
|
||||
if (comparison < 0)
|
||||
return ModEffect.DifficultyReduction;
|
||||
|
||||
return ModEffect.DifficultyIncrease;
|
||||
}
|
||||
|
||||
protected enum ModEffect
|
||||
{
|
||||
NotChanged,
|
||||
DifficultyReduction,
|
||||
DifficultyIncrease
|
||||
}
|
||||
|
||||
private partial class EffectCounter : RollingCounter<double>
|
||||
{
|
||||
protected override double RollingDuration => 500;
|
||||
|
||||
protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(@"0.00x");
|
||||
|
||||
protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,222 +0,0 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for displays of singular counters. Not to be confused with <see cref="BeatmapAttributesDisplay"/> which aggregates multiple attributes.
|
||||
/// </summary>
|
||||
public abstract partial class ModCounterDisplay : Container, IHasCurrentValue<double>
|
||||
{
|
||||
public const float HEIGHT = 42;
|
||||
private const float transition_duration = 200;
|
||||
|
||||
private readonly Box contentBackground;
|
||||
private readonly Box labelBackground;
|
||||
private readonly FillFlowContainer content;
|
||||
|
||||
public Bindable<double> Current
|
||||
{
|
||||
get => current.Current;
|
||||
set => current.Current = value;
|
||||
}
|
||||
|
||||
private readonly BindableWithCurrent<double> current = new BindableWithCurrent<double>();
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Text to display in the left area of the display.
|
||||
/// </summary>
|
||||
protected abstract LocalisableString Label { get; }
|
||||
|
||||
protected virtual string CounterFormat => @"N0";
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected readonly RollingCounter<double> Counter;
|
||||
|
||||
protected ModCounterDisplay()
|
||||
{
|
||||
Height = ShearedButton.HEIGHT;
|
||||
AutoSizeAxes = Axes.X;
|
||||
|
||||
InternalChild = new InputBlockingContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Masking = true,
|
||||
CornerRadius = ModSelectPanel.CORNER_RADIUS,
|
||||
Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0),
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
contentBackground = new Box
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.Absolute, 56)
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Masking = true,
|
||||
CornerRadius = ModSelectPanel.CORNER_RADIUS,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
labelBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Horizontal = 18 },
|
||||
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||
Text = Label,
|
||||
Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
|
||||
}
|
||||
}
|
||||
},
|
||||
content = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
|
||||
Spacing = new Vector2(2, 0),
|
||||
Child = Counter = new EffectCounter(CounterFormat)
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Current = { BindTarget = Current }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
labelBackground.Colour = colourProvider.Background4;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
Current.BindValueChanged(e =>
|
||||
{
|
||||
var effect = CalculateEffectForComparison(e.NewValue.CompareTo(Current.Default));
|
||||
setColours(effect);
|
||||
}, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fades colours of text and its background according to displayed value.
|
||||
/// </summary>
|
||||
/// <param name="effect">Effect of the value.</param>
|
||||
private void setColours(ModEffect effect)
|
||||
{
|
||||
switch (effect)
|
||||
{
|
||||
case ModEffect.NotChanged:
|
||||
contentBackground.FadeColour(colourProvider.Background3, transition_duration, Easing.OutQuint);
|
||||
content.FadeColour(Colour4.White, transition_duration, Easing.OutQuint);
|
||||
break;
|
||||
|
||||
case ModEffect.DifficultyReduction:
|
||||
contentBackground.FadeColour(colours.ForModType(ModType.DifficultyReduction), transition_duration, Easing.OutQuint);
|
||||
content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint);
|
||||
break;
|
||||
|
||||
case ModEffect.DifficultyIncrease:
|
||||
contentBackground.FadeColour(colours.ForModType(ModType.DifficultyIncrease), transition_duration, Easing.OutQuint);
|
||||
content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(effect));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts signed integer into <see cref="ModEffect"/>. Negative values are counted as difficulty reduction, positive as increase.
|
||||
/// </summary>
|
||||
/// <param name="comparison">Value to convert. Will arrive from comparison between <see cref="Current"/> bindable once it changes and it's <see cref="Bindable{T}.Default"/>.</param>
|
||||
/// <returns>Effect of the value.</returns>
|
||||
protected virtual ModEffect CalculateEffectForComparison(int comparison)
|
||||
{
|
||||
if (comparison == 0)
|
||||
return ModEffect.NotChanged;
|
||||
if (comparison < 0)
|
||||
return ModEffect.DifficultyReduction;
|
||||
|
||||
return ModEffect.DifficultyIncrease;
|
||||
}
|
||||
|
||||
protected enum ModEffect
|
||||
{
|
||||
NotChanged,
|
||||
DifficultyReduction,
|
||||
DifficultyIncrease
|
||||
}
|
||||
|
||||
private partial class EffectCounter : RollingCounter<double>
|
||||
{
|
||||
private readonly string? format;
|
||||
|
||||
public EffectCounter(string? format)
|
||||
{
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
protected override double RollingDuration => 500;
|
||||
|
||||
protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(format);
|
||||
|
||||
protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
109
osu.Game/Overlays/Mods/ModFooterInformationDisplay.cs
Normal file
109
osu.Game/Overlays/Mods/ModFooterInformationDisplay.cs
Normal file
@ -0,0 +1,109 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public abstract partial class ModFooterInformationDisplay : CompositeDrawable
|
||||
{
|
||||
protected FillFlowContainer LeftContent { get; private set; } = null!;
|
||||
protected FillFlowContainer RightContent { get; private set; } = null!;
|
||||
protected Container Content { get; private set; } = null!;
|
||||
|
||||
private Container innerContent = null!;
|
||||
|
||||
protected Box MainBackground { get; private set; } = null!;
|
||||
protected Box FrontBackground { get; private set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = Content = new Container
|
||||
{
|
||||
Origin = Anchor.BottomRight,
|
||||
Anchor = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Height = ShearedButton.HEIGHT,
|
||||
Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0),
|
||||
CornerRadius = ShearedButton.CORNER_RADIUS,
|
||||
BorderThickness = ShearedButton.BORDER_THICKNESS,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
MainBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new FillFlowContainer // divide inner and outer content
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
innerContent = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
BorderThickness = ShearedButton.BORDER_THICKNESS,
|
||||
CornerRadius = ShearedButton.CORNER_RADIUS,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
FrontBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
LeftContent = new FillFlowContainer // actual inner content
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Horizontal = 15 },
|
||||
Spacing = new Vector2(10),
|
||||
}
|
||||
}
|
||||
},
|
||||
RightContent = new FillFlowContainer
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
MainBackground.Colour = colourProvider.Background4;
|
||||
FrontBackground.Colour = colourProvider.Background3;
|
||||
Color4 glowColour = colourProvider.Background1;
|
||||
|
||||
Content.BorderColour = ColourInfo.GradientVertical(MainBackground.Colour, glowColour);
|
||||
innerContent.BorderColour = ColourInfo.GradientVertical(FrontBackground.Colour, glowColour);
|
||||
}
|
||||
}
|
||||
}
|
@ -182,7 +182,7 @@ namespace osu.Game.Overlays.Mods
|
||||
aboveColumnsContent = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = ModCounterDisplay.HEIGHT,
|
||||
Height = DifficultyMultiplierDisplay.HEIGHT,
|
||||
Padding = new MarginPadding { Horizontal = 100 },
|
||||
Child = SearchTextBox = new ShearedSearchTextBox
|
||||
{
|
||||
@ -197,7 +197,7 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = ModCounterDisplay.HEIGHT + PADDING,
|
||||
Top = DifficultyMultiplierDisplay.HEIGHT + PADDING,
|
||||
Bottom = PADDING
|
||||
},
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
Loading…
Reference in New Issue
Block a user