1using System; 2using System.Drawing; 3using System.Windows.Forms; 4 5namespace WindowCapture.UI 6{ 7 /// <summary> 8 /// Toast notification that appears in the bottom-right corner of the screen 9 /// </summary> 10 public class ToastNotification : Form 11 { 12 private Timer fadeTimer; 13 private Timer closeTimer; 14 private Label lblTitle; 15 private Label lblMessage; 16 private int targetY; 17 private bool isAnimatingIn = true; 18 19 public ToastNotification(string title, string message, bool isError = false) 20 { 21 // Form settings 22 this.FormBorderStyle = FormBorderStyle.None; 23 this.ShowInTaskbar = false; 24 this.TopMost = true; 25 this.StartPosition = FormStartPosition.Manual; 26 this.Size = new Size(300, 80); 27 this.BackColor = isError ? Color.FromArgb(60, 30, 30) : Color.FromArgb(30, 30, 30); 28 this.Opacity = 0; 29 30 // Position in bottom-right corner 31 var screen = Screen.PrimaryScreen.WorkingArea; 32 targetY = screen.Bottom - this.Height - 10; 33 this.Location = new Point(screen.Right - this.Width - 10, targetY + 50); // Start below target 34 35 // Border 36 this.Paint += (s, e) => 37 { 38 var borderColor = isError ? Color.FromArgb(180, 60, 60) : Color.FromArgb(0, 120, 215); 39 using (var pen = new Pen(borderColor, 2)) 40 { 41 e.Graphics.DrawRectangle(pen, 1, 1, this.Width - 2, this.Height - 2); 42 } 43 }; 44 45 // Title label 46 lblTitle = new Label(); 47 lblTitle.Text = title; 48 lblTitle.ForeColor = isError ? Color.FromArgb(255, 100, 100) : Color.FromArgb(0, 150, 255); 49 lblTitle.Font = new Font("Segoe UI", 10f, FontStyle.Bold); 50 lblTitle.Location = new Point(10, 8); 51 lblTitle.Size = new Size(280, 22); 52 lblTitle.BackColor = Color.Transparent; 53 this.Controls.Add(lblTitle); 54 55 // Message label 56 lblMessage = new Label(); 57 lblMessage.Text = message; 58 lblMessage.ForeColor = Color.White; 59 lblMessage.Font = new Font("Segoe UI", 9f); 60 lblMessage.Location = new Point(10, 32); 61 lblMessage.Size = new Size(280, 40); 62 lblMessage.BackColor = Color.Transparent; 63 this.Controls.Add(lblMessage); 64 65 // Click to close 66 this.Click += (s, e) => this.Close(); 67 lblTitle.Click += (s, e) => this.Close(); 68 lblMessage.Click += (s, e) => this.Close(); 69 70 // Fade in animation 71 fadeTimer = new Timer(); 72 fadeTimer.Interval = 15; 73 fadeTimer.Tick += FadeTimer_Tick; 74 fadeTimer.Start(); 75 76 // Auto close after delay 77 closeTimer = new Timer(); 78 closeTimer.Interval = isError ? 5000 : 3000; 79 closeTimer.Tick += (s, e) => 80 { 81 closeTimer.Stop(); 82 isAnimatingIn = false; 83 fadeTimer.Start(); 84 }; 85 } 86 87 private void FadeTimer_Tick(object sender, EventArgs e) 88 { 89 if (isAnimatingIn) 90 { 91 // Fade in and slide up 92 if (this.Opacity < 1) 93 { 94 this.Opacity += 0.1; 95 } 96 97 if (this.Top > targetY) 98 { 99 this.Top -= 5; 100 } 101 else 102 { 103 this.Top = targetY; 104 } 105 106 if (this.Opacity >= 1 && this.Top <= targetY) 107 { 108 fadeTimer.Stop(); 109 closeTimer.Start(); 110 } 111 } 112 else 113 { 114 // Fade out 115 this.Opacity -= 0.1; 116 if (this.Opacity <= 0) 117 { 118 fadeTimer.Stop(); 119 this.Close(); 120 } 121 } 122 } 123 124 protected override void OnFormClosed(FormClosedEventArgs e) 125 { 126 if (fadeTimer != null) fadeTimer.Dispose(); 127 if (closeTimer != null) closeTimer.Dispose(); 128 base.OnFormClosed(e); 129 } 130 131 protected override CreateParams CreateParams 132 { 133 get 134 { 135 // Make window click-through friendly and tool window (no taskbar) 136 CreateParams cp = base.CreateParams; 137 cp.ExStyle |= 0x00000080; // WS_EX_TOOLWINDOW 138 return cp; 139 } 140 } 141 142 /// <summary> 143 /// Show a toast notification 144 /// </summary> 145 public static void Show(string title, string message, bool isError = false) 146 { 147 // Must be called on UI thread 148 var toast = new ToastNotification(title, message, isError); 149 toast.Show(); 150 } 151 } 152}