From 559960036e61edf1caefb5670fe9c939dad0ef59 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 5 Feb 2019 14:48:35 +0300 Subject: [PATCH] update top score design --- .../Graphics/Containers/OsuHoverContainer.cs | 10 +- .../BeatmapSet/Scores/ClickableUsername.cs | 15 +- .../BeatmapSet/Scores/DrawableScore.cs | 16 +- .../BeatmapSet/Scores/DrawableTopScore.cs | 422 ++++++++++++------ .../BeatmapSet/Scores/ScoresContainer.cs | 7 + 5 files changed, 328 insertions(+), 142 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuHoverContainer.cs b/osu.Game/Graphics/Containers/OsuHoverContainer.cs index 276b0f9dd1..091499b7cd 100644 --- a/osu.Game/Graphics/Containers/OsuHoverContainer.cs +++ b/osu.Game/Graphics/Containers/OsuHoverContainer.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Input.Events; +using osuTK.Graphics; +using System.Collections.Generic; namespace osu.Game.Graphics.Containers { @@ -16,17 +16,19 @@ namespace osu.Game.Graphics.Containers protected Color4 IdleColour = Color4.White; + protected const float FADE_DURATION = 500; + protected virtual IEnumerable EffectTargets => new[] { Content }; protected override bool OnHover(HoverEvent e) { - EffectTargets.ForEach(d => d.FadeColour(HoverColour, 500, Easing.OutQuint)); + EffectTargets.ForEach(d => d.FadeColour(HoverColour, FADE_DURATION, Easing.OutQuint)); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - EffectTargets.ForEach(d => d.FadeColour(IdleColour, 500, Easing.OutQuint)); + EffectTargets.ForEach(d => d.FadeColour(IdleColour, FADE_DURATION, Easing.OutQuint)); base.OnHoverLost(e); } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs index 0eb8b325d3..e2aade986d 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs @@ -3,16 +3,20 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; +using System.Collections.Generic; namespace osu.Game.Overlays.BeatmapSet.Scores { public class ClickableUsername : OsuHoverContainer { - private readonly OsuSpriteText text; + private readonly SpriteText text; + protected override IEnumerable EffectTargets => new[] { text }; + private UserProfileOverlay profile; private User user; @@ -24,7 +28,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (user == value) return; user = value; - text.Text = user.Username; + OnUserUpdate(user); } } @@ -41,12 +45,17 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public ClickableUsername() { AutoSizeAxes = Axes.Both; - Child = text = new OsuSpriteText + Child = text = new SpriteText { Font = @"Exo2.0-BoldItalic", }; } + protected virtual void OnUserUpdate(User user) + { + text.Text = user.Username; + } + [BackgroundDependencyLoader(true)] private void load(UserProfileOverlay profile) { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index 1f50385adc..609524f170 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osuTK; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,6 +15,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Users; +using osuTK; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -56,13 +56,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Size = new Vector2(30, 20), Margin = new MarginPadding { Left = 60 } }, - new ClickableUsername - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - User = score.User, - Margin = new MarginPadding { Left = 100 } - }, + //new ClickableUsername + //{ + // Anchor = Anchor.CentreLeft, + // Origin = Anchor.CentreLeft, + // User = score.User, + // Margin = new MarginPadding { Left = 100 } + //}, modsContainer = new ScoreModsContainer { Anchor = Anchor.CentreLeft, diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index c9551cf6f8..2e2bb78634 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -1,13 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osuTK; -using osuTK.Graphics; +using Humanizer; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -19,29 +19,38 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Users; +using osuTK; +using osuTK.Graphics; +using System.Collections.Generic; namespace osu.Game.Overlays.BeatmapSet.Scores { public class DrawableTopScore : Container { private const float fade_duration = 100; - private const float height = 200; + private const float height = 100; private const float avatar_size = 80; private const float margin = 10; private readonly Box background; - private readonly Box bottomBackground; - private readonly Box middleLine; private readonly UpdateableAvatar avatar; private readonly DrawableFlag flag; private readonly ClickableUsername username; - private readonly OsuSpriteText rankText; - private readonly OsuSpriteText date; + private readonly SpriteText rankText; + private readonly SpriteText date; private readonly DrawableRank rank; - private readonly InfoColumn totalScore; - private readonly InfoColumn accuracy; - private readonly InfoColumn statistics; - private readonly ScoreModsContainer modsContainer; + + private readonly AutoSizeInfoColumn totalScore; + private readonly MediumInfoColumn accuracy; + private readonly MediumInfoColumn maxCombo; + + private readonly SmallInfoColumn hitGreat; + private readonly SmallInfoColumn hitGood; + private readonly SmallInfoColumn hitMeh; + private readonly SmallInfoColumn hitMiss; + private readonly SmallInfoColumn pp; + + private readonly ModsInfoColumn modsInfo; private APIScoreInfo score; public APIScoreInfo Score @@ -54,153 +63,296 @@ namespace osu.Game.Overlays.BeatmapSet.Scores avatar.User = username.User = score.User; flag.Country = score.User.Country; - date.Text = $@"achieved {score.Date:MMM d, yyyy}"; + date.Text = $@"achieved {score.Date.Humanize()}"; rank.UpdateRank(score.Rank); totalScore.Value = $@"{score.TotalScore:N0}"; accuracy.Value = $@"{score.Accuracy:P2}"; - statistics.Value = $"{score.Statistics[HitResult.Great]}/{score.Statistics[HitResult.Good]}/{score.Statistics[HitResult.Meh]}"; + maxCombo.Value = $@"{score.MaxCombo:N0}x"; - modsContainer.Clear(); - foreach (Mod mod in score.Mods) - modsContainer.Add(new ModIcon(mod) - { - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.45f), - }); + hitGreat.Value = $"{score.Statistics[HitResult.Great]}"; + hitGood.Value = $"{score.Statistics[HitResult.Good]}"; + hitMeh.Value = $"{score.Statistics[HitResult.Meh]}"; + hitMiss.Value = $"{score.Statistics[HitResult.Miss]}"; + pp.Value = $@"{score.PP:N0}"; + + modsInfo.ClearMods(); + modsInfo.Mods = score.Mods; } } public DrawableTopScore() { RelativeSizeAxes = Axes.X; - Height = height; - CornerRadius = 5; - BorderThickness = 4; + AutoSizeAxes = Axes.Y; + CornerRadius = 3; Masking = true; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.2f), + Radius = 1, + Offset = new Vector2(0, 1), + }; Children = new Drawable[] { background = new Box { RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true, //used for correct border representation - }, - avatar = new UpdateableAvatar - { - Size = new Vector2(avatar_size), - Masking = true, - CornerRadius = 5, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.25f), - Offset = new Vector2(0, 2), - Radius = 1, - }, - Margin = new MarginPadding { Top = margin, Left = margin } - }, - flag = new DrawableFlag - { - Size = new Vector2(30, 20), - Position = new Vector2(margin * 2 + avatar_size, height / 4), - }, - username = new ClickableUsername - { - Origin = Anchor.BottomLeft, - TextSize = 30, - Position = new Vector2(margin * 2 + avatar_size, height / 4), - Margin = new MarginPadding { Bottom = 4 } - }, - rankText = new OsuSpriteText - { - Anchor = Anchor.TopRight, - Origin = Anchor.BottomRight, - Text = "#1", - TextSize = 40, - Font = @"Exo2.0-BoldItalic", - Y = height / 4, - Margin = new MarginPadding { Right = margin } - }, - date = new OsuSpriteText - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Y = height / 4, - Margin = new MarginPadding { Right = margin } + Colour = Color4.White, }, new Container { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.Both, - Height = 0.5f, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(margin), Children = new Drawable[] { - bottomBackground = new Box { RelativeSizeAxes = Axes.Both }, - middleLine = new Box + new FillFlowContainer { - RelativeSizeAxes = Axes.X, - Height = 1, - }, - rank = new DrawableRank(ScoreRank.F) - { - Origin = Anchor.BottomLeft, - Size = new Vector2(avatar_size, 40), - FillMode = FillMode.Fit, - Y = height / 4, - Margin = new MarginPadding { Left = margin } - }, - new FillFlowContainer - { - Origin = Anchor.BottomLeft, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Position = new Vector2(height / 2, height / 4), Direction = FillDirection.Horizontal, - Spacing = new Vector2(15, 0), - Children = new[] + Spacing = new Vector2(margin, 0), + Children = new Drawable[] { - totalScore = new InfoColumn("Score"), - accuracy = new InfoColumn("Accuracy"), - statistics = new InfoColumn("300/100/50"), - }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 2), + Children = new Drawable[] + { + rankText = new SpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Text = "#1", + TextSize = 20, + Font = @"Exo2.0-BoldItalic", + }, + rank = new DrawableRank(ScoreRank.F) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Size = new Vector2(30), + FillMode = FillMode.Fit, + }, + } + }, + avatar = new UpdateableAvatar + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = 5, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Offset = new Vector2(0, 2), + Radius = 1, + }, + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 3), + Children = new Drawable[] + { + username = new ClickableTopScoreUsername + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + TextSize = 20, + }, + date = new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + TextSize = 10, + }, + flag = new DrawableFlag + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(20, 13), + }, + } + } + } }, - modsContainer = new ScoreModsContainer + new Container { - AutoSizeAxes = Axes.Y, - Width = 80, - Position = new Vector2(height / 2, height / 4), + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(margin, 0), + Children = new Drawable[] + { + totalScore = new AutoSizeInfoColumn("Total Score"), + accuracy = new MediumInfoColumn("Accuracy"), + maxCombo = new MediumInfoColumn("Max Combo"), + hitGreat = new SmallInfoColumn("300", 20), + hitGood = new SmallInfoColumn("100", 20), + hitMeh = new SmallInfoColumn("50", 20), + hitMiss = new SmallInfoColumn("miss", 20), + pp = new SmallInfoColumn("pp", 20), + modsInfo = new ModsInfoColumn("mods"), + } + } } } - }, + } }; } [BackgroundDependencyLoader] private void load(OsuColour colours) { - background.Colour = bottomBackground.Colour = colours.Gray4; - middleLine.Colour = colours.Gray2; - date.Colour = colours.Gray9; - BorderColour = rankText.Colour = colours.Yellow; + date.Colour = rankText.Colour = colours.ContextMenuGray; } protected override bool OnHover(HoverEvent e) { - background.FadeIn(fade_duration, Easing.OutQuint); + background.FadeColour(Color4.WhiteSmoke, fade_duration, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - background.FadeOut(fade_duration, Easing.OutQuint); + background.FadeColour(Color4.White, fade_duration, Easing.OutQuint); base.OnHoverLost(e); } - private class InfoColumn : FillFlowContainer + private class ClickableTopScoreUsername : ClickableUsername { - private readonly OsuSpriteText headerText; - private readonly OsuSpriteText valueText; + private Box underscore; + + public ClickableTopScoreUsername() + { + Add(new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = 1, + Position = new Vector2(0, TextSize / 2 + 1.5f), + Depth = 1, + Child = underscore = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + IdleColour = colours.ContextMenuGray; + HoverColour = underscore.Colour = colours.Blue; + } + + protected override bool OnHover(HoverEvent e) + { + underscore.FadeIn(FADE_DURATION, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + underscore.FadeOut(FADE_DURATION, Easing.OutQuint); + base.OnHoverLost(e); + } + } + + private class DrawableInfoColumn : FillFlowContainer + { + private readonly SpriteText headerText; + private const float header_text_size = 12; + + public DrawableInfoColumn(string header) + { + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Spacing = new Vector2(0, 2); + Children = new Drawable[] + { + new Container + { + AutoSizeAxes = Axes.X, + Height = header_text_size, + Child = headerText = new SpriteText + { + TextSize = 12, + Text = header.ToUpper(), + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + Height = 3, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.LightGray, + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + headerText.Colour = colours.ContextMenuGray; + } + } + + private class ModsInfoColumn : DrawableInfoColumn + { + private readonly FillFlowContainer modsContainer; + + public IEnumerable Mods + { + set + { + foreach (Mod mod in value) + modsContainer.Add(new ModIcon(mod) + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.3f), + }); + } + } + + public ModsInfoColumn(string header) : base(header) + { + AutoSizeAxes = Axes.Both; + Add(modsContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + }); + } + + public void ClearMods() => modsContainer.Clear(); + } + + private class TextInfoColumn : DrawableInfoColumn + { + private readonly SpriteText valueText; public string Value { @@ -213,31 +365,47 @@ namespace osu.Game.Overlays.BeatmapSet.Scores get { return valueText.Text; } } - public InfoColumn(string header) + public TextInfoColumn(string header, float valueTextSize = 25) : base(header) { - AutoSizeAxes = Axes.Both; - Direction = FillDirection.Vertical; - Spacing = new Vector2(0, 3); - Children = new Drawable[] + Add(valueText = new SpriteText { - headerText = new OsuSpriteText - { - TextSize = 14, - Text = header, - Font = @"Exo2.0-Bold", - }, - valueText = new OsuSpriteText - { - TextSize = 25, - Font = @"Exo2.0-RegularItalic", - } - }; + TextSize = valueTextSize, + Font = @"Exo2.0-Light", + }); } [BackgroundDependencyLoader] private void load(OsuColour colours) { - headerText.Colour = colours.Gray9; + valueText.Colour = colours.ContextMenuGray; + } + } + + private class AutoSizeInfoColumn : TextInfoColumn + { + public AutoSizeInfoColumn(string header, float valueTextSize = 25) : base(header, valueTextSize) + { + AutoSizeAxes = Axes.Both; + } + } + + private class MediumInfoColumn : TextInfoColumn + { + private const float width = 70; + + public MediumInfoColumn(string header, float valueTextSize = 25) : base(header, valueTextSize) + { + Width = width; + } + } + + private class SmallInfoColumn : TextInfoColumn + { + private const float width = 40; + + public SmallInfoColumn(string header, float valueTextSize = 25) : base(header, valueTextSize) + { + Width = width; } } } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index ab34d2ba1d..ac3068c2c8 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -12,6 +12,8 @@ using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -98,6 +100,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores AutoSizeAxes = Axes.Y; Children = new Drawable[] { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, new FillFlowContainer { Anchor = Anchor.TopCentre,