Fixing div by zero in network signal animation code of GP1212 displays.
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Diagnostics;
7 using System.Threading.Tasks;
9 using System.Windows.Forms;
12 namespace SharpDisplayManager
14 [System.ComponentModel.DesignerCategory("Code")]
15 public class MarqueeLabel : Label
17 private bool iOwnTimer;
18 private StringFormat iStringFormat;
19 private SolidBrush iBrush;
20 private SizeF iTextSize;
21 private SizeF iSeparatorSize;
22 private SizeF iScrollSize;
23 private Font iFontInUse;
24 private string iSeparator;
26 [Category("Appearance")]
27 [Description("Separator in our scrolling loop.")]
29 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
30 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
31 public string Separator
39 if (value != Separator)
42 OnTextChanged(EventArgs.Empty);
47 [Category("Behavior")]
48 [Description("How fast is our text scrolling, in pixels per second.")]
50 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
51 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
52 public int PixelsPerSecond { get; set; }
54 [Category("Behavior")]
55 [Description("Should we scale down our font to try fit our text without scrolling.")]
57 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
58 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
59 public bool ScaleToFit { get; set; }
61 [Category("Behavior")]
62 [Description("Minimum size of our font allowed when scaling is enabled.")]
64 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
65 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
66 public float MinFontSize { get; set; }
68 [Category("Behavior")]
69 [Description("Use an internal or an external timer.")]
71 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
72 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
87 Timer.Tick += new EventHandler(Timer_Tick);
100 private int CurrentPosition { get; set; }
101 private Timer Timer { get; set; }
102 private DateTime LastTickTime { get; set; }
103 private double PixelsLeft { get; set; }
104 //DateTime a = new DateTime(2010, 05, 12, 13, 15, 00);
105 //DateTime b = new DateTime(2010, 05, 12, 13, 45, 00);
106 //Console.WriteLine(b.Subtract(a).TotalMinutes);
108 public MarqueeLabel()
110 UseCompatibleTextRendering = true;
111 //PixelsPerSecond = 32;
112 LastTickTime = DateTime.Now;
115 iBrush = new SolidBrush(ForeColor);
118 //Just clone our font
119 iFontInUse = new Font(Font, Font.Style);
121 //Following is needed if we ever switch from Label to Control base class.
122 //Without it you get some pretty nasty flicker
123 //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
124 //SetStyle(ControlStyles.UserPaint, true);
125 //SetStyle(ControlStyles.AllPaintingInWmPaint, true);
126 //SetStyle(ControlStyles.DoubleBuffer, true);
129 public void UpdateAnimation(DateTime aLastTickTime, DateTime aNewTickTime)
138 while (CurrentPosition > (iTextSize.Width + iSeparatorSize.Width))
140 CurrentPosition -= ((int)(iTextSize.Width + iSeparatorSize.Width));
144 while (CurrentPosition > iScrollSize.Width)
146 CurrentPosition -= (int)iScrollSize.Width;
150 PixelsLeft += aNewTickTime.Subtract(aLastTickTime).TotalSeconds * PixelsPerSecond;
152 //Keep track of our pixels left over
153 //PixelsLeft = offset - Math.Truncate(offset);
154 double offset = Math.Truncate(PixelsLeft);
155 PixelsLeft -= offset;
157 CurrentPosition += Convert.ToInt32(offset);
162 BackColor = Color.Red;
164 else if (offset==1.0)
166 if (BackColor != Color.White)
168 BackColor = Color.White;
175 //BackColor = Color.Green;
178 //Only redraw if something has changed
185 void Timer_Tick(object sender, EventArgs e)
187 DateTime NewTickTime = DateTime.Now;
189 UpdateAnimation(LastTickTime, NewTickTime);
191 LastTickTime = NewTickTime;
194 private StringFormat GetStringFormatFromContentAllignment(ContentAlignment ca)
196 StringFormat format = new StringFormat(StringFormat.GenericTypographic);
199 case ContentAlignment.TopCenter:
200 format.Alignment = StringAlignment.Center;
201 format.LineAlignment = StringAlignment.Near;
203 case ContentAlignment.TopLeft:
204 format.Alignment = StringAlignment.Near;
205 format.LineAlignment = StringAlignment.Near;
207 case ContentAlignment.TopRight:
208 format.Alignment = StringAlignment.Far;
209 format.LineAlignment = StringAlignment.Near;
211 case ContentAlignment.MiddleCenter:
212 format.Alignment = StringAlignment.Center;
213 format.LineAlignment = StringAlignment.Center;
215 case ContentAlignment.MiddleLeft:
216 format.Alignment = StringAlignment.Near;
217 format.LineAlignment = StringAlignment.Center;
219 case ContentAlignment.MiddleRight:
220 format.Alignment = StringAlignment.Far;
221 format.LineAlignment = StringAlignment.Center;
223 case ContentAlignment.BottomCenter:
224 format.Alignment = StringAlignment.Center;
225 format.LineAlignment = StringAlignment.Far;
227 case ContentAlignment.BottomLeft:
228 format.Alignment = StringAlignment.Near;
229 format.LineAlignment = StringAlignment.Far;
231 case ContentAlignment.BottomRight:
232 format.Alignment = StringAlignment.Far;
233 format.LineAlignment = StringAlignment.Far;
237 format.FormatFlags |= StringFormatFlags.NoWrap;
238 format.FormatFlags |= StringFormatFlags.NoClip;
239 format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
240 format.Trimming = StringTrimming.None;
245 protected override void OnForeColorChanged(EventArgs e)
247 //Color has changed recreate our brush
248 iBrush = new SolidBrush(ForeColor);
250 base.OnForeColorChanged(e);
254 private void ComputeSizes()
256 //For all string measurements and drawing issues refer to the following article:
257 // http://stackoverflow.com/questions/1203087/why-is-graphics-measurestring-returning-a-higher-than-expected-number
258 //Update text size according to text and font
259 Graphics g = this.CreateGraphics();
260 g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
261 iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
262 iTextSize = g.MeasureString(Text, iFontInUse, Int32.MaxValue, iStringFormat);
263 iSeparatorSize = g.MeasureString(Separator, iFontInUse, Int32.MaxValue, iStringFormat);
264 //Scroll width is the width of our text and our separator without taking kerning into account since
265 //both text and separator are drawn independently from each other.
266 iScrollSize.Width = iSeparatorSize.Width + iTextSize.Width;
267 iScrollSize.Height = Math.Max(iSeparatorSize.Height, iTextSize.Height); //Not relevant for now
268 //We don't want scroll width to take kerning into account so we don't use the following
269 //iScrollSize = g.MeasureString(Text + Separator, Font, Int32.MaxValue, iStringFormat);
272 private void HandleTextSizeChange()
278 if (ScaleToFit && iFontInUse.SizeInPoints > MinFontSize)
281 iFontInUse = new Font(Font.FontFamily, iFontInUse.SizeInPoints - 1, Font.Style);
282 //Recurse until we are done
283 HandleTextSizeChange();
289 //Our minimum font size still needs scrolling
290 //Reset our font then
291 iFontInUse = new Font(Font,Font.Style);
295 //Scrolling is ok or needed
296 //Always align left when scrolling
297 iStringFormat.Alignment = StringAlignment.Near;
301 //Reset our timer whenever our text changes
304 LastTickTime = DateTime.Now;
307 protected override void OnTextChanged(EventArgs e)
309 //Just clone our font
310 iFontInUse = new Font(Font, Font.Style);
312 HandleTextSizeChange();
314 base.OnTextChanged(e);
317 protected override void OnFontChanged(EventArgs e)
319 //Just clone our font
320 iFontInUse = new Font(Font,Font.Style);
322 HandleTextSizeChange();
324 base.OnFontChanged(e);
327 protected override void OnSizeChanged(EventArgs e)
329 //Just clone our font
330 iFontInUse = new Font(Font, Font.Style);
332 HandleTextSizeChange();
334 base.OnSizeChanged(e);
337 protected override void OnTextAlignChanged(EventArgs e)
339 iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
342 //Always align left when scrolling to avoid bugs
343 iStringFormat.Alignment = StringAlignment.Near;
348 base.OnTextAlignChanged(e);
351 protected override void OnPaint(PaintEventArgs e)
353 //Disable anti-aliasing
354 e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
357 //Draw it all in a single call would take kerning into account
358 //e.Graphics.TranslateTransform(-(float)CurrentPosition, 0);
359 //e.Graphics.DrawString(Text + Separator + Text, Font, iBrush, ClientRectangle, StringFormat);
361 //Doing separate draw operation allows us not to take kerning into account between separator and string
363 e.Graphics.TranslateTransform(-(float)CurrentPosition, 0);
364 e.Graphics.DrawString(Text, iFontInUse, iBrush, ClientRectangle, iStringFormat);
366 e.Graphics.TranslateTransform(iTextSize.Width, 0);
367 e.Graphics.DrawString(Separator, iFontInUse, iBrush, ClientRectangle, iStringFormat);
369 e.Graphics.TranslateTransform(iSeparatorSize.Width, 0);
370 e.Graphics.DrawString(Text, iFontInUse, iBrush, ClientRectangle, iStringFormat);
374 e.Graphics.DrawString(Text, iFontInUse, iBrush, ClientRectangle, iStringFormat);
379 //DrawText is not working without anti-aliasing. See: stackoverflow.com/questions/8283631/graphics-drawstring-vs-textrenderer-drawtextwhich-can-deliver-better-quality
380 //TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, BackColor, iTextFormatFlags);
385 public bool NeedToScroll()
387 //if (Width < e.Graphics.MeasureString(Text, Font).Width)
388 if (Width < iTextSize.Width)
395 protected override void Dispose(bool disposing)