Server/MainForm.cs
author sl
Sun, 31 Aug 2014 21:34:58 +0200
changeset 53 f7ad2dce46a9
parent 52 b22b0127afa4
child 54 fdda7642776a
permissions -rw-r--r--
GP1212A02: Clock support.
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@52
   376
sl@52
   377
                if (iDisplay.SupportPowerOnOff())
sl@52
   378
                {
sl@52
   379
                    buttonPowerOn.Enabled = true;
sl@52
   380
                    buttonPowerOff.Enabled = true;
sl@52
   381
                }
sl@52
   382
                else
sl@52
   383
                {
sl@52
   384
                    buttonPowerOn.Enabled = false;
sl@52
   385
                    buttonPowerOff.Enabled = false;
sl@52
   386
                }
sl@53
   387
sl@53
   388
                if (iDisplay.SupportClock())
sl@53
   389
                {
sl@53
   390
                    buttonShowClock.Enabled = true;
sl@53
   391
                    buttonHideClock.Enabled = true;
sl@53
   392
                }
sl@53
   393
                else
sl@53
   394
                {
sl@53
   395
                    buttonShowClock.Enabled = false;
sl@53
   396
                    buttonHideClock.Enabled = false;
sl@53
   397
                }
sl@7
   398
            }
sl@7
   399
            else
sl@7
   400
            {
sl@7
   401
                buttonFill.Enabled = false;
sl@7
   402
                buttonClear.Enabled = false;
sl@7
   403
                buttonOpen.Enabled = true;
sl@7
   404
                buttonClose.Enabled = false;
sl@7
   405
                trackBarBrightness.Enabled = false;
sl@52
   406
                buttonPowerOn.Enabled = false;
sl@52
   407
                buttonPowerOff.Enabled = false;
sl@53
   408
                buttonShowClock.Enabled = false;
sl@53
   409
                buttonHideClock.Enabled = false;
sl@9
   410
                toolStripStatusLabelConnect.Text = "Disconnected";
sl@48
   411
                toolStripStatusLabelPower.Text = "N/A";
sl@7
   412
            }
sl@7
   413
        }
sl@9
   414
sl@13
   415
sl@13
   416
sl@9
   417
        private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
sl@9
   418
        {
sl@16
   419
            //Save our show borders setting
sl@13
   420
            tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@48
   421
            cds.ShowBorders = checkBoxShowBorders.Checked;
sl@9
   422
            Properties.Settings.Default.Save();
sl@9
   423
        }
sl@13
   424
sl@13
   425
        private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
sl@13
   426
        {
sl@16
   427
            //Save our connect on startup setting
sl@13
   428
            Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
sl@13
   429
            Properties.Settings.Default.Save();
sl@13
   430
        }
sl@13
   431
sl@16
   432
        private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
sl@16
   433
        {
sl@16
   434
            //Save our reverse screen setting
sl@48
   435
            cds.ReverseScreen = checkBoxReverseScreen.Checked;
sl@16
   436
            Properties.Settings.Default.Save();
sl@16
   437
        }
sl@16
   438
sl@14
   439
        private void MainForm_Resize(object sender, EventArgs e)
sl@14
   440
        {
sl@14
   441
            if (WindowState == FormWindowState.Minimized)
sl@14
   442
            {
sl@14
   443
                // Do some stuff
sl@14
   444
                //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
   445
                iCreateBitmap = true;
sl@14
   446
            }
sl@14
   447
        }
sl@14
   448
sl@17
   449
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
sl@17
   450
        {
sl@17
   451
            StopServer();
sl@32
   452
            e.Cancel = iClosing;
sl@17
   453
        }
sl@17
   454
sl@17
   455
        public void StartServer()
sl@17
   456
        {
sl@17
   457
            iServiceHost = new ServiceHost
sl@17
   458
                (
sl@17
   459
                    typeof(DisplayServer),
sl@20
   460
                    new Uri[] { new Uri("net.tcp://localhost:8001/") }
sl@17
   461
                );
sl@17
   462
sl@30
   463
            iServiceHost.AddServiceEndpoint(typeof(IDisplayService), new NetTcpBinding(SecurityMode.None,true), "DisplayService");
sl@17
   464
            iServiceHost.Open();
sl@17
   465
        }
