Server/MainForm.cs
author sl
Mon, 25 Aug 2014 22:06:20 +0200
changeset 44 a4f39c390e9a
parent 41 1864e4fd1728
child 45 b5a0fa4770d3
permissions -rw-r--r--
MiniDisplay API update.
     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             }
    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 buttonOpen_Click(object sender, EventArgs e)
   274         {
   275             if (iDisplay.Open(Display.TMiniDisplayType.EMiniDisplayAutoDetect))
   276             {
   277                 UpdateStatus();
   278                 iDisplay.RequestPowerSupplyStatus();
   279             }
   280             else
   281             {
   282                 UpdateStatus();
   283                 toolStripStatusLabelConnect.Text = "Connection error";
   284             }
   285 
   286         }
   287 
   288         private void buttonClose_Click(object sender, EventArgs e)
   289         {
   290             iDisplay.Close();
   291             UpdateStatus();
   292         }
   293 
   294         private void buttonClear_Click(object sender, EventArgs e)
   295         {
   296             iDisplay.Clear();
   297             iDisplay.SwapBuffers();
   298         }
   299 
   300         private void buttonFill_Click(object sender, EventArgs e)
   301         {
   302             iDisplay.Fill();
   303             iDisplay.SwapBuffers();
   304         }
   305 
   306         private void trackBarBrightness_Scroll(object sender, EventArgs e)
   307         {
   308             Properties.Settings.Default.DisplayBrightness = trackBarBrightness.Value;
   309             Properties.Settings.Default.Save();
   310             iDisplay.SetBrightness(trackBarBrightness.Value);
   311 
   312         }
   313 
   314         private void UpdateStatus()
   315         {
   316             if (iDisplay.IsOpen())
   317             {
   318                 buttonFill.Enabled = true;
   319                 buttonClear.Enabled = true;
   320                 buttonOpen.Enabled = false;
   321                 buttonClose.Enabled = true;
   322                 trackBarBrightness.Enabled = true;
   323                 trackBarBrightness.Minimum = iDisplay.MinBrightness();
   324                 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
   325                 trackBarBrightness.Value = Properties.Settings.Default.DisplayBrightness;
   326                 trackBarBrightness.LargeChange = Math.Max(1,(iDisplay.MaxBrightness() - iDisplay.MinBrightness())/5);
   327                 trackBarBrightness.SmallChange = 1;
   328                 iDisplay.SetBrightness(Properties.Settings.Default.DisplayBrightness);
   329 
   330                 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
   331                 //+ " - " + iDisplay.SerialNumber();
   332             }
   333             else
   334             {
   335                 buttonFill.Enabled = false;
   336                 buttonClear.Enabled = false;
   337                 buttonOpen.Enabled = true;
   338                 buttonClose.Enabled = false;
   339                 trackBarBrightness.Enabled = false;
   340                 toolStripStatusLabelConnect.Text = "Disconnected";
   341             }
   342         }
   343 
   344 
   345 
   346         private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
   347         {
   348             //Save our show borders setting
   349             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   350             Properties.Settings.Default.DisplayShowBorders = checkBoxShowBorders.Checked;
   351             Properties.Settings.Default.Save();
   352         }
   353 
   354         private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
   355         {
   356             //Save our connect on startup setting
   357             Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
   358             Properties.Settings.Default.Save();
   359         }
   360 
   361         private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
   362         {
   363             //Save our reverse screen setting
   364             Properties.Settings.Default.DisplayReverseScreen = checkBoxReverseScreen.Checked;
   365             Properties.Settings.Default.Save();
   366         }
   367 
   368         private void MainForm_Resize(object sender, EventArgs e)
   369         {
   370             if (WindowState == FormWindowState.Minimized)
   371             {
   372                 // Do some stuff
   373                 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   374                 iCreateBitmap = true;
   375             }
   376         }
   377 
   378         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   379         {
   380             StopServer();
   381             e.Cancel = iClosing;
   382         }
   383 
   384         public void StartServer()
   385         {
   386             iServiceHost = new ServiceHost
   387                 (
   388                     typeof(DisplayServer),
   389                     new Uri[] { new Uri("net.tcp://localhost:8001/") }
   390                 );
   391 
   392             iServiceHost.AddServiceEndpoint(typeof(IDisplayService), new NetTcpBinding(SecurityMode.None,true), "DisplayService");
   393             iServiceHost.Open();
   394         }
   395 
   396         public void StopServer()
   397         {
   398             if (iClients.Count > 0 && !iClosing)
   399             {
   400                 //Tell our clients
   401                 iClosing = true;
   402                 BroadcastCloseEvent();
   403             }
   404             else if (iClosing)
   405             {
   406                 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
   407                 {
   408                     iClosing = false; //We make sure we force close if asked twice
   409                 }
   410             }
   411             else
   412             {
   413                 //We removed that as it often lags for some reason
   414                 //iServiceHost.Close();
   415             }
   416         }
   417 
   418         public void BroadcastCloseEvent()
   419         {
   420             Trace.TraceInformation("BroadcastCloseEvent - start");
   421 
   422             var inactiveClients = new List<string>();
   423             foreach (var client in iClients)
   424             {
   425                 //if (client.Key != eventData.ClientName)
   426                 {
   427                     try
   428                     {
   429                         Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
   430                         client.Value.Callback.OnCloseOrder(/*eventData*/);
   431                     }
   432                     catch (Exception ex)
   433                     {
   434                         inactiveClients.Add(client.Key);
   435                     }
   436                 }
   437             }
   438 
   439             if (inactiveClients.Count > 0)
   440             {
   441                 foreach (var client in inactiveClients)
   442                 {
   443                     iClients.Remove(client);
   444                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
   445                 }
   446             }
   447         }
   448 
   449         private void buttonStartClient_Click(object sender, EventArgs e)
   450         {
   451             Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
   452             clientThread.Start();
   453             BringToFront();
   454         }
   455 
   456         private void buttonSuspend_Click(object sender, EventArgs e)
   457         {
   458             timer.Enabled = !timer.Enabled;
   459             if (!timer.Enabled)
   460             {
   461                 buttonSuspend.Text = "Suspend";
   462             }
   463             else
   464             {
   465                 buttonSuspend.Text = "Pause";
   466             }
   467         }
   468 
   469         private void buttonCloseClients_Click(object sender, EventArgs e)
   470         {
   471             BroadcastCloseEvent();
   472         }
   473 
   474         private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
   475         {
   476 
   477         }
   478 
   479         //Delegates are used for our thread safe method
   480         public delegate void AddClientDelegate(string aSessionId, IDisplayServiceCallback aCallback);
   481         public delegate void RemoveClientDelegate(string aSessionId);
   482         public delegate void SetTextDelegate(string SessionId, TextField aTextField);
   483         public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList<TextField> aTextFields);
   484         public delegate void SetClientNameDelegate(string aSessionId, string aName);
   485 
   486 
   487         /// <summary>
   488         ///
   489         /// </summary>
   490         /// <param name="aSessionId"></param>
   491         /// <param name="aCallback"></param>
   492         public void AddClientThreadSafe(string aSessionId, IDisplayServiceCallback aCallback)
   493         {
   494             if (this.InvokeRequired)
   495             {
   496                 //Not in the proper thread, invoke ourselves
   497                 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
   498                 this.Invoke(d, new object[] { aSessionId, aCallback });
   499             }
   500             else
   501             {
   502                 //We are in the proper thread
   503                 //Add this session to our collection of clients
   504                 ClientData newClient = new ClientData(aSessionId, aCallback);
   505                 Program.iMainForm.iClients.Add(aSessionId, newClient);
   506                 //Add this session to our UI
   507                 UpdateClientTreeViewNode(newClient);
   508             }
   509         }
   510 
   511         /// <summary>
   512         ///
   513         /// </summary>
   514         /// <param name="aSessionId"></param>
   515         public void RemoveClientThreadSafe(string aSessionId)
   516         {
   517             if (this.InvokeRequired)
   518             {
   519                 //Not in the proper thread, invoke ourselves
   520                 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
   521                 this.Invoke(d, new object[] { aSessionId });
   522             }
   523             else
   524             {
   525                 //We are in the proper thread
   526                 //Remove this session from both client collection and UI tree view
   527                 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
   528                 {
   529                     Program.iMainForm.iClients.Remove(aSessionId);
   530                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
   531                 }
   532 
   533                 if (iClosing && iClients.Count == 0)
   534                 {
   535                     //We were closing our form
   536                     //All clients are now closed
   537                     //Just resume our close operation
   538                     iClosing = false;
   539                     Close();
   540                 }
   541             }
   542         }
   543 
   544         /// <summary>
   545         ///
   546         /// </summary>
   547         /// <param name="aLineIndex"></param>
   548         /// <param name="aText"></param>
   549         public void SetTextThreadSafe(string aSessionId, TextField aTextField)
   550         {
   551             if (this.InvokeRequired)
   552             {
   553                 //Not in the proper thread, invoke ourselves
   554                 SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
   555                 this.Invoke(d, new object[] { aSessionId, aTextField });
   556             }
   557             else
   558             {
   559                 ClientData client = iClients[aSessionId];
   560                 if (client != null)
   561                 {
   562                     //Make sure all our texts are in place
   563                     while (client.Texts.Count < (aTextField.Index + 1))
   564                     {
   565                         //Add a text field with proper index
   566                         client.Texts.Add(new TextField(client.Texts.Count));
   567                     }
   568                     client.Texts[aTextField.Index] = aTextField;
   569 
   570                     //We are in the proper thread
   571                     //Only support two lines for now
   572                     if (aTextField.Index == 0)
   573                     {
   574                         marqueeLabelTop.Text = aTextField.Text;
   575                         marqueeLabelTop.TextAlign = aTextField.Alignment;
   576                     }
   577                     else if (aTextField.Index == 1)
   578                     {
   579                         marqueeLabelBottom.Text = aTextField.Text;
   580                         marqueeLabelBottom.TextAlign = aTextField.Alignment;
   581                     }
   582 
   583 
   584                     UpdateClientTreeViewNode(client);
   585                 }
   586             }
   587         }
   588 
   589         /// <summary>
   590         ///
   591         /// </summary>
   592         /// <param name="aTexts"></param>
   593         public void SetTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<TextField> aTextFields)
   594         {
   595             if (this.InvokeRequired)
   596             {
   597                 //Not in the proper thread, invoke ourselves
   598                 SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
   599                 this.Invoke(d, new object[] { aSessionId, aTextFields });
   600             }
   601             else
   602             {
   603                 //We are in the proper thread
   604                 ClientData client = iClients[aSessionId];
   605                 if (client != null)
   606                 {
   607                     //Populate our client with the given text fields
   608                     int j = 0;
   609                     foreach (TextField textField in aTextFields)
   610                     {
   611                         if (client.Texts.Count < (j + 1))
   612                         {
   613                             client.Texts.Add(textField);
   614                         }
   615                         else
   616                         {
   617                             client.Texts[j] = textField;
   618                         }
   619                         j++;
   620                     }                    
   621                     //Only support two lines for now
   622                     for (int i = 0; i < aTextFields.Count; i++)
   623                     {
   624                         if (aTextFields[i].Index == 0)
   625                         {
   626                             marqueeLabelTop.Text = aTextFields[i].Text;
   627                             marqueeLabelTop.TextAlign = aTextFields[i].Alignment;
   628                         }
   629                         else if (aTextFields[i].Index == 1)
   630                         {
   631                             marqueeLabelBottom.Text = aTextFields[i].Text;
   632                             marqueeLabelBottom.TextAlign = aTextFields[i].Alignment;
   633                         }
   634                     }
   635 
   636 
   637                     UpdateClientTreeViewNode(client);
   638                 }
   639             }
   640         }
   641 
   642 
   643         /// <summary>
   644         ///
   645         /// </summary>
   646         /// <param name="aSessionId"></param>
   647         /// <param name="aName"></param>
   648         public void SetClientNameThreadSafe(string aSessionId, string aName)
   649         {
   650             if (this.InvokeRequired)
   651             {
   652                 //Not in the proper thread, invoke ourselves
   653                 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
   654                 this.Invoke(d, new object[] { aSessionId, aName });
   655             }
   656             else
   657             {
   658                 //We are in the proper thread
   659                 //Get our client
   660                 ClientData client = iClients[aSessionId];
   661                 if (client != null)
   662                 {
   663                     //Set its name
   664                     client.Name = aName;
   665                     //Update our tree-view
   666                     UpdateClientTreeViewNode(client);
   667                 }
   668             }
   669         }
   670 
   671         /// <summary>
   672         ///
   673         /// </summary>
   674         /// <param name="aClient"></param>
   675         private void UpdateClientTreeViewNode(ClientData aClient)
   676         {
   677             if (aClient == null)
   678             {
   679                 return;
   680             }
   681 
   682             TreeNode node = null;
   683             //Check that our client node already exists
   684             //Get our client root node using its key which is our session ID
   685             TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
   686             if (nodes.Count()>0)
   687             {
   688                 //We already have a node for that client
   689                 node = nodes[0];
   690                 //Clear children as we are going to recreate them below
   691                 node.Nodes.Clear();
   692             }
   693             else
   694             {
   695                 //Client node does not exists create a new one
   696                 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
   697                 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
   698             }
   699 
   700             if (node != null)
   701             {
   702                 //Change its name
   703                 if (aClient.Name != "")
   704                 {
   705                     //We have a name, us it as text for our root node
   706                     node.Text = aClient.Name;
   707                     //Add a child with SessionId
   708                     node.Nodes.Add(new TreeNode(aClient.SessionId));
   709                 }
   710                 else
   711                 {
   712                     //No name, use session ID instead
   713                     node.Text = aClient.SessionId;
   714                 }
   715 
   716                 if (aClient.Texts.Count > 0)
   717                 {
   718                     //Create root node for our texts
   719                     TreeNode textsRoot = new TreeNode("Text");
   720                     node.Nodes.Add(textsRoot);
   721                     //For each text add a new entry
   722                     foreach (TextField field in aClient.Texts)
   723                     {
   724                         textsRoot.Nodes.Add(new TreeNode(field.Text));
   725                     }
   726                 }
   727 
   728                 node.ExpandAll();
   729             }
   730         }
   731 
   732         private void buttonAddRow_Click(object sender, EventArgs e)
   733         {
   734             if (tableLayoutPanel.RowCount < 6)
   735             {
   736                 tableLayoutPanel.RowCount++;
   737                 CheckFontHeight();
   738             }
   739         }
   740 
   741         private void buttonRemoveRow_Click(object sender, EventArgs e)
   742         {
   743             if (tableLayoutPanel.RowCount > 1)
   744             {
   745                 tableLayoutPanel.RowCount--;
   746                 CheckFontHeight();
   747             }
   748         }
   749 
   750         private void buttonAddColumn_Click(object sender, EventArgs e)
   751         {
   752             if (tableLayoutPanel.ColumnCount < 8)
   753             {
   754                 tableLayoutPanel.ColumnCount++;
   755                 //CheckFontHeight();
   756             }
   757         }
   758 
   759         private void buttonRemoveColumn_Click(object sender, EventArgs e)
   760         {
   761             if (tableLayoutPanel.ColumnCount > 1)
   762             {
   763                 tableLayoutPanel.ColumnCount--;
   764                 //CheckFontHeight();
   765             }
   766         }
   767 
   768         private void buttonAlignLeft_Click(object sender, EventArgs e)
   769         {
   770             marqueeLabelTop.TextAlign = ContentAlignment.MiddleLeft;
   771             marqueeLabelBottom.TextAlign = ContentAlignment.MiddleLeft;
   772         }
   773 
   774         private void buttonAlignCenter_Click(object sender, EventArgs e)
   775         {
   776             marqueeLabelTop.TextAlign = ContentAlignment.MiddleCenter;
   777             marqueeLabelBottom.TextAlign = ContentAlignment.MiddleCenter;
   778         }
   779 
   780         private void buttonAlignRight_Click(object sender, EventArgs e)
   781         {
   782             marqueeLabelTop.TextAlign = ContentAlignment.MiddleRight;
   783             marqueeLabelBottom.TextAlign = ContentAlignment.MiddleRight;
   784         }
   785 
   786     }
   787 
   788     /// <summary>
   789     /// A UI thread copy of a client relevant data.
   790     /// Keeping this copy in the UI thread helps us deal with threading issues.
   791     /// </summary>
   792     public class ClientData
   793     {
   794         public ClientData(string aSessionId, IDisplayServiceCallback aCallback)
   795         {
   796             SessionId = aSessionId;
   797             Name = "";
   798             Texts = new List<TextField>();
   799             Callback = aCallback;
   800         }
   801 
   802         public string SessionId { get; set; }
   803         public string Name { get; set; }
   804         public List<TextField> Texts { get; set; }
   805         public IDisplayServiceCallback Callback { get; set; }
   806     }
   807 }