using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Windows.Forms; using WinFormAnimation; namespace Server.Helper; [ToolboxItem(true)] [ToolboxBitmap(typeof(CircularProgressBar), "CircularProgressBar.bmp")] [DefaultBindingProperty("Value")] public class CircularProgressBar : ProgressBar { private readonly Animator _animator; private int? _animatedStartAngle; private float? _animatedValue; private AnimationFunctions.Function _animationFunction; private Brush _backBrush; private KnownAnimationFunctions _knownAnimationFunction; private ProgressBarStyle? _lastStyle; private int _lastValue; [Category("Behavior")] public KnownAnimationFunctions AnimationFunction { get { return _knownAnimationFunction; } set { _animationFunction = AnimationFunctions.FromKnown(value); _knownAnimationFunction = value; } } [Category("Behavior")] public int AnimationSpeed { get; set; } [EditorBrowsable(EditorBrowsableState.Never)] [Browsable(false)] public AnimationFunctions.Function CustomAnimationFunction { private get { return _animationFunction; } set { if (value == null) { throw new ArgumentNullException("value"); } _knownAnimationFunction = KnownAnimationFunctions.None; _animationFunction = value; } } [EditorBrowsable(EditorBrowsableState.Always)] [Browsable(true)] public override Font Font { get { return base.Font; } set { base.Font = value; } } [Category("Appearance")] public Color InnerColor { get; set; } [Category("Layout")] public int InnerMargin { get; set; } [Category("Layout")] public int InnerWidth { get; set; } [Category("Appearance")] public Color OuterColor { get; set; } [Category("Layout")] public int OuterMargin { get; set; } [Category("Layout")] public int OuterWidth { get; set; } [Category("Appearance")] public Color ProgressColor { get; set; } [Category("Layout")] public int ProgressWidth { get; set; } [Category("Appearance")] public Font SecondaryFont { get; set; } [Category("Layout")] public int StartAngle { get; set; } [Category("Appearance")] public Color SubscriptColor { get; set; } [Category("Layout")] public Padding SubscriptMargin { get; set; } [Category("Appearance")] public string SubscriptText { get; set; } [Category("Appearance")] public Color SuperscriptColor { get; set; } [Category("Layout")] public Padding SuperscriptMargin { get; set; } [Category("Appearance")] public string SuperscriptText { get; set; } [EditorBrowsable(EditorBrowsableState.Always)] [Browsable(true)] public override string Text { get { return base.Text; } set { base.Text = value; } } [Category("Layout")] public Padding TextMargin { get; set; } public CircularProgressBar() { SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, value: true); _animator = (base.DesignMode ? null : new Animator()); AnimationFunction = KnownAnimationFunctions.Liner; AnimationSpeed = 500; base.MarqueeAnimationSpeed = 2000; StartAngle = 270; _lastValue = base.Value; BackColor = Color.Transparent; ForeColor = Color.FromArgb(64, 64, 64); DoubleBuffered = true; Font = new Font(Font.FontFamily, 72f, FontStyle.Bold); SecondaryFont = new Font(Font.FontFamily, (float)((double)Font.Size * 0.5), FontStyle.Regular); OuterMargin = -25; OuterWidth = 26; OuterColor = Color.Gray; ProgressWidth = 25; ProgressColor = Color.FromArgb(255, 128, 0); InnerMargin = 2; InnerWidth = -1; InnerColor = Color.FromArgb(224, 224, 224); TextMargin = new Padding(8, 8, 0, 0); base.Value = 68; SuperscriptMargin = new Padding(10, 35, 0, 0); SuperscriptColor = Color.FromArgb(166, 166, 166); SuperscriptText = "°C"; SubscriptMargin = new Padding(10, -35, 0, 0); SubscriptColor = Color.FromArgb(166, 166, 166); SubscriptText = ".23"; base.Size = new Size(320, 320); } private static PointF AddPoint(PointF p, int v) { p.X += v; p.Y += v; return p; } private static SizeF AddSize(SizeF s, int v) { s.Height += v; s.Width += v; return s; } private static Rectangle ToRectangle(RectangleF rect) { return new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height); } protected override void OnLocationChanged(EventArgs e) { base.OnLocationChanged(e); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { try { if (!base.DesignMode) { if (base.Style == ProgressBarStyle.Marquee) { InitializeMarquee(_lastStyle != base.Style); } else { InitializeContinues(_lastStyle != base.Style); } _lastStyle = base.Style; } if (_backBrush == null) { RecreateBackgroundBrush(); } StartPaint(e.Graphics); } catch { } } protected override void OnParentBackColorChanged(EventArgs e) { RecreateBackgroundBrush(); } protected override void OnParentBackgroundImageChanged(EventArgs e) { RecreateBackgroundBrush(); } protected override void OnParentChanged(EventArgs e) { if (base.Parent != null) { base.Parent.Invalidated -= ParentOnInvalidated; base.Parent.Resize -= ParentOnResize; } base.OnParentChanged(e); if (base.Parent != null) { base.Parent.Invalidated += ParentOnInvalidated; base.Parent.Resize += ParentOnResize; } } protected override void OnStyleChanged(EventArgs e) { base.OnStyleChanged(e); Invalidate(); } protected virtual void InitializeContinues(bool firstTime) { if (_lastValue == base.Value && !firstTime) { return; } _lastValue = base.Value; _animator.Stop(); _animatedStartAngle = null; if (AnimationSpeed <= 0) { _animatedValue = base.Value; Invalidate(); return; } _animator.Paths = new Path(_animatedValue ?? ((float)base.Value), base.Value, (ulong)AnimationSpeed, CustomAnimationFunction).ToArray(); _animator.Repeat = false; _animator.Play(new SafeInvoker(delegate(float v) { try { _animatedValue = v; Invalidate(); } catch { _animator.Stop(); } }, this)); } protected virtual void InitializeMarquee(bool firstTime) { if (!firstTime && (_animator.ActivePath == null || (_animator.ActivePath.Duration == (ulong)base.MarqueeAnimationSpeed && _animator.ActivePath.Function == CustomAnimationFunction))) { return; } _animator.Stop(); _animatedValue = null; if (AnimationSpeed <= 0) { _animatedStartAngle = 0; Invalidate(); return; } _animator.Paths = new Path(0f, 359f, (ulong)base.MarqueeAnimationSpeed, CustomAnimationFunction).ToArray(); _animator.Repeat = true; _animator.Play(new SafeInvoker(delegate(float v) { try { _animatedStartAngle = (int)(v % 360f); Invalidate(); } catch { _animator.Stop(); } }, this)); } protected virtual void ParentOnInvalidated(object sender, InvalidateEventArgs invalidateEventArgs) { RecreateBackgroundBrush(); } protected virtual void ParentOnResize(object sender, EventArgs eventArgs) { RecreateBackgroundBrush(); } protected virtual void RecreateBackgroundBrush() { lock (this) { _backBrush?.Dispose(); _backBrush = new SolidBrush(BackColor); if (BackColor.A == byte.MaxValue) { return; } if (base.Parent != null && base.Parent.Width > 0 && base.Parent.Height > 0) { using (Bitmap bitmap = new Bitmap(base.Parent.Width, base.Parent.Height)) { using (Graphics graphics = Graphics.FromImage(bitmap)) { PaintEventArgs e = new PaintEventArgs(graphics, new Rectangle(new Point(0, 0), bitmap.Size)); InvokePaintBackground(base.Parent, e); InvokePaint(base.Parent, e); if (BackColor.A > 0) { graphics.FillRectangle(_backBrush, base.Bounds); } } _backBrush = new TextureBrush(bitmap); ((TextureBrush)_backBrush).TranslateTransform(-base.Bounds.X, -base.Bounds.Y); return; } } _backBrush = new SolidBrush(Color.FromArgb(255, BackColor)); } } protected virtual void StartPaint(Graphics g) { try { lock (this) { g.TextRenderingHint = TextRenderingHint.AntiAlias; g.SmoothingMode = SmoothingMode.AntiAlias; PointF pointF = AddPoint(Point.Empty, 2); SizeF sizeF = AddSize(base.Size, -4); if (OuterWidth + OuterMargin < 0) { int num = Math.Abs(OuterWidth + OuterMargin); pointF = AddPoint(Point.Empty, num); sizeF = AddSize(base.Size, -2 * num); } if (OuterColor != Color.Empty && OuterColor != Color.Transparent && OuterWidth != 0) { g.FillEllipse(new SolidBrush(OuterColor), new RectangleF(pointF, sizeF)); if (OuterWidth >= 0) { pointF = AddPoint(pointF, OuterWidth); sizeF = AddSize(sizeF, -2 * OuterWidth); g.FillEllipse(_backBrush, new RectangleF(pointF, sizeF)); } } pointF = AddPoint(pointF, OuterMargin); sizeF = AddSize(sizeF, -2 * OuterMargin); g.FillPie(new SolidBrush(ProgressColor), ToRectangle(new RectangleF(pointF, sizeF)), _animatedStartAngle ?? StartAngle, ((_animatedValue ?? ((float)base.Value)) - (float)base.Minimum) / (float)(base.Maximum - base.Minimum) * 360f); if (ProgressWidth >= 0) { pointF = AddPoint(pointF, ProgressWidth); sizeF = AddSize(sizeF, -2 * ProgressWidth); g.FillEllipse(_backBrush, new RectangleF(pointF, sizeF)); } pointF = AddPoint(pointF, InnerMargin); sizeF = AddSize(sizeF, -2 * InnerMargin); if (InnerColor != Color.Empty && InnerColor != Color.Transparent && InnerWidth != 0) { g.FillEllipse(new SolidBrush(InnerColor), new RectangleF(pointF, sizeF)); if (InnerWidth >= 0) { pointF = AddPoint(pointF, InnerWidth); sizeF = AddSize(sizeF, -2 * InnerWidth); g.FillEllipse(_backBrush, new RectangleF(pointF, sizeF)); } } if (Text == string.Empty) { return; } pointF.X += TextMargin.Left; pointF.Y += TextMargin.Top; sizeF.Width -= TextMargin.Right; sizeF.Height -= TextMargin.Bottom; StringFormat format = new StringFormat((RightToLeft == RightToLeft.Yes) ? StringFormatFlags.DirectionRightToLeft : ((StringFormatFlags)0)) { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Near }; SizeF size = g.MeasureString(Text, Font); PointF location = new PointF(pointF.X + (sizeF.Width - size.Width) / 2f, pointF.Y + (sizeF.Height - size.Height) / 2f); if (SubscriptText != string.Empty || SuperscriptText != string.Empty) { float num2 = 0f; SizeF size2 = SizeF.Empty; SizeF size3 = SizeF.Empty; if (SuperscriptText != string.Empty) { size2 = g.MeasureString(SuperscriptText, SecondaryFont); num2 = Math.Max(size2.Width, num2); size2.Width -= SuperscriptMargin.Right; size2.Height -= SuperscriptMargin.Bottom; } if (SubscriptText != string.Empty) { size3 = g.MeasureString(SubscriptText, SecondaryFont); num2 = Math.Max(size3.Width, num2); size3.Width -= SubscriptMargin.Right; size3.Height -= SubscriptMargin.Bottom; } location.X -= num2 / 4f; if (SuperscriptText != string.Empty) { PointF location2 = new PointF(location.X + size.Width - size2.Width / 2f, location.Y - size2.Height * 0.85f); location2.X += SuperscriptMargin.Left; location2.Y += SuperscriptMargin.Top; g.DrawString(SuperscriptText, SecondaryFont, new SolidBrush(SuperscriptColor), new RectangleF(location2, size2), format); } if (SubscriptText != string.Empty) { PointF location3 = new PointF(location.X + size.Width - size3.Width / 2f, location.Y + size.Height * 0.85f); location3.X += SubscriptMargin.Left; location3.Y += SubscriptMargin.Top; g.DrawString(SubscriptText, SecondaryFont, new SolidBrush(SubscriptColor), new RectangleF(location3, size3), format); } } g.DrawString(Text, Font, new SolidBrush(ForeColor), new RectangleF(location, size), format); } } catch { } } }