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