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