#region Imports using DPumpHydr.WinFrmUI.RLT.Util; using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; #endregion namespace DPumpHydr.WinFrmUI.RLT.Controls { #region NightButton public class NightButton : Control, IButtonControl { #region Fields private int _Radius = 20; private readonly Timer animationTimer; private int buttonGlow; private int stringGlow; private bool hoverButton; private int mouseState; private Color _NormalBackColor = ColorTranslator.FromHtml("#F25D59"); private Color _PressedBackColor = Color.FromArgb(100, ColorTranslator.FromHtml("#F25D59")); private Color _HoverBackColor = Color.FromArgb(50, ColorTranslator.FromHtml("#F25D59")); private Color _PressedForeColor = Color.White; private Color _HoverForeColor = Color.White; private float margin, width, height; private Rectangle stringRect; private RectangleF buttonRect; private GraphicsPath roundRectPath; private InterpolationMode _InterpolationType = InterpolationMode.HighQualityBicubic; private PixelOffsetMode _PixelOffsetType = PixelOffsetMode.HighQuality; private SmoothingMode _SmoothingType = SmoothingMode.AntiAlias; #endregion #region Properties [Browsable(true)] [Description("Sets the radius of curvature for the control.")] public int Radius { get => _Radius; set { if (value is not (< 1 or > 20)) { _Radius = value; } else { throw new Exception("The entered value cannot be less than 1 or greater than 20."); } Invalidate(); } } public SmoothingMode SmoothingType { get => _SmoothingType; set { _SmoothingType = value; Invalidate(); } } public InterpolationMode InterpolationType { get => _InterpolationType; set { _InterpolationType = value; Invalidate(); } } public PixelOffsetMode PixelOffsetType { get => _PixelOffsetType; set { _PixelOffsetType = value; Invalidate(); } } public Color PressedForeColor { get => _PressedForeColor; set { _PressedForeColor = value; Invalidate(); } } public Color HoverForeColor { get => _HoverForeColor; set { _HoverForeColor = value; Invalidate(); } } public Color NormalBackColor { get => _NormalBackColor; set { _NormalBackColor = value; Invalidate(); } } public Color PressedBackColor { get => _PressedBackColor; set { _PressedBackColor = value; Invalidate(); } } public Color HoverBackColor { get => _HoverBackColor; set { _HoverBackColor = value; Invalidate(); } } #endregion #region IButtonControl private DialogResult dlgResult; [Browsable(false)] private bool IsDefault { get; set; } /// /// /// public DialogResult DialogResult { get => dlgResult; set { if (System.Enum.IsDefined(typeof(DialogResult), value)) { dlgResult = value; } } } public void NotifyDefault(bool value) { IsDefault = value; } public void PerformClick() { if (CanSelect) { OnClick(EventArgs.Empty); } } #endregion #region Create Round Rectangle // Snippet by RodStephens private GraphicsPath RoundedRect(RectangleF rect, float x_radius, float y_radius, bool round_upperLeft, bool round_upperRight, bool round_lowerRight, bool round_lowerLeft) { PointF point1, point2; GraphicsPath path = new(); // Upper left corner if (round_upperLeft) { RectangleF corner = new(rect.X, rect.Y, 2 * x_radius, 2 * y_radius); path.AddArc(corner, 180, 90); point1 = new(rect.X + x_radius, rect.Y); } else { point1 = new(rect.X, rect.Y); } // Top side if (round_upperRight) { point2 = new(rect.Right - x_radius, rect.Y); } else { point2 = new(rect.Right, rect.Y); path.AddLine(point1, point2); } // Upper right corner if (round_upperRight) { RectangleF corner = new(rect.Right - (2 * x_radius), rect.Y, 2 * x_radius, 2 * y_radius); path.AddArc(corner, 270, 90); point1 = new(rect.Right, rect.Y + y_radius); } else { point1 = new(rect.Right, rect.Y); } // Right side if (round_lowerRight) { point2 = new(rect.Right, rect.Bottom - y_radius); } else { point2 = new(rect.Right, rect.Bottom); path.AddLine(point1, point2); } // Lower right corner if (round_lowerRight) { RectangleF corner = new(rect.Right - (2 * x_radius), rect.Bottom - (2 * y_radius), 2 * x_radius, 2 * y_radius); path.AddArc(corner, 0, 90); point1 = new(rect.Right - x_radius, rect.Bottom); } else { point1 = new(rect.Right, rect.Bottom); } // Bottom side if (round_lowerLeft) { point2 = new(rect.X + x_radius, rect.Bottom); } else { point2 = new(rect.X, rect.Bottom); path.AddLine(point1, point2); } // Lower left corner if (round_lowerLeft) { RectangleF corner = new(rect.X, rect.Bottom - (2 * y_radius), 2 * x_radius, 2 * y_radius); path.AddArc(corner, 90, 90); point1 = new(rect.X, rect.Bottom - y_radius); } else { point1 = new(rect.X, rect.Bottom); } // Left side if (round_upperLeft) { point2 = new(rect.X, rect.Y + y_radius); } else { point2 = new(rect.X, rect.Y); path.AddLine(point1, point2); } path.CloseFigure(); return path; } #endregion #region EventArgs protected override void OnMouseUp(MouseEventArgs e) { mouseState = 0; Invalidate(); base.OnMouseUp(e); } protected override void OnMouseDown(MouseEventArgs e) { mouseState = 1; Invalidate(); Focus(); base.OnMouseDown(e); } protected override void OnMouseMove(MouseEventArgs e) { mouseState = 3; hoverButton = true; base.OnMouseMove(e); } protected override void OnMouseLeave(EventArgs e) { mouseState = 0; hoverButton = false; Invalidate(); base.OnMouseLeave(e); } protected override void OnTextChanged(EventArgs e) { Invalidate(); base.OnTextChanged(e); } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); animationTimer.Start(); } protected override void OnResize(EventArgs e) { if (Width > 0 && Height > 0) { stringRect = new(0, 0, Width, Height); } Invalidate(); base.OnResize(e); } private void OnAnimation(object sender, EventArgs e) { if (DesignMode) { return; } if (hoverButton) { if (buttonGlow < 242) { buttonGlow += 15; } if (stringGlow < 160) { stringGlow += 15; } } else { if (buttonGlow >= 15) { buttonGlow -= 15; } if (stringGlow >= 15) { stringGlow -= 15; } } Invalidate(); } #endregion #region Native Hand Cursor protected override void WndProc(ref Message msg) { if (msg.Msg == NativeConstants.WM_SETCURSOR) { IntPtr cursor = NativeMethods.LoadCursor(IntPtr.Zero, NativeConstants.IDC_HAND); NativeMethods.SetCursor(cursor); msg.Result = IntPtr.Zero; return; } base.WndProc(ref msg); } #endregion public NightButton() { SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true); BackColor = Color.Transparent; DoubleBuffered = true; Font = new("Segoe UI", 10); ForeColor = ColorTranslator.FromHtml("#F25D59"); Size = new(144, 47); MinimumSize = new(144, 47); Cursor = Cursors.Hand; animationTimer = new Timer { Interval = 1 }; animationTimer.Tick += OnAnimation; } private void FillButton(Graphics g) { using SolidBrush animBrush = new(Color.FromArgb(buttonGlow, ForeColor)); g.FillPath(animBrush, roundRectPath); } private void DrawButton(Graphics g) { Color penColor = Color.Empty; Color brushColor = Color.Empty; switch (mouseState) { case 0: // Inactive state penColor = NormalBackColor; brushColor = ForeColor; break; case 1: // Pressed state penColor = PressedBackColor; brushColor = PressedForeColor; break; case 3: // Hover state penColor = HoverBackColor; brushColor = Color.FromArgb(80 + stringGlow, HoverForeColor); break; } using Pen pathPen = new(penColor, 2f); using SolidBrush stringBrush = new(brushColor); using StringFormat sf = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; g.DrawPath(pathPen, roundRectPath); g.DrawString(Text, Font, stringBrush, stringRect, sf); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.SmoothingMode = _SmoothingType; g.InterpolationMode = _InterpolationType; g.PixelOffsetMode = _PixelOffsetType; margin = 3; width = ClientSize.Width - (2 * margin); height = ClientSize.Height - 6; buttonRect = new(margin, margin, width, height); roundRectPath = RoundedRect(buttonRect, _Radius, _Radius, false, true, true, false); FillButton(g); DrawButton(g); base.OnPaint(e); } } #endregion }