Merge branch 'master' into log-diffcalc-failure

This commit is contained in:
Salman Ahmed 2022-07-25 11:16:31 +03:00 committed by GitHub
commit 678acabf7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 488 additions and 204 deletions

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics;
namespace osu.Game.Tests.Visual.Editing namespace osu.Game.Tests.Visual.Editing
{ {
[Ignore("Timeline initialisation is kinda broken.")] // Initial work to rectify this was done in https://github.com/ppy/osu/pull/19297, but needs more massaging to work.
public class TestSceneTimelineZoom : TimelineTestScene public class TestSceneTimelineZoom : TimelineTestScene
{ {
public override Drawable CreateTestComponent() => Empty(); public override Drawable CreateTestComponent() => Empty();

View File

@ -141,6 +141,19 @@ namespace osu.Game.Tests.Visual.Online
AddUntilStep("best score not displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 1); AddUntilStep("best score not displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 1);
} }
[Test]
public void TestUnprocessedPP()
{
AddStep("Load scores with unprocessed PP", () =>
{
var allScores = createScores();
allScores.Scores[0].PP = null;
allScores.UserScore = createUserBest();
allScores.UserScore.Score.PP = null;
scoresContainer.Scores = allScores;
});
}
private int onlineID = 1; private int onlineID = 1;
private APIScoresCollection createScores() private APIScoresCollection createScores()

View File

@ -7,6 +7,7 @@ using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
@ -99,6 +100,23 @@ namespace osu.Game.Tests.Visual.Online
Accuracy = 0.55879 Accuracy = 0.55879
}; };
var unprocessedPPScore = new SoloScoreInfo
{
Rank = ScoreRank.B,
Beatmap = new APIBeatmap
{
BeatmapSet = new APIBeatmapSet
{
Title = "C18H27NO3(extend)",
Artist = "Team Grimoire",
},
DifficultyName = "[4K] Cataclysmic Hypernova",
Status = BeatmapOnlineStatus.Ranked,
},
EndedAt = DateTimeOffset.Now,
Accuracy = 0.55879
};
Add(new FillFlowContainer Add(new FillFlowContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -112,6 +130,7 @@ namespace osu.Game.Tests.Visual.Online
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(firstScore)), new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(firstScore)),
new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(secondScore)), new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(secondScore)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unprocessedPPScore)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(firstScore, 0.97)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(firstScore, 0.97)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(secondScore, 0.85)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(secondScore, 0.85)),
new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(thirdScore, 0.66)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(thirdScore, 0.66)),

View File

@ -0,0 +1,77 @@
// 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 System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneModPresetColumn : OsuTestScene
{
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
[Test]
public void TestBasicAppearance()
{
ModPresetColumn modPresetColumn = null!;
AddStep("create content", () => Child = new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(30),
Child = modPresetColumn = new ModPresetColumn
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Presets = createTestPresets().ToArray()
}
});
AddStep("change presets", () => modPresetColumn.Presets = createTestPresets().Skip(1).ToArray());
}
private static IEnumerable<ModPreset> createTestPresets() => new[]
{
new ModPreset
{
Name = "First preset",
Description = "Please ignore",
Mods = new Mod[]
{
new OsuModHardRock(),
new OsuModDoubleTime()
}
},
new ModPreset
{
Name = "AR0",
Description = "For good readers",
Mods = new Mod[]
{
new OsuModDifficultyAdjust
{
ApproachRate = { Value = 0 }
}
}
},
new ModPreset
{
Name = "This preset is going to have an extraordinarily long name",
Description = "This is done so that the capability to truncate overlong texts may be demonstrated",
Mods = new Mod[]
{
new OsuModFlashlight(),
new OsuModSpinIn()
}
}
};
}
}

View File

@ -24,6 +24,11 @@ namespace osu.Game.Localisation
/// </summary> /// </summary>
public static LocalisableString ModCustomisation => new TranslatableString(getKey(@"mod_customisation"), @"Mod Customisation"); public static LocalisableString ModCustomisation => new TranslatableString(getKey(@"mod_customisation"), @"Mod Customisation");
/// <summary>
/// "Personal Presets"
/// </summary>
public static LocalisableString PersonalPresets => new TranslatableString(getKey(@"personal_presets"), @"Personal Presets");
private static string getKey(string key) => $@"{prefix}:{key}"; private static string getKey(string key) => $@"{prefix}:{key}";
} }
} }

View File

