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