Normalize all the line endings

This commit is contained in:
Dean Herbert
2018-04-13 18:19:50 +09:00
parent f99503b60c
commit 32a74f95a5
1069 changed files with 95293 additions and 95293 deletions

View File

@ -1,43 +1,43 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK.Graphics;
using osu.Game.Graphics.Textures;
namespace osu.Game.Graphics.Backgrounds
{
public class Background : BufferedContainer
{
public Sprite Sprite;
private readonly string textureName;
public Background(string textureName = @"")
{
CacheDrawnFrameBuffer = true;
this.textureName = textureName;
RelativeSizeAxes = Axes.Both;
Add(Sprite = new Sprite
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = Color4.DarkGray,
FillMode = FillMode.Fill,
});
}
[BackgroundDependencyLoader]
private void load(LargeTextureStore textures)
{
if (!string.IsNullOrEmpty(textureName))
Sprite.Texture = textures.Get(textureName);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using OpenTK.Graphics;
using osu.Game.Graphics.Textures;
namespace osu.Game.Graphics.Backgrounds
{
public class Background : BufferedContainer
{
public Sprite Sprite;
private readonly string textureName;
public Background(string textureName = @"")
{
CacheDrawnFrameBuffer = true;
this.textureName = textureName;
RelativeSizeAxes = Axes.Both;
Add(Sprite = new Sprite
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = Color4.DarkGray,
FillMode = FillMode.Fill,
});
}
[BackgroundDependencyLoader]
private void load(LargeTextureStore textures)
{
if (!string.IsNullOrEmpty(textureName))
Sprite.Texture = textures.Get(textureName);
}
}
}

View File

@ -1,280 +1,280 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
using OpenTK;
using OpenTK.Graphics;
using System;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
using OpenTK.Graphics.ES30;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Allocation;
using System.Collections.Generic;
using osu.Framework.Graphics.Batches;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Lists;
namespace osu.Game.Graphics.Backgrounds
{
public class Triangles : Drawable
{
private const float triangle_size = 100;
private const float base_velocity = 50;
/// <summary>
/// How many screen-space pixels are smoothed over.
/// Same behavior as Sprite's EdgeSmoothness.
/// </summary>
private const float edge_smoothness = 1;
public override bool HandleKeyboardInput => false;
public override bool HandleMouseInput => false;
public Color4 ColourLight = Color4.White;
public Color4 ColourDark = Color4.Black;
/// <summary>
/// Whether we want to expire triangles as they exit our draw area completely.
/// </summary>
protected virtual bool ExpireOffScreenTriangles => true;
/// <summary>
/// Whether we should create new triangles as others expire.
/// </summary>
protected virtual bool CreateNewTriangles => true;
/// <summary>
/// The amount of triangles we want compared to the default distribution.
/// </summary>
protected virtual float SpawnRatio => 1;
private float triangleScale = 1;
/// <summary>
/// Whether we should drop-off alpha values of triangles more quickly to improve
/// the visual appearance of fading. This defaults to on as it is generally more
/// aesthetically pleasing, but should be turned off in buffered containers.
/// </summary>
public bool HideAlphaDiscrepancies = true;
/// <summary>
/// The relative velocity of the triangles. Default is 1.
/// </summary>
public float Velocity = 1;
private readonly SortedList<TriangleParticle> parts = new SortedList<TriangleParticle>(Comparer<TriangleParticle>.Default);
private Shader shader;
private readonly Texture texture;
public Triangles()
{
texture = Texture.WhitePixel;
}
[BackgroundDependencyLoader]
private void load(ShaderManager shaders)
{
shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
}
protected override void LoadComplete()
{
base.LoadComplete();
addTriangles(true);
}
public float TriangleScale
{
get { return triangleScale; }
set
{
float change = value / triangleScale;
triangleScale = value;
for (int i = 0; i < parts.Count; i++)
{
TriangleParticle newParticle = parts[i];
newParticle.Scale *= change;
parts[i] = newParticle;
}
}
}
protected override void Update()
{
base.Update();
Invalidate(Invalidation.DrawNode, shallPropagate: false);
if (CreateNewTriangles)
addTriangles(false);
float adjustedAlpha = HideAlphaDiscrepancies ?
// Cubically scale alpha to make it drop off more sharply.
(float)Math.Pow(DrawInfo.Colour.AverageColour.Linear.A, 3) :
1;
float elapsedSeconds = (float)Time.Elapsed / 1000;
// Since position is relative, the velocity needs to scale inversely with DrawHeight.
// Since we will later multiply by the scale of individual triangles we normalize by
// dividing by triangleScale.
float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * triangleScale);
for (int i = 0; i < parts.Count; i++)
{
TriangleParticle newParticle = parts[i];
// Scale moved distance by the size of the triangle. Smaller triangles should move more slowly.
newParticle.Position.Y += parts[i].Scale * movedDistance;
newParticle.Colour.A = adjustedAlpha;
parts[i] = newParticle;
float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * 0.866f / DrawHeight;
if (bottomPos < 0)
parts.RemoveAt(i);
}
}
private void addTriangles(bool randomY)
{
int aimTriangleCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
for (int i = 0; i < aimTriangleCount - parts.Count; i++)
parts.Add(createTriangle(randomY));
}
private TriangleParticle createTriangle(bool randomY)
{
TriangleParticle particle = CreateTriangle();
particle.Position = new Vector2(RNG.NextSingle(), randomY ? RNG.NextSingle() : 1);
particle.Colour = CreateTriangleShade();
return particle;
}
/// <summary>
/// Creates a triangle particle with a random scale.
/// </summary>
/// <returns>The triangle particle.</returns>
protected virtual TriangleParticle CreateTriangle()
{
const float std_dev = 0.16f;
const float mean = 0.5f;
float u1 = 1 - RNG.NextSingle(); //uniform(0,1] random floats
float u2 = 1 - RNG.NextSingle();
float randStdNormal = (float)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2)); //random normal(0,1)
var scale = Math.Max(triangleScale * (mean + std_dev * randStdNormal), 0.1f); //random normal(mean,stdDev^2)
return new TriangleParticle { Scale = scale };
}
/// <summary>
/// Creates a shade of colour for the triangles.
/// </summary>
/// <returns>The colour.</returns>
protected virtual Color4 CreateTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1);
protected override DrawNode CreateDrawNode() => new TrianglesDrawNode();
private readonly TrianglesDrawNodeSharedData sharedData = new TrianglesDrawNodeSharedData();
protected override void ApplyDrawNode(DrawNode node)
{
base.ApplyDrawNode(node);
var trianglesNode = (TrianglesDrawNode)node;
trianglesNode.Shader = shader;
trianglesNode.Texture = texture;
trianglesNode.Size = DrawSize;
trianglesNode.Shared = sharedData;
trianglesNode.Parts.Clear();
trianglesNode.Parts.AddRange(parts);
}
private class TrianglesDrawNodeSharedData
{
public readonly LinearBatch<TexturedVertex2D> VertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles);
}
private class TrianglesDrawNode : DrawNode
{
public Shader Shader;
public Texture Texture;
public TrianglesDrawNodeSharedData Shared;
public readonly List<TriangleParticle> Parts = new List<TriangleParticle>();
public Vector2 Size;
public override void Draw(Action<TexturedVertex2D> vertexAction)
{
base.Draw(vertexAction);
Shader.Bind();
Texture.TextureGL.Bind();
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
foreach (TriangleParticle particle in Parts)
{
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(
Vector2Extensions.Transform(particle.Position * Size, DrawInfo.Matrix),
Vector2Extensions.Transform(particle.Position * Size + offset, DrawInfo.Matrix),
Vector2Extensions.Transform(particle.Position * Size + new Vector2(-offset.X, offset.Y), DrawInfo.Matrix)
);
ColourInfo colourInfo = DrawInfo.Colour;
colourInfo.ApplyChild(particle.Colour);
Texture.DrawTriangle(
triangle,
colourInfo,
null,
Shared.VertexBatch.AddAction,
Vector2.Divide(localInflationAmount, size));
}
Shader.Unbind();
}
}
protected struct TriangleParticle : IComparable<TriangleParticle>
{
/// <summary>
/// The position of the top vertex of the triangle.
/// </summary>
public Vector2 Position;
/// <summary>
/// The colour of the triangle.
/// </summary>
public Color4 Colour;
/// <summary>
/// The scale of the triangle.
/// </summary>
public float Scale;
/// <summary>
/// Compares two <see cref="TriangleParticle"/>s. This is a reverse comparer because when the
/// triangles are added to the particles list, they should be drawn from largest to smallest
/// such that the smaller triangles appear on top.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public int CompareTo(TriangleParticle other) => other.Scale.CompareTo(Scale);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
using OpenTK;
using OpenTK.Graphics;
using System;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
using OpenTK.Graphics.ES30;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Allocation;
using System.Collections.Generic;
using osu.Framework.Graphics.Batches;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Lists;
namespace osu.Game.Graphics.Backgrounds
{
public class Triangles : Drawable
{
private const float triangle_size = 100;
private const float base_velocity = 50;
/// <summary>
/// How many screen-space pixels are smoothed over.
/// Same behavior as Sprite's EdgeSmoothness.
/// </summary>
private const float edge_smoothness = 1;
public override bool HandleKeyboardInput => false;
public override bool HandleMouseInput => false;
public Color4 ColourLight = Color4.White;
public Color4 ColourDark = Color4.Black;
/// <summary>
/// Whether we want to expire triangles as they exit our draw area completely.
/// </summary>
protected virtual bool ExpireOffScreenTriangles => true;
/// <summary>
/// Whether we should create new triangles as others expire.
/// </summary>
protected virtual bool CreateNewTriangles => true;
/// <summary>
/// The amount of triangles we want compared to the default distribution.
/// </summary>
protected virtual float SpawnRatio => 1;
private float triangleScale = 1;
/// <summary>
/// Whether we should drop-off alpha values of triangles more quickly to improve
/// the visual appearance of fading. This defaults to on as it is generally more
/// aesthetically pleasing, but should be turned off in buffered containers.
/// </summary>
public bool HideAlphaDiscrepancies = true;
/// <summary>
/// The relative velocity of the triangles. Default is 1.
/// </summary>
public float Velocity = 1;
private readonly SortedList<TriangleParticle> parts = new SortedList<TriangleParticle>(Comparer<TriangleParticle>.Default);
private Shader shader;
private readonly Texture texture;
public Triangles()
{
texture = Texture.WhitePixel;
}
[BackgroundDependencyLoader]
private void load(ShaderManager shaders)
{
shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
}
protected override void LoadComplete()
{
base.LoadComplete();
addTriangles(true);
}
public float TriangleScale
{
get { return triangleScale; }
set
{
float change = value / triangleScale;
triangleScale = value;
for (int i = 0; i < parts.Count; i++)
{
TriangleParticle newParticle = parts[i];
newParticle.Scale *= change;
parts[i] = newParticle;
}
}
}
protected override void Update()
{
base.Update();
Invalidate(Invalidation.DrawNode, shallPropagate: false);
if (CreateNewTriangles)
addTriangles(false);
float adjustedAlpha = HideAlphaDiscrepancies ?
// Cubically scale alpha to make it drop off more sharply.
(float)Math.Pow(DrawInfo.Colour.AverageColour.Linear.A, 3) :
1;
float elapsedSeconds = (float)Time.Elapsed / 1000;
// Since position is relative, the velocity needs to scale inversely with DrawHeight.
// Since we will later multiply by the scale of individual triangles we normalize by
// dividing by triangleScale.
float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * triangleScale);
for (int i = 0; i < parts.Count; i++)
{
TriangleParticle newParticle = parts[i];
// Scale moved distance by the size of the triangle. Smaller triangles should move more slowly.
newParticle.Position.Y += parts[i].Scale * movedDistance;
newParticle.Colour.A = adjustedAlpha;
parts[i] = newParticle;
float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * 0.866f / DrawHeight;
if (bottomPos < 0)
parts.RemoveAt(i);
}
}
private void addTriangles(bool randomY)
{
int aimTriangleCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
for (int i = 0; i < aimTriangleCount - parts.Count; i++)
parts.Add(createTriangle(randomY));
}
private TriangleParticle createTriangle(bool randomY)
{
TriangleParticle particle = CreateTriangle();
particle.Position = new Vector2(RNG.NextSingle(), randomY ? RNG.NextSingle() : 1);
particle.Colour = CreateTriangleShade();
return particle;
}
/// <summary>
/// Creates a triangle particle with a random scale.
/// </summary>
/// <returns>The triangle particle.</returns>
protected virtual TriangleParticle CreateTriangle()
{
const float std_dev = 0.16f;
const float mean = 0.5f;
float u1 = 1 - RNG.NextSingle(); //uniform(0,1] random floats
float u2 = 1 - RNG.NextSingle();
float randStdNormal = (float)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2)); //random normal(0,1)
var scale = Math.Max(triangleScale * (mean + std_dev * randStdNormal), 0.1f); //random normal(mean,stdDev^2)
return new TriangleParticle { Scale = scale };
}
/// <summary>
/// Creates a shade of colour for the triangles.
/// </summary>
/// <returns>The colour.</returns>
protected virtual Color4 CreateTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1);
protected override DrawNode CreateDrawNode() => new TrianglesDrawNode();
private readonly TrianglesDrawNodeSharedData sharedData = new TrianglesDrawNodeSharedData();
protected override void ApplyDrawNode(DrawNode node)
{
base.ApplyDrawNode(node);
var trianglesNode = (TrianglesDrawNode)node;
trianglesNode.Shader = shader;
trianglesNode.Texture = texture;
trianglesNode.Size = DrawSize;
trianglesNode.Shared = sharedData;
trianglesNode.Parts.Clear();
trianglesNode.Parts.AddRange(parts);
}
private class TrianglesDrawNodeSharedData
{
public readonly LinearBatch<TexturedVertex2D> VertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles);
}
private class TrianglesDrawNode : DrawNode
{
public Shader Shader;
public Texture Texture;
public TrianglesDrawNodeSharedData Shared;
public readonly List<TriangleParticle> Parts = new List<TriangleParticle>();
public Vector2 Size;
public override void Draw(Action<TexturedVertex2D> vertexAction)
{
base.Draw(vertexAction);
Shader.Bind();
Texture.TextureGL.Bind();
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
foreach (TriangleParticle particle in Parts)
{
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(
Vector2Extensions.Transform(particle.Position * Size, DrawInfo.Matrix),
Vector2Extensions.Transform(particle.Position * Size + offset, DrawInfo.Matrix),
Vector2Extensions.Transform(particle.Position * Size + new Vector2(-offset.X, offset.Y), DrawInfo.Matrix)
);
ColourInfo colourInfo = DrawInfo.Colour;
colourInfo.ApplyChild(particle.Colour);
Texture.DrawTriangle(
triangle,
colourInfo,
null,
Shared.VertexBatch.AddAction,
Vector2.Divide(localInflationAmount, size));
}
Shader.Unbind();
}
}
protected struct TriangleParticle : IComparable<TriangleParticle>
{
/// <summary>
/// The position of the top vertex of the triangle.
/// </summary>
public Vector2 Position;
/// <summary>
/// The colour of the triangle.
/// </summary>
public Color4 Colour;
/// <summary>
/// The scale of the triangle.
/// </summary>
public float Scale;
/// <summary>
/// Compares two <see cref="TriangleParticle"/>s. This is a reverse comparer because when the
/// triangles are added to the particles list, they should be drawn from largest to smallest
/// such that the smaller triangles appear on top.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public int CompareTo(TriangleParticle other) => other.Scale.CompareTo(Scale);
}
}
}

View File

