Toasts – Diff between revs 43 and 44

Subversion Repositories:
Rev:
Show entire fileIgnore whitespace
Rev 43 Rev 44
Line 15... Line 15...
15 using System.Threading; 15 using System.Threading;
16 using System.Threading.Tasks; 16 using System.Threading.Tasks;
17 using System.Windows.Forms; 17 using System.Windows.Forms;
18 using TheArtOfDev.HtmlRenderer.WinForms; 18 using TheArtOfDev.HtmlRenderer.WinForms;
19 using Toasts.Properties; 19 using Toasts.Properties;
20 using static System.Windows.Forms.VisualStyles.VisualStyleElement; -  
21 using static TheArtOfDev.HtmlRenderer.Adapters.RGraphicsPath; -  
22 using static Toasts.FormAnimator; -  
Line 23... Line 20...
23   20  
24 namespace Toasts 21 namespace Toasts
25 { 22 {
26 public partial class ToastForm : Form 23 public partial class ToastForm : Form
27 { 24 {
28 #region Public Fields and Properties 25 #region Public Fields and Properties
29 26  
30 public bool EnableChime { get; set; } = true; 27 public bool EnableChime { get; set; } = true;
31   28  
32 public int LingerTime { get; set; } = 5000; 29 public int LingerTime { get; set; } = 5000;
33   30  
34 public FormAnimator.AnimationMethod AnimationMethodDetached { get; set; } = FormAnimator.AnimationMethod.Fade; 31 public FormAnimator.AnimationMethod AnimationMethodDetached { get; set; } = FormAnimator.AnimationMethod.Fade;
35   32  
36 public FormAnimator.AnimationDirection AnimationDirectionDetached { get; set; } = FormAnimator.AnimationDirection.None; 33 public FormAnimator.AnimationDirection AnimationDirectionDetached { get; set; } = FormAnimator.AnimationDirection.None;
37   34  
38 public FormAnimator.AnimationMethod AnimationMethod { get; set; } = FormAnimator.AnimationMethod.Slide; 35 public FormAnimator.AnimationMethod AnimationMethod { get; set; } = FormAnimator.AnimationMethod.Slide;
39   36  
40 public FormAnimator.AnimationDirection AnimationDirection { get; set; } = FormAnimator.AnimationDirection.Up; 37 public FormAnimator.AnimationDirection AnimationDirection { get; set; } = FormAnimator.AnimationDirection.Up;
41   38  
42 public int AnimationDuration { get; set; } = 500; 39 public int AnimationDuration { get; set; } = 500;
43   40  
44 public string ContentType { get; internal set; } = "text/plain"; 41 public string ContentType { get; internal set; } = "text/plain";
45   42  
46 public byte[] Chime 43 public byte[] Chime
47 { 44 {
48 get => _chime; 45 get => _chime;
49 set 46 set
50 { 47 {
51 if (value is null) 48 if (value is null)
52 { 49 {
53 return; 50 return;
54 } 51 }
55   52  
56 _chime = value; 53 _chime = value;
57 } 54 }
58 } 55 }
59   56  
60 /// <summary> 57 /// <summary>
61 /// 58 ///
62 /// </summary> 59 /// </summary>
63 /// <remarks>clone the image for safety</remarks> 60 /// <remarks>clone the image for safety</remarks>
64 public Image Image 61 public Image Image
65 { 62 {
66 get 63 get
67 { 64 {
68 try 65 try
Line 69... Line 66...
69 { 66 {
70   67  
71 return new Bitmap(imageBox.Image); 68 return new Bitmap(imageBox.Image);
72 } 69 }
73 catch 70 catch
74 { 71 {
75 return null; 72 return null;
76 } 73 }
77 } 74 }
78 set => imageBox.Image = value; 75 set => imageBox.Image = value;
79 } 76 }
80   77  
81 #endregion 78 #endregion
82   79  
83 #region Static Fields and Constants 80 #region Static Fields and Constants
84   81  
85 private static readonly object OpenNotificationsLock = new object(); 82 private static readonly object OpenNotificationsLock = new object();
86   83  
87 private static readonly HashSet<ToastForm> OpenNotifications = new HashSet<ToastForm>(); 84 private static readonly HashSet<ToastForm> OpenNotifications = new HashSet<ToastForm>();
88   85  
89 #endregion 86 #endregion
90   87  
91 #region Private Fields and Properties 88 #region Private Fields and Properties
92   89  
93 private bool _toastDetached; 90 private bool _toastDetached;
94 private object _toastDetachedLock = new object(); 91 private object _toastDetachedLock = new object();
95 private bool _mouseDown; 92 private bool _mouseDown;
96 private Point _lastLocation; 93 private Point _lastLocation;
97   94  
98 #endregion 95 #endregion
99   96  
100 #region Private Overrides 97 #region Private Overrides
101   98  
102 protected override bool ShowWithoutActivation => true; 99 protected override bool ShowWithoutActivation => true;
103 protected override CreateParams CreateParams 100 protected override CreateParams CreateParams
104 { 101 {
105 get 102 get
106 { 103 {
107 104  
108 var baseParams = base.CreateParams; 105 var baseParams = base.CreateParams;
109 106  
110 //const int WS_EX_NOACTIVATE = 0x08000000; 107 //const int WS_EX_NOACTIVATE = 0x08000000;
111 const int WS_EX_TOOLWINDOW = 0x00000080; 108 const int WS_EX_TOOLWINDOW = 0x00000080;
112 const int WS_EX_TOPMOST = 0x00000008; 109 const int WS_EX_TOPMOST = 0x00000008;
113 baseParams.ExStyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; 110 baseParams.ExStyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
114 111  
115 return baseParams; 112 return baseParams;
Line 116... Line 113...
116 } 113 }
117 } 114 }
Line 214... Line 242...
214 if (EnableChime) 242 if (EnableChime)
215 { 243 {
216 Task.Factory.StartNew(() => 244 Task.Factory.StartNew(() =>
217 { 245 {
218 try 246 try
219 { 247 {
220 using (var memoryStream = new MemoryStream(Chime)) 248 using (var memoryStream = new MemoryStream(Chime))
221 { 249 {
222 using (var player = new SoundPlayer(memoryStream)) 250 using (var player = new SoundPlayer(memoryStream))
223 { 251 {
224 player.Play(); 252 player.Play();
225 } 253 }
226 } 254 }
227 } 255 }
228 catch 256 catch
229 { 257 {
230 Debug.WriteLine("Sound file could not be played."); 258 Debug.WriteLine("Sound file could not be played.");
231 } 259 }
232 }); 260 });
233 } 261 }
234   262  
235 try 263 try
236 { 264 {
237 lock (OpenNotificationsLock) 265 lock (OpenNotificationsLock)
238 { 266 {
239 // if not image is provided, just collapse the panel for the extra space 267 // if not image is provided, just collapse the panel for the extra space
240 if (imageBox.Image == null) 268 if (imageBox.Image == null)
241 { 269 {
242 splitContainer1.Panel1Collapsed = true; 270 splitContainer1.Panel1Collapsed = true;
243 } 271 }
244   272  
245 Invoke(new MethodInvoker(() => 273 Invoke(new MethodInvoker(() =>
246 { 274 {
247 // compute notification height from body 275 // compute notification height from body
248 var maxWidth = tableLayoutPanel4.Width; 276 var maxWidth = tableLayoutPanel4.Width;
249 using (var m_Bitmap = new Bitmap(64, 64)) 277 using (var m_Bitmap = new Bitmap(64, 64))
250 { 278 {
251 using (var graphics = Graphics.FromImage(m_Bitmap)) 279 using (var graphics = Graphics.FromImage(m_Bitmap))
252 { 280 {
-   281 switch (ContentType)
-   282 {
-   283 case "text/markdown":
253 switch(ContentType) 284 var htmlDocument = new HtmlAgilityPack.HtmlDocument();
-   285 var panelText = htmlPanel1.Text;
-   286 if (!string.IsNullOrEmpty(panelText))
254 { 287 {
-   288 htmlDocument.LoadHtml(panelText);
255 case "text/markdown": 289 if (htmlDocument.DocumentNode != null && htmlDocument.DocumentNode.Descendants().Any())
-   290 {
-   291 var imgNodes = htmlDocument.DocumentNode.SelectNodes("//img");
256 var htmlDocument = new HtmlAgilityPack.HtmlDocument(); 292 if (imgNodes != null && imgNodes.Any())
-   293 {
-   294 foreach (var node in imgNodes)
257 htmlDocument.LoadHtml(htmlPanel1.Text); 295 {
258 foreach (var node in htmlDocument.DocumentNode.SelectNodes("//img")) 296 node.SetAttributeValue("style", $"max-width: {maxWidth}px");
259 { 297 }
-   298 }
260 node.SetAttributeValue("style", $"max-width: {maxWidth}px"); 299 }
261 } 300  
262   301 htmlPanel1.Text = htmlDocument.DocumentNode.WriteTo();
263 htmlPanel1.Text = htmlDocument.DocumentNode.WriteTo(); 302 }
264 break; 303 break;
265 default: 304 default:
266 break; 305 break;
267 } 306 }
268   307  
269 PointF point = new PointF(0, 0); 308 PointF point = new PointF(0, 0);
270 SizeF maxSize = new SizeF(maxWidth, Screen.PrimaryScreen.WorkingArea.Height); 309 SizeF maxSize = new SizeF(maxWidth, Screen.PrimaryScreen.WorkingArea.Height);
271 var renderSize = HtmlRender.Render(graphics, htmlPanel1.Text, point, maxSize); 310 var renderSize = HtmlRender.Render(graphics, htmlPanel1.Text, point, maxSize);
272 // total height = height of text fitting in rectangle + the height of the title on top + one extra line for the last line wrap 311 // total height = height of text fitting in rectangle + the height of the title on top + one extra line for the last line wrap
273 var computedOptimalHeight = (int)Math.Round(renderSize.Height) + labelTitle.Height + (int)Math.Round(htmlPanel1.Font.GetHeight()); 312 var computedOptimalHeight = (int)Math.Round(renderSize.Height) + labelTitle.Height + (int)Math.Round(htmlPanel1.Font.GetHeight());
274 // keep the default height of a notification constant 313 // keep the default height of a notification constant
275 if(computedOptimalHeight > Height) 314 if (computedOptimalHeight > Height)
276 { 315 {
277 Height = computedOptimalHeight; 316 Height = computedOptimalHeight;
278 } 317 }
279 } 318 }
280 } 319 }
281 })); 320 }));
282   321  
283 if (EnablePin) 322 if (EnablePin)
Line 293... Line 332...
293   332  
294 _formAnimator.Method = AnimationMethodDetached; 333 _formAnimator.Method = AnimationMethodDetached;
Line 295... Line 334...
295 _formAnimator.Direction = AnimationDirectionDetached; 334 _formAnimator.Direction = AnimationDirectionDetached;
517 } 561  
518 } 562 #endregion
519 } 563 }