Server/MainForm.cs
author sl
Sun, 18 Jan 2015 18:32:32 +0100
changeset 95 a4a02cc952a0
parent 94 fe939a729030
child 96 f3322473db40
permissions -rw-r--r--
Adding tray icon context menu.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading.Tasks;
     9 using System.Windows.Forms;
    10 using System.IO;
    11 using CodeProject.Dialog;
    12 using System.Drawing.Imaging;
    13 using System.ServiceModel;
    14 using System.Threading;
    15 using System.Diagnostics;
    16 using System.Deployment.Application;
    17 using System.Reflection;
    18 //
    19 using SharpDisplayClient;
    20 using SharpDisplay;
    21 
    22 namespace SharpDisplayManager
    23 {
    24     //Types declarations
    25     public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
    26     public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
    27     //Delegates are used for our thread safe method
    28     public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
    29     public delegate void RemoveClientDelegate(string aSessionId);
    30     public delegate void SetFieldDelegate(string SessionId, DataField aField);
    31     public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList<DataField> aFields);
    32     public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
    33     public delegate void SetClientNameDelegate(string aSessionId, string aName);
    34 
    35 
    36     /// <summary>
    37     /// Our Display manager main form
    38     /// </summary>
    39     public partial class MainForm : Form
    40     {
    41 
    42         DateTime LastTickTime;
    43         Display iDisplay;
    44         System.Drawing.Bitmap iBmp;
    45         bool iCreateBitmap; //Workaround render to bitmap issues when minimized
    46         ServiceHost iServiceHost;
    47         // Our collection of clients sorted by session id.
    48         public Dictionary<string, ClientData> iClients;
    49         // The name of the client which informations are currently displayed.
    50         public string iCurrentClientSessionId;
    51         ClientData iCurrentClientData;
    52         //
    53         public bool iClosing;
    54         //Function pointer for pixel color filtering
    55         ColorProcessingDelegate iColorFx;
    56         //Function pointer for pixel X coordinate intercept
    57         CoordinateTranslationDelegate iScreenX;
    58         //Function pointer for pixel Y coordinate intercept
    59         CoordinateTranslationDelegate iScreenY;
    60 
    61 		/// <summary>
    62 		/// Manage run when Windows startup option
    63 		/// </summary>
    64 		private StartupManager iStartupManager;
    65 
    66 		/// <summary>
    67 		/// System tray icon.
    68 		/// </summary>
    69 		private NotifyIconAdv iNotifyIcon;
    70 
    71         public MainForm()
    72         {
    73             iCurrentClientSessionId = "";
    74             iCurrentClientData = null;
    75             LastTickTime = DateTime.Now;
    76             iDisplay = new Display();
    77             iClients = new Dictionary<string, ClientData>();
    78 			iStartupManager = new StartupManager();
    79 			iNotifyIcon = new NotifyIconAdv();
    80 
    81             InitializeComponent();
    82             UpdateStatus();
    83             //We have a bug when drawing minimized and reusing our bitmap
    84             iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
    85             iCreateBitmap = false;
    86 
    87 			if (Properties.Settings.Default.StartMinimized)
    88 			{
    89 				WindowState = FormWindowState.Minimized;
    90 			}
    91 
    92         }
    93 
    94 		/// <summary>
    95 		/// 
    96 		/// </summary>
    97 		/// <param name="sender"></param>
    98 		/// <param name="e"></param>
    99         private void MainForm_Load(object sender, EventArgs e)
   100         {
   101 			if (ApplicationDeployment.IsNetworkDeployed)
   102 			{
   103 				this.Text += " - v" + ApplicationDeployment.CurrentDeployment.CurrentVersion;
   104 			}
   105 			else
   106 			{
   107 				this.Text += " - development";
   108 			}
   109 
   110             StartServer();
   111 
   112             if (Properties.Settings.Default.DisplayConnectOnStartup)
   113             {
   114                 OpenDisplayConnection();
   115             }
   116 
   117 			//Check if "run on Windows startup" is enabled
   118 			checkBoxAutoStart.Checked=iStartupManager.Startup;
   119 
   120 
   121 			//Setup notification icon
   122 			SetupTrayIcon();
   123 
   124 			// To make sure start up with minimize to tray works
   125 			if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
   126 			{
   127 				Visible = false;
   128 			}
   129         }
   130 
   131 		/// <summary>
   132 		/// 
   133 		/// </summary>
   134 		private void SetupTrayIcon()
   135 		{
   136 			iNotifyIcon.Icon = GetIcon("vfd.ico");
   137 			iNotifyIcon.Text = "Sharp Display Manager";
   138 			iNotifyIcon.Visible = true;
   139 
   140 			//Double click toggles visibility - typically brings up the application
   141 			iNotifyIcon.DoubleClick += delegate(object obj, EventArgs args)
   142 			{
   143 				SysTrayHideShow();
   144 			};
   145 
   146 			//Adding a context menu, useful to be able to exit the application
   147 			ContextMenu contextMenu = new ContextMenu();
   148 			//Context menu item to toggle visibility
   149 			MenuItem hideShowItem = new MenuItem("Hide/Show");
   150 			hideShowItem.Click += delegate(object obj, EventArgs args)
   151 			{
   152 				SysTrayHideShow();
   153 			};
   154 			contextMenu.MenuItems.Add(hideShowItem);
   155 
   156 			//Context menu item separator
   157 			contextMenu.MenuItems.Add(new MenuItem("-"));
   158 
   159 			//Context menu exit item
   160 			MenuItem exitItem = new MenuItem("Exit");
   161 			exitItem.Click += delegate(object obj, EventArgs args)
   162 			{
   163 				Application.Exit();
   164 			};
   165 			contextMenu.MenuItems.Add(exitItem);
   166 
   167 			iNotifyIcon.ContextMenu = contextMenu;
   168 		}
   169 
   170 		/// <summary>
   171 		/// Access icons from embedded resources.
   172 		/// </summary>
   173 		/// <param name="name"></param>
   174 		/// <returns></returns>
   175 		public static Icon GetIcon(string name)
   176 		{
   177 			name = "SharpDisplayManager.Resources." + name;
   178 
   179 			string[] names =
   180 			  Assembly.GetExecutingAssembly().GetManifestResourceNames();
   181 			for (int i = 0; i < names.Length; i++)
   182 			{
   183 				if (names[i].Replace('\\', '.') == name)
   184 				{
   185 					using (Stream stream = Assembly.GetExecutingAssembly().
   186 					  GetManifestResourceStream(names[i]))
   187 					{
   188 						return new Icon(stream);
   189 					}
   190 				}
   191 			}
   192 
   193 			return null;
   194 		}
   195 
   196 
   197         /// <summary>
   198         /// Set our current client.
   199         /// This will take care of applying our client layout and set data fields.
   200         /// </summary>
   201         /// <param name="aSessionId"></param>
   202         void SetCurrentClient(string aSessionId)
   203         {
   204             if (aSessionId == iCurrentClientSessionId)
   205             {
   206                 //Given client is already the current one.
   207                 //Don't bother changing anything then.
   208                 return;
   209             }
   210 
   211             //Set current client ID.
   212             iCurrentClientSessionId = aSessionId;
   213             //Fetch and set current client data.
   214             iCurrentClientData = iClients[aSessionId];
   215             //Apply layout and set data fields.
   216             UpdateTableLayoutPanel(iCurrentClientData);
   217         }
   218 
   219         private void buttonFont_Click(object sender, EventArgs e)
   220         {
   221             //fontDialog.ShowColor = true;
   222             //fontDialog.ShowApply = true;
   223             fontDialog.ShowEffects = true;
   224             MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
   225             fontDialog.Font = label.Font;
   226 
   227             fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
   228 
   229             //fontDialog.ShowHelp = true;
   230 
   231             //fontDlg.MaxSize = 40;
   232             //fontDlg.MinSize = 22;
   233 
   234             //fontDialog.Parent = this;
   235             //fontDialog.StartPosition = FormStartPosition.CenterParent;
   236 
   237             //DlgBox.ShowDialog(fontDialog);
   238 
   239             //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
   240             if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
   241             {
   242 
   243                 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
   244 
   245                 //MessageBox.Show("Ok");
   246                 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
   247                 {
   248                     ctrl.Font = fontDialog.Font;
   249                 }
   250                 cds.Font = fontDialog.Font;
   251                 Properties.Settings.Default.Save();
   252                 //
   253                 CheckFontHeight();
   254             }
   255         }
   256 
   257         /// <summary>
   258         ///
   259         /// </summary>
   260         void CheckFontHeight()
   261         {
   262             //Show font height and width
   263             labelFontHeight.Text = "Font height: " + cds.Font.Height;
   264             float charWidth = IsFixedWidth(cds.Font);
   265             if (charWidth == 0.0f)
   266             {
   267                 labelFontWidth.Visible = false;
   268             }
   269             else
   270             {
   271                 labelFontWidth.Visible = true;
   272                 labelFontWidth.Text = "Font width: " + charWidth;
   273             }
   274 
   275             MarqueeLabel label = null;
   276             //Get the first label control we can find
   277             foreach (Control ctrl in tableLayoutPanel.Controls)
   278             {
   279                 if (ctrl is MarqueeLabel)
   280                 {
   281                     label = (MarqueeLabel)ctrl;
   282                     break;
   283                 }
   284             }
   285 
   286             //Now check font height and show a warning if needed.
   287             if (label != null && label.Font.Height > label.Height)
   288             {
   289                 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
   290                 labelWarning.Visible = true;
   291             }
   292             else
   293             {
   294                 labelWarning.Visible = false;
   295             }
   296 
   297         }
   298 
   299         private void buttonCapture_Click(object sender, EventArgs e)
   300         {
   301             System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
   302             tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
   303             //Bitmap bmpToSave = new Bitmap(bmp);
   304             bmp.Save("D:\\capture.png");
   305 
   306             ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
   307 
   308             /*
   309             string outputFileName = "d:\\capture.png";
   310             using (MemoryStream memory = new MemoryStream())
   311             {
   312                 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
   313                 {
   314                     bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
   315                     byte[] bytes = memory.ToArray();
   316                     fs.Write(bytes, 0, bytes.Length);
   317                 }
   318             }
   319              */
   320 
   321         }
   322 
   323         private void CheckForRequestResults()
   324         {
   325             if (iDisplay.IsRequestPending())
   326             {
   327                 switch (iDisplay.AttemptRequestCompletion())
   328                 {
   329                     case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
   330                         toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
   331                         //Issue next request then
   332                         iDisplay.RequestPowerSupplyStatus();
   333                         break;
   334 
   335                     case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
   336                         if (iDisplay.PowerSupplyStatus())
   337                         {
   338                             toolStripStatusLabelPower.Text = "ON";
   339                         }
   340                         else
   341                         {
   342                             toolStripStatusLabelPower.Text = "OFF";
   343                         }
   344                         //Issue next request then
   345                         iDisplay.RequestDeviceId();
   346                         break;
   347 
   348                     case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
   349                         toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
   350                         //No more request to issue
   351                         break;
   352                 }
   353             }
   354         }
   355 
   356         public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
   357         {
   358             if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
   359             {
   360                 return 0xFFFFFFFF;
   361             }
   362             return 0x00000000;
   363         }
   364 
   365         public static uint ColorUntouched(int aX, int aY, uint aPixel)
   366         {
   367             return aPixel;
   368         }
   369 
   370         public static uint ColorInversed(int aX, int aY, uint aPixel)
   371         {
   372             return ~aPixel;
   373         }
   374 
   375         public static uint ColorChessboard(int aX, int aY, uint aPixel)
   376         {
   377             if ((aX % 2 == 0) && (aY % 2 == 0))
   378             {
   379                 return ~aPixel;
   380             }
   381             else if ((aX % 2 != 0) && (aY % 2 != 0))
   382             {
   383                 return ~aPixel;
   384             }
   385             return 0x00000000;
   386         }
   387 
   388 
   389         public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
   390         {
   391             return aBmp.Width - aX - 1;
   392         }
   393 
   394         public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
   395         {
   396             return iBmp.Height - aY - 1;
   397         }
   398 
   399         public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
   400         {
   401             return aX;
   402         }
   403 
   404         public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
   405         {
   406             return aY;
   407         }
   408 
   409         /// <summary>
   410         /// Select proper pixel delegates according to our current settings.
   411         /// </summary>
   412         private void SetupPixelDelegates()
   413         {
   414             //Select our pixel processing routine
   415             if (cds.InverseColors)
   416             {
   417                 //iColorFx = ColorChessboard;
   418                 iColorFx = ColorInversed;
   419             }
   420             else
   421             {
   422                 iColorFx = ColorWhiteIsOn;
   423             }
   424 
   425             //Select proper coordinate translation functions
   426             //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
   427             if (cds.ReverseScreen)
   428             {
   429                 iScreenX = ScreenReversedX;
   430                 iScreenY = ScreenReversedY;
   431             }
   432             else
   433             {
   434                 iScreenX = ScreenX;
   435                 iScreenY = ScreenY;
   436             }
   437 
   438         }
   439 
   440         //This is our timer tick responsible to perform our render
   441         private void timer_Tick(object sender, EventArgs e)
   442         {
   443             //Update our animations
   444             DateTime NewTickTime = DateTime.Now;
   445 
   446             //Update animation for all our marquees
   447             foreach (Control ctrl in tableLayoutPanel.Controls)
   448             {
   449                 if (ctrl is MarqueeLabel)
   450                 {
   451                     ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
   452                 }
   453             }
   454 
   455 
   456             //Update our display
   457             if (iDisplay.IsOpen())
   458             {
   459                 CheckForRequestResults();
   460 
   461                 //Draw to bitmap
   462                 if (iCreateBitmap)
   463                 {
   464                     iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   465                 }
   466                 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
   467                 //iBmp.Save("D:\\capture.png");
   468 
   469                 //Send it to our display
   470                 for (int i = 0; i < iBmp.Width; i++)
   471                 {
   472                     for (int j = 0; j < iBmp.Height; j++)
   473                     {
   474                         unchecked
   475                         {
   476                             //Get our processed pixel coordinates
   477                             int x = iScreenX(iBmp, i);
   478                             int y = iScreenY(iBmp, j);
   479                             //Get pixel color
   480                             uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
   481                             //Apply color effects
   482                             color = iColorFx(x,y,color);
   483                             //Now set our pixel
   484                             iDisplay.SetPixel(x, y, color);
   485                         }
   486                     }
   487                 }
   488 
   489                 iDisplay.SwapBuffers();
   490 
   491             }
   492 
   493             //Compute instant FPS
   494             toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
   495 
   496             LastTickTime = NewTickTime;
   497 
   498         }
   499 
   500         private void OpenDisplayConnection()
   501         {
   502             CloseDisplayConnection();
   503 
   504             if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
   505             {
   506                 UpdateStatus();
   507                 iDisplay.RequestFirmwareRevision();
   508             }
   509             else
   510             {
   511                 UpdateStatus();
   512                 toolStripStatusLabelConnect.Text = "Connection error";
   513             }
   514         }
   515 
   516         private void CloseDisplayConnection()
   517         {
   518             iDisplay.Close();
   519             UpdateStatus();
   520         }
   521 
   522         private void buttonOpen_Click(object sender, EventArgs e)
   523         {
   524             OpenDisplayConnection();
   525         }
   526 
   527         private void buttonClose_Click(object sender, EventArgs e)
   528         {
   529             CloseDisplayConnection();
   530         }
   531 
   532         private void buttonClear_Click(object sender, EventArgs e)
   533         {
   534             iDisplay.Clear();
   535             iDisplay.SwapBuffers();
   536         }
   537 
   538         private void buttonFill_Click(object sender, EventArgs e)
   539         {
   540             iDisplay.Fill();
   541             iDisplay.SwapBuffers();
   542         }
   543 
   544         private void trackBarBrightness_Scroll(object sender, EventArgs e)
   545         {
   546             cds.Brightness = trackBarBrightness.Value;
   547             Properties.Settings.Default.Save();
   548             iDisplay.SetBrightness(trackBarBrightness.Value);
   549 
   550         }
   551 
   552 
   553         /// <summary>
   554         /// CDS stands for Current Display Settings
   555         /// </summary>
   556         private DisplaySettings cds
   557         {
   558             get
   559             {
   560                 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
   561                 if (settings == null)
   562                 {
   563                     settings = new DisplaysSettings();
   564                     settings.Init();
   565                     Properties.Settings.Default.DisplaysSettings = settings;
   566                 }
   567 
   568                 //Make sure all our settings have been created
   569                 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
   570                 {
   571                     settings.Displays.Add(new DisplaySettings());
   572                 }
   573 
   574                 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
   575                 return displaySettings;
   576             }
   577         }
   578 
   579         /// <summary>
   580         /// Check if the given font has a fixed character pitch.
   581         /// </summary>
   582         /// <param name="ft"></param>
   583         /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
   584         public float IsFixedWidth(Font ft)
   585         {
   586             Graphics g = CreateGraphics();
   587             char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
   588             float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
   589 
   590             bool fixedWidth = true;
   591 
   592             foreach (char c in charSizes)
   593                 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
   594                     fixedWidth = false;
   595 
   596             if (fixedWidth)
   597             {
   598                 return charWidth;
   599             }
   600 
   601             return 0.0f;
   602         }
   603 
   604         private void UpdateStatus()
   605         {
   606             //Synchronize UI with settings
   607             //Load settings
   608             checkBoxShowBorders.Checked = cds.ShowBorders;
   609             tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   610 
   611             //Set the proper font to each of our labels
   612             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
   613             {
   614                 ctrl.Font = cds.Font;
   615             }
   616 
   617             CheckFontHeight();
   618             checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
   619 			checkBoxMinimizeToTray.Checked = Properties.Settings.Default.MinimizeToTray;
   620 			checkBoxStartMinimized.Checked = Properties.Settings.Default.StartMinimized;
   621             checkBoxReverseScreen.Checked = cds.ReverseScreen;
   622             checkBoxInverseColors.Checked = cds.InverseColors;
   623             comboBoxDisplayType.SelectedIndex = cds.DisplayType;
   624             timer.Interval = cds.TimerInterval;
   625             maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
   626             //
   627             SetupPixelDelegates();
   628 
   629             if (iDisplay.IsOpen())
   630             {
   631                 //Only setup brightness if display is open
   632                 trackBarBrightness.Minimum = iDisplay.MinBrightness();
   633                 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
   634                 trackBarBrightness.Value = cds.Brightness;
   635                 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
   636                 trackBarBrightness.SmallChange = 1;
   637                 iDisplay.SetBrightness(cds.Brightness);
   638                 //
   639                 buttonFill.Enabled = true;
   640                 buttonClear.Enabled = true;
   641                 buttonOpen.Enabled = false;
   642                 buttonClose.Enabled = true;
   643                 trackBarBrightness.Enabled = true;
   644                 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
   645                 //+ " - " + iDisplay.SerialNumber();
   646 
   647                 if (iDisplay.SupportPowerOnOff())
   648                 {
   649                     buttonPowerOn.Enabled = true;
   650                     buttonPowerOff.Enabled = true;
   651                 }
   652                 else
   653                 {
   654                     buttonPowerOn.Enabled = false;
   655                     buttonPowerOff.Enabled = false;
   656                 }
   657 
   658                 if (iDisplay.SupportClock())
   659                 {
   660                     buttonShowClock.Enabled = true;
   661                     buttonHideClock.Enabled = true;
   662                 }
   663                 else
   664                 {
   665                     buttonShowClock.Enabled = false;
   666                     buttonHideClock.Enabled = false;
   667                 }
   668             }
   669             else
   670             {
   671                 buttonFill.Enabled = false;
   672                 buttonClear.Enabled = false;
   673                 buttonOpen.Enabled = true;
   674                 buttonClose.Enabled = false;
   675                 trackBarBrightness.Enabled = false;
   676                 buttonPowerOn.Enabled = false;
   677                 buttonPowerOff.Enabled = false;
   678                 buttonShowClock.Enabled = false;
   679                 buttonHideClock.Enabled = false;
   680                 toolStripStatusLabelConnect.Text = "Disconnected";
   681                 toolStripStatusLabelPower.Text = "N/A";
   682             }
   683         }
   684 
   685 
   686 
   687         private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
   688         {
   689             //Save our show borders setting
   690             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   691             cds.ShowBorders = checkBoxShowBorders.Checked;
   692             Properties.Settings.Default.Save();
   693             CheckFontHeight();
   694         }
   695 
   696         private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
   697         {
   698             //Save our connect on startup setting
   699             Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
   700             Properties.Settings.Default.Save();
   701         }
   702 
   703 		private void checkBoxMinimizeToTray_CheckedChanged(object sender, EventArgs e)
   704 		{
   705 			//Save our "Minimize to tray" setting
   706 			Properties.Settings.Default.MinimizeToTray = checkBoxMinimizeToTray.Checked;
   707 			Properties.Settings.Default.Save();
   708 
   709 		}
   710 
   711 		private void checkBoxStartMinimized_CheckedChanged(object sender, EventArgs e)
   712 		{
   713 			//Save our "Start minimized" setting
   714 			Properties.Settings.Default.StartMinimized = checkBoxStartMinimized.Checked;
   715 			Properties.Settings.Default.Save();
   716 		}
   717 
   718 		private void checkBoxAutoStart_CheckedChanged(object sender, EventArgs e)
   719 		{
   720 			iStartupManager.Startup = checkBoxAutoStart.Checked;
   721 		}
   722 
   723 
   724         private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
   725         {
   726             //Save our reverse screen setting
   727             cds.ReverseScreen = checkBoxReverseScreen.Checked;
   728             Properties.Settings.Default.Save();
   729             SetupPixelDelegates();
   730         }
   731 
   732         private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
   733         {
   734             //Save our inverse colors setting
   735             cds.InverseColors = checkBoxInverseColors.Checked;
   736             Properties.Settings.Default.Save();
   737             SetupPixelDelegates();
   738         }
   739 
   740         private void MainForm_Resize(object sender, EventArgs e)
   741         {
   742             if (WindowState == FormWindowState.Minimized)
   743             {
   744                 // Do some stuff
   745                 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   746                 iCreateBitmap = true;
   747             }
   748         }
   749 
   750         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   751         {
   752             StopServer();
   753             e.Cancel = iClosing;
   754         }
   755 
   756         public void StartServer()
   757         {
   758             iServiceHost = new ServiceHost
   759                 (
   760                     typeof(Session),
   761                     new Uri[] { new Uri("net.tcp://localhost:8001/") }
   762                 );
   763 
   764             iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
   765             iServiceHost.Open();
   766         }
   767 
   768         public void StopServer()
   769         {
   770             if (iClients.Count > 0 && !iClosing)
   771             {
   772                 //Tell our clients
   773                 iClosing = true;
   774                 BroadcastCloseEvent();
   775             }
   776             else if (iClosing)
   777             {
   778                 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
   779                 {
   780                     iClosing = false; //We make sure we force close if asked twice
   781                 }
   782             }
   783             else
   784             {
   785                 //We removed that as it often lags for some reason
   786                 //iServiceHost.Close();
   787             }
   788         }
   789 
   790         public void BroadcastCloseEvent()
   791         {
   792             Trace.TraceInformation("BroadcastCloseEvent - start");
   793 
   794             var inactiveClients = new List<string>();
   795             foreach (var client in iClients)
   796             {
   797                 //if (client.Key != eventData.ClientName)
   798                 {
   799                     try
   800                     {
   801                         Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
   802                         client.Value.Callback.OnCloseOrder(/*eventData*/);
   803                     }
   804                     catch (Exception ex)
   805                     {
   806                         inactiveClients.Add(client.Key);
   807                     }
   808                 }
   809             }
   810 
   811             if (inactiveClients.Count > 0)
   812             {
   813                 foreach (var client in inactiveClients)
   814                 {
   815                     iClients.Remove(client);
   816                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
   817                 }
   818             }
   819         }
   820 
   821         private void buttonStartClient_Click(object sender, EventArgs e)
   822         {
   823             Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
   824             clientThread.Start();
   825             BringToFront();
   826         }
   827 
   828         private void buttonSuspend_Click(object sender, EventArgs e)
   829         {
   830             LastTickTime = DateTime.Now; //Reset timer to prevent jump
   831             timer.Enabled = !timer.Enabled;
   832             if (!timer.Enabled)
   833             {
   834                 buttonSuspend.Text = "Run";
   835             }
   836             else
   837             {
   838                 buttonSuspend.Text = "Pause";
   839             }
   840         }
   841 
   842         private void buttonCloseClients_Click(object sender, EventArgs e)
   843         {
   844             BroadcastCloseEvent();
   845         }
   846 
   847         private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
   848         {
   849 
   850         }
   851 
   852 
   853         /// <summary>
   854         ///
   855         /// </summary>
   856         /// <param name="aSessionId"></param>
   857         /// <param name="aCallback"></param>
   858         public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
   859         {
   860             if (this.InvokeRequired)
   861             {
   862                 //Not in the proper thread, invoke ourselves
   863                 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
   864                 this.Invoke(d, new object[] { aSessionId, aCallback });
   865             }
   866             else
   867             {
   868                 //We are in the proper thread
   869                 //Add this session to our collection of clients
   870                 ClientData newClient = new ClientData(aSessionId, aCallback);
   871                 Program.iMainForm.iClients.Add(aSessionId, newClient);
   872                 //Add this session to our UI
   873                 UpdateClientTreeViewNode(newClient);
   874             }
   875         }
   876 
   877         /// <summary>
   878         ///
   879         /// </summary>
   880         /// <param name="aSessionId"></param>
   881         public void RemoveClientThreadSafe(string aSessionId)
   882         {
   883             if (this.InvokeRequired)
   884             {
   885                 //Not in the proper thread, invoke ourselves
   886                 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
   887                 this.Invoke(d, new object[] { aSessionId });
   888             }
   889             else
   890             {
   891                 //We are in the proper thread
   892                 //Remove this session from both client collection and UI tree view
   893                 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
   894                 {
   895                     Program.iMainForm.iClients.Remove(aSessionId);
   896                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
   897                 }
   898 
   899                 if (iClosing && iClients.Count == 0)
   900                 {
   901                     //We were closing our form
   902                     //All clients are now closed
   903                     //Just resume our close operation
   904                     iClosing = false;
   905                     Close();
   906                 }
   907             }
   908         }
   909 
   910         /// <summary>
   911         ///
   912         /// </summary>
   913         /// <param name="aSessionId"></param>
   914         /// <param name="aLayout"></param>
   915         public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
   916         {
   917             if (this.InvokeRequired)
   918             {
   919                 //Not in the proper thread, invoke ourselves
   920                 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
   921                 this.Invoke(d, new object[] { aSessionId, aLayout });
   922             }
   923             else
   924             {
   925                 ClientData client = iClients[aSessionId];
   926                 if (client != null)
   927                 {
   928                     client.Layout = aLayout;
   929                     UpdateTableLayoutPanel(client);
   930                     //
   931                     UpdateClientTreeViewNode(client);
   932                 }
   933             }
   934         }
   935 
   936         /// <summary>
   937         ///
   938         /// </summary>
   939         /// <param name="aSessionId"></param>
   940         /// <param name="aField"></param>
   941         public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
   942         {
   943             if (this.InvokeRequired)
   944             {
   945                 //Not in the proper thread, invoke ourselves
   946                 SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
   947                 this.Invoke(d, new object[] { aSessionId, aField });
   948             }
   949             else
   950             {
   951                 //We are in the proper thread
   952                 //Call the non-thread-safe variant
   953                 SetClientField(aSessionId, aField);
   954             }
   955         }
   956 
   957         /// <summary>
   958         ///
   959         /// </summary>
   960         /// <param name="aSessionId"></param>
   961         /// <param name="aField"></param>
   962         private void SetClientField(string aSessionId, DataField aField)
   963         {
   964             SetCurrentClient(aSessionId);
   965             ClientData client = iClients[aSessionId];
   966             if (client != null)
   967             {
   968                 bool somethingChanged = false;
   969 
   970                 //Make sure all our fields are in place
   971                 while (client.Fields.Count < (aField.Index + 1))
   972                 {
   973                     //Add a text field with proper index
   974                     client.Fields.Add(new DataField(client.Fields.Count));
   975                     somethingChanged = true;
   976                 }
   977 
   978                 if (client.Fields[aField.Index].IsSameLayout(aField))
   979                 {
   980                     //Same layout just update our field
   981                     client.Fields[aField.Index] = aField;
   982                     //
   983                     if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
   984                     {
   985                         //Text field control already in place, just change the text
   986                         MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
   987                         somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
   988                         label.Text = aField.Text;
   989                         label.TextAlign = aField.Alignment;
   990                     }
   991                     else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
   992                     {
   993                         somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
   994                         //Bitmap field control already in place just change the bitmap
   995                         PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
   996                         pictureBox.Image = aField.Bitmap;
   997                     }
   998                     else
   999                     {
  1000                         somethingChanged = true;
  1001                         //The requested control in our layout it not of the correct type
  1002                         //Wrong control type, re-create them all
  1003                         UpdateTableLayoutPanel(iCurrentClientData);
  1004                     }
  1005                 }
  1006                 else
  1007                 {
  1008                     somethingChanged = true;
  1009                     //Different layout, need to rebuild it
  1010                     client.Fields[aField.Index] = aField;
  1011                     UpdateTableLayoutPanel(iCurrentClientData);
  1012                 }
  1013 
  1014                 //
  1015                 if (somethingChanged)
  1016                 {
  1017                     UpdateClientTreeViewNode(client);
  1018                 }
  1019             }
  1020         }
  1021 
  1022         /// <summary>
  1023         ///
  1024         /// </summary>
  1025         /// <param name="aTexts"></param>
  1026         public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
  1027         {
  1028             if (this.InvokeRequired)
  1029             {
  1030                 //Not in the proper thread, invoke ourselves
  1031                 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
  1032                 this.Invoke(d, new object[] { aSessionId, aFields });
  1033             }
  1034             else
  1035             {
  1036                 //Put each our text fields in a label control
  1037                 foreach (DataField field in aFields)
  1038                 {
  1039                     SetClientField(aSessionId, field);
  1040                 }
  1041             }
  1042         }
  1043 
  1044         /// <summary>
  1045         ///
  1046         /// </summary>
  1047         /// <param name="aSessionId"></param>
  1048         /// <param name="aName"></param>
  1049         public void SetClientNameThreadSafe(string aSessionId, string aName)
  1050         {
  1051             if (this.InvokeRequired)
  1052             {
  1053                 //Not in the proper thread, invoke ourselves
  1054                 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
  1055                 this.Invoke(d, new object[] { aSessionId, aName });
  1056             }
  1057             else
  1058             {
  1059                 //We are in the proper thread
  1060                 //Get our client
  1061                 ClientData client = iClients[aSessionId];
  1062                 if (client != null)
  1063                 {
  1064                     //Set its name
  1065                     client.Name = aName;
  1066                     //Update our tree-view
  1067                     UpdateClientTreeViewNode(client);
  1068                 }
  1069             }
  1070         }
  1071 
  1072         /// <summary>
  1073         ///
  1074         /// </summary>
  1075         /// <param name="aClient"></param>
  1076         private void UpdateClientTreeViewNode(ClientData aClient)
  1077         {
  1078             if (aClient == null)
  1079             {
  1080                 return;
  1081             }
  1082 
  1083             TreeNode node = null;
  1084             //Check that our client node already exists
  1085             //Get our client root node using its key which is our session ID
  1086             TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
  1087             if (nodes.Count()>0)
  1088             {
  1089                 //We already have a node for that client
  1090                 node = nodes[0];
  1091                 //Clear children as we are going to recreate them below
  1092                 node.Nodes.Clear();
  1093             }
  1094             else
  1095             {
  1096                 //Client node does not exists create a new one
  1097                 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
  1098                 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
  1099             }
  1100 
  1101             if (node != null)
  1102             {
  1103                 //Change its name
  1104                 if (aClient.Name != "")
  1105                 {
  1106                     //We have a name, us it as text for our root node
  1107                     node.Text = aClient.Name;
  1108                     //Add a child with SessionId
  1109                     node.Nodes.Add(new TreeNode(aClient.SessionId));
  1110                 }
  1111                 else
  1112                 {
  1113                     //No name, use session ID instead
  1114                     node.Text = aClient.SessionId;
  1115                 }
  1116 
  1117                 if (aClient.Fields.Count > 0)
  1118                 {
  1119                     //Create root node for our texts
  1120                     TreeNode textsRoot = new TreeNode("Fields");
  1121                     node.Nodes.Add(textsRoot);
  1122                     //For each text add a new entry
  1123                     foreach (DataField field in aClient.Fields)
  1124                     {
  1125                         if (!field.IsBitmap)
  1126                         {
  1127                             DataField textField = (DataField)field;
  1128                             textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
  1129                         }
  1130                         else
  1131                         {
  1132                             textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
  1133                         }
  1134                     }
  1135                 }
  1136 
  1137                 node.ExpandAll();
  1138             }
  1139         }
  1140 
  1141         private void buttonAddRow_Click(object sender, EventArgs e)
  1142         {
  1143             if (tableLayoutPanel.RowCount < 6)
  1144             {
  1145                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
  1146             }
  1147         }
  1148 
  1149         private void buttonRemoveRow_Click(object sender, EventArgs e)
  1150         {
  1151             if (tableLayoutPanel.RowCount > 1)
  1152             {
  1153                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
  1154             }
  1155 
  1156             UpdateTableLayoutRowStyles();
  1157         }
  1158 
  1159         private void buttonAddColumn_Click(object sender, EventArgs e)
  1160         {
  1161             if (tableLayoutPanel.ColumnCount < 8)
  1162             {
  1163                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
  1164             }
  1165         }
  1166 
  1167         private void buttonRemoveColumn_Click(object sender, EventArgs e)
  1168         {
  1169             if (tableLayoutPanel.ColumnCount > 1)
  1170             {
  1171                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
  1172             }
  1173         }
  1174 
  1175 
  1176         /// <summary>
  1177         /// Update our table layout row styles to make sure each rows have similar height
  1178         /// </summary>
  1179         private void UpdateTableLayoutRowStyles()
  1180         {
  1181             foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
  1182             {
  1183                 rowStyle.SizeType = SizeType.Percent;
  1184                 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
  1185             }
  1186         }
  1187 
  1188         /// DEPRECATED
  1189         /// <summary>
  1190         /// Empty and recreate our table layout with the given number of columns and rows.
  1191         /// Sizes of rows and columns are uniform.
  1192         /// </summary>
  1193         /// <param name="aColumn"></param>
  1194         /// <param name="aRow"></param>
  1195         private void UpdateTableLayoutPanel(int aColumn, int aRow)
  1196         {
  1197             tableLayoutPanel.Controls.Clear();
  1198             tableLayoutPanel.RowStyles.Clear();
  1199             tableLayoutPanel.ColumnStyles.Clear();
  1200             tableLayoutPanel.RowCount = 0;
  1201             tableLayoutPanel.ColumnCount = 0;
  1202 
  1203             while (tableLayoutPanel.RowCount < aRow)
  1204             {
  1205                 tableLayoutPanel.RowCount++;
  1206             }
  1207 
  1208             while (tableLayoutPanel.ColumnCount < aColumn)
  1209             {
  1210                 tableLayoutPanel.ColumnCount++;
  1211             }
  1212 
  1213             for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
  1214             {
  1215                 //Create our column styles
  1216                 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
  1217 
  1218                 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
  1219                 {
  1220                     if (i == 0)
  1221                     {
  1222                         //Create our row styles
  1223                         this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
  1224                     }
  1225 
  1226                     MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
  1227                     control.AutoEllipsis = true;
  1228                     control.AutoSize = true;
  1229                     control.BackColor = System.Drawing.Color.Transparent;
  1230                     control.Dock = System.Windows.Forms.DockStyle.Fill;
  1231                     control.Location = new System.Drawing.Point(1, 1);
  1232                     control.Margin = new System.Windows.Forms.Padding(0);
  1233                     control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
  1234                     control.OwnTimer = false;
  1235                     control.PixelsPerSecond = 64;
  1236                     control.Separator = "|";
  1237                     //control.Size = new System.Drawing.Size(254, 30);
  1238                     //control.TabIndex = 2;
  1239                     control.Font = cds.Font;
  1240                     control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
  1241                     control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  1242                     control.UseCompatibleTextRendering = true;
  1243                     //
  1244                     tableLayoutPanel.Controls.Add(control, i, j);
  1245                 }
  1246             }
  1247 
  1248             CheckFontHeight();
  1249         }
  1250 
  1251 
  1252         /// <summary>
  1253         /// Update our display table layout.
  1254         /// </summary>
  1255         /// <param name="aLayout"></param>
  1256         private void UpdateTableLayoutPanel(ClientData aClient)
  1257         {
  1258             TableLayout layout = aClient.Layout;
  1259             int fieldCount = 0;
  1260 
  1261             tableLayoutPanel.Controls.Clear();
  1262             tableLayoutPanel.RowStyles.Clear();
  1263             tableLayoutPanel.ColumnStyles.Clear();
  1264             tableLayoutPanel.RowCount = 0;
  1265             tableLayoutPanel.ColumnCount = 0;
  1266 
  1267             while (tableLayoutPanel.RowCount < layout.Rows.Count)
  1268             {
  1269                 tableLayoutPanel.RowCount++;
  1270             }
  1271 
  1272             while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
  1273             {
  1274                 tableLayoutPanel.ColumnCount++;
  1275             }
  1276 
  1277             for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
  1278             {
  1279                 //Create our column styles
  1280                 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
  1281 
  1282                 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
  1283                 {
  1284                     if (i == 0)
  1285                     {
  1286                         //Create our row styles
  1287                         this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
  1288                     }
  1289 
  1290                     //Check if we already have a control
  1291                     Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
  1292                     if (existingControl!=null)
  1293                     {
  1294                         //We already have a control in that cell as a results of row/col spanning
  1295                         //Move on to next cell then
  1296                         continue;
  1297                     }
  1298 
  1299                     fieldCount++;
  1300 
  1301                     //Check if a client field already exists for that cell
  1302                     if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
  1303                     {
  1304                         //No client field specified, create a text field by default
  1305                         aClient.Fields.Add(new DataField(aClient.Fields.Count));
  1306                     }
  1307 
  1308                     //Create a control corresponding to the field specified for that cell
  1309                     DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
  1310                     Control control = CreateControlForDataField(field);
  1311 
  1312                     //Add newly created control to our table layout at the specified row and column
  1313                     tableLayoutPanel.Controls.Add(control, i, j);
  1314                     //Make sure we specify row and column span for that new control
  1315                     tableLayoutPanel.SetRowSpan(control,field.RowSpan);
  1316                     tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
  1317                 }
  1318             }
  1319 
  1320             //
  1321             while (aClient.Fields.Count > fieldCount)
  1322             {
  1323                 //We have too much fields for this layout
  1324                 //Just discard them until we get there
  1325                 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
  1326             }
  1327 
  1328             CheckFontHeight();
  1329         }
  1330 
  1331         /// <summary>
  1332         /// Check our type of data field and create corresponding control
  1333         /// </summary>
  1334         /// <param name="aField"></param>
  1335         private Control CreateControlForDataField(DataField aField)
  1336         {
  1337             Control control=null;
  1338             if (!aField.IsBitmap)
  1339             {
  1340                 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
  1341                 label.AutoEllipsis = true;
  1342                 label.AutoSize = true;
  1343                 label.BackColor = System.Drawing.Color.Transparent;
  1344                 label.Dock = System.Windows.Forms.DockStyle.Fill;
  1345                 label.Location = new System.Drawing.Point(1, 1);
  1346                 label.Margin = new System.Windows.Forms.Padding(0);
  1347                 label.Name = "marqueeLabel" + aField.Index;
  1348                 label.OwnTimer = false;
  1349                 label.PixelsPerSecond = 64;
  1350                 label.Separator = "|";
  1351                 //control.Size = new System.Drawing.Size(254, 30);
  1352                 //control.TabIndex = 2;
  1353                 label.Font = cds.Font;
  1354 
  1355                 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  1356                 label.UseCompatibleTextRendering = true;
  1357                 label.Text = aField.Text;
  1358                 //
  1359                 control = label;
  1360             }
  1361             else
  1362             {
  1363                 //Create picture box
  1364                 PictureBox picture = new PictureBox();
  1365                 picture.AutoSize = true;
  1366                 picture.BackColor = System.Drawing.Color.Transparent;
  1367                 picture.Dock = System.Windows.Forms.DockStyle.Fill;
  1368                 picture.Location = new System.Drawing.Point(1, 1);
  1369                 picture.Margin = new System.Windows.Forms.Padding(0);
  1370                 picture.Name = "pictureBox" + aField;
  1371                 //Set our image
  1372                 picture.Image = aField.Bitmap;
  1373                 //
  1374                 control = picture;
  1375             }
  1376 
  1377             return control;
  1378         }
  1379 
  1380 
  1381         private void buttonAlignLeft_Click(object sender, EventArgs e)
  1382         {
  1383             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1384             {
  1385                 ctrl.TextAlign = ContentAlignment.MiddleLeft;
  1386             }
  1387         }
  1388 
  1389         private void buttonAlignCenter_Click(object sender, EventArgs e)
  1390         {
  1391             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1392             {
  1393                 ctrl.TextAlign = ContentAlignment.MiddleCenter;
  1394             }
  1395         }
  1396 
  1397         private void buttonAlignRight_Click(object sender, EventArgs e)
  1398         {
  1399             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1400             {
  1401                 ctrl.TextAlign = ContentAlignment.MiddleRight;
  1402             }
  1403         }
  1404 
  1405         private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
  1406         {
  1407             Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
  1408             cds.DisplayType = comboBoxDisplayType.SelectedIndex;
  1409             Properties.Settings.Default.Save();
  1410             if (iDisplay.IsOpen())
  1411             {
  1412                 OpenDisplayConnection();
  1413             }
  1414             else
  1415             {
  1416                 UpdateStatus();
  1417             }
  1418         }
  1419 
  1420 
  1421         private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
  1422         {
  1423             if (maskedTextBoxTimerInterval.Text != "")
  1424             {
  1425                 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
  1426 
  1427                 if (interval > 0)
  1428                 {
  1429                     timer.Interval = interval;
  1430                     cds.TimerInterval = timer.Interval;
  1431                     Properties.Settings.Default.Save();
  1432                 }
  1433             }
  1434         }
  1435 
  1436         private void buttonPowerOn_Click(object sender, EventArgs e)
  1437         {
  1438             iDisplay.PowerOn();
  1439         }
  1440 
  1441         private void buttonPowerOff_Click(object sender, EventArgs e)
  1442         {
  1443             iDisplay.PowerOff();
  1444         }
  1445 
  1446         private void buttonShowClock_Click(object sender, EventArgs e)
  1447         {
  1448             iDisplay.ShowClock();
  1449         }
  1450 
  1451         private void buttonHideClock_Click(object sender, EventArgs e)
  1452         {
  1453             iDisplay.HideClock();
  1454         }
  1455 
  1456         private void buttonUpdate_Click(object sender, EventArgs e)
  1457         {
  1458             InstallUpdateSyncWithInfo();
  1459         }
  1460 
  1461 
  1462         private void InstallUpdateSyncWithInfo()
  1463         {
  1464             UpdateCheckInfo info = null;
  1465 
  1466             if (ApplicationDeployment.IsNetworkDeployed)
  1467             {
  1468                 ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
  1469 
  1470                 try
  1471                 {
  1472                     info = ad.CheckForDetailedUpdate();
  1473 
  1474                 }
  1475                 catch (DeploymentDownloadException dde)
  1476                 {
  1477                     MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
  1478                     return;
  1479                 }
  1480                 catch (InvalidDeploymentException ide)
  1481                 {
  1482                     MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
  1483                     return;
  1484                 }
  1485                 catch (InvalidOperationException ioe)
  1486                 {
  1487                     MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
  1488                     return;
  1489                 }
  1490 
  1491 				if (info.UpdateAvailable)
  1492 				{
  1493 					Boolean doUpdate = true;
  1494 
  1495 					if (!info.IsUpdateRequired)
  1496 					{
  1497 						DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
  1498 						if (!(DialogResult.OK == dr))
  1499 						{
  1500 							doUpdate = false;
  1501 						}
  1502 					}
  1503 					else
  1504 					{
  1505 						// Display a message that the app MUST reboot. Display the minimum required version.
  1506 						MessageBox.Show("This application has detected a mandatory update from your current " +
  1507 							"version to version " + info.MinimumRequiredVersion.ToString() +
  1508 							". The application will now install the update and restart.",
  1509 							"Update Available", MessageBoxButtons.OK,
  1510 							MessageBoxIcon.Information);
  1511 					}
  1512 
  1513 					if (doUpdate)
  1514 					{
  1515 						try
  1516 						{
  1517 							ad.Update();
  1518 							MessageBox.Show("The application has been upgraded, and will now restart.");
  1519 							Application.Restart();
  1520 						}
  1521 						catch (DeploymentDownloadException dde)
  1522 						{
  1523 							MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
  1524 							return;
  1525 						}
  1526 					}
  1527 				}
  1528 				else
  1529 				{
  1530 					MessageBox.Show("You are already running the latest version.", "Application up-to-date");
  1531 				}
  1532             }
  1533         }
  1534 
  1535 
  1536 		/// <summary>
  1537 		/// Used to 
  1538 		/// </summary>
  1539 		private void SysTrayHideShow()
  1540 		{
  1541 			Visible = !Visible;
  1542 			if (Visible)
  1543 			{
  1544 				Activate();
  1545 				WindowState = FormWindowState.Normal;
  1546 			}
  1547 		}
  1548 
  1549 		/// <summary>
  1550 		/// Use to handle minimize events.
  1551 		/// </summary>
  1552 		/// <param name="sender"></param>
  1553 		/// <param name="e"></param>
  1554 		private void MainForm_SizeChanged(object sender, EventArgs e)
  1555 		{
  1556 			if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
  1557 			{
  1558 				if (Visible)
  1559 				{
  1560 					SysTrayHideShow();
  1561 				}
  1562 			}
  1563 			
  1564 		}
  1565 
  1566     }
  1567 
  1568     /// <summary>
  1569     /// A UI thread copy of a client relevant data.
  1570     /// Keeping this copy in the UI thread helps us deal with threading issues.
  1571     /// </summary>
  1572     public class ClientData
  1573     {
  1574         public ClientData(string aSessionId, ICallback aCallback)
  1575         {
  1576             SessionId = aSessionId;
  1577             Name = "";
  1578             Fields = new List<DataField>();
  1579             Layout = new TableLayout(1, 2); //Default to one column and two rows
  1580             Callback = aCallback;
  1581         }
  1582 
  1583         public string SessionId { get; set; }
  1584         public string Name { get; set; }
  1585         public List<DataField> Fields { get; set; }
  1586         public TableLayout Layout { get; set; }
  1587         public ICallback Callback { get; set; }
  1588     }
  1589 }