@ -1,86 +1,86 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Graphics.Containers
{
public class BeatSyncedContainer : Container
{
protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private int lastBeat;
private TimingControlPoint lastTimingPoint;
/// <summary>
/// The amount of time before a beat we should fire <see cref="OnNewBeat(int, TimingControlPoint, EffectControlPoint, TrackAmplitudes)"/>.
/// This allows for adding easing to animations that may be synchronised to the beat.
/// </summary>
protected double EarlyActivationMilliseconds;
/// <summary>
/// The time in milliseconds until the next beat.
/// </summary>
public double TimeUntilNextBeat { get; private set; }
/// <summary>
/// The time in milliseconds since the last beat
/// </summary>
public double TimeSinceLastBeat { get; private set; }
protected override void Update()
{
if (!Beatmap.Value.TrackLoaded || !Beatmap.Value.BeatmapLoaded) return;
var track = Beatmap.Value.Track;
var beatmap = Beatmap.Value.Beatmap;
if (track == null || beatmap == null)
return;
double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime;
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
if (timingPoint.BeatLength == 0)
return;
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / timingPoint.BeatLength);
// The beats before the start of the first control point are off by 1, this should do the trick
if (currentTrackTime < timingPoint.Time)
beatIndex--;
TimeUntilNextBeat = (timingPoint.Time - currentTrackTime) % timingPoint.BeatLength;
if (TimeUntilNextBeat < 0)
TimeUntilNextBeat += timingPoint.BeatLength;
TimeSinceLastBeat = timingPoint.BeatLength - TimeUntilNextBeat;
if (timingPoint.Equals(lastTimingPoint) && beatIndex == lastBeat)
return;
using (BeginDelayedSequence(-TimeSinceLastBeat, true))
OnNewBeat(beatIndex, timingPoint, effectPoint, track.CurrentAmplitudes);
lastBeat = beatIndex;
lastTimingPoint = timingPoint;
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
Beatmap.BindTo(game.Beatmap);
}
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
{
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Graphics.Containers
{
public class BeatSyncedContainer : Container
{
protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private int lastBeat;
private TimingControlPoint lastTimingPoint;
/// <summary>
/// The amount of time before a beat we should fire <see cref="OnNewBeat(int, TimingControlPoint, EffectControlPoint, TrackAmplitudes)"/>.
/// This allows for adding easing to animations that may be synchronised to the beat.
/// </summary>
protected double EarlyActivationMilliseconds;
/// <summary>
/// The time in milliseconds until the next beat.
/// </summary>
public double TimeUntilNextBeat { get; private set; }
/// <summary>
/// The time in milliseconds since the last beat
/// </summary>
public double TimeSinceLastBeat { get; private set; }
protected override void Update()
{
if (!Beatmap.Value.TrackLoaded || !Beatmap.Value.BeatmapLoaded) return;
var track = Beatmap.Value.Track;
var beatmap = Beatmap.Value.Beatmap;
if (track == null || beatmap == null)
return;
double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime;
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
if (timingPoint.BeatLength == 0)
return;
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / timingPoint.BeatLength);
// The beats before the start of the first control point are off by 1, this should do the trick
if (currentTrackTime < timingPoint.Time)
beatIndex--;
TimeUntilNextBeat = (timingPoint.Time - currentTrackTime) % timingPoint.BeatLength;
if (TimeUntilNextBeat < 0)
TimeUntilNextBeat += timingPoint.BeatLength;
TimeSinceLastBeat = timingPoint.BeatLength - TimeUntilNextBeat;
if (timingPoint.Equals(lastTimingPoint) && beatIndex == lastBeat)
return;
using (BeginDelayedSequence(-TimeSinceLastBeat, true))
OnNewBeat(beatIndex, timingPoint, effectPoint, track.CurrentAmplitudes);
lastBeat = beatIndex;
lastTimingPoint = timingPoint;
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
Beatmap.BindTo(game.Beatmap);
}
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
{
}
}
}

View File

@ -1,62 +1,62 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
namespace osu.Game.Graphics.Containers
{
/// <summary>
/// Display an icon that is forced to scale to the size of this container.
/// </summary>
public class ConstrainedIconContainer : CompositeDrawable
{
public Drawable Icon
{
get
{
return InternalChild;
}
set
{
InternalChild = value;
}
}
/// <summary>
/// Determines an edge effect of this <see cref="Container"/>.
/// Edge effects are e.g. glow or a shadow.
/// Only has an effect when <see cref="CompositeDrawable.Masking"/> is true.
/// </summary>
public new EdgeEffectParameters EdgeEffect
{
get { return base.EdgeEffect; }
set { base.EdgeEffect = value; }
}
protected override void Update()
{
base.Update();
if (InternalChildren.Count > 0 && InternalChild.DrawSize.X > 0)
{
// We're modifying scale here for a few reasons
// - Guarantees correctness if BorderWidth is being used
// - If we were to use RelativeSize/FillMode, we'd need to set the Icon's RelativeSizeAxes directly.
// We can't do this because we would need access to AutoSizeAxes to set it to none.
// Other issues come up along the way too, so it's not a good solution.
var fitScale = Math.Min(DrawSize.X / InternalChild.DrawSize.X, DrawSize.Y / InternalChild.DrawSize.Y);
InternalChild.Scale = new Vector2(fitScale);
InternalChild.Anchor = Anchor.Centre;
InternalChild.Origin = Anchor.Centre;
}
}
public ConstrainedIconContainer()
{
Masking = true;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
namespace osu.Game.Graphics.Containers
{
/// <summary>
/// Display an icon that is forced to scale to the size of this container.
/// </summary>
public class ConstrainedIconContainer : CompositeDrawable
{
public Drawable Icon
{
get
{
return InternalChild;
}
set
{
InternalChild = value;
}
}
/// <summary>
/// Determines an edge effect of this <see cref="Container"/>.
/// Edge effects are e.g. glow or a shadow.
/// Only has an effect when <see cref="CompositeDrawable.Masking"/> is true.
/// </summary>
public new EdgeEffectParameters EdgeEffect
{
get { return base.EdgeEffect; }
set { base.EdgeEffect = value; }
}
protected override void Update()
{
base.Update();
if (InternalChildren.Count > 0 && InternalChild.DrawSize.X > 0)
{
// We're modifying scale here for a few reasons
// - Guarantees correctness if BorderWidth is being used
// - If we were to use RelativeSize/FillMode, we'd need to set the Icon's RelativeSizeAxes directly.
// We can't do this because we would need access to AutoSizeAxes to set it to none.
// Other issues come up along the way too, so it's not a good solution.
var fitScale = Math.Min(DrawSize.X / InternalChild.DrawSize.X, DrawSize.Y / InternalChild.DrawSize.Y);
InternalChild.Scale = new Vector2(fitScale);
InternalChild.Anchor = Anchor.Centre;
InternalChild.Origin = Anchor.Centre;
}
}
public ConstrainedIconContainer()
{
Masking = true;
}
}
}

View File

@ -1,104 +1,104 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Online.Chat;
using System;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using System.Collections.Generic;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Game.Graphics.Containers
{
public class LinkFlowContainer : OsuTextFlowContainer
{
public LinkFlowContainer(Action<SpriteText> defaultCreationParameters = null)
: base(defaultCreationParameters)
{
}
public override bool HandleMouseInput => true;
private OsuGame game;
private Action showNotImplementedError;
[BackgroundDependencyLoader(true)]
private void load(OsuGame game, NotificationOverlay notifications)
{
// will be null in tests
this.game = game;
showNotImplementedError = () => notifications?.Post(new SimpleNotification
{
Text = @"This link type is not yet supported!",
Icon = FontAwesome.fa_life_saver,
});
}
public void AddLinks(string text, List<Link> links)
{
if (string.IsNullOrEmpty(text) || links == null)
return;
if (links.Count == 0)
{
AddText(text);
return;
}
int previousLinkEnd = 0;
foreach (var link in links)
{
AddText(text.Substring(previousLinkEnd, link.Index - previousLinkEnd));
AddLink(text.Substring(link.Index, link.Length), link.Url, link.Action, link.Argument);
previousLinkEnd = link.Index + link.Length;
}
AddText(text.Substring(previousLinkEnd));
}
public void AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null)
{
AddInternal(new DrawableLinkCompiler(AddText(text).ToList())
{
TooltipText = tooltipText ?? (url != text ? url : string.Empty),
Action = () =>
{
switch (linkType)
{
case LinkAction.OpenBeatmap:
// todo: replace this with overlay.ShowBeatmap(id) once an appropriate API call is implemented.
if (int.TryParse(linkArgument, out int beatmapId))
Process.Start($"https://osu.ppy.sh/b/{beatmapId}");
break;
case LinkAction.OpenBeatmapSet:
if (int.TryParse(linkArgument, out int setId))
game?.ShowBeatmapSet(setId);
break;
case LinkAction.OpenChannel:
game?.OpenChannel(linkArgument);
break;
case LinkAction.OpenEditorTimestamp:
case LinkAction.JoinMultiplayerMatch:
case LinkAction.Spectate:
showNotImplementedError?.Invoke();
break;
case LinkAction.External:
Process.Start(url);
break;
case LinkAction.OpenUserProfile:
if (long.TryParse(linkArgument, out long userId))
game?.ShowUser(userId);
break;
default:
throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action.");
}
},
});
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Online.Chat;
using System;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using System.Collections.Generic;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Game.Graphics.Containers
{
public class LinkFlowContainer : OsuTextFlowContainer
{
public LinkFlowContainer(Action<SpriteText> defaultCreationParameters = null)
: base(defaultCreationParameters)
{
}
public override bool HandleMouseInput => true;
private OsuGame game;
private Action showNotImplementedError;
[BackgroundDependencyLoader(true)]
private void load(OsuGame game, NotificationOverlay notifications)
{
// will be null in tests
this.game = game;
showNotImplementedError = () => notifications?.Post(new SimpleNotification
{
Text = @"This link type is not yet supported!",
Icon = FontAwesome.fa_life_saver,
});
}
public void AddLinks(string text, List<Link> links)
{
if (string.IsNullOrEmpty(text) || links == null)
return;
if (links.Count == 0)
{
AddText(text);
return;
}
int previousLinkEnd = 0;
foreach (var link in links)
{
AddText(text.Substring(previousLinkEnd, link.Index - previousLinkEnd));
AddLink(text.Substring(link.Index, link.Length), link.Url, link.Action, link.Argument);
previousLinkEnd = link.Index + link.Length;
}
AddText(text.Substring(previousLinkEnd));
}
public void AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null)
{
AddInternal(new DrawableLinkCompiler(AddText(text).ToList())
{
TooltipText = tooltipText ?? (url != text ? url : string.Empty),
Action = () =>
{
switch (linkType)
{
case LinkAction.OpenBeatmap:
// todo: replace this with overlay.ShowBeatmap(id) once an appropriate API call is implemented.
if (int.TryParse(linkArgument, out int beatmapId))
Process.Start($"https://osu.ppy.sh/b/{beatmapId}");
break;
case LinkAction.OpenBeatmapSet:
if (int.TryParse(linkArgument, out int setId))
game?.ShowBeatmapSet(setId);
break;
case LinkAction.OpenChannel:
game?.OpenChannel(linkArgument);
break;
case LinkAction.OpenEditorTimestamp:
case LinkAction.JoinMultiplayerMatch:
case LinkAction.Spectate:
showNotImplementedError?.Invoke();
break;
case LinkAction.External:
Process.Start(url);
break;
case LinkAction.OpenUserProfile:
if (long.TryParse(linkArgument, out long userId))
game?.ShowUser(userId);
break;
default:
throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action.");
}
},
});
}
}
}

View File

@ -1,42 +1,42 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.Containers
{
public class OsuClickableContainer : ClickableContainer
{
private readonly HoverSampleSet sampleSet;
private readonly Container content = new Container { RelativeSizeAxes = Axes.Both };
protected override Container<Drawable> Content => content;
protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
{
this.sampleSet = sampleSet;
}
[BackgroundDependencyLoader]
private void load()
{
if (AutoSizeAxes != Axes.None)
{
content.RelativeSizeAxes = RelativeSizeAxes;
content.AutoSizeAxes = AutoSizeAxes;
}
InternalChildren = new Drawable[]
{
content,
CreateHoverClickSounds(sampleSet)
};
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.Containers
{
public class OsuClickableContainer : ClickableContainer
{
private readonly HoverSampleSet sampleSet;
private readonly Container content = new Container { RelativeSizeAxes = Axes.Both };
protected override Container<Drawable> Content => content;
protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
{
this.sampleSet = sampleSet;
}
[BackgroundDependencyLoader]
private void load()
{
if (AutoSizeAxes != Axes.None)
{
content.RelativeSizeAxes = RelativeSizeAxes;
content.AutoSizeAxes = AutoSizeAxes;
}
InternalChildren = new Drawable[]
{
content,
CreateHoverClickSounds(sampleSet)
};
}
}
}

View File

@ -1,73 +1,73 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK;
namespace osu.Game.Graphics.Containers
{
public class OsuFocusedOverlayContainer : FocusedOverlayContainer
{
private SampleChannel samplePopIn;
private SampleChannel samplePopOut;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
StateChanged += onStateChanged;
}
/// <summary>
/// Whether mouse input should be blocked screen-wide while this overlay is visible.
/// Performing mouse actions outside of the valid extents will hide the overlay but pass the events through.
/// </summary>
public virtual bool BlockScreenWideMouse => BlockPassThroughMouse;
// receive input outside our bounds so we can trigger a close event on ourselves.
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnClick(InputState state)
{
if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position))
{
State = Visibility.Hidden;
return true;
}
return base.OnClick(state);
}
protected override bool OnDragStart(InputState state)
{
if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position))
{
State = Visibility.Hidden;
return true;
}
return base.OnDragStart(state);
}
protected override bool OnDrag(InputState state) => State == Visibility.Hidden;
private void onStateChanged(Visibility visibility)
{
switch (visibility)
{
case Visibility.Visible:
samplePopIn?.Play();
break;
case Visibility.Hidden:
samplePopOut?.Play();
break;
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK;
namespace osu.Game.Graphics.Containers
{
public class OsuFocusedOverlayContainer : FocusedOverlayContainer
{
private SampleChannel samplePopIn;
private SampleChannel samplePopOut;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
StateChanged += onStateChanged;
}
/// <summary>
/// Whether mouse input should be blocked screen-wide while this overlay is visible.
/// Performing mouse actions outside of the valid extents will hide the overlay but pass the events through.
/// </summary>
public virtual bool BlockScreenWideMouse => BlockPassThroughMouse;
// receive input outside our bounds so we can trigger a close event on ourselves.
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnClick(InputState state)
{
if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position))
{
State = Visibility.Hidden;
return true;
}
return base.OnClick(state);
}
protected override bool OnDragStart(InputState state)
{
if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position))
{
State = Visibility.Hidden;
return true;
}
return base.OnDragStart(state);
}
protected override bool OnDrag(InputState state) => State == Visibility.Hidden;
private void onStateChanged(Visibility visibility)
{
switch (visibility)
{
case Visibility.Visible:
samplePopIn?.Play();
break;
case Visibility.Hidden:
samplePopOut?.Play();
break;
}
}
}
}

View File

@ -1,45 +1,45 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Input;
namespace osu.Game.Graphics.Containers
{
public class OsuHoverContainer : OsuClickableContainer
{
protected Color4 HoverColour;
protected Color4 IdleColour = Color4.White;
protected virtual IEnumerable<Drawable> EffectTargets => new[] { Content };
protected override bool OnHover(InputState state)
{
EffectTargets.ForEach(d => d.FadeColour(HoverColour, 500, Easing.OutQuint));
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
EffectTargets.ForEach(d => d.FadeColour(IdleColour, 500, Easing.OutQuint));
base.OnHoverLost(state);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
HoverColour = colours.Yellow;
}
protected override void LoadComplete()
{
base.LoadComplete();
EffectTargets.ForEach(d => d.FadeColour(IdleColour));
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Input;
namespace osu.Game.Graphics.Containers
{
public class OsuHoverContainer : OsuClickableContainer
{
protected Color4 HoverColour;
protected Color4 IdleColour = Color4.White;
protected virtual IEnumerable<Drawable> EffectTargets => new[] { Content };
protected override bool OnHover(InputState state)
{
EffectTargets.ForEach(d => d.FadeColour(HoverColour, 500, Easing.OutQuint));
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
EffectTargets.ForEach(d => d.FadeColour(IdleColour, 500, Easing.OutQuint));
base.OnHoverLost(state);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
HoverColour = colours.Yellow;
}
protected override void LoadComplete()
{
base.LoadComplete();
EffectTargets.ForEach(d => d.FadeColour(IdleColour));
}
}
}

View File

@ -1,75 +1,75 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK.Input;
namespace osu.Game.Graphics.Containers
{
public class OsuScrollContainer : ScrollContainer
{
/// <summary>
/// Allows controlling the scroll bar from any position in the container using the right mouse button.
/// Uses the value of <see cref="DistanceDecayOnRightMouseScrollbar"/> to smoothly scroll to the dragged location.
/// </summary>
public bool RightMouseScrollbar = false;
/// <summary>
/// Controls the rate with which the target position is approached when performing a relative drag. Default is 0.02.
/// </summary>
public double DistanceDecayOnRightMouseScrollbar = 0.02;
private bool shouldPerformRightMouseScroll(InputState state) => RightMouseScrollbar && state.Mouse.IsPressed(MouseButton.Right);
private void scrollToRelative(float value) => ScrollTo(Clamp((value - Scrollbar.DrawSize[ScrollDim] / 2) / Scrollbar.Size[ScrollDim]), true, DistanceDecayOnRightMouseScrollbar);
private bool mouseScrollBarDragging;
protected override bool IsDragging => base.IsDragging || mouseScrollBarDragging;
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
if (shouldPerformRightMouseScroll(state))
{
scrollToRelative(state.Mouse.Position[ScrollDim]);
return true;
}
return base.OnMouseDown(state, args);
}
protected override bool OnDrag(InputState state)
{
if (mouseScrollBarDragging)
{
scrollToRelative(state.Mouse.Position[ScrollDim]);
return true;
}
return base.OnDrag(state);
}
protected override bool OnDragStart(InputState state)
{
if (shouldPerformRightMouseScroll(state))
{
mouseScrollBarDragging = true;
return true;
}
return base.OnDragStart(state);
}
protected override bool OnDragEnd(InputState state)
{
if (mouseScrollBarDragging)
{
mouseScrollBarDragging = false;
return true;
}
return base.OnDragEnd(state);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK.Input;
namespace osu.Game.Graphics.Containers
{
public class OsuScrollContainer : ScrollContainer
{
/// <summary>
/// Allows controlling the scroll bar from any position in the container using the right mouse button.
/// Uses the value of <see cref="DistanceDecayOnRightMouseScrollbar"/> to smoothly scroll to the dragged location.
/// </summary>
public bool RightMouseScrollbar = false;
/// <summary>
/// Controls the rate with which the target position is approached when performing a relative drag. Default is 0.02.
/// </summary>
public double DistanceDecayOnRightMouseScrollbar = 0.02;
private bool shouldPerformRightMouseScroll(InputState state) => RightMouseScrollbar && state.Mouse.IsPressed(MouseButton.Right);
private void scrollToRelative(float value) => ScrollTo(Clamp((value - Scrollbar.DrawSize[ScrollDim] / 2) / Scrollbar.Size[ScrollDim]), true, DistanceDecayOnRightMouseScrollbar);
private bool mouseScrollBarDragging;
protected override bool IsDragging => base.IsDragging || mouseScrollBarDragging;
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
if (shouldPerformRightMouseScroll(state))
{
scrollToRelative(state.Mouse.Position[ScrollDim]);
return true;
}
return base.OnMouseDown(state, args);
}
protected override bool OnDrag(InputState state)
{
if (mouseScrollBarDragging)
{
scrollToRelative(state.Mouse.Position[ScrollDim]);
return true;
}
return base.OnDrag(state);
}
protected override bool OnDragStart(InputState state)
{
if (shouldPerformRightMouseScroll(state))
{
mouseScrollBarDragging = true;
return true;
}
return base.OnDragStart(state);
}
protected override bool OnDragEnd(InputState state)
{
if (mouseScrollBarDragging)
{
mouseScrollBarDragging = false;
return true;
}
return base.OnDragEnd(state);
}
}
}

View File

@ -1,21 +1,21 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.Containers
{
public class OsuTextFlowContainer : TextFlowContainer
{
public OsuTextFlowContainer(Action<SpriteText> defaultCreationParameters = null) : base(defaultCreationParameters)
{
}
protected override SpriteText CreateSpriteText() => new OsuSpriteText();
public void AddIcon(FontAwesome icon, Action<SpriteText> creationParameters = null) => AddText(((char)icon).ToString(), creationParameters);
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.Containers
{
public class OsuTextFlowContainer : TextFlowContainer
{
public OsuTextFlowContainer(Action<SpriteText> defaultCreationParameters = null) : base(defaultCreationParameters)
{
}
protected override SpriteText CreateSpriteText() => new OsuSpriteText();
public void AddIcon(FontAwesome icon, Action<SpriteText> creationParameters = null) => AddText(((char)icon).ToString(), creationParameters);
}
}

View File

@ -1,78 +1,78 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Input;
using OpenTK;
using osu.Framework.Allocation;
using osu.Game.Configuration;
using osu.Framework.Configuration;
using osu.Framework.MathUtils;
namespace osu.Game.Graphics.Containers
{
public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition
{
public const float DEFAULT_PARALLAX_AMOUNT = 0.02f;
public float ParallaxAmount = DEFAULT_PARALLAX_AMOUNT;
private Bindable<bool> parallaxEnabled;
public ParallaxContainer()
{
RelativeSizeAxes = Axes.Both;
AddInternal(content = new Container
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});
}
private readonly Container content;
private InputManager input;
protected override Container<Drawable> Content => content;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
parallaxEnabled = config.GetBindable<bool>(OsuSetting.MenuParallax);
parallaxEnabled.ValueChanged += delegate
{
if (!parallaxEnabled)
{
content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint);
content.Scale = new Vector2(1 + ParallaxAmount);
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
input = GetContainingInputManager();
}
private bool firstUpdate = true;
protected override void Update()
{
base.Update();
if (parallaxEnabled)
{
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount;
double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000);
content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint);
content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint);
}
firstUpdate = false;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Input;
using OpenTK;
using osu.Framework.Allocation;
using osu.Game.Configuration;
using osu.Framework.Configuration;
using osu.Framework.MathUtils;
namespace osu.Game.Graphics.Containers
{
public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition
{
public const float DEFAULT_PARALLAX_AMOUNT = 0.02f;
public float ParallaxAmount = DEFAULT_PARALLAX_AMOUNT;
private Bindable<bool> parallaxEnabled;
public ParallaxContainer()
{
RelativeSizeAxes = Axes.Both;
AddInternal(content = new Container
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});
}
private readonly Container content;
private InputManager input;
protected override Container<Drawable> Content => content;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
parallaxEnabled = config.GetBindable<bool>(OsuSetting.MenuParallax);
parallaxEnabled.ValueChanged += delegate
{
if (!parallaxEnabled)
{
content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint);
content.Scale = new Vector2(1 + ParallaxAmount);
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
input = GetContainingInputManager();
}
private bool firstUpdate = true;
protected override void Update()
{
base.Update();
if (parallaxEnabled)
{
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount;
double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000);
content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint);
content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint);
}
firstUpdate = false;
}
}
}

View File

@ -1,13 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.Containers
{
public class ReverseChildIDFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable
{
protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.Containers
{
public class ReverseChildIDFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable
{
protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
}
}

View File

@ -1,194 +1,194 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.Containers
{
/// <summary>
/// A container that can scroll to each section inside it.
/// </summary>
public class SectionsContainer<T> : Container<T>
where T : Drawable
{
private Drawable expandableHeader, fixedHeader, footer, headerBackground;
private readonly ScrollContainer scrollContainer;
private readonly Container headerBackgroundContainer;
private readonly FlowContainer<T> scrollContentContainer;
protected override Container<T> Content => scrollContentContainer;
public Drawable ExpandableHeader
{
get { return expandableHeader; }
set
{
if (value == expandableHeader) return;
expandableHeader?.Expire();
expandableHeader = value;
if (value == null) return;
AddInternal(expandableHeader);
lastKnownScroll = float.NaN;
}
}
public Drawable FixedHeader
{
get { return fixedHeader; }
set
{
if (value == fixedHeader) return;
fixedHeader?.Expire();
fixedHeader = value;
if (value == null) return;
AddInternal(fixedHeader);
lastKnownScroll = float.NaN;
}
}
public Drawable Footer
{
get { return footer; }
set
{
if (value == footer) return;
if (footer != null)
scrollContainer.Remove(footer);
footer = value;
if (value == null) return;
footer.Anchor |= Anchor.y2;
footer.Origin |= Anchor.y2;
scrollContainer.Add(footer);
lastKnownScroll = float.NaN;
}
}
public Drawable HeaderBackground
{
get { return headerBackground; }
set
{
if (value == headerBackground) return;
headerBackgroundContainer.Clear();
headerBackground = value;
if (value == null) return;
headerBackgroundContainer.Add(headerBackground);
lastKnownScroll = float.NaN;
}
}
public Bindable<T> SelectedSection { get; } = new Bindable<T>();
protected virtual FlowContainer<T> CreateScrollContentContainer()
=> new FillFlowContainer<T>
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
};
public override void Add(T drawable)
{
base.Add(drawable);
lastKnownScroll = float.NaN;
headerHeight = float.NaN;
footerHeight = float.NaN;
}
private float headerHeight, footerHeight;
private readonly MarginPadding originalSectionsMargin;
private void updateSectionsMargin()
{
if (!Children.Any()) return;
var newMargin = originalSectionsMargin;
newMargin.Top += headerHeight;
newMargin.Bottom += footerHeight;
scrollContentContainer.Margin = newMargin;
}
public SectionsContainer()
{
AddInternal(scrollContainer = new ScrollContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
ScrollbarVisible = false,
Children = new Drawable[] { scrollContentContainer = CreateScrollContentContainer() }
});
AddInternal(headerBackgroundContainer = new Container
{
RelativeSizeAxes = Axes.X
});
originalSectionsMargin = scrollContentContainer.Margin;
}
public void ScrollTo(Drawable section) => scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - (FixedHeader?.BoundingBox.Height ?? 0));
public void ScrollToTop() => scrollContainer.ScrollTo(0);
private float lastKnownScroll;
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
float headerH = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
float footerH = Footer?.LayoutSize.Y ?? 0;
if (headerH != headerHeight || footerH != footerHeight)
{
headerHeight = headerH;
footerHeight = footerH;
updateSectionsMargin();
}
float currentScroll = scrollContainer.Current;
if (currentScroll != lastKnownScroll)
{
lastKnownScroll = currentScroll;
if (ExpandableHeader != null && FixedHeader != null)
{
float offset = Math.Min(ExpandableHeader.LayoutSize.Y, currentScroll);
ExpandableHeader.Y = -offset;
FixedHeader.Y = -offset + ExpandableHeader.LayoutSize.Y;
}
headerBackgroundContainer.Height = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
headerBackgroundContainer.Y = ExpandableHeader?.Y ?? 0;
T bestMatch = null;
float minDiff = float.MaxValue;
float scrollOffset = FixedHeader?.LayoutSize.Y ?? 0;
foreach (var section in Children)
{
float diff = Math.Abs(scrollContainer.GetChildPosInContent(section) - currentScroll - scrollOffset);
if (diff < minDiff)
{
minDiff = diff;
bestMatch = section;
}
}
if (bestMatch != null)
SelectedSection.Value = bestMatch;
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.Containers
{
/// <summary>
/// A container that can scroll to each section inside it.
/// </summary>
public class SectionsContainer<T> : Container<T>
where T : Drawable
{
private Drawable expandableHeader, fixedHeader, footer, headerBackground;
private readonly ScrollContainer scrollContainer;
private readonly Container headerBackgroundContainer;
private readonly FlowContainer<T> scrollContentContainer;
protected override Container<T> Content => scrollContentContainer;
public Drawable ExpandableHeader
{
get { return expandableHeader; }
set
{
if (value == expandableHeader) return;
expandableHeader?.Expire();
expandableHeader = value;
if (value == null) return;
AddInternal(expandableHeader);
lastKnownScroll = float.NaN;
}
}
public Drawable FixedHeader
{
get { return fixedHeader; }
set
{
if (value == fixedHeader) return;
fixedHeader?.Expire();
fixedHeader = value;
if (value == null) return;
AddInternal(fixedHeader);
lastKnownScroll = float.NaN;
}
}
public Drawable Footer
{
get { return footer; }
set
{
if (value == footer) return;
if (footer != null)
scrollContainer.Remove(footer);
footer = value;
if (value == null) return;
footer.Anchor |= Anchor.y2;
footer.Origin |= Anchor.y2;
scrollContainer.Add(footer);
lastKnownScroll = float.NaN;
}
}
public Drawable HeaderBackground
{
get { return headerBackground; }
set
{
if (value == headerBackground) return;
headerBackgroundContainer.Clear();
headerBackground = value;
if (value == null) return;
headerBackgroundContainer.Add(headerBackground);
lastKnownScroll = float.NaN;
}
}
public Bindable<T> SelectedSection { get; } = new Bindable<T>();
protected virtual FlowContainer<T> CreateScrollContentContainer()
=> new FillFlowContainer<T>
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
};
public override void Add(T drawable)
{
base.Add(drawable);
lastKnownScroll = float.NaN;
headerHeight = float.NaN;
footerHeight = float.NaN;
}
private float headerHeight, footerHeight;
private readonly MarginPadding originalSectionsMargin;
private void updateSectionsMargin()
{
if (!Children.Any()) return;
var newMargin = originalSectionsMargin;
newMargin.Top += headerHeight;
newMargin.Bottom += footerHeight;
scrollContentContainer.Margin = newMargin;
}
public SectionsContainer()
{
AddInternal(scrollContainer = new ScrollContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
ScrollbarVisible = false,
Children = new Drawable[] { scrollContentContainer = CreateScrollContentContainer() }
});
AddInternal(headerBackgroundContainer = new Container
{
RelativeSizeAxes = Axes.X
});
originalSectionsMargin = scrollContentContainer.Margin;
}
public void ScrollTo(Drawable section) => scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - (FixedHeader?.BoundingBox.Height ?? 0));
public void ScrollToTop() => scrollContainer.ScrollTo(0);
private float lastKnownScroll;
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
float headerH = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
float footerH = Footer?.LayoutSize.Y ?? 0;
if (headerH != headerHeight || footerH != footerHeight)
{
headerHeight = headerH;
footerHeight = footerH;
updateSectionsMargin();
}
float currentScroll = scrollContainer.Current;
if (currentScroll != lastKnownScroll)
{
lastKnownScroll = currentScroll;
if (ExpandableHeader != null && FixedHeader != null)
{
float offset = Math.Min(ExpandableHeader.LayoutSize.Y, currentScroll);
ExpandableHeader.Y = -offset;
FixedHeader.Y = -offset + ExpandableHeader.LayoutSize.Y;
}
headerBackgroundContainer.Height = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
headerBackgroundContainer.Y = ExpandableHeader?.Y ?? 0;
T bestMatch = null;
float minDiff = float.MaxValue;
float scrollOffset = FixedHeader?.LayoutSize.Y ?? 0;
foreach (var section in Children)
{
float diff = Math.Abs(scrollContainer.GetChildPosInContent(section) - currentScroll - scrollOffset);
if (diff < minDiff)
{
minDiff = diff;
bestMatch = section;
}
}
if (bestMatch != null)
SelectedSection.Value = bestMatch;
}
}
}
}

View File

@ -1,67 +1,67 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
namespace osu.Game.Graphics.Cursor
{
/// <summary>
/// A container which provides a <see cref="MenuCursor"/> which can be overridden by hovered <see cref="Drawable"/>s.
/// </summary>
public class CursorOverrideContainer : Container, IProvideCursor
{
protected override Container<Drawable> Content => content;
private readonly Container content;
/// <summary>
/// Whether any cursors can be displayed.
/// </summary>
public bool CanShowCursor = true;
public CursorContainer Cursor { get; }
public bool ProvidingUserCursor => true;
public CursorOverrideContainer()
{
AddRangeInternal(new Drawable[]
{
Cursor = new MenuCursor { State = Visibility.Hidden },
content = new Container { RelativeSizeAxes = Axes.Both }
});
}
private InputManager inputManager;
protected override void LoadComplete()
{
base.LoadComplete();
inputManager = GetContainingInputManager();
}
private IProvideCursor currentTarget;
protected override void Update()
{
base.Update();
if (!CanShowCursor)
{
currentTarget?.Cursor?.Hide();
return;
}
var newTarget = inputManager.HoveredDrawables.OfType<IProvideCursor>().FirstOrDefault(t => t.ProvidingUserCursor) ?? this;
if (currentTarget == newTarget)
return;
currentTarget?.Cursor?.Hide();
newTarget.Cursor?.Show();
currentTarget = newTarget;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
namespace osu.Game.Graphics.Cursor
{
/// <summary>
/// A container which provides a <see cref="MenuCursor"/> which can be overridden by hovered <see cref="Drawable"/>s.
/// </summary>
public class CursorOverrideContainer : Container, IProvideCursor
{
protected override Container<Drawable> Content => content;
private readonly Container content;
/// <summary>
/// Whether any cursors can be displayed.
/// </summary>
public bool CanShowCursor = true;
public CursorContainer Cursor { get; }
public bool ProvidingUserCursor => true;
public CursorOverrideContainer()
{
AddRangeInternal(new Drawable[]
{
Cursor = new MenuCursor { State = Visibility.Hidden },
content = new Container { RelativeSizeAxes = Axes.Both }
});
}
private InputManager inputManager;
protected override void LoadComplete()
{
base.LoadComplete();
inputManager = GetContainingInputManager();
}
private IProvideCursor currentTarget;
protected override void Update()
{
base.Update();
if (!CanShowCursor)
{
currentTarget?.Cursor?.Hide();
return;
}
var newTarget = inputManager.HoveredDrawables.OfType<IProvideCursor>().FirstOrDefault(t => t.ProvidingUserCursor) ?? this;
if (currentTarget == newTarget)
return;
currentTarget?.Cursor?.Hide();
newTarget.Cursor?.Show();
currentTarget = newTarget;
}
}
}

View File

@ -1,26 +1,26 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
namespace osu.Game.Graphics.Cursor
{
/// <summary>
/// Interface for <see cref="IDrawable"/>s that display cursors which can replace the user's cursor.
/// </summary>
public interface IProvideCursor : IDrawable
{
/// <summary>
/// The cursor provided by this <see cref="IDrawable"/>.
/// May be null if no cursor should be visible.
/// </summary>
CursorContainer Cursor { get; }
/// <summary>
/// Whether <see cref="Cursor"/> should be displayed as the singular user cursor. This will temporarily hide any other user cursor.
/// This value is checked every frame and may be used to control whether multiple cursors are displayed (e.g. watching replays).
/// </summary>
bool ProvidingUserCursor { get; }
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
namespace osu.Game.Graphics.Cursor
{
/// <summary>
/// Interface for <see cref="IDrawable"/>s that display cursors which can replace the user's cursor.
/// </summary>
public interface IProvideCursor : IDrawable
{
/// <summary>
/// The cursor provided by this <see cref="IDrawable"/>.
/// May be null if no cursor should be visible.
/// </summary>
CursorContainer Cursor { get; }
/// <summary>
/// Whether <see cref="Cursor"/> should be displayed as the singular user cursor. This will temporarily hide any other user cursor.
/// This value is checked every frame and may be used to control whether multiple cursors are displayed (e.g. watching replays).
/// </summary>
bool ProvidingUserCursor { get; }
}
}

View File

@ -1,157 +1,157 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Configuration;
using System;
using System.Diagnostics;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Graphics.Cursor
{
public class MenuCursor : CursorContainer
{
protected override Drawable CreateCursor() => new Cursor();
private Bindable<bool> cursorRotate;
private bool dragging;
private bool startRotation;
protected override bool OnMouseMove(InputState state)
{
if (cursorRotate && dragging)
{
Debug.Assert(state.Mouse.PositionMouseDown != null);
// don't start rotating until we're moved a minimum distance away from the mouse down location,
// else it can have an annoying effect.
// ReSharper disable once PossibleInvalidOperationException
startRotation |= Vector2Extensions.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30;
if (startRotation)
{
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value;
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
// Always rotate in the direction of least distance
float diff = (degrees - ActiveCursor.Rotation) % 360;
if (diff < -180) diff += 360;
if (diff > 180) diff -= 360;
degrees = ActiveCursor.Rotation + diff;
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
}
}
return base.OnMouseMove(state);
}
protected override bool OnDragStart(InputState state)
{
dragging = true;
return base.OnDragStart(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
ActiveCursor.Scale = new Vector2(1);
ActiveCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
if (!state.Mouse.HasMainButtonPressed)
{
dragging = false;
startRotation = false;
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
ActiveCursor.ScaleTo(1, 500, Easing.OutElastic);
}
return base.OnMouseUp(state, args);
}
protected override bool OnClick(InputState state)
{
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
return base.OnClick(state);
}
protected override void PopIn()
{
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
ActiveCursor.FadeTo(0, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(0.6f, 250, Easing.In);
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
cursorRotate = config.GetBindable<bool>(OsuSetting.CursorRotation);
}
public class Cursor : Container
{
private Container cursorContainer;
private Bindable<double> cursorScale;
private const float base_scale = 0.15f;
public Sprite AdditiveLayer;
public Cursor()
{
AutoSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, TextureStore textures, OsuColour colour)
{
Children = new Drawable[]
{
cursorContainer = new Container
{
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Sprite
{
Texture = textures.Get(@"Cursor/menu-cursor"),
},
AdditiveLayer = new Sprite
{
Blending = BlendingMode.Additive,
Colour = colour.Pink,
Alpha = 0,
Texture = textures.Get(@"Cursor/menu-cursor-additive"),
},
}
}
};
cursorScale = config.GetBindable<double>(OsuSetting.MenuCursorSize);
cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale * base_scale);
cursorScale.TriggerChange();
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Configuration;
using System;
using System.Diagnostics;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Graphics.Cursor
{
public class MenuCursor : CursorContainer
{
protected override Drawable CreateCursor() => new Cursor();
private Bindable<bool> cursorRotate;
private bool dragging;
private bool startRotation;
protected override bool OnMouseMove(InputState state)
{
if (cursorRotate && dragging)
{
Debug.Assert(state.Mouse.PositionMouseDown != null);
// don't start rotating until we're moved a minimum distance away from the mouse down location,
// else it can have an annoying effect.
// ReSharper disable once PossibleInvalidOperationException
startRotation |= Vector2Extensions.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30;
if (startRotation)
{
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value;
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
// Always rotate in the direction of least distance
float diff = (degrees - ActiveCursor.Rotation) % 360;
if (diff < -180) diff += 360;
if (diff > 180) diff -= 360;
degrees = ActiveCursor.Rotation + diff;
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
}
}
return base.OnMouseMove(state);
}
protected override bool OnDragStart(InputState state)
{
dragging = true;
return base.OnDragStart(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
ActiveCursor.Scale = new Vector2(1);
ActiveCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
if (!state.Mouse.HasMainButtonPressed)
{
dragging = false;
startRotation = false;
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
ActiveCursor.ScaleTo(1, 500, Easing.OutElastic);
}
return base.OnMouseUp(state, args);
}
protected override bool OnClick(InputState state)
{
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
return base.OnClick(state);
}
protected override void PopIn()
{
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
ActiveCursor.FadeTo(0, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(0.6f, 250, Easing.In);
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
cursorRotate = config.GetBindable<bool>(OsuSetting.CursorRotation);
}
public class Cursor : Container
{
private Container cursorContainer;
private Bindable<double> cursorScale;
private const float base_scale = 0.15f;
public Sprite AdditiveLayer;
public Cursor()
{
AutoSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, TextureStore textures, OsuColour colour)
{
Children = new Drawable[]
{
cursorContainer = new Container
{
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Sprite
{
Texture = textures.Get(@"Cursor/menu-cursor"),
},
AdditiveLayer = new Sprite
{
Blending = BlendingMode.Additive,
Colour = colour.Pink,
Alpha = 0,
Texture = textures.Get(@"Cursor/menu-cursor-additive"),
},
}
}
};
cursorScale = config.GetBindable<double>(OsuSetting.MenuCursorSize);
cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale * base_scale);
cursorScale.TriggerChange();
}
}
}
}

View File

@ -1,14 +1,14 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.Cursor
{
public class OsuContextMenuContainer : ContextMenuContainer
{
protected override Menu CreateMenu() => new OsuContextMenu();
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.Cursor
{
public class OsuContextMenuContainer : ContextMenuContainer
{
protected override Menu CreateMenu() => new OsuContextMenu();
}
}

View File

@ -1,105 +1,105 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.Cursor
{
public class OsuTooltipContainer : TooltipContainer
{
protected override ITooltip CreateTooltip() => new OsuTooltip();
public OsuTooltipContainer(CursorContainer cursor) : base(cursor)
{
}
public class OsuTooltip : Tooltip
{
private readonly Box background;
private readonly OsuSpriteText text;
private bool instantMovement = true;
public override string TooltipText
{
set
{
if (value == text.Text) return;
text.Text = value;
if (IsPresent)
{
AutoSizeDuration = 250;
background.FlashColour(OsuColour.Gray(0.4f), 1000, Easing.OutQuint);
}
else
AutoSizeDuration = 0;
}
}
private const float text_size = 16;
public OsuTooltip()
{
AutoSizeEasing = Easing.OutQuint;
CornerRadius = 5;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(40),
Radius = 5,
};
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.9f,
},
text = new OsuSpriteText
{
TextSize = text_size,
Padding = new MarginPadding(5),
Font = @"Exo2.0-Regular",
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
background.Colour = colour.Gray3;
}
protected override void PopIn()
{
instantMovement |= !IsPresent;
this.FadeIn(500, Easing.OutQuint);
}
protected override void PopOut() => this.Delay(150).FadeOut(500, Easing.OutQuint);
public override void Move(Vector2 pos)
{
if (instantMovement)
{
Position = pos;
instantMovement = false;
}
else
{
this.MoveTo(pos, 200, Easing.OutQuint);
}
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.Cursor
{
public class OsuTooltipContainer : TooltipContainer
{
protected override ITooltip CreateTooltip() => new OsuTooltip();
public OsuTooltipContainer(CursorContainer cursor) : base(cursor)
{
}
public class OsuTooltip : Tooltip
{
private readonly Box background;
private readonly OsuSpriteText text;
private bool instantMovement = true;
public override string TooltipText
{
set
{
if (value == text.Text) return;
text.Text = value;
if (IsPresent)
{
AutoSizeDuration = 250;
background.FlashColour(OsuColour.Gray(0.4f), 1000, Easing.OutQuint);
}
else
AutoSizeDuration = 0;
}
}
private const float text_size = 16;
public OsuTooltip()
{
AutoSizeEasing = Easing.OutQuint;
CornerRadius = 5;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(40),
Radius = 5,
};
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.9f,
},
text = new OsuSpriteText
{
TextSize = text_size,
Padding = new MarginPadding(5),
Font = @"Exo2.0-Regular",
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
background.Colour = colour.Gray3;
}
protected override void PopIn()
{
instantMovement |= !IsPresent;
this.FadeIn(500, Easing.OutQuint);
}
protected override void PopOut() => this.Delay(150).FadeOut(500, Easing.OutQuint);
public override void Move(Vector2 pos)
{
if (instantMovement)
{
Position = pos;
instantMovement = false;
}
else
{
this.MoveTo(pos, 200, Easing.OutQuint);
}
}
}
}
}

View File

@ -1,65 +1,65 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics
{
public class DrawableDate : OsuSpriteText, IHasTooltip
{
private readonly DateTimeOffset date;
public DrawableDate(DateTimeOffset date)
{
AutoSizeAxes = Axes.Both;
Font = "Exo2.0-RegularItalic";
this.date = date.ToLocalTime();
}
[BackgroundDependencyLoader]
private void load()
{
updateTime();
}
protected override void LoadComplete()
{
base.LoadComplete();
Scheduler.Add(updateTimeWithReschedule);
}
private void updateTimeWithReschedule()
{
updateTime();
var diffToNow = DateTimeOffset.Now.Subtract(date);
double timeUntilNextUpdate = 1000;
if (diffToNow.TotalSeconds > 60)
{
timeUntilNextUpdate *= 60;
if (diffToNow.TotalMinutes > 60)
{
timeUntilNextUpdate *= 60;
if (diffToNow.TotalHours > 24)
timeUntilNextUpdate *= 24;
}
}
Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate);
}
public override bool HandleMouseInput => true;
private void updateTime() => Text = date.Humanize();
public string TooltipText => date.ToString();
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics
{
public class DrawableDate : OsuSpriteText, IHasTooltip
{
private readonly DateTimeOffset date;
public DrawableDate(DateTimeOffset date)
{
AutoSizeAxes = Axes.Both;
Font = "Exo2.0-RegularItalic";
this.date = date.ToLocalTime();
}
[BackgroundDependencyLoader]
private void load()
{
updateTime();
}
protected override void LoadComplete()
{
base.LoadComplete();
Scheduler.Add(updateTimeWithReschedule);
}
private void updateTimeWithReschedule()
{
updateTime();
var diffToNow = DateTimeOffset.Now.Subtract(date);
double timeUntilNextUpdate = 1000;
if (diffToNow.TotalSeconds > 60)
{
timeUntilNextUpdate *= 60;
if (diffToNow.TotalMinutes > 60)
{
timeUntilNextUpdate *= 60;
if (diffToNow.TotalHours > 24)
timeUntilNextUpdate *= 24;
}
}
Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate);
}
public override bool HandleMouseInput => true;
private void updateTime() => Text = date.Humanize();
public string TooltipText => date.ToString();
}
}

View File

@ -1,38 +1,38 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Graphics
{
/// <summary>
/// A type of drawable that has an accent colour.
/// The accent colour is used to colorize various objects inside a drawable
/// without colorizing the drawable itself.
/// </summary>
public interface IHasAccentColour : IDrawable
{
Color4 AccentColour { get; set; }
}
public static class AccentedColourExtensions
{
/// <summary>
/// Smoothly adjusts <see cref="IHasAccentColour.AccentColour"/> over time.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> FadeAccent<T>(this T accentedDrawable, Color4 newColour, double duration = 0, Easing easing = Easing.None)
where T : IHasAccentColour
=> accentedDrawable.TransformTo(nameof(accentedDrawable.AccentColour), newColour, duration, easing);
/// <summary>
/// Smoothly adjusts <see cref="IHasAccentColour.AccentColour"/> over time.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> FadeAccent<T>(this TransformSequence<T> t, Color4 newColour, double duration = 0, Easing easing = Easing.None)
where T : Drawable, IHasAccentColour
=> t.Append(o => o.FadeAccent(newColour, duration, easing));
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Graphics
{
/// <summary>
/// A type of drawable that has an accent colour.
/// The accent colour is used to colorize various objects inside a drawable
/// without colorizing the drawable itself.
/// </summary>
public interface IHasAccentColour : IDrawable
{
Color4 AccentColour { get; set; }
}
public static class AccentedColourExtensions
{
/// <summary>
/// Smoothly adjusts <see cref="IHasAccentColour.AccentColour"/> over time.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> FadeAccent<T>(this T accentedDrawable, Color4 newColour, double duration = 0, Easing easing = Easing.None)
where T : IHasAccentColour
=> accentedDrawable.TransformTo(nameof(accentedDrawable.AccentColour), newColour, duration, easing);
/// <summary>
/// Smoothly adjusts <see cref="IHasAccentColour.AccentColour"/> over time.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> FadeAccent<T>(this TransformSequence<T> t, Color4 newColour, double duration = 0, Easing easing = Easing.None)
where T : Drawable, IHasAccentColour
=> t.Append(o => o.FadeAccent(newColour, duration, easing));
}
}

View File

@ -1,96 +1,96 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK.Graphics;
namespace osu.Game.Graphics
{
public class OsuColour
{
public static Color4 Gray(float amt) => new Color4(amt, amt, amt, 1f);
public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255);
public static Color4 FromHex(string hex)
{
if (hex[0] == '#')
hex = hex.Substring(1);
switch (hex.Length)
{
default:
throw new ArgumentException(@"Invalid hex string length!");
case 3:
return new Color4(
(byte)(Convert.ToByte(hex.Substring(0, 1), 16) * 17),
(byte)(Convert.ToByte(hex.Substring(1, 1), 16) * 17),
(byte)(Convert.ToByte(hex.Substring(2, 1), 16) * 17),
255);
case 6:
return new Color4(
Convert.ToByte(hex.Substring(0, 2), 16),
Convert.ToByte(hex.Substring(2, 2), 16),
Convert.ToByte(hex.Substring(4, 2), 16),
255);
}
}
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = FromHex(@"eeeeff");
public readonly Color4 PurpleLight = FromHex(@"aa88ff");
public readonly Color4 Purple = FromHex(@"8866ee");
public readonly Color4 PurpleDark = FromHex(@"6644cc");
public readonly Color4 PurpleDarker = FromHex(@"441188");
public readonly Color4 PinkLighter = FromHex(@"ffddee");
public readonly Color4 PinkLight = FromHex(@"ff99cc");
public readonly Color4 Pink = FromHex(@"ff66aa");
public readonly Color4 PinkDark = FromHex(@"cc5288");
public readonly Color4 PinkDarker = FromHex(@"bb1177");
public readonly Color4 BlueLighter = FromHex(@"ddffff");
public readonly Color4 BlueLight = FromHex(@"99eeff");
public readonly Color4 Blue = FromHex(@"66ccff");
public readonly Color4 BlueDark = FromHex(@"44aadd");
public readonly Color4 BlueDarker = FromHex(@"2299bb");
public readonly Color4 YellowLighter = FromHex(@"ffffdd");
public readonly Color4 YellowLight = FromHex(@"ffdd55");
public readonly Color4 Yellow = FromHex(@"ffcc22");
public readonly Color4 YellowDark = FromHex(@"eeaa00");
public readonly Color4 YellowDarker = FromHex(@"cc6600");
public readonly Color4 GreenLighter = FromHex(@"eeffcc");
public readonly Color4 GreenLight = FromHex(@"b3d944");
public readonly Color4 Green = FromHex(@"88b300");
public readonly Color4 GreenDark = FromHex(@"668800");
public readonly Color4 GreenDarker = FromHex(@"445500");
public readonly Color4 Gray0 = FromHex(@"000");
public readonly Color4 Gray1 = FromHex(@"111");
public readonly Color4 Gray2 = FromHex(@"222");
public readonly Color4 Gray3 = FromHex(@"333");
public readonly Color4 Gray4 = FromHex(@"444");
public readonly Color4 Gray5 = FromHex(@"555");
public readonly Color4 Gray6 = FromHex(@"666");
public readonly Color4 Gray7 = FromHex(@"777");
public readonly Color4 Gray8 = FromHex(@"888");
public readonly Color4 Gray9 = FromHex(@"999");
public readonly Color4 GrayA = FromHex(@"aaa");
public readonly Color4 GrayB = FromHex(@"bbb");
public readonly Color4 GrayC = FromHex(@"ccc");
public readonly Color4 GrayD = FromHex(@"ddd");
public readonly Color4 GrayE = FromHex(@"eee");
public readonly Color4 GrayF = FromHex(@"fff");
public readonly Color4 RedLighter = FromHex(@"ffeded");
public readonly Color4 RedLight = FromHex(@"ed7787");
public readonly Color4 Red = FromHex(@"ed1121");
public readonly Color4 RedDark = FromHex(@"ba0011");
public readonly Color4 RedDarker = FromHex(@"870000");
public readonly Color4 ChatBlue = FromHex(@"17292e");
public readonly Color4 ContextMenuGray = FromHex(@"223034");
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK.Graphics;
namespace osu.Game.Graphics
{
public class OsuColour
{
public static Color4 Gray(float amt) => new Color4(amt, amt, amt, 1f);
public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255);
public static Color4 FromHex(string hex)
{
if (hex[0] == '#')
hex = hex.Substring(1);
switch (hex.Length)
{
default:
throw new ArgumentException(@"Invalid hex string length!");
case 3:
return new Color4(
(byte)(Convert.ToByte(hex.Substring(0, 1), 16) * 17),
(byte)(Convert.ToByte(hex.Substring(1, 1), 16) * 17),
(byte)(Convert.ToByte(hex.Substring(2, 1), 16) * 17),
255);
case 6:
return new Color4(
Convert.ToByte(hex.Substring(0, 2), 16),
Convert.ToByte(hex.Substring(2, 2), 16),
Convert.ToByte(hex.Substring(4, 2), 16),
255);
}
}
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = FromHex(@"eeeeff");
public readonly Color4 PurpleLight = FromHex(@"aa88ff");
public readonly Color4 Purple = FromHex(@"8866ee");
public readonly Color4 PurpleDark = FromHex(@"6644cc");
public readonly Color4 PurpleDarker = FromHex(@"441188");
public readonly Color4 PinkLighter = FromHex(@"ffddee");
public readonly Color4 PinkLight = FromHex(@"ff99cc");
public readonly Color4 Pink = FromHex(@"ff66aa");
public readonly Color4 PinkDark = FromHex(@"cc5288");
public readonly Color4 PinkDarker = FromHex(@"bb1177");
public readonly Color4 BlueLighter = FromHex(@"ddffff");
public readonly Color4 BlueLight = FromHex(@"99eeff");
public readonly Color4 Blue = FromHex(@"66ccff");
public readonly Color4 BlueDark = FromHex(@"44aadd");
public readonly Color4 BlueDarker = FromHex(@"2299bb");
public readonly Color4 YellowLighter = FromHex(@"ffffdd");
public readonly Color4 YellowLight = FromHex(@"ffdd55");
public readonly Color4 Yellow = FromHex(@"ffcc22");
public readonly Color4 YellowDark = FromHex(@"eeaa00");
public readonly Color4 YellowDarker = FromHex(@"cc6600");
public readonly Color4 GreenLighter = FromHex(@"eeffcc");
public readonly Color4 GreenLight = FromHex(@"b3d944");
public readonly Color4 Green = FromHex(@"88b300");
public readonly Color4 GreenDark = FromHex(@"668800");
public readonly Color4 GreenDarker = FromHex(@"445500");
public readonly Color4 Gray0 = FromHex(@"000");
public readonly Color4 Gray1 = FromHex(@"111");
public readonly Color4 Gray2 = FromHex(@"222");
public readonly Color4 Gray3 = FromHex(@"333");
public readonly Color4 Gray4 = FromHex(@"444");
public readonly Color4 Gray5 = FromHex(@"555");
public readonly Color4 Gray6 = FromHex(@"666");
public readonly Color4 Gray7 = FromHex(@"777");
public readonly Color4 Gray8 = FromHex(@"888");
public readonly Color4 Gray9 = FromHex(@"999");
public readonly Color4 GrayA = FromHex(@"aaa");
public readonly Color4 GrayB = FromHex(@"bbb");
public readonly Color4 GrayC = FromHex(@"ccc");
public readonly Color4 GrayD = FromHex(@"ddd");
public readonly Color4 GrayE = FromHex(@"eee");
public readonly Color4 GrayF = FromHex(@"fff");
public readonly Color4 RedLighter = FromHex(@"ffeded");
public readonly Color4 RedLight = FromHex(@"ed7787");
public readonly Color4 Red = FromHex(@"ed1121");
public readonly Color4 RedDark = FromHex(@"ba0011");
public readonly Color4 RedDarker = FromHex(@"870000");
public readonly Color4 ChatBlue = FromHex(@"17292e");
public readonly Color4 ContextMenuGray = FromHex(@"223034");
}
}

View File

@ -1,110 +1,110 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Drawing.Imaging;
using System.IO;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Platform;
using osu.Game.Configuration;
using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Game.Graphics
{
public class ScreenshotManager : Container, IKeyBindingHandler<GlobalAction>, IHandleGlobalInput
{
private Bindable<ScreenshotFormat> screenshotFormat;
private GameHost host;
private Storage storage;
private NotificationOverlay notificationOverlay;
private SampleChannel shutter;
[BackgroundDependencyLoader]
private void load(GameHost host, OsuConfigManager config, Storage storage, NotificationOverlay notificationOverlay, AudioManager audio)
{
this.host = host;
this.storage = storage.GetStorageForDirectory(@"screenshots");
this.notificationOverlay = notificationOverlay;
screenshotFormat = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat);
shutter = audio.Sample.Get("UI/shutter");
}
public bool OnPressed(GlobalAction action)
{
switch (action)
{
case GlobalAction.TakeScreenshot:
shutter.Play();
TakeScreenshotAsync();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => false;
public async void TakeScreenshotAsync()
{
using (var bitmap = await host.TakeScreenshotAsync())
{
var fileName = getFileName();
if (fileName == null) return;
var stream = storage.GetStream(fileName, FileAccess.Write);
switch (screenshotFormat.Value)
{
case ScreenshotFormat.Png:
bitmap.Save(stream, ImageFormat.Png);
break;
case ScreenshotFormat.Jpg:
bitmap.Save(stream, ImageFormat.Jpeg);
break;
default:
throw new ArgumentOutOfRangeException(nameof(screenshotFormat));
}
notificationOverlay.Post(new SimpleNotification
{
Text = $"{fileName} saved!",
Activated = () =>
{
storage.OpenInNativeExplorer();
return true;
}
});
}
}
private string getFileName()
{
var dt = DateTime.Now;
var fileExt = screenshotFormat.ToString().ToLower();
var withoutIndex = $"osu_{dt:yyyy-MM-dd_HH-mm-ss}.{fileExt}";
if (!storage.Exists(withoutIndex))
return withoutIndex;
for (ulong i = 1; i < ulong.MaxValue; i++)
{
var indexedName = $"osu_{dt:yyyy-MM-dd_HH-mm-ss}-{i}.{fileExt}";
if (!storage.Exists(indexedName))
return indexedName;
}
return null;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Drawing.Imaging;
using System.IO;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Platform;
using osu.Game.Configuration;
using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Game.Graphics
{
public class ScreenshotManager : Container, IKeyBindingHandler<GlobalAction>, IHandleGlobalInput
{
private Bindable<ScreenshotFormat> screenshotFormat;
private GameHost host;
private Storage storage;
private NotificationOverlay notificationOverlay;
private SampleChannel shutter;
[BackgroundDependencyLoader]
private void load(GameHost host, OsuConfigManager config, Storage storage, NotificationOverlay notificationOverlay, AudioManager audio)
{
this.host = host;
this.storage = storage.GetStorageForDirectory(@"screenshots");
this.notificationOverlay = notificationOverlay;
screenshotFormat = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat);
shutter = audio.Sample.Get("UI/shutter");
}
public bool OnPressed(GlobalAction action)
{
switch (action)
{
case GlobalAction.TakeScreenshot:
shutter.Play();
TakeScreenshotAsync();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => false;
public async void TakeScreenshotAsync()
{
using (var bitmap = await host.TakeScreenshotAsync())
{
var fileName = getFileName();
if (fileName == null) return;
var stream = storage.GetStream(fileName, FileAccess.Write);
switch (screenshotFormat.Value)
{
case ScreenshotFormat.Png:
bitmap.Save(stream, ImageFormat.Png);
break;
case ScreenshotFormat.Jpg:
bitmap.Save(stream, ImageFormat.Jpeg);
break;
default:
throw new ArgumentOutOfRangeException(nameof(screenshotFormat));
}
notificationOverlay.Post(new SimpleNotification
{
Text = $"{fileName} saved!",
Activated = () =>
{
storage.OpenInNativeExplorer();
return true;
}
});
}
}
private string getFileName()
{
var dt = DateTime.Now;
var fileExt = screenshotFormat.ToString().ToLower();
var withoutIndex = $"osu_{dt:yyyy-MM-dd_HH-mm-ss}.{fileExt}";
if (!storage.Exists(withoutIndex))
return withoutIndex;
for (ulong i = 1; i < ulong.MaxValue; i++)
{
var indexedName = $"osu_{dt:yyyy-MM-dd_HH-mm-ss}-{i}.{fileExt}";
if (!storage.Exists(indexedName))
return indexedName;
}
return null;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +1,63 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Graphics.Sprites
{
public class OsuSpriteText : SpriteText
{
public const float FONT_SIZE = 16;
public OsuSpriteText()
{
Shadow = true;
TextSize = FONT_SIZE;
}
protected override Drawable CreateFallbackCharacterDrawable()
{
var tex = GetTextureForCharacter('?');
if (tex != null)
{
float adjust = (RNG.NextSingle() - 0.5f) * 2;
return new Sprite
{
Texture = tex,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Scale = new Vector2(1 + adjust * 0.2f),
Rotation = adjust * 15,
Colour = Color4.White,
};
}
return base.CreateFallbackCharacterDrawable();
}
}
public static class OsuSpriteTextTransformExtensions
{
/// <summary>
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> TransformTextTo<T>(this T spriteText, string newText, double duration = 0, Easing easing = Easing.None)
where T : OsuSpriteText
=> spriteText.TransformTo(nameof(OsuSpriteText.Text), newText, duration, easing);
/// <summary>
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> TransformTextTo<T>(this TransformSequence<T> t, string newText, double duration = 0, Easing easing = Easing.None)
where T : OsuSpriteText
=> t.Append(o => o.TransformTextTo(newText, duration, easing));
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Graphics.Sprites
{
public class OsuSpriteText : SpriteText
{
public const float FONT_SIZE = 16;
public OsuSpriteText()
{
Shadow = true;
TextSize = FONT_SIZE;
}
protected override Drawable CreateFallbackCharacterDrawable()
{
var tex = GetTextureForCharacter('?');
if (tex != null)
{
float adjust = (RNG.NextSingle() - 0.5f) * 2;
return new Sprite
{
Texture = tex,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Scale = new Vector2(1 + adjust * 0.2f),
Rotation = adjust * 15,
Colour = Color4.White,
};
}
return base.CreateFallbackCharacterDrawable();
}
}
public static class OsuSpriteTextTransformExtensions
{
/// <summary>
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> TransformTextTo<T>(this T spriteText, string newText, double duration = 0, Easing easing = Easing.None)
where T : OsuSpriteText
=> spriteText.TransformTo(nameof(OsuSpriteText.Text), newText, duration, easing);
/// <summary>
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> TransformTextTo<T>(this TransformSequence<T> t, string newText, double duration = 0, Easing easing = Easing.None)
where T : OsuSpriteText
=> t.Append(o => o.TransformTextTo(newText, duration, easing));
}
}

View File

@ -1,18 +1,18 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
namespace osu.Game.Graphics.Textures
{
/// <summary>
/// A texture store that bypasses atlasing.
/// </summary>
public class LargeTextureStore : TextureStore
{
public LargeTextureStore(IResourceStore<RawTexture> store = null) : base(store, false)
{
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
namespace osu.Game.Graphics.Textures
{
/// <summary>
/// A texture store that bypasses atlasing.
/// </summary>
public class LargeTextureStore : TextureStore
{
public LargeTextureStore(IResourceStore<RawTexture> store = null) : base(store, false)
{
}
}
}

View File

@ -1,26 +1,26 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class BackButton : TwoLayerButton
{
public BackButton()
{
Text = @"back";
Icon = FontAwesome.fa_osu_left_o;
Anchor = Anchor.BottomLeft;
Origin = Anchor.BottomLeft;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.Pink;
HoverColour = colours.PinkDark;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class BackButton : TwoLayerButton
{
public BackButton()
{
Text = @"back";
Icon = FontAwesome.fa_osu_left_o;
Anchor = Anchor.BottomLeft;
Origin = Anchor.BottomLeft;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.Pink;
HoverColour = colours.PinkDark;
}
}
}

View File

@ -1,138 +1,138 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using System;
namespace osu.Game.Graphics.UserInterface
{
public class Bar : Container, IHasAccentColour
{
private readonly Box background;
private readonly Box bar;
private const int resize_duration = 250;
private const Easing easing = Easing.InOutCubic;
private float length;
/// <summary>
/// Length of the bar, ranges from 0 to 1
/// </summary>
public float Length
{
get
{
return length;
}
set
{
length = MathHelper.Clamp(value, 0, 1);
updateBarLength();
}
}
public Color4 BackgroundColour
{
get
{
return background.Colour;
}
set
{
background.Colour = value;
}
}
public Color4 AccentColour
{
get
{
return bar.Colour;
}
set
{
bar.Colour = value;
}
}
private BarDirection direction = BarDirection.LeftToRight;
public BarDirection Direction
{
get
{
return direction;
}
set
{
direction = value;
updateBarLength();
}
}
public Bar()
{
Children = new[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = new Color4(0, 0, 0, 0)
},
bar = new Box
{
RelativeSizeAxes = Axes.Both,
Width = 0,
},
};
}
private void updateBarLength()
{
switch (direction)
{
case BarDirection.LeftToRight:
case BarDirection.RightToLeft:
bar.ResizeTo(new Vector2(length, 1), resize_duration, easing);
break;
case BarDirection.TopToBottom:
case BarDirection.BottomToTop:
bar.ResizeTo(new Vector2(1, length), resize_duration, easing);
break;
}
switch (direction)
{
case BarDirection.LeftToRight:
case BarDirection.TopToBottom:
bar.Anchor = Anchor.TopLeft;
bar.Origin = Anchor.TopLeft;
break;
case BarDirection.RightToLeft:
case BarDirection.BottomToTop:
bar.Anchor = Anchor.BottomRight;
bar.Origin = Anchor.BottomRight;
break;
}
}
}
[Flags]
public enum BarDirection
{
LeftToRight = 1 << 0,
RightToLeft = 1 << 1,
TopToBottom = 1 << 2,
BottomToTop = 1 << 3,
Vertical = TopToBottom | BottomToTop,
Horizontal = LeftToRight | RightToLeft,
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using System;
namespace osu.Game.Graphics.UserInterface
{
public class Bar : Container, IHasAccentColour
{
private readonly Box background;
private readonly Box bar;
private const int resize_duration = 250;
private const Easing easing = Easing.InOutCubic;
private float length;
/// <summary>
/// Length of the bar, ranges from 0 to 1
/// </summary>
public float Length
{
get
{
return length;
}
set
{
length = MathHelper.Clamp(value, 0, 1);
updateBarLength();
}
}
public Color4 BackgroundColour
{
get
{
return background.Colour;
}
set
{
background.Colour = value;
}
}
public Color4 AccentColour
{
get
{
return bar.Colour;
}
set
{
bar.Colour = value;
}
}
private BarDirection direction = BarDirection.LeftToRight;
public BarDirection Direction
{
get
{
return direction;
}
set
{
direction = value;
updateBarLength();
}
}
public Bar()
{
Children = new[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = new Color4(0, 0, 0, 0)
},
bar = new Box
{
RelativeSizeAxes = Axes.Both,
Width = 0,
},
};
}
private void updateBarLength()
{
switch (direction)
{
case BarDirection.LeftToRight:
case BarDirection.RightToLeft:
bar.ResizeTo(new Vector2(length, 1), resize_duration, easing);
break;
case BarDirection.TopToBottom:
case BarDirection.BottomToTop:
bar.ResizeTo(new Vector2(1, length), resize_duration, easing);
break;
}
switch (direction)
{
case BarDirection.LeftToRight:
case BarDirection.TopToBottom:
bar.Anchor = Anchor.TopLeft;
bar.Origin = Anchor.TopLeft;
break;
case BarDirection.RightToLeft:
case BarDirection.BottomToTop:
bar.Anchor = Anchor.BottomRight;
bar.Origin = Anchor.BottomRight;
break;
}
}
}
[Flags]
public enum BarDirection
{
LeftToRight = 1 << 0,
RightToLeft = 1 << 1,
TopToBottom = 1 << 2,
BottomToTop = 1 << 3,
Vertical = TopToBottom | BottomToTop,
Horizontal = LeftToRight | RightToLeft,
}
}

View File

@ -1,77 +1,77 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Graphics.UserInterface
{
public class BarGraph : FillFlowContainer<Bar>
{
/// <summary>
/// Manually sets the max value, if null <see cref="Enumerable.Max(IEnumerable{float})"/> is instead used
/// </summary>
public float? MaxValue { get; set; }
private BarDirection direction = BarDirection.BottomToTop;
public new BarDirection Direction
{
get
{
return direction;
}
set
{
direction = value;
base.Direction = (direction & BarDirection.Horizontal) > 0 ? FillDirection.Vertical : FillDirection.Horizontal;
foreach (var bar in Children)
{
bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / Children.Count) : new Vector2(1.0f / Children.Count, 1);
bar.Direction = direction;
}
}
}
/// <summary>
/// A list of floats that defines the length of each <see cref="Bar"/>
/// </summary>
public IEnumerable<float> Values
{
set
{
List<Bar> bars = Children.ToList();
foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null }))
{
float length = MaxValue ?? value.Max();
if (length != 0)
length = bar.Value / length;
float size = value.Count();
if (size != 0)
size = 1.0f / size;
if (bar.Bar != null)
{
bar.Bar.Length = length;
bar.Bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, size) : new Vector2(size, 1);
}
else
{
Add(new Bar
{
RelativeSizeAxes = Axes.Both,
Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, size) : new Vector2(size, 1),
Length = length,
Direction = Direction,
});
}
}
//I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
RemoveRange(Children.Where((bar, index) => index >= value.Count()).ToList());
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Graphics.UserInterface
{
public class BarGraph : FillFlowContainer<Bar>
{
/// <summary>
/// Manually sets the max value, if null <see cref="Enumerable.Max(IEnumerable{float})"/> is instead used
/// </summary>
public float? MaxValue { get; set; }
private BarDirection direction = BarDirection.BottomToTop;
public new BarDirection Direction
{
get
{
return direction;
}
set
{
direction = value;
base.Direction = (direction & BarDirection.Horizontal) > 0 ? FillDirection.Vertical : FillDirection.Horizontal;
foreach (var bar in Children)
{
bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / Children.Count) : new Vector2(1.0f / Children.Count, 1);
bar.Direction = direction;
}
}
}
/// <summary>
/// A list of floats that defines the length of each <see cref="Bar"/>
/// </summary>
public IEnumerable<float> Values
{
set
{
List<Bar> bars = Children.ToList();
foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null }))
{
float length = MaxValue ?? value.Max();
if (length != 0)
length = bar.Value / length;
float size = value.Count();
if (size != 0)
size = 1.0f / size;
if (bar.Bar != null)
{
bar.Bar.Length = length;
bar.Bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, size) : new Vector2(size, 1);
}
else
{
Add(new Bar
{
RelativeSizeAxes = Axes.Both,
Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, size) : new Vector2(size, 1),
Length = length,
Direction = Direction,
});
}
}
//I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
RemoveRange(Children.Where((bar, index) => index >= value.Count()).ToList());
}
}
}
}

View File

@ -1,94 +1,94 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK;
using osu.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using System.Linq;
namespace osu.Game.Graphics.UserInterface
{
public class BreadcrumbControl<T> : OsuTabControl<T>
{
private const float padding = 10;
protected override TabItem<T> CreateTabItem(T value) => new BreadcrumbTabItem(value);
protected override float StripWidth() => base.StripWidth() - (padding + 8);
public BreadcrumbControl()
{
Height = 26;
TabContainer.Spacing = new Vector2(padding, 0f);
Current.ValueChanged += tab =>
{
foreach (var t in TabContainer.Children.OfType<BreadcrumbTabItem>())
{
var tIndex = TabContainer.IndexOf(t);
var tabIndex = TabContainer.IndexOf(TabMap[tab]);
t.State = tIndex < tabIndex ? Visibility.Hidden : Visibility.Visible;
t.Chevron.FadeTo(tIndex <= tabIndex ? 0f : 1f, 500, Easing.OutQuint);
}
};
}
private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility>
{
public event Action<Visibility> StateChanged;
public readonly SpriteIcon Chevron;
//don't allow clicking between transitions and don't make the chevron clickable
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceiveMouseInputAt(screenSpacePos);
public override bool HandleKeyboardInput => State == Visibility.Visible;
public override bool HandleMouseInput => State == Visibility.Visible;
private Visibility state;
public Visibility State
{
get { return state; }
set
{
if (value == state) return;
state = value;
const float transition_duration = 500;
if (State == Visibility.Visible)
{
this.FadeIn(transition_duration, Easing.OutQuint);
this.ScaleTo(new Vector2(1f), transition_duration, Easing.OutQuint);
}
else
{
this.FadeOut(transition_duration, Easing.OutQuint);
this.ScaleTo(new Vector2(0.8f, 1f), transition_duration, Easing.OutQuint);
}
StateChanged?.Invoke(State);
}
}
public BreadcrumbTabItem(T value) : base(value)
{
Text.TextSize = 16;
Padding = new MarginPadding { Right = padding + 8 }; //padding + chevron width
Add(Chevron = new SpriteIcon
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreLeft,
Size = new Vector2(12),
Icon = FontAwesome.fa_chevron_right,
Margin = new MarginPadding { Left = padding },
Alpha = 0f,
});
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK;
using osu.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using System.Linq;
namespace osu.Game.Graphics.UserInterface
{
public class BreadcrumbControl<T> : OsuTabControl<T>
{
private const float padding = 10;
protected override TabItem<T> CreateTabItem(T value) => new BreadcrumbTabItem(value);
protected override float StripWidth() => base.StripWidth() - (padding + 8);
public BreadcrumbControl()
{
Height = 26;
TabContainer.Spacing = new Vector2(padding, 0f);
Current.ValueChanged += tab =>
{
foreach (var t in TabContainer.Children.OfType<BreadcrumbTabItem>())
{
var tIndex = TabContainer.IndexOf(t);
var tabIndex = TabContainer.IndexOf(TabMap[tab]);
t.State = tIndex < tabIndex ? Visibility.Hidden : Visibility.Visible;
t.Chevron.FadeTo(tIndex <= tabIndex ? 0f : 1f, 500, Easing.OutQuint);
}
};
}
private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility>
{
public event Action<Visibility> StateChanged;
public readonly SpriteIcon Chevron;
//don't allow clicking between transitions and don't make the chevron clickable
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceiveMouseInputAt(screenSpacePos);
public override bool HandleKeyboardInput => State == Visibility.Visible;
public override bool HandleMouseInput => State == Visibility.Visible;
private Visibility state;
public Visibility State
{
get { return state; }
set
{
if (value == state) return;
state = value;
const float transition_duration = 500;
if (State == Visibility.Visible)
{
this.FadeIn(transition_duration, Easing.OutQuint);
this.ScaleTo(new Vector2(1f), transition_duration, Easing.OutQuint);
}
else
{
this.FadeOut(transition_duration, Easing.OutQuint);
this.ScaleTo(new Vector2(0.8f, 1f), transition_duration, Easing.OutQuint);
}
StateChanged?.Invoke(State);
}
}
public BreadcrumbTabItem(T value) : base(value)
{
Text.TextSize = 16;
Padding = new MarginPadding { Right = padding + 8 }; //padding + chevron width
Add(Chevron = new SpriteIcon
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreLeft,
Size = new Vector2(12),
Icon = FontAwesome.fa_chevron_right,
Margin = new MarginPadding { Left = padding },
Alpha = 0f,
});
}
}
}
}

View File

@ -1,284 +1,284 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
using osu.Framework.Configuration;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
public class DialogButton : OsuClickableContainer
{
private const float hover_width = 0.9f;
private const float hover_duration = 500;
private const float glow_fade_duration = 250;
private const float click_duration = 200;
public readonly BindableBool Selected = new BindableBool();
private readonly Container backgroundContainer;
private readonly Container colourContainer;
private readonly Container glowContainer;
private readonly Box leftGlow;
private readonly Box centerGlow;
private readonly Box rightGlow;
private readonly Box background;
private readonly SpriteText spriteText;
private Vector2 hoverSpacing => new Vector2(3f, 0f);
public DialogButton()
{
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
backgroundContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 1f,
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = backgroundColour,
},
},
},
glowContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 1f,
Alpha = 0f,
Children = new Drawable[]
{
leftGlow = new Box
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft,
Width = 0.125f,
},
centerGlow = new Box
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Width = 0.75f,
},
rightGlow = new Box
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Width = 0.125f,
},
},
},
new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Masking = true,
Children = new Drawable[]
{
colourContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Width = 0.8f,
Masking = true,
MaskingSmoothness = 2,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Radius = 5,
},
Colour = ButtonColour,
Shear = new Vector2(0.2f, 0),
Children = new Drawable[]
{
new Box
{
EdgeSmoothness = new Vector2(2, 0),
RelativeSizeAxes = Axes.Both,
},
new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
MaskingSmoothness = 0,
Children = new[]
{
new Triangles
{
RelativeSizeAxes = Axes.Both,
TriangleScale = 4,
ColourDark = OsuColour.Gray(0.88f),
Shear = new Vector2(-0.2f, 0),
},
},
},
},
},
},
},
spriteText = new OsuSpriteText
{
Text = Text,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
TextSize = 28,
Font = "Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.1f),
Colour = Color4.White,
},
};
updateGlow();
Selected.ValueChanged += selectionChanged;
}
private Color4 buttonColour;
public Color4 ButtonColour
{
get
{
return buttonColour;
}
set
{
buttonColour = value;
updateGlow();
colourContainer.Colour = value;
}
}
private Color4 backgroundColour = OsuColour.Gray(34);
public Color4 BackgroundColour
{
get
{
return backgroundColour;
}
set
{
backgroundColour = value;
background.Colour = value;
}
}
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
spriteText.Text = Text;
}
}
private float textSize = 28;
public float TextSize
{
get
{
return textSize;
}
set
{
textSize = value;
spriteText.TextSize = value;
}
}
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => backgroundContainer.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnClick(InputState state)
{
colourContainer.ResizeTo(new Vector2(1.5f, 1f), click_duration, Easing.In);
flash();
this.Delay(click_duration).Schedule(delegate
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f));
spriteText.Spacing = Vector2.Zero;
glowContainer.FadeOut();
});
return base.OnClick(state);
}
protected override bool OnHover(InputState state)
{
base.OnHover(state);
Selected.Value = true;
return true;
}
protected override void OnHoverLost(InputState state)
{
base.OnHoverLost(state);
Selected.Value = false;
}
private void selectionChanged(bool isSelected)
{
if (isSelected)
{
spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic);
colourContainer.ResizeTo(new Vector2(hover_width, 1f), hover_duration, Easing.OutElastic);
glowContainer.FadeIn(glow_fade_duration, Easing.Out);
}
else
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f), hover_duration, Easing.OutElastic);
spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, Easing.OutElastic);
glowContainer.FadeOut(glow_fade_duration, Easing.Out);
}
}
private void flash()
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both
};
colourContainer.Add(flash);
flash.Colour = ButtonColour;
flash.Blending = BlendingMode.Additive;
flash.Alpha = 0.3f;
flash.FadeOutFromOne(click_duration);
flash.Expire();
}
private void updateGlow()
{
leftGlow.Colour = ColourInfo.GradientHorizontal(new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f), ButtonColour);
centerGlow.Colour = ButtonColour;
rightGlow.Colour = ColourInfo.GradientHorizontal(ButtonColour, new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f));
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
using osu.Framework.Configuration;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
public class DialogButton : OsuClickableContainer
{
private const float hover_width = 0.9f;
private const float hover_duration = 500;
private const float glow_fade_duration = 250;
private const float click_duration = 200;
public readonly BindableBool Selected = new BindableBool();
private readonly Container backgroundContainer;
private readonly Container colourContainer;
private readonly Container glowContainer;
private readonly Box leftGlow;
private readonly Box centerGlow;
private readonly Box rightGlow;
private readonly Box background;
private readonly SpriteText spriteText;
private Vector2 hoverSpacing => new Vector2(3f, 0f);
public DialogButton()
{
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
backgroundContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 1f,
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = backgroundColour,
},
},
},
glowContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 1f,
Alpha = 0f,
Children = new Drawable[]
{
leftGlow = new Box
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft,
Width = 0.125f,
},
centerGlow = new Box
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Width = 0.75f,
},
rightGlow = new Box
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Width = 0.125f,
},
},
},
new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Masking = true,
Children = new Drawable[]
{
colourContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Width = 0.8f,
Masking = true,
MaskingSmoothness = 2,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Radius = 5,
},
Colour = ButtonColour,
Shear = new Vector2(0.2f, 0),
Children = new Drawable[]
{
new Box
{
EdgeSmoothness = new Vector2(2, 0),
RelativeSizeAxes = Axes.Both,
},
new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
MaskingSmoothness = 0,
Children = new[]
{
new Triangles
{
RelativeSizeAxes = Axes.Both,
TriangleScale = 4,
ColourDark = OsuColour.Gray(0.88f),
Shear = new Vector2(-0.2f, 0),
},
},
},
},
},
},
},
spriteText = new OsuSpriteText
{
Text = Text,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
TextSize = 28,
Font = "Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.1f),
Colour = Color4.White,
},
};
updateGlow();
Selected.ValueChanged += selectionChanged;
}
private Color4 buttonColour;
public Color4 ButtonColour
{
get
{
return buttonColour;
}
set
{
buttonColour = value;
updateGlow();
colourContainer.Colour = value;
}
}
private Color4 backgroundColour = OsuColour.Gray(34);
public Color4 BackgroundColour
{
get
{
return backgroundColour;
}
set
{
backgroundColour = value;
background.Colour = value;
}
}
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
spriteText.Text = Text;
}
}
private float textSize = 28;
public float TextSize
{
get
{
return textSize;
}
set
{
textSize = value;
spriteText.TextSize = value;
}
}
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => backgroundContainer.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnClick(InputState state)
{
colourContainer.ResizeTo(new Vector2(1.5f, 1f), click_duration, Easing.In);
flash();
this.Delay(click_duration).Schedule(delegate
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f));
spriteText.Spacing = Vector2.Zero;
glowContainer.FadeOut();
});
return base.OnClick(state);
}
protected override bool OnHover(InputState state)
{
base.OnHover(state);
Selected.Value = true;
return true;
}
protected override void OnHoverLost(InputState state)
{
base.OnHoverLost(state);
Selected.Value = false;
}
private void selectionChanged(bool isSelected)
{
if (isSelected)
{
spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic);
colourContainer.ResizeTo(new Vector2(hover_width, 1f), hover_duration, Easing.OutElastic);
glowContainer.FadeIn(glow_fade_duration, Easing.Out);
}
else
{
colourContainer.ResizeTo(new Vector2(0.8f, 1f), hover_duration, Easing.OutElastic);
spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, Easing.OutElastic);
glowContainer.FadeOut(glow_fade_duration, Easing.Out);
}
}
private void flash()
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both
};
colourContainer.Add(flash);
flash.Colour = ButtonColour;
flash.Blending = BlendingMode.Additive;
flash.Alpha = 0.3f;
flash.FadeOutFromOne(click_duration);
flash.Expire();
}
private void updateGlow()
{
leftGlow.Colour = ColourInfo.GradientHorizontal(new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f), ButtonColour);
centerGlow.Colour = ButtonColour;
rightGlow.Colour = ColourInfo.GradientHorizontal(ButtonColour, new Color4(ButtonColour.R, ButtonColour.G, ButtonColour.B, 0f));
}
}
}

