Server/MainForm.cs
author sl
Sun, 31 Aug 2014 16:12:59 +0200
changeset 48 9039acfde091
parent 47 c9e3d1389d06
child 50 ba4cad33db58
permissions -rw-r--r--
Extending our settings framework to store custom settings for each display type.
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@12
   150
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
sl@12
   151
                        if (iDisplay.PowerSupplyStatus())
sl@12
   152
                        {
sl@12
   153
                            toolStripStatusLabelPower.Text = "ON";
sl@12
   154
                        }
sl@12
   155
                        else
sl@12
   156
                        {
sl@12
   157
                            toolStripStatusLabelPower.Text = "OFF";
sl@12
   158
                        }
sl@12
   159
                        //Issue next request then
sl@12
   160
                        iDisplay.RequestDeviceId();
sl@12
   161
                        break;
sl@12
   162
sl@12
   163
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
sl@12
   164
                        toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
sl@12
   165
                        //Issue next request then
sl@12
   166
                        iDisplay.RequestFirmwareRevision();
sl@12
   167
                        break;
sl@12
   168
sl@12
   169
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
sl@12
   170
                        toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
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@12
   273
                iDisplay.RequestPowerSupplyStatus();
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@48
   322
        private DisplaySettingsEntry cds
sl@48
   323
        {
sl@48
   324
            get
sl@48
   325
            {
sl@48
   326
                DisplaySettings settings = Properties.Settings.Default.DisplaySettings;
sl@48
   327
sl@48
   328
                //Make sure all our settings have been created
sl@48
   329
                while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
sl@48
   330
                {
sl@48
   331
                    settings.Displays.Add(new DisplaySettingsEntry());
sl@48
   332
                }
sl@48
   333
sl@48
   334
                DisplaySettingsEntry displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
sl@48
   335
                return displaySettings;
sl@48
   336
            }
sl@48
   337
        }
sl@48
   338
sl@7
   339
        private void UpdateStatus()
sl@7
   340
        {
sl@48
   341
            //Synchronize UI with settings
sl@48
   342
            //Load settings
sl@48
   343
            marqueeLabelTop.Font = cds.Font;
sl@48
   344
            marqueeLabelBottom.Font = cds.Font;
sl@48
   345
            checkBoxShowBorders.Checked = cds.ShowBorders;
sl@48
   346
            checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
sl@48
   347
            checkBoxReverseScreen.Checked = cds.ReverseScreen;
sl@48
   348
            comboBoxDisplayType.SelectedIndex = cds.DisplayType;
sl@48
   349
            timer.Interval = cds.TimerInterval;
sl@48
   350
            maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
sl@48
   351
sl@48
   352
sl@7
   353
            if (iDisplay.IsOpen())
sl@7
   354
            {
sl@48
   355
                //Only setup brightness if display is open
sl@48
   356
                trackBarBrightness.Minimum = iDisplay.MinBrightness();
sl@48
   357
                trackBarBrightness.Maximum = iDisplay.MaxBrightness();
sl@48
   358
                trackBarBrightness.Value = cds.Brightness;
sl@48
   359
                trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
sl@48
   360
                trackBarBrightness.SmallChange = 1;
sl@48
   361
                iDisplay.SetBrightness(cds.Brightness);
sl@48
   362
                //
sl@7
   363
                buttonFill.Enabled = true;
sl@7
   364
                buttonClear.Enabled = true;
sl@7
   365
                buttonOpen.Enabled = false;
sl@7
   366
                buttonClose.Enabled = true;
sl@7
   367
                trackBarBrightness.Enabled = true;
sl@10
   368
                toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
sl@10
   369
                //+ " - " + iDisplay.SerialNumber();
sl@7
   370
            }
sl@7
   371
            else
sl@7
   372
            {
sl@7
   373
                buttonFill.Enabled = false;
sl@7
   374
                buttonClear.Enabled = false;
sl@7
   375
                buttonOpen.Enabled = true;
sl@7
   376
                buttonClose.Enabled = false;
sl@7
   377
                trackBarBrightness.Enabled = false;
sl@9
   378
                toolStripStatusLabelConnect.Text = "Disconnected";
sl@48
   379
                toolStripStatusLabelPower.Text = "N/A";
sl@7
   380
            }
sl@7
   381
        }
