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