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