View File

@ -1,58 +1,58 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Input;
using System;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A textbox which holds focus eagerly.
/// </summary>
public class FocusedTextBox : OsuTextBox
{
protected override Color4 BackgroundUnfocused => new Color4(10, 10, 10, 255);
protected override Color4 BackgroundFocused => new Color4(10, 10, 10, 255);
public Action Exit;
private bool focus;
public bool HoldFocus
{
get { return focus; }
set
{
focus = value;
if (!focus && HasFocus)
GetContainingInputManager().ChangeFocus(null);
}
}
// We may not be focused yet, but we need to handle keyboard input to be able to request focus
public override bool HandleKeyboardInput => HoldFocus || base.HandleKeyboardInput;
protected override void OnFocus(InputState state)
{
base.OnFocus(state);
BorderThickness = 0;
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (!args.Repeat && args.Key == Key.Escape)
{
if (Text.Length > 0)
Text = string.Empty;
else
Exit?.Invoke();
return true;
}
return base.OnKeyDown(state, args);
}
public override bool RequestsFocus => HoldFocus;
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Input;
using System;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A textbox which holds focus eagerly.
/// </summary>
public class FocusedTextBox : OsuTextBox
{
protected override Color4 BackgroundUnfocused => new Color4(10, 10, 10, 255);
protected override Color4 BackgroundFocused => new Color4(10, 10, 10, 255);
public Action Exit;
private bool focus;
public bool HoldFocus
{
get { return focus; }
set
{
focus = value;
if (!focus && HasFocus)
GetContainingInputManager().ChangeFocus(null);
}
}
// We may not be focused yet, but we need to handle keyboard input to be able to request focus
public override bool HandleKeyboardInput => HoldFocus || base.HandleKeyboardInput;
protected override void OnFocus(InputState state)
{
base.OnFocus(state);
BorderThickness = 0;
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (!args.Repeat && args.Key == Key.Escape)
{
if (Text.Length > 0)
Text = string.Empty;
else
Exit?.Invoke();
return true;
}
return base.OnKeyDown(state, args);
}
public override bool RequestsFocus => HoldFocus;
}
}

