Adding text field support to our tree view.
Trying to fix our messy text alignment issue causing loop problems.
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;
90 public void UpdateAnimation(DateTime aLastTickTime, DateTime aNewTickTime)
99 while (CurrentPosition > (iTextSize.Width + iSeparatorSize.Width))
101 CurrentPosition -= ((int)(iTextSize.Width + iSeparatorSize.Width));
105 while (CurrentPosition > iScrollSize.Width)
107 CurrentPosition -= (int)iScrollSize.Width;
111 PixelsLeft += aNewTickTime.Subtract(aLastTickTime).TotalSeconds * PixelsPerSecond;
113 //Keep track of our pixels left over
114 //PixelsLeft = offset - Math.Truncate(offset);
115 double offset = Math.Truncate(PixelsLeft);
116 PixelsLeft -= offset;
118 CurrentPosition += Convert.ToInt32(offset);
123 BackColor = Color.Red;
125 else if (offset==1.0)
127 if (BackColor != Color.White)
129 BackColor = Color.White;
136 //BackColor = Color.Green;
139 //Only redraw if something has changed
146 void Timer_Tick(object sender, EventArgs e)
148 DateTime NewTickTime = DateTime.Now;
150 UpdateAnimation(LastTickTime, NewTickTime);
152 LastTickTime = NewTickTime;
155 private StringFormat GetStringFormatFromContentAllignment(ContentAlignment ca)
157 StringFormat format = new StringFormat();
158 format = StringFormat.GenericTypographic;
161 case ContentAlignment.TopCenter:
162 format.Alignment = StringAlignment.Center;
163 format.LineAlignment = StringAlignment.Near;
165 case ContentAlignment.TopLeft:
166 format.Alignment = StringAlignment.Near;
167 format.LineAlignment = StringAlignment.Near;
169 case ContentAlignment.TopRight:
170 format.Alignment = StringAlignment.Far;
171 format.LineAlignment = StringAlignment.Near;
173 case ContentAlignment.MiddleCenter:
174 format.Alignment = StringAlignment.Center;
175 format.LineAlignment = StringAlignment.Center;
177 case ContentAlignment.MiddleLeft:
178 format.Alignment = StringAlignment.Near;
179 format.LineAlignment = StringAlignment.Center;
181 case ContentAlignment.MiddleRight:
182 format.Alignment = StringAlignment.Far;
183 format.LineAlignment = StringAlignment.Center;
185 case ContentAlignment.BottomCenter:
186 format.Alignment = StringAlignment.Center;
187 format.LineAlignment = StringAlignment.Far;
189 case ContentAlignment.BottomLeft:
190 format.Alignment = StringAlignment.Near;
191 format.LineAlignment = StringAlignment.Far;
193 case ContentAlignment.BottomRight:
194 format.Alignment = StringAlignment.Far;
195 format.LineAlignment = StringAlignment.Far;
199 format.FormatFlags |= StringFormatFlags.NoWrap;
200 format.FormatFlags |= StringFormatFlags.NoClip;
201 format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
202 format.Trimming = StringTrimming.None;
207 protected override void OnForeColorChanged(EventArgs e)
209 //Color has changed recreate our brush
210 iBrush = new SolidBrush(ForeColor);
212 base.OnForeColorChanged(e);
216 private void HandleTextSizeChange()
218 //Reset our timer whenever our text changes
220 LastTickTime = DateTime.Now;
223 //TextAlign = iRequestedContentAlignment;
225 //For all string measurements and drawing issues refer to the following article:
226 // http://stackoverflow.com/questions/1203087/why-is-graphics-measurestring-returning-a-higher-than-expected-number
227 //Update text size according to text and font
228 Graphics g = this.CreateGraphics();
229 g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
230 iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
231 iTextSize = g.MeasureString(Text, Font, Int32.MaxValue, iStringFormat);
232 iSeparatorSize = g.MeasureString(Separator, Font, Int32.MaxValue, iStringFormat);
233 //Scroll width is the width of our text and our separator without taking kerning into account since
234 //both text and separator are drawn independently from each other.
235 iScrollSize.Width = iSeparatorSize.Width + iTextSize.Width;
236 iScrollSize.Height = Math.Max(iSeparatorSize.Height, iTextSize.Height); //Not relevant for now
237 //We don't want scroll with to take kerning into account so we don't use the following
238 //iScrollSize = g.MeasureString(Text + Separator, Font, Int32.MaxValue, iStringFormat);
242 //Always align left when scrolling
243 //Somehow draw string still takes into our control alignment so we need to set it too
244 //ContentAlignment original = TextAlign;
245 TextAlign = ContentAlignment.MiddleLeft;
246 //Make sure our original text alignment remain the same even though we override it when scrolling
247 //iRequestedContentAlignment = original;
248 //iStringFormat will get updated in OnTextAlignChanged
249 //iStringFormat.Alignment = StringAlignment.Near;
253 protected override void OnTextChanged(EventArgs e)
255 HandleTextSizeChange();
257 base.OnTextChanged(e);
260 protected override void OnFontChanged(EventArgs e)
262 HandleTextSizeChange();
264 base.OnFontChanged(e);
267 protected override void OnTextAlignChanged(EventArgs e)
269 iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
270 //iRequestedContentAlignment = TextAlign;
271 base.OnTextAlignChanged(e);
275 protected override void OnPaint(PaintEventArgs e)
277 //Disable anti-aliasing
278 e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
281 //Draw it all in a single call would take kerning into account
282 //e.Graphics.TranslateTransform(-(float)CurrentPosition, 0);
283 //e.Graphics.DrawString(Text + Separator + Text, Font, iBrush, ClientRectangle, iStringFormat);
285 //Doing separate draw operation allows us not to take kerning into account between separator and string
287 e.Graphics.TranslateTransform(-(float)CurrentPosition, 0);
288 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
290 e.Graphics.TranslateTransform(iTextSize.Width, 0);
291 e.Graphics.DrawString(Separator, Font, iBrush, ClientRectangle, iStringFormat);
293 e.Graphics.TranslateTransform(iSeparatorSize.Width, 0);
294 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
298 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
303 //DrawText is not working without anti-aliasing. See: stackoverflow.com/questions/8283631/graphics-drawstring-vs-textrenderer-drawtextwhich-can-deliver-better-quality
304 //TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, BackColor, iTextFormatFlags);
309 public bool NeedToScroll()
311 //if (Width < e.Graphics.MeasureString(Text, Font).Width)
312 if (Width < iTextSize.Width)
319 protected override void Dispose(bool disposing)