sl@17
   466
sl@17
   467
        public void StopServer()
sl@17
   468
        {
sl@32
   469
            if (iClients.Count > 0 && !iClosing)
sl@29
   470
            {
sl@29
   471
                //Tell our clients
sl@32
   472
                iClosing = true;
sl@29
   473
                BroadcastCloseEvent();
sl@29
   474
            }
sl@32
   475
            else if (iClosing)
sl@32
   476
            {
sl@32
   477
                if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
sl@32
   478
                {
sl@32
   479
                    iClosing = false; //We make sure we force close if asked twice
sl@32
   480
                }
sl@32
   481
            }
sl@32
   482
            else
sl@36
   483
            {
sl@32
   484
                //We removed that as it often lags for some reason
sl@32
   485
                //iServiceHost.Close();
sl@32
   486
            }
sl@17
   487
        }
sl@17
   488
sl@21
   489
        public void BroadcastCloseEvent()
sl@21
   490
        {
sl@31
   491
            Trace.TraceInformation("BroadcastCloseEvent - start");
sl@31
   492
sl@21
   493
            var inactiveClients = new List<string>();
sl@21
   494
            foreach (var client in iClients)
sl@21
   495
            {
sl@21
   496
                //if (client.Key != eventData.ClientName)
sl@21
   497
                {
sl@21
   498
                    try
sl@21
   499
                    {
sl@31
   500
                        Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
sl@33
   501
                        client.Value.Callback.OnCloseOrder(/*eventData*/);
sl@21
   502
                    }
sl@21
   503
                    catch (Exception ex)
sl@21
   504
                    {
sl@21
   505
                        inactiveClients.Add(client.Key);
sl@21
   506
                    }
sl@21
   507
                }
sl@21
   508
            }
sl@21
   509
sl@21
   510
            if (inactiveClients.Count > 0)
sl@21
   511
            {
sl@21
   512
                foreach (var client in inactiveClients)
sl@21
   513
                {
sl@21
   514
                    iClients.Remove(client);
sl@30
   515
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
sl@21
   516
                }
sl@21
   517
            }
sl@21
   518
        }
sl@21
   519
sl@25
   520
        private void buttonStartClient_Click(object sender, EventArgs e)
sl@25
   521
        {
sl@25
   522
            Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
sl@25
   523
            clientThread.Start();
sl@36
   524
            BringToFront();
sl@25
   525
        }
sl@25
   526
sl@27
   527
        private void buttonSuspend_Click(object sender, EventArgs e)
sl@27
   528
        {
sl@52
   529
            LastTickTime = DateTime.Now; //Reset timer to prevent jump
sl@27
   530
            timer.Enabled = !timer.Enabled;
sl@27
   531
            if (!timer.Enabled)
sl@27
   532
            {
sl@52
   533
                buttonSuspend.Text = "Run";
sl@27
   534
            }
sl@27
   535
            else
sl@27
   536
            {
sl@27
   537
                buttonSuspend.Text = "Pause";
sl@27
   538
            }
sl@27
   539
        }
sl@27
   540
sl@29
   541
        private void buttonCloseClients_Click(object sender, EventArgs e)
sl@29
   542
        {
sl@29
   543
            BroadcastCloseEvent();
sl@29
   544
        }
sl@29
   545
sl@30
   546
        private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
sl@30
   547
        {
sl@21
   548
sl@30
   549
        }
sl@30
   550
sl@36
   551
        //Delegates are used for our thread safe method
sl@30
   552
        public delegate void AddClientDelegate(string aSessionId, IDisplayServiceCallback aCallback);
sl@30
   553
        public delegate void RemoveClientDelegate(string aSessionId);
sl@43
   554
        public delegate void SetTextDelegate(string SessionId, TextField aTextField);
sl@43
   555
        public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList<TextField> aTextFields);
sl@32
   556
        public delegate void SetClientNameDelegate(string aSessionId, string aName);
sl@30
   557
sl@36
   558
sl@30
   559
        /// <summary>
sl@36
   560
        ///
sl@30
   561
        /// </summary>
sl@30
   562
        /// <param name="aSessionId"></param>
