1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 14:17:26 +08:00

Made custom tooltip

This commit is contained in:
Givikap120 2023-11-23 23:30:18 +02:00
parent 9172632b0b
commit c2a44cf118
3 changed files with 188 additions and 54 deletions

View File

@ -0,0 +1,158 @@
// 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.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Framework.Utils;
using osuTK;
namespace osu.Game.Overlays.Mods
{
public partial class AdjustedAttributesTooltip : CompositeDrawable, ITooltip
{
private Dictionary<string, Bindable<OldNewPair>> attributes = new Dictionary<string, Bindable<OldNewPair>>();
private Container content;
private FillFlowContainer attributesFillFlow;
[Resolved]
private OsuColour colours { get; set; } = null!;
public AdjustedAttributesTooltip()
{
// Need to be initialized in constructor to ensure accessability in AddAttribute function
InternalChild = content = new Container
{
AutoSizeAxes = Axes.Both
};
attributesFillFlow = new FillFlowContainer
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both
};
}
[BackgroundDependencyLoader]
private void load()
{
AutoSizeAxes = Axes.Both;
Masking = true;
CornerRadius = 15;
content.AddRange(new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray1,
Alpha = 0.8f
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding {Vertical = 10, Horizontal = 15},
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new OsuSpriteText
{
Text = "One or more values are being adjusted by mods that change speed.",
},
attributesFillFlow
}
}
});
}
private void checkAttributes()
{
foreach (var attribute in attributes)
{
if (!Precision.AlmostEquals(attribute.Value.Value.Old, attribute.Value.Value.New))
{
content.Show();
return;
}
}
content.Hide();
}
public void AddAttribute(string name)
{
Bindable<OldNewPair> newBindable = new Bindable<OldNewPair>();
newBindable.BindValueChanged(_ => checkAttributes());
attributes.Add(name, newBindable);
attributesFillFlow.Add(new AttributeDisplay(name, newBindable.GetBoundCopy()));
}
public void UpdateAttribute(string name, double oldValue, double newValue)
{
Bindable<OldNewPair> attribute = attributes[name];
OldNewPair attributeValue = attribute.Value;
attributeValue.Old = oldValue;
attributeValue.New = newValue;
attribute.Value = attributeValue;
}
protected override void Update()
{
}
public void SetContent(object content)
{
}
public void Move(Vector2 pos)
{
Position = pos;
}
private struct OldNewPair
{
public double Old, New;
}
private partial class AttributeDisplay : CompositeDrawable
{
public Bindable<OldNewPair> AttributeValues = new Bindable<OldNewPair>();
public string AttributeName;
private OsuSpriteText text = new OsuSpriteText
{
Font = OsuFont.Default.With(weight: FontWeight.Bold)
};
public AttributeDisplay(string name, Bindable<OldNewPair> boundCopy)
{
AutoSizeAxes = Axes.Both;
AttributeName = name;
AttributeValues = boundCopy;
InternalChild = text;
AttributeValues.BindValueChanged(_ => update(), true);
}
private void update()
{
if (Precision.AlmostEquals(AttributeValues.Value.Old, AttributeValues.Value.New))
{
Hide();
}
else
{
Show();
text.Text = $"{AttributeName}: {(AttributeValues.Value.Old):0.0#} → {(AttributeValues.Value.New):0.0#}";
}
}
}
}
}

View File

