// Copyright (c) ppy Pty Ltd . 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.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.Rulesets.Mods; using osuTK; namespace osu.Game.Overlays.Mods { /// /// Base class for displays of mods effects. /// public abstract class ModsEffectDisplay : Container, IHasCurrentValue { public const float HEIGHT = 42; private const float transition_duration = 200; private readonly Box contentBackground; private readonly Box labelBackground; private readonly Container content; public Bindable Current { get => current.Current; set => current.Current = value; } private readonly BindableWithCurrent current = new BindableWithCurrent(); [Resolved] private OsuColour colours { get; set; } = null!; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; /// /// Text to display in the left area of the display. /// protected abstract LocalisableString Label { get; } /// /// Calculates, does current value increase difficulty or decrease it. /// /// Value to calculate for. Will arrive from bindable once it changes. /// Effect of the value. /// /// Default implementation compares the value with ., bigger value counts as difficulty increase. /// protected virtual ModEffect CalculateEffect(double value) { return CalculateForSign(value.CompareTo(Current.Default)); } protected virtual float ValueAreaWidth => 56; protected override Container Content => content; protected ModsEffectDisplay() { Height = 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), Children = new Drawable[] { contentBackground = new Box { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Y, Width = ValueAreaWidth + ModSelectPanel.CORNER_RADIUS }, new GridContainer { RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.Absolute, ValueAreaWidth) }, 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 Container { AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0) } } } } } }; } [BackgroundDependencyLoader] private void load() { labelBackground.Colour = colourProvider.Background4; } protected override void LoadComplete() { Current.BindValueChanged(e => { var effect = CalculateEffect(e.NewValue); setColours(effect); }, true); } /// /// Fades colours of text and its background according to displayed value. /// /// Effect of the value. 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)); } } #region Quick implementations for CalculateEffect /// /// Converts signed integer into . Negative values are counted as difficulty reduction, positive as increase. /// /// Value to convert. Can be obtained from CompareTo. /// Effect. protected ModEffect CalculateForSign(int comparison) { if (comparison == 0) return ModEffect.NotChanged; if (comparison < 0) return ModEffect.DifficultyReduction; return ModEffect.DifficultyIncrease; } #endregion protected enum ModEffect { NotChanged, DifficultyReduction, DifficultyIncrease } } }