A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System;
5using osu.Framework.Allocation;
6using osu.Framework.Bindables;
7using osu.Framework.Graphics.Shaders;
8using osu.Framework.Graphics.Textures;
9using osu.Framework.Graphics.Transforms;
10
11namespace osu.Framework.Graphics.UserInterface
12{
13 public class CircularProgress : Drawable, ITexturedShaderDrawable, IHasCurrentValue<double>
14 {
15 private readonly BindableWithCurrent<double> current = new BindableWithCurrent<double>();
16
17 public Bindable<double> Current
18 {
19 get => current.Current;
20 set => current.Current = value;
21 }
22
23 public CircularProgress()
24 {
25 Current.ValueChanged += newValue => Invalidate(Invalidation.DrawNode);
26 }
27
28 public IShader RoundedTextureShader { get; private set; }
29 public IShader TextureShader { get; private set; }
30
31 #region Disposal
32
33 protected override void Dispose(bool isDisposing)
34 {
35 texture?.Dispose();
36 texture = null;
37
38 base.Dispose(isDisposing);
39 }
40
41 #endregion
42
43 protected override DrawNode CreateDrawNode() => new CircularProgressDrawNode(this);
44
45 public TransformSequence<CircularProgress> FillTo(double newValue, double duration = 0, Easing easing = Easing.None)
46 => FillTo(newValue, duration, new DefaultEasingFunction(easing));
47
48 public TransformSequence<CircularProgress> FillTo<TEasing>(double newValue, double duration, in TEasing easing)
49 where TEasing : IEasingFunction
50 => this.TransformBindableTo(Current, newValue, duration, easing);
51
52 [BackgroundDependencyLoader]
53 private void load(ShaderManager shaders)
54 {
55 RoundedTextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
56 TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE);
57 }
58
59 private Texture texture = Texture.WhitePixel;
60
61 public Texture Texture
62 {
63 get => texture;
64 set
65 {
66 if (value == texture)
67 return;
68
69 texture?.Dispose();
70 texture = value;
71
72 Invalidate(Invalidation.DrawNode);
73 }
74 }
75
76 private float innerRadius = 1;
77
78 /// <summary>
79 /// The inner fill radius, relative to the <see cref="Drawable.DrawSize"/> of the <see cref="CircularProgress"/>.
80 /// The value range is 0 to 1 where 0 is invisible and 1 is completely filled.
81 /// The entire texture still fills the disk without cropping it.
82 /// </summary>
83 public float InnerRadius
84 {
85 get => innerRadius;
86 set
87 {
88 innerRadius = Math.Clamp(value, 0, 1);
89 Invalidate(Invalidation.DrawNode);
90 }
91 }
92 }
93
94 public static class CircularProgressTransformSequenceExtensions
95 {
96 public static TransformSequence<CircularProgress> FillTo(this TransformSequence<CircularProgress> t, double newValue, double duration = 0, Easing easing = Easing.None)
97 => t.FillTo(newValue, duration, new DefaultEasingFunction(easing));
98
99 public static TransformSequence<CircularProgress> FillTo<TEasing>(this TransformSequence<CircularProgress> t, double newValue, double duration, TEasing easing)
100 where TEasing : IEasingFunction
101 => t.Append(cp => cp.FillTo(newValue, duration, easing));
102 }
103}