Toasts – Blame information for rev 18

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;
18 office 227 private readonly TaskCompletionSource<object> _showFormTaskCompletionSource;
16 office 228  
1 office 229 #endregion
230  
231 #region Event Handlers
232  
9 office 233 private void Notification_Load(object sender, EventArgs e)
1 office 234 {
16 office 235 Task.Factory.StartNew(() =>
236 {
237 using (var memoryStream = new MemoryStream(_sound))
9 office 238 {
16 office 239 using (var player = new SoundPlayer(memoryStream))
240 {
241 player.Play();
242 }
9 office 243 }
16 office 244 });
8 office 245  
16 office 246 try
8 office 247 {
16 office 248 lock (OpenNotificationsLock)
8 office 249 {
16 office 250 var notifications = OpenNotifications.ToArray();
8 office 251  
16 office 252 foreach (var openForm in notifications)
15 office 253 {
16 office 254 if (openForm == null)
255 {
256 continue;
257 }
7 office 258  
16 office 259 if (openForm.IsDisposed)
260 {
261 OpenNotifications.Remove(openForm);
15 office 262  
16 office 263 continue;
264 }
1 office 265  
16 office 266 if (openForm.IsHandleCreated != true)
267 {
268 continue;
269 }
4 office 270  
16 office 271 // Move each open form upwards to make room for this one
272 var handle = Handle;
273 openForm.BeginInvoke(new MethodInvoker(() =>
274 {
275 try
276 {
277 if (openForm.Handle == handle)
278 {
279 return;
280 }
1 office 281  
16 office 282 openForm.Top -= Height;
283 }
284 catch
285 {
286 Debug.WriteLine("Error while moving forms up.");
287 }
288 }));
289 }
15 office 290  
16 office 291 Invoke(new MethodInvoker(() =>
292 {
293 Location = new Point(_screenWidth - Width, _screenHeight - Height);
294 }));
295  
296 OpenNotifications.Add(this);
297  
298 // Only start the timer if it has been enabled in the constructor.
299 if (_toastTimer.Enabled)
300 {
301 _toastTimer.Start();
302 }
303 }
304 }
305 catch
15 office 306 {
16 office 307 Debug.WriteLine("Error on form load event.");
15 office 308 }
1 office 309 }
310  
311 private void Notification_FormClosed(object sender, FormClosedEventArgs e)
312 {
16 office 313 try
1 office 314 {
16 office 315 lock (OpenNotificationsLock)
7 office 316 {
16 office 317 OpenNotifications.Remove(this);
7 office 318 }
16 office 319 }
320 catch
321 {
322 Debug.WriteLine("Error in form closed event.");
323 }
324 }
15 office 325  
16 office 326 private void Notification_Shown(object sender, EventArgs e)
327 {
328 // Reverse animation direction for hiding.
329 switch (_formAnimator.Direction)
330 {
331 case FormAnimator.AnimationDirection.Up:
332 _formAnimator.Direction = FormAnimator.AnimationDirection.Down;
333 break;
334 case FormAnimator.AnimationDirection.Down:
335 _formAnimator.Direction = FormAnimator.AnimationDirection.Up;
336 break;
337 case FormAnimator.AnimationDirection.Left:
338 _formAnimator.Direction = FormAnimator.AnimationDirection.Right;
339 break;
340 case FormAnimator.AnimationDirection.Right:
341 _formAnimator.Direction = FormAnimator.AnimationDirection.Left;
342 break;
1 office 343 }
18 office 344  
345 _showFormTaskCompletionSource.TrySetResult(new { });
1 office 346 }
347  
18 office 348 private async void ToastTimer_Elapsed(object sender, EventArgs e)
1 office 349 {
18 office 350 await _showFormTaskCompletionSource.Task;
351  
16 office 352 if (IsDisposed)
15 office 353 {
354 return;
355 }
1 office 356  
16 office 357 try
358 {
359 _toastTimer.Stop();
360 BeginInvoke(new MethodInvoker(() =>
361 {
362 lock (OpenNotificationsLock)
363 {
364 Close();
365 }
366 }));
367 }
368 catch
369 {
370 Debug.WriteLine("Error in timer elapsed event.");
371 }
1 office 372 }
373  
15 office 374 private void Toast_Click(object sender, EventArgs e)
1 office 375 {
16 office 376 try
377 {
378 lock (OpenNotificationsLock)
379 {
380 Close();
381 }
382 }
383 catch
384 {
385 Debug.WriteLine("Error in form click event.");
386 }
1 office 387 }
388  
389 #endregion
390 }
391 }