sl@9
   382
sl@13
   383
sl@13
   384
sl@9
   385
        private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
sl@9
   386
        {
sl@16
   387
            //Save our show borders setting
sl@13
   388
            tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@48
   389
            cds.ShowBorders = checkBoxShowBorders.Checked;
sl@9
   390
            Properties.Settings.Default.Save();
sl@9
   391
        }
sl@13
   392
sl@13
   393
        private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
sl@13
   394
        {
sl@16
   395
            //Save our connect on startup setting
sl@13
   396
            Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
sl@13
   397
            Properties.Settings.Default.Save();
sl@13
   398
        }
sl@13
   399
sl@16
   400
        private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
sl@16
   401
        {
sl@16
   402
            //Save our reverse screen setting
sl@48
   403
            cds.ReverseScreen = checkBoxReverseScreen.Checked;
sl@16
   404
            Properties.Settings.Default.Save();
sl@16
   405
        }
sl@16
   406
sl@14
   407
        private void MainForm_Resize(object sender, EventArgs e)
sl@14
   408
        {
sl@14
   409
            if (WindowState == FormWindowState.Minimized)
sl@14
   410
            {
sl@14
   411
                // Do some stuff
sl@14
   412
                //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
   413
                iCreateBitmap = true;
sl@14
   414
            }
sl@14
   415
        }
sl@14
   416
sl@17
   417
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
sl@17
   418
        {
sl@17
   419
            StopServer();
sl@32
   420
            e.Cancel = iClosing;
sl@17
   421
        }
sl@17
   422
sl@17
   423
        public void StartServer()
sl@17
   424
        {
sl@17
   425
            iServiceHost = new ServiceHost
sl@17
   426
                (
sl@17
   427
                    typeof(DisplayServer),
sl@20
   428
                    new Uri[] { new Uri("net.tcp://localhost:8001/") }
sl@17
   429
                );
sl@17
   430
sl@30
   431
            iServiceHost.AddServiceEndpoint(typeof(IDisplayService), new NetTcpBinding(SecurityMode.None,true), "DisplayService");
sl@17
   432
            iServiceHost.Open();
sl@17
   433
        }
sl@17
   434
sl@17
   435
        public void StopServer()
sl@17
   436
        {
sl@32
   437
            if (iClients.Count > 0 && !iClosing)
sl@29
   438
            {
sl@29
   439
                //Tell our clients
sl@32
   440
                iClosing = true;
sl@29
   441
                BroadcastCloseEvent();
sl@29
   442
            }
sl@32
   443
            else if (iClosing)
sl@32
   444
            {
sl@32
   445
                if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
sl@32
   446
                {
sl@32
   447
                    iClosing = false; //We make sure we force close if asked twice
sl@32
   448
                }
sl@32
   449
            }
sl@32
   450
            else
sl@36
   451
            {
sl@32
   452
                //We removed that as it often lags for some reason
sl@32
   453
                //iServiceHost.Close();
sl@32
   454
            }
sl@17
   455
        }
sl@17
   456
sl@21
   457
        public void BroadcastCloseEvent()
sl@21
   458
        {
sl@31
   459
            Trace.TraceInformation("BroadcastCloseEvent - start");
sl@31
   460
sl@21
   461
            var inactiveClients = new List<string>();
sl@21
   462
            foreach (var client in iClients)
sl@21
   463
            {
sl@21
   464
                //if (client.Key != eventData.ClientName)
sl@21
   465
                {
sl@21
   466
                    try
sl@21
   467
                    {
sl@31
   468
                        Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
sl@33
   469
                        client.Value.Callback.OnCloseOrder(/*eventData*/);
sl@21
   470
                    }
sl@21
   471
                    catch (Exception ex)
sl@21
   472
                    {
sl@21
   473
                        inactiveClients.Add(client.Key);
sl@21
   474
                    }
sl@21
   475
                }
sl@21
   476
            }
sl@21
   477
sl@21
   478
            if (inactiveClients.Count > 0)
sl@21
   479
            {
sl@21
   480
                foreach (var client in inactiveClients)
sl@21
   481
                {
sl@21
   482
                    iClients.Remove(client);
sl@30
   483
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
sl@21
   484
                }
sl@21
   485
            }
sl@21
   486
        }
sl@21
   487