sl@30
   563
        /// <param name="aCallback"></param>
sl@30
   564
        public void AddClientThreadSafe(string aSessionId, IDisplayServiceCallback aCallback)
sl@30
   565
        {
sl@33
   566
            if (this.InvokeRequired)
sl@30
   567
            {
sl@30
   568
                //Not in the proper thread, invoke ourselves
sl@30
   569
                AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
sl@30
   570
                this.Invoke(d, new object[] { aSessionId, aCallback });
sl@30
   571
            }
sl@30
   572
            else
sl@30
   573
            {
sl@30
   574
                //We are in the proper thread
sl@30
   575
                //Add this session to our collection of clients
sl@33
   576
                ClientData newClient = new ClientData(aSessionId, aCallback);
sl@33
   577
                Program.iMainForm.iClients.Add(aSessionId, newClient);
sl@30
   578
                //Add this session to our UI
sl@33
   579
                UpdateClientTreeViewNode(newClient);
sl@30
   580
            }
sl@30
   581
        }
sl@30
   582
sl@30
   583
        /// <summary>
sl@36
   584
        ///
sl@30
   585
        /// </summary>
sl@30
   586
        /// <param name="aSessionId"></param>
sl@30
   587
        public void RemoveClientThreadSafe(string aSessionId)
sl@30
   588
        {
sl@33
   589
            if (this.InvokeRequired)
sl@30
   590
            {
sl@30
   591
                //Not in the proper thread, invoke ourselves
sl@30
   592
                RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
sl@30
   593
                this.Invoke(d, new object[] { aSessionId });
sl@30
   594
            }
sl@30
   595
            else
sl@30
   596
            {
sl@30
   597
                //We are in the proper thread
sl@33
   598
                //Remove this session from both client collection and UI tree view
sl@30
   599
                if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
sl@30
   600
                {
sl@30
   601
                    Program.iMainForm.iClients.Remove(aSessionId);
sl@30
   602
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
sl@32
   603
                }
sl@32
   604
sl@32
   605
                if (iClosing && iClients.Count == 0)
sl@32
   606
                {
sl@32
   607
                    //We were closing our form
sl@32
   608
                    //All clients are now closed
sl@32
   609
                    //Just resume our close operation
sl@32
   610
                    iClosing = false;
sl@32
   611
                    Close();
sl@32
   612
                }
sl@30
   613
            }
sl@30
   614
        }
sl@30
   615
sl@30
   616
        /// <summary>
sl@36
   617
        ///
sl@30
   618
        /// </summary>
sl@30
   619
        /// <param name="aLineIndex"></param>
sl@30
   620
        /// <param name="aText"></param>
sl@43
   621
        public void SetTextThreadSafe(string aSessionId, TextField aTextField)
sl@30
   622
        {
sl@33
   623
            if (this.InvokeRequired)
sl@30
   624
            {
sl@30
   625
                //Not in the proper thread, invoke ourselves
sl@30
   626
                SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
sl@43
   627
                this.Invoke(d, new object[] { aSessionId, aTextField });
sl@30
   628
            }
sl@30
   629
            else
sl@30
   630
            {
sl@34
   631
                ClientData client = iClients[aSessionId];
sl@34
   632
                if (client != null)
sl@30
   633
                {
sl@34
   634
                    //Make sure all our texts are in place
sl@43
   635
                    while (client.Texts.Count < (aTextField.Index + 1))
sl@34
   636
                    {
sl@43
   637
                        //Add a text field with proper index
sl@43
   638
                        client.Texts.Add(new TextField(client.Texts.Count));
sl@34
   639
                    }
sl@43
   640
                    client.Texts[aTextField.Index] = aTextField;
sl@34
   641
sl@34
   642
                    //We are in the proper thread
sl@34
   643
                    //Only support two lines for now
sl@43
   644
                    if (aTextField.Index == 0)
sl@34
   645
                    {
sl@43
   646
                        marqueeLabelTop.Text = aTextField.Text;
sl@43
   647
                        marqueeLabelTop.TextAlign = aTextField.Alignment;
sl@34
   648
                    }
sl@43
   649
                    else if (aTextField.Index == 1)
sl@34
   650
                    {
sl@43
   651
                        marqueeLabelBottom.Text = aTextField.Text;
sl@43
   652
                        marqueeLabelBottom.TextAlign = aTextField.Alignment;
sl@34
   653
                    }
sl@34
   654
sl@34
   655
sl@34
   656
                    UpdateClientTreeViewNode(client);
sl@30
   657
                }
sl@30
   658
            }
sl@30
   659
        }
