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