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)