@ -6,7 +6,6 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions; using osu.Framework.Extensions;
@ -25,6 +24,7 @@ using osu.Framework.Localisation;
using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Scoring.Drawables;
namespace osu.Game.Overlays.BeatmapSet.Scores namespace osu.Game.Overlays.BeatmapSet.Scores
{ {
@ -179,8 +179,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (showPerformancePoints) if (showPerformancePoints)
{ {
Debug.Assert(score.PP != null); if (score.PP != null)
content.Add(new StatisticText(score.PP.Value, format: @"N0")); content.Add(new StatisticText(score.PP, format: @"N0"));
else
content.Add(new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(text_size) });
} }
content.Add(new ScoreboardTime(score.Date, text_size) content.Add(new ScoreboardTime(score.Date, text_size)
@ -222,19 +224,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private class StatisticText : OsuSpriteText, IHasTooltip private class StatisticText : OsuSpriteText, IHasTooltip
{ {
private readonly double count; private readonly double? count;
private readonly double? maxCount; private readonly double? maxCount;
private readonly bool showTooltip; private readonly bool showTooltip;
public LocalisableString TooltipText => maxCount == null || !showTooltip ? string.Empty : $"{count}/{maxCount}"; public LocalisableString TooltipText => maxCount == null || !showTooltip ? string.Empty : $"{count}/{maxCount}";
public StatisticText(double count, double? maxCount = null, string format = null, bool showTooltip = true) public StatisticText(double? count, double? maxCount = null, string format = null, bool showTooltip = true)
{ {
this.count = count; this.count = count;
this.maxCount = maxCount; this.maxCount = maxCount;
this.showTooltip = showTooltip; this.showTooltip = showTooltip;
Text = count.ToLocalisableString(format); Text = count?.ToLocalisableString(format) ?? default;
Font = OsuFont.GetFont(size: text_size); Font = OsuFont.GetFont(size: text_size);
} }

View File

@ -12,14 +12,17 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Scoring.Drawables;
using osuTK; using osuTK;
namespace osu.Game.Overlays.BeatmapSet.Scores namespace osu.Game.Overlays.BeatmapSet.Scores
@ -121,7 +124,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x"); maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x");
ppColumn.Alpha = value.BeatmapInfo.Status.GrantsPerformancePoints() ? 1 : 0; ppColumn.Alpha = value.BeatmapInfo.Status.GrantsPerformancePoints() ? 1 : 0;
ppColumn.Text = value.PP?.ToLocalisableString(@"N0") ?? default;
if (value.PP is double pp)
ppColumn.Text = pp.ToLocalisableString(@"N0");
else
ppColumn.Drawable = new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(smallFont.Size) };
statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(createStatisticsColumn); statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(createStatisticsColumn);
modsColumn.Mods = value.Mods; modsColumn.Mods = value.Mods;
@ -197,30 +204,48 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
} }
} }
private class TextColumn : InfoColumn private class TextColumn : InfoColumn, IHasCurrentValue<string>
{ {
private readonly SpriteText text; private readonly OsuTextFlowContainer text;
public TextColumn(LocalisableString title, FontUsage font, float? minWidth = null)
: this(title, new OsuSpriteText { Font = font }, minWidth)
{
}
private TextColumn(LocalisableString title, SpriteText text, float? minWidth = null)
: base(title, text, minWidth)
{
this.text = text;
}
public LocalisableString Text public LocalisableString Text
{ {
set => text.Text = value; set => text.Text = value;
} }
public Drawable Drawable
{
set
{
text.Clear();
text.AddArbitraryDrawable(value);
}
}
private Bindable<string> current;
public Bindable<string> Current public Bindable<string> Current
{ {
get => text.Current; get => current;
set => text.Current = value; set
{
text.Clear();
text.AddText(value.Value, t => t.Current = current = value);
}
}
public TextColumn(LocalisableString title, FontUsage font, float? minWidth = null)
: this(title, new OsuTextFlowContainer(t => t.Font = font)
{
AutoSizeAxes = Axes.Both
}, minWidth)
{
}
private TextColumn(LocalisableString title, OsuTextFlowContainer text, float? minWidth = null)
: base(title, text, minWidth)
{
this.text = text;
} }
} }

View File

