Server/MainForm.cs
author sl
Tue, 26 Aug 2014 19:24:04 +0200
changeset 45 b5a0fa4770d3
parent 43 86aad774b532
child 46 0c0ee86760ea
permissions -rw-r--r--
Now requesting extra info on auto start-up too.
     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 //
    17 using SharpDisplayInterface;
    18 using SharpDisplayClient;
    19 
    20 
    21 namespace SharpDisplayManager
    22 {
    23     public partial class MainForm : Form
    24     {
    25         DateTime LastTickTime;
    26         Display iDisplay;
    27         System.Drawing.Bitmap iBmp;
    28         bool iCreateBitmap; //Workaround render to bitmap issues when minimized
    29         ServiceHost iServiceHost;
    30         /// <summary>
    31         /// Our collection of clients
    32         /// </summary>
    33         public Dictionary<string, ClientData> iClients;
    34         public bool iClosing;
    35 
    36         public MainForm()
    37         {
    38             LastTickTime = DateTime.Now;
    39             iDisplay = new Display();
    40             iClients = new Dictionary<string, ClientData>();
    41 
    42             InitializeComponent();
    43             UpdateStatus();
    44 
    45             //Load settings
    46             marqueeLabelTop.Font = Properties.Settings.Default.DisplayFont;
    47             marqueeLabelBottom.Font = Properties.Settings.Default.DisplayFont;
    48             checkBoxShowBorders.Checked = Properties.Settings.Default.DisplayShowBorders;
    49             checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
    50             checkBoxReverseScreen.Checked = Properties.Settings.Default.DisplayReverseScreen;
    51             //
    52             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
    53             //We have a bug when drawing minimized and reusing our bitmap
    54             iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
    55             iCreateBitmap = false;
    56         }
    57 
    58         private void MainForm_Load(object sender, EventArgs e)
    59         {
    60             StartServer();
    61 
    62             //
    63             CheckFontHeight();
    64             //
    65 
    66 
    67             if (Properties.Settings.Default.DisplayConnectOnStartup)
    68             {
    69                 iDisplay.Open(Display.TMiniDisplayType.EMiniDisplayAutoDetect);
    70                 UpdateStatus();
    71                 iDisplay.RequestPowerSupplyStatus();
    72             }
    73         }
    74 
    75 
    76         private void buttonFont_Click(object sender, EventArgs e)
    77         {
    78             //fontDialog.ShowColor = true;
    79             //fontDialog.ShowApply = true;
    80             fontDialog.ShowEffects = true;
    81             fontDialog.Font = marqueeLabelTop.Font;
    82 
    83             fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
    84 
    85             //fontDialog.ShowHelp = true;
    86 
    87             //fontDlg.MaxSize = 40;
    88             //fontDlg.MinSize = 22;
    89 
    90             //fontDialog.Parent = this;
    91             //fontDialog.StartPosition = FormStartPosition.CenterParent;
    92 
    93             //DlgBox.ShowDialog(fontDialog);
    94 
    95             //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
    96             if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
    97             {
    98 
    99                 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
   100 
   101                 //MessageBox.Show("Ok");
   102                 marqueeLabelTop.Font = fontDialog.Font;
   103                 marqueeLabelBottom.Font = fontDialog.Font;
   104                 Properties.Settings.Default.DisplayFont = fontDialog.Font;
   105                 Properties.Settings.Default.Save();
   106                 //
   107                 CheckFontHeight();
   108             }
   109         }
   110 
   111         /// <summary>
   112         ///
   113         /// </summary>
   114         void CheckFontHeight()
   115         {
   116             if (marqueeLabelBottom.Font.Height > marqueeLabelBottom.Height)
   117             {
   118                 labelWarning.Text = "WARNING: Selected font is too height by " + (marqueeLabelBottom.Font.Height - marqueeLabelBottom.Height) + " pixels!";
   119                 labelWarning.Visible = true;
   120             }
   121             else
   122             {
   123                 labelWarning.Visible = false;
   124             }
   125 
   126         }
   127 
   128         private void buttonCapture_Click(object sender, EventArgs e)
   129         {
   130             System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
   131             tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
   132             //Bitmap bmpToSave = new Bitmap(bmp);
   133             bmp.Save("D:\\capture.png");
   134 
   135             marqueeLabelTop.Text = "Sweet";
   136 
   137             /*
   138             string outputFileName = "d:\\capture.png";
   139             using (MemoryStream memory = new MemoryStream())
   140             {
   141                 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
   142                 {
   143                     bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
   144                     byte[] bytes = memory.ToArray();
   145                     fs.Write(bytes, 0, bytes.Length);
   146                 }
   147             }
   148              */
   149 
   150         }
   151 
   152         private void CheckForRequestResults()
   153         {
   154             if (iDisplay.IsRequestPending())
   155             {
   156                 switch (iDisplay.AttemptRequestCompletion())
   157                 {
   158                     case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
   159                         if (iDisplay.PowerSupplyStatus())
   160                         {
   161                             toolStripStatusLabelPower.Text = "ON";
   162                         }
   163                         else
   164                         {
   165                             toolStripStatusLabelPower.Text = "OFF";
   166                         }
   167                         //Issue next request then
   168                         iDisplay.RequestDeviceId();
   169                         break;
   170 
   171                     case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
   172                         toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
   173                         //Issue next request then
   174                         iDisplay.RequestFirmwareRevision();
   175                         break;
   176 
   177                     case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
   178                         toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
   179                         //No more request to issue
   180                         break;
   181                 }
   182             }
   183         }
   184 
   185 
   186         public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
   187 
   188 
   189         public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
   190         {
   191             return aBmp.Width - aX - 1;
   192         }
   193 
   194         public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
   195         {
   196             return iBmp.Height - aY - 1;
   197         }
   198 
   199         public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
   200         {
   201             return aX;
   202         }
   203 
   204         public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
   205         {
   206             return aY;
   207         }
   208 
   209 
   210         //This is our timer tick responsible to perform our render
   211         private void timer_Tick(object sender, EventArgs e)
   212         {
   213             //Update our animations
   214             DateTime NewTickTime = DateTime.Now;
   215 
   216             marqueeLabelTop.UpdateAnimation(LastTickTime, NewTickTime);
   217             marqueeLabelBottom.UpdateAnimation(LastTickTime, NewTickTime);
   218 
   219             //Update our display
   220             if (iDisplay.IsOpen())
   221             {
   222                 CheckForRequestResults();
   223 
   224                 //Draw to bitmap
   225                 if (iCreateBitmap)
   226                 {
   227                     iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   228                 }
   229                 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
   230                 //iBmp.Save("D:\\capture.png");
   231 
   232                 //Select proper coordinate translation functions
   233                 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
   234                 CoordinateTranslationDelegate screenX;
   235                 CoordinateTranslationDelegate screenY;
   236 
   237                 if (Properties.Settings.Default.DisplayReverseScreen)
   238                 {
   239                     screenX = ScreenReversedX;
   240                     screenY = ScreenReversedY;
   241                 }
   242                 else
   243                 {
   244                     screenX = ScreenX;
   245                     screenY = ScreenY;
   246                 }
   247 
   248                 //Send it to our display
   249                 for (int i = 0; i < iBmp.Width; i++)
   250                 {
   251                     for (int j = 0; j < iBmp.Height; j++)
   252                     {
   253                         unchecked
   254                         {
   255                             uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
   256                             //For some reason when the app is minimized in the task bar only the alpha of our color is set.
   257                             //Thus that strange test for rendering to work both when the app is in the task bar and when it isn't.
   258                             iDisplay.SetPixel(screenX(iBmp, i), screenY(iBmp, j), Convert.ToInt32(!(color != 0xFF000000)));
   259                         }
   260                     }
   261                 }
   262 
   263                 iDisplay.SwapBuffers();
   264 
   265             }
   266 
   267             //Compute instant FPS
   268             toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " FPS";
   269 
   270             LastTickTime = NewTickTime;
   271 
   272         }
   273 
   274         private void buttonOpen_Click(object sender, EventArgs e)
   275         {
   276             if (iDisplay.Open(Display.TMiniDisplayType.EMiniDisplayAutoDetect))
   277             {
   278                 UpdateStatus();
   279                 iDisplay.RequestPowerSupplyStatus();
   280             }
   281             else
   282             {
   283                 UpdateStatus();
   284                 toolStripStatusLabelConnect.Text = "Connection error";
   285             }
   286 
   287         }
   288 
   289         private void buttonClose_Click(object sender, EventArgs e)
   290         {
   291             iDisplay.Close();
   292             UpdateStatus();
   293         }
   294 
   295         private void buttonClear_Click(object sender, EventArgs e)
   296         {
   297             iDisplay.Clear();
   298             iDisplay.SwapBuffers();
   299         }
   300 
   301         private void buttonFill_Click(object sender, EventArgs e)
   302         {
   303             iDisplay.Fill();
   304             iDisplay.SwapBuffers();
   305         }
   306 
   307         private void trackBarBrightness_Scroll(object sender, EventArgs e)
   308         {
   309             Properties.Settings.Default.DisplayBrightness = trackBarBrightness.Value;
   310             Properties.Settings.Default.Save();
   311             iDisplay.SetBrightness(trackBarBrightness.Value);
   312 
   313         }
   314 
   315         private void UpdateStatus()
   316         {
   317             if (iDisplay.IsOpen())
   318             {
   319                 buttonFill.Enabled = true;
   320                 buttonClear.Enabled = true;
   321                 buttonOpen.Enabled = false;
   322                 buttonClose.Enabled = true;
   323                 trackBarBrightness.Enabled = true;
   324                 trackBarBrightness.Minimum = iDisplay.MinBrightness();
   325                 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
   326                 trackBarBrightness.Value = Properties.Settings.Default.DisplayBrightness;
   327                 trackBarBrightness.LargeChange = Math.Max(1,(iDisplay.MaxBrightness() - iDisplay.MinBrightness())/5);
   328                 trackBarBrightness.SmallChange = 1;
   329                 iDisplay.SetBrightness(Properties.Settings.Default.DisplayBrightness);
   330 
   331                 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
   332                 //+ " - " + iDisplay.SerialNumber();
   333             }
   334             else
   335             {
   336                 buttonFill.Enabled = false;
   337                 buttonClear.Enabled = false;
   338                 buttonOpen.Enabled = true;
   339                 buttonClose.Enabled = false;
   340                 trackBarBrightness.Enabled = false;
   341                 toolStripStatusLabelConnect.Text = "Disconnected";
   342             }
   343         }
   344 
   345 
   346 
   347         private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
   348         {
   349             //Save our show borders setting
   350             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   351             Properties.Settings.Default.DisplayShowBorders = checkBoxShowBorders.Checked;
   352             Properties.Settings.Default.Save();
   353         }
   354 
   355         private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
   356         {
   357             //Save our connect on startup setting
   358             Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
   359             Properties.Settings.Default.Save();
   360         }
   361 
   362         private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
   363         {
   364             //Save our reverse screen setting
   365             Properties.Settings.Default.DisplayReverseScreen = checkBoxReverseScreen.Checked;
   366             Properties.Settings.Default.Save();
   367         }
   368 
   369         private void MainForm_Resize(object sender, EventArgs e)
   370         {
   371             if (WindowState == FormWindowState.Minimized)
   372             {
   373                 // Do some stuff
   374                 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   375                 iCreateBitmap = true;
   376             }
   377         }
   378 
   379         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   380         {
   381             StopServer();
   382             e.Cancel = iClosing;
   383         }
   384 
   385         public void StartServer()
   386         {
   387             iServiceHost = new ServiceHost
   388                 (
   389                     typeof(DisplayServer),
   390                     new Uri[] { new Uri("net.tcp://localhost:8001/") }
   391                 );
   392 
   393             iServiceHost.AddServiceEndpoint(typeof(IDisplayService), new NetTcpBinding(SecurityMode.None,true), "DisplayService");
   394             iServiceHost.Open();
   395         }
   396 
   397         public void StopServer()
   398         {
   399             if (iClients.Count > 0 && !iClosing)
   400             {
   401                 //Tell our clients
   402                 iClosing = true;
   403                 BroadcastCloseEvent();
   404             }
   405             else if (iClosing)
   406             {
   407                 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
   408                 {
   409                     iClosing = false; //We make sure we force close if asked twice
   410                 }
   411             }
   412             else
   413             {
   414                 //We removed that as it often lags for some reason
   415                 //iServiceHost.Close();
   416             }
   417         }
   418 
   419         public void BroadcastCloseEvent()
   420         {
   421             Trace.TraceInformation("BroadcastCloseEvent - start");
   422 
   423             var inactiveClients = new List<string>();
   424             foreach (var client in iClients)
   425             {
   426                 //if (client.Key != eventData.ClientName)
   427                 {
   428                     try
   429                     {
   430                         Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
   431                         client.Value.Callback.OnCloseOrder(/*eventData*/);
   432                     }
   433                     catch (Exception ex)
   434                     {
   435                         inactiveClients.Add(client.Key);
   436                     }
   437                 }
   438             }
   439 
   440             if (inactiveClients.Count > 0)
   441             {
   442                 foreach (var client in inactiveClients)
   443                 {
   444                     iClients.Remove(client);
   445                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
   446                 }
   447             }
   448         }
   449 
   450         private void buttonStartClient_Click(object sender, EventArgs e)
   451         {
   452             Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
   453             clientThread.Start();
   454             BringToFront();
   455         }
   456 
   457         private void buttonSuspend_Click(object sender, EventArgs e)
   458         {
   459             timer.Enabled = !timer.Enabled;
   460             if (!timer.Enabled)
   461             {
   462                 buttonSuspend.Text = "Suspend";
   463             }
   464             else
   465             {
   466                 buttonSuspend.Text = "Pause";
   467             }
   468         }
   469 
   470         private void buttonCloseClients_Click(object sender, EventArgs e)
   471         {
   472             BroadcastCloseEvent();
   473         }
   474 
   475         private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
   476         {
   477 
   478         }
   479 
   480         //Delegates are used for our thread safe method
   481         public delegate void AddClientDelegate(string aSessionId, IDisplayServiceCallback aCallback);
   482         public delegate void RemoveClientDelegate(string aSessionId);
   483         public delegate void SetTextDelegate(string SessionId, TextField aTextField);
   484         public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList<TextField> aTextFields);
   485         public delegate void SetClientNameDelegate(string aSessionId, string aName);
   486 
   487 
   488         /// <summary>
   489         ///
   490         /// </summary>
   491         /// <param name="aSessionId"></param>
   492         /// <param name="aCallback"></param>
   493         public void AddClientThreadSafe(string aSessionId, IDisplayServiceCallback aCallback)
   494         {
   495             if (this.InvokeRequired)
   496             {
   497                 //Not in the proper thread, invoke ourselves
   498                 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
   499                 this.Invoke(d, new object[] { aSessionId, aCallback });
   500             }
   501             else
   502             {
   503                 //We are in the proper thread
   504                 //Add this session to our collection of clients
   505                 ClientData newClient = new ClientData(aSessionId, aCallback);
   506                 Program.iMainForm.iClients.Add(aSessionId, newClient);
   507                 //Add this session to our UI
   508                 UpdateClientTreeViewNode(newClient);
   509             }
   510         }
   511 
   512         /// <summary>
   513         ///
   514         /// </summary>
   515         /// <param name="aSessionId"></param>
   516         public void RemoveClientThreadSafe(string aSessionId)
   517         {
   518             if (this.InvokeRequired)
   519             {
   520                 //Not in the proper thread, invoke ourselves
   521                 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
   522                 this.Invoke(d, new object[] { aSessionId });
   523             }
   524             else
   525             {
   526                 //We are in the proper thread
   527                 //Remove this session from both client collection and UI tree view
   528                 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
   529                 {
   530                     Program.iMainForm.iClients.Remove(aSessionId);
   531                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
   532                 }
   533 
   534                 if (iClosing && iClients.Count == 0)
   535                 {
   536                     //We were closing our form
   537                     //All clients are now closed
   538                     //Just resume our close operation
   539                     iClosing = false;
   540                     Close();
   541                 }
   542             }
   543         }
   544 
   545         /// <summary>
   546         ///
   547         /// </summary>
   548         /// <param name="aLineIndex"></param>
   549         /// <param name="aText"></param>
   550         public void SetTextThreadSafe(string aSessionId, TextField aTextField)
   551         {
   552             if (this.InvokeRequired)
   553             {
   554                 //Not in the proper thread, invoke ourselves
   555                 SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
   556                 this.Invoke(d, new object[] { aSessionId, aTextField });
   557             }
   558             else
   559             {
   560                 ClientData client = iClients[aSessionId];
   561                 if (client != null)
   562                 {
   563                     //Make sure all our texts are in place
   564                     while (client.Texts.Count < (aTextField.Index + 1))
   565                     {
   566                         //Add a text field with proper index
   567                         client.Texts.Add(new TextField(client.Texts.Count));
   568                     }
   569                     client.Texts[aTextField.Index] = aTextField;
   570 
   571                     //We are in the proper thread
   572                     //Only support two lines for now
   573                     if (aTextField.Index == 0)
   574                     {
   575                         marqueeLabelTop.Text = aTextField.Text;
   576                         marqueeLabelTop.TextAlign = aTextField.Alignment;
   577                     }
   578                     else if (aTextField.Index == 1)
   579                     {
   580                         marqueeLabelBottom.Text = aTextField.Text;
   581                         marqueeLabelBottom.TextAlign = aTextField.Alignment;
   582                     }
   583 
   584 
   585                     UpdateClientTreeViewNode(client);
   586                 }
   587             }
   588         }
   589 
   590         /// <summary>
   591         ///
   592         /// </summary>
   593         /// <param name="aTexts"></param>
   594         public void SetTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<TextField> aTextFields)
   595         {
   596             if (this.InvokeRequired)
   597             {
   598                 //Not in the proper thread, invoke ourselves
   599                 SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
   600                 this.Invoke(d, new object[] { aSessionId, aTextFields });
   601             }
   602             else
   603             {
   604                 //We are in the proper thread
   605                 ClientData client = iClients[aSessionId];
   606                 if (client != null)
   607                 {
   608                     //Populate our client with the given text fields
   609                     int j = 0;
   610                     foreach (TextField textField in aTextFields)
   611                     {
   612                         if (client.Texts.Count < (j + 1))
   613                         {
   614                             client.Texts.Add(textField);
   615                         }
   616                         else
   617                         {
   618                             client.Texts[j] = textField;
   619                         }
   620                         j++;
   621                     }                    
   622                     //Only support two lines for now
   623                     for (int i = 0; i < aTextFields.Count; i++)
   624                     {
   625                         if (aTextFields[i].Index == 0)
   626                         {
   627                             marqueeLabelTop.Text = aTextFields[i].Text;
   628                             marqueeLabelTop.TextAlign = aTextFields[i].Alignment;
   629                         }
   630                         else if (aTextFields[i].Index == 1)
   631                         {
   632                             marqueeLabelBottom.Text = aTextFields[i].Text;
   633                             marqueeLabelBottom.TextAlign = aTextFields[i].Alignment;
   634                         }
   635                     }
   636 
   637 
   638                     UpdateClientTreeViewNode(client);
   639                 }
   640             }
   641         }
   642 
   643 
   644         /// <summary>
   645         ///
   646         /// </summary>
   647         /// <param name="aSessionId"></param>
   648         /// <param name="aName"></param>
   649         public void SetClientNameThreadSafe(string aSessionId, string aName)
   650         {
   651             if (this.InvokeRequired)
   652             {
   653                 //Not in the proper thread, invoke ourselves
   654                 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
   655                 this.Invoke(d, new object[] { aSessionId, aName });
   656             }
   657             else
   658             {
   659                 //We are in the proper thread
   660                 //Get our client
   661                 ClientData client = iClients[aSessionId];
   662                 if (client != null)
   663                 {
   664                     //Set its name
   665                     client.Name = aName;
   666                     //Update our tree-view
   667                     UpdateClientTreeViewNode(client);
   668                 }
   669             }
   670         }
   671 
   672         /// <summary>
   673         ///
   674         /// </summary>
   675         /// <param name="aClient"></param>
   676         private void UpdateClientTreeViewNode(ClientData aClient)
   677         {
   678             if (aClient == null)
   679             {
   680                 return;
   681             }
   682 
   683             TreeNode node = null;
   684             //Check that our client node already exists
   685             //Get our client root node using its key which is our session ID
   686             TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
   687             if (nodes.Count()>0)
   688             {
   689                 //We already have a node for that client
   690                 node = nodes[0];
   691                 //Clear children as we are going to recreate them below
   692                 node.Nodes.Clear();
   693             }
   694             else
   695             {
   696                 //Client node does not exists create a new one
   697                 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
   698                 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
   699             }
   700 
   701             if (node != null)
   702             {
   703                 //Change its name
   704                 if (aClient.Name != "")
   705                 {
   706                     //We have a name, us it as text for our root node
   707                     node.Text = aClient.Name;
   708                     //Add a child with SessionId
   709                     node.Nodes.Add(new TreeNode(aClient.SessionId));
   710                 }
   711                 else
   712                 {
   713                     //No name, use session ID instead
   714                     node.Text = aClient.SessionId;
   715                 }
   716 
   717                 if (aClient.Texts.Count > 0)
   718                 {
   719                     //Create root node for our texts
   720                     TreeNode textsRoot = new TreeNode("Text");
   721                     node.Nodes.Add(textsRoot);
   722                     //For each text add a new entry
   723                     foreach (TextField field in aClient.Texts)
   724                     {
   725                         textsRoot.Nodes.Add(new TreeNode(field.Text));
   726                     }
   727                 }
   728 
   729                 node.ExpandAll();
   730             }
   731         }
   732 
   733         private void buttonAddRow_Click(object sender, EventArgs e)
   734         {
   735             if (tableLayoutPanel.RowCount < 6)
   736             {
   737                 tableLayoutPanel.RowCount++;
   738                 CheckFontHeight();
   739             }
   740         }
   741 
   742         private void buttonRemoveRow_Click(object sender, EventArgs e)
   743         {
   744             if (tableLayoutPanel.RowCount > 1)
   745             {
   746                 tableLayoutPanel.RowCount--;
   747                 CheckFontHeight();
   748             }
   749         }
   750 
   751         private void buttonAddColumn_Click(object sender, EventArgs e)
   752         {
   753             if (tableLayoutPanel.ColumnCount < 8)
   754             {
   755                 tableLayoutPanel.ColumnCount++;
   756                 //CheckFontHeight();
   757             }
   758         }
   759 
   760         private void buttonRemoveColumn_Click(object sender, EventArgs e)
   761         {
   762             if (tableLayoutPanel.ColumnCount > 1)
   763             {
   764                 tableLayoutPanel.ColumnCount--;
   765                 //CheckFontHeight();
   766             }
   767         }
   768 
   769         private void buttonAlignLeft_Click(object sender, EventArgs e)
   770         {
   771             marqueeLabelTop.TextAlign = ContentAlignment.MiddleLeft;
   772             marqueeLabelBottom.TextAlign = ContentAlignment.MiddleLeft;
   773         }
   774 
   775         private void buttonAlignCenter_Click(object sender, EventArgs e)
   776         {
   777             marqueeLabelTop.TextAlign = ContentAlignment.MiddleCenter;
   778             marqueeLabelBottom.TextAlign = ContentAlignment.MiddleCenter;
   779         }
   780 
   781         private void buttonAlignRight_Click(object sender, EventArgs e)
   782         {
   783             marqueeLabelTop.TextAlign = ContentAlignment.MiddleRight;
   784             marqueeLabelBottom.TextAlign = ContentAlignment.MiddleRight;
   785         }
   786 
   787     }
   788 
   789     /// <summary>
   790     /// A UI thread copy of a client relevant data.
   791     /// Keeping this copy in the UI thread helps us deal with threading issues.
   792     /// </summary>
   793     public class ClientData
   794     {
   795         public ClientData(string aSessionId, IDisplayServiceCallback aCallback)
   796         {
   797             SessionId = aSessionId;
   798             Name = "";
   799             Texts = new List<TextField>();
   800             Callback = aCallback;
   801         }
   802 
   803         public string SessionId { get; set; }
   804         public string Name { get; set; }
   805         public List<TextField> Texts { get; set; }
   806         public IDisplayServiceCallback Callback { get; set; }
   807     }
   808 }