Adding Design tab.
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 ContentAlignment iRequestedContentAlignment;
25 [Category("Appearance")]
26 [Description("Separator in our scrolling loop.")]
28 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
29 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
30 public string Separator { get; set; }
32 [Category("Behavior")]
33 [Description("How fast is our text scrolling, in pixels per second.")]
35 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
36 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
37 public int PixelsPerSecond { get; set; }
39 [Category("Behavior")]
40 [Description("Use an internal or an external timer.")]
42 [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
43 [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
58 Timer.Tick += new EventHandler(Timer_Tick);
71 private int CurrentPosition { get; set; }
72 private Timer Timer { get; set; }
73 private DateTime LastTickTime { get; set; }
74 private double PixelsLeft { get; set; }
75 //DateTime a = new DateTime(2010, 05, 12, 13, 15, 00);
76 //DateTime b = new DateTime(2010, 05, 12, 13, 45, 00);
77 //Console.WriteLine(b.Subtract(a).TotalMinutes);
81 UseCompatibleTextRendering = true;
82 //PixelsPerSecond = 32;
83 LastTickTime = DateTime.Now;
86 iBrush = new SolidBrush(ForeColor);
87 //iRequestedContentAlignment = TextAlign;
89 //Following is needed if we ever switch from Label to Control base class.
90 //Without it you get some pretty nasty flicker
91 //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
92 //SetStyle(ControlStyles.UserPaint, true);
93 //SetStyle(ControlStyles.AllPaintingInWmPaint, true);
94 //SetStyle(ControlStyles.DoubleBuffer, true);
97 public void UpdateAnimation(DateTime aLastTickTime, DateTime aNewTickTime)
106 while (CurrentPosition > (iTextSize.Width + iSeparatorSize.Width))
108 CurrentPosition -= ((int)(iTextSize.Width + iSeparatorSize.Width));
112 while (CurrentPosition > iScrollSize.Width)
114 CurrentPosition -= (int)iScrollSize.Width;
118 PixelsLeft += aNewTickTime.Subtract(aLastTickTime).TotalSeconds * PixelsPerSecond;
120 //Keep track of our pixels left over
121 //PixelsLeft = offset - Math.Truncate(offset);
122 double offset = Math.Truncate(PixelsLeft);
123 PixelsLeft -= offset;
125 CurrentPosition += Convert.ToInt32(offset);
130 BackColor = Color.Red;
132 else if (offset==1.0)
134 if (BackColor != Color.White)
136 BackColor = Color.White;
143 //BackColor = Color.Green;
146 //Only redraw if something has changed
153 void Timer_Tick(object sender, EventArgs e)
155 DateTime NewTickTime = DateTime.Now;
157 UpdateAnimation(LastTickTime, NewTickTime);
159 LastTickTime = NewTickTime;
162 private StringFormat GetStringFormatFromContentAllignment(ContentAlignment ca)
164 StringFormat format = new StringFormat();
165 format = StringFormat.GenericTypographic;
168 case ContentAlignment.TopCenter:
169 format.Alignment = StringAlignment.Center;
170 format.LineAlignment = StringAlignment.Near;
172 case ContentAlignment.TopLeft:
173 format.Alignment = StringAlignment.Near;
174 format.LineAlignment = StringAlignment.Near;
176 case ContentAlignment.TopRight:
177 format.Alignment = StringAlignment.Far;
178 format.LineAlignment = StringAlignment.Near;
180 case ContentAlignment.MiddleCenter:
181 format.Alignment = StringAlignment.Center;
182 format.LineAlignment = StringAlignment.Center;
184 case ContentAlignment.MiddleLeft:
185 format.Alignment = StringAlignment.Near;
186 format.LineAlignment = StringAlignment.Center;
188 case ContentAlignment.MiddleRight:
189 format.Alignment = StringAlignment.Far;
190 format.LineAlignment = StringAlignment.Center;
192 case ContentAlignment.BottomCenter:
193 format.Alignment = StringAlignment.Center;
194 format.LineAlignment = StringAlignment.Far;
196 case ContentAlignment.BottomLeft:
197 format.Alignment = StringAlignment.Near;
198 format.LineAlignment = StringAlignment.Far;
200 case ContentAlignment.BottomRight:
201 format.Alignment = StringAlignment.Far;
202 format.LineAlignment = StringAlignment.Far;
206 format.FormatFlags |= StringFormatFlags.NoWrap;
207 format.FormatFlags |= StringFormatFlags.NoClip;
208 format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
209 format.Trimming = StringTrimming.None;
214 protected override void OnForeColorChanged(EventArgs e)
216 //Color has changed recreate our brush
217 iBrush = new SolidBrush(ForeColor);
219 base.OnForeColorChanged(e);
223 private void HandleTextSizeChange()
225 //Reset our timer whenever our text changes
227 LastTickTime = DateTime.Now;
230 //TextAlign = iRequestedContentAlignment;
232 //For all string measurements and drawing issues refer to the following article:
233 // http://stackoverflow.com/questions/1203087/why-is-graphics-measurestring-returning-a-higher-than-expected-number
234 //Update text size according to text and font
235 Graphics g = this.CreateGraphics();
236 g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
237 iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
238 iTextSize = g.MeasureString(Text, Font, Int32.MaxValue, iStringFormat);
239 iSeparatorSize = g.MeasureString(Separator, Font, Int32.MaxValue, iStringFormat);
240 //Scroll width is the width of our text and our separator without taking kerning into account since
241 //both text and separator are drawn independently from each other.
242 iScrollSize.Width = iSeparatorSize.Width + iTextSize.Width;
243 iScrollSize.Height = Math.Max(iSeparatorSize.Height, iTextSize.Height); //Not relevant for now
244 //We don't want scroll with to take kerning into account so we don't use the following
245 //iScrollSize = g.MeasureString(Text + Separator, Font, Int32.MaxValue, iStringFormat);
249 //Always align left when scrolling
250 //Somehow draw string still takes into our control alignment so we need to set it too
251 //ContentAlignment original = TextAlign;
252 TextAlign = ContentAlignment.MiddleLeft;
253 //Make sure our original text alignment remain the same even though we override it when scrolling
254 //iRequestedContentAlignment = original;
255 //iStringFormat will get updated in OnTextAlignChanged
256 //iStringFormat.Alignment = StringAlignment.Near;
260 protected override void OnTextChanged(EventArgs e)
262 HandleTextSizeChange();
264 base.OnTextChanged(e);
267 protected override void OnFontChanged(EventArgs e)
269 HandleTextSizeChange();
271 base.OnFontChanged(e);
274 protected override void OnTextAlignChanged(EventArgs e)
276 iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
277 //iRequestedContentAlignment = TextAlign;
278 base.OnTextAlignChanged(e);
282 protected override void OnPaint(PaintEventArgs e)
284 //Disable anti-aliasing
285 e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
288 //Draw it all in a single call would take kerning into account
289 //e.Graphics.TranslateTransform(-(float)CurrentPosition, 0);
290 //e.Graphics.DrawString(Text + Separator + Text, Font, iBrush, ClientRectangle, iStringFormat);
292 //Doing separate draw operation allows us not to take kerning into account between separator and string
294 e.Graphics.TranslateTransform(-(float)CurrentPosition, 0);
295 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
297 e.Graphics.TranslateTransform(iTextSize.Width, 0);
298 e.Graphics.DrawString(Separator, Font, iBrush, ClientRectangle, iStringFormat);
300 e.Graphics.TranslateTransform(iSeparatorSize.Width, 0);
301 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
305 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
310 //DrawText is not working without anti-aliasing. See: stackoverflow.com/questions/8283631/graphics-drawstring-vs-textrenderer-drawtextwhich-can-deliver-better-quality
311 //TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, BackColor, iTextFormatFlags);
316 public bool NeedToScroll()
318 //if (Width < e.Graphics.MeasureString(Text, Font).Width)
319 if (Width < iTextSize.Width)
326 protected override void Dispose(bool disposing)