sl@25
   488
        private void buttonStartClient_Click(object sender, EventArgs e)
sl@25
   489
        {
sl@25
   490
            Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
sl@25
   491
            clientThread.Start();
sl@36
   492
            BringToFront();
sl@25
   493
        }
sl@25
   494
sl@27
   495
        private void buttonSuspend_Click(object sender, EventArgs e)
sl@27
   496
        {
sl@27
   497
            timer.Enabled = !timer.Enabled;
sl@27
   498
            if (!timer.Enabled)
sl@27
   499
            {
sl@27
   500
                buttonSuspend.Text = "Suspend";
sl@27
   501
            }
sl@27
   502
            else
sl@27
   503
            {
sl@27
   504
                buttonSuspend.Text = "Pause";
sl@27
   505
            }
sl@27
   506
        }
sl@27
   507
sl@29
   508
        private void buttonCloseClients_Click(object sender, EventArgs e)
sl@29
   509
        {
sl@29
   510
            BroadcastCloseEvent();
sl@29
   511
        }
sl@29
   512
sl@30
   513
        private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
sl@30
   514
        {
sl@21
   515
sl@30
   516
        }
sl@30
   517
sl@36
   518
        //Delegates are used for our thread safe method
sl@30
   519
        public delegate void AddClientDelegate(string aSessionId, IDisplayServiceCallback aCallback);
sl@30
   520
        public delegate void RemoveClientDelegate(string aSessionId);
sl@43
   521
        public delegate void SetTextDelegate(string SessionId, TextField aTextField);
sl@43
   522
        public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList<TextField> aTextFields);
sl@32
   523
        public delegate void SetClientNameDelegate(string aSessionId, string aName);
sl@30
   524
sl@36
   525
sl@30
   526
        /// <summary>
sl@36
   527
        ///
sl@30
   528
        /// </summary>
sl@30
   529
        /// <param name="aSessionId"></param>
sl@30
   530
        /// <param name="aCallback"></param>
sl@30
   531
        public void AddClientThreadSafe(string aSessionId, IDisplayServiceCallback aCallback)
sl@30
   532
        {
sl@33
   533
            if (this.InvokeRequired)
sl@30
   534
            {
sl@30
   535
                //Not in the proper thread, invoke ourselves
sl@30
   536
                AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
sl@30
   537
                this.Invoke(d, new object[] { aSessionId, aCallback });
sl@30
   538
            }
sl@30
   539
            else
sl@30
   540
            {
sl@30
   541
                //We are in the proper thread
sl@30
   542
                //Add this session to our collection of clients
sl@33
   543
                ClientData newClient = new ClientData(aSessionId, aCallback);
sl@33
   544
                Program.iMainForm.iClients.Add(aSessionId, newClient);
sl@30
   545
                //Add this session to our UI
sl@33
   546
                UpdateClientTreeViewNode(newClient);
sl@30
   547
            }
sl@30
   548
        }
sl@30
   549
sl@30
   550
        /// <summary>
sl@36
   551
        ///
sl@30
   552
        /// </summary>
sl@30
   553
        /// <param name="aSessionId"></param>
sl@30
   554
        public void RemoveClientThreadSafe(string aSessionId)
