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