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