View File

@ -1,36 +1,36 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Adds hover and click sounds to a drawable.
/// Does not draw anything.
/// </summary>
public class HoverClickSounds : HoverSounds
{
private SampleChannel sampleClick;
public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) : base(sampleSet)
{
}
protected override bool OnClick(InputState state)
{
sampleClick?.Play();
return base.OnClick(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}");
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Adds hover and click sounds to a drawable.
/// Does not draw anything.
/// </summary>
public class HoverClickSounds : HoverSounds
{
private SampleChannel sampleClick;
public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) : base(sampleSet)
{
}
protected override bool OnClick(InputState state)
{
sampleClick?.Play();
return base.OnClick(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}");
}
}
}

View File

@ -1,53 +1,53 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Adds hover sounds to a drawable.
/// Does not draw anything.
/// </summary>
public class HoverSounds : CompositeDrawable
{
private SampleChannel sampleHover;
protected readonly HoverSampleSet SampleSet;
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
{
SampleSet = sampleSet;
RelativeSizeAxes = Axes.Both;
}
protected override bool OnHover(InputState state)
{
sampleHover?.Play();
return base.OnHover(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
}
}
public enum HoverSampleSet
{
[Description("")]
Loud,
[Description("-soft")]
Normal,
[Description("-softer")]
Soft
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Adds hover sounds to a drawable.
/// Does not draw anything.
/// </summary>
public class HoverSounds : CompositeDrawable
{
private SampleChannel sampleHover;
protected readonly HoverSampleSet SampleSet;
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
{
SampleSet = sampleSet;
RelativeSizeAxes = Axes.Both;
}
protected override bool OnHover(InputState state)
{
sampleHover?.Play();
return base.OnHover(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
}
}
public enum HoverSampleSet
{
[Description("")]
Loud,
[Description("-soft")]
Normal,
[Description("-softer")]
Soft
}
}

View File

@ -1,180 +1,180 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
{
public class IconButton : OsuClickableContainer
{
public const float BUTTON_SIZE = 30;
private Color4? flashColour;
/// <summary>
/// The colour that should be flashed when the <see cref="IconButton"/> is clicked.
/// </summary>
public Color4 FlashColour
{
get { return flashColour ?? Color4.White; }
set { flashColour = value; }
}
private Color4? iconColour;
/// <summary>
/// The icon colour. This does not affect <see cref="IconButton.Colour"/>.
/// </summary>
public Color4 IconColour
{
get { return iconColour ?? Color4.White; }
set
{
iconColour = value;
icon.Colour = value;
}
}
private Color4? iconHoverColour;
/// <summary>
/// The icon colour while the <see cref="IconButton"/> is hovered.
/// </summary>
public Color4 IconHoverColour
{
get { return iconHoverColour ?? IconColour; }
set { iconHoverColour = value; }
}
private Color4? hoverColour;
/// <summary>
/// The background colour of the <see cref="IconButton"/> while it is hovered.
/// </summary>
public Color4 HoverColour
{
get { return hoverColour ?? Color4.White; }
set
{
hoverColour = value;
hover.Colour = value;
}
}
/// <summary>
/// The icon.
/// </summary>
public FontAwesome Icon
{
get { return icon.Icon; }
set { icon.Icon = value; }
}
/// <summary>
/// The icon scale. This does not affect <see cref="IconButton.Scale"/>.
/// </summary>
public Vector2 IconScale
{
get { return icon.Scale; }
set { icon.Scale = value; }
}
/// <summary>
/// The size of the <see cref="IconButton"/> while it is not being pressed.
/// </summary>
public Vector2 ButtonSize
{
get { return content.Size; }
set { content.Size = value; }
}
private readonly Container content;
private readonly SpriteIcon icon;
private readonly Box hover;
public IconButton()
{
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
content = new Container
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(BUTTON_SIZE),
CornerRadius = 5,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.04f),
Type = EdgeEffectType.Shadow,
Radius = 5,
},
Children = new Drawable[]
{
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
},
icon = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(18),
}
}
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (hoverColour == null)
HoverColour = colours.Yellow.Opacity(0.6f);
if (flashColour == null)
FlashColour = colours.Yellow;
Enabled.ValueChanged += enabled => this.FadeColour(enabled ? Color4.White : colours.Gray9, 200, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
hover.FadeIn(500, Easing.OutQuint);
icon.FadeColour(IconHoverColour, 500, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(500, Easing.OutQuint);
icon.FadeColour(IconColour, 500, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
hover.FlashColour(FlashColour, 800, Easing.OutQuint);
return base.OnClick(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
content.ScaleTo(0.75f, 2000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
{
public class IconButton : OsuClickableContainer
{
public const float BUTTON_SIZE = 30;
private Color4? flashColour;
/// <summary>
/// The colour that should be flashed when the <see cref="IconButton"/> is clicked.
/// </summary>
public Color4 FlashColour
{
get { return flashColour ?? Color4.White; }
set { flashColour = value; }
}
private Color4? iconColour;
/// <summary>
/// The icon colour. This does not affect <see cref="IconButton.Colour"/>.
/// </summary>
public Color4 IconColour
{
get { return iconColour ?? Color4.White; }
set
{
iconColour = value;
icon.Colour = value;
}
}
private Color4? iconHoverColour;
/// <summary>
/// The icon colour while the <see cref="IconButton"/> is hovered.
/// </summary>
public Color4 IconHoverColour
{
get { return iconHoverColour ?? IconColour; }
set { iconHoverColour = value; }
}
private Color4? hoverColour;
/// <summary>
/// The background colour of the <see cref="IconButton"/> while it is hovered.
/// </summary>
public Color4 HoverColour
{
get { return hoverColour ?? Color4.White; }
set
{
hoverColour = value;
hover.Colour = value;
}
}
/// <summary>
/// The icon.
/// </summary>
public FontAwesome Icon
{
get { return icon.Icon; }
set { icon.Icon = value; }
}
/// <summary>
/// The icon scale. This does not affect <see cref="IconButton.Scale"/>.
/// </summary>
public Vector2 IconScale
{
get { return icon.Scale; }
set { icon.Scale = value; }
}
/// <summary>
/// The size of the <see cref="IconButton"/> while it is not being pressed.
/// </summary>
public Vector2 ButtonSize
{
get { return content.Size; }
set { content.Size = value; }
}
private readonly Container content;
private readonly SpriteIcon icon;
private readonly Box hover;
public IconButton()
{
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
content = new Container
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(BUTTON_SIZE),
CornerRadius = 5,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.04f),
Type = EdgeEffectType.Shadow,
Radius = 5,
},
Children = new Drawable[]
{
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
},
icon = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(18),
}
}
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (hoverColour == null)
HoverColour = colours.Yellow.Opacity(0.6f);
if (flashColour == null)
FlashColour = colours.Yellow;
Enabled.ValueChanged += enabled => this.FadeColour(enabled ? Color4.White : colours.Gray9, 200, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
hover.FadeIn(500, Easing.OutQuint);
icon.FadeColour(IconHoverColour, 500, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(500, Easing.OutQuint);
icon.FadeColour(IconColour, 500, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
hover.FlashColour(FlashColour, 800, Easing.OutQuint);
return base.OnClick(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
content.ScaleTo(0.75f, 2000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
}
}

View File

@ -1,118 +1,118 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Caching;
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
namespace osu.Game.Graphics.UserInterface
{
public class LineGraph : Container
{
/// <summary>
/// Manually set the max value, otherwise <see cref="Enumerable.Max(IEnumerable{float})"/> will be used.
/// </summary>
public float? MaxValue { get; set; }
/// <summary>
/// Manually set the min value, otherwise <see cref="Enumerable.Min(IEnumerable{float})"/> will be used.
/// </summary>
public float? MinValue { get; set; }
public float ActualMaxValue { get; private set; } = float.NaN;
public float ActualMinValue { get; private set; } = float.NaN;
private const double transform_duration = 1500;
/// <summary>
/// Hold an empty area if values are less.
/// </summary>
public int DefaultValueCount;
private readonly Container<Path> maskingContainer;
private readonly Path path;
private float[] values;
/// <summary>
/// A list of floats decides position of each line node.
/// </summary>
public IEnumerable<float> Values
{
get { return values; }
set
{
values = value.ToArray();
float max = values.Max(), min = values.Min();
if (MaxValue > max) max = MaxValue.Value;
if (MinValue < min) min = MinValue.Value;
ActualMaxValue = max;
ActualMinValue = min;
pathCached.Invalidate();
maskingContainer.Width = 0;
maskingContainer.ResizeWidthTo(1, transform_duration, Easing.OutQuint);
}
}
public LineGraph()
{
Add(maskingContainer = new Container<Path>
{
Masking = true,
RelativeSizeAxes = Axes.Both,
Child = path = new Path { RelativeSizeAxes = Axes.Both, PathWidth = 1 }
});
}
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) > 0)
pathCached.Invalidate();
return base.Invalidate(invalidation, source, shallPropagate);
}
private Cached pathCached = new Cached();
protected override void Update()
{
base.Update();
if (!pathCached.IsValid)
{
applyPath();
pathCached.Validate();
}
}
private void applyPath()
{
path.ClearVertices();
if (values == null) return;
int count = Math.Max(values.Length, DefaultValueCount);
for (int i = 0; i < values.Length; i++)
{
float x = (i + count - values.Length) / (float)(count - 1) * DrawWidth - 1;
float y = GetYPosition(values[i]) * DrawHeight - 1;
// the -1 is for inner offset in path (actually -PathWidth)
path.AddVertex(new Vector2(x, y));
}
}
protected float GetYPosition(float value)
{
if (ActualMaxValue == ActualMinValue) return 0;
return (ActualMaxValue - value) / (ActualMaxValue - ActualMinValue);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Caching;
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
namespace osu.Game.Graphics.UserInterface
{
public class LineGraph : Container
{
/// <summary>
/// Manually set the max value, otherwise <see cref="Enumerable.Max(IEnumerable{float})"/> will be used.
/// </summary>
public float? MaxValue { get; set; }
/// <summary>
/// Manually set the min value, otherwise <see cref="Enumerable.Min(IEnumerable{float})"/> will be used.
/// </summary>
public float? MinValue { get; set; }
public float ActualMaxValue { get; private set; } = float.NaN;
public float ActualMinValue { get; private set; } = float.NaN;
private const double transform_duration = 1500;
/// <summary>
/// Hold an empty area if values are less.
/// </summary>
public int DefaultValueCount;
private readonly Container<Path> maskingContainer;
private readonly Path path;
private float[] values;
/// <summary>
/// A list of floats decides position of each line node.
/// </summary>
public IEnumerable<float> Values
{
get { return values; }
set
{
values = value.ToArray();
float max = values.Max(), min = values.Min();
if (MaxValue > max) max = MaxValue.Value;
if (MinValue < min) min = MinValue.Value;
ActualMaxValue = max;
ActualMinValue = min;
pathCached.Invalidate();
maskingContainer.Width = 0;
maskingContainer.ResizeWidthTo(1, transform_duration, Easing.OutQuint);
}
}
public LineGraph()
{
Add(maskingContainer = new Container<Path>
{
Masking = true,
RelativeSizeAxes = Axes.Both,
Child = path = new Path { RelativeSizeAxes = Axes.Both, PathWidth = 1 }
});
}
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) > 0)
pathCached.Invalidate();
return base.Invalidate(invalidation, source, shallPropagate);
}
private Cached pathCached = new Cached();
protected override void Update()
{
base.Update();
if (!pathCached.IsValid)
{
applyPath();
pathCached.Validate();
}
}
private void applyPath()
{
path.ClearVertices();
if (values == null) return;
int count = Math.Max(values.Length, DefaultValueCount);
for (int i = 0; i < values.Length; i++)
{
float x = (i + count - values.Length) / (float)(count - 1) * DrawWidth - 1;
float y = GetYPosition(values[i]) * DrawHeight - 1;
// the -1 is for inner offset in path (actually -PathWidth)
path.AddVertex(new Vector2(x, y));
}
}
protected float GetYPosition(float value)
{
if (ActualMaxValue == ActualMinValue) return 0;
return (ActualMaxValue - value) / (ActualMaxValue - ActualMinValue);
}
}
}

View File

@ -1,46 +1,46 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
namespace osu.Game.Graphics.UserInterface
{
public class LoadingAnimation : VisibilityContainer
{
private readonly SpriteIcon spinner;
public LoadingAnimation()
{
Size = new Vector2(20);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Children = new Drawable[]
{
spinner = new SpriteIcon
{
Size = new Vector2(20),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.fa_spinner
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
spinner.Spin(2000, RotationDirection.Clockwise);
}
private const float transition_duration = 500;
protected override void PopIn() => this.FadeIn(transition_duration * 5, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(transition_duration, Easing.OutQuint);
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
namespace osu.Game.Graphics.UserInterface
{
public class LoadingAnimation : VisibilityContainer
{
private readonly SpriteIcon spinner;
public LoadingAnimation()
{
Size = new Vector2(20);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Children = new Drawable[]
{
spinner = new SpriteIcon
{
Size = new Vector2(20),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.fa_spinner
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
spinner.Spin(2000, RotationDirection.Clockwise);
}
private const float transition_duration = 500;
protected override void PopIn() => this.FadeIn(transition_duration * 5, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(transition_duration, Easing.OutQuint);
}
}

View File

@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Graphics.UserInterface
{
public enum MenuItemType
{
Standard,
Highlighted,
Destructive,
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Graphics.UserInterface
{
public enum MenuItemType
{
Standard,
Highlighted,
Destructive,
}
}

View File

@ -1,142 +1,142 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
public class Nub : CircularContainer, IHasCurrentValue<bool>, IHasAccentColour
{
public const float COLLAPSED_SIZE = 20;
public const float EXPANDED_SIZE = 40;
private const float border_width = 3;
public Nub()
{
Box fill;
Size = new Vector2(COLLAPSED_SIZE, 12);
BorderColour = Color4.White;
BorderThickness = border_width;
Masking = true;
Children = new[]
{
fill = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true,
},
};
Current.ValueChanged += newValue =>
{
if (newValue)
fill.FadeIn(200, Easing.OutQuint);
else
fill.FadeTo(0.01f, 200, Easing.OutQuint); //todo: remove once we figure why containers aren't drawing at all times
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.Pink;
GlowingAccentColour = colours.PinkLighter;
GlowColour = colours.PinkDarker;
EdgeEffect = new EdgeEffectParameters
{
Colour = GlowColour,
Type = EdgeEffectType.Glow,
Radius = 10,
Roundness = 8,
};
}
protected override void LoadComplete()
{
FadeEdgeEffectTo(0);
}
private bool glowing;
public bool Glowing
{
get { return glowing; }
set
{
glowing = value;
if (value)
{
this.FadeColour(GlowingAccentColour, 500, Easing.OutQuint);
FadeEdgeEffectTo(1, 500, Easing.OutQuint);
}
else
{
FadeEdgeEffectTo(0, 500);
this.FadeColour(AccentColour, 500);
}
}
}
public bool Expanded
{
set
{
this.ResizeTo(new Vector2(value ? EXPANDED_SIZE : COLLAPSED_SIZE, 12), 500, Easing.OutQuint);
}
}
public Bindable<bool> Current { get; } = new Bindable<bool>();
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
if (!Glowing)
Colour = value;
}
}
private Color4 glowingAccentColour;
public Color4 GlowingAccentColour
{
get { return glowingAccentColour; }
set
{
glowingAccentColour = value;
if (Glowing)
Colour = value;
}
}
private Color4 glowColour;
public Color4 GlowColour
{
get { return glowColour; }
set
{
glowColour = value;
var effect = EdgeEffect;
effect.Colour = value;
EdgeEffect = effect;
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
public class Nub : CircularContainer, IHasCurrentValue<bool>, IHasAccentColour
{
public const float COLLAPSED_SIZE = 20;
public const float EXPANDED_SIZE = 40;
private const float border_width = 3;
public Nub()
{
Box fill;
Size = new Vector2(COLLAPSED_SIZE, 12);
BorderColour = Color4.White;
BorderThickness = border_width;
Masking = true;
Children = new[]
{
fill = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true,
},
};
Current.ValueChanged += newValue =>
{
if (newValue)
fill.FadeIn(200, Easing.OutQuint);
else
fill.FadeTo(0.01f, 200, Easing.OutQuint); //todo: remove once we figure why containers aren't drawing at all times
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.Pink;
GlowingAccentColour = colours.PinkLighter;
GlowColour = colours.PinkDarker;
EdgeEffect = new EdgeEffectParameters
{
Colour = GlowColour,
Type = EdgeEffectType.Glow,
Radius = 10,
Roundness = 8,
};
}
protected override void LoadComplete()
{
FadeEdgeEffectTo(0);
}
private bool glowing;
public bool Glowing
{
get { return glowing; }
set
{
glowing = value;
if (value)
{
this.FadeColour(GlowingAccentColour, 500, Easing.OutQuint);
FadeEdgeEffectTo(1, 500, Easing.OutQuint);
}
else
{
FadeEdgeEffectTo(0, 500);
this.FadeColour(AccentColour, 500);
}
}
}
public bool Expanded
{
set
{
this.ResizeTo(new Vector2(value ? EXPANDED_SIZE : COLLAPSED_SIZE, 12), 500, Easing.OutQuint);
}
}
public Bindable<bool> Current { get; } = new Bindable<bool>();
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
if (!Glowing)
Colour = value;
}
}
private Color4 glowingAccentColour;
public Color4 GlowingAccentColour
{
get { return glowingAccentColour; }
set
{
glowingAccentColour = value;
if (Glowing)
Colour = value;
}
}
private Color4 glowColour;
public Color4 GlowColour
{
get { return glowColour; }
set
{
glowColour = value;
var effect = EdgeEffect;
effect.Colour = value;
EdgeEffect = effect;
}
}
}
}

View File

@ -1,18 +1,18 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A button with added default sound effects.
/// </summary>
public class OsuButton : Button
{
public OsuButton()
{
Add(new HoverClickSounds(HoverSampleSet.Loud));
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A button with added default sound effects.
/// </summary>
public class OsuButton : Button
{
public OsuButton()
{
Add(new HoverClickSounds(HoverSampleSet.Loud));
}
}
}

View File

@ -1,119 +1,119 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class OsuCheckbox : Checkbox
{
private Bindable<bool> bindable;
public Bindable<bool> Bindable
{
set
{
bindable = value;
Current.BindTo(bindable);
}
}
public Color4 CheckedColor { get; set; } = Color4.Cyan;
public Color4 UncheckedColor { get; set; } = Color4.White;
public int FadeDuration { get; set; }
public string LabelText
{
get { return labelSpriteText?.Text; }
set
{
if (labelSpriteText != null)
labelSpriteText.Text = value;
}
}
public MarginPadding LabelPadding
{
get { return labelSpriteText?.Padding ?? new MarginPadding(); }
set
{
if (labelSpriteText != null)
labelSpriteText.Padding = value;
}
}
protected readonly Nub Nub;
private readonly SpriteText labelSpriteText;
private SampleChannel sampleChecked;
private SampleChannel sampleUnchecked;
public OsuCheckbox()
{
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
labelSpriteText = new OsuSpriteText(),
Nub = new Nub
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 5 },
},
new HoverClickSounds()
};
Nub.Current.BindTo(Current);
Current.DisabledChanged += disabled =>
{
Alpha = disabled ? 0.3f : 1;
};
}
protected override void LoadComplete()
{
base.LoadComplete();
Current.ValueChanged += newValue =>
{
if (newValue)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
};
}
protected override bool OnHover(InputState state)
{
Nub.Glowing = true;
Nub.Expanded = true;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
Nub.Glowing = false;
Nub.Expanded = false;
base.OnHoverLost(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleChecked = audio.Sample.Get(@"UI/check-on");
sampleUnchecked = audio.Sample.Get(@"UI/check-off");
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class OsuCheckbox : Checkbox
{
private Bindable<bool> bindable;
public Bindable<bool> Bindable
{
set
{
bindable = value;
Current.BindTo(bindable);
}
}
public Color4 CheckedColor { get; set; } = Color4.Cyan;
public Color4 UncheckedColor { get; set; } = Color4.White;
public int FadeDuration { get; set; }
public string LabelText
{
get { return labelSpriteText?.Text; }
set
{
if (labelSpriteText != null)
labelSpriteText.Text = value;
}
}
public MarginPadding LabelPadding
{
get { return labelSpriteText?.Padding ?? new MarginPadding(); }
set
{
if (labelSpriteText != null)
labelSpriteText.Padding = value;
}
}
protected readonly Nub Nub;
private readonly SpriteText labelSpriteText;
private SampleChannel sampleChecked;
private SampleChannel sampleUnchecked;
public OsuCheckbox()
{
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
labelSpriteText = new OsuSpriteText(),
Nub = new Nub
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 5 },
},
new HoverClickSounds()
};
Nub.Current.BindTo(Current);
Current.DisabledChanged += disabled =>
{
Alpha = disabled ? 0.3f : 1;
};
}
protected override void LoadComplete()
{
base.LoadComplete();
Current.ValueChanged += newValue =>
{
if (newValue)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
};
}
protected override bool OnHover(InputState state)
{
Nub.Glowing = true;
Nub.Expanded = true;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
Nub.Glowing = false;
Nub.Expanded = false;
base.OnHoverLost(state);
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleChecked = audio.Sample.Get(@"UI/check-on");
sampleUnchecked = audio.Sample.Get(@"UI/check-off");
}
}
}

View File

@ -1,39 +1,39 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
{
public class OsuContextMenu : OsuMenu
{
private const int fade_duration = 250;
public OsuContextMenu()
: base(Direction.Vertical)
{
MaskingContainer.CornerRadius = 5;
MaskingContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.1f),
Radius = 4,
};
ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL };
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.ContextMenuGray;
}
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
{
public class OsuContextMenu : OsuMenu
{
private const int fade_duration = 250;
public OsuContextMenu()
: base(Direction.Vertical)
{
MaskingContainer.CornerRadius = 5;
MaskingContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.1f),
Radius = 4,
};
ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL };
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.ContextMenuGray;
}
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
}
}

View File

@ -1,255 +1,255 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Graphics.UserInterface
{
public class OsuDropdown<T> : Dropdown<T>, IHasAccentColour
{
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
updateAccentColour();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == default(Color4))
accentColour = colours.PinkDarker;
updateAccentColour();
}
private void updateAccentColour()
{
var header = Header as IHasAccentColour;
if (header != null) header.AccentColour = accentColour;
var menu = Menu as IHasAccentColour;
if (menu != null) menu.AccentColour = accentColour;
}
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader();
protected override DropdownMenu CreateMenu() => new OsuDropdownMenu();
#region OsuDropdownMenu
protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour
{
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
public OsuDropdownMenu()
{
CornerRadius = 4;
BackgroundColour = Color4.Black.Opacity(0.5f);
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
ItemsContainer.Padding = new MarginPadding(5);
}
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
protected override void UpdateSize(Vector2 newSize)
{
if (Direction == Direction.Vertical)
{
Width = newSize.X;
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
}
else
{
Height = newSize.Y;
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
}
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
foreach (var c in Children.OfType<IHasAccentColour>())
c.AccentColour = value;
}
}
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuDropdownMenuItem(item) { AccentColour = accentColour };
#region DrawableOsuDropdownMenuItem
public class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour
{
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour ?? nonAccentSelectedColour; }
set
{
accentColour = value;
updateColours();
}
}
private void updateColours()
{
BackgroundColourHover = accentColour ?? nonAccentHoverColour;
BackgroundColourSelected = accentColour ?? nonAccentSelectedColour;
UpdateBackgroundColour();
UpdateForegroundColour();
}
private Color4 nonAccentHoverColour;
private Color4 nonAccentSelectedColour;
public DrawableOsuDropdownMenuItem(MenuItem item)
: base(item)
{
Foreground.Padding = new MarginPadding(2);
Masking = true;
CornerRadius = 6;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Transparent;
nonAccentHoverColour = colours.PinkDarker;
nonAccentSelectedColour = Color4.Black.Opacity(0.5f);
updateColours();
AddInternal(new HoverClickSounds(HoverSampleSet.Soft));
}
protected override void UpdateForegroundColour()
{
base.UpdateForegroundColour();
var content = Foreground.Children.FirstOrDefault() as Content;
if (content != null) content.Chevron.Alpha = IsHovered ? 1 : 0;
}
protected override Drawable CreateContent() => new Content();
protected new class Content : FillFlowContainer, IHasText
{
public string Text
{
get { return Label.Text; }
set { Label.Text = value; }
}
public readonly OsuSpriteText Label;
public readonly SpriteIcon Chevron;
public Content()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Horizontal;
Children = new Drawable[]
{
Chevron = new SpriteIcon
{
AlwaysPresent = true,
Icon = FontAwesome.fa_chevron_right,
Colour = Color4.Black,
Alpha = 0.5f,
Size = new Vector2(8),
Margin = new MarginPadding { Left = 3, Right = 3 },
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
Label = new OsuSpriteText
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
};
}
}
}
#endregion
}
#endregion
public class OsuDropdownHeader : DropdownHeader, IHasAccentColour
{
protected readonly SpriteText Text;
protected override string Label
{
get { return Text.Text; }
set { Text.Text = value; }
}
protected readonly SpriteIcon Icon;
private Color4 accentColour;
public virtual Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
BackgroundColourHover = accentColour;
}
}
public OsuDropdownHeader()
{
Foreground.Padding = new MarginPadding(4);
AutoSizeAxes = Axes.None;
Margin = new MarginPadding { Bottom = 4 };
CornerRadius = 4;
Height = 40;
Foreground.Children = new Drawable[]
{
Text = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
Icon = new SpriteIcon
{
Icon = FontAwesome.fa_chevron_down,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 4 },
Size = new Vector2(20),
},
};
AddInternal(new HoverClickSounds());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
BackgroundColourHover = colours.PinkDarker;
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Graphics.UserInterface
{
public class OsuDropdown<T> : Dropdown<T>, IHasAccentColour
{
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
updateAccentColour();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == default(Color4))
accentColour = colours.PinkDarker;
updateAccentColour();
}
private void updateAccentColour()
{
var header = Header as IHasAccentColour;
if (header != null) header.AccentColour = accentColour;
var menu = Menu as IHasAccentColour;
if (menu != null) menu.AccentColour = accentColour;
}
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader();
protected override DropdownMenu CreateMenu() => new OsuDropdownMenu();
#region OsuDropdownMenu
protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour
{
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
public OsuDropdownMenu()
{
CornerRadius = 4;
BackgroundColour = Color4.Black.Opacity(0.5f);
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
ItemsContainer.Padding = new MarginPadding(5);
}
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
protected override void UpdateSize(Vector2 newSize)
{
if (Direction == Direction.Vertical)
{
Width = newSize.X;
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
}
else
{
Height = newSize.Y;
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
}
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
foreach (var c in Children.OfType<IHasAccentColour>())
c.AccentColour = value;
}
}
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuDropdownMenuItem(item) { AccentColour = accentColour };
#region DrawableOsuDropdownMenuItem
public class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour
{
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour ?? nonAccentSelectedColour; }
set
{
accentColour = value;
updateColours();
}
}
private void updateColours()
{
BackgroundColourHover = accentColour ?? nonAccentHoverColour;
BackgroundColourSelected = accentColour ?? nonAccentSelectedColour;
UpdateBackgroundColour();
UpdateForegroundColour();
}
private Color4 nonAccentHoverColour;
private Color4 nonAccentSelectedColour;
public DrawableOsuDropdownMenuItem(MenuItem item)
: base(item)
{
Foreground.Padding = new MarginPadding(2);
Masking = true;
CornerRadius = 6;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Transparent;
nonAccentHoverColour = colours.PinkDarker;
nonAccentSelectedColour = Color4.Black.Opacity(0.5f);
updateColours();
AddInternal(new HoverClickSounds(HoverSampleSet.Soft));
}
protected override void UpdateForegroundColour()
{
base.UpdateForegroundColour();
var content = Foreground.Children.FirstOrDefault() as Content;
if (content != null) content.Chevron.Alpha = IsHovered ? 1 : 0;
}
protected override Drawable CreateContent() => new Content();
protected new class Content : FillFlowContainer, IHasText
{
public string Text
{
get { return Label.Text; }
set { Label.Text = value; }
}
public readonly OsuSpriteText Label;
public readonly SpriteIcon Chevron;
public Content()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Horizontal;
Children = new Drawable[]
{
Chevron = new SpriteIcon
{
AlwaysPresent = true,
Icon = FontAwesome.fa_chevron_right,
Colour = Color4.Black,
Alpha = 0.5f,
Size = new Vector2(8),
Margin = new MarginPadding { Left = 3, Right = 3 },
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
Label = new OsuSpriteText
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
};
}
}
}
#endregion
}
#endregion
public class OsuDropdownHeader : DropdownHeader, IHasAccentColour
{
protected readonly SpriteText Text;
protected override string Label
{
get { return Text.Text; }
set { Text.Text = value; }
}
protected readonly SpriteIcon Icon;
private Color4 accentColour;
public virtual Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
BackgroundColourHover = accentColour;
}
}
public OsuDropdownHeader()
{
Foreground.Padding = new MarginPadding(4);
AutoSizeAxes = Axes.None;
Margin = new MarginPadding { Bottom = 4 };
CornerRadius = 4;
Height = 40;
Foreground.Children = new Drawable[]
{
Text = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
Icon = new SpriteIcon
{
Icon = FontAwesome.fa_chevron_down,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 4 },
Size = new Vector2(20),
},
};
AddInternal(new HoverClickSounds());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
BackgroundColourHover = colours.PinkDarker;
}
}
}
}

