Toasts – Blame information for rev 21

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 // =====COPYRIGHT=====
2 // Code originally retrieved from http://www.vbforums.com/showthread.php?t=547778 - no license information supplied
3 // =====COPYRIGHT=====
4  
5 using System;
15 office 6 using System.Collections.Concurrent;
16 office 7 using System.Collections.Generic;
8 using System.Diagnostics;
1 office 9 using System.Drawing;
8 office 10 using System.IO;
15 office 11 using System.Linq;
8 office 12 using System.Media;
16 office 13 using System.Threading;
14 using System.Threading.Tasks;
1 office 15 using System.Windows.Forms;
11 office 16 using Toasts.Properties;
1 office 17  
18 namespace Toasts
19 {
2 office 20 public partial class ToastForm : Form
1 office 21 {
22 #region Static Fields and Constants
23  
16 office 24 private static readonly object OpenNotificationsLock = new object();
1 office 25  
16 office 26 private static readonly HashSet<ToastForm> OpenNotifications = new HashSet<ToastForm>();
27  
1 office 28 #endregion
29  
12 office 30 #region Private Overrides
31  
32 protected override bool ShowWithoutActivation => true;
33  
34 protected override CreateParams CreateParams
35 {
36 get
37 {
38 var baseParams = base.CreateParams;
39  
40 const int WS_EX_NOACTIVATE = 0x08000000;
41 const int WS_EX_TOOLWINDOW = 0x00000080;
42 const int WS_EX_TOPMOST = 0x00000008;
43 baseParams.ExStyle |= WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
44  
45 return baseParams;
46 }
47 }
48  
49 #endregion
50  
1 office 51 #region Constructors, Destructors and Finalizers
52  
11 office 53 private ToastForm()
7 office 54 {
55 InitializeComponent();
16 office 56 Region = Region.FromHrgn(NativeMethods.CreateRoundRectRgn(0, 0, Width - 5, Height - 5, 20, 20));
57  
58 _screenWidth = Screen.PrimaryScreen.WorkingArea.Width;
59 _screenHeight = Screen.PrimaryScreen.WorkingArea.Height;
15 office 60  
16 office 61 _formAnimator = new FormAnimator(this, FormAnimator.AnimationMethod.Slide, FormAnimator.AnimationDirection.Up,
62 500);
63  
64 using (var memoryStream = new MemoryStream())
15 office 65 {
16 office 66 Resources.normal.CopyTo(memoryStream);
67  
68 memoryStream.Position = 0L;
69  
70 _sound = memoryStream.ToArray();
15 office 71 }
72  
18 office 73 _showFormTaskCompletionSource = new TaskCompletionSource<object>();
74  
15 office 75 _toastTimer = new System.Timers.Timer();
76 _toastTimer.Elapsed += ToastTimer_Elapsed;
77 _toastTimer.Enabled = false;
7 office 78 }
11 office 79  
1 office 80 /// <summary>
15 office 81 /// Display a toast with a title, body and a logo indefinitely on screen.
1 office 82 /// </summary>
15 office 83 /// <param name="title">the toast title</param>
84 /// <param name="body">the toast body</param>
85 /// <param name="logo">the toast logo</param>
86 public ToastForm(string title, string body, Image logo) : this()
87 {
88 _toastTimer.Enabled = false;
89 labelTitle.Text = title;
90 labelBody.Text = body;
91 imageBox.Image = logo;
92 }
93  
94 /// <summary>
95 /// Display a toast on screen.
96 /// </summary>
97 /// <param name="title">the toast title</param>
98 /// <param name="body">the toast body</param>
99 /// <param name="duration">the duration in milliseconds to display the toast on screen for</param>
100 /// <param name="logo">the toast logo</param>
101 /// <param name="background">the background image for the toast</param>
102 /// <param name="sound">a sound to play when the toast is displayed</param>
103 /// <param name="animation">the form animation type <see cref="FormAnimator"/></param>
104 /// <param name="direction">the form animation direction <see cref="FormAnimator"/></param>
8 office 105 public ToastForm(string title, string body, int duration, Image logo, Image background, byte[] sound,
7 office 106 FormAnimator.AnimationMethod animation, FormAnimator.AnimationDirection direction) : this()
1 office 107 {
15 office 108 _toastTimer.Enabled = true;
109 _toastTimer.Interval = duration;
1 office 110 labelTitle.Text = title;
111 labelBody.Text = body;
112 imageBox.Image = logo;
113 BackgroundImage = background;
114  
8 office 115 _sound = sound;
116  
16 office 117 _formAnimator = new FormAnimator(this, animation, direction, 500);
1 office 118 }
119  
15 office 120 /// <summary>
121 /// Display a toast on screen.
122 /// </summary>
123 /// <param name="title">the toast title</param>
124 /// <param name="body">the toast body</param>
125 /// <param name="duration">the duration in milliseconds to display the toast on screen for</param>
126 /// <param name="logo">the toast logo</param>
127 /// <param name="sound">a sound to play when the toast is displayed</param>
128 /// <param name="animation">the form animation type <see cref="FormAnimator"/></param>
129 /// <param name="direction">the form animation direction <see cref="FormAnimator"/></param>
8 office 130 public ToastForm(string title, string body, int duration, Image logo, byte[] sound,
7 office 131 FormAnimator.AnimationMethod animation, FormAnimator.AnimationDirection direction) : this()
2 office 132 {
15 office 133 _toastTimer.Enabled = true;
134 _toastTimer.Interval = duration;
2 office 135 labelTitle.Text = title;
136 labelBody.Text = body;
137 imageBox.Image = logo;
1 office 138  
8 office 139 _sound = sound;
140  
16 office 141 _formAnimator = new FormAnimator(this, animation, direction, 500);
2 office 142 }
143  
15 office 144 /// <summary>
145 /// Display a toast on screen.
146 /// </summary>
147 /// <param name="title">the toast title</param>
148 /// <param name="body">the toast body</param>
149 /// <param name="duration">the duration in milliseconds to display the toast on screen for</param>
150 /// <param name="logo">the toast logo</param>
151 /// <param name="sound">a sound to play when the toast is displayed</param>
8 office 152 public ToastForm(string title, string body, int duration, Image logo, byte[] sound) : this()
1 office 153 {
15 office 154 _toastTimer.Enabled = true;
155 _toastTimer.Interval = duration;
2 office 156 labelTitle.Text = title;
157 labelBody.Text = body;
158 imageBox.Image = logo;
159  
8 office 160 _sound = sound;
1 office 161 }
162  
15 office 163 /// <summary>
164 /// Display a toast on screen.
165 /// </summary>
166 /// <param name="title">the toast title</param>
167 /// <param name="body">the toast body</param>
168 /// <param name="duration">the duration in milliseconds to display the toast on screen for</param>
169 /// <param name="logo">the toast logo</param>
9 office 170 public ToastForm(string title, string body, int duration, Image logo) : this()
171 {
15 office 172 _toastTimer.Enabled = true;
173 _toastTimer.Interval = duration;
9 office 174 labelTitle.Text = title;
175 labelBody.Text = body;
176 imageBox.Image = logo;
177 }
178  
15 office 179 /// <summary>
180 /// Display a toast on screen.
181 /// </summary>
182 /// <param name="title">the toast title</param>
183 /// <param name="body">the toast body</param>
184 /// <param name="duration">the duration in milliseconds to display the toast on screen for</param>
185 /// <param name="logo">the toast logo</param>
10 office 186 public ToastForm(string title, string body, int duration, Icon logo) : this()
187 {
18 office 188 _toastTimer.Enabled = true;
15 office 189 _toastTimer.Interval = duration;
10 office 190 labelTitle.Text = title;
191 labelBody.Text = body;
192 imageBox.Image = logo.ToBitmap();
193 }
194  
7 office 195 /// <summary>
11 office 196 /// Clean up any resources being used.
7 office 197 /// </summary>
198 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
199 protected override void Dispose(bool disposing)
200 {
16 office 201 if (disposing && components != null)
202 {
203 if (_toastTimer != null)
204 {
205 _toastTimer.Dispose();
206 _toastTimer = null;
207 }
208  
209 components.Dispose();
210 }
7 office 211 base.Dispose(disposing);
212 }
213  
1 office 214 #endregion
215  
216 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
217  
16 office 218 private readonly FormAnimator _formAnimator;
1 office 219  
16 office 220 private readonly byte[] _sound;
1 office 221  
16 office 222 private System.Timers.Timer _toastTimer;
1 office 223  
16 office 224 private readonly int _screenWidth;
225  
226 private readonly int _screenHeight;
21 office 227  
18 office 228 private readonly TaskCompletionSource<object> _showFormTaskCompletionSource;
16 office 229  
1 office 230 #endregion
231  
232 #region Event Handlers
233  
9 office 234 private void Notification_Load(object sender, EventArgs e)
1 office 235 {
16 office 236 Task.Factory.StartNew(() =>
237 {
238 using (var memoryStream = new MemoryStream(_sound))
9 office 239 {
16 office 240 using (var player = new SoundPlayer(memoryStream))
241 {
242 player.Play();
243 }
9 office 244 }
16 office 245 });
8 office 246  
16 office 247 try
8 office 248 {
16 office 249 lock (OpenNotificationsLock)
8 office 250 {
16 office 251 var notifications = OpenNotifications.ToArray();
8 office 252  
16 office 253 foreach (var openForm in notifications)
15 office 254 {
16 office 255 if (openForm == null)
256 {
257 continue;
258 }
7 office 259  
16 office 260 if (openForm.IsDisposed)
261 {
262 OpenNotifications.Remove(openForm);
15 office 263  
16 office 264 continue;
265 }
1 office 266  
16 office 267 if (openForm.IsHandleCreated != true)
268 {
269 continue;
270 }
4 office 271  
16 office 272 // Move each open form upwards to make room for this one
273 var handle = Handle;
274 openForm.BeginInvoke(new MethodInvoker(() =>
275 {
276 try
277 {
278 if (openForm.Handle == handle)
279 {
280 return;
281 }
1 office 282  
16 office 283 openForm.Top -= Height;
284 }
285 catch
286 {
287 Debug.WriteLine("Error while moving forms up.");
288 }
289 }));
290 }
15 office 291  
16 office 292 Invoke(new MethodInvoker(() =>
293 {
294 Location = new Point(_screenWidth - Width, _screenHeight - Height);
295 }));
296  
297 OpenNotifications.Add(this);
298  
299 // Only start the timer if it has been enabled in the constructor.
300 if (_toastTimer.Enabled)
301 {
302 _toastTimer.Start();
303 }
304 }
305 }
306 catch
15 office 307 {
16 office 308 Debug.WriteLine("Error on form load event.");
15 office 309 }
1 office 310 }
311  
312 private void Notification_FormClosed(object sender, FormClosedEventArgs e)
313 {
16 office 314 try
1 office 315 {
16 office 316 lock (OpenNotificationsLock)
7 office 317 {
16 office 318 OpenNotifications.Remove(this);
7 office 319 }
16 office 320 }
321 catch
322 {
323 Debug.WriteLine("Error in form closed event.");
324 }
325 }
15 office 326  
16 office 327 private void Notification_Shown(object sender, EventArgs e)
328 {
329 // Reverse animation direction for hiding.
330 switch (_formAnimator.Direction)
331 {
332 case FormAnimator.AnimationDirection.Up:
333 _formAnimator.Direction = FormAnimator.AnimationDirection.Down;
334 break;
335 case FormAnimator.AnimationDirection.Down:
336 _formAnimator.Direction = FormAnimator.AnimationDirection.Up;
337 break;
338 case FormAnimator.AnimationDirection.Left:
339 _formAnimator.Direction = FormAnimator.AnimationDirection.Right;
340 break;
341 case FormAnimator.AnimationDirection.Right:
342 _formAnimator.Direction = FormAnimator.AnimationDirection.Left;
343 break;
1 office 344 }
18 office 345  
346 _showFormTaskCompletionSource.TrySetResult(new { });
1 office 347 }
348  
18 office 349 private async void ToastTimer_Elapsed(object sender, EventArgs e)
1 office 350 {
18 office 351 await _showFormTaskCompletionSource.Task;
352  
16 office 353 if (IsDisposed)
15 office 354 {
355 return;
356 }
1 office 357  
16 office 358 try
359 {
360 _toastTimer.Stop();
361 BeginInvoke(new MethodInvoker(() =>
362 {
363 lock (OpenNotificationsLock)
364 {
365 Close();
366 }
367 }));
368 }
369 catch
370 {
371 Debug.WriteLine("Error in timer elapsed event.");
372 }
1 office 373 }
374  
15 office 375 private void Toast_Click(object sender, EventArgs e)
1 office 376 {
16 office 377 try
378 {
21 office 379 BeginInvoke(new MethodInvoker(() =>
16 office 380 {
21 office 381 lock (OpenNotificationsLock)
382 {
383 Close();
384 }
385 }));
16 office 386 }
387 catch
388 {
389 Debug.WriteLine("Error in form click event.");
390 }
1 office 391 }
392  
393 #endregion
394 }
395 }