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