sl@30
   660
sl@30
   661
        /// <summary>
sl@36
   662
        ///
sl@30
   663
        /// </summary>
sl@30
   664
        /// <param name="aTexts"></param>
sl@43
   665
        public void SetTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<TextField> aTextFields)
sl@30
   666
        {
sl@33
   667
            if (this.InvokeRequired)
sl@30
   668
            {
sl@30
   669
                //Not in the proper thread, invoke ourselves
sl@30
   670
                SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
sl@43
   671
                this.Invoke(d, new object[] { aSessionId, aTextFields });
sl@30
   672
            }
sl@30
   673
            else
sl@30
   674
            {
sl@43
   675
                //We are in the proper thread
sl@34
   676
                ClientData client = iClients[aSessionId];
sl@34
   677
                if (client != null)
sl@30
   678
                {
sl@43
   679
                    //Populate our client with the given text fields
sl@34
   680
                    int j = 0;
sl@43
   681
                    foreach (TextField textField in aTextFields)
sl@30
   682
                    {
sl@34
   683
                        if (client.Texts.Count < (j + 1))
sl@34
   684
                        {
sl@43
   685
                            client.Texts.Add(textField);
sl@34
   686
                        }
sl@34
   687
                        else
sl@34
   688
                        {
sl@43
   689
                            client.Texts[j] = textField;
sl@34
   690
                        }
sl@34
   691
                        j++;
sl@43
   692
                    }                    
sl@34
   693
                    //Only support two lines for now
sl@43
   694
                    for (int i = 0; i < aTextFields.Count; i++)
sl@30
   695
                    {
sl@43
   696
                        if (aTextFields[i].Index == 0)
sl@34
   697
                        {
sl@43
   698
                            marqueeLabelTop.Text = aTextFields[i].Text;
sl@43
   699
                            marqueeLabelTop.TextAlign = aTextFields[i].Alignment;
sl@34
   700
                        }
sl@43
   701
                        else if (aTextFields[i].Index == 1)
sl@34
   702
                        {
sl@43
   703
                            marqueeLabelBottom.Text = aTextFields[i].Text;
sl@43
   704
                            marqueeLabelBottom.TextAlign = aTextFields[i].Alignment;
sl@34
   705
                        }
sl@30
   706
                    }
sl@34
   707
sl@34
   708
sl@34
   709
                    UpdateClientTreeViewNode(client);
sl@30
   710
                }
sl@30
   711
            }
sl@32
   712
        }
sl@30
   713
sl@32
   714
sl@32
   715
        /// <summary>
sl@36
   716
        ///
sl@32
   717
        /// </summary>
sl@32
   718
        /// <param name="aSessionId"></param>
sl@32
   719
        /// <param name="aName"></param>
sl@32
   720
        public void SetClientNameThreadSafe(string aSessionId, string aName)
sl@32
   721
        {
sl@32
   722
            if (this.InvokeRequired)
sl@32
   723
            {
sl@32
   724
                //Not in the proper thread, invoke ourselves
sl@32
   725
                SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
sl@32
   726
                this.Invoke(d, new object[] { aSessionId, aName });
sl@32
   727
            }
sl@32
   728
            else
sl@32
   729
            {
sl@32
   730
                //We are in the proper thread
sl@33
   731
                //Get our client
sl@33
   732
                ClientData client = iClients[aSessionId];
sl@33
   733
                if (client != null)
sl@32
   734
                {
sl@33
   735
                    //Set its name
sl@33
   736
                    client.Name = aName;
sl@33
   737
                    //Update our tree-view
sl@33
   738
                    UpdateClientTreeViewNode(client);
sl@33
   739
                }
sl@33
   740
            }
sl@33
   741
        }
sl@33
   742
sl@33
   743
        /// <summary>
sl@36
   744
        ///
sl@33
   745
        /// </summary>