View File

@ -1,32 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.ComponentModel;
using System.Reflection;
using System.Collections.Generic;
namespace osu.Game.Graphics.UserInterface
{
public class OsuEnumDropdown<T> : OsuDropdown<T>
{
public OsuEnumDropdown()
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException("OsuEnumDropdown only supports enums as the generic type argument");
List<KeyValuePair<string, T>> items = new List<KeyValuePair<string, T>>();
foreach (var val in (T[])Enum.GetValues(typeof(T)))
{
var field = typeof(T).GetField(Enum.GetName(typeof(T), val));
items.Add(
new KeyValuePair<string, T>(
field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? Enum.GetName(typeof(T), val),
val
)
);
}
Items = items;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.ComponentModel;
using System.Reflection;
using System.Collections.Generic;
namespace osu.Game.Graphics.UserInterface
{
public class OsuEnumDropdown<T> : OsuDropdown<T>
{
public OsuEnumDropdown()
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException("OsuEnumDropdown only supports enums as the generic type argument");
List<KeyValuePair<string, T>> items = new List<KeyValuePair<string, T>>();
foreach (var val in (T[])Enum.GetValues(typeof(T)))
{
var field = typeof(T).GetField(Enum.GetName(typeof(T), val));
items.Add(
new KeyValuePair<string, T>(
field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? Enum.GetName(typeof(T), val),
val
)
);
}
Items = items;
}
}
}

View File

@ -1,170 +1,170 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Graphics.UserInterface
{
public class OsuMenu : Menu
{
public OsuMenu(Direction direction, bool topLevelMenu = false)
: base(direction, topLevelMenu)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
MaskingContainer.CornerRadius = 4;
ItemsContainer.Padding = new MarginPadding(5);
}
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
protected override void UpdateSize(Vector2 newSize)
{
if (Direction == Direction.Vertical)
{
Width = newSize.X;
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
}
else
{
Height = newSize.Y;
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
}
}
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item);
protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical)
{
Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight
};
protected class DrawableOsuMenuItem : DrawableMenuItem
{
private const int margin_horizontal = 17;
private const int text_size = 17;
private const int transition_length = 80;
public const int MARGIN_VERTICAL = 4;
private SampleChannel sampleClick;
private SampleChannel sampleHover;
private TextContainer text;
public DrawableOsuMenuItem(MenuItem item)
: base(item)
{
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleHover = audio.Sample.Get(@"UI/generic-hover");
sampleClick = audio.Sample.Get(@"UI/generic-select");
BackgroundColour = Color4.Transparent;
BackgroundColourHover = OsuColour.FromHex(@"172023");
updateTextColour();
}
private void updateTextColour()
{
switch ((Item as OsuMenuItem)?.Type)
{
default:
case MenuItemType.Standard:
text.Colour = Color4.White;
break;
case MenuItemType.Destructive:
text.Colour = Color4.Red;
break;
case MenuItemType.Highlighted:
text.Colour = OsuColour.FromHex(@"ffcc22");
break;
}
}
protected override bool OnHover(InputState state)
{
sampleHover.Play();
text.BoldText.FadeIn(transition_length, Easing.OutQuint);
text.NormalText.FadeOut(transition_length, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
text.BoldText.FadeOut(transition_length, Easing.OutQuint);
text.NormalText.FadeIn(transition_length, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
sampleClick.Play();
return base.OnClick(state);
}
protected sealed override Drawable CreateContent() => text = CreateTextContainer();
protected virtual TextContainer CreateTextContainer() => new TextContainer();
protected class TextContainer : Container, IHasText
{
public string Text
{
get { return NormalText.Text; }
set
{
NormalText.Text = value;
BoldText.Text = value;
}
}
public readonly SpriteText NormalText;
public readonly SpriteText BoldText;
public TextContainer()
{
Anchor = Anchor.CentreLeft;
Origin = Anchor.CentreLeft;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
NormalText = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
TextSize = text_size,
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
},
BoldText = new OsuSpriteText
{
AlwaysPresent = true,
Alpha = 0,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
TextSize = text_size,
Font = @"Exo2.0-Bold",
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
}
};
}
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Graphics.UserInterface
{
public class OsuMenu : Menu
{
public OsuMenu(Direction direction, bool topLevelMenu = false)
: base(direction, topLevelMenu)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
MaskingContainer.CornerRadius = 4;
ItemsContainer.Padding = new MarginPadding(5);
}
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
protected override void UpdateSize(Vector2 newSize)
{
if (Direction == Direction.Vertical)
{
Width = newSize.X;
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
}
else
{
Height = newSize.Y;
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
}
}
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item);
protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical)
{
Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight
};
protected class DrawableOsuMenuItem : DrawableMenuItem
{
private const int margin_horizontal = 17;
private const int text_size = 17;
private const int transition_length = 80;
public const int MARGIN_VERTICAL = 4;
private SampleChannel sampleClick;
private SampleChannel sampleHover;
private TextContainer text;
public DrawableOsuMenuItem(MenuItem item)
: base(item)
{
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleHover = audio.Sample.Get(@"UI/generic-hover");
sampleClick = audio.Sample.Get(@"UI/generic-select");
BackgroundColour = Color4.Transparent;
BackgroundColourHover = OsuColour.FromHex(@"172023");
updateTextColour();
}
private void updateTextColour()
{
switch ((Item as OsuMenuItem)?.Type)
{
default:
case MenuItemType.Standard:
text.Colour = Color4.White;
break;
case MenuItemType.Destructive:
text.Colour = Color4.Red;
break;
case MenuItemType.Highlighted:
text.Colour = OsuColour.FromHex(@"ffcc22");
break;
}
}
protected override bool OnHover(InputState state)
{
sampleHover.Play();
text.BoldText.FadeIn(transition_length, Easing.OutQuint);
text.NormalText.FadeOut(transition_length, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
text.BoldText.FadeOut(transition_length, Easing.OutQuint);
text.NormalText.FadeIn(transition_length, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
sampleClick.Play();
return base.OnClick(state);
}
protected sealed override Drawable CreateContent() => text = CreateTextContainer();
protected virtual TextContainer CreateTextContainer() => new TextContainer();
protected class TextContainer : Container, IHasText
{
public string Text
{
get { return NormalText.Text; }
set
{
NormalText.Text = value;
BoldText.Text = value;
}
}
public readonly SpriteText NormalText;
public readonly SpriteText BoldText;
public TextContainer()
{
Anchor = Anchor.CentreLeft;
Origin = Anchor.CentreLeft;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
NormalText = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
TextSize = text_size,
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
},
BoldText = new OsuSpriteText
{
AlwaysPresent = true,
Alpha = 0,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
TextSize = text_size,
Font = @"Exo2.0-Bold",
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
}
};
}
}
}
}
}

