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