sl@33
   746
        /// <param name="aClient"></param>
sl@33
   747
        private void UpdateClientTreeViewNode(ClientData aClient)
sl@33
   748
        {
sl@33
   749
            if (aClient == null)
sl@33
   750
            {
sl@33
   751
                return;
sl@33
   752
            }
sl@33
   753
sl@33
   754
            TreeNode node = null;
sl@33
   755
            //Check that our client node already exists
sl@33
   756
            //Get our client root node using its key which is our session ID
sl@33
   757
            TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
sl@33
   758
            if (nodes.Count()>0)
sl@33
   759
            {
sl@33
   760
                //We already have a node for that client
sl@33
   761
                node = nodes[0];
sl@33
   762
                //Clear children as we are going to recreate them below
sl@33
   763
                node.Nodes.Clear();
sl@33
   764
            }
sl@33
   765
            else
sl@33
   766
            {
sl@33
   767
                //Client node does not exists create a new one
sl@33
   768
                treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
sl@33
   769
                node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
sl@33
   770
            }
sl@33
   771
sl@33
   772
            if (node != null)
sl@33
   773
            {
sl@33
   774
                //Change its name
sl@33
   775
                if (aClient.Name != "")
sl@33
   776
                {
sl@33
   777
                    //We have a name, us it as text for our root node
sl@33
   778
                    node.Text = aClient.Name;
sl@32
   779
                    //Add a child with SessionId
sl@33
   780
                    node.Nodes.Add(new TreeNode(aClient.SessionId));
sl@33
   781
                }
sl@33
   782
                else
sl@33
   783
                {
sl@33
   784
                    //No name, use session ID instead
sl@33
   785
                    node.Text = aClient.SessionId;
sl@33
   786
                }
sl@36
   787
sl@33
   788
                if (aClient.Texts.Count > 0)
sl@33
   789
                {
sl@33
   790
                    //Create root node for our texts
sl@33
   791
                    TreeNode textsRoot = new TreeNode("Text");
sl@33
   792
                    node.Nodes.Add(textsRoot);
sl@33
   793
                    //For each text add a new entry
sl@43
   794
                    foreach (TextField field in aClient.Texts)
sl@33
   795
                    {
sl@43
   796
                        textsRoot.Nodes.Add(new TreeNode(field.Text));
sl@33
   797
                    }
sl@32
   798
                }
sl@34
   799
sl@34
   800
                node.ExpandAll();
sl@32
   801
            }
sl@30
   802
        }
sl@17
   803
sl@38
   804
        private void buttonAddRow_Click(object sender, EventArgs e)
sl@38
   805
        {
sl@38
   806
            if (tableLayoutPanel.RowCount < 6)
sl@38
   807
            {
sl@38
   808
                tableLayoutPanel.RowCount++;
sl@38
   809
                CheckFontHeight();
sl@38
   810
            }
sl@38
   811
        }
sl@38
   812
sl@38
   813
        private void buttonRemoveRow_Click(object sender, EventArgs e)
sl@38
   814
        {
sl@38
   815
            if (tableLayoutPanel.RowCount > 1)
sl@38
   816
            {
sl@38
   817
                tableLayoutPanel.RowCount--;
sl@38
   818
                CheckFontHeight();
sl@38
   819
            }
sl@38
   820
        }
sl@38
   821
sl@38
   822
        private void buttonAddColumn_Click(object sender, EventArgs e)
sl@38
   823
        {
sl@38
   824
            if (tableLayoutPanel.ColumnCount < 8)
sl@38
   825
            {
sl@38
   826
                tableLayoutPanel.ColumnCount++;
sl@38
   827
                //CheckFontHeight();
sl@38
   828
            }
sl@38
   829
        }
sl@38
   830
sl@38
   831
        private void buttonRemoveColumn_Click(object sender, EventArgs e)
sl@38
   832
        {
sl@38
   833
            if (tableLayoutPanel.ColumnCount > 1)
sl@38
   834
            {
sl@38
   835
                tableLayoutPanel.ColumnCount--;
sl@38
   836
                //CheckFontHeight();
sl@38
   837
            }
sl@38
   838
        }
sl@38
   839
