1using System; 2using System.Drawing; 3using System.Drawing.Drawing2D; 4using System.Windows.Forms; 5using System.Collections.Generic; 6using WindowCapture.Helpers; 7 8namespace WindowCapture.UI 9{ 10 // Glass-style float numeric control 11 public class DarkFloatNumeric : Control 12 { 13 private static readonly Color GE = Color.FromArgb(225, 232, 245); 14 15 private float _value, _min, _max, _step; 16 private bool hoverUp, hoverDown; 17 private Timer repeatTimer; 18 private int repeatDir; 19 20 public event EventHandler ValueChanged; 21 22 public float Value 23 { 24 get { return _value; } 25 set { float v = Math.Max(_min, Math.Min(_max, value)); if (Math.Abs(v - _value) > 0.001f) { _value = v; Invalidate(); if (ValueChanged != null) ValueChanged(this, EventArgs.Empty); } } 26 } 27 public float Minimum { get { return _min; } set { _min = value; } } 28 public float Maximum { get { return _max; } set { _max = value; } } 29 public float Step { get { return _step; } set { _step = value; } } 30 31 public DarkFloatNumeric() 32 { 33 SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor, true); 34 BackColor = Color.Transparent; 35 Size = new Size(80, 26); Font = new Font("Segoe UI", 11f, GraphicsUnit.Pixel); 36 _min = 0.1f; _max = 10f; _step = 0.1f; _value = 1f; 37 repeatTimer = new Timer(); repeatTimer.Interval = 100; 38 repeatTimer.Tick += (s, e) => { ChangeValue(repeatDir); }; 39 } 40 41 protected override void OnPaint(PaintEventArgs e) 42 { 43 var g = e.Graphics; 44 float glow = GlowHelper.ComputeGlow(this); 45 int fillA = 12 + (int)(18 * glow); 46 using (var brush = new SolidBrush(Color.FromArgb(fillA, GE))) 47 g.FillRectangle(brush, 0, 0, Width, Height); 48 int borderA = 40 + (int)(60 * glow); 49 using (var pen = new Pen(Color.FromArgb(borderA, GE), 1f)) 50 g.DrawRectangle(pen, 0, 0, Width - 1, Height - 1); 51 52 g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; 53 Color tc = SettingsDialog.AdaptiveTextColor; 54 int textA = 160 + (int)(65 * glow); 55 using (var brush = new SolidBrush(Color.FromArgb(textA, tc))) 56 { 57 var sf = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center }; 58 g.DrawString(_value.ToString("0.0"), Font, brush, new Rectangle(7, 0, Width - 30, Height), sf); 59 } 60 61 int btnW = 22, btnH = Height / 2; 62 if (hoverUp) using (var brush = new SolidBrush(Color.FromArgb(25, tc))) g.FillRectangle(brush, Width - btnW, 0, btnW, btnH); 63 if (hoverDown) using (var brush = new SolidBrush(Color.FromArgb(25, tc))) g.FillRectangle(brush, Width - btnW, btnH, btnW, btnH); 64 int sepA = 30 + (int)(30 * glow); 65 using (var pen = new Pen(Color.FromArgb(sepA, tc), 1f)) g.DrawLine(pen, Width - btnW, 0, Width - btnW, Height); 66 67 DrawGlassArrow(g, new Rectangle(Width - btnW, 0, btnW, btnH), true, hoverUp, glow); 68 DrawGlassArrow(g, new Rectangle(Width - btnW, btnH, btnW, btnH), false, hoverDown, glow); 69 } 70 71 private void DrawGlassArrow(Graphics g, Rectangle r, bool up, bool hov, float glow) 72 { 73 Color tc = SettingsDialog.AdaptiveTextColor; 74 int cx = r.X + r.Width / 2, cy = r.Y + r.Height / 2, sz = 3; 75 Point[] pts = up 76 ? new Point[] { new Point(cx - sz, cy + 1), new Point(cx + sz, cy + 1), new Point(cx, cy - 2) } 77 : new Point[] { new Point(cx - sz, cy - 1), new Point(cx + sz, cy - 1), new Point(cx, cy + 2) }; 78 int arrowA = (int)((hov ? 180 : 80) + (40 * glow)); 79 if (arrowA > 255) arrowA = 255; 80 using (var brush = new SolidBrush(Color.FromArgb(arrowA, tc))) 81 g.FillPolygon(brush, pts); 82 } 83 84 protected override void OnMouseMove(MouseEventArgs e) 85 { 86 int btnW = 22, btnH = Height / 2; 87 bool u = e.X >= Width - btnW && e.Y < btnH, d = e.X >= Width - btnW && e.Y >= btnH; 88 if (u != hoverUp || d != hoverDown) { hoverUp = u; hoverDown = d; Invalidate(); } 89 } 90 protected override void OnMouseLeave(EventArgs e) { hoverUp = hoverDown = false; Invalidate(); } 91 protected override void OnMouseDown(MouseEventArgs e) 92 { 93 int btnW = 22, btnH = Height / 2; 94 if (e.X >= Width - btnW) { int dir = e.Y < btnH ? 1 : -1; ChangeValue(dir); repeatDir = dir; repeatTimer.Start(); } 95 } 96 protected override void OnMouseUp(MouseEventArgs e) { repeatTimer.Stop(); } 97 protected override void OnMouseWheel(MouseEventArgs e) { ChangeValue(e.Delta > 0 ? 1 : -1); } 98 99 private void ChangeValue(int dir) 100 { 101 float v = (float)Math.Round(_value + dir * _step, 1); 102 if (v >= _min && v <= _max) { _value = v; Invalidate(); if (ValueChanged != null) ValueChanged(this, EventArgs.Empty); } 103 } 104 105 protected override void Dispose(bool disposing) 106 { if (disposing && repeatTimer != null) { repeatTimer.Dispose(); repeatTimer = null; } base.Dispose(disposing); } 107 } 108}