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