MarqueeLabel.cs
author sl
Tue, 08 Jul 2014 18:59:07 +0200
changeset 8 5129c03ab7ba
parent 6 70b26a1ae93b
child 11 de55741d90f0
permissions -rw-r--r--
Adding persistent settings and marquee separator.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Diagnostics;
     5 using System.Linq;
     6 using System.Text;
     7 using System.Threading.Tasks;
     8 //using System.Timers;
     9 using System.Windows.Forms;
    10 using System.Drawing;
    11 
    12 namespace SharpDisplayManager
    13 {
    14     class MarqueeLabel : Label
    15     {
    16         private bool iOwnTimer;
    17         private StringFormat iStringFormat;
    18         private SolidBrush iBrush;
    19         private SizeF iTextSize;
    20         private SizeF iSeparatorSize;
    21 
    22         [Category("Appearance")]
    23         [Description("Separator in our scrolling loop.")]
    24         [DefaultValue(" | ")]
    25         [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
    26         public string Separator { get; set; }
    27 
    28         [Category("Behavior")]
    29         [Description("How fast is our text scrolling, in pixels per second.")]
    30         [DefaultValue(32)]
    31         [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
    32         public int PixelsPerSecond { get; set; }
    33 
    34         [Category("Behavior")]
    35         [Description("Use an internal or an external timer.")]
    36         [DefaultValue(true)]
    37         [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
    38         public bool OwnTimer
    39         {
    40             get
    41             {
    42                 return iOwnTimer;
    43             }
    44             set
    45             {
    46                 iOwnTimer = value;
    47 
    48                 if (iOwnTimer)
    49                 {
    50                     Timer = new Timer();
    51                     Timer.Interval = 10;
    52                     Timer.Tick += new EventHandler(Timer_Tick);
    53                     Timer.Start();
    54                 }
    55                 else
    56                 {
    57                     if (Timer != null)
    58                         Timer.Dispose();
    59                     Timer = null;
    60                 }
    61 
    62             }
    63         }
    64 
    65         private int CurrentPosition { get; set; }
    66         private Timer Timer { get; set; }
    67         private DateTime LastTickTime { get; set; }
    68         private double PixelsLeft { get; set; }
    69         //DateTime a = new DateTime(2010, 05, 12, 13, 15, 00);
    70         //DateTime b = new DateTime(2010, 05, 12, 13, 45, 00);
    71         //Console.WriteLine(b.Subtract(a).TotalMinutes);
    72 
    73         public MarqueeLabel()
    74         {
    75             UseCompatibleTextRendering = true;
    76             //PixelsPerSecond = 32;
    77             LastTickTime = DateTime.Now;
    78             PixelsLeft = 0;
    79             iBrush = new SolidBrush(ForeColor);
    80         }
    81 
    82         public void UpdateAnimation(DateTime aLastTickTime, DateTime aNewTickTime)
    83         {
    84             if (!NeedToScroll())
    85             {
    86                 CurrentPosition = 0;
    87                 return;
    88             }
    89 
    90             while (CurrentPosition > (iTextSize.Width + iSeparatorSize.Width))
    91             {
    92                 CurrentPosition -= ((int)(iTextSize.Width + iSeparatorSize.Width));
    93             }
    94 
    95             PixelsLeft += aNewTickTime.Subtract(aLastTickTime).TotalSeconds * PixelsPerSecond;
    96 
    97             //Keep track of our pixels left over
    98             //PixelsLeft = offset - Math.Truncate(offset);
    99             double offset = Math.Truncate(PixelsLeft);
   100             PixelsLeft -= offset;
   101 
   102             CurrentPosition += Convert.ToInt32(offset);
   103 
   104             /*
   105             if (offset > 1.0)
   106             {
   107                 BackColor = Color.Red;
   108             }
   109             else if (offset==1.0)
   110             {
   111                 if (BackColor != Color.White)
   112                 {
   113                     BackColor = Color.White;
   114                 }
   115 
   116             }
   117             else
   118             {
   119                 //Too slow
   120                 //BackColor = Color.Green;
   121             }*/
   122 
   123             //Only redraw if something has changed
   124             if (offset != 0)
   125             {
   126                 Invalidate();
   127             }
   128         }
   129 
   130         void Timer_Tick(object sender, EventArgs e)
   131         {
   132             DateTime NewTickTime = DateTime.Now;
   133             //
   134             UpdateAnimation(LastTickTime, NewTickTime);
   135             //
   136             LastTickTime = NewTickTime;
   137         }
   138 
   139         private StringFormat GetStringFormatFromContentAllignment(ContentAlignment ca)
   140         {
   141             StringFormat format = new StringFormat();
   142             switch (ca)
   143             {
   144                 case ContentAlignment.TopCenter:
   145                     format.Alignment = StringAlignment.Near;
   146                     format.LineAlignment = StringAlignment.Center;
   147                     break;
   148                 case ContentAlignment.TopLeft:
   149                     format.Alignment = StringAlignment.Near;
   150                     format.LineAlignment = StringAlignment.Near;
   151                     break;
   152                 case ContentAlignment.TopRight:
   153                     format.Alignment = StringAlignment.Near;
   154                     format.LineAlignment = StringAlignment.Far;
   155                     break;
   156                 case ContentAlignment.MiddleCenter:
   157                     format.Alignment = StringAlignment.Center;
   158                     format.LineAlignment = StringAlignment.Center;
   159                     break;
   160                 case ContentAlignment.MiddleLeft:
   161                     format.Alignment = StringAlignment.Center;
   162                     format.LineAlignment = StringAlignment.Near;
   163                     break;
   164                 case ContentAlignment.MiddleRight:
   165                     format.Alignment = StringAlignment.Center;
   166                     format.LineAlignment = StringAlignment.Far;
   167                     break;
   168                 case ContentAlignment.BottomCenter:
   169                     format.Alignment = StringAlignment.Far;
   170                     format.LineAlignment = StringAlignment.Center;
   171                     break;
   172                 case ContentAlignment.BottomLeft:
   173                     format.Alignment = StringAlignment.Far;
   174                     format.LineAlignment = StringAlignment.Near;
   175                     break;
   176                 case ContentAlignment.BottomRight:
   177                     format.Alignment = StringAlignment.Far;
   178                     format.LineAlignment = StringAlignment.Far;
   179                     break;
   180             }
   181 
   182             format.FormatFlags |= StringFormatFlags.NoWrap;
   183             format.FormatFlags |= StringFormatFlags.NoClip;
   184             format.Trimming = StringTrimming.None;
   185 
   186             return format;
   187         }
   188 
   189         protected override void OnForeColorChanged(EventArgs e)
   190         {
   191             //Color has changed recreate our brush
   192             iBrush = new SolidBrush(ForeColor);
   193 
   194             base.OnForeColorChanged(e);
   195         }
   196 
   197 
   198         private void HandleTextSizeChange()
   199         {
   200             //Update text size according to text and font
   201             Graphics g = this.CreateGraphics();
   202             g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
   203             iTextSize = g.MeasureString(Text, Font);
   204             iSeparatorSize = g.MeasureString(Separator, Font);
   205             iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
   206 
   207             if (NeedToScroll())
   208             {
   209                 //Always align left when scrolling
   210                 iStringFormat.Alignment = StringAlignment.Near;
   211             }
   212         }
   213 
   214         protected override void OnTextChanged(EventArgs e)
   215         {
   216             HandleTextSizeChange();
   217 
   218             base.OnTextChanged(e);
   219         }
   220 
   221         protected override void OnFontChanged(EventArgs e)
   222         {
   223             HandleTextSizeChange();
   224 
   225             base.OnFontChanged(e);
   226         }
   227 
   228         protected override void OnTextAlignChanged(EventArgs e)
   229         {
   230             iStringFormat = GetStringFormatFromContentAllignment(TextAlign);
   231 
   232             base.OnTextAlignChanged(e);
   233 
   234         }
   235 
   236         protected override void OnPaint(PaintEventArgs e)
   237         {
   238             //Disable anti-aliasing
   239             e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
   240             if (NeedToScroll())
   241             {
   242                 //Draw the first one
   243                 e.Graphics.TranslateTransform(-(float)CurrentPosition, 0);
   244                 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
   245                 //Draw separator
   246                 e.Graphics.TranslateTransform(iTextSize.Width, 0);
   247                 e.Graphics.DrawString(Separator, Font, iBrush, ClientRectangle, iStringFormat);
   248                 //Draw the last one
   249                 e.Graphics.TranslateTransform(iSeparatorSize.Width, 0);
   250                 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
   251             }
   252             else
   253             {
   254                 e.Graphics.DrawString(Text, Font, iBrush, ClientRectangle, iStringFormat);
   255             }
   256 
   257 
   258 
   259             //DrawText is not working without anti-aliasing. See: stackoverflow.com/questions/8283631/graphics-drawstring-vs-textrenderer-drawtextwhich-can-deliver-better-quality
   260             //TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, BackColor, iTextFormatFlags);
   261 
   262             //base.OnPaint(e);
   263         }
   264 
   265         public bool NeedToScroll()
   266         {
   267             //if (Width < e.Graphics.MeasureString(Text, Font).Width)
   268             if (Width < iTextSize.Width)
   269             {
   270                 return true;
   271             }
   272             return false;
   273         }
   274 
   275         protected override void Dispose(bool disposing)
   276         {
   277             if (disposing)
   278             {
   279                 if (Timer != null)
   280                     Timer.Dispose();
   281             }
   282             Timer = null;
   283         }
   284     }
   285 }