mirror of
https://github.com/ppy/osu
synced 2025-01-09 23:59:44 +00:00
208f66cc76
The same tooltip can be used for the rank graph, the play history graph, and the replay history graph. The only difference between those three is the displayed label, which has now been included as part of the `TooltipContent`, rather than unnecessarily recreating tooltips just for different sprite texts.
306 lines
10 KiB
C#
306 lines
10 KiB
C#
// 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 JetBrains.Annotations;
|
|
using osu.Framework.Allocation;
|
|
using osu.Framework.Graphics;
|
|
using osu.Framework.Graphics.Containers;
|
|
using osu.Framework.Graphics.Cursor;
|
|
using osu.Framework.Graphics.Shapes;
|
|
using osu.Framework.Input.Events;
|
|
using osu.Framework.Localisation;
|
|
using osu.Game.Graphics;
|
|
using osu.Game.Graphics.Sprites;
|
|
using osu.Game.Graphics.UserInterface;
|
|
using osuTK;
|
|
|
|
namespace osu.Game.Overlays.Profile
|
|
{
|
|
/// <summary>
|
|
/// Graph which is used in <see cref="UserProfileOverlay"/> to present changes in user statistics over time.
|
|
/// </summary>
|
|
/// <typeparam name="TKey">Type of data to be used for X-axis of the graph.</typeparam>
|
|
/// <typeparam name="TValue">Type of data to be used for Y-axis of the graph.</typeparam>
|
|
public abstract class UserGraph<TKey, TValue> : Container, IHasCustomTooltip<UserGraphTooltipContent>
|
|
{
|
|
protected const float FADE_DURATION = 150;
|
|
|
|
private readonly UserLineGraph graph;
|
|
private KeyValuePair<TKey, TValue>[] data;
|
|
private int hoveredIndex = -1;
|
|
|
|
protected UserGraph()
|
|
{
|
|
Add(graph = new UserLineGraph
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Alpha = 0
|
|
});
|
|
|
|
graph.OnBallMove += i => hoveredIndex = i;
|
|
}
|
|
|
|
[BackgroundDependencyLoader]
|
|
private void load(OsuColour colours)
|
|
{
|
|
graph.LineColour = colours.Yellow;
|
|
}
|
|
|
|
private float lastHoverPosition;
|
|
|
|
protected override bool OnHover(HoverEvent e)
|
|
{
|
|
if (data?.Length > 1)
|
|
{
|
|
graph.UpdateBallPosition(lastHoverPosition = e.MousePosition.X);
|
|
graph.ShowBar();
|
|
|
|
return true;
|
|
}
|
|
|
|
return base.OnHover(e);
|
|
}
|
|
|
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
|
{
|
|
if (data?.Length > 1)
|
|
graph.UpdateBallPosition(e.MousePosition.X);
|
|
|
|
return base.OnMouseMove(e);
|
|
}
|
|
|
|
protected override void OnHoverLost(HoverLostEvent e)
|
|
{
|
|
graph.HideBar();
|
|
base.OnHoverLost(e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set of values which will be used to create a graph.
|
|
/// </summary>
|
|
[CanBeNull]
|
|
protected KeyValuePair<TKey, TValue>[] Data
|
|
{
|
|
set
|
|
{
|
|
data = value;
|
|
redrawGraph();
|
|
}
|
|
}
|
|
|
|
private void redrawGraph()
|
|
{
|
|
hoveredIndex = -1;
|
|
|
|
if (data?.Length > 1)
|
|
{
|
|
graph.DefaultValueCount = data.Length;
|
|
graph.Values = data.Select(pair => GetDataPointHeight(pair.Value)).ToArray();
|
|
ShowGraph();
|
|
|
|
if (IsHovered)
|
|
graph.UpdateBallPosition(lastHoverPosition);
|
|
return;
|
|
}
|
|
|
|
HideGraph();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Function used to convert <see cref="Data"/> point to it's Y-axis position on the graph.
|
|
/// </summary>
|
|
/// <param name="value">Value to convert.</param>
|
|
protected abstract float GetDataPointHeight(TValue value);
|
|
|
|
protected virtual void ShowGraph() => graph.FadeIn(FADE_DURATION, Easing.Out);
|
|
protected virtual void HideGraph() => graph.FadeOut(FADE_DURATION, Easing.Out);
|
|
|
|
public ITooltip<UserGraphTooltipContent> GetCustomTooltip() => new UserGraphTooltip();
|
|
|
|
public UserGraphTooltipContent TooltipContent
|
|
{
|
|
get
|
|
{
|
|
if (data == null || hoveredIndex == -1)
|
|
return default;
|
|
|
|
var (key, value) = data[hoveredIndex];
|
|
return GetTooltipContent(key, value);
|
|
}
|
|
}
|
|
|
|
protected abstract UserGraphTooltipContent GetTooltipContent(TKey key, TValue value);
|
|
|
|
protected class UserLineGraph : LineGraph
|
|
{
|
|
private readonly CircularContainer movingBall;
|
|
private readonly Container bar;
|
|
private readonly Box ballBg;
|
|
private readonly Box line;
|
|
|
|
public Action<int> OnBallMove;
|
|
|
|
public UserLineGraph()
|
|
{
|
|
Add(bar = new Container
|
|
{
|
|
Origin = Anchor.TopCentre,
|
|
RelativeSizeAxes = Axes.Y,
|
|
AutoSizeAxes = Axes.X,
|
|
Alpha = 0,
|
|
RelativePositionAxes = Axes.Both,
|
|
Children = new Drawable[]
|
|
{
|
|
line = new Box
|
|
{
|
|
Anchor = Anchor.Centre,
|
|
Origin = Anchor.Centre,
|
|
RelativeSizeAxes = Axes.Y,
|
|
Width = 2,
|
|
},
|
|
movingBall = new CircularContainer
|
|
{
|
|
Anchor = Anchor.TopCentre,
|
|
Origin = Anchor.Centre,
|
|
Size = new Vector2(20),
|
|
Masking = true,
|
|
BorderThickness = 4,
|
|
RelativePositionAxes = Axes.Y,
|
|
Child = ballBg = new Box { RelativeSizeAxes = Axes.Both }
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
[BackgroundDependencyLoader]
|
|
private void load(OverlayColourProvider colourProvider, OsuColour colours)
|
|
{
|
|
ballBg.Colour = colourProvider.Background5;
|
|
movingBall.BorderColour = line.Colour = colours.Yellow;
|
|
}
|
|
|
|
public void UpdateBallPosition(float mouseXPosition)
|
|
{
|
|
const int duration = 200;
|
|
int index = calculateIndex(mouseXPosition);
|
|
Vector2 position = calculateBallPosition(index);
|
|
movingBall.MoveToY(position.Y, duration, Easing.OutQuint);
|
|
bar.MoveToX(position.X, duration, Easing.OutQuint);
|
|
OnBallMove.Invoke(index);
|
|
}
|
|
|
|
public void ShowBar() => bar.FadeIn(FADE_DURATION);
|
|
|
|
public void HideBar() => bar.FadeOut(FADE_DURATION);
|
|
|
|
private int calculateIndex(float mouseXPosition) => (int)Math.Clamp(MathF.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1)), 0, DefaultValueCount - 1);
|
|
|
|
private Vector2 calculateBallPosition(int index)
|
|
{
|
|
float y = GetYPosition(Values.ElementAt(index));
|
|
return new Vector2(index / (float)(DefaultValueCount - 1), y);
|
|
}
|
|
}
|
|
|
|
private class UserGraphTooltip : VisibilityContainer, ITooltip<UserGraphTooltipContent>
|
|
{
|
|
protected readonly OsuSpriteText Label, Counter, BottomText;
|
|
private readonly Box background;
|
|
|
|
public UserGraphTooltip()
|
|
{
|
|
AutoSizeAxes = Axes.Both;
|
|
Masking = true;
|
|
CornerRadius = 10;
|
|
|
|
Children = new Drawable[]
|
|
{
|
|
background = new Box
|
|
{
|
|
RelativeSizeAxes = Axes.Both
|
|
},
|
|
new FillFlowContainer
|
|
{
|
|
AutoSizeAxes = Axes.Both,
|
|
Direction = FillDirection.Vertical,
|
|
Padding = new MarginPadding(10),
|
|
Children = new Drawable[]
|
|
{
|
|
new FillFlowContainer
|
|
{
|
|
AutoSizeAxes = Axes.Both,
|
|
Direction = FillDirection.Horizontal,
|
|
Spacing = new Vector2(3, 0),
|
|
Children = new Drawable[]
|
|
{
|
|
Label = new OsuSpriteText
|
|
{
|
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
|
},
|
|
Counter = new OsuSpriteText
|
|
{
|
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
|
Anchor = Anchor.BottomLeft,
|
|
Origin = Anchor.BottomLeft,
|
|
}
|
|
}
|
|
},
|
|
BottomText = new OsuSpriteText
|
|
{
|
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
[BackgroundDependencyLoader]
|
|
private void load(OsuColour colours)
|
|
{
|
|
// Temporary colour since it's currently impossible to change it without bugs (see https://github.com/ppy/osu-framework/issues/3231)
|
|
// If above is fixed, this should use OverlayColourProvider
|
|
background.Colour = colours.Gray1;
|
|
}
|
|
|
|
public void SetContent(UserGraphTooltipContent content)
|
|
{
|
|
Label.Text = content.Name;
|
|
Counter.Text = content.Count;
|
|
BottomText.Text = content.Time;
|
|
}
|
|
|
|
private bool instantMove = true;
|
|
|
|
public void Move(Vector2 pos)
|
|
{
|
|
if (instantMove)
|
|
{
|
|
Position = pos;
|
|
instantMove = false;
|
|
}
|
|
else
|
|
this.MoveTo(pos, 200, Easing.OutQuint);
|
|
}
|
|
|
|
protected override void PopIn()
|
|
{
|
|
instantMove |= !IsPresent;
|
|
this.FadeIn(200, Easing.OutQuint);
|
|
}
|
|
|
|
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
|
|
}
|
|
}
|
|
|
|
public class UserGraphTooltipContent
|
|
{
|
|
// todo: change to init-only on C# 9
|
|
public LocalisableString Name { get; set; }
|
|
public LocalisableString Count { get; set; }
|
|
public LocalisableString Time { get; set; }
|
|
}
|
|
}
|