@ -12,14 +12,10 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation; using osu.Game.Localisation;
using osu.Game.Overlays.Mods.Input; using osu.Game.Overlays.Mods.Input;
@ -29,10 +25,8 @@ using osuTK.Graphics;
namespace osu.Game.Overlays.Mods namespace osu.Game.Overlays.Mods
{ {
public class ModColumn : CompositeDrawable public class ModColumn : ModSelectColumn
{ {
public readonly Container TopLevelContent;
public readonly ModType ModType; public readonly ModType ModType;
private IReadOnlyList<ModState> availableMods = Array.Empty<ModState>(); private IReadOnlyList<ModState> availableMods = Array.Empty<ModState>();
@ -62,149 +56,29 @@ namespace osu.Game.Overlays.Mods
} }
} }
/// <summary>
/// Determines whether this column should accept user input.
/// </summary>
public Bindable<bool> Active = new BindableBool(true);
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => base.ReceivePositionalInputAtSubTree(screenSpacePos) && Active.Value;
protected virtual ModPanel CreateModPanel(ModState mod) => new ModPanel(mod); protected virtual ModPanel CreateModPanel(ModState mod) => new ModPanel(mod);
private readonly bool allowIncompatibleSelection; private readonly bool allowIncompatibleSelection;
private readonly TextFlowContainer headerText;
private readonly Box headerBackground;
private readonly Container contentContainer;
private readonly Box contentBackground;
private readonly FillFlowContainer<ModPanel> panelFlow;
private readonly ToggleAllCheckbox? toggleAllCheckbox; private readonly ToggleAllCheckbox? toggleAllCheckbox;
private Colour4 accentColour;
private Bindable<ModSelectHotkeyStyle> hotkeyStyle = null!; private Bindable<ModSelectHotkeyStyle> hotkeyStyle = null!;
private IModHotkeyHandler hotkeyHandler = null!; private IModHotkeyHandler hotkeyHandler = null!;
private Task? latestLoadTask; private Task? latestLoadTask;
internal bool ItemsLoaded => latestLoadTask == null; internal bool ItemsLoaded => latestLoadTask == null;
private const float header_height = 42;
public ModColumn(ModType modType, bool allowIncompatibleSelection) public ModColumn(ModType modType, bool allowIncompatibleSelection)
{ {
ModType = modType; ModType = modType;
this.allowIncompatibleSelection = allowIncompatibleSelection; this.allowIncompatibleSelection = allowIncompatibleSelection;
Width = 320; HeaderText = ModType.Humanize(LetterCasing.Title);
RelativeSizeAxes = Axes.Y;
Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0);
Container controlContainer;
InternalChildren = new Drawable[]
{
TopLevelContent = new Container
{
RelativeSizeAxes = Axes.Both,
CornerRadius = ModSelectPanel.CORNER_RADIUS,
Masking = true,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
Height = header_height + ModSelectPanel.CORNER_RADIUS,
Children = new Drawable[]
{
headerBackground = new Box
{
RelativeSizeAxes = Axes.X,
Height = header_height + ModSelectPanel.CORNER_RADIUS
},
headerText = new OsuTextFlowContainer(t =>
{
t.Font = OsuFont.TorusAlternate.With(size: 17);
t.Shadow = false;
t.Colour = Colour4.Black;
})
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
Padding = new MarginPadding
{
Horizontal = 17,
Bottom = ModSelectPanel.CORNER_RADIUS
}
}
}
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = header_height },
Child = contentContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = ModSelectPanel.CORNER_RADIUS,
BorderThickness = 3,
Children = new Drawable[]
{
contentBackground = new Box
{
RelativeSizeAxes = Axes.Both
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension()
},
Content = new[]
{
new Drawable[]
{
controlContainer = new Container
{
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding { Horizontal = 14 }
}
},
new Drawable[]
{
new OsuScrollContainer(Direction.Vertical)
{
RelativeSizeAxes = Axes.Both,
ClampExtension = 100,
ScrollbarOverlapsContent = false,
Child = panelFlow = new FillFlowContainer<ModPanel>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0, 7),
Padding = new MarginPadding(7)
}
}
}
}
}
}
}
}
}
}
};
createHeaderText();
if (allowIncompatibleSelection) if (allowIncompatibleSelection)
{ {
controlContainer.Height = 35; ControlContainer.Height = 35;
controlContainer.Add(toggleAllCheckbox = new ToggleAllCheckbox(this) ControlContainer.Add(toggleAllCheckbox = new ToggleAllCheckbox(this)
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
@ -212,7 +86,7 @@ namespace osu.Game.Overlays.Mods
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0) Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0)
}); });
panelFlow.Padding = new MarginPadding ItemsFlow.Padding = new MarginPadding
{ {
Top = 0, Top = 0,
Bottom = 7, Bottom = 7,
@ -221,33 +95,17 @@ namespace osu.Game.Overlays.Mods
} }
} }
private void createHeaderText()
{
IEnumerable<string> headerTextWords = ModType.Humanize(LetterCasing.Title).Split(' ');
if (headerTextWords.Count() > 1)
{
headerText.AddText($"{headerTextWords.First()} ", t => t.Font = t.Font.With(weight: FontWeight.SemiBold));
headerTextWords = headerTextWords.Skip(1);
}
headerText.AddText(string.Join(' ', headerTextWords));
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider, OsuColour colours, OsuConfigManager configManager) private void load(OsuColour colours, OsuConfigManager configManager)
{ {
headerBackground.Colour = accentColour = colours.ForModType(ModType); AccentColour = colours.ForModType(ModType);
if (toggleAllCheckbox != null) if (toggleAllCheckbox != null)
{ {
toggleAllCheckbox.AccentColour = accentColour; toggleAllCheckbox.AccentColour = AccentColour;
toggleAllCheckbox.AccentHoverColour = accentColour.Lighten(0.3f); toggleAllCheckbox.AccentHoverColour = AccentColour.Lighten(0.3f);
} }
contentContainer.BorderColour = ColourInfo.GradientVertical(colourProvider.Background4, colourProvider.Background3);
contentBackground.Colour = colourProvider.Background4;
hotkeyStyle = configManager.GetBindable<ModSelectHotkeyStyle>(OsuSetting.ModSelectHotkeyStyle); hotkeyStyle = configManager.GetBindable<ModSelectHotkeyStyle>(OsuSetting.ModSelectHotkeyStyle);
} }
@ -278,7 +136,7 @@ namespace osu.Game.Overlays.Mods
latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded => latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded =>
{ {
panelFlow.ChildrenEnumerable = loaded; ItemsFlow.ChildrenEnumerable = loaded;
updateState(); updateState();
}, (cancellationTokenSource = new CancellationTokenSource()).Token); }, (cancellationTokenSource = new CancellationTokenSource()).Token);
loadTask.ContinueWith(_ => loadTask.ContinueWith(_ =>

View File

@ -0,0 +1,77 @@
// 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 System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Localisation;
using osu.Game.Rulesets.Mods;
using osuTK;
namespace osu.Game.Overlays.Mods
{
public class ModPresetColumn : ModSelectColumn
{
private IReadOnlyList<ModPreset> presets = Array.Empty<ModPreset>();
/// <summary>
/// Sets the collection of available mod presets.
/// </summary>
public IReadOnlyList<ModPreset> Presets
{
get => presets;
set
{
presets = value;
if (IsLoaded)
asyncLoadPanels();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.Orange1;
HeaderText = ModSelectOverlayStrings.PersonalPresets;
}
protected override void LoadComplete()
{
base.LoadComplete();
asyncLoadPanels();
}
private CancellationTokenSource? cancellationTokenSource;
private Task? latestLoadTask;
internal bool ItemsLoaded => latestLoadTask == null;
private void asyncLoadPanels()
{
cancellationTokenSource?.Cancel();
var panels = presets.Select(preset => new ModPresetPanel(preset)
{
Shear = Vector2.Zero
});
Task? loadTask;
latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded =>
{
ItemsFlow.ChildrenEnumerable = loaded;
}, (cancellationTokenSource = new CancellationTokenSource()).Token);
loadTask.ContinueWith(_ =>
{
if (loadTask == latestLoadTask)
latestLoadTask = null;
});
}
}
}

View File

@ -0,0 +1,177 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Mods
{
public abstract class ModSelectColumn : CompositeDrawable, IHasAccentColour
{
public readonly Container TopLevelContent;
public LocalisableString HeaderText
{
set => createHeaderText(value);
}
public Color4 AccentColour
{
get => headerBackground.Colour;
set => headerBackground.Colour = value;
}
/// <summary>
/// Determines whether this column should accept user input.
/// </summary>
public readonly Bindable<bool> Active = new BindableBool(true);
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => base.ReceivePositionalInputAtSubTree(screenSpacePos) && Active.Value;
protected readonly Container ControlContainer;
protected readonly FillFlowContainer ItemsFlow;
private readonly TextFlowContainer headerText;
private readonly Box headerBackground;
private readonly Container contentContainer;
private readonly Box contentBackground;
private const float header_height = 42;
protected ModSelectColumn()
{
Width = 320;
RelativeSizeAxes = Axes.Y;
Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0);
InternalChildren = new Drawable[]
{
TopLevelContent = new Container
{
RelativeSizeAxes = Axes.Both,
CornerRadius = ModSelectPanel.CORNER_RADIUS,
Masking = true,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
Height = header_height + ModSelectPanel.CORNER_RADIUS,
Children = new Drawable[]
{
headerBackground = new Box
{
RelativeSizeAxes = Axes.X,
Height = header_height + ModSelectPanel.CORNER_RADIUS
},
headerText = new OsuTextFlowContainer(t =>
{
t.Font = OsuFont.TorusAlternate.With(size: 17);
t.Shadow = false;
t.Colour = Colour4.Black;
})
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
Padding = new MarginPadding
{
Horizontal = 17,
Bottom = ModSelectPanel.CORNER_RADIUS
}
}
}
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = header_height },
Child = contentContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = ModSelectPanel.CORNER_RADIUS,
BorderThickness = 3,
Children = new Drawable[]
{
contentBackground = new Box
{
RelativeSizeAxes = Axes.Both
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension()
},
Content = new[]
{
new Drawable[]
{
ControlContainer = new Container
{
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding { Horizontal = 14 }
}
},
new Drawable[]
{
new OsuScrollContainer(Direction.Vertical)
{
RelativeSizeAxes = Axes.Both,
ClampExtension = 100,
ScrollbarOverlapsContent = false,
Child = ItemsFlow = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0, 7),
Padding = new MarginPadding(7)
}
}
}
}
}
}
}
}
}
}
};
}
private void createHeaderText(LocalisableString text)
{
headerText.Clear();
int wordIndex = 0;
headerText.AddText(text, t =>
{
if (wordIndex == 0)
t.Font = t.Font.With(weight: FontWeight.SemiBold);
wordIndex += 1;
});
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
contentContainer.BorderColour = ColourInfo.GradientVertical(colourProvider.Background4, colourProvider.Background3);
contentBackground.Colour = colourProvider.Background4;
}
}
}

