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