mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 09:32:55 +08:00
Merge branch 'master' into sh-xh-grading-2
This commit is contained in:
commit
3b03ca802a
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
@ -7,6 +7,7 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
@ -7,6 +7,7 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
@ -6,6 +6,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
@ -6,6 +6,7 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
@ -43,22 +43,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
|
|
||||||
private readonly InputResampler resampler = new InputResampler();
|
private readonly InputResampler resampler = new InputResampler();
|
||||||
|
|
||||||
protected override DrawNode CreateDrawNode() => new TrailDrawNode();
|
protected override DrawNode CreateDrawNode() => new TrailDrawNode(this);
|
||||||
|
|
||||||
protected override void ApplyDrawNode(DrawNode node)
|
|
||||||
{
|
|
||||||
base.ApplyDrawNode(node);
|
|
||||||
|
|
||||||
TrailDrawNode tNode = (TrailDrawNode)node;
|
|
||||||
tNode.Shader = shader;
|
|
||||||
tNode.Texture = texture;
|
|
||||||
tNode.Size = size;
|
|
||||||
tNode.Time = time;
|
|
||||||
|
|
||||||
for (int i = 0; i < parts.Length; ++i)
|
|
||||||
if (parts[i].InvalidationID > tNode.Parts[i].InvalidationID)
|
|
||||||
tNode.Parts[i] = parts[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
public CursorTrail()
|
public CursorTrail()
|
||||||
{
|
{
|
||||||
@ -167,33 +152,52 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
|
|
||||||
private class TrailDrawNode : DrawNode
|
private class TrailDrawNode : DrawNode
|
||||||
{
|
{
|
||||||
public IShader Shader;
|
protected new CursorTrail Source => (CursorTrail)base.Source;
|
||||||
public Texture Texture;
|
|
||||||
|
|
||||||
public float Time;
|
private IShader shader;
|
||||||
|
private Texture texture;
|
||||||
|
|
||||||
public readonly TrailPart[] Parts = new TrailPart[max_sprites];
|
private float time;
|
||||||
public Vector2 Size;
|
|
||||||
|
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
||||||
|
private Vector2 size;
|
||||||
|
|
||||||
private readonly VertexBuffer<TexturedTrailVertex> vertexBuffer = new QuadVertexBuffer<TexturedTrailVertex>(max_sprites, BufferUsageHint.DynamicDraw);
|
private readonly VertexBuffer<TexturedTrailVertex> vertexBuffer = new QuadVertexBuffer<TexturedTrailVertex>(max_sprites, BufferUsageHint.DynamicDraw);
|
||||||
|
|
||||||
public TrailDrawNode()
|
public TrailDrawNode(CursorTrail source)
|
||||||
|
: base(source)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < max_sprites; i++)
|
for (int i = 0; i < max_sprites; i++)
|
||||||
{
|
{
|
||||||
Parts[i].InvalidationID = 0;
|
parts[i].InvalidationID = 0;
|
||||||
Parts[i].WasUpdated = false;
|
parts[i].WasUpdated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ApplyState()
|
||||||
|
{
|
||||||
|
base.ApplyState();
|
||||||
|
|
||||||
|
shader = Source.shader;
|
||||||
|
texture = Source.texture;
|
||||||
|
size = Source.size;
|
||||||
|
time = Source.time;
|
||||||
|
|
||||||
|
for (int i = 0; i < Source.parts.Length; ++i)
|
||||||
|
{
|
||||||
|
if (Source.parts[i].InvalidationID > parts[i].InvalidationID)
|
||||||
|
parts[i] = Source.parts[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
||||||
{
|
{
|
||||||
Shader.GetUniform<float>("g_FadeClock").UpdateValue(ref Time);
|
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
||||||
|
|
||||||
int updateStart = -1, updateEnd = 0;
|
int updateStart = -1, updateEnd = 0;
|
||||||
for (int i = 0; i < Parts.Length; ++i)
|
for (int i = 0; i < parts.Length; ++i)
|
||||||
{
|
{
|
||||||
if (Parts[i].WasUpdated)
|
if (parts[i].WasUpdated)
|
||||||
{
|
{
|
||||||
if (updateStart == -1)
|
if (updateStart == -1)
|
||||||
updateStart = i;
|
updateStart = i;
|
||||||
@ -202,22 +206,22 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
int start = i * 4;
|
int start = i * 4;
|
||||||
int end = start;
|
int end = start;
|
||||||
|
|
||||||
Vector2 pos = Parts[i].Position;
|
Vector2 pos = parts[i].Position;
|
||||||
float time = Parts[i].Time;
|
float localTime = parts[i].Time;
|
||||||
|
|
||||||
Texture.DrawQuad(
|
texture.DrawQuad(
|
||||||
new Quad(pos.X - Size.X / 2, pos.Y - Size.Y / 2, Size.X, Size.Y),
|
new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
|
||||||
DrawColourInfo.Colour,
|
DrawColourInfo.Colour,
|
||||||
null,
|
null,
|
||||||
v => vertexBuffer.Vertices[end++] = new TexturedTrailVertex
|
v => vertexBuffer.Vertices[end++] = new TexturedTrailVertex
|
||||||
{
|
{
|
||||||
Position = v.Position,
|
Position = v.Position,
|
||||||
TexturePosition = v.TexturePosition,
|
TexturePosition = v.TexturePosition,
|
||||||
Time = time + 1,
|
Time = localTime + 1,
|
||||||
Colour = v.Colour,
|
Colour = v.Colour,
|
||||||
});
|
});
|
||||||
|
|
||||||
Parts[i].WasUpdated = false;
|
parts[i].WasUpdated = false;
|
||||||
}
|
}
|
||||||
else if (updateStart != -1)
|
else if (updateStart != -1)
|
||||||
{
|
{
|
||||||
@ -232,12 +236,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
|
|
||||||
base.Draw(vertexAction);
|
base.Draw(vertexAction);
|
||||||
|
|
||||||
Shader.Bind();
|
shader.Bind();
|
||||||
|
|
||||||
Texture.TextureGL.Bind();
|
texture.TextureGL.Bind();
|
||||||
vertexBuffer.Draw();
|
vertexBuffer.Draw();
|
||||||
|
|
||||||
Shader.Unbind();
|
shader.Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -6,6 +6,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
@ -61,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var first = (OsuHitObject)Objects.First();
|
var first = (OsuHitObject)Objects.First();
|
||||||
return first.StartTime - first.TimePreempt;
|
return first.StartTime - Math.Max(2000, first.TimePreempt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Game.Graphics.Backgrounds;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,7 @@ using osuTK;
|
|||||||
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.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Audio;
|
using osu.Framework.Graphics.Audio;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Editor
|
namespace osu.Game.Tests.Visual.Editor
|
||||||
@ -16,35 +17,38 @@ namespace osu.Game.Tests.Visual.Editor
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestCaseWaveform : OsuTestCase
|
public class TestCaseWaveform : OsuTestCase
|
||||||
{
|
{
|
||||||
|
private WorkingBeatmap waveformBeatmap;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Beatmap.Value = new WaveformTestBeatmap();
|
waveformBeatmap = new WaveformTestBeatmap();
|
||||||
|
}
|
||||||
|
|
||||||
FillFlowContainer flow;
|
[TestCase(1f)]
|
||||||
Child = flow = new FillFlowContainer
|
[TestCase(1f / 2)]
|
||||||
|
[TestCase(1f / 4)]
|
||||||
|
[TestCase(1f / 8)]
|
||||||
|
[TestCase(1f / 16)]
|
||||||
|
[TestCase(0f)]
|
||||||
|
public void TestResolution(float resolution)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
TestWaveformGraph graph = null;
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Spacing = new Vector2(0, 10),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 1; i <= 16; i *= 2)
|
AddStep("add graph", () =>
|
||||||
{
|
{
|
||||||
var newDisplay = new WaveformGraph
|
Child = new Container
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Resolution = 1f / i,
|
|
||||||
Waveform = Beatmap.Value.Waveform,
|
|
||||||
};
|
|
||||||
|
|
||||||
flow.Add(new Container
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = 100,
|
Height = 100,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
newDisplay,
|
graph = new TestWaveformGraph
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Resolution = resolution,
|
||||||
|
Waveform = waveformBeatmap.Waveform,
|
||||||
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -62,13 +66,42 @@ namespace osu.Game.Tests.Visual.Editor
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = $"Resolution: {1f / i:0.00}"
|
Text = $"Resolution: {resolution:0.00}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => graph.ResampledWaveform != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDefaultBeatmap()
|
||||||
|
{
|
||||||
|
TestWaveformGraph graph = null;
|
||||||
|
|
||||||
|
AddStep("add graph", () =>
|
||||||
|
{
|
||||||
|
Child = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 100,
|
||||||
|
Child = graph = new TestWaveformGraph
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Waveform = new DummyWorkingBeatmap().Waveform,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => graph.ResampledWaveform != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestWaveformGraph : WaveformGraph
|
||||||
|
{
|
||||||
|
public new Waveform ResampledWaveform => base.ResampledWaveform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
// 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 NUnit.Framework;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Overlays.Profile.Header;
|
|
||||||
using osu.Game.Users;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Online
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class TestCaseBadgeContainer : OsuTestCase
|
|
||||||
{
|
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BadgeContainer) };
|
|
||||||
|
|
||||||
public TestCaseBadgeContainer()
|
|
||||||
{
|
|
||||||
BadgeContainer badgeContainer;
|
|
||||||
|
|
||||||
Child = badgeContainer = new BadgeContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both
|
|
||||||
};
|
|
||||||
|
|
||||||
AddStep("Show 1 badge", () => badgeContainer.ShowBadges(new[]
|
|
||||||
{
|
|
||||||
new Badge
|
|
||||||
{
|
|
||||||
AwardedAt = DateTimeOffset.Now,
|
|
||||||
Description = "Appreciates compasses",
|
|
||||||
ImageUrl = "https://assets.ppy.sh/profile-badges/mg2018-1star.png",
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
AddStep("Show 2 badges", () => badgeContainer.ShowBadges(new[]
|
|
||||||
{
|
|
||||||
new Badge
|
|
||||||
{
|
|
||||||
AwardedAt = DateTimeOffset.Now,
|
|
||||||
Description = "Contributed to osu!lazer testing",
|
|
||||||
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.png",
|
|
||||||
},
|
|
||||||
new Badge
|
|
||||||
{
|
|
||||||
AwardedAt = DateTimeOffset.Now,
|
|
||||||
Description = "Appreciates compasses",
|
|
||||||
ImageUrl = "https://assets.ppy.sh/profile-badges/mg2018-1star.png",
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
AddStep("Show many badges", () => badgeContainer.ShowBadges(Enumerable.Range(1, 20).Select(i => new Badge
|
|
||||||
{
|
|
||||||
AwardedAt = DateTimeOffset.Now,
|
|
||||||
Description = $"Contributed to osu!lazer testing {i} times",
|
|
||||||
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg",
|
|
||||||
}).ToArray()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays.Profile.Header;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Country = new Country { FlagName = @"AU" },
|
Country = new Country { FlagName = @"AU" },
|
||||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
||||||
IsSupporter = true,
|
IsSupporter = true,
|
||||||
|
SupportLevel = 3,
|
||||||
}) { Width = 300 },
|
}) { Width = 300 },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -6,11 +6,12 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Profile;
|
using osu.Game.Overlays.Profile;
|
||||||
using osu.Game.Overlays.Profile.Header;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Online
|
namespace osu.Game.Tests.Visual.Online
|
||||||
@ -19,7 +20,9 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
public class TestCaseUserProfile : OsuTestCase
|
public class TestCaseUserProfile : OsuTestCase
|
||||||
{
|
{
|
||||||
private readonly TestUserProfileOverlay profile;
|
private readonly TestUserProfileOverlay profile;
|
||||||
private IAPIProvider api;
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
@ -27,25 +30,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
typeof(UserProfileOverlay),
|
typeof(UserProfileOverlay),
|
||||||
typeof(RankGraph),
|
typeof(RankGraph),
|
||||||
typeof(LineGraph),
|
typeof(LineGraph),
|
||||||
typeof(BadgeContainer)
|
typeof(SectionsContainer<>),
|
||||||
|
typeof(SupporterIcon)
|
||||||
};
|
};
|
||||||
|
|
||||||
public TestCaseUserProfile()
|
public static readonly User TEST_USER = new User
|
||||||
{
|
|
||||||
Add(profile = new TestUserProfileOverlay());
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(IAPIProvider api)
|
|
||||||
{
|
|
||||||
this.api = api;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
AddStep("Show offline dummy", () => profile.ShowUser(new User
|
|
||||||
{
|
{
|
||||||
Username = @"Somebody",
|
Username = @"Somebody",
|
||||||
Id = 1,
|
Id = 1,
|
||||||
@ -58,6 +47,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
Ranks = new UserStatistics.UserRanks { Global = 2148, Country = 1 },
|
Ranks = new UserStatistics.UserRanks { Global = 2148, Country = 1 },
|
||||||
PP = 4567.89m,
|
PP = 4567.89m,
|
||||||
|
Level = new UserStatistics.LevelInfo
|
||||||
|
{
|
||||||
|
Current = 727,
|
||||||
|
Progress = 69,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
RankHistory = new User.RankHistoryData
|
RankHistory = new User.RankHistoryData
|
||||||
{
|
{
|
||||||
@ -72,10 +66,22 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Description = "Outstanding help by being a voluntary test subject.",
|
Description = "Outstanding help by being a voluntary test subject.",
|
||||||
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg"
|
ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}, false));
|
Title = "osu!volunteer",
|
||||||
|
Colour = "ff0000",
|
||||||
|
Achievements = new User.UserAchievement[0],
|
||||||
|
};
|
||||||
|
|
||||||
checkSupporterTag(false);
|
public TestCaseUserProfile()
|
||||||
|
{
|
||||||
|
Add(profile = new TestUserProfileOverlay());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
AddStep("Show offline dummy", () => profile.ShowUser(TEST_USER, false));
|
||||||
|
|
||||||
AddStep("Show null dummy", () => profile.ShowUser(new User
|
AddStep("Show null dummy", () => profile.ShowUser(new User
|
||||||
{
|
{
|
||||||
@ -92,8 +98,6 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
|
||||||
}, api.IsLoggedIn));
|
}, api.IsLoggedIn));
|
||||||
|
|
||||||
checkSupporterTag(true);
|
|
||||||
|
|
||||||
AddStep("Show flyte", () => profile.ShowUser(new User
|
AddStep("Show flyte", () => profile.ShowUser(new User
|
||||||
{
|
{
|
||||||
Username = @"flyte",
|
Username = @"flyte",
|
||||||
@ -106,15 +110,6 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep("Show without reload", profile.Show);
|
AddStep("Show without reload", profile.Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSupporterTag(bool isSupporter)
|
|
||||||
{
|
|
||||||
AddUntilStep("wait for load", () => profile.Header.User != null);
|
|
||||||
if (isSupporter)
|
|
||||||
AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1);
|
|
||||||
else
|
|
||||||
AddAssert("no supporter", () => profile.Header.SupporterTag.Alpha == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestUserProfileOverlay : UserProfileOverlay
|
private class TestUserProfileOverlay : UserProfileOverlay
|
||||||
{
|
{
|
||||||
public new ProfileHeader Header => base.Header;
|
public new ProfileHeader Header => base.Header;
|
||||||
|
81
osu.Game.Tests/Visual/Online/TestCaseUserProfileHeader.cs
Normal file
81
osu.Game.Tests/Visual/Online/TestCaseUserProfileHeader.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Overlays.Profile;
|
||||||
|
using osu.Game.Overlays.Profile.Header;
|
||||||
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public class TestCaseUserProfileHeader : OsuTestCase
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(ProfileHeader),
|
||||||
|
typeof(RankGraph),
|
||||||
|
typeof(LineGraph),
|
||||||
|
typeof(ProfileHeaderTabControl),
|
||||||
|
typeof(CentreHeaderContainer),
|
||||||
|
typeof(BottomHeaderContainer),
|
||||||
|
typeof(DetailHeaderContainer),
|
||||||
|
typeof(ProfileHeaderButton)
|
||||||
|
};
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
private readonly ProfileHeader header;
|
||||||
|
|
||||||
|
public TestCaseUserProfileHeader()
|
||||||
|
{
|
||||||
|
header = new ProfileHeader();
|
||||||
|
Add(header);
|
||||||
|
|
||||||
|
AddStep("Show offline dummy", () => header.User.Value = TestCaseUserProfile.TEST_USER);
|
||||||
|
|
||||||
|
AddStep("Show null dummy", () => header.User.Value = new User
|
||||||
|
{
|
||||||
|
Username = "Null"
|
||||||
|
});
|
||||||
|
|
||||||
|
addOnlineStep("Show ppy", new User
|
||||||
|
{
|
||||||
|
Username = @"peppy",
|
||||||
|
Id = 2,
|
||||||
|
IsSupporter = true,
|
||||||
|
Country = new Country { FullName = @"Australia", FlagName = @"AU" },
|
||||||
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
|
||||||
|
});
|
||||||
|
|
||||||
|
addOnlineStep("Show flyte", new User
|
||||||
|
{
|
||||||
|
Username = @"flyte",
|
||||||
|
Id = 3103765,
|
||||||
|
Country = new Country { FullName = @"Japan", FlagName = @"JP" },
|
||||||
|
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOnlineStep(string name, User fallback)
|
||||||
|
{
|
||||||
|
AddStep(name, () =>
|
||||||
|
{
|
||||||
|
if (api.IsLoggedIn)
|
||||||
|
{
|
||||||
|
var request = new GetUserRequest(fallback.Id);
|
||||||
|
request.Success += user => header.User.Value = user;
|
||||||
|
api.Queue(request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
header.User.Value = fallback;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
@ -178,64 +178,68 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
/// <returns>The colour.</returns>
|
/// <returns>The colour.</returns>
|
||||||
protected virtual Color4 CreateTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1);
|
protected virtual Color4 CreateTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1);
|
||||||
|
|
||||||
protected override DrawNode CreateDrawNode() => new TrianglesDrawNode();
|
protected override DrawNode CreateDrawNode() => new TrianglesDrawNode(this);
|
||||||
|
|
||||||
protected override void ApplyDrawNode(DrawNode node)
|
|
||||||
{
|
|
||||||
base.ApplyDrawNode(node);
|
|
||||||
|
|
||||||
var trianglesNode = (TrianglesDrawNode)node;
|
|
||||||
|
|
||||||
trianglesNode.Shader = shader;
|
|
||||||
trianglesNode.Texture = texture;
|
|
||||||
trianglesNode.Size = DrawSize;
|
|
||||||
|
|
||||||
trianglesNode.Parts.Clear();
|
|
||||||
trianglesNode.Parts.AddRange(parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TrianglesDrawNode : DrawNode
|
private class TrianglesDrawNode : DrawNode
|
||||||
{
|
{
|
||||||
public IShader Shader;
|
protected new Triangles Source => (Triangles)base.Source;
|
||||||
public Texture Texture;
|
|
||||||
|
|
||||||
public readonly List<TriangleParticle> Parts = new List<TriangleParticle>();
|
private IShader shader;
|
||||||
public Vector2 Size;
|
private Texture texture;
|
||||||
|
|
||||||
|
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
|
||||||
|
private Vector2 size;
|
||||||
|
|
||||||
private readonly LinearBatch<TexturedVertex2D> vertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles);
|
private readonly LinearBatch<TexturedVertex2D> vertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles);
|
||||||
|
|
||||||
|
public TrianglesDrawNode(Triangles source)
|
||||||
|
: base(source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ApplyState()
|
||||||
|
{
|
||||||
|
base.ApplyState();
|
||||||
|
|
||||||
|
shader = Source.shader;
|
||||||
|
texture = Source.texture;
|
||||||
|
size = Source.DrawSize;
|
||||||
|
|
||||||
|
parts.Clear();
|
||||||
|
parts.AddRange(Source.parts);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
||||||
{
|
{
|
||||||
base.Draw(vertexAction);
|
base.Draw(vertexAction);
|
||||||
|
|
||||||
Shader.Bind();
|
shader.Bind();
|
||||||
Texture.TextureGL.Bind();
|
texture.TextureGL.Bind();
|
||||||
|
|
||||||
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
|
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
|
||||||
|
|
||||||
foreach (TriangleParticle particle in Parts)
|
foreach (TriangleParticle particle in parts)
|
||||||
{
|
{
|
||||||
var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f);
|
var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f);
|
||||||
var size = new Vector2(2 * offset.X, offset.Y);
|
|
||||||
|
|
||||||
var triangle = new Triangle(
|
var triangle = new Triangle(
|
||||||
Vector2Extensions.Transform(particle.Position * Size, DrawInfo.Matrix),
|
Vector2Extensions.Transform(particle.Position * size, DrawInfo.Matrix),
|
||||||
Vector2Extensions.Transform(particle.Position * Size + offset, DrawInfo.Matrix),
|
Vector2Extensions.Transform(particle.Position * size + offset, DrawInfo.Matrix),
|
||||||
Vector2Extensions.Transform(particle.Position * Size + new Vector2(-offset.X, offset.Y), DrawInfo.Matrix)
|
Vector2Extensions.Transform(particle.Position * size + new Vector2(-offset.X, offset.Y), DrawInfo.Matrix)
|
||||||
);
|
);
|
||||||
|
|
||||||
ColourInfo colourInfo = DrawColourInfo.Colour;
|
ColourInfo colourInfo = DrawColourInfo.Colour;
|
||||||
colourInfo.ApplyChild(particle.Colour);
|
colourInfo.ApplyChild(particle.Colour);
|
||||||
|
|
||||||
Texture.DrawTriangle(
|
texture.DrawTriangle(
|
||||||
triangle,
|
triangle,
|
||||||
colourInfo,
|
colourInfo,
|
||||||
null,
|
null,
|
||||||
vertexBatch.AddAction,
|
vertexBatch.AddAction,
|
||||||
Vector2.Divide(localInflationAmount, size));
|
Vector2.Divide(localInflationAmount, new Vector2(2 * offset.X, offset.Y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader.Unbind();
|
shader.Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
|
@ -35,6 +35,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
|
if (HoverColour == default)
|
||||||
HoverColour = colours.Yellow;
|
HoverColour = colours.Yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +142,17 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
public void ScrollToTop() => scrollContainer.ScrollTo(0);
|
public void ScrollToTop() => scrollContainer.ScrollTo(0);
|
||||||
|
|
||||||
|
public override void InvalidateFromChild(Invalidation invalidation, Drawable source = null)
|
||||||
|
{
|
||||||
|
base.InvalidateFromChild(invalidation, source);
|
||||||
|
|
||||||
|
if ((invalidation & Invalidation.DrawSize) != 0)
|
||||||
|
{
|
||||||
|
if (source == ExpandableHeader) //We need to recalculate the positions if the ExpandableHeader changed its size
|
||||||
|
lastKnownScroll = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private float lastKnownScroll;
|
private float lastKnownScroll;
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
|
@ -92,5 +92,15 @@ namespace osu.Game.Graphics
|
|||||||
public readonly Color4 ChatBlue = FromHex(@"17292e");
|
public readonly Color4 ChatBlue = FromHex(@"17292e");
|
||||||
|
|
||||||
public readonly Color4 ContextMenuGray = FromHex(@"223034");
|
public readonly Color4 ContextMenuGray = FromHex(@"223034");
|
||||||
|
|
||||||
|
public readonly Color4 CommunityUserGreenLight = FromHex(@"deff87");
|
||||||
|
public readonly Color4 CommunityUserGreen = FromHex(@"05ffa2");
|
||||||
|
public readonly Color4 CommunityUserGreenDark = FromHex(@"a6cc00");
|
||||||
|
public readonly Color4 CommunityUserGrayGreenLighter = FromHex(@"9ebab1");
|
||||||
|
public readonly Color4 CommunityUserGrayGreenLight = FromHex(@"77998e");
|
||||||
|
public readonly Color4 CommunityUserGrayGreen = FromHex(@"4e7466");
|
||||||
|
public readonly Color4 CommunityUserGrayGreenDark = FromHex(@"33413c");
|
||||||
|
public readonly Color4 CommunityUserGrayGreenDarker = FromHex(@"2c3532");
|
||||||
|
public readonly Color4 CommunityUserGrayGreenDarkest = FromHex(@"1e2422");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Graphics.Backgrounds;
|
using osu.Game.Graphics.Backgrounds;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using osuTK;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Lines;
|
using osu.Framework.Graphics.Lines;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
@ -63,6 +64,12 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Color4 LineColour
|
||||||
|
{
|
||||||
|
get => maskingContainer.Colour;
|
||||||
|
set => maskingContainer.Colour = value;
|
||||||
|
}
|
||||||
|
|
||||||
public LineGraph()
|
public LineGraph()
|
||||||
{
|
{
|
||||||
Add(maskingContainer = new Container<Path>
|
Add(maskingContainer = new Container<Path>
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
@ -5,7 +5,7 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
private readonly SpriteIcon iconSprite;
|
private readonly SpriteIcon iconSprite;
|
||||||
private readonly OsuSpriteText titleText, pageText;
|
private readonly OsuSpriteText titleText, pageText;
|
||||||
|
public const float ICON_WIDTH = icon_size + icon_spacing;
|
||||||
|
private const float icon_size = 25, icon_spacing = 10;
|
||||||
|
|
||||||
protected IconUsage Icon
|
protected IconUsage Icon
|
||||||
{
|
{
|
||||||
@ -48,12 +50,12 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Spacing = new Vector2(10, 0),
|
Spacing = new Vector2(icon_spacing, 0),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
iconSprite = new SpriteIcon
|
iconSprite = new SpriteIcon
|
||||||
{
|
{
|
||||||
Size = new Vector2(25),
|
Size = new Vector2(icon_size),
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Graphics.Containers;
|
|||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using System;
|
using System;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
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;
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -11,6 +11,7 @@ using osuTK;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
|
@ -6,6 +6,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
@ -7,6 +7,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
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.Graphics.UserInterface;
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
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;
|
||||||
|
@ -8,6 +8,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
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;
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Extensions;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
@ -19,6 +19,7 @@ using osu.Framework.Graphics.Textures;
|
|||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using System;
|
using System;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
@ -8,6 +8,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -10,6 +10,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Graphics;
|
|||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Transforms;
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
// 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 osu.Game.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Components
|
|
||||||
{
|
|
||||||
public class DrawableJoinDate : DrawableDate
|
|
||||||
{
|
|
||||||
public DrawableJoinDate(DateTimeOffset date)
|
|
||||||
: base(date)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string Format() => Text = Date.ToUniversalTime().Year < 2008 ? "Here since the beginning" : $"{Date:MMMM yyyy}";
|
|
||||||
|
|
||||||
public override string TooltipText => $"{Date:MMMM d, yyyy}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
// 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.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Components
|
|
||||||
{
|
|
||||||
public class GradeBadge : Container
|
|
||||||
{
|
|
||||||
private const float width = 50;
|
|
||||||
private readonly string grade;
|
|
||||||
private readonly Sprite badge;
|
|
||||||
private readonly SpriteText numberText;
|
|
||||||
|
|
||||||
public int DisplayCount
|
|
||||||
{
|
|
||||||
set => numberText.Text = value.ToString(@"#,0");
|
|
||||||
}
|
|
||||||
|
|
||||||
public GradeBadge(string grade)
|
|
||||||
{
|
|
||||||
this.grade = grade;
|
|
||||||
Width = width;
|
|
||||||
Height = 41;
|
|
||||||
Add(badge = new Sprite
|
|
||||||
{
|
|
||||||
Width = width,
|
|
||||||
Height = 26
|
|
||||||
});
|
|
||||||
Add(numberText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(TextureStore textures)
|
|
||||||
{
|
|
||||||
badge.Texture = textures.Get($"Grades/{grade}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,197 +0,0 @@
|
|||||||
// 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 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.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Users;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Header
|
|
||||||
{
|
|
||||||
public class BadgeContainer : Container
|
|
||||||
{
|
|
||||||
private static readonly Vector2 badge_size = new Vector2(86, 40);
|
|
||||||
private static readonly MarginPadding outer_padding = new MarginPadding(3);
|
|
||||||
|
|
||||||
private OsuSpriteText badgeCountText;
|
|
||||||
private FillFlowContainer badgeFlowContainer;
|
|
||||||
private FillFlowContainer outerBadgeContainer;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
Child = new Container
|
|
||||||
{
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 4,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = colours.Gray3
|
|
||||||
},
|
|
||||||
outerBadgeContainer = new OuterBadgeContainer(onOuterHover, onOuterHoverLost)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Padding = outer_padding,
|
|
||||||
Width = DrawableBadge.DRAWABLE_BADGE_SIZE.X + outer_padding.TotalHorizontal,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
badgeCountText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Alpha = 0,
|
|
||||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular)
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Child = badgeFlowContainer = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Scheduler.AddDelayed(rotateBadges, 3000, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rotateBadges()
|
|
||||||
{
|
|
||||||
if (outerBadgeContainer.IsHovered) return;
|
|
||||||
|
|
||||||
visibleBadge = (visibleBadge + 1) % badgeCount;
|
|
||||||
|
|
||||||
badgeFlowContainer.MoveToX(-DrawableBadge.DRAWABLE_BADGE_SIZE.X * visibleBadge, 500, Easing.InOutQuad);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int visibleBadge;
|
|
||||||
private int badgeCount;
|
|
||||||
|
|
||||||
public void ShowBadges(Badge[] badges)
|
|
||||||
{
|
|
||||||
if (badges == null || badges.Length == 0)
|
|
||||||
{
|
|
||||||
Hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
badgeCount = badges.Length;
|
|
||||||
|
|
||||||
badgeCountText.FadeTo(badgeCount > 1 ? 1 : 0);
|
|
||||||
badgeCountText.Text = $"{badges.Length} badges";
|
|
||||||
|
|
||||||
Show();
|
|
||||||
visibleBadge = 0;
|
|
||||||
|
|
||||||
badgeFlowContainer.Clear();
|
|
||||||
for (var index = 0; index < badges.Length; index++)
|
|
||||||
{
|
|
||||||
int displayIndex = index;
|
|
||||||
LoadComponentAsync(new DrawableBadge(badges[index])
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
}, asyncBadge =>
|
|
||||||
{
|
|
||||||
badgeFlowContainer.Add(asyncBadge);
|
|
||||||
|
|
||||||
// load in stable order regardless of async load order.
|
|
||||||
badgeFlowContainer.SetLayoutPosition(asyncBadge, displayIndex);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOuterHover()
|
|
||||||
{
|
|
||||||
badgeFlowContainer.ClearTransforms();
|
|
||||||
badgeFlowContainer.X = 0;
|
|
||||||
badgeFlowContainer.Direction = FillDirection.Full;
|
|
||||||
outerBadgeContainer.AutoSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
badgeFlowContainer.MaximumSize = new Vector2(ChildSize.X, float.MaxValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOuterHoverLost()
|
|
||||||
{
|
|
||||||
badgeFlowContainer.X = -DrawableBadge.DRAWABLE_BADGE_SIZE.X * visibleBadge;
|
|
||||||
badgeFlowContainer.Direction = FillDirection.Horizontal;
|
|
||||||
outerBadgeContainer.AutoSizeAxes = Axes.Y;
|
|
||||||
outerBadgeContainer.Width = DrawableBadge.DRAWABLE_BADGE_SIZE.X + outer_padding.TotalHorizontal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OuterBadgeContainer : FillFlowContainer
|
|
||||||
{
|
|
||||||
private readonly Action hoverAction;
|
|
||||||
private readonly Action hoverLostAction;
|
|
||||||
|
|
||||||
public OuterBadgeContainer(Action hoverAction, Action hoverLostAction)
|
|
||||||
{
|
|
||||||
this.hoverAction = hoverAction;
|
|
||||||
this.hoverLostAction = hoverLostAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
|
||||||
{
|
|
||||||
hoverAction();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e) => hoverLostAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DrawableBadge : Container, IHasTooltip
|
|
||||||
{
|
|
||||||
public static readonly Vector2 DRAWABLE_BADGE_SIZE = badge_size + outer_padding.Total;
|
|
||||||
|
|
||||||
private readonly Badge badge;
|
|
||||||
|
|
||||||
public DrawableBadge(Badge badge)
|
|
||||||
{
|
|
||||||
this.badge = badge;
|
|
||||||
Padding = outer_padding;
|
|
||||||
Size = DRAWABLE_BADGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(LargeTextureStore textures)
|
|
||||||
{
|
|
||||||
Child = new Sprite
|
|
||||||
{
|
|
||||||
FillMode = FillMode.Fit,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Texture = textures.Get(badge.ImageUrl),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
Child.FadeInFromZero(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TooltipText => badge.Description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
153
osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs
Normal file
153
osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
|
{
|
||||||
|
public class BottomHeaderContainer : CompositeDrawable
|
||||||
|
{
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
private LinkFlowContainer topLinkContainer;
|
||||||
|
private LinkFlowContainer bottomLinkContainer;
|
||||||
|
|
||||||
|
private Color4 iconColour;
|
||||||
|
|
||||||
|
public BottomHeaderContainer()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
iconColour = colours.CommunityUserGrayGreenLighter;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.CommunityUserGrayGreenDarker,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
||||||
|
Spacing = new Vector2(0, 10),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
topLinkContainer = new LinkFlowContainer(text => text.Font = text.Font.With(size: 12))
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
},
|
||||||
|
bottomLinkContainer = new LinkFlowContainer(text => text.Font = text.Font.With(size: 12))
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateDisplay(user.NewValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay(User user)
|
||||||
|
{
|
||||||
|
topLinkContainer.Clear();
|
||||||
|
bottomLinkContainer.Clear();
|
||||||
|
|
||||||
|
if (user == null) return;
|
||||||
|
|
||||||
|
if (user.JoinDate.ToUniversalTime().Year < 2008)
|
||||||
|
topLinkContainer.AddText("Here since the beginning");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topLinkContainer.AddText("Joined ");
|
||||||
|
topLinkContainer.AddText(new DrawableDate(user.JoinDate), embolden);
|
||||||
|
}
|
||||||
|
|
||||||
|
addSpacer(topLinkContainer);
|
||||||
|
|
||||||
|
if (user.PlayStyles?.Length > 0)
|
||||||
|
{
|
||||||
|
topLinkContainer.AddText("Plays with ");
|
||||||
|
topLinkContainer.AddText(string.Join(", ", user.PlayStyles.Select(style => style.GetDescription())), embolden);
|
||||||
|
|
||||||
|
addSpacer(topLinkContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.LastVisit.HasValue)
|
||||||
|
{
|
||||||
|
topLinkContainer.AddText("Last seen ");
|
||||||
|
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value), embolden);
|
||||||
|
|
||||||
|
addSpacer(topLinkContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
topLinkContainer.AddText("Contributed ");
|
||||||
|
topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: embolden);
|
||||||
|
|
||||||
|
string websiteWithoutProtcol = user.Website;
|
||||||
|
if (!string.IsNullOrEmpty(websiteWithoutProtcol))
|
||||||
|
{
|
||||||
|
if (Uri.TryCreate(websiteWithoutProtcol, UriKind.Absolute, out var uri))
|
||||||
|
{
|
||||||
|
websiteWithoutProtcol = uri.Host + uri.PathAndQuery + uri.Fragment;
|
||||||
|
websiteWithoutProtcol = websiteWithoutProtcol.TrimEnd('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
|
||||||
|
tryAddInfo(OsuIcon.Heart, user.Interests);
|
||||||
|
tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
|
||||||
|
bottomLinkContainer.NewLine();
|
||||||
|
if (!string.IsNullOrEmpty(user.Twitter))
|
||||||
|
tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
||||||
|
tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
||||||
|
tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
|
||||||
|
tryAddInfo(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
|
||||||
|
tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtcol, user.Website);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
|
||||||
|
|
||||||
|
private void tryAddInfo(IconUsage icon, string content, string link = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(content)) return;
|
||||||
|
|
||||||
|
bottomLinkContainer.AddIcon(icon, text =>
|
||||||
|
{
|
||||||
|
text.Font = text.Font.With(size: 10);
|
||||||
|
text.Colour = iconColour;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (link != null)
|
||||||
|
bottomLinkContainer.AddLink(" " + content, link, creationParameters: embolden);
|
||||||
|
else
|
||||||
|
bottomLinkContainer.AddText(" " + content, embolden);
|
||||||
|
|
||||||
|
addSpacer(bottomLinkContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void embolden(SpriteText text) => text.Font = text.Font.With(weight: FontWeight.Bold);
|
||||||
|
}
|
||||||
|
}
|
150
osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs
Normal file
150
osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// 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.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
|
{
|
||||||
|
public class CentreHeaderContainer : CompositeDrawable
|
||||||
|
{
|
||||||
|
public readonly BindableBool DetailsVisible = new BindableBool(true);
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
private OverlinedInfoContainer hiddenDetailGlobal;
|
||||||
|
private OverlinedInfoContainer hiddenDetailCountry;
|
||||||
|
|
||||||
|
public CentreHeaderContainer()
|
||||||
|
{
|
||||||
|
Height = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, TextureStore textures)
|
||||||
|
{
|
||||||
|
Container<Drawable> hiddenDetailContainer;
|
||||||
|
Container<Drawable> expandedDetailContainer;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.CommunityUserGrayGreenDark
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Padding = new MarginPadding { Vertical = 10 },
|
||||||
|
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new AddFriendButton
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
new MessageUserButton
|
||||||
|
{
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Vertical = 10 },
|
||||||
|
Width = UserProfileOverlay.CONTENT_X_MARGIN,
|
||||||
|
Child = new ExpandDetailsButton
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
DetailsVisible = { BindTarget = DetailsVisible }
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new LevelBadge
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Size = new Vector2(40),
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
expandedDetailContainer = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Width = 200,
|
||||||
|
Height = 6,
|
||||||
|
Margin = new MarginPadding { Right = 50 },
|
||||||
|
Child = new LevelProgressBar
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
User = { BindTarget = User }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hiddenDetailContainer = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Width = 200,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Alpha = 0,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
Margin = new MarginPadding { Right = 50 },
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
hiddenDetailGlobal = new OverlinedInfoContainer
|
||||||
|
{
|
||||||
|
Title = "Global Ranking",
|
||||||
|
LineColour = colours.Yellow
|
||||||
|
},
|
||||||
|
hiddenDetailCountry = new OverlinedInfoContainer
|
||||||
|
{
|
||||||
|
Title = "Country Ranking",
|
||||||
|
LineColour = colours.Yellow
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DetailsVisible.BindValueChanged(visible =>
|
||||||
|
{
|
||||||
|
hiddenDetailContainer.Alpha = visible.NewValue ? 1 : 0;
|
||||||
|
expandedDetailContainer.Alpha = visible.NewValue ? 0 : 1;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateDisplay(user.NewValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay(User user)
|
||||||
|
{
|
||||||
|
hiddenDetailGlobal.Content = user?.Statistics?.Ranks.Global?.ToString("#,##0") ?? "-";
|
||||||
|
hiddenDetailCountry.Content = user?.Statistics?.Ranks.Country?.ToString("#,##0") ?? "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
// 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.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class AddFriendButton : ProfileHeaderButton
|
||||||
|
{
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
public override string TooltipText => "friends";
|
||||||
|
|
||||||
|
private OsuSpriteText followerText;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Padding = new MarginPadding { Right = 10 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Icon = FontAwesome.Solid.User,
|
||||||
|
FillMode = FillMode.Fit,
|
||||||
|
Size = new Vector2(50, 14)
|
||||||
|
},
|
||||||
|
followerText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.Bold)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateFollowers(user.NewValue), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFollowers(User user) => followerText.Text = user?.FollowerCount?.Length > 0 ? user.FollowerCount[0].ToString("#,##0") : "0";
|
||||||
|
}
|
||||||
|
}
|
46
osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs
Normal file
46
osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class DrawableBadge : CompositeDrawable, IHasTooltip
|
||||||
|
{
|
||||||
|
public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40);
|
||||||
|
|
||||||
|
private readonly Badge badge;
|
||||||
|
|
||||||
|
public DrawableBadge(Badge badge)
|
||||||
|
{
|
||||||
|
this.badge = badge;
|
||||||
|
Size = DRAWABLE_BADGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(LargeTextureStore textures)
|
||||||
|
{
|
||||||
|
InternalChild = new Sprite
|
||||||
|
{
|
||||||
|
FillMode = FillMode.Fit,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Texture = textures.Get(badge.ImageUrl),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
InternalChild.FadeInFromZero(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TooltipText => badge.Description;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
// 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.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class ExpandDetailsButton : ProfileHeaderButton
|
||||||
|
{
|
||||||
|
public readonly BindableBool DetailsVisible = new BindableBool();
|
||||||
|
|
||||||
|
public override string TooltipText => DetailsVisible.Value ? "collapse" : "expand";
|
||||||
|
|
||||||
|
private SpriteIcon icon;
|
||||||
|
|
||||||
|
public ExpandDetailsButton()
|
||||||
|
{
|
||||||
|
Action = () => DetailsVisible.Toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
IdleColour = colours.CommunityUserGrayGreen;
|
||||||
|
HoverColour = colours.CommunityUserGrayGreen.Darken(0.2f);
|
||||||
|
|
||||||
|
Child = icon = new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(20, 12)
|
||||||
|
};
|
||||||
|
|
||||||
|
DetailsVisible.BindValueChanged(visible => updateState(visible.NewValue), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState(bool detailsVisible) => icon.Icon = detailsVisible ? FontAwesome.Solid.ChevronUp : FontAwesome.Solid.ChevronDown;
|
||||||
|
}
|
||||||
|
}
|
57
osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs
Normal file
57
osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// 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.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class LevelBadge : CompositeDrawable, IHasTooltip
|
||||||
|
{
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
public string TooltipText { get; }
|
||||||
|
|
||||||
|
private OsuSpriteText levelText;
|
||||||
|
|
||||||
|
public LevelBadge()
|
||||||
|
{
|
||||||
|
TooltipText = "Level";
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, TextureStore textures)
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Texture = textures.Get("Profile/levelbadge"),
|
||||||
|
Colour = colours.Yellow,
|
||||||
|
},
|
||||||
|
levelText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Font = OsuFont.GetFont(size: 20)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateLevel(user.NewValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLevel(User user)
|
||||||
|
{
|
||||||
|
levelText.Text = user?.Statistics?.Level.Current.ToString() ?? "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
// 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.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class LevelProgressBar : CompositeDrawable, IHasTooltip
|
||||||
|
{
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
public string TooltipText { get; }
|
||||||
|
|
||||||
|
private Bar levelProgressBar;
|
||||||
|
private OsuSpriteText levelProgressText;
|
||||||
|
|
||||||
|
public LevelProgressBar()
|
||||||
|
{
|
||||||
|
TooltipText = "Progress to next level";
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Child = levelProgressBar = new Bar
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BackgroundColour = Color4.Black,
|
||||||
|
Direction = BarDirection.LeftToRight,
|
||||||
|
AccentColour = colours.Yellow
|
||||||
|
}
|
||||||
|
},
|
||||||
|
levelProgressText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateProgress(user.NewValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProgress(User user)
|
||||||
|
{
|
||||||
|
levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0;
|
||||||
|
levelProgressText.Text = user?.Statistics?.Level.Progress.ToString("0'%'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
// 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.Sprites;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class MessageUserButton : ProfileHeaderButton
|
||||||
|
{
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
public override string TooltipText => "send message";
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private ChannelManager channelManager { get; set; }
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private UserProfileOverlay userOverlay { get; set; }
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private ChatOverlay chatOverlay { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider apiProvider { get; set; }
|
||||||
|
|
||||||
|
public MessageUserButton()
|
||||||
|
{
|
||||||
|
Content.Alpha = 0;
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
Child = new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Icon = FontAwesome.Solid.Envelope,
|
||||||
|
FillMode = FillMode.Fit,
|
||||||
|
Size = new Vector2(50, 14)
|
||||||
|
};
|
||||||
|
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
if (!Content.IsPresent) return;
|
||||||
|
|
||||||
|
channelManager?.OpenPrivateChannel(User.Value);
|
||||||
|
userOverlay?.Hide();
|
||||||
|
chatOverlay?.Show();
|
||||||
|
};
|
||||||
|
|
||||||
|
User.ValueChanged += e => Content.Alpha = !e.NewValue.PMFriendsOnly && apiProvider.LocalUser.Value.Id != e.NewValue.Id ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class OverlinedInfoContainer : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly Circle line;
|
||||||
|
private readonly OsuSpriteText title;
|
||||||
|
private readonly OsuSpriteText content;
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
set => title.Text = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Content
|
||||||
|
{
|
||||||
|
set => content.Text = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color4 LineColour
|
||||||
|
{
|
||||||
|
set => line.Colour = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverlinedInfoContainer(bool big = false, int minimumWidth = 60)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
line = new Circle
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 4,
|
||||||
|
},
|
||||||
|
title = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: big ? 14 : 12, weight: FontWeight.Bold)
|
||||||
|
},
|
||||||
|
content = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: big ? 40 : 18, weight: FontWeight.Light)
|
||||||
|
},
|
||||||
|
new Container //Add a minimum size to the FillFlowContainer
|
||||||
|
{
|
||||||
|
Width = minimumWidth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
// 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.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class OverlinedTotalPlayTime : CompositeDrawable, IHasTooltip
|
||||||
|
{
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
public string TooltipText { get; set; }
|
||||||
|
|
||||||
|
private OverlinedInfoContainer info;
|
||||||
|
|
||||||
|
public OverlinedTotalPlayTime()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
TooltipText = "0 hours";
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
InternalChild = info = new OverlinedInfoContainer
|
||||||
|
{
|
||||||
|
Title = "Total Play Time",
|
||||||
|
LineColour = colours.Yellow,
|
||||||
|
};
|
||||||
|
|
||||||
|
User.BindValueChanged(updateTime, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTime(ValueChangedEvent<User> user)
|
||||||
|
{
|
||||||
|
TooltipText = (user.NewValue?.Statistics?.PlayTime ?? 0) / 3600 + " hours";
|
||||||
|
info.Content = formatTime(user.NewValue?.Statistics?.PlayTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string formatTime(int? secondsNull)
|
||||||
|
{
|
||||||
|
if (secondsNull == null) return "0h 0m";
|
||||||
|
|
||||||
|
int seconds = secondsNull.Value;
|
||||||
|
string time = "";
|
||||||
|
|
||||||
|
int days = seconds / 86400;
|
||||||
|
seconds -= days * 86400;
|
||||||
|
if (days > 0)
|
||||||
|
time += days + "d ";
|
||||||
|
|
||||||
|
int hours = seconds / 3600;
|
||||||
|
seconds -= hours * 3600;
|
||||||
|
time += hours + "h ";
|
||||||
|
|
||||||
|
int minutes = seconds / 60;
|
||||||
|
time += minutes + "m";
|
||||||
|
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public abstract class ProfileHeaderButton : OsuHoverContainer, IHasTooltip
|
||||||
|
{
|
||||||
|
public abstract string TooltipText { get; }
|
||||||
|
|
||||||
|
private readonly Box background;
|
||||||
|
private readonly Container content;
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
protected override IEnumerable<Drawable> EffectTargets => new[] { background };
|
||||||
|
|
||||||
|
protected ProfileHeaderButton()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
IdleColour = Color4.Black;
|
||||||
|
HoverColour = OsuColour.Gray(0.1f);
|
||||||
|
|
||||||
|
base.Content.Add(new CircularContainer
|
||||||
|
{
|
||||||
|
Masking = true,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
content = new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Horizontal = 10 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
280
osu.Game/Overlays/Profile/Header/Components/RankGraph.cs
Normal file
280
osu.Game/Overlays/Profile/Header/Components/RankGraph.cs
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
// 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 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.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class RankGraph : Container, IHasCustomTooltip
|
||||||
|
{
|
||||||
|
private const float secondary_textsize = 13;
|
||||||
|
private const float padding = 10;
|
||||||
|
private const float fade_duration = 150;
|
||||||
|
private const int ranked_days = 88;
|
||||||
|
|
||||||
|
private readonly RankChartLineGraph graph;
|
||||||
|
private readonly OsuSpriteText placeholder;
|
||||||
|
|
||||||
|
private KeyValuePair<int, int>[] ranks;
|
||||||
|
private int dayIndex;
|
||||||
|
public Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
public RankGraph()
|
||||||
|
{
|
||||||
|
Padding = new MarginPadding { Vertical = padding };
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
placeholder = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Text = "No recent plays",
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular)
|
||||||
|
},
|
||||||
|
graph = new RankChartLineGraph
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Y = -secondary_textsize,
|
||||||
|
Alpha = 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
graph.OnBallMove += i => dayIndex = i;
|
||||||
|
|
||||||
|
User.ValueChanged += userChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
graph.LineColour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void userChanged(ValueChangedEvent<User> e)
|
||||||
|
{
|
||||||
|
placeholder.FadeIn(fade_duration, Easing.Out);
|
||||||
|
|
||||||
|
if (e.NewValue?.Statistics?.Ranks.Global == null)
|
||||||
|
{
|
||||||
|
graph.FadeOut(fade_duration, Easing.Out);
|
||||||
|
ranks = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] userRanks = e.NewValue.RankHistory?.Data ?? new[] { e.NewValue.Statistics.Ranks.Global.Value };
|
||||||
|
ranks = userRanks.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray();
|
||||||
|
|
||||||
|
if (ranks.Length > 1)
|
||||||
|
{
|
||||||
|
placeholder.FadeOut(fade_duration, Easing.Out);
|
||||||
|
|
||||||
|
graph.DefaultValueCount = ranks.Length;
|
||||||
|
graph.Values = ranks.Select(x => -(float)Math.Log(x.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.FadeTo(ranks.Length > 1 ? 1 : 0, fade_duration, Easing.Out);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
if (ranks?.Length > 1)
|
||||||
|
{
|
||||||
|
graph.UpdateBallPosition(e.MousePosition.X);
|
||||||
|
graph.ShowBall();
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
|
{
|
||||||
|
if (ranks?.Length > 1)
|
||||||
|
graph.UpdateBallPosition(e.MousePosition.X);
|
||||||
|
|
||||||
|
return base.OnMouseMove(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
if (ranks?.Length > 1)
|
||||||
|
{
|
||||||
|
graph.HideBall();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RankChartLineGraph : LineGraph
|
||||||
|
{
|
||||||
|
private readonly CircularContainer movingBall;
|
||||||
|
private readonly Box ballBg;
|
||||||
|
private readonly Box movingBar;
|
||||||
|
|
||||||
|
public Action<int> OnBallMove;
|
||||||
|
|
||||||
|
public RankChartLineGraph()
|
||||||
|
{
|
||||||
|
Add(movingBar = new Box
|
||||||
|
{
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 1.5f,
|
||||||
|
Alpha = 0,
|
||||||
|
RelativePositionAxes = Axes.Both,
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(movingBall = new CircularContainer
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(18),
|
||||||
|
Alpha = 0,
|
||||||
|
Masking = true,
|
||||||
|
BorderThickness = 4,
|
||||||
|
RelativePositionAxes = Axes.Both,
|
||||||
|
Child = ballBg = new Box { RelativeSizeAxes = Axes.Both }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
ballBg.Colour = colours.CommunityUserGrayGreenDarkest;
|
||||||
|
movingBall.BorderColour = colours.Yellow;
|
||||||
|
movingBar.Colour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateBallPosition(float mouseXPosition)
|
||||||
|
{
|
||||||
|
int index = calculateIndex(mouseXPosition);
|
||||||
|
movingBall.Position = calculateBallPosition(index);
|
||||||
|
movingBar.X = movingBall.X;
|
||||||
|
OnBallMove.Invoke(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowBall()
|
||||||
|
{
|
||||||
|
movingBall.FadeIn(fade_duration);
|
||||||
|
movingBar.FadeIn(fade_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HideBall()
|
||||||
|
{
|
||||||
|
movingBall.FadeOut(fade_duration);
|
||||||
|
movingBar.FadeOut(fade_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1));
|
||||||
|
|
||||||
|
private Vector2 calculateBallPosition(int index)
|
||||||
|
{
|
||||||
|
float y = GetYPosition(Values.ElementAt(index));
|
||||||
|
return new Vector2(index / (float)(DefaultValueCount - 1), y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TooltipText => User.Value?.Statistics?.Ranks.Global == null ? "" : $"{ranks[dayIndex].Value:#,##0}|{ranked_days - ranks[dayIndex].Key + 1}";
|
||||||
|
|
||||||
|
public ITooltip GetCustomTooltip() => new RankGraphTooltip();
|
||||||
|
|
||||||
|
public class RankGraphTooltip : VisibilityContainer, ITooltip
|
||||||
|
{
|
||||||
|
private readonly OsuSpriteText globalRankingText, timeText;
|
||||||
|
private readonly Box background;
|
||||||
|
|
||||||
|
public string TooltipText { get; set; }
|
||||||
|
|
||||||
|
public RankGraphTooltip()
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||||
|
Text = "Global Ranking "
|
||||||
|
},
|
||||||
|
globalRankingText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
timeText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
background.Colour = colours.CommunityUserGrayGreenDarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Refresh()
|
||||||
|
{
|
||||||
|
var info = TooltipText.Split('|');
|
||||||
|
globalRankingText.Text = info[0];
|
||||||
|
timeText.Text = info[1] == "0" ? "now" : $"{info[1]} days ago";
|
||||||
|
}
|
||||||
|
|
||||||
|
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() => this.FadeIn(200, Easing.OutQuint);
|
||||||
|
|
||||||
|
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs
Normal file
85
osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
|
{
|
||||||
|
public class SupporterIcon : CompositeDrawable, IHasTooltip
|
||||||
|
{
|
||||||
|
private readonly Box background;
|
||||||
|
private readonly FillFlowContainer iconContainer;
|
||||||
|
private readonly CircularContainer content;
|
||||||
|
|
||||||
|
public string TooltipText => "osu!supporter";
|
||||||
|
|
||||||
|
public int SupportLevel
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
int count = MathHelper.Clamp(value, 0, 3);
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
content.Hide();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content.Show();
|
||||||
|
iconContainer.Clear();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
iconContainer.Add(new SpriteIcon
|
||||||
|
{
|
||||||
|
Width = 12,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Icon = FontAwesome.Solid.Heart,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
iconContainer.Padding = new MarginPadding { Horizontal = DrawHeight / 2 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupporterIcon()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
InternalChild = content = new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Masking = true,
|
||||||
|
Alpha = 0,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box { RelativeSizeAxes = Axes.Both },
|
||||||
|
iconContainer = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Height = 0.6f,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
background.Colour = colours.Pink;
|
||||||
|
iconContainer.Colour = colours.CommunityUserGrayGreenDark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
202
osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs
Normal file
202
osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// 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.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
|
{
|
||||||
|
public class DetailHeaderContainer : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly Dictionary<ScoreRank, ScoreRankInfo> scoreRankInfos = new Dictionary<ScoreRank, ScoreRankInfo>();
|
||||||
|
private OverlinedInfoContainer medalInfo;
|
||||||
|
private OverlinedInfoContainer ppInfo;
|
||||||
|
private OverlinedInfoContainer detailGlobalRank;
|
||||||
|
private OverlinedInfoContainer detailCountryRank;
|
||||||
|
private RankGraph rankGraph;
|
||||||
|
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
User.ValueChanged += e => updateDisplay(e.NewValue);
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.CommunityUserGrayGreenDarkest,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(0, 20),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OverlinedTotalPlayTime
|
||||||
|
{
|
||||||
|
User = { BindTarget = User }
|
||||||
|
},
|
||||||
|
medalInfo = new OverlinedInfoContainer
|
||||||
|
{
|
||||||
|
Title = "Medals",
|
||||||
|
LineColour = colours.GreenLight,
|
||||||
|
},
|
||||||
|
ppInfo = new OverlinedInfoContainer
|
||||||
|
{
|
||||||
|
Title = "pp",
|
||||||
|
LineColour = colours.Red,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH),
|
||||||
|
scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X),
|
||||||
|
scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH),
|
||||||
|
scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S),
|
||||||
|
scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Right = 130 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rankGraph = new RankGraph
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Width = 130,
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Padding = new MarginPadding { Horizontal = 10 },
|
||||||
|
Spacing = new Vector2(0, 20),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
detailGlobalRank = new OverlinedInfoContainer(true, 110)
|
||||||
|
{
|
||||||
|
Title = "Global Ranking",
|
||||||
|
LineColour = colours.Yellow,
|
||||||
|
},
|
||||||
|
detailCountryRank = new OverlinedInfoContainer(false, 110)
|
||||||
|
{
|
||||||
|
Title = "Country Ranking",
|
||||||
|
LineColour = colours.Yellow,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay(User user)
|
||||||
|
{
|
||||||
|
medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0";
|
||||||
|
ppInfo.Content = user?.Statistics?.PP?.ToString("#,##0") ?? "0";
|
||||||
|
|
||||||
|
foreach (var scoreRankInfo in scoreRankInfos)
|
||||||
|
scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0;
|
||||||
|
|
||||||
|
detailGlobalRank.Content = user?.Statistics?.Ranks.Global?.ToString("#,##0") ?? "-";
|
||||||
|
detailCountryRank.Content = user?.Statistics?.Ranks.Country?.ToString("#,##0") ?? "-";
|
||||||
|
|
||||||
|
rankGraph.User.Value = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ScoreRankInfo : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly ScoreRank rank;
|
||||||
|
private readonly Sprite rankSprite;
|
||||||
|
private readonly OsuSpriteText rankCount;
|
||||||
|
|
||||||
|
public int RankCount
|
||||||
|
{
|
||||||
|
set => rankCount.Text = value.ToString("#,##0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScoreRankInfo(ScoreRank rank)
|
||||||
|
{
|
||||||
|
this.rank = rank;
|
||||||
|
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Width = 56,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
rankSprite = new Sprite
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
FillMode = FillMode.Fit
|
||||||
|
},
|
||||||
|
rankCount = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(TextureStore textures)
|
||||||
|
{
|
||||||
|
rankSprite.Texture = textures.Get($"Grades/{rank.GetDescription()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs
Normal file
92
osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// 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.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
|
{
|
||||||
|
public class MedalHeaderContainer : CompositeDrawable
|
||||||
|
{
|
||||||
|
private FillFlowContainer badgeFlowContainer;
|
||||||
|
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
Alpha = 0;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
User.ValueChanged += e => updateDisplay(e.NewValue);
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.CommunityUserGrayGreenDarkest,
|
||||||
|
},
|
||||||
|
new Container //artificial shadow
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 3,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = new ColourInfo
|
||||||
|
{
|
||||||
|
TopLeft = Color4.Black.Opacity(0.2f),
|
||||||
|
TopRight = Color4.Black.Opacity(0.2f),
|
||||||
|
BottomLeft = Color4.Black.Opacity(0),
|
||||||
|
BottomRight = Color4.Black.Opacity(0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
badgeFlowContainer = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Full,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Margin = new MarginPadding { Top = 5 },
|
||||||
|
Spacing = new Vector2(10, 10),
|
||||||
|
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplay(User user)
|
||||||
|
{
|
||||||
|
var badges = user.Badges;
|
||||||
|
badgeFlowContainer.Clear();
|
||||||
|
if (badges?.Length > 0)
|
||||||
|
{
|
||||||
|
Show();
|
||||||
|
for (var index = 0; index < badges.Length; index++)
|
||||||
|
{
|
||||||
|
int displayIndex = index;
|
||||||
|
LoadComponentAsync(new DrawableBadge(badges[index]), asyncBadge =>
|
||||||
|
{
|
||||||
|
badgeFlowContainer.Add(asyncBadge);
|
||||||
|
|
||||||
|
// load in stable order regardless of async load order.
|
||||||
|
badgeFlowContainer.SetLayoutPosition(asyncBadge, displayIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
155
osu.Game/Overlays/Profile/Header/ProfileHeaderTabControl.cs
Normal file
155
osu.Game/Overlays/Profile/Header/ProfileHeaderTabControl.cs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
|
{
|
||||||
|
public class ProfileHeaderTabControl : TabControl<string>
|
||||||
|
{
|
||||||
|
private readonly Box bar;
|
||||||
|
|
||||||
|
private Color4 accentColour;
|
||||||
|
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get => accentColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (accentColour == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
accentColour = value;
|
||||||
|
bar.Colour = value;
|
||||||
|
|
||||||
|
foreach (TabItem<string> tabItem in TabContainer)
|
||||||
|
{
|
||||||
|
((ProfileHeaderTabItem)tabItem).AccentColour = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public new MarginPadding Padding
|
||||||
|
{
|
||||||
|
get => TabContainer.Padding;
|
||||||
|
set => TabContainer.Padding = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileHeaderTabControl()
|
||||||
|
{
|
||||||
|
TabContainer.Masking = false;
|
||||||
|
TabContainer.Spacing = new Vector2(15, 0);
|
||||||
|
|
||||||
|
AddInternal(bar = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 2,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.CentreLeft
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Dropdown<string> CreateDropdown() => null;
|
||||||
|
|
||||||
|
protected override TabItem<string> CreateTabItem(string value) => new ProfileHeaderTabItem(value)
|
||||||
|
{
|
||||||
|
AccentColour = AccentColour
|
||||||
|
};
|
||||||
|
|
||||||
|
private class ProfileHeaderTabItem : TabItem<string>
|
||||||
|
{
|
||||||
|
private readonly OsuSpriteText text;
|
||||||
|
private readonly Drawable bar;
|
||||||
|
|
||||||
|
private Color4 accentColour;
|
||||||
|
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get => accentColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (accentColour == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
accentColour = value;
|
||||||
|
bar.Colour = value;
|
||||||
|
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileHeaderTabItem(string value)
|
||||||
|
: base(value)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding { Bottom = 10 },
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Text = value,
|
||||||
|
Font = OsuFont.GetFont()
|
||||||
|
},
|
||||||
|
bar = new Circle
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 0,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
},
|
||||||
|
new HoverClickSounds()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
base.OnHover(e);
|
||||||
|
|
||||||
|
updateState();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnActivated() => updateState();
|
||||||
|
|
||||||
|
protected override void OnDeactivated() => updateState();
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
if (Active.Value || IsHovered)
|
||||||
|
{
|
||||||
|
text.FadeColour(Color4.White, 120, Easing.InQuad);
|
||||||
|
bar.ResizeHeightTo(7.5f, 120, Easing.InQuad);
|
||||||
|
|
||||||
|
if (Active.Value)
|
||||||
|
text.Font = text.Font.With(weight: FontWeight.Bold);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text.FadeColour(AccentColour, 120, Easing.InQuad);
|
||||||
|
bar.ResizeHeightTo(0, 120, Easing.InQuad);
|
||||||
|
text.Font = text.Font.With(weight: FontWeight.Medium);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,216 +0,0 @@
|
|||||||
// 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 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.Sprites;
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Users;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Header
|
|
||||||
{
|
|
||||||
public class RankGraph : Container
|
|
||||||
{
|
|
||||||
private const float primary_textsize = 25;
|
|
||||||
private const float secondary_textsize = 13;
|
|
||||||
private const float padding = 10;
|
|
||||||
private const float fade_duration = 150;
|
|
||||||
private const int ranked_days = 88;
|
|
||||||
|
|
||||||
private readonly SpriteText rankText, performanceText, relativeText;
|
|
||||||
private readonly RankChartLineGraph graph;
|
|
||||||
private readonly OsuSpriteText placeholder;
|
|
||||||
|
|
||||||
private KeyValuePair<int, int>[] ranks;
|
|
||||||
public Bindable<User> User = new Bindable<User>();
|
|
||||||
|
|
||||||
public RankGraph()
|
|
||||||
{
|
|
||||||
Padding = new MarginPadding { Vertical = padding };
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
placeholder = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Text = "No recent plays",
|
|
||||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Regular, italics: true)
|
|
||||||
},
|
|
||||||
rankText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Font = OsuFont.GetFont(size: primary_textsize, weight: FontWeight.Regular, italics: true),
|
|
||||||
},
|
|
||||||
relativeText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Font = OsuFont.GetFont(size: secondary_textsize, weight: FontWeight.Regular, italics: true),
|
|
||||||
Y = 25,
|
|
||||||
},
|
|
||||||
performanceText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Font = OsuFont.GetFont(size: secondary_textsize, weight: FontWeight.Regular, italics: true)
|
|
||||||
},
|
|
||||||
graph = new RankChartLineGraph
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 60,
|
|
||||||
Y = -secondary_textsize,
|
|
||||||
Alpha = 0,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
graph.OnBallMove += showHistoryRankTexts;
|
|
||||||
|
|
||||||
User.ValueChanged += userChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
graph.Colour = colours.Yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void userChanged(ValueChangedEvent<User> e)
|
|
||||||
{
|
|
||||||
placeholder.FadeIn(fade_duration, Easing.Out);
|
|
||||||
|
|
||||||
if (e.NewValue?.Statistics?.Ranks.Global == null)
|
|
||||||
{
|
|
||||||
rankText.Text = string.Empty;
|
|
||||||
performanceText.Text = string.Empty;
|
|
||||||
relativeText.Text = string.Empty;
|
|
||||||
graph.FadeOut(fade_duration, Easing.Out);
|
|
||||||
ranks = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] userRanks = e.NewValue.RankHistory?.Data ?? new[] { e.NewValue.Statistics.Ranks.Global.Value };
|
|
||||||
ranks = userRanks.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray();
|
|
||||||
|
|
||||||
if (ranks.Length > 1)
|
|
||||||
{
|
|
||||||
placeholder.FadeOut(fade_duration, Easing.Out);
|
|
||||||
|
|
||||||
graph.DefaultValueCount = ranks.Length;
|
|
||||||
graph.Values = ranks.Select(x => -(float)Math.Log(x.Value));
|
|
||||||
graph.SetStaticBallPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
graph.FadeTo(ranks.Length > 1 ? 1 : 0, fade_duration, Easing.Out);
|
|
||||||
|
|
||||||
updateRankTexts();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateRankTexts()
|
|
||||||
{
|
|
||||||
var user = User.Value;
|
|
||||||
|
|
||||||
performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty;
|
|
||||||
rankText.Text = user.Statistics.Ranks.Global > 0 ? $"#{user.Statistics.Ranks.Global:#,0}" : "no rank";
|
|
||||||
relativeText.Text = user.Country != null && user.Statistics.Ranks.Country > 0 ? $"{user.Country.FullName} #{user.Statistics.Ranks.Country:#,0}" : "no rank";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showHistoryRankTexts(int dayIndex)
|
|
||||||
{
|
|
||||||
rankText.Text = $"#{ranks[dayIndex].Value:#,0}";
|
|
||||||
relativeText.Text = dayIndex + 1 == ranks.Length ? "Now" : $"{ranked_days - ranks[dayIndex].Key} days ago";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
|
||||||
{
|
|
||||||
if (ranks?.Length > 1)
|
|
||||||
{
|
|
||||||
graph.UpdateBallPosition(e.MousePosition.X);
|
|
||||||
graph.ShowBall();
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnHover(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
|
||||||
{
|
|
||||||
if (ranks?.Length > 1)
|
|
||||||
graph.UpdateBallPosition(e.MousePosition.X);
|
|
||||||
|
|
||||||
return base.OnMouseMove(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e)
|
|
||||||
{
|
|
||||||
if (ranks?.Length > 1)
|
|
||||||
{
|
|
||||||
graph.HideBall();
|
|
||||||
updateRankTexts();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnHoverLost(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RankChartLineGraph : LineGraph
|
|
||||||
{
|
|
||||||
private readonly CircularContainer staticBall;
|
|
||||||
private readonly CircularContainer movingBall;
|
|
||||||
|
|
||||||
public Action<int> OnBallMove;
|
|
||||||
|
|
||||||
public RankChartLineGraph()
|
|
||||||
{
|
|
||||||
Add(staticBall = new CircularContainer
|
|
||||||
{
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Size = new Vector2(8),
|
|
||||||
Masking = true,
|
|
||||||
RelativePositionAxes = Axes.Both,
|
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
|
||||||
});
|
|
||||||
Add(movingBall = new CircularContainer
|
|
||||||
{
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Size = new Vector2(8),
|
|
||||||
Alpha = 0,
|
|
||||||
Masking = true,
|
|
||||||
RelativePositionAxes = Axes.Both,
|
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStaticBallPosition() => staticBall.Position = new Vector2(1, GetYPosition(Values.Last()));
|
|
||||||
|
|
||||||
public void UpdateBallPosition(float mouseXPosition)
|
|
||||||
{
|
|
||||||
int index = calculateIndex(mouseXPosition);
|
|
||||||
movingBall.Position = calculateBallPosition(index);
|
|
||||||
OnBallMove.Invoke(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowBall() => movingBall.FadeIn(fade_duration);
|
|
||||||
|
|
||||||
public void HideBall() => movingBall.FadeOut(fade_duration);
|
|
||||||
|
|
||||||
private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1));
|
|
||||||
|
|
||||||
private Vector2 calculateBallPosition(int index)
|
|
||||||
{
|
|
||||||
float y = GetYPosition(Values.ElementAt(index));
|
|
||||||
return new Vector2(index / (float)(DefaultValueCount - 1), y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
// 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.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Cursor;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Backgrounds;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Header
|
|
||||||
{
|
|
||||||
public class SupporterIcon : CircularContainer, IHasTooltip
|
|
||||||
{
|
|
||||||
private readonly Box background;
|
|
||||||
|
|
||||||
public string TooltipText => "osu!supporter";
|
|
||||||
|
|
||||||
public SupporterIcon()
|
|
||||||
{
|
|
||||||
Masking = true;
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box { RelativeSizeAxes = Axes.Both },
|
|
||||||
new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Scale = new Vector2(0.8f),
|
|
||||||
Masking = true,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
background = new Box { RelativeSizeAxes = Axes.Both },
|
|
||||||
new Triangles
|
|
||||||
{
|
|
||||||
TriangleScale = 0.2f,
|
|
||||||
ColourLight = OsuColour.FromHex(@"ff7db7"),
|
|
||||||
ColourDark = OsuColour.FromHex(@"de5b95"),
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Velocity = 0.3f,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new SpriteIcon
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Icon = FontAwesome.Solid.Heart,
|
|
||||||
Scale = new Vector2(0.45f),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
background.Colour = colours.Pink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
201
osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs
Normal file
201
osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Header
|
||||||
|
{
|
||||||
|
public class TopHeaderContainer : CompositeDrawable
|
||||||
|
{
|
||||||
|
private const float avatar_size = 110;
|
||||||
|
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
private SupporterIcon supporterTag;
|
||||||
|
private UpdateableAvatar avatar;
|
||||||
|
private OsuSpriteText usernameText;
|
||||||
|
private ExternalLinkButton openUserExternally;
|
||||||
|
private OsuSpriteText titleText;
|
||||||
|
private DrawableFlag userFlag;
|
||||||
|
private OsuSpriteText userCountryText;
|
||||||
|
private FillFlowContainer userStats;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
Height = 150;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.CommunityUserGrayGreenDarker,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
|
||||||
|
Height = avatar_size,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
avatar = new UpdateableAvatar
|
||||||
|
{
|
||||||
|
Size = new Vector2(avatar_size),
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = avatar_size * 0.25f,
|
||||||
|
OpenOnClick = { Value = false },
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Padding = new MarginPadding { Left = 10 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
usernameText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular)
|
||||||
|
},
|
||||||
|
openUserExternally = new ExternalLinkButton
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding { Left = 5 },
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
titleText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Regular)
|
||||||
|
},
|
||||||
|
supporterTag = new SupporterIcon
|
||||||
|
{
|
||||||
|
Height = 20,
|
||||||
|
Margin = new MarginPadding { Top = 5 }
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 1.5f,
|
||||||
|
Margin = new MarginPadding { Top = 10 },
|
||||||
|
Colour = colours.CommunityUserGrayGreenLighter,
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Margin = new MarginPadding { Top = 5 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
userFlag = new DrawableFlag
|
||||||
|
{
|
||||||
|
Size = new Vector2(30, 20)
|
||||||
|
},
|
||||||
|
userCountryText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 17.5f, weight: FontWeight.Regular),
|
||||||
|
Margin = new MarginPadding { Left = 40 },
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Colour = colours.CommunityUserGrayGreenLighter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
userStats = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Width = 300,
|
||||||
|
Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN },
|
||||||
|
Padding = new MarginPadding { Vertical = 15 },
|
||||||
|
Spacing = new Vector2(0, 2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
User.BindValueChanged(user => updateUser(user.NewValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUser(User user)
|
||||||
|
{
|
||||||
|
avatar.User = user;
|
||||||
|
usernameText.Text = user?.Username ?? string.Empty;
|
||||||
|
openUserExternally.Link = $@"https://osu.ppy.sh/users/{user?.Id ?? 0}";
|
||||||
|
userFlag.Country = user?.Country;
|
||||||
|
userCountryText.Text = user?.Country?.FullName ?? "Alien";
|
||||||
|
supporterTag.SupportLevel = user?.SupportLevel ?? 0;
|
||||||
|
titleText.Text = user?.Title ?? string.Empty;
|
||||||
|
titleText.Colour = OsuColour.FromHex(user?.Colour ?? "fff");
|
||||||
|
|
||||||
|
userStats.Clear();
|
||||||
|
if (user?.Statistics != null)
|
||||||
|
{
|
||||||
|
userStats.Add(new UserStatsLine("Ranked Score", user.Statistics.RankedScore.ToString("#,##0")));
|
||||||
|
userStats.Add(new UserStatsLine("Hit Accuracy", Math.Round(user.Statistics.Accuracy, 2).ToString("#0.00'%'")));
|
||||||
|
userStats.Add(new UserStatsLine("Play Count", user.Statistics.PlayCount.ToString("#,##0")));
|
||||||
|
userStats.Add(new UserStatsLine("Total Score", user.Statistics.TotalScore.ToString("#,##0")));
|
||||||
|
userStats.Add(new UserStatsLine("Total Hits", user.Statistics.TotalHits.ToString("#,##0")));
|
||||||
|
userStats.Add(new UserStatsLine("Maximum Combo", user.Statistics.MaxCombo.ToString("#,##0")));
|
||||||
|
userStats.Add(new UserStatsLine("Replays Watched by Others", user.Statistics.ReplaysWatched.ToString("#,##0")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UserStatsLine : Container
|
||||||
|
{
|
||||||
|
public UserStatsLine(string left, string right)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 15),
|
||||||
|
Text = left,
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold),
|
||||||
|
Text = right,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,483 +1,152 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
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.Colour;
|
||||||
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.Textures;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays.Profile.Components;
|
|
||||||
using osu.Game.Overlays.Profile.Header;
|
using osu.Game.Overlays.Profile.Header;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using Humanizer;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile
|
namespace osu.Game.Overlays.Profile
|
||||||
{
|
{
|
||||||
public class ProfileHeader : Container
|
public class ProfileHeader : Container
|
||||||
{
|
{
|
||||||
private readonly LinkFlowContainer infoTextLeft;
|
private readonly UserCoverBackground coverContainer;
|
||||||
private readonly LinkFlowContainer infoTextRight;
|
private readonly ProfileHeaderTabControl infoTabControl;
|
||||||
private readonly FillFlowContainer<SpriteText> scoreText, scoreNumberText;
|
|
||||||
private readonly RankGraph rankGraph;
|
|
||||||
|
|
||||||
public readonly SupporterIcon SupporterTag;
|
private const float cover_height = 150;
|
||||||
private readonly Container coverContainer;
|
private const float cover_info_height = 75;
|
||||||
private readonly Sprite levelBadge;
|
|
||||||
private readonly SpriteText levelText;
|
|
||||||
private readonly GradeBadge gradeSSPlus, gradeSS, gradeSPlus, gradeS, gradeA;
|
|
||||||
private readonly Box colourBar;
|
|
||||||
private readonly DrawableFlag countryFlag;
|
|
||||||
private readonly BadgeContainer badgeContainer;
|
|
||||||
|
|
||||||
private const float cover_height = 350;
|
public ProfileHeader()
|
||||||
private const float info_height = 150;
|
|
||||||
private const float info_width = 220;
|
|
||||||
private const float avatar_size = 110;
|
|
||||||
private const float level_position = 30;
|
|
||||||
private const float level_height = 60;
|
|
||||||
private const float stats_width = 280;
|
|
||||||
|
|
||||||
public ProfileHeader(User user)
|
|
||||||
{
|
{
|
||||||
|
CentreHeaderContainer centreHeaderContainer;
|
||||||
|
DetailHeaderContainer detailHeaderContainer;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = cover_height + info_height;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
coverContainer = new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = cover_height,
|
Height = cover_height,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
coverContainer = new UserCoverBackground
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.1f), Color4.Black.Opacity(0.75f))
|
Colour = ColourInfo.GradientVertical(OsuColour.FromHex("222").Opacity(0.8f), OsuColour.FromHex("222").Opacity(0.2f))
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
|
||||||
Origin = Anchor.BottomLeft,
|
Y = cover_height,
|
||||||
Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN, Bottom = 20, Right = stats_width + UserProfileOverlay.CONTENT_X_MARGIN },
|
Height = cover_info_height,
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Anchor = Anchor.TopLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Depth = -float.MaxValue,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new UpdateableAvatar
|
new ProfileHeaderTitle
|
||||||
{
|
{
|
||||||
User = user,
|
X = -ScreenTitle.ICON_WIDTH,
|
||||||
Size = new Vector2(avatar_size),
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 5,
|
|
||||||
OpenOnClick = { Value = false },
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Colour = Color4.Black.Opacity(0.25f),
|
|
||||||
Radius = 4,
|
|
||||||
},
|
},
|
||||||
},
|
infoTabControl = new ProfileHeaderTabControl
|
||||||
new Container
|
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
X = avatar_size + 10,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Both,
|
Height = cover_info_height - 30,
|
||||||
Children = new Drawable[]
|
Margin = new MarginPadding { Left = -UserProfileOverlay.CONTENT_X_MARGIN },
|
||||||
{
|
Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN }
|
||||||
SupporterTag = new SupporterIcon
|
}
|
||||||
{
|
}
|
||||||
Alpha = 0,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Y = -75,
|
|
||||||
Size = new Vector2(25, 25)
|
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Horizontal,
|
Margin = new MarginPadding { Top = cover_height },
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Y = -48,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
usernameText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = user.Username,
|
|
||||||
Font = OsuFont.GetFont(size: 30, weight: FontWeight.Regular, italics: true)
|
|
||||||
},
|
|
||||||
new ExternalLinkButton($@"https://osu.ppy.sh/users/{user.Id}")
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Margin = new MarginPadding { Left = 3, Bottom = 3 }, //To better lineup with the font
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
countryFlag = new DrawableFlag(user.Country)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Width = 30,
|
|
||||||
Height = 20
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
badgeContainer = new BadgeContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Margin = new MarginPadding { Bottom = 5 },
|
|
||||||
Alpha = 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colourBar = new Box
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
X = UserProfileOverlay.CONTENT_X_MARGIN,
|
|
||||||
Height = 5,
|
|
||||||
Width = info_width,
|
|
||||||
Alpha = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Box // this is a temporary workaround for incorrect masking behaviour of FillMode.Fill used in UserCoverBackground (see https://github.com/ppy/osu-framework/issues/1675)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 1,
|
|
||||||
Y = cover_height,
|
|
||||||
Colour = OsuColour.Gray(34),
|
|
||||||
},
|
|
||||||
infoTextLeft = new LinkFlowContainer(t => t.Font = t.Font.With(size: 14))
|
|
||||||
{
|
|
||||||
X = UserProfileOverlay.CONTENT_X_MARGIN,
|
|
||||||
Y = cover_height + 20,
|
|
||||||
Width = info_width,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
ParagraphSpacing = 0.8f,
|
|
||||||
LineSpacing = 0.2f
|
|
||||||
},
|
|
||||||
infoTextRight = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Regular, italics: true))
|
|
||||||
{
|
|
||||||
X = UserProfileOverlay.CONTENT_X_MARGIN + info_width + 20,
|
|
||||||
Y = cover_height + 20,
|
|
||||||
Width = info_width,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
ParagraphSpacing = 0.8f,
|
|
||||||
LineSpacing = 0.2f
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
X = -UserProfileOverlay.CONTENT_X_MARGIN,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Width = stats_width,
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Y = level_position,
|
|
||||||
Height = level_height,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
Colour = Color4.Black.Opacity(0.5f),
|
|
||||||
RelativeSizeAxes = Axes.Both
|
|
||||||
},
|
|
||||||
levelBadge = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Height = 50,
|
|
||||||
Width = 50,
|
|
||||||
Alpha = 0
|
|
||||||
},
|
|
||||||
levelText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Y = 11,
|
|
||||||
Font = OsuFont.GetFont(size: 20)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Y = cover_height,
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Height = cover_height - level_height - level_position - 5,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
Colour = Color4.Black.Opacity(0.5f),
|
|
||||||
RelativeSizeAxes = Axes.Both
|
|
||||||
},
|
|
||||||
scoreText = new FillFlowContainer<SpriteText>
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Padding = new MarginPadding { Horizontal = 20, Vertical = 18 },
|
|
||||||
Spacing = new Vector2(0, 2)
|
|
||||||
},
|
|
||||||
scoreNumberText = new FillFlowContainer<SpriteText>
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Padding = new MarginPadding { Horizontal = 20, Vertical = 18 },
|
|
||||||
Spacing = new Vector2(0, 2)
|
|
||||||
},
|
|
||||||
new FillFlowContainer<GradeBadge>
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Y = -64,
|
|
||||||
Spacing = new Vector2(20, 0),
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
gradeSSPlus = new GradeBadge("SSPlus") { Alpha = 0 },
|
|
||||||
gradeSS = new GradeBadge("SS") { Alpha = 0 },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new FillFlowContainer<GradeBadge>
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Y = -18,
|
|
||||||
Spacing = new Vector2(20, 0),
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
gradeSPlus = new GradeBadge("SPlus") { Alpha = 0 },
|
|
||||||
gradeS = new GradeBadge("S") { Alpha = 0 },
|
|
||||||
gradeA = new GradeBadge("A") { Alpha = 0 },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Height = info_height - 15,
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new TopHeaderContainer
|
||||||
{
|
{
|
||||||
Colour = Color4.Black.Opacity(0.25f),
|
RelativeSizeAxes = Axes.X,
|
||||||
RelativeSizeAxes = Axes.Both
|
User = { BindTarget = User },
|
||||||
},
|
},
|
||||||
rankGraph = new RankGraph
|
centreHeaderContainer = new CentreHeaderContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.X,
|
||||||
}
|
User = { BindTarget = User },
|
||||||
}
|
},
|
||||||
}
|
detailHeaderContainer = new DetailHeaderContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
User = { BindTarget = User },
|
||||||
|
},
|
||||||
|
new MedalHeaderContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
User = { BindTarget = User },
|
||||||
|
},
|
||||||
|
new BottomHeaderContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
User = { BindTarget = User },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
infoTabControl.AddItem("Info");
|
||||||
|
infoTabControl.AddItem("Modding");
|
||||||
|
|
||||||
|
centreHeaderContainer.DetailsVisible.BindValueChanged(visible => detailHeaderContainer.Alpha = visible.NewValue ? 1 : 0, true);
|
||||||
|
User.ValueChanged += e => updateDisplay(e.NewValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
levelBadge.Texture = textures.Get(@"Profile/levelbadge");
|
infoTabControl.AccentColour = colours.CommunityUserGreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly OsuSpriteText usernameText;
|
public Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
private User user;
|
private void updateDisplay(User user)
|
||||||
|
|
||||||
public User User
|
|
||||||
{
|
{
|
||||||
get => user;
|
coverContainer.User = user;
|
||||||
set
|
|
||||||
{
|
|
||||||
user = value;
|
|
||||||
loadUser();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadUser()
|
private class ProfileHeaderTitle : ScreenTitle
|
||||||
{
|
{
|
||||||
LoadComponentAsync(new UserCoverBackground(user)
|
public ProfileHeaderTitle()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
Title = "Player";
|
||||||
Anchor = Anchor.Centre,
|
Section = "Info";
|
||||||
Origin = Anchor.Centre,
|
|
||||||
FillMode = FillMode.Fill,
|
|
||||||
Depth = float.MaxValue,
|
|
||||||
}, background =>
|
|
||||||
{
|
|
||||||
coverContainer.Add(background);
|
|
||||||
background.FadeInFromZero(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (user.IsSupporter)
|
|
||||||
SupporterTag.Show();
|
|
||||||
|
|
||||||
usernameText.Text = user.Username;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(user.Colour))
|
|
||||||
{
|
|
||||||
colourBar.Colour = OsuColour.FromHex(user.Colour);
|
|
||||||
colourBar.Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void boldItalic(SpriteText t) => t.Font = t.Font.With(Typeface.Exo, weight: FontWeight.Bold, italics: true);
|
[BackgroundDependencyLoader]
|
||||||
void lightText(SpriteText t) => t.Alpha = 0.8f;
|
private void load(OsuColour colours)
|
||||||
|
|
||||||
OsuSpriteText createScoreText(string text) => new OsuSpriteText
|
|
||||||
{
|
{
|
||||||
Font = OsuFont.GetFont(size: 14),
|
AccentColour = colours.CommunityUserGreen;
|
||||||
Text = text
|
|
||||||
};
|
|
||||||
|
|
||||||
OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
Text = text
|
|
||||||
};
|
|
||||||
|
|
||||||
if (user.Country != null)
|
|
||||||
{
|
|
||||||
infoTextLeft.AddText("From ", lightText);
|
|
||||||
infoTextLeft.AddText(user.Country.FullName, boldItalic);
|
|
||||||
countryFlag.Country = user.Country;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infoTextLeft.NewParagraph();
|
|
||||||
|
|
||||||
if (user.JoinDate.ToUniversalTime().Year < 2008)
|
|
||||||
{
|
|
||||||
infoTextLeft.AddText(new DrawableJoinDate(user.JoinDate), lightText);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
infoTextLeft.AddText("Joined ", lightText);
|
|
||||||
infoTextLeft.AddText(new DrawableJoinDate(user.JoinDate), boldItalic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.LastVisit.HasValue)
|
|
||||||
{
|
|
||||||
infoTextLeft.NewLine();
|
|
||||||
infoTextLeft.AddText("Last seen ", lightText);
|
|
||||||
infoTextLeft.AddText(new DrawableDate(user.LastVisit.Value), boldItalic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.PlayStyle?.Length > 0)
|
|
||||||
{
|
|
||||||
infoTextLeft.NewParagraph();
|
|
||||||
infoTextLeft.AddText("Plays with ", lightText);
|
|
||||||
infoTextLeft.AddText(string.Join(", ", user.PlayStyle), boldItalic);
|
|
||||||
}
|
|
||||||
|
|
||||||
infoTextLeft.NewLine();
|
|
||||||
infoTextLeft.AddText("Contributed ", lightText);
|
|
||||||
infoTextLeft.AddLink("forum post".ToQuantity(user.PostCount), url: $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: boldItalic);
|
|
||||||
|
|
||||||
string websiteWithoutProtcol = user.Website;
|
|
||||||
if (!string.IsNullOrEmpty(websiteWithoutProtcol))
|
|
||||||
{
|
|
||||||
int protocolIndex = websiteWithoutProtcol.IndexOf("//", StringComparison.Ordinal);
|
|
||||||
if (protocolIndex >= 0)
|
|
||||||
websiteWithoutProtcol = websiteWithoutProtcol.Substring(protocolIndex + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
tryAddInfoRightLine(FontAwesome.Solid.MapMarker, user.Location);
|
|
||||||
tryAddInfoRightLine(FontAwesome.Regular.Heart, user.Interests);
|
|
||||||
tryAddInfoRightLine(FontAwesome.Solid.Suitcase, user.Occupation);
|
|
||||||
infoTextRight.NewParagraph();
|
|
||||||
if (!string.IsNullOrEmpty(user.Twitter))
|
|
||||||
tryAddInfoRightLine(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
|
||||||
tryAddInfoRightLine(FontAwesome.Solid.Gamepad, user.Discord);
|
|
||||||
tryAddInfoRightLine(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
|
|
||||||
tryAddInfoRightLine(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
|
|
||||||
tryAddInfoRightLine(FontAwesome.Solid.Globe, websiteWithoutProtcol, user.Website);
|
|
||||||
|
|
||||||
if (user.Statistics != null)
|
|
||||||
{
|
|
||||||
levelBadge.Show();
|
|
||||||
levelText.Text = user.Statistics.Level.Current.ToString();
|
|
||||||
|
|
||||||
scoreText.Add(createScoreText("Ranked Score"));
|
|
||||||
scoreNumberText.Add(createScoreNumberText(user.Statistics.RankedScore.ToString(@"#,0")));
|
|
||||||
scoreText.Add(createScoreText("Accuracy"));
|
|
||||||
scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy:0.##}%"));
|
|
||||||
scoreText.Add(createScoreText("Play Count"));
|
|
||||||
scoreNumberText.Add(createScoreNumberText(user.Statistics.PlayCount.ToString(@"#,0")));
|
|
||||||
scoreText.Add(createScoreText("Total Score"));
|
|
||||||
scoreNumberText.Add(createScoreNumberText(user.Statistics.TotalScore.ToString(@"#,0")));
|
|
||||||
scoreText.Add(createScoreText("Total Hits"));
|
|
||||||
scoreNumberText.Add(createScoreNumberText(user.Statistics.TotalHits.ToString(@"#,0")));
|
|
||||||
scoreText.Add(createScoreText("Max Combo"));
|
|
||||||
scoreNumberText.Add(createScoreNumberText(user.Statistics.MaxCombo.ToString(@"#,0")));
|
|
||||||
scoreText.Add(createScoreText("Replays Watched by Others"));
|
|
||||||
scoreNumberText.Add(createScoreNumberText(user.Statistics.ReplaysWatched.ToString(@"#,0")));
|
|
||||||
|
|
||||||
gradeSSPlus.DisplayCount = user.Statistics.GradesCount.SSPlus;
|
|
||||||
gradeSSPlus.Show();
|
|
||||||
gradeSS.DisplayCount = user.Statistics.GradesCount.SS;
|
|
||||||
gradeSS.Show();
|
|
||||||
gradeSPlus.DisplayCount = user.Statistics.GradesCount.SPlus;
|
|
||||||
gradeSPlus.Show();
|
|
||||||
gradeS.DisplayCount = user.Statistics.GradesCount.S;
|
|
||||||
gradeS.Show();
|
|
||||||
gradeA.DisplayCount = user.Statistics.GradesCount.A;
|
|
||||||
gradeA.Show();
|
|
||||||
|
|
||||||
rankGraph.User.Value = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
badgeContainer.ShowBadges(user.Badges);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tryAddInfoRightLine(IconUsage icon, string str, string url = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(str)) return;
|
|
||||||
|
|
||||||
infoTextRight.AddIcon(icon);
|
|
||||||
if (url != null)
|
|
||||||
{
|
|
||||||
infoTextRight.AddLink(" " + str, url);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
infoTextRight.AddText(" " + str);
|
|
||||||
}
|
|
||||||
|
|
||||||
infoTextRight.NewLine();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osuTK;
|
|
||||||
using osu.Framework.Graphics;
|
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.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile
|
namespace osu.Game.Overlays.Profile
|
||||||
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -7,6 +7,7 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
@ -16,6 +16,7 @@ using System.ComponentModel;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
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.Graphics.UserInterface;
|
||||||
|
@ -5,7 +5,7 @@ using osuTK;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Backgrounds;
|
using osu.Game.Graphics.Backgrounds;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Caching;
|
using osu.Framework.Caching;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -31,7 +31,7 @@ namespace osu.Game.Overlays
|
|||||||
private SectionsContainer<ProfileSection> sectionsContainer;
|
private SectionsContainer<ProfileSection> sectionsContainer;
|
||||||
private ProfileTabControl tabs;
|
private ProfileTabControl tabs;
|
||||||
|
|
||||||
public const float CONTENT_X_MARGIN = 50;
|
public const float CONTENT_X_MARGIN = 70;
|
||||||
|
|
||||||
public UserProfileOverlay()
|
public UserProfileOverlay()
|
||||||
{
|
{
|
||||||
@ -81,7 +81,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
Show();
|
Show();
|
||||||
|
|
||||||
if (user.Id == Header?.User?.Id)
|
if (user.Id == Header?.User.Value?.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
userReq?.Cancel();
|
userReq?.Cancel();
|
||||||
@ -113,12 +113,10 @@ namespace osu.Game.Overlays
|
|||||||
Colour = OsuColour.Gray(0.2f)
|
Colour = OsuColour.Gray(0.2f)
|
||||||
});
|
});
|
||||||
|
|
||||||
Header = new ProfileHeader(user);
|
|
||||||
|
|
||||||
Add(sectionsContainer = new SectionsContainer<ProfileSection>
|
Add(sectionsContainer = new SectionsContainer<ProfileSection>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ExpandableHeader = Header,
|
ExpandableHeader = Header = new ProfileHeader(),
|
||||||
FixedHeader = tabs,
|
FixedHeader = tabs,
|
||||||
HeaderBackground = new Box
|
HeaderBackground = new Box
|
||||||
{
|
{
|
||||||
@ -169,7 +167,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private void userLoadComplete(User user)
|
private void userLoadComplete(User user)
|
||||||
{
|
{
|
||||||
Header.User = user;
|
Header.User.Value = user;
|
||||||
|
|
||||||
if (user.ProfileOrder != null)
|
if (user.ProfileOrder != null)
|
||||||
{
|
{
|
||||||
|
@ -67,24 +67,12 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
internal BindableInt Combo;
|
internal BindableInt Combo;
|
||||||
private IShader shader;
|
private IShader shader;
|
||||||
|
|
||||||
protected override DrawNode CreateDrawNode() => new FlashlightDrawNode();
|
protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(this);
|
||||||
|
|
||||||
public override bool RemoveCompletedTransforms => false;
|
public override bool RemoveCompletedTransforms => false;
|
||||||
|
|
||||||
public List<BreakPeriod> Breaks;
|
public List<BreakPeriod> Breaks;
|
||||||
|
|
||||||
protected override void ApplyDrawNode(DrawNode node)
|
|
||||||
{
|
|
||||||
base.ApplyDrawNode(node);
|
|
||||||
|
|
||||||
var flashNode = (FlashlightDrawNode)node;
|
|
||||||
|
|
||||||
flashNode.Shader = shader;
|
|
||||||
flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad;
|
|
||||||
flashNode.FlashlightPosition = Vector2Extensions.Transform(FlashlightPosition, DrawInfo.Matrix);
|
|
||||||
flashNode.FlashlightSize = Vector2Extensions.Transform(FlashlightSize, DrawInfo.Matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ShaderManager shaderManager)
|
private void load(ShaderManager shaderManager)
|
||||||
{
|
{
|
||||||
@ -139,27 +127,44 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
Invalidate(Invalidation.DrawNode);
|
Invalidate(Invalidation.DrawNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class FlashlightDrawNode : DrawNode
|
private class FlashlightDrawNode : DrawNode
|
||||||
{
|
{
|
||||||
public IShader Shader;
|
protected new Flashlight Source => (Flashlight)base.Source;
|
||||||
public Quad ScreenSpaceDrawQuad;
|
|
||||||
public Vector2 FlashlightPosition;
|
private IShader shader;
|
||||||
public Vector2 FlashlightSize;
|
private Quad screenSpaceDrawQuad;
|
||||||
|
private Vector2 flashlightPosition;
|
||||||
|
private Vector2 flashlightSize;
|
||||||
|
|
||||||
|
public FlashlightDrawNode(Flashlight source)
|
||||||
|
: base(source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ApplyState()
|
||||||
|
{
|
||||||
|
base.ApplyState();
|
||||||
|
|
||||||
|
shader = Source.shader;
|
||||||
|
screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad;
|
||||||
|
flashlightPosition = Vector2Extensions.Transform(Source.FlashlightPosition, DrawInfo.Matrix);
|
||||||
|
flashlightSize = Vector2Extensions.Transform(Source.FlashlightSize, DrawInfo.Matrix);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
||||||
{
|
{
|
||||||
base.Draw(vertexAction);
|
base.Draw(vertexAction);
|
||||||
|
|
||||||
Shader.Bind();
|
shader.Bind();
|
||||||
|
|
||||||
Shader.GetUniform<Vector2>("flashlightPos").UpdateValue(ref FlashlightPosition);
|
shader.GetUniform<Vector2>("flashlightPos").UpdateValue(ref flashlightPosition);
|
||||||
Shader.GetUniform<Vector2>("flashlightSize").UpdateValue(ref FlashlightSize);
|
shader.GetUniform<Vector2>("flashlightSize").UpdateValue(ref flashlightSize);
|
||||||
|
|
||||||
Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
|
Texture.WhitePixel.DrawQuad(screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
|
||||||
|
|
||||||
Shader.Unbind();
|
shader.Unbind();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
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;
|
||||||
|
@ -16,6 +16,7 @@ using osuTK.Input;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
@ -150,62 +150,67 @@ namespace osu.Game.Screens.Menu
|
|||||||
Invalidate(Invalidation.DrawNode, shallPropagate: false);
|
Invalidate(Invalidation.DrawNode, shallPropagate: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawNode CreateDrawNode() => new VisualisationDrawNode();
|
protected override DrawNode CreateDrawNode() => new VisualisationDrawNode(this);
|
||||||
|
|
||||||
protected override void ApplyDrawNode(DrawNode node)
|
|
||||||
{
|
|
||||||
base.ApplyDrawNode(node);
|
|
||||||
|
|
||||||
var visNode = (VisualisationDrawNode)node;
|
|
||||||
|
|
||||||
visNode.Shader = shader;
|
|
||||||
visNode.Texture = texture;
|
|
||||||
visNode.Size = DrawSize.X;
|
|
||||||
visNode.Colour = AccentColour;
|
|
||||||
visNode.AudioData = frequencyAmplitudes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class VisualisationDrawNode : DrawNode
|
private class VisualisationDrawNode : DrawNode
|
||||||
{
|
{
|
||||||
public IShader Shader;
|
protected new LogoVisualisation Source => (LogoVisualisation)base.Source;
|
||||||
public Texture Texture;
|
|
||||||
|
private IShader shader;
|
||||||
|
private Texture texture;
|
||||||
|
|
||||||
//Asuming the logo is a circle, we don't need a second dimension.
|
//Asuming the logo is a circle, we don't need a second dimension.
|
||||||
public float Size;
|
private float size;
|
||||||
|
|
||||||
public Color4 Colour;
|
private Color4 colour;
|
||||||
public float[] AudioData;
|
private float[] audioData;
|
||||||
|
|
||||||
private readonly QuadBatch<TexturedVertex2D> vertexBatch = new QuadBatch<TexturedVertex2D>(100, 10);
|
private readonly QuadBatch<TexturedVertex2D> vertexBatch = new QuadBatch<TexturedVertex2D>(100, 10);
|
||||||
|
|
||||||
|
public VisualisationDrawNode(LogoVisualisation source)
|
||||||
|
: base(source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ApplyState()
|
||||||
|
{
|
||||||
|
base.ApplyState();
|
||||||
|
|
||||||
|
shader = Source.shader;
|
||||||
|
texture = Source.texture;
|
||||||
|
size = Source.DrawSize.X;
|
||||||
|
colour = Source.AccentColour;
|
||||||
|
audioData = Source.frequencyAmplitudes;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
||||||
{
|
{
|
||||||
base.Draw(vertexAction);
|
base.Draw(vertexAction);
|
||||||
|
|
||||||
Shader.Bind();
|
shader.Bind();
|
||||||
Texture.TextureGL.Bind();
|
texture.TextureGL.Bind();
|
||||||
|
|
||||||
Vector2 inflation = DrawInfo.MatrixInverse.ExtractScale().Xy;
|
Vector2 inflation = DrawInfo.MatrixInverse.ExtractScale().Xy;
|
||||||
|
|
||||||
ColourInfo colourInfo = DrawColourInfo.Colour;
|
ColourInfo colourInfo = DrawColourInfo.Colour;
|
||||||
colourInfo.ApplyChild(Colour);
|
colourInfo.ApplyChild(colour);
|
||||||
|
|
||||||
if (AudioData != null)
|
if (audioData != null)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < visualiser_rounds; j++)
|
for (int j = 0; j < visualiser_rounds; j++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < bars_per_visualiser; i++)
|
for (int i = 0; i < bars_per_visualiser; i++)
|
||||||
{
|
{
|
||||||
if (AudioData[i] < amplitude_dead_zone)
|
if (audioData[i] < amplitude_dead_zone)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float rotation = MathHelper.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
|
float rotation = MathHelper.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
|
||||||
float rotationCos = (float)Math.Cos(rotation);
|
float rotationCos = (float)Math.Cos(rotation);
|
||||||
float rotationSin = (float)Math.Sin(rotation);
|
float rotationSin = (float)Math.Sin(rotation);
|
||||||
//taking the cos and sin to the 0..1 range
|
//taking the cos and sin to the 0..1 range
|
||||||
var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * Size;
|
var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;
|
||||||
|
|
||||||
var barSize = new Vector2(Size * (float)Math.Sqrt(2 * (1 - Math.Cos(MathHelper.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * AudioData[i]);
|
var barSize = new Vector2(size * (float)Math.Sqrt(2 * (1 - Math.Cos(MathHelper.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
|
||||||
//The distance between the position and the sides of the bar.
|
//The distance between the position and the sides of the bar.
|
||||||
var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
|
var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
|
||||||
//The distance between the bottom side of the bar and the top side.
|
//The distance between the bottom side of the bar and the top side.
|
||||||
@ -218,7 +223,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
|
Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
|
||||||
);
|
);
|
||||||
|
|
||||||
Texture.DrawQuad(
|
texture.DrawQuad(
|
||||||
rectangle,
|
rectangle,
|
||||||
colourInfo,
|
colourInfo,
|
||||||
null,
|
null,
|
||||||
@ -229,7 +234,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader.Unbind();
|
shader.Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Screens.Multi
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
X = -35,
|
X = -ScreenTitle.ICON_WIDTH,
|
||||||
},
|
},
|
||||||
breadcrumbs = new HeaderBreadcrumbControl(stack)
|
breadcrumbs = new HeaderBreadcrumbControl(stack)
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@ 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.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
|
@ -95,8 +95,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
UserPlaybackRate.ValueChanged += _ => updateRate();
|
UserPlaybackRate.ValueChanged += _ => updateRate();
|
||||||
|
|
||||||
Seek(Math.Min(0, gameplayStartTime - beatmap.BeatmapInfo.AudioLeadIn));
|
Seek(Math.Min(-beatmap.BeatmapInfo.AudioLeadIn, gameplayStartTime));
|
||||||
adjustableClock.ProcessFrame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Restart()
|
public void Restart()
|
||||||
@ -137,6 +136,9 @@ namespace osu.Game.Screens.Play
|
|||||||
// remove the offset component here because most of the time we want the seek to be aligned to gameplay, not the audio track.
|
// remove the offset component here because most of the time we want the seek to be aligned to gameplay, not the audio track.
|
||||||
// we may want to consider reversing the application of offsets in the future as it may feel more correct.
|
// we may want to consider reversing the application of offsets in the future as it may feel more correct.
|
||||||
adjustableClock.Seek(time - totalOffset);
|
adjustableClock.Seek(time - totalOffset);
|
||||||
|
|
||||||
|
// manually process frame to ensure GameplayClock is correctly updated after a seek.
|
||||||
|
userOffsetClock.ProcessFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user