sl@41
   840
        private void buttonAlignLeft_Click(object sender, EventArgs e)
sl@41
   841
        {
sl@41
   842
            marqueeLabelTop.TextAlign = ContentAlignment.MiddleLeft;
sl@41
   843
            marqueeLabelBottom.TextAlign = ContentAlignment.MiddleLeft;
sl@41
   844
        }
sl@41
   845
sl@41
   846
        private void buttonAlignCenter_Click(object sender, EventArgs e)
sl@41
   847
        {
sl@41
   848
            marqueeLabelTop.TextAlign = ContentAlignment.MiddleCenter;
sl@41
   849
            marqueeLabelBottom.TextAlign = ContentAlignment.MiddleCenter;
sl@41
   850
        }
sl@41
   851
sl@41
   852
        private void buttonAlignRight_Click(object sender, EventArgs e)
sl@41
   853
        {
sl@41
   854
            marqueeLabelTop.TextAlign = ContentAlignment.MiddleRight;
sl@41
   855
            marqueeLabelBottom.TextAlign = ContentAlignment.MiddleRight;
sl@41
   856
        }
sl@36
   857
sl@46
   858
        private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
sl@46
   859
        {
sl@48
   860
            Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
sl@48
   861
            cds.DisplayType = comboBoxDisplayType.SelectedIndex;
sl@46
   862
            Properties.Settings.Default.Save();
sl@51
   863
            if (iDisplay.IsOpen())
sl@51
   864
            {
sl@51
   865
                OpenDisplayConnection();
sl@51
   866
            }
sl@51
   867
            else
sl@51
   868
            {
sl@51
   869
                UpdateStatus();
sl@51
   870
            }
sl@46
   871
        }
sl@46
   872
sl@47
   873
sl@47
   874
        private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
sl@47
   875
        {
sl@47
   876
            if (maskedTextBoxTimerInterval.Text != "")
sl@47
   877
            {
sl@51
   878
                int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
sl@51
   879
sl@51
   880
                if (interval > 0)
sl@51
   881
                {
sl@51
   882
                    timer.Interval = interval;
sl@51
   883
                    cds.TimerInterval = timer.Interval;
sl@51
   884
                    Properties.Settings.Default.Save();
sl@51
   885
                }
sl@47
   886
            }
sl@47
   887
        }
sl@47
   888
sl@52
   889
        private void buttonPowerOn_Click(object sender, EventArgs e)
sl@52
   890
        {
sl@52
   891
            iDisplay.PowerOn();
sl@52
   892
        }
sl@52
   893
sl@52
   894
        private void buttonPowerOff_Click(object sender, EventArgs e)
sl@52
   895
        {
sl@52
   896
            iDisplay.PowerOff();
sl@52
   897
        }
sl@52
   898
sl@53
   899
        private void buttonShowClock_Click(object sender, EventArgs e)
sl@53
   900
        {
sl@53
   901
            iDisplay.ShowClock();
sl@53
   902
        }
sl@53
   903
sl@53
   904
        private void buttonHideClock_Click(object sender, EventArgs e)
sl@53
   905
        {
sl@53
   906
            iDisplay.HideClock();
sl@53
   907
        }
sl@53
   908
sl@0
   909
    }
sl@34
   910
sl@34
   911
    /// <summary>
sl@34
   912
    /// A UI thread copy of a client relevant data.
sl@34
   913
    /// Keeping this copy in the UI thread helps us deal with threading issues.
sl@34
   914
    /// </summary>
sl@34
   915
    public class ClientData
sl@34
   916
    {
sl@34
   917
        public ClientData(string aSessionId, IDisplayServiceCallback aCallback)
sl@34
   918
        {
sl@34
   919
            SessionId = aSessionId;
sl@34
   920
            Name = "";
sl@43
   921
            Texts = new List<TextField>();
sl@34
   922
            Callback = aCallback;
sl@34
   923
        }
sl@34
   924
sl@34
   925
        public string SessionId { get; set; }
sl@34
   926
        public string Name { get; set; }
sl@43
   927
        public List<TextField> Texts { get; set; }
sl@34
   928
        public IDisplayServiceCallback Callback { get; set; }
sl@34
   929
    }
sl@0
   930
}