View File

@ -1,25 +1,25 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
public class OsuMenuItem : MenuItem
{
public readonly MenuItemType Type;
public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard)
: base(text)
{
Type = type;
}
public OsuMenuItem(string text, MenuItemType type, Action action)
: base(text, action)
{
Type = type;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
public class OsuMenuItem : MenuItem
{
public readonly MenuItemType Type;
public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard)
: base(text)
{
Type = type;
}
public OsuMenuItem(string text, MenuItemType type, Action action)
: base(text, action)
{
Type = type;
}
}
}

View File

@ -1,119 +1,119 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Platform;
namespace osu.Game.Graphics.UserInterface
{
public class OsuPasswordTextBox : OsuTextBox
{
protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize);
public override bool AllowClipboardExport => false;
private readonly CapsWarning warning;
private GameHost host;
public OsuPasswordTextBox()
{
Add(warning = new CapsWarning
{
Size = new Vector2(20),
Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight,
Margin = new MarginPadding { Right = 10 },
Alpha = 0,
});
}
[BackgroundDependencyLoader]
private void load(GameHost host)
{
this.host = host;
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.CapsLock)
updateCapsWarning(host.CapsLockEnabled);
return base.OnKeyDown(state, args);
}
protected override void OnFocus(InputState state)
{
updateCapsWarning(host.CapsLockEnabled);
base.OnFocus(state);
}
protected override void OnFocusLost(InputState state)
{
updateCapsWarning(false);
base.OnFocusLost(state);
}
private void updateCapsWarning(bool visible) => warning.FadeTo(visible ? 1 : 0, 250, Easing.OutQuint);
public class PasswordMaskChar : Container
{
private readonly CircularContainer circle;
public PasswordMaskChar(float size)
{
Size = new Vector2(size / 2, size);
Children = new[]
{
circle = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f, 0),
Children = new[]
{
new Box
{
Colour = Color4.White,
RelativeSizeAxes = Axes.Both,
}
},
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
circle.FadeIn(500, Easing.OutQuint);
circle.ResizeTo(new Vector2(0.8f), 500, Easing.OutQuint);
}
}
private class CapsWarning : SpriteIcon, IHasTooltip
{
public string TooltipText => @"Caps lock is active";
public CapsWarning()
{
Icon = FontAwesome.fa_warning;
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
Colour = colour.YellowLight;
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Platform;
namespace osu.Game.Graphics.UserInterface
{
public class OsuPasswordTextBox : OsuTextBox
{
protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize);
public override bool AllowClipboardExport => false;
private readonly CapsWarning warning;
private GameHost host;
public OsuPasswordTextBox()
{
Add(warning = new CapsWarning
{
Size = new Vector2(20),
Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight,
Margin = new MarginPadding { Right = 10 },
Alpha = 0,
});
}
[BackgroundDependencyLoader]
private void load(GameHost host)
{
this.host = host;
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.CapsLock)
updateCapsWarning(host.CapsLockEnabled);
return base.OnKeyDown(state, args);
}
protected override void OnFocus(InputState state)
{
updateCapsWarning(host.CapsLockEnabled);
base.OnFocus(state);
}
protected override void OnFocusLost(InputState state)
{
updateCapsWarning(false);
base.OnFocusLost(state);
}
private void updateCapsWarning(bool visible) => warning.FadeTo(visible ? 1 : 0, 250, Easing.OutQuint);
public class PasswordMaskChar : Container
{
private readonly CircularContainer circle;
public PasswordMaskChar(float size)
{
Size = new Vector2(size / 2, size);
Children = new[]
{
circle = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f, 0),
Children = new[]
{
new Box
{
Colour = Color4.White,
RelativeSizeAxes = Axes.Both,
}
},
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
circle.FadeIn(500, Easing.OutQuint);
circle.ResizeTo(new Vector2(0.8f), 500, Easing.OutQuint);
}
}
private class CapsWarning : SpriteIcon, IHasTooltip
{
public string TooltipText => @"Caps lock is active";
public CapsWarning()
{
Icon = FontAwesome.fa_warning;
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
Colour = colour.YellowLight;
}
}
}
}

View File