sl@30
   555
        {
sl@33
   556
            if (this.InvokeRequired)
sl@30
   557
            {
sl@30
   558
                //Not in the proper thread, invoke ourselves
sl@30
   559
                RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
sl@30
   560
                this.Invoke(d, new object[] { aSessionId });
sl@30
   561
            }
sl@30
   562
            else
sl@30
   563
            {
sl@30
   564
                //We are in the proper thread
sl@33
   565
                //Remove this session from both client collection and UI tree view
sl@30
   566
                if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
sl@30
   567
                {
sl@30
   568
                    Program.iMainForm.iClients.Remove(aSessionId);
sl@30
   569
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
sl@32
   570
                }
sl@32
   571
sl@32
   572
                if (iClosing && iClients.Count == 0)
sl@32
   573
                {
sl@32
   574
                    //We were closing our form
sl@32
   575
                    //All clients are now closed
sl@32
   576
                    //Just resume our close operation
sl@32
   577
                    iClosing = false;
sl@32
   578
                    Close();
sl@32
   579
                }
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="aLineIndex"></param>
sl@30
   587
        /// <param name="aText"></param>
sl@43
   588
        public void SetTextThreadSafe(string aSessionId, TextField aTextField)
sl@30
   589
        {
sl@33
   590
            if (this.InvokeRequired)
sl@30
   591
            {
sl@30
   592
                //Not in the proper thread, invoke ourselves
sl@30
   593
                SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
sl@43
   594
                this.Invoke(d, new object[] { aSessionId, aTextField });
sl@30
   595
            }
sl@30
   596
            else
sl@30
   597
            {
sl@34
   598
                ClientData client = iClients[aSessionId];
sl@34
   599
                if (client != null)
sl@30
   600
                {
sl@34
   601
                    //Make sure all our texts are in place
sl@43
   602
                    while (client.Texts.Count < (aTextField.Index + 1))
sl@34
   603
                    {
sl@43
   604
                        //Add a text field with proper index
sl@43
   605
                        client.Texts.Add(new TextField(client.Texts.Count));
sl@34
   606
                    }
sl@43
   607
                    client.Texts[aTextField.Index] = aTextField;
sl@34
   608
sl@34
   609
                    //We are in the proper thread
sl@34
   610
                    //Only support two lines for now
sl@43
   611
                    if (aTextField.Index == 0)
sl@34
   612
                    {
sl@43
   613
                        marqueeLabelTop.Text = aTextField.Text;
sl@43
   614
                        marqueeLabelTop.TextAlign = aTextField.Alignment;
sl@34
   615
                    }
sl@43
   616
                    else if (aTextField.Index == 1)
sl@34
   617
                    {
sl@43
   618
                        marqueeLabelBottom.Text = aTextField.Text;
sl@43
   619
                        marqueeLabelBottom.TextAlign = aTextField.Alignment;
sl@34
   620
                    }
sl@34
   621
sl@34
   622
sl@34
   623
                    UpdateClientTreeViewNode(client);
sl@30
   624
                }
sl@30
   625
            }
sl@30
   626
        }
sl@30
   627
sl@30
   628
        /// <summary>
sl@36
   629
        ///
sl@30
   630
        /// </summary>
sl@30
   631
        /// <param name="aTexts"></param>
sl@43
   632
        public void SetTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<TextField> aTextFields)
sl@30
   633
        {
sl@33
   634
            if (this.InvokeRequired)
sl@30
   635
            {
sl@30
   636
                //Not in the proper thread, invoke ourselves
sl@30
   637
                SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
sl@43
   638
                this.Invoke(d, new object[] { aSessionId, aTextFields });
sl@30
   639
            }
sl@30
   640
            else
sl@30
   641
            {
sl@43
   642
                //We are in the proper thread
sl@34
   643
                ClientData client = iClients[aSessionId];
sl@34
   644
                if (client != null)
sl@30
   645
                {
sl@43
   646
                    //Populate our client with the given text fields
sl@34
   647
                    int j = 0;
sl@43
   648
                    foreach (TextField textField in aTextFields)
sl@30
   649
                    {
sl@34
   650
                        if (client.Texts.Count < (j + 1))
sl@34
   651
                        {
sl@43
   652
                            client.Texts.Add(textField);
sl@34
   653
                        }
sl@34
   654
                        else
sl@34
   655
                        {
sl@43
   656
                            client.Texts[j] = textField;
sl@34
   657
                        }
sl@34
   658
                        j++;
sl@43
   659
                    }                    
sl@34
   660
                    //Only support two lines for now
sl@43
   661
                    for (int i = 0; i < aTextFields.Count; i++)
sl@30
   662
                    {
sl@43
   663
                        if (aTextFields[i].Index == 0)
sl@34
   664
                        {
sl@43
   665
                            marqueeLabelTop.Text = aTextFields[i].Text;
sl@43
   666
                            marqueeLabelTop.TextAlign = aTextFields[i].Alignment;
sl@34
   667
                        }
sl@43
   668
                        else if (aTextFields[i].Index == 1)
sl@34
   669
                        {
sl@43
   670
                            marqueeLabelBottom.Text = aTextFields[i].Text;
sl@43
   671
                            marqueeLabelBottom.TextAlign = aTextFields[i].Alignment;
sl@34
   672
                        }
sl@30
   673
                    }
sl@34
   674
sl@34
   675
sl@34
   676
                    UpdateClientTreeViewNode(client);
sl@30
   677
                }
sl@30
   678
            }
sl@32
   679
        }
sl@30
   680
sl@32
   681
sl@32
   682
        /// <summary>
sl@36
   683
        ///
sl@32
   684
        /// </summary>
sl@32
   685
        /// <param name="aSessionId"></param>
sl@32
   686
        /// <param name="aName"></param>
sl@32
   687
        public void SetClientNameThreadSafe(string aSessionId, string aName)
sl@32
   688
        {
sl@32
   689
            if (this.InvokeRequired)
sl@32
   690
            {
sl@32
   691
                //Not in the proper thread, invoke ourselves
sl@32
   692
                SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
sl@32
   693
                this.Invoke(d, new object[] { aSessionId, aName });
sl@32
   694
            }
sl@32
   695
            else
sl@32
   696
            {
sl@32
   697
                //We are in the proper thread
sl@33
   698
                //Get our client
sl@33
   699
                ClientData client = iClients[aSessionId];
sl@33
   700
                if (client != null)
sl@32
   701
                {
sl@33
   702
                    //Set its name
sl@33
   703
                    client.Name = aName;
sl@33
   704
                    //Update our tree-view
sl@33
   705
                    UpdateClientTreeViewNode(client);
sl@33
   706
                }
sl@33
   707
            }
sl@33
   708
        }
sl@33
   709
sl@33
   710
        /// <summary>
sl@36
   711
        ///
sl@33
   712
        /// </summary>
sl@33
   713
        /// <param name="aClient"></param>
sl@33
   714
        private void UpdateClientTreeViewNode(ClientData aClient)
sl@33
   715
        {
sl@33
   716
            if (aClient == null)
sl@33
   717
            {
sl@33
   718
                return;
sl@33
   719
            }
sl@33
   720
sl@33
   721
            TreeNode node = null;
sl@33
   722
            //Check that our client node already exists
sl@33
   723
            //Get our client root node using its key which is our session ID
sl@33
   724
            TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
sl@33
   725
            if (nodes.Count()>0)
sl@33
   726
            {
sl@33
   727
                //We already have a node for that client
sl@33
   728
                node = nodes[0];
sl@33
   729
                //Clear children as we are going to recreate them below
sl@33
   730
                node.Nodes.Clear();
sl@33
   731
            }
sl@33
   732
            else
sl@33
   733
            {
sl@33
   734
                //Client node does not exists create a new one
sl@33
   735
                treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
sl@33
   736
                node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
sl@33
   737
            }
sl@33
   738
sl@33
   739
            if (node != null)
sl@33
   740
            {
sl@33
   741
                //Change its name
sl@33
   742
                if (aClient.Name != "")
sl@33
   743
                {
sl@33
   744
                    //We have a name, us it as text for our root node
sl@33
   745
                    node.Text = aClient.Name;
sl@32
   746
                    //Add a child with SessionId
sl@33
   747
                    node.Nodes.Add(new TreeNode(aClient.SessionId));
sl@33
   748
                }
sl@33
   749
                else
sl@33
   750
                {
sl@33
   751
                    //No name, use session ID instead
sl@33
   752
                    node.Text = aClient.SessionId;
sl@33
   753
                }
sl@36
   754
sl@33
   755
                if (aClient.Texts.Count > 0)
sl@33
   756
                {
sl@33
   757
                    //Create root node for our texts
sl@33
   758
                    TreeNode textsRoot = new TreeNode("Text");
sl@33
   759
                    node.Nodes.Add(textsRoot);
sl@33
   760
                    //For each text add a new entry
sl@43
   761
                    foreach (TextField field in aClient.Texts)
sl@33
   762
                    {
sl@43
   763
                        textsRoot.Nodes.Add(new TreeNode(field.Text));
sl@33
   764
                    }
sl@32
   765
                }
sl@34
   766
sl@34
   767
                node.ExpandAll();
sl@32
   768
            }
sl@30
   769
        }
sl@17
   770
sl@38
   771
        private void buttonAddRow_Click(object sender, EventArgs e)
sl@38
   772
        {
sl@38
   773
            if (tableLayoutPanel.RowCount < 6)
sl@38
   774
            {
sl@38
   775
                tableLayoutPanel.RowCount++;
sl@38
   776
                CheckFontHeight();
sl@38
   777
            }
sl@38
   778
        }
sl@38
   779
sl@38
   780
        private void buttonRemoveRow_Click(object sender, EventArgs e)
sl@38
   781
        {
sl@38
   782
            if (tableLayoutPanel.RowCount > 1)
sl@38
   783
            {
sl@38
   784
                tableLayoutPanel.RowCount--;
sl@38
   785
                CheckFontHeight();
sl@38
   786
            }
sl@38
   787
        }
sl@38
   788
sl@38
   789
        private void buttonAddColumn_Click(object sender, EventArgs e)
sl@38
   790
        {
sl@38
   791
            if (tableLayoutPanel.ColumnCount < 8)
sl@38
   792
            {
sl@38
   793
                tableLayoutPanel.ColumnCount++;
sl@38
   794
                //CheckFontHeight();
sl@38
   795
            }
sl@38
   796
        }
sl@38
   797
sl@38
   798
        private void buttonRemoveColumn_Click(object sender, EventArgs e)
sl@38
   799
        {
sl@38
   800
            if (tableLayoutPanel.ColumnCount > 1)
sl@38
   801
            {
sl@38
   802
                tableLayoutPanel.ColumnCount--;
sl@38
   803
                //CheckFontHeight();
sl@38
   804
            }
sl@38
   805
        }
sl@38
   806
sl@41
   807
        private void buttonAlignLeft_Click(object sender, EventArgs e)
sl@41
   808
        {
sl@41
   809
            marqueeLabelTop.TextAlign = ContentAlignment.MiddleLeft;
sl@41
   810
            marqueeLabelBottom.TextAlign = ContentAlignment.MiddleLeft;
sl@41
   811
        }
sl@41
   812
sl@41
   813
        private void buttonAlignCenter_Click(object sender, EventArgs e)
sl@41
   814
        {
sl@41
   815
            marqueeLabelTop.TextAlign = ContentAlignment.MiddleCenter;
sl@41
   816
            marqueeLabelBottom.TextAlign = ContentAlignment.MiddleCenter;
sl@41
   817
        }
sl@41
   818
sl@41
   819
        private void buttonAlignRight_Click(object sender, EventArgs e)
sl@41
   820
        {
sl@41
   821
            marqueeLabelTop.TextAlign = ContentAlignment.MiddleRight;
sl@41
   822
            marqueeLabelBottom.TextAlign = ContentAlignment.MiddleRight;
sl@41
   823
        }
sl@36
   824
sl@46
   825
        private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
sl@46
   826
        {
sl@48
   827
            Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
sl@48
   828
            cds.DisplayType = comboBoxDisplayType.SelectedIndex;
sl@46
   829
            Properties.Settings.Default.Save();
sl@46
   830
            OpenDisplayConnection();
sl@46
   831
        }
sl@46
   832
sl@47
   833
sl@47
   834
        private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
sl@47
   835
        {
sl@47
   836
            if (maskedTextBoxTimerInterval.Text != "")
sl@47
   837
            {
sl@47
   838
                timer.Interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
sl@48
   839
                cds.TimerInterval = timer.Interval;
sl@47
   840
                Properties.Settings.Default.Save();
sl@47
   841
            }
sl@47
   842
        }
sl@47
   843
sl@0
   844
    }
sl@34
   845
sl@34
   846
    /// <summary>
sl@34
   847
    /// A UI thread copy of a client relevant data.
sl@34
   848
    /// Keeping this copy in the UI thread helps us deal with threading issues.
sl@34
   849
    /// </summary>
sl@34
   850
    public class ClientData
sl@34
   851
    {
sl@34
   852
        public ClientData(string aSessionId, IDisplayServiceCallback aCallback)
sl@34
   853
        {
sl@34
   854
            SessionId = aSessionId;
sl@34
   855
            Name = "";
sl@43
   856
            Texts = new List<TextField>();
sl@34
   857
            Callback = aCallback;
sl@34
   858
        }
sl@34
   859
sl@34
   860
        public string SessionId { get; set; }
sl@34
   861
        public string Name { get; set; }
sl@43
   862
        public List<TextField> Texts { get; set; }
sl@34
   863
        public IDisplayServiceCallback Callback { get; set; }
sl@34
   864
    }
sl@0
   865
}