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