@ -1,218 +1,218 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Globalization;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface
{
public class OsuSliderBar<T> : SliderBar<T>, IHasTooltip, IHasAccentColour
where T : struct, IEquatable<T>, IComparable, IConvertible
{
/// <summary>
/// Maximum number of decimal digits to be displayed in the tooltip.
/// </summary>
private const int max_decimal_digits = 5;
private SampleChannel sample;
private double lastSampleTime;
private T lastSampleValue;
protected readonly Nub Nub;
private readonly Box leftBox;
private readonly Box rightBox;
public virtual string TooltipText
{
get
{
var bindableDouble = CurrentNumber as BindableNumber<double>;
var bindableFloat = CurrentNumber as BindableNumber<float>;
var floatValue = bindableDouble?.Value ?? bindableFloat?.Value;
var floatPrecision = bindableDouble?.Precision ?? bindableFloat?.Precision;
if (floatValue != null)
{
var floatMinValue = bindableDouble?.MinValue ?? bindableFloat.MinValue;
var floatMaxValue = bindableDouble?.MaxValue ?? bindableFloat.MaxValue;
if (floatMaxValue == 1 && (floatMinValue == 0 || floatMinValue == -1))
return floatValue.Value.ToString("P0");
var decimalPrecision = normalise((decimal)floatPrecision, max_decimal_digits);
// Find the number of significant digits (we could have less than 5 after normalize())
var significantDigits = findPrecision(decimalPrecision);
return floatValue.Value.ToString($"N{significantDigits}");
}
var bindableInt = CurrentNumber as BindableNumber<int>;
if (bindableInt != null)
return bindableInt.Value.ToString("N0");
return Current.Value.ToString(CultureInfo.InvariantCulture);
}
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
leftBox.Colour = value;
rightBox.Colour = value;
}
}
public OsuSliderBar()
{
Height = 12;
RangePadding = 20;
Children = new Drawable[]
{
leftBox = new Box
{
Height = 2,
EdgeSmoothness = new Vector2(0, 0.5f),
Position = new Vector2(2, 0),
RelativeSizeAxes = Axes.None,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
rightBox = new Box
{
Height = 2,
EdgeSmoothness = new Vector2(0, 0.5f),
Position = new Vector2(-2, 0),
RelativeSizeAxes = Axes.None,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Alpha = 0.5f,
},
Nub = new Nub
{
Origin = Anchor.TopCentre,
Expanded = true,
},
new HoverClickSounds()
};
Current.DisabledChanged += disabled =>
{
Alpha = disabled ? 0.3f : 1;
};
}
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
{
sample = audio.Sample.Get(@"UI/sliderbar-notch");
AccentColour = colours.Pink;
}
protected override bool OnHover(InputState state)
{
Nub.Glowing = true;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
Nub.Glowing = false;
base.OnHoverLost(state);
}
protected override void OnUserChange()
{
base.OnUserChange();
playSample();
}
private void playSample()
{
if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
return;
if (Current.Value.Equals(lastSampleValue))
return;
lastSampleValue = Current.Value;
lastSampleTime = Clock.CurrentTime;
sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
if (NormalizedValue == 0)
sample.Frequency.Value -= 0.4f;
else if (NormalizedValue == 1)
sample.Frequency.Value += 0.4f;
sample.Play();
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Nub.Current.Value = true;
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Nub.Current.Value = false;
return base.OnMouseUp(state, args);
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
leftBox.Scale = new Vector2(MathHelper.Clamp(
Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
rightBox.Scale = new Vector2(MathHelper.Clamp(
DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
}
protected override void UpdateValue(float value)
{
Nub.MoveToX(RangePadding + UsableWidth * value, 250, Easing.OutQuint);
}
/// <summary>
/// Removes all non-significant digits, keeping at most a requested number of decimal digits.
/// </summary>
/// <param name="d">The decimal to normalize.</param>
/// <param name="sd">The maximum number of decimal digits to keep. The final result may have fewer decimal digits than this value.</param>
/// <returns>The normalised decimal.</returns>
private decimal normalise(decimal d, int sd)
=> decimal.Parse(Math.Round(d, sd).ToString(string.Concat("0.", new string('#', sd)), CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
/// <summary>
/// Finds the number of digits after the decimal.
/// </summary>
/// <param name="d">The value to find the number of decimal digits for.</param>
/// <returns>The number decimal digits.</returns>
private int findPrecision(decimal d)
{
int precision = 0;
while (d != Math.Round(d))
{
d *= 10;
precision++;
}
return precision;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Globalization;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface
{
public class OsuSliderBar<T> : SliderBar<T>, IHasTooltip, IHasAccentColour
where T : struct, IEquatable<T>, IComparable, IConvertible
{
/// <summary>
/// Maximum number of decimal digits to be displayed in the tooltip.
/// </summary>
private const int max_decimal_digits = 5;
private SampleChannel sample;
private double lastSampleTime;
private T lastSampleValue;
protected readonly Nub Nub;
private readonly Box leftBox;
private readonly Box rightBox;
public virtual string TooltipText
{
get
{
var bindableDouble = CurrentNumber as BindableNumber<double>;
var bindableFloat = CurrentNumber as BindableNumber<float>;
var floatValue = bindableDouble?.Value ?? bindableFloat?.Value;
var floatPrecision = bindableDouble?.Precision ?? bindableFloat?.Precision;
if (floatValue != null)
{
var floatMinValue = bindableDouble?.MinValue ?? bindableFloat.MinValue;
var floatMaxValue = bindableDouble?.MaxValue ?? bindableFloat.MaxValue;
if (floatMaxValue == 1 && (floatMinValue == 0 || floatMinValue == -1))
return floatValue.Value.ToString("P0");
var decimalPrecision = normalise((decimal)floatPrecision, max_decimal_digits);
// Find the number of significant digits (we could have less than 5 after normalize())
var significantDigits = findPrecision(decimalPrecision);
return floatValue.Value.ToString($"N{significantDigits}");
}
var bindableInt = CurrentNumber as BindableNumber<int>;
if (bindableInt != null)
return bindableInt.Value.ToString("N0");
return Current.Value.ToString(CultureInfo.InvariantCulture);
}
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
leftBox.Colour = value;
rightBox.Colour = value;
}
}
public OsuSliderBar()
{
Height = 12;
RangePadding = 20;
Children = new Drawable[]
{
leftBox = new Box
{
Height = 2,
EdgeSmoothness = new Vector2(0, 0.5f),
Position = new Vector2(2, 0),
RelativeSizeAxes = Axes.None,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
rightBox = new Box
{
Height = 2,
EdgeSmoothness = new Vector2(0, 0.5f),
Position = new Vector2(-2, 0),
RelativeSizeAxes = Axes.None,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Alpha = 0.5f,
},
Nub = new Nub
{
Origin = Anchor.TopCentre,
Expanded = true,
},
new HoverClickSounds()
};
Current.DisabledChanged += disabled =>
{
Alpha = disabled ? 0.3f : 1;
};
}
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
{
sample = audio.Sample.Get(@"UI/sliderbar-notch");
AccentColour = colours.Pink;
}
protected override bool OnHover(InputState state)
{
Nub.Glowing = true;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
Nub.Glowing = false;
base.OnHoverLost(state);
}
protected override void OnUserChange()
{
base.OnUserChange();
playSample();
}
private void playSample()
{
if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
return;
if (Current.Value.Equals(lastSampleValue))
return;
lastSampleValue = Current.Value;
lastSampleTime = Clock.CurrentTime;
sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
if (NormalizedValue == 0)
sample.Frequency.Value -= 0.4f;
else if (NormalizedValue == 1)
sample.Frequency.Value += 0.4f;
sample.Play();
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Nub.Current.Value = true;
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Nub.Current.Value = false;
return base.OnMouseUp(state, args);
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
leftBox.Scale = new Vector2(MathHelper.Clamp(
Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
rightBox.Scale = new Vector2(MathHelper.Clamp(
DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
}
protected override void UpdateValue(float value)
{
Nub.MoveToX(RangePadding + UsableWidth * value, 250, Easing.OutQuint);
}
/// <summary>
/// Removes all non-significant digits, keeping at most a requested number of decimal digits.
/// </summary>
/// <param name="d">The decimal to normalize.</param>
/// <param name="sd">The maximum number of decimal digits to keep. The final result may have fewer decimal digits than this value.</param>
/// <returns>The normalised decimal.</returns>
private decimal normalise(decimal d, int sd)
=> decimal.Parse(Math.Round(d, sd).ToString(string.Concat("0.", new string('#', sd)), CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
/// <summary>
/// Finds the number of digits after the decimal.
/// </summary>
/// <param name="d">The value to find the number of decimal digits for.</param>
/// <returns>The number decimal digits.</returns>
private int findPrecision(decimal d)
{
int precision = 0;
while (d != Math.Round(d))
{
d *= 10;
precision++;
}
return precision;
}
}
}

View File

@ -1,286 +1,286 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.MathUtils;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTabControl<T> : TabControl<T>
{
private readonly Box strip;
protected override Dropdown<T> CreateDropdown() => new OsuTabDropdown();
protected override TabItem<T> CreateTabItem(T value) => new OsuTabItem(value);
protected virtual float StripWidth() => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X;
protected virtual float StripHeight() => 1;
private static bool isEnumType => typeof(T).IsEnum;
public OsuTabControl()
{
TabContainer.Spacing = new Vector2(10f, 0f);
Add(strip = new Box
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Height = StripHeight(),
Colour = Color4.White.Opacity(0),
});
if (isEnumType)
foreach (var val in (T[])Enum.GetValues(typeof(T)))
AddItem(val);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == default(Color4))
AccentColour = colours.Blue;
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
var dropdown = Dropdown as IHasAccentColour;
if (dropdown != null)
dropdown.AccentColour = value;
foreach (var i in TabContainer.Children.OfType<IHasAccentColour>())
i.AccentColour = value;
}
}
public Color4 StripColour
{
get => strip.Colour;
set => strip.Colour = value;
}
protected override TabFillFlowContainer CreateTabFlow() => new OsuTabFillFlowContainer
{
Direction = FillDirection.Full,
RelativeSizeAxes = Axes.Both,
Depth = -1,
Masking = true
};
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
// dont bother calculating if the strip is invisible
if (strip.Colour.MaxAlpha > 0)
strip.Width = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth(), 0, 500, Easing.OutQuint);
}
public class OsuTabItem : TabItem<T>, IHasAccentColour
{
protected readonly SpriteText Text;
protected readonly Box Bar;
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
if (!Active)
Text.Colour = value;
}
}
private const float transition_length = 500;
private void fadeActive()
{
Bar.FadeIn(transition_length, Easing.OutQuint);
Text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
}
private void fadeInactive()
{
Bar.FadeOut(transition_length, Easing.OutQuint);
Text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
if (!Active)
fadeActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
fadeInactive();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == default(Color4))
AccentColour = colours.Blue;
}
public OsuTabItem(T value) : base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
Text = new OsuSpriteText
{
Margin = new MarginPadding { Top = 5, Bottom = 5 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Text = (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active?
},
Bar = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
new HoverClickSounds()
};
}
protected override void OnActivated() => fadeActive();
protected override void OnDeactivated() => fadeInactive();
}
// todo: this needs to go
private class OsuTabDropdown : OsuDropdown<T>
{
public OsuTabDropdown()
{
RelativeSizeAxes = Axes.X;
}
protected override DropdownMenu CreateMenu() => new OsuTabDropdownMenu();
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight
};
private class OsuTabDropdownMenu : OsuDropdownMenu
{
public OsuTabDropdownMenu()
{
Anchor = Anchor.TopRight;
Origin = Anchor.TopRight;
BackgroundColour = Color4.Black.Opacity(0.7f);
MaxHeight = 400;
}
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuTabDropdownMenuItem(item) { AccentColour = AccentColour };
private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem
{
public DrawableOsuTabDropdownMenuItem(MenuItem item)
: base(item)
{
ForegroundColourHover = Color4.Black;
}
}
}
protected class OsuTabDropdownHeader : OsuDropdownHeader
{
public override Color4 AccentColour
{
get
{
return base.AccentColour;
}
set
{
base.AccentColour = value;
Foreground.Colour = value;
}
}
public OsuTabDropdownHeader()
{
RelativeSizeAxes = Axes.None;
AutoSizeAxes = Axes.X;
BackgroundColour = Color4.Black.Opacity(0.5f);
Background.Height = 0.5f;
Background.CornerRadius = 5;
Background.Masking = true;
Foreground.RelativeSizeAxes = Axes.None;
Foreground.AutoSizeAxes = Axes.X;
Foreground.RelativeSizeAxes = Axes.Y;
Foreground.Margin = new MarginPadding(5);
Foreground.Children = new Drawable[]
{
new SpriteIcon
{
Icon = FontAwesome.fa_ellipsis_h,
Size = new Vector2(14),
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
};
Padding = new MarginPadding { Left = 5, Right = 5 };
}
protected override bool OnHover(InputState state)
{
Foreground.Colour = BackgroundColour;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
Foreground.Colour = BackgroundColourHover;
base.OnHoverLost(state);
}
}
}
private class OsuTabFillFlowContainer : TabFillFlowContainer
{
protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.MathUtils;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTabControl<T> : TabControl<T>
{
private readonly Box strip;
protected override Dropdown<T> CreateDropdown() => new OsuTabDropdown();
protected override TabItem<T> CreateTabItem(T value) => new OsuTabItem(value);
protected virtual float StripWidth() => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X;
protected virtual float StripHeight() => 1;
private static bool isEnumType => typeof(T).IsEnum;
public OsuTabControl()
{
TabContainer.Spacing = new Vector2(10f, 0f);
Add(strip = new Box
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Height = StripHeight(),
Colour = Color4.White.Opacity(0),
});
if (isEnumType)
foreach (var val in (T[])Enum.GetValues(typeof(T)))
AddItem(val);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == default(Color4))
AccentColour = colours.Blue;
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
var dropdown = Dropdown as IHasAccentColour;
if (dropdown != null)
dropdown.AccentColour = value;
foreach (var i in TabContainer.Children.OfType<IHasAccentColour>())
i.AccentColour = value;
}
}
public Color4 StripColour
{
get => strip.Colour;
set => strip.Colour = value;
}
protected override TabFillFlowContainer CreateTabFlow() => new OsuTabFillFlowContainer
{
Direction = FillDirection.Full,
RelativeSizeAxes = Axes.Both,
Depth = -1,
Masking = true
};
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
// dont bother calculating if the strip is invisible
if (strip.Colour.MaxAlpha > 0)
strip.Width = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth(), 0, 500, Easing.OutQuint);
}
public class OsuTabItem : TabItem<T>, IHasAccentColour
{
protected readonly SpriteText Text;
protected readonly Box Bar;
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
if (!Active)
Text.Colour = value;
}
}
private const float transition_length = 500;
private void fadeActive()
{
Bar.FadeIn(transition_length, Easing.OutQuint);
Text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
}
private void fadeInactive()
{
Bar.FadeOut(transition_length, Easing.OutQuint);
Text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
if (!Active)
fadeActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
fadeInactive();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == default(Color4))
AccentColour = colours.Blue;
}
public OsuTabItem(T value) : base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
Text = new OsuSpriteText
{
Margin = new MarginPadding { Top = 5, Bottom = 5 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Text = (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active?
},
Bar = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
new HoverClickSounds()
};
}
protected override void OnActivated() => fadeActive();
protected override void OnDeactivated() => fadeInactive();
}
// todo: this needs to go
private class OsuTabDropdown : OsuDropdown<T>
{
public OsuTabDropdown()
{
RelativeSizeAxes = Axes.X;
}
protected override DropdownMenu CreateMenu() => new OsuTabDropdownMenu();
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight
};
private class OsuTabDropdownMenu : OsuDropdownMenu
{
public OsuTabDropdownMenu()
{
Anchor = Anchor.TopRight;
Origin = Anchor.TopRight;
BackgroundColour = Color4.Black.Opacity(0.7f);
MaxHeight = 400;
}
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuTabDropdownMenuItem(item) { AccentColour = AccentColour };
private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem
{
public DrawableOsuTabDropdownMenuItem(MenuItem item)
: base(item)
{
ForegroundColourHover = Color4.Black;
}
}
}
protected class OsuTabDropdownHeader : OsuDropdownHeader
{
public override Color4 AccentColour
{
get
{
return base.AccentColour;
}
set
{
base.AccentColour = value;
Foreground.Colour = value;
}
}
public OsuTabDropdownHeader()
{
RelativeSizeAxes = Axes.None;
AutoSizeAxes = Axes.X;
BackgroundColour = Color4.Black.Opacity(0.5f);
Background.Height = 0.5f;
Background.CornerRadius = 5;
Background.Masking = true;
Foreground.RelativeSizeAxes = Axes.None;
Foreground.AutoSizeAxes = Axes.X;
Foreground.RelativeSizeAxes = Axes.Y;
Foreground.Margin = new MarginPadding(5);
Foreground.Children = new Drawable[]
{
new SpriteIcon
{
Icon = FontAwesome.fa_ellipsis_h,
Size = new Vector2(14),
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
};
Padding = new MarginPadding { Left = 5, Right = 5 };
}
protected override bool OnHover(InputState state)
{
Foreground.Colour = BackgroundColour;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
Foreground.Colour = BackgroundColourHover;
base.OnHoverLost(state);
}
}
}
private class OsuTabFillFlowContainer : TabFillFlowContainer
{
protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y);
}
}
}

View File

@ -1,136 +1,136 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A Checkbox styled to be placed in line with an <see cref="OsuTabControl{T}"/>
/// </summary>
public class OsuTabControlCheckbox : Checkbox
{
private readonly Box box;
private readonly SpriteText text;
private readonly SpriteIcon icon;
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (Current)
{
text.Colour = AccentColour;
icon.Colour = AccentColour;
}
}
}
public string Text
{
get { return text.Text; }
set { text.Text = value; }
}
private const float transition_length = 500;
private void fadeIn()
{
box.FadeIn(transition_length, Easing.OutQuint);
text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
}
private void fadeOut()
{
box.FadeOut(transition_length, Easing.OutQuint);
text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
fadeIn();
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
if (!Current)
fadeOut();
base.OnHoverLost(state);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.Blue;
}
public OsuTabControlCheckbox()
{
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = 5, Bottom = 5, },
Spacing = new Vector2(5f, 0f),
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
text = new OsuSpriteText
{
TextSize = 14,
Font = @"Exo2.0-Bold",
},
icon = new SpriteIcon
{
Size = new Vector2(14),
Icon = FontAwesome.fa_circle_o,
Shadow = true,
},
},
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
};
Current.ValueChanged += v =>
{
if (v)
{
fadeIn();
icon.Icon = FontAwesome.fa_check_circle_o;
}
else
{
fadeOut();
icon.Icon = FontAwesome.fa_circle_o;
}
};
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A Checkbox styled to be placed in line with an <see cref="OsuTabControl{T}"/>
/// </summary>
public class OsuTabControlCheckbox : Checkbox
{
private readonly Box box;
private readonly SpriteText text;
private readonly SpriteIcon icon;
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (Current)
{
text.Colour = AccentColour;
icon.Colour = AccentColour;
}
}
}
public string Text
{
get { return text.Text; }
set { text.Text = value; }
}
private const float transition_length = 500;
private void fadeIn()
{
box.FadeIn(transition_length, Easing.OutQuint);
text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
}
private void fadeOut()
{
box.FadeOut(transition_length, Easing.OutQuint);
text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
fadeIn();
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
if (!Current)
fadeOut();
base.OnHoverLost(state);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.Blue;
}
public OsuTabControlCheckbox()
{
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = 5, Bottom = 5, },
Spacing = new Vector2(5f, 0f),
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
text = new OsuSpriteText
{
TextSize = 14,
Font = @"Exo2.0-Bold",
},
icon = new SpriteIcon
{
Size = new Vector2(14),
Icon = FontAwesome.fa_circle_o,
Shadow = true,
},
},
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
};
Current.ValueChanged += v =>
{
if (v)
{
fadeIn();
icon.Icon = FontAwesome.fa_check_circle_o;
}
else
{
fadeOut();
icon.Icon = FontAwesome.fa_circle_o;
}
};
}
}
}

View File

@ -1,63 +1,63 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTextBox : TextBox
{
protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f);
protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f);
protected override Color4 BackgroundCommit => BorderColour;
protected override float LeftRightPadding => 10;
protected override SpriteText CreatePlaceholder() => new OsuSpriteText
{
Font = @"Exo2.0-MediumItalic",
Colour = new Color4(180, 180, 180, 255),
Margin = new MarginPadding { Left = 2 },
};
public OsuTextBox()
{
Height = 40;
TextContainer.Height = 0.5f;
CornerRadius = 5;
Current.DisabledChanged += disabled =>
{
Alpha = disabled ? 0.3f : 1;
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
BorderColour = colour.Yellow;
}
protected override void OnFocus(InputState state)
{
BorderThickness = 3;
base.OnFocus(state);
}
protected override void OnFocusLost(InputState state)
{
BorderThickness = 0;
base.OnFocusLost(state);
}
protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize };
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTextBox : TextBox
{
protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f);
protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f);
protected override Color4 BackgroundCommit => BorderColour;
protected override float LeftRightPadding => 10;
protected override SpriteText CreatePlaceholder() => new OsuSpriteText
{
Font = @"Exo2.0-MediumItalic",
Colour = new Color4(180, 180, 180, 255),
Margin = new MarginPadding { Left = 2 },
};
public OsuTextBox()
{
Height = 40;
TextContainer.Height = 0.5f;
CornerRadius = 5;
Current.DisabledChanged += disabled =>
{
Alpha = disabled ? 0.3f : 1;
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
BorderColour = colour.Yellow;
}
protected override void OnFocus(InputState state)
{
BorderThickness = 3;
base.OnFocus(state);
}
protected override void OnFocusLost(InputState state)
{
BorderThickness = 0;
base.OnFocusLost(state);
}
protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize };
}
}

View File

