Server/MainForm.cs
author sl
Sun, 18 Jan 2015 19:01:29 +0100
changeset 96 f3322473db40
parent 95 a4a02cc952a0
child 97 be7183f8c14c
permissions -rw-r--r--
Clear the screen on startup if not in debug mode.
     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             if (Properties.Settings.Default.DisplayConnectOnStartup)
   112             {
   113                 OpenDisplayConnection();
   114             }
   115 
   116 			//Setup notification icon
   117 			SetupTrayIcon();
   118 
   119 			// To make sure start up with minimize to tray works
   120 			if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
   121 			{
   122 				Visible = false;
   123 			}
   124 
   125 #if !DEBUG
   126 			//When not debugging we want the screen to be empty until a client takes over 
   127 			tableLayoutPanel.Controls.Clear();
   128 			tableLayoutPanel.RowStyles.Clear();
   129 			tableLayoutPanel.ColumnStyles.Clear();
   130 #endif
   131         }
   132 
   133 		/// <summary>
   134 		/// 
   135 		/// </summary>
   136 		private void SetupTrayIcon()
   137 		{
   138 			iNotifyIcon.Icon = GetIcon("vfd.ico");
   139 			iNotifyIcon.Text = "Sharp Display Manager";
   140 			iNotifyIcon.Visible = true;
   141 
   142 			//Double click toggles visibility - typically brings up the application
   143 			iNotifyIcon.DoubleClick += delegate(object obj, EventArgs args)
   144 			{
   145 				SysTrayHideShow();
   146 			};
   147 
   148 			//Adding a context menu, useful to be able to exit the application
   149 			ContextMenu contextMenu = new ContextMenu();
   150 			//Context menu item to toggle visibility
   151 			MenuItem hideShowItem = new MenuItem("Hide/Show");
   152 			hideShowItem.Click += delegate(object obj, EventArgs args)
   153 			{
   154 				SysTrayHideShow();
   155 			};
   156 			contextMenu.MenuItems.Add(hideShowItem);
   157 
   158 			//Context menu item separator
   159 			contextMenu.MenuItems.Add(new MenuItem("-"));
   160 
   161 			//Context menu exit item
   162 			MenuItem exitItem = new MenuItem("Exit");
   163 			exitItem.Click += delegate(object obj, EventArgs args)
   164 			{
   165 				Application.Exit();
   166 			};
   167 			contextMenu.MenuItems.Add(exitItem);
   168 
   169 			iNotifyIcon.ContextMenu = contextMenu;
   170 		}
   171 
   172 		/// <summary>
   173 		/// Access icons from embedded resources.
   174 		/// </summary>
   175 		/// <param name="name"></param>
   176 		/// <returns></returns>
   177 		public static Icon GetIcon(string name)
   178 		{
   179 			name = "SharpDisplayManager.Resources." + name;
   180 
   181 			string[] names =
   182 			  Assembly.GetExecutingAssembly().GetManifestResourceNames();
   183 			for (int i = 0; i < names.Length; i++)
   184 			{
   185 				if (names[i].Replace('\\', '.') == name)
   186 				{
   187 					using (Stream stream = Assembly.GetExecutingAssembly().
   188 					  GetManifestResourceStream(names[i]))
   189 					{
   190 						return new Icon(stream);
   191 					}
   192 				}
   193 			}
   194 
   195 			return null;
   196 		}
   197 
   198 
   199         /// <summary>
   200         /// Set our current client.
   201         /// This will take care of applying our client layout and set data fields.
   202         /// </summary>
   203         /// <param name="aSessionId"></param>
   204         void SetCurrentClient(string aSessionId)
   205         {
   206             if (aSessionId == iCurrentClientSessionId)
   207             {
   208                 //Given client is already the current one.
   209                 //Don't bother changing anything then.
   210                 return;
   211             }
   212 
   213             //Set current client ID.
   214             iCurrentClientSessionId = aSessionId;
   215             //Fetch and set current client data.
   216             iCurrentClientData = iClients[aSessionId];
   217             //Apply layout and set data fields.
   218             UpdateTableLayoutPanel(iCurrentClientData);
   219         }
   220 
   221         private void buttonFont_Click(object sender, EventArgs e)
   222         {
   223             //fontDialog.ShowColor = true;
   224             //fontDialog.ShowApply = true;
   225             fontDialog.ShowEffects = true;
   226             MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
   227             fontDialog.Font = label.Font;
   228 
   229             fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
   230 
   231             //fontDialog.ShowHelp = true;
   232 
   233             //fontDlg.MaxSize = 40;
   234             //fontDlg.MinSize = 22;
   235 
   236             //fontDialog.Parent = this;
   237             //fontDialog.StartPosition = FormStartPosition.CenterParent;
   238 
   239             //DlgBox.ShowDialog(fontDialog);
   240 
   241             //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
   242             if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
   243             {
   244 
   245                 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
   246 
   247                 //MessageBox.Show("Ok");
   248                 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
   249                 {
   250                     ctrl.Font = fontDialog.Font;
   251                 }
   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         private void OpenDisplayConnection()
   503         {
   504             CloseDisplayConnection();
   505 
   506             if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
   507             {
   508                 UpdateStatus();
   509                 iDisplay.RequestFirmwareRevision();
   510             }
   511             else
   512             {
   513                 UpdateStatus();
   514                 toolStripStatusLabelConnect.Text = "Connection error";
   515             }
   516         }
   517 
   518         private void CloseDisplayConnection()
   519         {
   520             iDisplay.Close();
   521             UpdateStatus();
   522         }
   523 
   524         private void buttonOpen_Click(object sender, EventArgs e)
   525         {
   526             OpenDisplayConnection();
   527         }
   528 
   529         private void buttonClose_Click(object sender, EventArgs e)
   530         {
   531             CloseDisplayConnection();
   532         }
   533 
   534         private void buttonClear_Click(object sender, EventArgs e)
   535         {
   536             iDisplay.Clear();
   537             iDisplay.SwapBuffers();
   538         }
   539 
   540         private void buttonFill_Click(object sender, EventArgs e)
   541         {
   542             iDisplay.Fill();
   543             iDisplay.SwapBuffers();
   544         }
   545 
   546         private void trackBarBrightness_Scroll(object sender, EventArgs e)
   547         {
   548             cds.Brightness = trackBarBrightness.Value;
   549             Properties.Settings.Default.Save();
   550             iDisplay.SetBrightness(trackBarBrightness.Value);
   551 
   552         }
   553 
   554 
   555         /// <summary>
   556         /// CDS stands for Current Display Settings
   557         /// </summary>
   558         private DisplaySettings cds
   559         {
   560             get
   561             {
   562                 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
   563                 if (settings == null)
   564                 {
   565                     settings = new DisplaysSettings();
   566                     settings.Init();
   567                     Properties.Settings.Default.DisplaysSettings = settings;
   568                 }
   569 
   570                 //Make sure all our settings have been created
   571                 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
   572                 {
   573                     settings.Displays.Add(new DisplaySettings());
   574                 }
   575 
   576                 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
   577                 return displaySettings;
   578             }
   579         }
   580 
   581         /// <summary>
   582         /// Check if the given font has a fixed character pitch.
   583         /// </summary>
   584         /// <param name="ft"></param>
   585         /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
   586         public float IsFixedWidth(Font ft)
   587         {
   588             Graphics g = CreateGraphics();
   589             char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
   590             float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
   591 
   592             bool fixedWidth = true;
   593 
   594             foreach (char c in charSizes)
   595                 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
   596                     fixedWidth = false;
   597 
   598             if (fixedWidth)
   599             {
   600                 return charWidth;
   601             }
   602 
   603             return 0.0f;
   604         }
   605 
   606         private void UpdateStatus()
   607         {
   608             //Synchronize UI with settings
   609             //Load settings
   610             checkBoxShowBorders.Checked = cds.ShowBorders;
   611             tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   612 
   613             //Set the proper font to each of our labels
   614             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
   615             {
   616                 ctrl.Font = cds.Font;
   617             }
   618 
   619             CheckFontHeight();
   620 			//Check if "run on Windows startup" is enabled
   621 			checkBoxAutoStart.Checked = iStartupManager.Startup;
   622 			//
   623             checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
   624 			checkBoxMinimizeToTray.Checked = Properties.Settings.Default.MinimizeToTray;
   625 			checkBoxStartMinimized.Checked = Properties.Settings.Default.StartMinimized;
   626             checkBoxReverseScreen.Checked = cds.ReverseScreen;
   627             checkBoxInverseColors.Checked = cds.InverseColors;
   628             comboBoxDisplayType.SelectedIndex = cds.DisplayType;
   629             timer.Interval = cds.TimerInterval;
   630             maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
   631             //
   632             SetupPixelDelegates();
   633 
   634             if (iDisplay.IsOpen())
   635             {
   636                 //Only setup brightness if display is open
   637                 trackBarBrightness.Minimum = iDisplay.MinBrightness();
   638                 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
   639                 trackBarBrightness.Value = cds.Brightness;
   640                 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
   641                 trackBarBrightness.SmallChange = 1;
   642                 iDisplay.SetBrightness(cds.Brightness);
   643                 //
   644                 buttonFill.Enabled = true;
   645                 buttonClear.Enabled = true;
   646                 buttonOpen.Enabled = false;
   647                 buttonClose.Enabled = true;
   648                 trackBarBrightness.Enabled = true;
   649                 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
   650                 //+ " - " + iDisplay.SerialNumber();
   651 
   652                 if (iDisplay.SupportPowerOnOff())
   653                 {
   654                     buttonPowerOn.Enabled = true;
   655                     buttonPowerOff.Enabled = true;
   656                 }
   657                 else
   658                 {
   659                     buttonPowerOn.Enabled = false;
   660                     buttonPowerOff.Enabled = false;
   661                 }
   662 
   663                 if (iDisplay.SupportClock())
   664                 {
   665                     buttonShowClock.Enabled = true;
   666                     buttonHideClock.Enabled = true;
   667                 }
   668                 else
   669                 {
   670                     buttonShowClock.Enabled = false;
   671                     buttonHideClock.Enabled = false;
   672                 }
   673             }
   674             else
   675             {
   676                 buttonFill.Enabled = false;
   677                 buttonClear.Enabled = false;
   678                 buttonOpen.Enabled = true;
   679                 buttonClose.Enabled = false;
   680                 trackBarBrightness.Enabled = false;
   681                 buttonPowerOn.Enabled = false;
   682                 buttonPowerOff.Enabled = false;
   683                 buttonShowClock.Enabled = false;
   684                 buttonHideClock.Enabled = false;
   685                 toolStripStatusLabelConnect.Text = "Disconnected";
   686                 toolStripStatusLabelPower.Text = "N/A";
   687             }
   688         }
   689 
   690 
   691 
   692         private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
   693         {
   694             //Save our show borders setting
   695             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   696             cds.ShowBorders = checkBoxShowBorders.Checked;
   697             Properties.Settings.Default.Save();
   698             CheckFontHeight();
   699         }
   700 
   701         private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
   702         {
   703             //Save our connect on startup setting
   704             Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
   705             Properties.Settings.Default.Save();
   706         }
   707 
   708 		private void checkBoxMinimizeToTray_CheckedChanged(object sender, EventArgs e)
   709 		{
   710 			//Save our "Minimize to tray" setting
   711 			Properties.Settings.Default.MinimizeToTray = checkBoxMinimizeToTray.Checked;
   712 			Properties.Settings.Default.Save();
   713 
   714 		}
   715 
   716 		private void checkBoxStartMinimized_CheckedChanged(object sender, EventArgs e)
   717 		{
   718 			//Save our "Start minimized" setting
   719 			Properties.Settings.Default.StartMinimized = checkBoxStartMinimized.Checked;
   720 			Properties.Settings.Default.Save();
   721 		}
   722 
   723 		private void checkBoxAutoStart_CheckedChanged(object sender, EventArgs e)
   724 		{
   725 			iStartupManager.Startup = checkBoxAutoStart.Checked;
   726 		}
   727 
   728 
   729         private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
   730         {
   731             //Save our reverse screen setting
   732             cds.ReverseScreen = checkBoxReverseScreen.Checked;
   733             Properties.Settings.Default.Save();
   734             SetupPixelDelegates();
   735         }
   736 
   737         private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
   738         {
   739             //Save our inverse colors setting
   740             cds.InverseColors = checkBoxInverseColors.Checked;
   741             Properties.Settings.Default.Save();
   742             SetupPixelDelegates();
   743         }
   744 
   745         private void MainForm_Resize(object sender, EventArgs e)
   746         {
   747             if (WindowState == FormWindowState.Minimized)
   748             {
   749                 // Do some stuff
   750                 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   751                 iCreateBitmap = true;
   752             }
   753         }
   754 
   755         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   756         {
   757             StopServer();
   758             e.Cancel = iClosing;
   759         }
   760 
   761         public void StartServer()
   762         {
   763             iServiceHost = new ServiceHost
   764                 (
   765                     typeof(Session),
   766                     new Uri[] { new Uri("net.tcp://localhost:8001/") }
   767                 );
   768 
   769             iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
   770             iServiceHost.Open();
   771         }
   772 
   773         public void StopServer()
   774         {
   775             if (iClients.Count > 0 && !iClosing)
   776             {
   777                 //Tell our clients
   778                 iClosing = true;
   779                 BroadcastCloseEvent();
   780             }
   781             else if (iClosing)
   782             {
   783                 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
   784                 {
   785                     iClosing = false; //We make sure we force close if asked twice
   786                 }
   787             }
   788             else
   789             {
   790                 //We removed that as it often lags for some reason
   791                 //iServiceHost.Close();
   792             }
   793         }
   794 
   795         public void BroadcastCloseEvent()
   796         {
   797             Trace.TraceInformation("BroadcastCloseEvent - start");
   798 
   799             var inactiveClients = new List<string>();
   800             foreach (var client in iClients)
   801             {
   802                 //if (client.Key != eventData.ClientName)
   803                 {
   804                     try
   805                     {
   806                         Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
   807                         client.Value.Callback.OnCloseOrder(/*eventData*/);
   808                     }
   809                     catch (Exception ex)
   810                     {
   811                         inactiveClients.Add(client.Key);
   812                     }
   813                 }
   814             }
   815 
   816             if (inactiveClients.Count > 0)
   817             {
   818                 foreach (var client in inactiveClients)
   819                 {
   820                     iClients.Remove(client);
   821                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
   822                 }
   823             }
   824         }
   825 
   826         private void buttonStartClient_Click(object sender, EventArgs e)
   827         {
   828             Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
   829             clientThread.Start();
   830             BringToFront();
   831         }
   832 
   833         private void buttonSuspend_Click(object sender, EventArgs e)
   834         {
   835             LastTickTime = DateTime.Now; //Reset timer to prevent jump
   836             timer.Enabled = !timer.Enabled;
   837             if (!timer.Enabled)
   838             {
   839                 buttonSuspend.Text = "Run";
   840             }
   841             else
   842             {
   843                 buttonSuspend.Text = "Pause";
   844             }
   845         }
   846 
   847         private void buttonCloseClients_Click(object sender, EventArgs e)
   848         {
   849             BroadcastCloseEvent();
   850         }
   851 
   852         private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
   853         {
   854 
   855         }
   856 
   857 
   858         /// <summary>
   859         ///
   860         /// </summary>
   861         /// <param name="aSessionId"></param>
   862         /// <param name="aCallback"></param>
   863         public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
   864         {
   865             if (this.InvokeRequired)
   866             {
   867                 //Not in the proper thread, invoke ourselves
   868                 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
   869                 this.Invoke(d, new object[] { aSessionId, aCallback });
   870             }
   871             else
   872             {
   873                 //We are in the proper thread
   874                 //Add this session to our collection of clients
   875                 ClientData newClient = new ClientData(aSessionId, aCallback);
   876                 Program.iMainForm.iClients.Add(aSessionId, newClient);
   877                 //Add this session to our UI
   878                 UpdateClientTreeViewNode(newClient);
   879             }
   880         }
   881 
   882         /// <summary>
   883         ///
   884         /// </summary>
   885         /// <param name="aSessionId"></param>
   886         public void RemoveClientThreadSafe(string aSessionId)
   887         {
   888             if (this.InvokeRequired)
   889             {
   890                 //Not in the proper thread, invoke ourselves
   891                 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
   892                 this.Invoke(d, new object[] { aSessionId });
   893             }
   894             else
   895             {
   896                 //We are in the proper thread
   897                 //Remove this session from both client collection and UI tree view
   898                 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
   899                 {
   900                     Program.iMainForm.iClients.Remove(aSessionId);
   901                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
   902                 }
   903 
   904                 if (iClosing && iClients.Count == 0)
   905                 {
   906                     //We were closing our form
   907                     //All clients are now closed
   908                     //Just resume our close operation
   909                     iClosing = false;
   910                     Close();
   911                 }
   912             }
   913         }
   914 
   915         /// <summary>
   916         ///
   917         /// </summary>
   918         /// <param name="aSessionId"></param>
   919         /// <param name="aLayout"></param>
   920         public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
   921         {
   922             if (this.InvokeRequired)
   923             {
   924                 //Not in the proper thread, invoke ourselves
   925                 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
   926                 this.Invoke(d, new object[] { aSessionId, aLayout });
   927             }
   928             else
   929             {
   930                 ClientData client = iClients[aSessionId];
   931                 if (client != null)
   932                 {
   933                     client.Layout = aLayout;
   934                     UpdateTableLayoutPanel(client);
   935                     //
   936                     UpdateClientTreeViewNode(client);
   937                 }
   938             }
   939         }
   940 
   941         /// <summary>
   942         ///
   943         /// </summary>
   944         /// <param name="aSessionId"></param>
   945         /// <param name="aField"></param>
   946         public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
   947         {
   948             if (this.InvokeRequired)
   949             {
   950                 //Not in the proper thread, invoke ourselves
   951                 SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
   952                 this.Invoke(d, new object[] { aSessionId, aField });
   953             }
   954             else
   955             {
   956                 //We are in the proper thread
   957                 //Call the non-thread-safe variant
   958                 SetClientField(aSessionId, aField);
   959             }
   960         }
   961 
   962         /// <summary>
   963         ///
   964         /// </summary>
   965         /// <param name="aSessionId"></param>
   966         /// <param name="aField"></param>
   967         private void SetClientField(string aSessionId, DataField aField)
   968         {
   969             SetCurrentClient(aSessionId);
   970             ClientData client = iClients[aSessionId];
   971             if (client != null)
   972             {
   973                 bool somethingChanged = false;
   974 
   975                 //Make sure all our fields are in place
   976                 while (client.Fields.Count < (aField.Index + 1))
   977                 {
   978                     //Add a text field with proper index
   979                     client.Fields.Add(new DataField(client.Fields.Count));
   980                     somethingChanged = true;
   981                 }
   982 
   983                 if (client.Fields[aField.Index].IsSameLayout(aField))
   984                 {
   985                     //Same layout just update our field
   986                     client.Fields[aField.Index] = aField;
   987                     //
   988                     if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
   989                     {
   990                         //Text field control already in place, just change the text
   991                         MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
   992                         somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
   993                         label.Text = aField.Text;
   994                         label.TextAlign = aField.Alignment;
   995                     }
   996                     else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
   997                     {
   998                         somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
   999                         //Bitmap field control already in place just change the bitmap
  1000                         PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
  1001                         pictureBox.Image = aField.Bitmap;
  1002                     }
  1003                     else
  1004                     {
  1005                         somethingChanged = true;
  1006                         //The requested control in our layout it not of the correct type
  1007                         //Wrong control type, re-create them all
  1008                         UpdateTableLayoutPanel(iCurrentClientData);
  1009                     }
  1010                 }
  1011                 else
  1012                 {
  1013                     somethingChanged = true;
  1014                     //Different layout, need to rebuild it
  1015                     client.Fields[aField.Index] = aField;
  1016                     UpdateTableLayoutPanel(iCurrentClientData);
  1017                 }
  1018 
  1019                 //
  1020                 if (somethingChanged)
  1021                 {
  1022                     UpdateClientTreeViewNode(client);
  1023                 }
  1024             }
  1025         }
  1026 
  1027         /// <summary>
  1028         ///
  1029         /// </summary>
  1030         /// <param name="aTexts"></param>
  1031         public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
  1032         {
  1033             if (this.InvokeRequired)
  1034             {
  1035                 //Not in the proper thread, invoke ourselves
  1036                 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
  1037                 this.Invoke(d, new object[] { aSessionId, aFields });
  1038             }
  1039             else
  1040             {
  1041                 //Put each our text fields in a label control
  1042                 foreach (DataField field in aFields)
  1043                 {
  1044                     SetClientField(aSessionId, field);
  1045                 }
  1046             }
  1047         }
  1048 
  1049         /// <summary>
  1050         ///
  1051         /// </summary>
  1052         /// <param name="aSessionId"></param>
  1053         /// <param name="aName"></param>
  1054         public void SetClientNameThreadSafe(string aSessionId, string aName)
  1055         {
  1056             if (this.InvokeRequired)
  1057             {
  1058                 //Not in the proper thread, invoke ourselves
  1059                 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
  1060                 this.Invoke(d, new object[] { aSessionId, aName });
  1061             }
  1062             else
  1063             {
  1064                 //We are in the proper thread
  1065                 //Get our client
  1066                 ClientData client = iClients[aSessionId];
  1067                 if (client != null)
  1068                 {
  1069                     //Set its name
  1070                     client.Name = aName;
  1071                     //Update our tree-view
  1072                     UpdateClientTreeViewNode(client);
  1073                 }
  1074             }
  1075         }
  1076 
  1077         /// <summary>
  1078         ///
  1079         /// </summary>
  1080         /// <param name="aClient"></param>
  1081         private void UpdateClientTreeViewNode(ClientData aClient)
  1082         {
  1083             if (aClient == null)
  1084             {
  1085                 return;
  1086             }
  1087 
  1088             TreeNode node = null;
  1089             //Check that our client node already exists
  1090             //Get our client root node using its key which is our session ID
  1091             TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
  1092             if (nodes.Count()>0)
  1093             {
  1094                 //We already have a node for that client
  1095                 node = nodes[0];
  1096                 //Clear children as we are going to recreate them below
  1097                 node.Nodes.Clear();
  1098             }
  1099             else
  1100             {
  1101                 //Client node does not exists create a new one
  1102                 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
  1103                 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
  1104             }
  1105 
  1106             if (node != null)
  1107             {
  1108                 //Change its name
  1109                 if (aClient.Name != "")
  1110                 {
  1111                     //We have a name, us it as text for our root node
  1112                     node.Text = aClient.Name;
  1113                     //Add a child with SessionId
  1114                     node.Nodes.Add(new TreeNode(aClient.SessionId));
  1115                 }
  1116                 else
  1117                 {
  1118                     //No name, use session ID instead
  1119                     node.Text = aClient.SessionId;
  1120                 }
  1121 
  1122                 if (aClient.Fields.Count > 0)
  1123                 {
  1124                     //Create root node for our texts
  1125                     TreeNode textsRoot = new TreeNode("Fields");
  1126                     node.Nodes.Add(textsRoot);
  1127                     //For each text add a new entry
  1128                     foreach (DataField field in aClient.Fields)
  1129                     {
  1130                         if (!field.IsBitmap)
  1131                         {
  1132                             DataField textField = (DataField)field;
  1133                             textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
  1134                         }
  1135                         else
  1136                         {
  1137                             textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
  1138                         }
  1139                     }
  1140                 }
  1141 
  1142                 node.ExpandAll();
  1143             }
  1144         }
  1145 
  1146         private void buttonAddRow_Click(object sender, EventArgs e)
  1147         {
  1148             if (tableLayoutPanel.RowCount < 6)
  1149             {
  1150                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
  1151             }
  1152         }
  1153 
  1154         private void buttonRemoveRow_Click(object sender, EventArgs e)
  1155         {
  1156             if (tableLayoutPanel.RowCount > 1)
  1157             {
  1158                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
  1159             }
  1160 
  1161             UpdateTableLayoutRowStyles();
  1162         }
  1163 
  1164         private void buttonAddColumn_Click(object sender, EventArgs e)
  1165         {
  1166             if (tableLayoutPanel.ColumnCount < 8)
  1167             {
  1168                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
  1169             }
  1170         }
  1171 
  1172         private void buttonRemoveColumn_Click(object sender, EventArgs e)
  1173         {
  1174             if (tableLayoutPanel.ColumnCount > 1)
  1175             {
  1176                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
  1177             }
  1178         }
  1179 
  1180 
  1181         /// <summary>
  1182         /// Update our table layout row styles to make sure each rows have similar height
  1183         /// </summary>
  1184         private void UpdateTableLayoutRowStyles()
  1185         {
  1186             foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
  1187             {
  1188                 rowStyle.SizeType = SizeType.Percent;
  1189                 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
  1190             }
  1191         }
  1192 
  1193         /// DEPRECATED
  1194         /// <summary>
  1195         /// Empty and recreate our table layout with the given number of columns and rows.
  1196         /// Sizes of rows and columns are uniform.
  1197         /// </summary>
  1198         /// <param name="aColumn"></param>
  1199         /// <param name="aRow"></param>
  1200         private void UpdateTableLayoutPanel(int aColumn, int aRow)
  1201         {
  1202             tableLayoutPanel.Controls.Clear();
  1203             tableLayoutPanel.RowStyles.Clear();
  1204             tableLayoutPanel.ColumnStyles.Clear();
  1205             tableLayoutPanel.RowCount = 0;
  1206             tableLayoutPanel.ColumnCount = 0;
  1207 
  1208             while (tableLayoutPanel.RowCount < aRow)
  1209             {
  1210                 tableLayoutPanel.RowCount++;
  1211             }
  1212 
  1213             while (tableLayoutPanel.ColumnCount < aColumn)
  1214             {
  1215                 tableLayoutPanel.ColumnCount++;
  1216             }
  1217 
  1218             for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
  1219             {
  1220                 //Create our column styles
  1221                 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
  1222 
  1223                 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
  1224                 {
  1225                     if (i == 0)
  1226                     {
  1227                         //Create our row styles
  1228                         this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
  1229                     }
  1230 
  1231                     MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
  1232                     control.AutoEllipsis = true;
  1233                     control.AutoSize = true;
  1234                     control.BackColor = System.Drawing.Color.Transparent;
  1235                     control.Dock = System.Windows.Forms.DockStyle.Fill;
  1236                     control.Location = new System.Drawing.Point(1, 1);
  1237                     control.Margin = new System.Windows.Forms.Padding(0);
  1238                     control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
  1239                     control.OwnTimer = false;
  1240                     control.PixelsPerSecond = 64;
  1241                     control.Separator = "|";
  1242                     //control.Size = new System.Drawing.Size(254, 30);
  1243                     //control.TabIndex = 2;
  1244                     control.Font = cds.Font;
  1245                     control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
  1246                     control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  1247                     control.UseCompatibleTextRendering = true;
  1248                     //
  1249                     tableLayoutPanel.Controls.Add(control, i, j);
  1250                 }
  1251             }
  1252 
  1253             CheckFontHeight();
  1254         }
  1255 
  1256 
  1257         /// <summary>
  1258         /// Update our display table layout.
  1259         /// </summary>
  1260         /// <param name="aLayout"></param>
  1261         private void UpdateTableLayoutPanel(ClientData aClient)
  1262         {
  1263             TableLayout layout = aClient.Layout;
  1264             int fieldCount = 0;
  1265 
  1266             tableLayoutPanel.Controls.Clear();
  1267             tableLayoutPanel.RowStyles.Clear();
  1268             tableLayoutPanel.ColumnStyles.Clear();
  1269             tableLayoutPanel.RowCount = 0;
  1270             tableLayoutPanel.ColumnCount = 0;
  1271 
  1272             while (tableLayoutPanel.RowCount < layout.Rows.Count)
  1273             {
  1274                 tableLayoutPanel.RowCount++;
  1275             }
  1276 
  1277             while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
  1278             {
  1279                 tableLayoutPanel.ColumnCount++;
  1280             }
  1281 
  1282             for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
  1283             {
  1284                 //Create our column styles
  1285                 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
  1286 
  1287                 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
  1288                 {
  1289                     if (i == 0)
  1290                     {
  1291                         //Create our row styles
  1292                         this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
  1293                     }
  1294 
  1295                     //Check if we already have a control
  1296                     Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
  1297                     if (existingControl!=null)
  1298                     {
  1299                         //We already have a control in that cell as a results of row/col spanning
  1300                         //Move on to next cell then
  1301                         continue;
  1302                     }
  1303 
  1304                     fieldCount++;
  1305 
  1306                     //Check if a client field already exists for that cell
  1307                     if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
  1308                     {
  1309                         //No client field specified, create a text field by default
  1310                         aClient.Fields.Add(new DataField(aClient.Fields.Count));
  1311                     }
  1312 
  1313                     //Create a control corresponding to the field specified for that cell
  1314                     DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
  1315                     Control control = CreateControlForDataField(field);
  1316 
  1317                     //Add newly created control to our table layout at the specified row and column
  1318                     tableLayoutPanel.Controls.Add(control, i, j);
  1319                     //Make sure we specify row and column span for that new control
  1320                     tableLayoutPanel.SetRowSpan(control,field.RowSpan);
  1321                     tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
  1322                 }
  1323             }
  1324 
  1325             //
  1326             while (aClient.Fields.Count > fieldCount)
  1327             {
  1328                 //We have too much fields for this layout
  1329                 //Just discard them until we get there
  1330                 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
  1331             }
  1332 
  1333             CheckFontHeight();
  1334         }
  1335 
  1336         /// <summary>
  1337         /// Check our type of data field and create corresponding control
  1338         /// </summary>
  1339         /// <param name="aField"></param>
  1340         private Control CreateControlForDataField(DataField aField)
  1341         {
  1342             Control control=null;
  1343             if (!aField.IsBitmap)
  1344             {
  1345                 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
  1346                 label.AutoEllipsis = true;
  1347                 label.AutoSize = true;
  1348                 label.BackColor = System.Drawing.Color.Transparent;
  1349                 label.Dock = System.Windows.Forms.DockStyle.Fill;
  1350                 label.Location = new System.Drawing.Point(1, 1);
  1351                 label.Margin = new System.Windows.Forms.Padding(0);
  1352                 label.Name = "marqueeLabel" + aField.Index;
  1353                 label.OwnTimer = false;
  1354                 label.PixelsPerSecond = 64;
  1355                 label.Separator = "|";
  1356                 //control.Size = new System.Drawing.Size(254, 30);
  1357                 //control.TabIndex = 2;
  1358                 label.Font = cds.Font;
  1359 
  1360                 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  1361                 label.UseCompatibleTextRendering = true;
  1362                 label.Text = aField.Text;
  1363                 //
  1364                 control = label;
  1365             }
  1366             else
  1367             {
  1368                 //Create picture box
  1369                 PictureBox picture = new PictureBox();
  1370                 picture.AutoSize = true;
  1371                 picture.BackColor = System.Drawing.Color.Transparent;
  1372                 picture.Dock = System.Windows.Forms.DockStyle.Fill;
  1373                 picture.Location = new System.Drawing.Point(1, 1);
  1374                 picture.Margin = new System.Windows.Forms.Padding(0);
  1375                 picture.Name = "pictureBox" + aField;
  1376                 //Set our image
  1377                 picture.Image = aField.Bitmap;
  1378                 //
  1379                 control = picture;
  1380             }
  1381 
  1382             return control;
  1383         }
  1384 
  1385 
  1386         private void buttonAlignLeft_Click(object sender, EventArgs e)
  1387         {
  1388             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1389             {
  1390                 ctrl.TextAlign = ContentAlignment.MiddleLeft;
  1391             }
  1392         }
  1393 
  1394         private void buttonAlignCenter_Click(object sender, EventArgs e)
  1395         {
  1396             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1397             {
  1398                 ctrl.TextAlign = ContentAlignment.MiddleCenter;
  1399             }
  1400         }
  1401 
  1402         private void buttonAlignRight_Click(object sender, EventArgs e)
  1403         {
  1404             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1405             {
  1406                 ctrl.TextAlign = ContentAlignment.MiddleRight;
  1407             }
  1408         }
  1409 
  1410         private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
  1411         {
  1412             Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
  1413             cds.DisplayType = comboBoxDisplayType.SelectedIndex;
  1414             Properties.Settings.Default.Save();
  1415             if (iDisplay.IsOpen())
  1416             {
  1417                 OpenDisplayConnection();
  1418             }
  1419             else
  1420             {
  1421                 UpdateStatus();
  1422             }
  1423         }
  1424 
  1425 
  1426         private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
  1427         {
  1428             if (maskedTextBoxTimerInterval.Text != "")
  1429             {
  1430                 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
  1431 
  1432                 if (interval > 0)
  1433                 {
  1434                     timer.Interval = interval;
  1435                     cds.TimerInterval = timer.Interval;
  1436                     Properties.Settings.Default.Save();
  1437                 }
  1438             }
  1439         }
  1440 
  1441         private void buttonPowerOn_Click(object sender, EventArgs e)
  1442         {
  1443             iDisplay.PowerOn();
  1444         }
  1445 
  1446         private void buttonPowerOff_Click(object sender, EventArgs e)
  1447         {
  1448             iDisplay.PowerOff();
  1449         }
  1450 
  1451         private void buttonShowClock_Click(object sender, EventArgs e)
  1452         {
  1453             iDisplay.ShowClock();
  1454         }
  1455 
  1456         private void buttonHideClock_Click(object sender, EventArgs e)
  1457         {
  1458             iDisplay.HideClock();
  1459         }
  1460 
  1461         private void buttonUpdate_Click(object sender, EventArgs e)
  1462         {
  1463             InstallUpdateSyncWithInfo();
  1464         }
  1465 
  1466 
  1467         private void InstallUpdateSyncWithInfo()
  1468         {
  1469             UpdateCheckInfo info = null;
  1470 
  1471             if (ApplicationDeployment.IsNetworkDeployed)
  1472             {
  1473                 ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
  1474 
  1475                 try
  1476                 {
  1477                     info = ad.CheckForDetailedUpdate();
  1478 
  1479                 }
  1480                 catch (DeploymentDownloadException dde)
  1481                 {
  1482                     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);
  1483                     return;
  1484                 }
  1485                 catch (InvalidDeploymentException ide)
  1486                 {
  1487                     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);
  1488                     return;
  1489                 }
  1490                 catch (InvalidOperationException ioe)
  1491                 {
  1492                     MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
  1493                     return;
  1494                 }
  1495 
  1496 				if (info.UpdateAvailable)
  1497 				{
  1498 					Boolean doUpdate = true;
  1499 
  1500 					if (!info.IsUpdateRequired)
  1501 					{
  1502 						DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
  1503 						if (!(DialogResult.OK == dr))
  1504 						{
  1505 							doUpdate = false;
  1506 						}
  1507 					}
  1508 					else
  1509 					{
  1510 						// Display a message that the app MUST reboot. Display the minimum required version.
  1511 						MessageBox.Show("This application has detected a mandatory update from your current " +
  1512 							"version to version " + info.MinimumRequiredVersion.ToString() +
  1513 							". The application will now install the update and restart.",
  1514 							"Update Available", MessageBoxButtons.OK,
  1515 							MessageBoxIcon.Information);
  1516 					}
  1517 
  1518 					if (doUpdate)
  1519 					{
  1520 						try
  1521 						{
  1522 							ad.Update();
  1523 							MessageBox.Show("The application has been upgraded, and will now restart.");
  1524 							Application.Restart();
  1525 						}
  1526 						catch (DeploymentDownloadException dde)
  1527 						{
  1528 							MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
  1529 							return;
  1530 						}
  1531 					}
  1532 				}
  1533 				else
  1534 				{
  1535 					MessageBox.Show("You are already running the latest version.", "Application up-to-date");
  1536 				}
  1537             }
  1538         }
  1539 
  1540 
  1541 		/// <summary>
  1542 		/// Used to 
  1543 		/// </summary>
  1544 		private void SysTrayHideShow()
  1545 		{
  1546 			Visible = !Visible;
  1547 			if (Visible)
  1548 			{
  1549 				Activate();
  1550 				WindowState = FormWindowState.Normal;
  1551 			}
  1552 		}
  1553 
  1554 		/// <summary>
  1555 		/// Use to handle minimize events.
  1556 		/// </summary>
  1557 		/// <param name="sender"></param>
  1558 		/// <param name="e"></param>
  1559 		private void MainForm_SizeChanged(object sender, EventArgs e)
  1560 		{
  1561 			if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
  1562 			{
  1563 				if (Visible)
  1564 				{
  1565 					SysTrayHideShow();
  1566 				}
  1567 			}
  1568 			
  1569 		}
  1570 
  1571     }
  1572 
  1573     /// <summary>
  1574     /// A UI thread copy of a client relevant data.
  1575     /// Keeping this copy in the UI thread helps us deal with threading issues.
  1576     /// </summary>
  1577     public class ClientData
  1578     {
  1579         public ClientData(string aSessionId, ICallback aCallback)
  1580         {
  1581             SessionId = aSessionId;
  1582             Name = "";
  1583             Fields = new List<DataField>();
  1584             Layout = new TableLayout(1, 2); //Default to one column and two rows
  1585             Callback = aCallback;
  1586         }
  1587 
  1588         public string SessionId { get; set; }
  1589         public string Name { get; set; }
  1590         public List<DataField> Fields { get; set; }
  1591         public TableLayout Layout { get; set; }
  1592         public ICallback Callback { get; set; }
  1593     }
  1594 }