View File

@ -19,6 +19,7 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards; using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Scoring.Drawables;
using osu.Game.Utils; using osu.Game.Utils;
using osuTK; using osuTK;
@ -218,8 +219,19 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
private Drawable createDrawablePerformance() private Drawable createDrawablePerformance()
{ {
if (Score.PP.HasValue) if (!Score.PP.HasValue)
{ {
if (Score.Beatmap?.Status.GrantsPerformancePoints() == true)
return new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(16), Colour = colourProvider.Highlight1 };
return new OsuSpriteText
{
Font = OsuFont.GetFont(weight: FontWeight.Bold),
Text = "-",
Colour = colourProvider.Highlight1
};
}
return new FillFlowContainer return new FillFlowContainer
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -246,14 +258,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
}; };
} }
return new OsuSpriteText
{
Font = OsuFont.GetFont(weight: FontWeight.Bold),
Text = "-",
Colour = colourProvider.Highlight1
};
}
private class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer private class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer
{ {
public ScoreBeatmapMetadataContainer(IBeatmapInfo beatmapInfo) public ScoreBeatmapMetadataContainer(IBeatmapInfo beatmapInfo)

View File

@ -42,12 +42,11 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
CreateDrawableAccuracy(), CreateDrawableAccuracy(),
new Container new Container
{ {
AutoSizeAxes = Axes.Y, Size = new Vector2(50, 14),
Width = 50,
Child = new OsuSpriteText Child = new OsuSpriteText
{ {
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
Text = $"{Score.PP * weight:0}pp", Text = Score.PP.HasValue ? $"{Score.PP * weight:0}pp" : string.Empty,
}, },
} }
} }

View File

@ -0,0 +1,27 @@
// 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.
#nullable disable
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Scoring.Drawables
{
/// <summary>
/// A placeholder used in PP columns for scores with unprocessed PP value.
/// </summary>
public class UnprocessedPerformancePointsPlaceholder : SpriteIcon, IHasTooltip
{
public LocalisableString TooltipText => ScoresStrings.StatusProcessing;
public UnprocessedPerformancePointsPlaceholder()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Icon = FontAwesome.Solid.ExclamationTriangle;
}
}
}