@ -1,98 +1,98 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class PageTabControl<T> : OsuTabControl<T>
{
protected override TabItem<T> CreateTabItem(T value) => new PageTabItem(value);
public PageTabControl()
{
Height = 30;
}
public class PageTabItem : TabItem<T>
{
private const float transition_duration = 100;
private readonly Box box;
protected readonly SpriteText Text;
public PageTabItem(T value) : base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
Text = new OsuSpriteText
{
Margin = new MarginPadding { Top = 8, Bottom = 8 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Text = (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14,
Font = @"Exo2.0-Bold",
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 5,
Scale = new Vector2(1f, 0f),
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
new HoverClickSounds()
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
box.Colour = colours.Yellow;
}
protected override bool OnHover(InputState state)
{
if (!Active)
slideActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
slideInactive();
}
private void slideActive()
{
box.ScaleTo(new Vector2(1f), transition_duration);
}
private void slideInactive()
{
box.ScaleTo(new Vector2(1f, 0f), transition_duration);
}
protected override void OnActivated() => slideActive();
protected override void OnDeactivated() => slideInactive();
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class PageTabControl<T> : OsuTabControl<T>
{
protected override TabItem<T> CreateTabItem(T value) => new PageTabItem(value);
public PageTabControl()
{
Height = 30;
}
public class PageTabItem : TabItem<T>
{
private const float transition_duration = 100;
private readonly Box box;
protected readonly SpriteText Text;
public PageTabItem(T value) : base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
Text = new OsuSpriteText
{
Margin = new MarginPadding { Top = 8, Bottom = 8 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Text = (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14,
Font = @"Exo2.0-Bold",
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 5,
Scale = new Vector2(1f, 0f),
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
new HoverClickSounds()
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
box.Colour = colours.Yellow;
}
protected override bool OnHover(InputState state)
{
if (!Active)
slideActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
slideInactive();
}
private void slideActive()
{
box.ScaleTo(new Vector2(1f), transition_duration);
}
private void slideInactive()
{
box.ScaleTo(new Vector2(1f, 0f), transition_duration);
}
protected override void OnActivated() => slideActive();
protected override void OnDeactivated() => slideInactive();
}
}
}

View File

@ -1,43 +1,43 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Used as an accuracy counter. Represented visually as a percentage.
/// </summary>
public class PercentageCounter : RollingCounter<double>
{
protected override double RollingDuration => 750;
private float epsilon => 1e-10f;
public void SetFraction(float numerator, float denominator)
{
Current.Value = Math.Abs(denominator) < epsilon ? 1.0f : numerator / denominator;
}
public PercentageCounter()
{
DisplayedCountSpriteText.FixedWidth = true;
Current.Value = DisplayedCount = 1.0f;
}
protected override string FormatCount(double count)
{
return $@"{count:P2}";
}
protected override double GetProportionalDuration(double currentValue, double newValue)
{
return Math.Abs(currentValue - newValue) * RollingDuration * 100.0f;
}
public override void Increment(double amount)
{
Current.Value = Current + amount;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Used as an accuracy counter. Represented visually as a percentage.
/// </summary>
public class PercentageCounter : RollingCounter<double>
{
protected override double RollingDuration => 750;
private float epsilon => 1e-10f;
public void SetFraction(float numerator, float denominator)
{
Current.Value = Math.Abs(denominator) < epsilon ? 1.0f : numerator / denominator;
}
public PercentageCounter()
{
DisplayedCountSpriteText.FixedWidth = true;
Current.Value = DisplayedCount = 1.0f;
}
protected override string FormatCount(double count)
{
return $@"{count:P2}";
}
protected override double GetProportionalDuration(double currentValue, double newValue)
{
return Math.Abs(currentValue - newValue) * RollingDuration * 100.0f;
}
public override void Increment(double amount)
{
Current.Value = Current + amount;
}
}
}

View File

@ -1,67 +1,67 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class ProgressBar : SliderBar<double>
{
public Action<double> OnSeek;
private readonly Box fill;
private readonly Box background;
public Color4 FillColour
{
set { fill.FadeColour(value, 150, Easing.OutQuint); }
}
public Color4 BackgroundColour
{
set
{
background.Alpha = 1;
background.Colour = value;
}
}
public double EndTime
{
set { CurrentNumber.MaxValue = value; }
}
public double CurrentTime
{
set { CurrentNumber.Value = value; }
}
public ProgressBar()
{
CurrentNumber.MinValue = 0;
CurrentNumber.MaxValue = 1;
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
background = new Box
{
Alpha = 0,
RelativeSizeAxes = Axes.Both
},
fill = new Box { RelativeSizeAxes = Axes.Y }
};
}
protected override void UpdateValue(float value)
{
fill.Width = value * UsableWidth;
}
protected override void OnUserChange() => OnSeek?.Invoke(Current);
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class ProgressBar : SliderBar<double>
{
public Action<double> OnSeek;
private readonly Box fill;
private readonly Box background;
public Color4 FillColour
{
set { fill.FadeColour(value, 150, Easing.OutQuint); }
}
public Color4 BackgroundColour
{
set
{
background.Alpha = 1;
background.Colour = value;
}
}
public double EndTime
{
set { CurrentNumber.MaxValue = value; }
}
public double CurrentTime
{
set { CurrentNumber.Value = value; }
}
public ProgressBar()
{
CurrentNumber.MinValue = 0;
CurrentNumber.MaxValue = 1;
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
background = new Box
{
Alpha = 0,
RelativeSizeAxes = Axes.Both
},
fill = new Box { RelativeSizeAxes = Axes.Y }
};
}
protected override void UpdateValue(float value)
{
fill.Width = value * UsableWidth;
}
protected override void OnUserChange() => OnSeek?.Invoke(Current);
}
}

View File

@ -1,182 +1,182 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
using System;
using System.Collections.Generic;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public abstract class RollingCounter<T> : Container, IHasAccentColour
where T : struct, IEquatable<T>
{
/// <summary>
/// The current value.
/// </summary>
public Bindable<T> Current = new Bindable<T>();
protected SpriteText DisplayedCountSpriteText;
/// <summary>
/// If true, the roll-up duration will be proportional to change in value.
/// </summary>
protected virtual bool IsRollingProportional => false;
/// <summary>
/// If IsRollingProportional = false, duration in milliseconds for the counter roll-up animation for each
/// element; else duration in milliseconds for the counter roll-up animation in total.
/// </summary>
protected virtual double RollingDuration => 0;
/// <summary>
/// Easing for the counter rollover animation.
/// </summary>
protected virtual Easing RollingEasing => Easing.OutQuint;
private T displayedCount;
/// <summary>
/// Value shown at the current moment.
/// </summary>
public virtual T DisplayedCount
{
get
{
return displayedCount;
}
set
{
if (EqualityComparer<T>.Default.Equals(displayedCount, value))
return;
displayedCount = value;
DisplayedCountSpriteText.Text = FormatCount(value);
}
}
public abstract void Increment(T amount);
private float textSize;
public float TextSize
{
get { return textSize; }
set
{
textSize = value;
DisplayedCountSpriteText.TextSize = value;
}
}
public Color4 AccentColour
{
get { return DisplayedCountSpriteText.Colour; }
set { DisplayedCountSpriteText.Colour = value; }
}
/// <summary>
/// Skeleton of a numeric counter which value rolls over time.
/// </summary>
protected RollingCounter()
{
Children = new Drawable[]
{
DisplayedCountSpriteText = new OsuSpriteText
{
Font = @"Venera"
},
};
TextSize = 40;
AutoSizeAxes = Axes.Both;
DisplayedCount = Current;
Current.ValueChanged += newValue =>
{
if (IsLoaded) TransformCount(displayedCount, newValue);
};
}
protected override void LoadComplete()
{
base.LoadComplete();
DisplayedCountSpriteText.Text = FormatCount(Current);
}
/// <summary>
/// Sets count value, bypassing rollover animation.
/// </summary>
/// <param name="count">New count value.</param>
public virtual void SetCountWithoutRolling(T count)
{
Current.Value = count;
StopRolling();
}
/// <summary>
/// Stops rollover animation, forcing the displayed count to be the actual count.
/// </summary>
public virtual void StopRolling()
{
FinishTransforms(false, nameof(DisplayedCount));
DisplayedCount = Current;
}
/// <summary>
/// Resets count to default value.
/// </summary>
public virtual void ResetCount()
{
SetCountWithoutRolling(default(T));
}
/// <summary>
/// Calculates the duration of the roll-up animation by using the difference between the current visible value
/// and the new final value.
/// </summary>
/// <remarks>
/// To be used in conjunction with IsRollingProportional = true.
/// Unless a derived class needs to have a proportional rolling, it is not necessary to override this function.
/// </remarks>
/// <param name="currentValue">Current visible value.</param>
/// <param name="newValue">New final value.</param>
/// <returns>Calculated rollover duration in milliseconds.</returns>
protected virtual double GetProportionalDuration(T currentValue, T newValue)
{
return RollingDuration;
}
/// <summary>
/// Used to format counts.
/// </summary>
/// <param name="count">Count to format.</param>
/// <returns>Count formatted as a string.</returns>
protected virtual string FormatCount(T count)
{
return count.ToString();
}
/// <summary>
/// Called when the count is updated to add a transformer that changes the value of the visible count (i.e.
/// implement the rollover animation).
/// </summary>
/// <param name="currentValue">Count value before modification.</param>
/// <param name="newValue">Expected count value after modification.</param>
protected virtual void TransformCount(T currentValue, T newValue)
{
double rollingTotalDuration =
IsRollingProportional
? GetProportionalDuration(currentValue, newValue)
: RollingDuration;
this.TransformTo(nameof(DisplayedCount), newValue, rollingTotalDuration, RollingEasing);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
using System;
using System.Collections.Generic;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public abstract class RollingCounter<T> : Container, IHasAccentColour
where T : struct, IEquatable<T>
{
/// <summary>
/// The current value.
/// </summary>
public Bindable<T> Current = new Bindable<T>();
protected SpriteText DisplayedCountSpriteText;
/// <summary>
/// If true, the roll-up duration will be proportional to change in value.
/// </summary>
protected virtual bool IsRollingProportional => false;
/// <summary>
/// If IsRollingProportional = false, duration in milliseconds for the counter roll-up animation for each
/// element; else duration in milliseconds for the counter roll-up animation in total.
/// </summary>
protected virtual double RollingDuration => 0;
/// <summary>
/// Easing for the counter rollover animation.
/// </summary>
protected virtual Easing RollingEasing => Easing.OutQuint;
private T displayedCount;
/// <summary>
/// Value shown at the current moment.
/// </summary>
public virtual T DisplayedCount
{
get
{
return displayedCount;
}
set
{
if (EqualityComparer<T>.Default.Equals(displayedCount, value))
return;
displayedCount = value;
DisplayedCountSpriteText.Text = FormatCount(value);
}
}
public abstract void Increment(T amount);
private float textSize;
public float TextSize
{
get { return textSize; }
set
{
textSize = value;
DisplayedCountSpriteText.TextSize = value;
}
}
public Color4 AccentColour
{
get { return DisplayedCountSpriteText.Colour; }
set { DisplayedCountSpriteText.Colour = value; }
}
/// <summary>
/// Skeleton of a numeric counter which value rolls over time.
/// </summary>
protected RollingCounter()
{
Children = new Drawable[]
{
DisplayedCountSpriteText = new OsuSpriteText
{
Font = @"Venera"
},
};
TextSize = 40;
AutoSizeAxes = Axes.Both;
DisplayedCount = Current;
Current.ValueChanged += newValue =>
{
if (IsLoaded) TransformCount(displayedCount, newValue);
};
}
protected override void LoadComplete()
{
base.LoadComplete();
DisplayedCountSpriteText.Text = FormatCount(Current);
}
/// <summary>
/// Sets count value, bypassing rollover animation.
/// </summary>
/// <param name="count">New count value.</param>
public virtual void SetCountWithoutRolling(T count)
{
Current.Value = count;
StopRolling();
}
/// <summary>
/// Stops rollover animation, forcing the displayed count to be the actual count.
/// </summary>
public virtual void StopRolling()
{
FinishTransforms(false, nameof(DisplayedCount));
DisplayedCount = Current;
}
/// <summary>
/// Resets count to default value.
/// </summary>
public virtual void ResetCount()
{
SetCountWithoutRolling(default(T));
}
/// <summary>
/// Calculates the duration of the roll-up animation by using the difference between the current visible value
/// and the new final value.
/// </summary>
/// <remarks>
/// To be used in conjunction with IsRollingProportional = true.
/// Unless a derived class needs to have a proportional rolling, it is not necessary to override this function.
/// </remarks>
/// <param name="currentValue">Current visible value.</param>
/// <param name="newValue">New final value.</param>
/// <returns>Calculated rollover duration in milliseconds.</returns>
protected virtual double GetProportionalDuration(T currentValue, T newValue)
{
return RollingDuration;
}
/// <summary>
/// Used to format counts.
/// </summary>
/// <param name="count">Count to format.</param>
/// <returns>Count formatted as a string.</returns>
protected virtual string FormatCount(T count)
{
return count.ToString();
}
/// <summary>
/// Called when the count is updated to add a transformer that changes the value of the visible count (i.e.
/// implement the rollover animation).
/// </summary>
/// <param name="currentValue">Count value before modification.</param>
/// <param name="newValue">Expected count value after modification.</param>
protected virtual void TransformCount(T currentValue, T newValue)
{
double rollingTotalDuration =
IsRollingProportional
? GetProportionalDuration(currentValue, newValue)
: RollingDuration;
this.TransformTo(nameof(DisplayedCount), newValue, rollingTotalDuration, RollingEasing);
}
}
}

View File

@ -1,54 +1,54 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class ScoreCounter : RollingCounter<double>
{
protected override double RollingDuration => 1000;
protected override Easing RollingEasing => Easing.Out;
public bool UseCommaSeparator;
/// <summary>
/// How many leading zeroes the counter has.
/// </summary>
public uint LeadingZeroes
{
get;
protected set;
}
/// <summary>
/// Displays score.
/// </summary>
/// <param name="leading">How many leading zeroes the counter will have.</param>
public ScoreCounter(uint leading = 0)
{
DisplayedCountSpriteText.FixedWidth = true;
LeadingZeroes = leading;
}
protected override double GetProportionalDuration(double currentValue, double newValue)
{
return currentValue > newValue ? currentValue - newValue : newValue - currentValue;
}
protected override string FormatCount(double count)
{
string format = new string('0', (int)LeadingZeroes);
if (UseCommaSeparator)
for (int i = format.Length - 3; i > 0; i -= 3)
format = format.Insert(i, @",");
return ((long)count).ToString(format);
}
public override void Increment(double amount)
{
Current.Value = Current + amount;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class ScoreCounter : RollingCounter<double>
{
protected override double RollingDuration => 1000;
protected override Easing RollingEasing => Easing.Out;
public bool UseCommaSeparator;
/// <summary>
/// How many leading zeroes the counter has.
/// </summary>
public uint LeadingZeroes
{
get;
protected set;
}
/// <summary>
/// Displays score.
/// </summary>
/// <param name="leading">How many leading zeroes the counter will have.</param>
public ScoreCounter(uint leading = 0)
{
DisplayedCountSpriteText.FixedWidth = true;
LeadingZeroes = leading;
}
protected override double GetProportionalDuration(double currentValue, double newValue)
{
return currentValue > newValue ? currentValue - newValue : newValue - currentValue;
}
protected override string FormatCount(double count)
{
string format = new string('0', (int)LeadingZeroes);
if (UseCommaSeparator)
for (int i = format.Length - 3; i > 0; i -= 3)
format = format.Insert(i, @",");
return ((long)count).ToString(format);
}
public override void Increment(double amount)
{
Current.Value = Current + amount;
}
}
}

View File

@ -1,73 +1,73 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Input;
namespace osu.Game.Graphics.UserInterface
{
public class SearchTextBox : FocusedTextBox
{
protected virtual bool AllowCommit => false;
public override bool HandleLeftRightArrows => false;
public SearchTextBox()
{
Height = 35;
AddRange(new Drawable[]
{
new SpriteIcon
{
Icon = FontAwesome.fa_search,
Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight,
Margin = new MarginPadding { Right = 10 },
Size = new Vector2(20),
}
});
PlaceholderText = "type to search";
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (HandlePendingText(state)) return true;
if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed)
{
switch (args.Key)
{
case Key.Left:
case Key.Right:
case Key.Up:
case Key.Down:
return false;
}
}
if (!AllowCommit)
{
switch (args.Key)
{
case Key.KeypadEnter:
case Key.Enter:
return false;
}
}
if (state.Keyboard.ShiftPressed)
{
switch (args.Key)
{
case Key.Delete:
return false;
}
}
return base.OnKeyDown(state, args);
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Input;
namespace osu.Game.Graphics.UserInterface
{
public class SearchTextBox : FocusedTextBox
{
protected virtual bool AllowCommit => false;
public override bool HandleLeftRightArrows => false;
public SearchTextBox()
{
Height = 35;
AddRange(new Drawable[]
{
new SpriteIcon
{
Icon = FontAwesome.fa_search,
Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight,
Margin = new MarginPadding { Right = 10 },
Size = new Vector2(20),
}
});
PlaceholderText = "type to search";
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (HandlePendingText(state)) return true;
if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed)
{
switch (args.Key)
{
case Key.Left:
case Key.Right:
case Key.Up:
case Key.Down:
return false;
}
}
if (!AllowCommit)
{
switch (args.Key)
{
case Key.KeypadEnter:
case Key.Enter:
return false;
}
}
if (state.Keyboard.ShiftPressed)
{
switch (args.Key)
{
case Key.Delete:
return false;
}
}
return base.OnKeyDown(state, args);
}
}
}

View File

@ -1,35 +1,35 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Used as an accuracy counter. Represented visually as a percentage.
/// </summary>
public class SimpleComboCounter : RollingCounter<int>
{
protected override double RollingDuration => 750;
public SimpleComboCounter()
{
Current.Value = DisplayedCount = 0;
}
protected override string FormatCount(int count)
{
return $@"{count}x";
}
protected override double GetProportionalDuration(int currentValue, int newValue)
{
return Math.Abs(currentValue - newValue) * RollingDuration * 100.0f;
}
public override void Increment(int amount)
{
Current.Value = Current + amount;
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Used as an accuracy counter. Represented visually as a percentage.
/// </summary>
public class SimpleComboCounter : RollingCounter<int>
{
protected override double RollingDuration => 750;
public SimpleComboCounter()
{
Current.Value = DisplayedCount = 0;
}
protected override string FormatCount(int count)
{
return $@"{count}x";
}
protected override double GetProportionalDuration(int currentValue, int newValue)
{
return Math.Abs(currentValue - newValue) * RollingDuration * 100.0f;
}
public override void Increment(int amount)
{
Current.Value = Current + amount;
}
}
}

View File

@ -1,154 +1,154 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using System;
using System.Linq;
namespace osu.Game.Graphics.UserInterface
{
public class StarCounter : Container
{
private readonly Container<Star> stars;
/// <summary>
/// Maximum amount of stars displayed.
/// </summary>
/// <remarks>
/// This does not limit the counter value, but the amount of stars displayed.
/// </remarks>
public int StarCount { get; }
private double animationDelay => 80;
private double scalingDuration => 1000;
private Easing scalingEasing => Easing.OutElasticHalf;
private float minStarScale => 0.4f;
private double fadingDuration => 100;
private float minStarAlpha => 0.5f;
private const float star_size = 20;
private const float star_spacing = 4;
private float countStars;
/// <summary>
/// Amount of stars represented.
/// </summary>
public float CountStars
{
get
{
return countStars;
}
set
{
if (countStars == value) return;
if (IsLoaded)
transformCount(value);
countStars = value;
}
}
/// <summary>
/// Shows a float count as stars. Used as star difficulty display.
/// </summary>
/// <param name="starCount">Maximum amount of stars to display.</param>
public StarCounter(int starCount = 10)
{
StarCount = Math.Max(starCount, 0);
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
stars = new FillFlowContainer<Star>
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(star_spacing),
ChildrenEnumerable = Enumerable.Range(0, StarCount).Select(i => new Star { Alpha = minStarAlpha })
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
// Animate initial state from zero.
ReplayAnimation();
}
public void ResetCount()
{
countStars = 0;
StopAnimation();
}
public void ReplayAnimation()
{
var t = countStars;
ResetCount();
CountStars = t;
}
public void StopAnimation()
{
int i = 0;
foreach (var star in stars.Children)
{
star.ClearTransforms(true);
star.FadeTo(i < countStars ? 1.0f : minStarAlpha);
star.Icon.ScaleTo(getStarScale(i, countStars));
i++;
}
}
private float getStarScale(int i, float value)
{
if (value <= i)
return minStarScale;
return i + 1 <= value ? 1.0f : Interpolation.ValueAt(value, minStarScale, 1.0f, i, i + 1);
}
private void transformCount(float newValue)
{
int i = 0;
foreach (var star in stars.Children)
{
star.ClearTransforms(true);
var delay = (countStars <= newValue ? Math.Max(i - countStars, 0) : Math.Max(countStars - 1 - i, 0)) * animationDelay;
star.Delay(delay).FadeTo(i < newValue ? 1.0f : minStarAlpha, fadingDuration);
star.Icon.Delay(delay).ScaleTo(getStarScale(i, newValue), scalingDuration, scalingEasing);
i++;
}
}
private class Star : Container
{
public readonly SpriteIcon Icon;
public Star()
{
Size = new Vector2(star_size);
Child = Icon = new SpriteIcon
{
Size = new Vector2(star_size),
Icon = FontAwesome.fa_star,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using System;
using System.Linq;
namespace osu.Game.Graphics.UserInterface
{
public class StarCounter : Container
{
private readonly Container<Star> stars;
/// <summary>
/// Maximum amount of stars displayed.
/// </summary>
/// <remarks>
/// This does not limit the counter value, but the amount of stars displayed.
/// </remarks>
public int StarCount { get; }
private double animationDelay => 80;
private double scalingDuration => 1000;
private Easing scalingEasing => Easing.OutElasticHalf;
private float minStarScale => 0.4f;
private double fadingDuration => 100;
private float minStarAlpha => 0.5f;
private const float star_size = 20;
private const float star_spacing = 4;
private float countStars;
/// <summary>
/// Amount of stars represented.
/// </summary>
public float CountStars
{
get
{
return countStars;
}
set
{
if (countStars == value) return;
if (IsLoaded)
transformCount(value);
countStars = value;
}
}
/// <summary>
/// Shows a float count as stars. Used as star difficulty display.
/// </summary>
/// <param name="starCount">Maximum amount of stars to display.</param>
public StarCounter(int starCount = 10)
{
StarCount = Math.Max(starCount, 0);
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
stars = new FillFlowContainer<Star>
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(star_spacing),
ChildrenEnumerable = Enumerable.Range(0, StarCount).Select(i => new Star { Alpha = minStarAlpha })
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
// Animate initial state from zero.
ReplayAnimation();
}
public void ResetCount()
{
countStars = 0;
StopAnimation();
}
public void ReplayAnimation()
{
var t = countStars;
ResetCount();
CountStars = t;
}
public void StopAnimation()
{
int i = 0;
foreach (var star in stars.Children)
{
star.ClearTransforms(true);
star.FadeTo(i < countStars ? 1.0f : minStarAlpha);
star.Icon.ScaleTo(getStarScale(i, countStars));
i++;
}
}
private float getStarScale(int i, float value)
{
if (value <= i)
return minStarScale;
return i + 1 <= value ? 1.0f : Interpolation.ValueAt(value, minStarScale, 1.0f, i, i + 1);
}
private void transformCount(float newValue)
{
int i = 0;
foreach (var star in stars.Children)
{
star.ClearTransforms(true);
var delay = (countStars <= newValue ? Math.Max(i - countStars, 0) : Math.Max(countStars - 1 - i, 0)) * animationDelay;
star.Delay(delay).FadeTo(i < newValue ? 1.0f : minStarAlpha, fadingDuration);
star.Icon.Delay(delay).ScaleTo(getStarScale(i, newValue), scalingDuration, scalingEasing);
i++;
}
}
private class Star : Container
{
public readonly SpriteIcon Icon;
public Star()
{
Size = new Vector2(star_size);
Child = Icon = new SpriteIcon
{
Size = new Vector2(star_size),
Icon = FontAwesome.fa_star,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
}
}
}
}

View File

@ -1,108 +1,108 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A button with moving triangles in the background.
/// </summary>
public class TriangleButton : OsuButton, IFilterable
{
private Box hover;
protected Triangles Triangles;
public TriangleButton()
{
Height = 40;
}
protected override SpriteText CreateText() => new OsuSpriteText
{
Depth = -1,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Font = @"Exo2.0-Bold",
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.BlueDark;
Content.Masking = true;
Content.CornerRadius = 5;
AddRange(new Drawable[]
{
Triangles = new Triangles
{
RelativeSizeAxes = Axes.Both,
ColourDark = colours.BlueDarker,
ColourLight = colours.Blue,
},
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive,
Colour = Color4.White.Opacity(0.1f),
Alpha = 0,
},
});
Enabled.ValueChanged += enabled_ValueChanged;
Enabled.TriggerChange();
}
private void enabled_ValueChanged(bool enabled)
{
this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
hover.FadeIn(200);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(200);
base.OnHoverLost(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Content.ScaleTo(0.9f, 4000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
public IEnumerable<string> FilterTerms => new[] { Text };
public bool MatchingFilter
{
set
{
this.FadeTo(value ? 1 : 0);
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A button with moving triangles in the background.
/// </summary>
public class TriangleButton : OsuButton, IFilterable
{
private Box hover;
protected Triangles Triangles;
public TriangleButton()
{
Height = 40;
}
protected override SpriteText CreateText() => new OsuSpriteText
{
Depth = -1,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Font = @"Exo2.0-Bold",
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = colours.BlueDark;
Content.Masking = true;
Content.CornerRadius = 5;
AddRange(new Drawable[]
{
Triangles = new Triangles
{
RelativeSizeAxes = Axes.Both,
ColourDark = colours.BlueDarker,
ColourLight = colours.Blue,
},
hover = new Box
{
RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive,
Colour = Color4.White.Opacity(0.1f),
Alpha = 0,
},
});
Enabled.ValueChanged += enabled_ValueChanged;
Enabled.TriggerChange();
}
private void enabled_ValueChanged(bool enabled)
{
this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
}
protected override bool OnHover(InputState state)
{
hover.FadeIn(200);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
hover.FadeOut(200);
base.OnHoverLost(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Content.ScaleTo(0.9f, 4000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
public IEnumerable<string> FilterTerms => new[] { Text };
public bool MatchingFilter
{
set
{
this.FadeTo(value ? 1 : 0);
}
}
}
}

View File

@ -1,254 +1,254 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
using osu.Game.Beatmaps.ControlPoints;
using osu.Framework.Audio.Track;
using System;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface
{
public class TwoLayerButton : OsuClickableContainer
{
private readonly BouncingIcon bouncingIcon;
public Box IconLayer;
public Box TextLayer;
private const int transform_time = 600;
private const int pulse_length = 250;
private const float shear = 0.1f;
public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50);
public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50);
private readonly SpriteText text;
public Color4 HoverColour;
private readonly Container c1;
private readonly Container c2;
public Color4 BackgroundColour
{
set
{
TextLayer.Colour = value;
IconLayer.Colour = value;
}
}
public override Anchor Origin
{
get
{
return base.Origin;
}
set
{
base.Origin = value;
c1.Origin = c1.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopLeft : Anchor.TopRight;
c2.Origin = c2.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopRight : Anchor.TopLeft;
X = (value & Anchor.x2) > 0 ? SIZE_RETRACTED.X * shear * 0.5f : 0;
Remove(c1);
Remove(c2);
c1.Depth = (value & Anchor.x2) > 0 ? 0 : 1;
c2.Depth = (value & Anchor.x2) > 0 ? 1 : 0;
Add(c1);
Add(c2);
}
}
public TwoLayerButton()
{
Size = SIZE_RETRACTED;
Children = new Drawable[]
{
c2 = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 0.4f,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
MaskingSmoothness = 2,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
Children = new[]
{
IconLayer = new Box
{
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(2, 0),
},
}
},
bouncingIcon = new BouncingIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
}
},
c1 = new Container
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
RelativeSizeAxes = Axes.Both,
Width = 0.6f,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
MaskingSmoothness = 2,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
Children = new[]
{
TextLayer = new Box
{
Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft,
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(2, 0),
},
}
},
text = new OsuSpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
}
},
};
}
public FontAwesome Icon
{
set
{
bouncingIcon.Icon = value;
}
}
public string Text
{
set
{
text.Text = value;
}
}
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => IconLayer.ReceiveMouseInputAt(screenSpacePos) || TextLayer.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnHover(InputState state)
{
this.ResizeTo(SIZE_EXTENDED, transform_time, Easing.OutElastic);
IconLayer.FadeColour(HoverColour, transform_time, Easing.OutElastic);
bouncingIcon.ScaleTo(1.1f, transform_time, Easing.OutElastic);
return true;
}
protected override void OnHoverLost(InputState state)
{
this.ResizeTo(SIZE_RETRACTED, transform_time, Easing.OutElastic);
IconLayer.FadeColour(TextLayer.Colour, transform_time, Easing.OutElastic);
bouncingIcon.ScaleTo(1, transform_time, Easing.OutElastic);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
return true;
}
protected override bool OnClick(InputState state)
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Colour = Color4.White.Opacity(0.5f),
};
Add(flash);
flash.Alpha = 1;
flash.FadeOut(500, Easing.OutQuint);
flash.Expire();
return base.OnClick(state);
}
private class BouncingIcon : BeatSyncedContainer
{
private const double beat_in_time = 60;
private readonly SpriteIcon icon;
public FontAwesome Icon { set { icon.Icon = value; } }
public BouncingIcon()
{
EarlyActivationMilliseconds = beat_in_time;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(25),
}
};
}
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
var beatLength = timingPoint.BeatLength;
float amplitudeAdjust = Math.Min(1, 0.4f + amplitudes.Maximum);
if (beatIndex < 0) return;
icon.ScaleTo(1 - 0.1f * amplitudeAdjust, beat_in_time, Easing.Out)
.Then()
.ScaleTo(1, beatLength * 2, Easing.OutQuint);
}
}
}
}
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
using osu.Game.Beatmaps.ControlPoints;
using osu.Framework.Audio.Track;
using System;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface
{
public class TwoLayerButton : OsuClickableContainer
{
private readonly BouncingIcon bouncingIcon;
public Box IconLayer;
public Box TextLayer;
private const int transform_time = 600;
private const int pulse_length = 250;
private const float shear = 0.1f;
public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50);
public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50);
private readonly SpriteText text;
public Color4 HoverColour;
private readonly Container c1;
private readonly Container c2;
public Color4 BackgroundColour
{
set
{
TextLayer.Colour = value;
IconLayer.Colour = value;
}
}
public override Anchor Origin
{
get
{
return base.Origin;
}
set
{
base.Origin = value;
c1.Origin = c1.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopLeft : Anchor.TopRight;
c2.Origin = c2.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopRight : Anchor.TopLeft;
X = (value & Anchor.x2) > 0 ? SIZE_RETRACTED.X * shear * 0.5f : 0;
Remove(c1);
Remove(c2);
c1.Depth = (value & Anchor.x2) > 0 ? 0 : 1;
c2.Depth = (value & Anchor.x2) > 0 ? 1 : 0;
Add(c1);
Add(c2);
}
}
public TwoLayerButton()
{
Size = SIZE_RETRACTED;
Children = new Drawable[]
{
c2 = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 0.4f,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
MaskingSmoothness = 2,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
Children = new[]
{
IconLayer = new Box
{
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(2, 0),
},
}
},
bouncingIcon = new BouncingIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
}
},
c1 = new Container
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
RelativeSizeAxes = Axes.Both,
Width = 0.6f,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
MaskingSmoothness = 2,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
Children = new[]
{
TextLayer = new Box
{
Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft,
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(2, 0),
},
}
},
text = new OsuSpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
}
},
};
}
public FontAwesome Icon
{
set
{
bouncingIcon.Icon = value;
}
}
public string Text
{
set
{
text.Text = value;
}
}
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => IconLayer.ReceiveMouseInputAt(screenSpacePos) || TextLayer.ReceiveMouseInputAt(screenSpacePos);
protected override bool OnHover(InputState state)
{
this.ResizeTo(SIZE_EXTENDED, transform_time, Easing.OutElastic);
IconLayer.FadeColour(HoverColour, transform_time, Easing.OutElastic);
bouncingIcon.ScaleTo(1.1f, transform_time, Easing.OutElastic);
return true;
}
protected override void OnHoverLost(InputState state)
{
this.ResizeTo(SIZE_RETRACTED, transform_time, Easing.OutElastic);
IconLayer.FadeColour(TextLayer.Colour, transform_time, Easing.OutElastic);
bouncingIcon.ScaleTo(1, transform_time, Easing.OutElastic);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
return true;
}
protected override bool OnClick(InputState state)
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Colour = Color4.White.Opacity(0.5f),
};
Add(flash);
flash.Alpha = 1;
flash.FadeOut(500, Easing.OutQuint);
flash.Expire();
return base.OnClick(state);
}
private class BouncingIcon : BeatSyncedContainer
{
private const double beat_in_time = 60;
private readonly SpriteIcon icon;
public FontAwesome Icon { set { icon.Icon = value; } }
public BouncingIcon()
{
EarlyActivationMilliseconds = beat_in_time;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(25),
}
};
}
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
var beatLength = timingPoint.BeatLength;
float amplitudeAdjust = Math.Min(1, 0.4f + amplitudes.Maximum);
if (beatIndex < 0) return;
icon.ScaleTo(1 - 0.1f * amplitudeAdjust, beat_in_time, Easing.Out)
.Then()
.ScaleTo(1, beatLength * 2, Easing.OutQuint);
}
}
}
}