@ -11,7 +11,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Configuration; using osu.Game.Configuration;
@ -28,7 +27,7 @@ namespace osu.Game.Overlays.Mods
/// On the mod select overlay, this provides a local updating view of BPM, star rating and other /// 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. /// difficulty attributes so the user can have a better insight into what mods are changing.
/// </summary> /// </summary>
public partial class BeatmapAttributesDisplay : ModFooterInformationDisplay, IHasTooltip public partial class BeatmapAttributesDisplay : ModFooterInformationDisplay, IHasCustomTooltip
{ {
private StarRatingDisplay starRatingDisplay = null!; private StarRatingDisplay starRatingDisplay = null!;
private BPMDisplay bpmDisplay = null!; private BPMDisplay bpmDisplay = null!;
@ -58,10 +57,11 @@ namespace osu.Game.Overlays.Mods
private CancellationTokenSource? cancellationSource; private CancellationTokenSource? cancellationSource;
private IBindable<StarDifficulty?> starDifficulty = null!; private IBindable<StarDifficulty?> starDifficulty = null!;
private BeatmapDifficulty? originalDifficulty; private AdjustedAttributesTooltip rateAdjustTooltip = null!;
private BeatmapDifficulty? adjustedDifficulty;
public ITooltip GetCustomTooltip() => rateAdjustTooltip;
public object TooltipContent => this;
private bool haveRateChangedValues;
private const float transition_duration = 250; private const float transition_duration = 250;
@ -70,6 +70,8 @@ namespace osu.Game.Overlays.Mods
{ {
const float shear = ShearedOverlayContainer.SHEAR; const float shear = ShearedOverlayContainer.SHEAR;
rateAdjustTooltip = new AdjustedAttributesTooltip();
LeftContent.AddRange(new Drawable[] LeftContent.AddRange(new Drawable[]
{ {
starRatingDisplay = new StarRatingDisplay(default, animated: true) starRatingDisplay = new StarRatingDisplay(default, animated: true)
@ -105,7 +107,6 @@ namespace osu.Game.Overlays.Mods
mods.BindValueChanged(_ => mods.BindValueChanged(_ =>
{ {
modSettingChangeTracker?.Dispose(); modSettingChangeTracker?.Dispose();
modSettingChangeTracker = new ModSettingChangeTracker(mods.Value); modSettingChangeTracker = new ModSettingChangeTracker(mods.Value);
modSettingChangeTracker.SettingChanged += _ => updateValues(); modSettingChangeTracker.SettingChanged += _ => updateValues();
updateValues(); updateValues();
@ -125,6 +126,9 @@ namespace osu.Game.Overlays.Mods
BeatmapInfo.BindValueChanged(_ => updateValues(), true); BeatmapInfo.BindValueChanged(_ => updateValues(), true);
rateAdjustTooltip.AddAttribute("AR");
rateAdjustTooltip.AddAttribute("OD");
updateCollapsedState(); updateCollapsedState();
} }
@ -173,15 +177,16 @@ namespace osu.Game.Overlays.Mods
bpmDisplay.Current.Value = BeatmapInfo.Value.BPM * rate; bpmDisplay.Current.Value = BeatmapInfo.Value.BPM * rate;
originalDifficulty = new BeatmapDifficulty(BeatmapInfo.Value.Difficulty); BeatmapDifficulty originalDifficulty = new BeatmapDifficulty(BeatmapInfo.Value.Difficulty);
foreach (var mod in mods.Value.OfType<IApplicableToDifficulty>()) foreach (var mod in mods.Value.OfType<IApplicableToDifficulty>())
mod.ApplyToDifficulty(originalDifficulty); mod.ApplyToDifficulty(originalDifficulty);
Ruleset ruleset = gameRuleset.Value.CreateInstance(); Ruleset ruleset = gameRuleset.Value.CreateInstance();
adjustedDifficulty = ruleset.GetRateAdjustedDisplayDifficulty(originalDifficulty, rate); BeatmapDifficulty adjustedDifficulty = ruleset.GetRateAdjustedDisplayDifficulty(originalDifficulty, rate);
haveRateChangedValues = hasRateAdjustedProperties(originalDifficulty, adjustedDifficulty); rateAdjustTooltip.UpdateAttribute("AR", originalDifficulty.ApproachRate, adjustedDifficulty.ApproachRate);
rateAdjustTooltip.UpdateAttribute("OD", originalDifficulty.OverallDifficulty, adjustedDifficulty.OverallDifficulty);
approachRateDisplay.AdjustType.Value = VerticalAttributeDisplay.CalculateEffect(originalDifficulty.ApproachRate, adjustedDifficulty.ApproachRate); approachRateDisplay.AdjustType.Value = VerticalAttributeDisplay.CalculateEffect(originalDifficulty.ApproachRate, adjustedDifficulty.ApproachRate);
overallDifficultyDisplay.AdjustType.Value = VerticalAttributeDisplay.CalculateEffect(originalDifficulty.OverallDifficulty, adjustedDifficulty.OverallDifficulty); overallDifficultyDisplay.AdjustType.Value = VerticalAttributeDisplay.CalculateEffect(originalDifficulty.OverallDifficulty, adjustedDifficulty.OverallDifficulty);
@ -197,29 +202,6 @@ namespace osu.Game.Overlays.Mods
RightContent.FadeTo(Collapsed.Value && !IsHovered ? 0 : 1, transition_duration, Easing.OutQuint); RightContent.FadeTo(Collapsed.Value && !IsHovered ? 0 : 1, transition_duration, Easing.OutQuint);
} }
public LocalisableString TooltipText
{
get
{
if (haveRateChangedValues)
{
return $"One or more values are being adjusted by mods that change speed." +
$" (AR {originalDifficulty?.ApproachRate ?? 0}→{(adjustedDifficulty?.ApproachRate ?? 0):0.0#}, " +
$"OD {originalDifficulty?.OverallDifficulty ?? 0}→{(adjustedDifficulty?.OverallDifficulty ?? 0):0.0#})";
}
return string.Empty;
}
}
private static bool hasRateAdjustedProperties(BeatmapDifficulty a, BeatmapDifficulty b)
{
if (!Precision.AlmostEquals(a.ApproachRate, b.ApproachRate)) return true;
if (!Precision.AlmostEquals(a.OverallDifficulty, b.OverallDifficulty)) return true;
return false;
}
private partial class BPMDisplay : RollingCounter<double> private partial class BPMDisplay : RollingCounter<double>
{ {
protected override double RollingDuration => 500; protected override double RollingDuration => 500;

View File

@ -26,10 +26,11 @@ using osu.Framework.Utils;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Overlays.Mods;
namespace osu.Game.Screens.Select.Details namespace osu.Game.Screens.Select.Details
{ {
public partial class AdvancedStats : Container, IHasTooltip public partial class AdvancedStats : Container, IHasCustomTooltip
{ {
[Resolved] [Resolved]
private BeatmapDifficultyCache difficultyCache { get; set; } private BeatmapDifficultyCache difficultyCache { get; set; }
@ -45,9 +46,9 @@ namespace osu.Game.Screens.Select.Details
protected readonly StatisticRow FirstValue, HpDrain, Accuracy, ApproachRate; protected readonly StatisticRow FirstValue, HpDrain, Accuracy, ApproachRate;
private readonly StatisticRow starDifficulty; private readonly StatisticRow starDifficulty;
private BeatmapDifficulty originalDifficulty; private AdjustedAttributesTooltip rateAdjustTooltip;
private BeatmapDifficulty adjustedDifficulty; public ITooltip GetCustomTooltip() => rateAdjustTooltip;
private bool haveRateChangedValues; public object TooltipContent => this;
private IBeatmapInfo beatmapInfo; private IBeatmapInfo beatmapInfo;
@ -85,6 +86,7 @@ namespace osu.Game.Screens.Select.Details
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
starDifficulty.AccentColour = colours.Yellow; starDifficulty.AccentColour = colours.Yellow;
rateAdjustTooltip = new AdjustedAttributesTooltip();
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -99,6 +101,9 @@ namespace osu.Game.Screens.Select.Details
gameRuleset.BindValueChanged(_ => updateStatistics()); gameRuleset.BindValueChanged(_ => updateStatistics());
mods.BindValueChanged(modsChanged, true); mods.BindValueChanged(modsChanged, true);
rateAdjustTooltip.AddAttribute("AR");
rateAdjustTooltip.AddAttribute("OD");
} }
private ModSettingChangeTracker modSettingChangeTracker; private ModSettingChangeTracker modSettingChangeTracker;
@ -121,14 +126,17 @@ namespace osu.Game.Screens.Select.Details
private void updateStatistics() private void updateStatistics()
{ {
IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.Difficulty; IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.Difficulty;
BeatmapDifficulty adjustedDifficulty = null;
if (baseDifficulty != null) if (baseDifficulty != null)
{ {
originalDifficulty = new BeatmapDifficulty(baseDifficulty); BeatmapDifficulty originalDifficulty = new BeatmapDifficulty(baseDifficulty);
foreach (var mod in mods.Value.OfType<IApplicableToDifficulty>()) foreach (var mod in mods.Value.OfType<IApplicableToDifficulty>())
mod.ApplyToDifficulty(originalDifficulty); mod.ApplyToDifficulty(originalDifficulty);
adjustedDifficulty = originalDifficulty;
if (gameRuleset != null) if (gameRuleset != null)
{ {
Ruleset ruleset = gameRuleset.Value.CreateInstance(); Ruleset ruleset = gameRuleset.Value.CreateInstance();
@ -138,7 +146,9 @@ namespace osu.Game.Screens.Select.Details
rate = mod.ApplyToRate(0, rate); rate = mod.ApplyToRate(0, rate);
adjustedDifficulty = ruleset.GetRateAdjustedDisplayDifficulty(originalDifficulty, rate); adjustedDifficulty = ruleset.GetRateAdjustedDisplayDifficulty(originalDifficulty, rate);
haveRateChangedValues = hasRateAdjustedProperties(originalDifficulty, adjustedDifficulty);
rateAdjustTooltip.UpdateAttribute("AR", originalDifficulty.ApproachRate, adjustedDifficulty.ApproachRate);
rateAdjustTooltip.UpdateAttribute("OD", originalDifficulty.OverallDifficulty, adjustedDifficulty.OverallDifficulty);
} }
} }
@ -204,22 +214,6 @@ namespace osu.Game.Screens.Select.Details
starDifficultyCancellationSource?.Cancel(); starDifficultyCancellationSource?.Cancel();
} }
public LocalisableString TooltipText
{
get
{
if (haveRateChangedValues)
{
// Rather than localising this, it should be displayed in a better way (a custom tooltip which isn't a single super-long line).
return "One or more values are being adjusted by mods that change speed." +
$" (AR {originalDifficulty?.ApproachRate ?? 0}→{(adjustedDifficulty?.ApproachRate ?? 0):0.0#}, " +
$"OD {originalDifficulty?.OverallDifficulty ?? 0}→{(adjustedDifficulty?.OverallDifficulty ?? 0):0.0#})";
}
return string.Empty;
}
}
private static bool hasRateAdjustedProperties(BeatmapDifficulty a, BeatmapDifficulty b) private static bool hasRateAdjustedProperties(BeatmapDifficulty a, BeatmapDifficulty b)
{ {
if (!Precision.AlmostEquals(a.ApproachRate, b.ApproachRate)) return true; if (!Precision.AlmostEquals(a.ApproachRate, b.ApproachRate)) return true;