Server/MainForm.cs
author StephaneLenclud
Sun, 08 Feb 2015 18:34:00 +0100
changeset 113 0846e5112dd7
parent 112 57b1c6507bd7
child 114 debe115b3b22
permissions -rw-r--r--
Audio: adding support for mute status.
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@88
    16
using System.Deployment.Application;
sl@94
    17
using System.Reflection;
StephaneLenclud@112
    18
//NAudio
StephaneLenclud@112
    19
using NAudio.CoreAudioApi;
StephaneLenclud@112
    20
using NAudio.CoreAudioApi.Interfaces;
StephaneLenclud@112
    21
using System.Runtime.InteropServices;
sl@25
    22
//
sl@25
    23
using SharpDisplayClient;
sl@55
    24
using SharpDisplay;
sl@0
    25
sl@0
    26
namespace SharpDisplayManager
sl@0
    27
{
sl@58
    28
    //Types declarations
sl@58
    29
    public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
sl@58
    30
    public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
sl@62
    31
    //Delegates are used for our thread safe method
sl@62
    32
    public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
sl@62
    33
    public delegate void RemoveClientDelegate(string aSessionId);
sl@79
    34
    public delegate void SetFieldDelegate(string SessionId, DataField aField);
sl@79
    35
    public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList<DataField> aFields);
sl@62
    36
    public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
sl@62
    37
    public delegate void SetClientNameDelegate(string aSessionId, string aName);
StephaneLenclud@112
    38
	public delegate void PlainUpdateDelegate();
sl@62
    39
sl@58
    40
sl@58
    41
    /// <summary>
sl@58
    42
    /// Our Display manager main form
sl@58
    43
    /// </summary>
StephaneLenclud@112
    44
	public partial class MainForm : Form, IMMNotificationClient
sl@0
    45
    {
sl@2
    46
        DateTime LastTickTime;
sl@3
    47
        Display iDisplay;
sl@14
    48
        System.Drawing.Bitmap iBmp;
sl@14
    49
        bool iCreateBitmap; //Workaround render to bitmap issues when minimized
sl@17
    50
        ServiceHost iServiceHost;
sl@65
    51
        // Our collection of clients sorted by session id.
sl@33
    52
        public Dictionary<string, ClientData> iClients;
sl@65
    53
        // The name of the client which informations are currently displayed.
sl@65
    54
        public string iCurrentClientSessionId;
sl@65
    55
        ClientData iCurrentClientData;
sl@65
    56
        //
sl@29
    57
        public bool iClosing;
sl@65
    58
        //Function pointer for pixel color filtering
sl@58
    59
        ColorProcessingDelegate iColorFx;
sl@65
    60
        //Function pointer for pixel X coordinate intercept
sl@58
    61
        CoordinateTranslationDelegate iScreenX;
sl@65
    62
        //Function pointer for pixel Y coordinate intercept
sl@58
    63
        CoordinateTranslationDelegate iScreenY;
StephaneLenclud@112
    64
		//NAudio
StephaneLenclud@112
    65
		private MMDeviceEnumerator iMultiMediaDeviceEnumerator;
StephaneLenclud@112
    66
		private MMDevice iMultiMediaDevice;
StephaneLenclud@112
    67
		
sl@2
    68
sl@94
    69
		/// <summary>
sl@94
    70
		/// Manage run when Windows startup option
sl@94
    71
		/// </summary>
sl@92
    72
		private StartupManager iStartupManager;
sl@92
    73
sl@94
    74
		/// <summary>
sl@94
    75
		/// System tray icon.
sl@94
    76
		/// </summary>
sl@94
    77
		private NotifyIconAdv iNotifyIcon;
sl@94
    78
sl@0
    79
        public MainForm()
sl@0
    80
        {
sl@65
    81
            iCurrentClientSessionId = "";
sl@65
    82
            iCurrentClientData = null;
sl@2
    83
            LastTickTime = DateTime.Now;
StephaneLenclud@104
    84
			//Instantiate our display and register for events notifications
sl@3
    85
            iDisplay = new Display();
StephaneLenclud@104
    86
			iDisplay.OnOpened += OnDisplayOpened;
StephaneLenclud@104
    87
			iDisplay.OnClosed += OnDisplayClosed;
StephaneLenclud@104
    88
			//
StephaneLenclud@104
    89
			iClients = new Dictionary<string, ClientData>();
sl@92
    90
			iStartupManager = new StartupManager();
sl@94
    91
			iNotifyIcon = new NotifyIconAdv();
sl@2
    92
StephaneLenclud@104
    93
			//Have our designer initialize its controls
sl@0
    94
            InitializeComponent();
StephaneLenclud@104
    95
StephaneLenclud@104
    96
			//Populate device types
StephaneLenclud@104
    97
			PopulateDeviceTypes();
StephaneLenclud@104
    98
StephaneLenclud@104
    99
			//Initial status update 
sl@7
   100
            UpdateStatus();
StephaneLenclud@104
   101
sl@14
   102
            //We have a bug when drawing minimized and reusing our bitmap
sl@14
   103
            iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
   104
            iCreateBitmap = false;
sl@94
   105
StephaneLenclud@104
   106
			//Minimize our window if desired
sl@94
   107
			if (Properties.Settings.Default.StartMinimized)
sl@94
   108
			{
sl@94
   109
				WindowState = FormWindowState.Minimized;
sl@94
   110
			}
sl@94
   111
sl@0
   112
        }
sl@0
   113
sl@94
   114
		/// <summary>
StephaneLenclud@106
   115
		///
StephaneLenclud@106
   116
		/// </summary>
StephaneLenclud@106
   117
		/// <param name="sender"></param>
StephaneLenclud@106
   118
		/// <param name="e"></param>
StephaneLenclud@106
   119
        private void MainForm_Load(object sender, EventArgs e)
StephaneLenclud@106
   120
        {
StephaneLenclud@106
   121
			//Check if we are running a Click Once deployed application
StephaneLenclud@106
   122
			if (ApplicationDeployment.IsNetworkDeployed)
StephaneLenclud@106
   123
			{
StephaneLenclud@106
   124
				//This is a proper Click Once installation, fetch and show our version number
StephaneLenclud@106
   125
				this.Text += " - v" + ApplicationDeployment.CurrentDeployment.CurrentVersion;
StephaneLenclud@106
   126
			}
StephaneLenclud@106
   127
			else
StephaneLenclud@106
   128
			{
StephaneLenclud@106
   129
				//Not a proper Click Once installation, assuming development build then
StephaneLenclud@106
   130
				this.Text += " - development";
StephaneLenclud@106
   131
			}
StephaneLenclud@106
   132
StephaneLenclud@112
   133
			//NAudio
StephaneLenclud@112
   134
			iMultiMediaDeviceEnumerator = new MMDeviceEnumerator();
StephaneLenclud@112
   135
			iMultiMediaDeviceEnumerator.RegisterEndpointNotificationCallback(this);
StephaneLenclud@112
   136
			
StephaneLenclud@112
   137
			UpdateAudioDeviceAndMasterVolumeThreadSafe();
StephaneLenclud@112
   138
StephaneLenclud@106
   139
			//Setup notification icon
StephaneLenclud@106
   140
			SetupTrayIcon();
StephaneLenclud@106
   141
StephaneLenclud@106
   142
			// To make sure start up with minimize to tray works
StephaneLenclud@106
   143
			if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
StephaneLenclud@106
   144
			{
StephaneLenclud@106
   145
				Visible = false;
StephaneLenclud@106
   146
			}
StephaneLenclud@106
   147
StephaneLenclud@106
   148
#if !DEBUG
StephaneLenclud@106
   149
			//When not debugging we want the screen to be empty until a client takes over
StephaneLenclud@106
   150
			ClearLayout();
StephaneLenclud@106
   151
#else
StephaneLenclud@106
   152
			//When developing we want at least one client for testing
StephaneLenclud@106
   153
			StartNewClient("abcdefghijklmnopqrst-0123456789","ABCDEFGHIJKLMNOPQRST-0123456789");
StephaneLenclud@106
   154
#endif
StephaneLenclud@106
   155
StephaneLenclud@106
   156
			//Open display connection on start-up if needed
StephaneLenclud@106
   157
			if (Properties.Settings.Default.DisplayConnectOnStartup)
StephaneLenclud@106
   158
			{
StephaneLenclud@106
   159
				OpenDisplayConnection();
StephaneLenclud@106
   160
			}
StephaneLenclud@106
   161
StephaneLenclud@106
   162
			//Start our server so that we can get client requests
StephaneLenclud@106
   163
			StartServer();
StephaneLenclud@106
   164
        }
StephaneLenclud@106
   165
StephaneLenclud@106
   166
		/// <summary>
StephaneLenclud@104
   167
		/// Called when our display is opened.
StephaneLenclud@104
   168
		/// </summary>
StephaneLenclud@104
   169
		/// <param name="aDisplay"></param>
StephaneLenclud@104
   170
		private void OnDisplayOpened(Display aDisplay)
StephaneLenclud@104
   171
		{
StephaneLenclud@105
   172
			//Set our screen size now that our display is connected
StephaneLenclud@105
   173
			//Our panelDisplay is the container of our tableLayoutPanel
StephaneLenclud@105
   174
			//tableLayoutPanel will resize itself to fit the client size of our panelDisplay
StephaneLenclud@105
   175
			//panelDisplay needs an extra 2 pixels for borders on each sides
StephaneLenclud@105
   176
			//tableLayoutPanel will eventually be the exact size of our display
StephaneLenclud@105
   177
			Size size = new Size(iDisplay.WidthInPixels() + 2, iDisplay.HeightInPixels() + 2);
StephaneLenclud@105
   178
			panelDisplay.Size = size;
StephaneLenclud@105
   179
StephaneLenclud@104
   180
			//Our display was just opened, update our UI
StephaneLenclud@104
   181
			UpdateStatus();
StephaneLenclud@104
   182
			//Initiate asynchronous request
StephaneLenclud@104
   183
			iDisplay.RequestFirmwareRevision();
StephaneLenclud@108
   184
StephaneLenclud@112
   185
			//
StephaneLenclud@112
   186
			UpdateMasterVolumeThreadSafe();
StephaneLenclud@112
   187
StephaneLenclud@108
   188
#if DEBUG
StephaneLenclud@108
   189
			//Testing icon in debug, no arm done if icon not supported
StephaneLenclud@109
   190
			//iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconRecording, 0, 1);
StephaneLenclud@112
   191
			//iDisplay.SetAllIconsStatus(2);
StephaneLenclud@108
   192
#endif
StephaneLenclud@108
   193
StephaneLenclud@104
   194
		}
StephaneLenclud@104
   195
StephaneLenclud@104
   196
		/// <summary>
StephaneLenclud@104
   197
		/// Called when our display is closed.
StephaneLenclud@104
   198
		/// </summary>
StephaneLenclud@104
   199
		/// <param name="aDisplay"></param>
StephaneLenclud@104
   200
		private void OnDisplayClosed(Display aDisplay)
StephaneLenclud@104
   201
		{
StephaneLenclud@104
   202
			//Our display was just closed, update our UI consequently
StephaneLenclud@104
   203
			UpdateStatus();
StephaneLenclud@104
   204
		}
StephaneLenclud@112
   205
		
StephaneLenclud@112
   206
        /// <summary>
StephaneLenclud@112
   207
        /// Receive volume change notification and reflect changes on our slider.
StephaneLenclud@112
   208
        /// </summary>
StephaneLenclud@112
   209
        /// <param name="data"></param>
StephaneLenclud@112
   210
        public void OnVolumeNotificationThreadSafe(AudioVolumeNotificationData data)
StephaneLenclud@112
   211
        {
StephaneLenclud@112
   212
			UpdateMasterVolumeThreadSafe();
StephaneLenclud@112
   213
        }
StephaneLenclud@112
   214
StephaneLenclud@112
   215
        /// <summary>
StephaneLenclud@112
   216
        /// Update master volume when user moves our slider.
StephaneLenclud@112
   217
        /// </summary>
StephaneLenclud@112
   218
        /// <param name="sender"></param>
StephaneLenclud@112
   219
        /// <param name="e"></param>
StephaneLenclud@112
   220
        private void trackBarMasterVolume_Scroll(object sender, EventArgs e)
StephaneLenclud@112
   221
        {
StephaneLenclud@112
   222
			iMultiMediaDevice.AudioEndpointVolume.MasterVolumeLevelScalar = trackBarMasterVolume.Value / 100.0f;
StephaneLenclud@112
   223
        }
StephaneLenclud@112
   224
StephaneLenclud@113
   225
StephaneLenclud@113
   226
		/// <summary>
StephaneLenclud@113
   227
		/// Mute check box changed.
StephaneLenclud@113
   228
		/// </summary>
StephaneLenclud@113
   229
		/// <param name="sender"></param>
StephaneLenclud@113
   230
		/// <param name="e"></param>
StephaneLenclud@113
   231
		private void checkBoxMute_CheckedChanged(object sender, EventArgs e)
StephaneLenclud@113
   232
		{
StephaneLenclud@113
   233
			iMultiMediaDevice.AudioEndpointVolume.Mute = checkBoxMute.Checked;
StephaneLenclud@113
   234
		}
StephaneLenclud@113
   235
StephaneLenclud@113
   236
StephaneLenclud@112
   237
        /// <summary>
StephaneLenclud@112
   238
        /// Device State Changed
StephaneLenclud@112
   239
        /// </summary>
StephaneLenclud@112
   240
        public void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)] string deviceId, [MarshalAs(UnmanagedType.I4)] DeviceState newState){}
StephaneLenclud@112
   241
StephaneLenclud@112
   242
        /// <summary>
StephaneLenclud@112
   243
        /// Device Added
StephaneLenclud@112
   244
        /// </summary>
StephaneLenclud@112
   245
        public void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId) { }
StephaneLenclud@112
   246
StephaneLenclud@112
   247
        /// <summary>
StephaneLenclud@112
   248
        /// Device Removed
StephaneLenclud@112
   249
        /// </summary>
StephaneLenclud@112
   250
        public void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)] string deviceId) { }
StephaneLenclud@112
   251
StephaneLenclud@112
   252
        /// <summary>
StephaneLenclud@112
   253
        /// Default Device Changed
StephaneLenclud@112
   254
        /// </summary>
StephaneLenclud@112
   255
        public void OnDefaultDeviceChanged(DataFlow flow, Role role, [MarshalAs(UnmanagedType.LPWStr)] string defaultDeviceId)
StephaneLenclud@112
   256
        {
StephaneLenclud@112
   257
            if (role == Role.Multimedia && flow == DataFlow.Render)
StephaneLenclud@112
   258
            {
StephaneLenclud@112
   259
                UpdateAudioDeviceAndMasterVolumeThreadSafe();
StephaneLenclud@112
   260
            }
StephaneLenclud@112
   261
        }
StephaneLenclud@112
   262
StephaneLenclud@112
   263
        /// <summary>
StephaneLenclud@112
   264
        /// Property Value Changed
StephaneLenclud@112
   265
        /// </summary>
StephaneLenclud@112
   266
        /// <param name="pwstrDeviceId"></param>
StephaneLenclud@112
   267
        /// <param name="key"></param>
StephaneLenclud@112
   268
        public void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId, PropertyKey key){}
StephaneLenclud@112
   269
StephaneLenclud@112
   270
StephaneLenclud@112
   271
        
StephaneLenclud@112
   272
StephaneLenclud@112
   273
		/// <summary>
StephaneLenclud@112
   274
		/// 
StephaneLenclud@112
   275
		/// </summary>
StephaneLenclud@112
   276
		private void UpdateMasterVolumeThreadSafe()
StephaneLenclud@112
   277
		{
StephaneLenclud@112
   278
			if (this.InvokeRequired)
StephaneLenclud@112
   279
			{
StephaneLenclud@112
   280
				//Not in the proper thread, invoke ourselves
StephaneLenclud@112
   281
				PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateMasterVolumeThreadSafe);
StephaneLenclud@112
   282
				this.Invoke(d, new object[] { });
StephaneLenclud@112
   283
				return;
StephaneLenclud@112
   284
			}
StephaneLenclud@112
   285
StephaneLenclud@113
   286
			//Update volume slider
StephaneLenclud@112
   287
			float volumeLevelScalar = iMultiMediaDevice.AudioEndpointVolume.MasterVolumeLevelScalar;
StephaneLenclud@112
   288
			trackBarMasterVolume.Value = Convert.ToInt32(volumeLevelScalar * 100);
StephaneLenclud@113
   289
			//Update mute checkbox
StephaneLenclud@113
   290
			checkBoxMute.Checked = iMultiMediaDevice.AudioEndpointVolume.Mute;
StephaneLenclud@112
   291
StephaneLenclud@112
   292
			//TODO: Check our display device too
StephaneLenclud@112
   293
			if (iDisplay.IsOpen())
StephaneLenclud@112
   294
			{
StephaneLenclud@112
   295
				int volumeIconCount = iDisplay.IconCount(Display.TMiniDisplayIconType.EMiniDisplayIconVolume);
StephaneLenclud@112
   296
				if (volumeIconCount > 0)
StephaneLenclud@112
   297
				{
StephaneLenclud@112
   298
					int currentVolume = Convert.ToInt32(volumeLevelScalar * volumeIconCount);
StephaneLenclud@112
   299
					for (int i = 0; i < volumeIconCount; i++)
StephaneLenclud@112
   300
					{
StephaneLenclud@112
   301
						if (i < currentVolume)
StephaneLenclud@112
   302
						{
StephaneLenclud@112
   303
							iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconVolume, i, 10);
StephaneLenclud@112
   304
						}
StephaneLenclud@112
   305
						else
StephaneLenclud@112
   306
						{
StephaneLenclud@112
   307
							iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconVolume, i, 0);
StephaneLenclud@112
   308
						}
StephaneLenclud@112
   309
					}
StephaneLenclud@112
   310
				}
StephaneLenclud@113
   311
StephaneLenclud@113
   312
				int muteIconCount = iDisplay.IconCount(Display.TMiniDisplayIconType.EMiniDisplayIconMute);
StephaneLenclud@113
   313
				if (muteIconCount > 0)
StephaneLenclud@113
   314
				{
StephaneLenclud@113
   315
					for (int i = 0; i < muteIconCount; i++)
StephaneLenclud@113
   316
					{
StephaneLenclud@113
   317
						if (iMultiMediaDevice.AudioEndpointVolume.Mute)
StephaneLenclud@113
   318
						{
StephaneLenclud@113
   319
							iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconMute, i, 10);
StephaneLenclud@113
   320
						}
StephaneLenclud@113
   321
						else
StephaneLenclud@113
   322
						{
StephaneLenclud@113
   323
							iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconMute, i, 0);
StephaneLenclud@113
   324
						}
StephaneLenclud@113
   325
					}
StephaneLenclud@113
   326
				}
StephaneLenclud@113
   327
StephaneLenclud@112
   328
			}
StephaneLenclud@112
   329
StephaneLenclud@112
   330
		}
StephaneLenclud@112
   331
StephaneLenclud@112
   332
        /// <summary>
StephaneLenclud@112
   333
        /// 
StephaneLenclud@112
   334
        /// </summary>
StephaneLenclud@112
   335
        private void UpdateAudioDeviceAndMasterVolumeThreadSafe()
StephaneLenclud@112
   336
        {
StephaneLenclud@112
   337
            if (this.InvokeRequired)
StephaneLenclud@112
   338
            {
StephaneLenclud@112
   339
                //Not in the proper thread, invoke ourselves
StephaneLenclud@112
   340
				PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateAudioDeviceAndMasterVolumeThreadSafe);
StephaneLenclud@112
   341
                this.Invoke(d, new object[] { });
StephaneLenclud@112
   342
                return;
StephaneLenclud@112
   343
            }
StephaneLenclud@112
   344
            
StephaneLenclud@112
   345
            //We are in the correct thread just go ahead.
StephaneLenclud@112
   346
            try
StephaneLenclud@112
   347
            {                
StephaneLenclud@112
   348
                //Get our master volume            
StephaneLenclud@112
   349
				iMultiMediaDevice = iMultiMediaDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
StephaneLenclud@112
   350
                //Show our volume in our track bar
StephaneLenclud@112
   351
				UpdateMasterVolumeThreadSafe();
StephaneLenclud@112
   352
StephaneLenclud@112
   353
                //Register to get volume modifications
StephaneLenclud@112
   354
				iMultiMediaDevice.AudioEndpointVolume.OnVolumeNotification += OnVolumeNotificationThreadSafe;
StephaneLenclud@112
   355
                //
StephaneLenclud@112
   356
				trackBarMasterVolume.Enabled = true;
StephaneLenclud@112
   357
            }
StephaneLenclud@112
   358
            catch (Exception ex)
StephaneLenclud@112
   359
            {
StephaneLenclud@112
   360
                Debug.WriteLine("Exception thrown in UpdateAudioDeviceAndMasterVolume");
StephaneLenclud@112
   361
                Debug.WriteLine(ex.ToString());
StephaneLenclud@112
   362
                //Something went wrong S/PDIF device ca throw exception I guess
StephaneLenclud@112
   363
				trackBarMasterVolume.Enabled = false;
StephaneLenclud@112
   364
            }
StephaneLenclud@112
   365
        }
StephaneLenclud@104
   366
StephaneLenclud@104
   367
		/// <summary>
StephaneLenclud@104
   368
		/// 
StephaneLenclud@104
   369
		/// </summary>
StephaneLenclud@104
   370
		private void PopulateDeviceTypes()
StephaneLenclud@104
   371
		{
StephaneLenclud@104
   372
			int count = Display.TypeCount();
StephaneLenclud@104
   373
StephaneLenclud@106
   374
			for (int i = 0; i < count; i++)
StephaneLenclud@104
   375
			{
StephaneLenclud@104
   376
				comboBoxDisplayType.Items.Add(Display.TypeName((Display.TMiniDisplayType)i));
StephaneLenclud@106
   377
			}
StephaneLenclud@104
   378
		}
StephaneLenclud@104
   379
StephaneLenclud@104
   380
		/// <summary>
sl@99
   381
		///
sl@94
   382
		/// </summary>
sl@95
   383
		private void SetupTrayIcon()
sl@95
   384
		{
sl@95
   385
			iNotifyIcon.Icon = GetIcon("vfd.ico");
sl@95
   386
			iNotifyIcon.Text = "Sharp Display Manager";
sl@95
   387
			iNotifyIcon.Visible = true;
sl@95
   388
sl@95
   389
			//Double click toggles visibility - typically brings up the application
sl@95
   390
			iNotifyIcon.DoubleClick += delegate(object obj, EventArgs args)
sl@95
   391
			{
sl@95
   392
				SysTrayHideShow();
sl@95
   393
			};
sl@95
   394
sl@95
   395
			//Adding a context menu, useful to be able to exit the application
sl@95
   396
			ContextMenu contextMenu = new ContextMenu();
sl@95
   397
			//Context menu item to toggle visibility
sl@95
   398
			MenuItem hideShowItem = new MenuItem("Hide/Show");
sl@95
   399
			hideShowItem.Click += delegate(object obj, EventArgs args)
sl@95
   400
			{
sl@95
   401
				SysTrayHideShow();
sl@95
   402
			};
sl@95
   403
			contextMenu.MenuItems.Add(hideShowItem);
sl@95
   404
sl@95
   405
			//Context menu item separator
sl@95
   406
			contextMenu.MenuItems.Add(new MenuItem("-"));
sl@95
   407
sl@95
   408
			//Context menu exit item
sl@95
   409
			MenuItem exitItem = new MenuItem("Exit");
sl@95
   410
			exitItem.Click += delegate(object obj, EventArgs args)
sl@95
   411
			{
sl@95
   412
				Application.Exit();
sl@95
   413
			};
sl@95
   414
			contextMenu.MenuItems.Add(exitItem);
sl@95
   415
sl@95
   416
			iNotifyIcon.ContextMenu = contextMenu;
sl@95
   417
		}
sl@95
   418
sl@95
   419
		/// <summary>
sl@94
   420
		/// Access icons from embedded resources.
sl@94
   421
		/// </summary>
sl@94
   422
		/// <param name="name"></param>
sl@94
   423
		/// <returns></returns>
sl@94
   424
		public static Icon GetIcon(string name)
sl@94
   425
		{
sl@94
   426
			name = "SharpDisplayManager.Resources." + name;
sl@94
   427
sl@94
   428
			string[] names =
sl@94
   429
			  Assembly.GetExecutingAssembly().GetManifestResourceNames();
sl@94
   430
			for (int i = 0; i < names.Length; i++)
sl@94
   431
			{
sl@94
   432
				if (names[i].Replace('\\', '.') == name)
sl@94
   433
				{
sl@94
   434
					using (Stream stream = Assembly.GetExecutingAssembly().
sl@94
   435
					  GetManifestResourceStream(names[i]))
sl@94
   436
					{
sl@94
   437
						return new Icon(stream);
sl@94
   438
					}
sl@94
   439
				}
sl@94
   440
			}
sl@94
   441
sl@94
   442
			return null;
sl@94
   443
		}
sl@94
   444
sl@94
   445
sl@65
   446
        /// <summary>
sl@65
   447
        /// Set our current client.
sl@65
   448
        /// This will take care of applying our client layout and set data fields.
sl@65
   449
        /// </summary>
sl@65
   450
        /// <param name="aSessionId"></param>
sl@65
   451
        void SetCurrentClient(string aSessionId)
sl@57
   452
        {
sl@65
   453
            if (aSessionId == iCurrentClientSessionId)
sl@57
   454
            {
sl@65
   455
                //Given client is already the current one.
sl@65
   456
                //Don't bother changing anything then.
sl@65
   457
                return;
sl@65
   458
            }
sl@57
   459
sl@65
   460
            //Set current client ID.
sl@65
   461
            iCurrentClientSessionId = aSessionId;
sl@65
   462
            //Fetch and set current client data.
sl@65
   463
            iCurrentClientData = iClients[aSessionId];
sl@65
   464
            //Apply layout and set data fields.
sl@65
   465
            UpdateTableLayoutPanel(iCurrentClientData);
sl@57
   466
        }
sl@57
   467
sl@0
   468
        private void buttonFont_Click(object sender, EventArgs e)
sl@0
   469
        {
sl@0
   470
            //fontDialog.ShowColor = true;
sl@0
   471
            //fontDialog.ShowApply = true;
sl@0
   472
            fontDialog.ShowEffects = true;
sl@99
   473
            fontDialog.Font = cds.Font;
sl@28
   474
sl@28
   475
            fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
sl@28
   476
sl@0
   477
            //fontDialog.ShowHelp = true;
sl@0
   478
sl@0
   479
            //fontDlg.MaxSize = 40;
sl@0
   480
            //fontDlg.MinSize = 22;
sl@0
   481
sl@0
   482
            //fontDialog.Parent = this;
sl@0
   483
            //fontDialog.StartPosition = FormStartPosition.CenterParent;
sl@0
   484
sl@0
   485
            //DlgBox.ShowDialog(fontDialog);
sl@0
   486
sl@0
   487
            //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
sl@0
   488
            if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
sl@0
   489
            {
sl@99
   490
                //Set the fonts to all our labels in our layout
sl@99
   491
                foreach (Control ctrl in tableLayoutPanel.Controls)
sl@99
   492
                {
sl@99
   493
                    if (ctrl is MarqueeLabel)
sl@99
   494
                    {
sl@99
   495
                        ((MarqueeLabel)ctrl).Font = fontDialog.Font;
sl@99
   496
                    }
sl@99
   497
                }
sl@0
   498
sl@99
   499
                //Save font settings
sl@48
   500
                cds.Font = fontDialog.Font;
sl@8
   501
                Properties.Settings.Default.Save();
sl@36
   502
                //
sl@37
   503
                CheckFontHeight();
sl@37
   504
            }
sl@37
   505
        }
sl@36
   506
sl@37
   507
        /// <summary>
sl@38
   508
        ///
sl@37
   509
        /// </summary>
sl@37
   510
        void CheckFontHeight()
sl@37
   511
        {
sl@54
   512
            //Show font height and width
sl@54
   513
            labelFontHeight.Text = "Font height: " + cds.Font.Height;
sl@54
   514
            float charWidth = IsFixedWidth(cds.Font);
sl@54
   515
            if (charWidth == 0.0f)
sl@54
   516
            {
sl@54
   517
                labelFontWidth.Visible = false;
sl@54
   518
            }
sl@54
   519
            else
sl@54
   520
            {
sl@54
   521
                labelFontWidth.Visible = true;
sl@54
   522
                labelFontWidth.Text = "Font width: " + charWidth;
sl@54
   523
            }
sl@54
   524
sl@70
   525
            MarqueeLabel label = null;
sl@68
   526
            //Get the first label control we can find
sl@68
   527
            foreach (Control ctrl in tableLayoutPanel.Controls)
sl@68
   528
            {
sl@68
   529
                if (ctrl is MarqueeLabel)
sl@68
   530
                {
sl@68
   531
                    label = (MarqueeLabel)ctrl;
sl@68
   532
                    break;
sl@68
   533
                }
sl@68
   534
            }
sl@68
   535
sl@54
   536
            //Now check font height and show a warning if needed.
sl@68
   537
            if (label != null && label.Font.Height > label.Height)
sl@37
   538
            {
sl@60
   539
                labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
sl@37
   540
                labelWarning.Visible = true;
sl@0
   541
            }
sl@37
   542
            else
sl@37
   543
            {
sl@37
   544
                labelWarning.Visible = false;
sl@37
   545
            }
sl@37
   546
sl@0
   547
        }
sl@0
   548
sl@0
   549
        private void buttonCapture_Click(object sender, EventArgs e)
sl@0
   550
        {
sl@0
   551
            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
sl@0
   552
            tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
sl@14
   553
            //Bitmap bmpToSave = new Bitmap(bmp);
sl@14
   554
            bmp.Save("D:\\capture.png");
sl@14
   555
sl@60
   556
            ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
sl@17
   557
sl@14
   558
            /*
sl@14
   559
            string outputFileName = "d:\\capture.png";
sl@14
   560
            using (MemoryStream memory = new MemoryStream())
sl@14
   561
            {
sl@14
   562
                using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
sl@14
   563
                {
sl@14
   564
                    bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
sl@14
   565
                    byte[] bytes = memory.ToArray();
sl@14
   566
                    fs.Write(bytes, 0, bytes.Length);
sl@14
   567
                }
sl@14
   568
            }
sl@14
   569
             */
sl@14
   570
sl@0
   571
        }
sl@2
   572
sl@12
   573
        private void CheckForRequestResults()
sl@12
   574
        {
sl@12
   575
            if (iDisplay.IsRequestPending())
sl@12
   576
            {
sl@12
   577
                switch (iDisplay.AttemptRequestCompletion())
sl@12
   578
                {
sl@51
   579
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
sl@51
   580
                        toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
sl@51
   581
                        //Issue next request then
sl@51
   582
                        iDisplay.RequestPowerSupplyStatus();
sl@51
   583
                        break;
sl@51
   584
sl@12
   585
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
sl@12
   586
                        if (iDisplay.PowerSupplyStatus())
sl@12
   587
                        {
sl@12
   588
                            toolStripStatusLabelPower.Text = "ON";
sl@12
   589
                        }
sl@12
   590
                        else
sl@12
   591
                        {
sl@12
   592
                            toolStripStatusLabelPower.Text = "OFF";
sl@12
   593
                        }
sl@12
   594
                        //Issue next request then
sl@12
   595
                        iDisplay.RequestDeviceId();
sl@12
   596
                        break;
sl@12
   597
sl@12
   598
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
sl@12
   599
                        toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
sl@12
   600
                        //No more request to issue
sl@12
   601
                        break;
sl@12
   602
                }
sl@12
   603
            }
sl@12
   604
        }
sl@12
   605
sl@58
   606
        public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
sl@58
   607
        {
sl@58
   608
            if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
sl@58
   609
            {
sl@58
   610
                return 0xFFFFFFFF;
sl@58
   611
            }
sl@58
   612
            return 0x00000000;
sl@58
   613
        }
sl@16
   614
sl@58
   615
        public static uint ColorUntouched(int aX, int aY, uint aPixel)
sl@57
   616
        {
sl@57
   617
            return aPixel;
sl@57
   618
        }
sl@57
   619
sl@58
   620
        public static uint ColorInversed(int aX, int aY, uint aPixel)
sl@57
   621
        {
sl@57
   622
            return ~aPixel;
sl@57
   623
        }
sl@57
   624
sl@58
   625
        public static uint ColorChessboard(int aX, int aY, uint aPixel)
sl@58
   626
        {
sl@58
   627
            if ((aX % 2 == 0) && (aY % 2 == 0))
sl@58
   628
            {
sl@58
   629
                return ~aPixel;
sl@58
   630
            }
sl@58
   631
            else if ((aX % 2 != 0) && (aY % 2 != 0))
sl@58
   632
            {
sl@58
   633
                return ~aPixel;
sl@58
   634
            }
sl@58
   635
            return 0x00000000;
sl@58
   636
        }
sl@58
   637
sl@16
   638
sl@16
   639
        public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
sl@16
   640
        {
sl@16
   641
            return aBmp.Width - aX - 1;
sl@16
   642
        }
sl@16
   643
sl@16
   644
        public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
sl@16
   645
        {
sl@16
   646
            return iBmp.Height - aY - 1;
sl@16
   647
        }
sl@16
   648
sl@16
   649
        public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
sl@16
   650
        {
sl@16
   651
            return aX;
sl@16
   652
        }
sl@16
   653
sl@16
   654
        public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
sl@16
   655
        {
sl@16
   656
            return aY;
sl@16
   657
        }
sl@16
   658
sl@58
   659
        /// <summary>
sl@58
   660
        /// Select proper pixel delegates according to our current settings.
sl@58
   661
        /// </summary>
sl@58
   662
        private void SetupPixelDelegates()
sl@58
   663
        {
sl@59
   664
            //Select our pixel processing routine
sl@58
   665
            if (cds.InverseColors)
sl@58
   666
            {
sl@58
   667
                //iColorFx = ColorChessboard;
sl@58
   668
                iColorFx = ColorInversed;
sl@58
   669
            }
sl@58
   670
            else
sl@58
   671
            {
sl@58
   672
                iColorFx = ColorWhiteIsOn;
sl@58
   673
            }
sl@58
   674
sl@58
   675
            //Select proper coordinate translation functions
sl@58
   676
            //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
sl@58
   677
            if (cds.ReverseScreen)
sl@58
   678
            {
sl@58
   679
                iScreenX = ScreenReversedX;
sl@58
   680
                iScreenY = ScreenReversedY;
sl@58
   681
            }
sl@58
   682
            else
sl@58
   683
            {
sl@58
   684
                iScreenX = ScreenX;
sl@58
   685
                iScreenY = ScreenY;
sl@58
   686
            }
sl@58
   687
sl@58
   688
        }
sl@16
   689
sl@16
   690
        //This is our timer tick responsible to perform our render
sl@2
   691
        private void timer_Tick(object sender, EventArgs e)
sl@14
   692
        {
sl@2
   693
            //Update our animations
sl@2
   694
            DateTime NewTickTime = DateTime.Now;
sl@2
   695
sl@60
   696
            //Update animation for all our marquees
sl@68
   697
            foreach (Control ctrl in tableLayoutPanel.Controls)
sl@60
   698
            {
sl@68
   699
                if (ctrl is MarqueeLabel)
sl@68
   700
                {
sl@68
   701
                    ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
sl@68
   702
                }
sl@60
   703
            }
sl@60
   704
sl@2
   705
sl@4
   706
            //Update our display
sl@4
   707
            if (iDisplay.IsOpen())
sl@4
   708
            {
sl@12
   709
                CheckForRequestResults();
sl@12
   710
sl@22
   711
                //Draw to bitmap
sl@14
   712
                if (iCreateBitmap)
sl@14
   713
                {
sl@14
   714
                    iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
   715
                }
sl@14
   716
                tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
sl@14
   717
                //iBmp.Save("D:\\capture.png");
sl@16
   718
sl@7
   719
                //Send it to our display
sl@14
   720
                for (int i = 0; i < iBmp.Width; i++)
sl@4
   721
                {
sl@14
   722
                    for (int j = 0; j < iBmp.Height; j++)
sl@4
   723
                    {
sl@4
   724
                        unchecked
sl@4
   725
                        {
sl@58
   726
                            //Get our processed pixel coordinates
sl@58
   727
                            int x = iScreenX(iBmp, i);
sl@58
   728
                            int y = iScreenY(iBmp, j);
sl@58
   729
                            //Get pixel color
sl@14
   730
                            uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
sl@57
   731
                            //Apply color effects
sl@58
   732
                            color = iColorFx(x,y,color);
sl@58
   733
                            //Now set our pixel
sl@58
   734
                            iDisplay.SetPixel(x, y, color);
sl@4
   735
                        }
sl@4
   736
                    }
sl@4
   737
                }
sl@4
   738
sl@4
   739
                iDisplay.SwapBuffers();
sl@4
   740
sl@4
   741
            }
sl@8
   742
sl@8
   743
            //Compute instant FPS
sl@47
   744
            toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
sl@8
   745
sl@8
   746
            LastTickTime = NewTickTime;
sl@8
   747
sl@2
   748
        }
sl@3
   749
StephaneLenclud@103
   750
		/// <summary>
StephaneLenclud@103
   751
		/// Attempt to establish connection with our display hardware.
StephaneLenclud@103
   752
		/// </summary>
sl@46
   753
        private void OpenDisplayConnection()
sl@3
   754
        {
sl@46
   755
            CloseDisplayConnection();
sl@46
   756
StephaneLenclud@104
   757
            if (!iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
StephaneLenclud@104
   758
            {   
StephaneLenclud@104
   759
				UpdateStatus();               
StephaneLenclud@104
   760
				toolStripStatusLabelConnect.Text = "Connection error";
sl@7
   761
            }
sl@46
   762
        }
sl@7
   763
sl@46
   764
        private void CloseDisplayConnection()
sl@46
   765
        {
StephaneLenclud@104
   766
			//Status will be updated upon receiving the closed event
sl@46
   767
            iDisplay.Close();
sl@46
   768
        }
sl@46
   769
sl@46
   770
        private void buttonOpen_Click(object sender, EventArgs e)
sl@46
   771
        {
sl@46
   772
            OpenDisplayConnection();
sl@3
   773
        }
sl@3
   774
sl@3
   775
        private void buttonClose_Click(object sender, EventArgs e)
sl@3
   776
        {
sl@46
   777
            CloseDisplayConnection();
sl@3
   778
        }
sl@3
   779
sl@3
   780
        private void buttonClear_Click(object sender, EventArgs e)
sl@3
   781
        {
sl@3
   782
            iDisplay.Clear();
sl@3
   783
            iDisplay.SwapBuffers();
sl@3
   784
        }
sl@3
   785
sl@3
   786
        private void buttonFill_Click(object sender, EventArgs e)
sl@3
   787
        {
sl@3
   788
            iDisplay.Fill();
sl@3
   789
            iDisplay.SwapBuffers();
sl@3
   790
        }
sl@3
   791
sl@3
   792
        private void trackBarBrightness_Scroll(object sender, EventArgs e)
sl@3
   793
        {
sl@48
   794
            cds.Brightness = trackBarBrightness.Value;
sl@9
   795
            Properties.Settings.Default.Save();
sl@3
   796
            iDisplay.SetBrightness(trackBarBrightness.Value);
sl@9
   797
sl@3
   798
        }
sl@7
   799
sl@48
   800
sl@48
   801
        /// <summary>
sl@48
   802
        /// CDS stands for Current Display Settings
sl@48
   803
        /// </summary>
sl@50
   804
        private DisplaySettings cds
sl@48
   805
        {
sl@48
   806
            get
sl@48
   807
            {
sl@65
   808
                DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
sl@51
   809
                if (settings == null)
sl@51
   810
                {
sl@51
   811
                    settings = new DisplaysSettings();
sl@51
   812
                    settings.Init();
sl@65
   813
                    Properties.Settings.Default.DisplaysSettings = settings;
sl@51
   814
                }
sl@48
   815
sl@48
   816
                //Make sure all our settings have been created
sl@48
   817
                while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
sl@48
   818
                {
sl@50
   819
                    settings.Displays.Add(new DisplaySettings());
sl@48
   820
                }
sl@48
   821
sl@50
   822
                DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
sl@48
   823
                return displaySettings;
sl@48
   824
            }
sl@48
   825
        }
sl@48
   826
sl@54
   827
        /// <summary>
sl@54
   828
        /// Check if the given font has a fixed character pitch.
sl@54
   829
        /// </summary>
sl@54
   830
        /// <param name="ft"></param>
sl@54
   831
        /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
sl@54
   832
        public float IsFixedWidth(Font ft)
sl@54
   833
        {
sl@54
   834
            Graphics g = CreateGraphics();
sl@54
   835
            char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
sl@54
   836
            float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
sl@54
   837
sl@54
   838
            bool fixedWidth = true;
sl@54
   839
sl@54
   840
            foreach (char c in charSizes)
sl@54
   841
                if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
sl@54
   842
                    fixedWidth = false;
sl@54
   843
sl@54
   844
            if (fixedWidth)
sl@54
   845
            {
sl@54
   846
                return charWidth;
sl@54
   847
            }
sl@54
   848
sl@54
   849
            return 0.0f;
sl@54
   850
        }
sl@54
   851
StephaneLenclud@103
   852
		/// <summary>
StephaneLenclud@103
   853
		/// Synchronize UI with settings
StephaneLenclud@103
   854
		/// </summary>
sl@7
   855
        private void UpdateStatus()
StephaneLenclud@103
   856
        {            
sl@48
   857
            //Load settings
sl@54
   858
            checkBoxShowBorders.Checked = cds.ShowBorders;
sl@54
   859
            tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@60
   860
sl@60
   861
            //Set the proper font to each of our labels
sl@60
   862
            foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
sl@60
   863
            {
sl@60
   864
                ctrl.Font = cds.Font;
sl@60
   865
            }
sl@60
   866
sl@54
   867
            CheckFontHeight();
sl@96
   868
			//Check if "run on Windows startup" is enabled
sl@96
   869
			checkBoxAutoStart.Checked = iStartupManager.Startup;
sl@96
   870
			//
sl@48
   871
            checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
sl@94
   872
			checkBoxMinimizeToTray.Checked = Properties.Settings.Default.MinimizeToTray;
sl@94
   873
			checkBoxStartMinimized.Checked = Properties.Settings.Default.StartMinimized;
sl@48
   874
            checkBoxReverseScreen.Checked = cds.ReverseScreen;
sl@57
   875
            checkBoxInverseColors.Checked = cds.InverseColors;
sl@100
   876
            checkBoxScaleToFit.Checked = cds.ScaleToFit;
sl@100
   877
            maskedTextBoxMinFontSize.Enabled = cds.ScaleToFit;
sl@100
   878
            labelMinFontSize.Enabled = cds.ScaleToFit;
sl@100
   879
            maskedTextBoxMinFontSize.Text = cds.MinFontSize.ToString();
StephaneLenclud@106
   880
			maskedTextBoxScrollingSpeed.Text = cds.ScrollingSpeedInPixelsPerSecond.ToString();
sl@48
   881
            comboBoxDisplayType.SelectedIndex = cds.DisplayType;
sl@48
   882
            timer.Interval = cds.TimerInterval;
sl@48
   883
            maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
sl@100
   884
            textBoxScrollLoopSeparator.Text = cds.Separator;
sl@58
   885
            //
sl@58
   886
            SetupPixelDelegates();
sl@48
   887
sl@7
   888
            if (iDisplay.IsOpen())
sl@7
   889
            {
StephaneLenclud@103
   890
				//We have a display connection
StephaneLenclud@103
   891
				//Reflect that in our UI
StephaneLenclud@103
   892
StephaneLenclud@103
   893
				tableLayoutPanel.Enabled = true;
StephaneLenclud@105
   894
				panelDisplay.Enabled = true;
StephaneLenclud@103
   895
sl@48
   896
                //Only setup brightness if display is open
sl@48
   897
                trackBarBrightness.Minimum = iDisplay.MinBrightness();
sl@48
   898
                trackBarBrightness.Maximum = iDisplay.MaxBrightness();
StephaneLenclud@105
   899
				if (cds.Brightness < iDisplay.MinBrightness() || cds.Brightness > iDisplay.MaxBrightness())
StephaneLenclud@105
   900
				{
StephaneLenclud@105
   901
					//Brightness out of range, this can occur when using auto-detect
StephaneLenclud@105
   902
					//Use max brightness instead
StephaneLenclud@105
   903
					trackBarBrightness.Value = iDisplay.MaxBrightness();
StephaneLenclud@105
   904
					iDisplay.SetBrightness(iDisplay.MaxBrightness());
StephaneLenclud@105
   905
				}
StephaneLenclud@105
   906
				else
StephaneLenclud@105
   907
				{
StephaneLenclud@105
   908
					trackBarBrightness.Value = cds.Brightness;
StephaneLenclud@105
   909
					iDisplay.SetBrightness(cds.Brightness);
StephaneLenclud@105
   910
				}
StephaneLenclud@105
   911
StephaneLenclud@105
   912
				//Try compute the steps to something that makes sense
sl@48
   913
                trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
sl@48
   914
                trackBarBrightness.SmallChange = 1;
StephaneLenclud@105
   915
                
sl@48
   916
                //
sl@7
   917
                buttonFill.Enabled = true;
sl@7
   918
                buttonClear.Enabled = true;
sl@7
   919
                buttonOpen.Enabled = false;
sl@7
   920
                buttonClose.Enabled = true;
sl@7
   921
                trackBarBrightness.Enabled = true;
sl@10
   922
                toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
sl@10
   923
                //+ " - " + iDisplay.SerialNumber();
sl@52
   924
sl@52
   925
                if (iDisplay.SupportPowerOnOff())
sl@52
   926
                {
sl@52
   927
                    buttonPowerOn.Enabled = true;
sl@52
   928
                    buttonPowerOff.Enabled = true;
sl@52
   929
                }
sl@52
   930
                else
sl@52
   931
                {
sl@52
   932
                    buttonPowerOn.Enabled = false;
sl@52
   933
                    buttonPowerOff.Enabled = false;
sl@52
   934
                }
sl@53
   935
sl@53
   936
                if (iDisplay.SupportClock())
sl@53
   937
                {
sl@53
   938
                    buttonShowClock.Enabled = true;
sl@53
   939
                    buttonHideClock.Enabled = true;
sl@53
   940
                }
sl@53
   941
                else
sl@53
   942
                {
sl@53
   943
                    buttonShowClock.Enabled = false;
sl@53
   944
                    buttonHideClock.Enabled = false;
sl@53
   945
                }
sl@7
   946
            }
sl@7
   947
            else
sl@7
   948
            {
StephaneLenclud@103
   949
				//Display is connection not available
StephaneLenclud@103
   950
				//Reflect that in our UI
StephaneLenclud@103
   951
				tableLayoutPanel.Enabled = false;
StephaneLenclud@105
   952
				panelDisplay.Enabled = false;
sl@7
   953
                buttonFill.Enabled = false;
sl@7
   954
                buttonClear.Enabled = false;
sl@7
   955
                buttonOpen.Enabled = true;
sl@7
   956
                buttonClose.Enabled = false;
sl@7
   957
                trackBarBrightness.Enabled = false;
sl@52
   958
                buttonPowerOn.Enabled = false;
sl@52
   959
                buttonPowerOff.Enabled = false;
sl@53
   960
                buttonShowClock.Enabled = false;
sl@53
   961
                buttonHideClock.Enabled = false;
sl@9
   962
                toolStripStatusLabelConnect.Text = "Disconnected";
sl@48
   963
                toolStripStatusLabelPower.Text = "N/A";
sl@7
   964
            }
StephaneLenclud@106
   965
sl@7
   966
        }
sl@9
   967
sl@13
   968
sl@13
   969
sl@9
   970
        private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
sl@9
   971
        {
sl@16
   972
            //Save our show borders setting
sl@13
   973
            tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@48
   974
            cds.ShowBorders = checkBoxShowBorders.Checked;
sl@9
   975
            Properties.Settings.Default.Save();
sl@57
   976
            CheckFontHeight();
sl@9
   977
        }
sl@13
   978
sl@13
   979
        private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
sl@13
   980
        {
sl@16
   981
            //Save our connect on startup setting
sl@13
   982
            Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
sl@13
   983
            Properties.Settings.Default.Save();
sl@13
   984
        }
sl@13
   985
sl@94
   986
		private void checkBoxMinimizeToTray_CheckedChanged(object sender, EventArgs e)
sl@94
   987
		{
sl@94
   988
			//Save our "Minimize to tray" setting
sl@94
   989
			Properties.Settings.Default.MinimizeToTray = checkBoxMinimizeToTray.Checked;
sl@94
   990
			Properties.Settings.Default.Save();
sl@94
   991
sl@94
   992
		}
sl@94
   993
sl@94
   994
		private void checkBoxStartMinimized_CheckedChanged(object sender, EventArgs e)
sl@94
   995
		{
sl@94
   996
			//Save our "Start minimized" setting
sl@94
   997
			Properties.Settings.Default.StartMinimized = checkBoxStartMinimized.Checked;
sl@94
   998
			Properties.Settings.Default.Save();
sl@94
   999
		}
sl@94
  1000
sl@94
  1001
		private void checkBoxAutoStart_CheckedChanged(object sender, EventArgs e)
sl@94
  1002
		{
sl@94
  1003
			iStartupManager.Startup = checkBoxAutoStart.Checked;
sl@94
  1004
		}
sl@94
  1005
sl@94
  1006
sl@16
  1007
        private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
sl@16
  1008
        {
sl@16
  1009
            //Save our reverse screen setting
sl@48
  1010
            cds.ReverseScreen = checkBoxReverseScreen.Checked;
sl@16
  1011
            Properties.Settings.Default.Save();
sl@58
  1012
            SetupPixelDelegates();
sl@16
  1013
        }
sl@16
  1014
sl@57
  1015
        private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
sl@57
  1016
        {
sl@57
  1017
            //Save our inverse colors setting
sl@57
  1018
            cds.InverseColors = checkBoxInverseColors.Checked;
sl@57
  1019
            Properties.Settings.Default.Save();
sl@58
  1020
            SetupPixelDelegates();
sl@57
  1021
        }
sl@57
  1022
sl@100
  1023
        private void checkBoxScaleToFit_CheckedChanged(object sender, EventArgs e)
sl@100
  1024
        {
sl@100
  1025
            //Save our scale to fit setting
sl@100
  1026
            cds.ScaleToFit = checkBoxScaleToFit.Checked;
sl@100
  1027
            Properties.Settings.Default.Save();
sl@100
  1028
            //
sl@100
  1029
            labelMinFontSize.Enabled = cds.ScaleToFit;
sl@100
  1030
            maskedTextBoxMinFontSize.Enabled = cds.ScaleToFit;
sl@100
  1031
        }
sl@100
  1032
sl@14
  1033
        private void MainForm_Resize(object sender, EventArgs e)
sl@14
  1034
        {
sl@14
  1035
            if (WindowState == FormWindowState.Minimized)
sl@14
  1036
            {
sl@14
  1037
                // Do some stuff
sl@14
  1038
                //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
  1039
                iCreateBitmap = true;
sl@14
  1040
            }
sl@14
  1041
        }
sl@14
  1042
sl@17
  1043
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
sl@17
  1044
        {
StephaneLenclud@105
  1045
			CloseDisplayConnection();
sl@17
  1046
            StopServer();
sl@32
  1047
            e.Cancel = iClosing;
sl@17
  1048
        }
sl@17
  1049
sl@17
  1050
        public void StartServer()
sl@17
  1051
        {
sl@17
  1052
            iServiceHost = new ServiceHost
sl@17
  1053
                (
sl@55
  1054
                    typeof(Session),
sl@20
  1055
                    new Uri[] { new Uri("net.tcp://localhost:8001/") }
sl@17
  1056
                );
sl@17
  1057
sl@55
  1058
            iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
sl@17
  1059
            iServiceHost.Open();
sl@17
  1060
        }
sl@17
  1061
sl@17
  1062
        public void StopServer()
sl@17
  1063
        {
sl@32
  1064
            if (iClients.Count > 0 && !iClosing)
sl@29
  1065
            {
sl@29
  1066
                //Tell our clients
sl@32
  1067
                iClosing = true;
sl@29
  1068
                BroadcastCloseEvent();
sl@29
  1069
            }
sl@32
  1070
            else if (iClosing)
sl@32
  1071
            {
sl@32
  1072
                if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
sl@32
  1073
                {
sl@32
  1074
                    iClosing = false; //We make sure we force close if asked twice
sl@32
  1075
                }
sl@32
  1076
            }
sl@32
  1077
            else
sl@36
  1078
            {
sl@32
  1079
                //We removed that as it often lags for some reason
sl@32
  1080
                //iServiceHost.Close();
sl@32
  1081
            }
sl@17
  1082
        }
sl@17
  1083
sl@21
  1084
        public void BroadcastCloseEvent()
sl@21
  1085
        {
sl@31
  1086
            Trace.TraceInformation("BroadcastCloseEvent - start");
sl@31
  1087
sl@21
  1088
            var inactiveClients = new List<string>();
sl@21
  1089
            foreach (var client in iClients)
sl@21
  1090
            {
sl@21
  1091
                //if (client.Key != eventData.ClientName)
sl@21
  1092
                {
sl@21
  1093
                    try
sl@21
  1094
                    {
sl@31
  1095
                        Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
sl@33
  1096
                        client.Value.Callback.OnCloseOrder(/*eventData*/);
sl@21
  1097
                    }
sl@21
  1098
                    catch (Exception ex)
sl@21
  1099
                    {
sl@21
  1100
                        inactiveClients.Add(client.Key);
sl@21
  1101
                    }
sl@21
  1102
                }
sl@21
  1103
            }
sl@21
  1104
sl@21
  1105
            if (inactiveClients.Count > 0)
sl@21
  1106
            {
sl@21
  1107
                foreach (var client in inactiveClients)
sl@21
  1108
                {
sl@21
  1109
                    iClients.Remove(client);
sl@30
  1110
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
sl@21
  1111
                }
sl@21
  1112
            }
sl@97
  1113
sl@97
  1114
			if (iClients.Count==0)
sl@97
  1115
			{
sl@97
  1116
				ClearLayout();
sl@97
  1117
			}
sl@21
  1118
        }
sl@21
  1119
sl@97
  1120
		/// <summary>
sl@97
  1121
		/// Just remove all our fields.
sl@97
  1122
		/// </summary>
sl@97
  1123
		private void ClearLayout()
sl@97
  1124
		{
sl@97
  1125
			tableLayoutPanel.Controls.Clear();
sl@97
  1126
			tableLayoutPanel.RowStyles.Clear();
sl@97
  1127
			tableLayoutPanel.ColumnStyles.Clear();
sl@97
  1128
		}
sl@97
  1129
StephaneLenclud@106
  1130
		/// <summary>
StephaneLenclud@106
  1131
		/// Just launch a demo client.
StephaneLenclud@106
  1132
		/// </summary>
StephaneLenclud@106
  1133
		private void StartNewClient(string aTopText = "", string aBottomText = "")
StephaneLenclud@106
  1134
		{
StephaneLenclud@106
  1135
			Thread clientThread = new Thread(SharpDisplayClient.Program.MainWithParams);
StephaneLenclud@106
  1136
			SharpDisplayClient.StartParams myParams = new SharpDisplayClient.StartParams(new Point(this.Right, this.Top),aTopText,aBottomText);
StephaneLenclud@106
  1137
			clientThread.Start(myParams);
StephaneLenclud@106
  1138
			BringToFront();
StephaneLenclud@106
  1139
		}
StephaneLenclud@106
  1140
sl@25
  1141
        private void buttonStartClient_Click(object sender, EventArgs e)
sl@25
  1142
        {
StephaneLenclud@106
  1143
			StartNewClient();
sl@25
  1144
        }
sl@25
  1145
sl@27
  1146
        private void buttonSuspend_Click(object sender, EventArgs e)
sl@27
  1147
        {
sl@52
  1148
            LastTickTime = DateTime.Now; //Reset timer to prevent jump
sl@27
  1149
            timer.Enabled = !timer.Enabled;
sl@27
  1150
            if (!timer.Enabled)
sl@27
  1151
            {
sl@52
  1152
                buttonSuspend.Text = "Run";
sl@27
  1153
            }
sl@27
  1154
            else
sl@27
  1155
            {
sl@27
  1156
                buttonSuspend.Text = "Pause";
sl@27
  1157
            }
sl@27
  1158
        }
sl@27
  1159
sl@29
  1160
        private void buttonCloseClients_Click(object sender, EventArgs e)
sl@29
  1161
        {
sl@29
  1162
            BroadcastCloseEvent();
sl@29
  1163
        }
sl@29
  1164
sl@30
  1165
        private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
sl@30
  1166
        {
sl@21
  1167
sl@30
  1168
        }
sl@30
  1169
sl@36
  1170
sl@30
  1171
        /// <summary>
sl@36
  1172
        ///
sl@30
  1173
        /// </summary>
sl@30
  1174
        /// <param name="aSessionId"></param>
sl@30
  1175
        /// <param name="aCallback"></param>
sl@55
  1176
        public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
sl@30
  1177
        {
sl@33
  1178
            if (this.InvokeRequired)
sl@30
  1179
            {
sl@30
  1180
                //Not in the proper thread, invoke ourselves
sl@30
  1181
                AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
sl@30
  1182
                this.Invoke(d, new object[] { aSessionId, aCallback });
sl@30
  1183
            }
sl@30
  1184
            else
sl@30
  1185
            {
sl@30
  1186
                //We are in the proper thread
sl@30
  1187
                //Add this session to our collection of clients
sl@33
  1188
                ClientData newClient = new ClientData(aSessionId, aCallback);
sl@33
  1189
                Program.iMainForm.iClients.Add(aSessionId, newClient);
sl@30
  1190
                //Add this session to our UI
sl@33
  1191
                UpdateClientTreeViewNode(newClient);
sl@30
  1192
            }
sl@30
  1193
        }
sl@30
  1194
sl@30
  1195
        /// <summary>
sl@36
  1196
        ///
sl@30
  1197
        /// </summary>
sl@30
  1198
        /// <param name="aSessionId"></param>
sl@30
  1199
        public void RemoveClientThreadSafe(string aSessionId)
sl@30
  1200
        {
sl@33
  1201
            if (this.InvokeRequired)
sl@30
  1202
            {
sl@30
  1203
                //Not in the proper thread, invoke ourselves
sl@30
  1204
                RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
sl@30
  1205
                this.Invoke(d, new object[] { aSessionId });
sl@30
  1206
            }
sl@30
  1207
            else
sl@30
  1208
            {
sl@30
  1209
                //We are in the proper thread
sl@33
  1210
                //Remove this session from both client collection and UI tree view
sl@30
  1211
                if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
sl@30
  1212
                {
sl@30
  1213
                    Program.iMainForm.iClients.Remove(aSessionId);
sl@30
  1214
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
sl@32
  1215
                }
sl@32
  1216
sl@97
  1217
				if (iClients.Count == 0)
sl@97
  1218
				{
sl@97
  1219
					//Clear our screen when last client disconnects
sl@97
  1220
					ClearLayout();
sl@97
  1221
sl@97
  1222
					if (iClosing)
sl@97
  1223
					{
sl@97
  1224
						//We were closing our form
sl@97
  1225
						//All clients are now closed
sl@97
  1226
						//Just resume our close operation
sl@97
  1227
						iClosing = false;
sl@97
  1228
						Close();
sl@97
  1229
					}
sl@97
  1230
				}
sl@30
  1231
            }
sl@30
  1232
        }
sl@30
  1233
sl@30
  1234
        /// <summary>
sl@36
  1235
        ///
sl@30
  1236
        /// </summary>
sl@62
  1237
        /// <param name="aSessionId"></param>
sl@72
  1238
        /// <param name="aLayout"></param>
sl@62
  1239
        public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
sl@62
  1240
        {
sl@62
  1241
            if (this.InvokeRequired)
sl@62
  1242
            {
sl@62
  1243
                //Not in the proper thread, invoke ourselves
sl@62
  1244
                SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
sl@62
  1245
                this.Invoke(d, new object[] { aSessionId, aLayout });
sl@62
  1246
            }
sl@62
  1247
            else
sl@62
  1248
            {
sl@62
  1249
                ClientData client = iClients[aSessionId];
sl@62
  1250
                if (client != null)
sl@62
  1251
                {
sl@62
  1252
                    client.Layout = aLayout;
sl@65
  1253
                    UpdateTableLayoutPanel(client);
sl@62
  1254
                    //
sl@62
  1255
                    UpdateClientTreeViewNode(client);
sl@62
  1256
                }
sl@62
  1257
            }
sl@62
  1258
        }
sl@62
  1259
sl@62
  1260
        /// <summary>
sl@62
  1261
        ///
sl@62
  1262
        /// </summary>
sl@67
  1263
        /// <param name="aSessionId"></param>
sl@72
  1264
        /// <param name="aField"></param>
sl@75
  1265
        public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
sl@30
  1266
        {
sl@33
  1267
            if (this.InvokeRequired)
sl@30
  1268
            {
sl@30
  1269
                //Not in the proper thread, invoke ourselves
sl@79
  1270
                SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
sl@72
  1271
                this.Invoke(d, new object[] { aSessionId, aField });
sl@30
  1272
            }
sl@30
  1273
            else
sl@30
  1274
            {
sl@75
  1275
                //We are in the proper thread
sl@75
  1276
                //Call the non-thread-safe variant
sl@75
  1277
                SetClientField(aSessionId, aField);
sl@75
  1278
            }
sl@75
  1279
        }
sl@75
  1280
sl@75
  1281
        /// <summary>
sl@79
  1282
        ///
sl@75
  1283
        /// </summary>
sl@75
  1284
        /// <param name="aSessionId"></param>
sl@75
  1285
        /// <param name="aField"></param>
sl@75
  1286
        private void SetClientField(string aSessionId, DataField aField)
sl@79
  1287
        {
sl@75
  1288
            SetCurrentClient(aSessionId);
sl@75
  1289
            ClientData client = iClients[aSessionId];
sl@75
  1290
            if (client != null)
sl@75
  1291
            {
sl@76
  1292
                bool somethingChanged = false;
sl@76
  1293
sl@75
  1294
                //Make sure all our fields are in place
sl@75
  1295
                while (client.Fields.Count < (aField.Index + 1))
sl@30
  1296
                {
sl@75
  1297
                    //Add a text field with proper index
sl@75
  1298
                    client.Fields.Add(new DataField(client.Fields.Count));
sl@76
  1299
                    somethingChanged = true;
sl@75
  1300
                }
sl@75
  1301
sl@75
  1302
                if (client.Fields[aField.Index].IsSameLayout(aField))
sl@75
  1303
                {
sl@75
  1304
                    //Same layout just update our field
sl@75
  1305
                    client.Fields[aField.Index] = aField;
sl@75
  1306
                    //
sl@75
  1307
                    if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
sl@79
  1308
                    {
sl@75
  1309
                        //Text field control already in place, just change the text
sl@72
  1310
                        MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
sl@76
  1311
                        somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
sl@72
  1312
                        label.Text = aField.Text;
sl@72
  1313
                        label.TextAlign = aField.Alignment;
sl@68
  1314
                    }
sl@75
  1315
                    else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
sl@75
  1316
                    {
sl@76
  1317
                        somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
sl@75
  1318
                        //Bitmap field control already in place just change the bitmap
sl@75
  1319
                        PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
sl@75
  1320
                        pictureBox.Image = aField.Bitmap;
sl@75
  1321
                    }
sl@68
  1322
                    else
sl@68
  1323
                    {
sl@76
  1324
                        somethingChanged = true;
sl@75
  1325
                        //The requested control in our layout it not of the correct type
sl@68
  1326
                        //Wrong control type, re-create them all
sl@68
  1327
                        UpdateTableLayoutPanel(iCurrentClientData);
sl@68
  1328
                    }
sl@30
  1329
                }
sl@75
  1330
                else
sl@75
  1331
                {
sl@76
  1332
                    somethingChanged = true;
sl@75
  1333
                    //Different layout, need to rebuild it
sl@75
  1334
                    client.Fields[aField.Index] = aField;
sl@75
  1335
                    UpdateTableLayoutPanel(iCurrentClientData);
sl@75
  1336
                }
sl@75
  1337
sl@75
  1338
                //
sl@76
  1339
                if (somethingChanged)
sl@76
  1340
                {
sl@76
  1341
                    UpdateClientTreeViewNode(client);
sl@76
  1342
                }
sl@30
  1343
            }
sl@30
  1344
        }
sl@30
  1345
sl@30
  1346
        /// <summary>
sl@36
  1347
        ///
sl@30
  1348
        /// </summary>
sl@30
  1349
        /// <param name="aTexts"></param>
sl@75
  1350
        public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
sl@30
  1351
        {
sl@33
  1352
            if (this.InvokeRequired)
sl@30
  1353
            {
sl@30
  1354
                //Not in the proper thread, invoke ourselves
sl@75
  1355
                SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
sl@72
  1356
                this.Invoke(d, new object[] { aSessionId, aFields });
sl@30
  1357
            }
sl@30
  1358
            else
sl@30
  1359
            {
sl@75
  1360
                //Put each our text fields in a label control
sl@75
  1361
                foreach (DataField field in aFields)
sl@30
  1362
                {
sl@75
  1363
                    SetClientField(aSessionId, field);
sl@30
  1364
                }
sl@30
  1365
            }
sl@32
  1366
        }
sl@30
  1367
sl@67
  1368
        /// <summary>
sl@67
  1369
        ///
sl@67
  1370
        /// </summary>
sl@67
  1371
        /// <param name="aSessionId"></param>
sl@32
  1372
        /// <param name="aName"></param>
sl@32
  1373
        public void SetClientNameThreadSafe(string aSessionId, string aName)
sl@32
  1374
        {
sl@32
  1375
            if (this.InvokeRequired)
sl@32
  1376
            {
sl@32
  1377
                //Not in the proper thread, invoke ourselves
sl@32
  1378
                SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
sl@32
  1379
                this.Invoke(d, new object[] { aSessionId, aName });
sl@32
  1380
            }
sl@32
  1381
            else
sl@32
  1382
            {
sl@32
  1383
                //We are in the proper thread
sl@33
  1384
                //Get our client
sl@33
  1385
                ClientData client = iClients[aSessionId];
sl@33
  1386
                if (client != null)
sl@32
  1387
                {
sl@33
  1388
                    //Set its name
sl@33
  1389
                    client.Name = aName;
sl@33
  1390
                    //Update our tree-view
sl@33
  1391
                    UpdateClientTreeViewNode(client);
sl@33
  1392
                }
sl@33
  1393
            }
sl@33
  1394
        }
sl@33
  1395
sl@33
  1396
        /// <summary>
sl@36
  1397
        ///
sl@33
  1398
        /// </summary>
sl@33
  1399
        /// <param name="aClient"></param>
sl@33
  1400
        private void UpdateClientTreeViewNode(ClientData aClient)
sl@33
  1401
        {
sl@33
  1402
            if (aClient == null)
sl@33
  1403
            {
sl@33
  1404
                return;
sl@33
  1405
            }
sl@33
  1406
sl@33
  1407
            TreeNode node = null;
sl@33
  1408
            //Check that our client node already exists
sl@33
  1409
            //Get our client root node using its key which is our session ID
sl@33
  1410
            TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
sl@33
  1411
            if (nodes.Count()>0)
sl@33
  1412
            {
sl@33
  1413
                //We already have a node for that client
sl@33
  1414
                node = nodes[0];
sl@33
  1415
                //Clear children as we are going to recreate them below
sl@33
  1416
                node.Nodes.Clear();
sl@33
  1417
            }
sl@33
  1418
            else
sl@33
  1419
            {
sl@33
  1420
                //Client node does not exists create a new one
sl@33
  1421
                treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
sl@33
  1422
                node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
sl@33
  1423
            }
sl@33
  1424
sl@33
  1425
            if (node != null)
sl@33
  1426
            {
sl@33
  1427
                //Change its name
sl@33
  1428
                if (aClient.Name != "")
sl@33
  1429
                {
sl@33
  1430
                    //We have a name, us it as text for our root node
sl@33
  1431
                    node.Text = aClient.Name;
sl@32
  1432
                    //Add a child with SessionId
sl@33
  1433
                    node.Nodes.Add(new TreeNode(aClient.SessionId));
sl@33
  1434
                }
sl@33
  1435
                else
sl@33
  1436
                {
sl@33
  1437
                    //No name, use session ID instead
sl@33
  1438
                    node.Text = aClient.SessionId;
sl@33
  1439
                }
sl@36
  1440
sl@67
  1441
                if (aClient.Fields.Count > 0)
sl@33
  1442
                {
sl@33
  1443
                    //Create root node for our texts
sl@70
  1444
                    TreeNode textsRoot = new TreeNode("Fields");
sl@33
  1445
                    node.Nodes.Add(textsRoot);
sl@33
  1446
                    //For each text add a new entry
sl@67
  1447
                    foreach (DataField field in aClient.Fields)
sl@33
  1448
                    {
sl@75
  1449
                        if (!field.IsBitmap)
sl@67
  1450
                        {
sl@72
  1451
                            DataField textField = (DataField)field;
sl@70
  1452
                            textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
sl@67
  1453
                        }
sl@67
  1454
                        else
sl@67
  1455
                        {
sl@72
  1456
                            textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
sl@70
  1457
                        }
sl@33
  1458
                    }
sl@32
  1459
                }
sl@34
  1460
sl@34
  1461
                node.ExpandAll();
sl@32
  1462
            }
sl@30
  1463
        }
sl@17
  1464
sl@60
  1465
        /// <summary>
sl@60
  1466
        /// Update our table layout row styles to make sure each rows have similar height
sl@60
  1467
        /// </summary>
sl@60
  1468
        private void UpdateTableLayoutRowStyles()
sl@60
  1469
        {
sl@60
  1470
            foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
sl@60
  1471
            {
sl@60
  1472
                rowStyle.SizeType = SizeType.Percent;
sl@60
  1473
                rowStyle.Height = 100 / tableLayoutPanel.RowCount;
sl@60
  1474
            }
sl@60
  1475
        }
sl@60
  1476
sl@70
  1477
        /// DEPRECATED
sl@60
  1478
        /// <summary>
sl@61
  1479
        /// Empty and recreate our table layout with the given number of columns and rows.
sl@61
  1480
        /// Sizes of rows and columns are uniform.
sl@60
  1481
        /// </summary>
sl@60
  1482
        /// <param name="aColumn"></param>
sl@60
  1483
        /// <param name="aRow"></param>
sl@62
  1484
        private void UpdateTableLayoutPanel(int aColumn, int aRow)
sl@60
  1485
        {
sl@61
  1486
            tableLayoutPanel.Controls.Clear();
sl@61
  1487
            tableLayoutPanel.RowStyles.Clear();
sl@61
  1488
            tableLayoutPanel.ColumnStyles.Clear();
sl@61
  1489
            tableLayoutPanel.RowCount = 0;
sl@61
  1490
            tableLayoutPanel.ColumnCount = 0;
sl@60
  1491
sl@61
  1492
            while (tableLayoutPanel.RowCount < aRow)
sl@61
  1493
            {
sl@61
  1494
                tableLayoutPanel.RowCount++;
sl@61
  1495
            }
sl@60
  1496
sl@61
  1497
            while (tableLayoutPanel.ColumnCount < aColumn)
sl@61
  1498
            {
sl@61
  1499
                tableLayoutPanel.ColumnCount++;
sl@61
  1500
            }
sl@61
  1501
sl@61
  1502
            for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
sl@61
  1503
            {
sl@61
  1504
                //Create our column styles
sl@61
  1505
                this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
sl@61
  1506
sl@61
  1507
                for (int j = 0; j < tableLayoutPanel.RowCount; j++)
sl@61
  1508
                {
sl@61
  1509
                    if (i == 0)
sl@61
  1510
                    {
sl@61
  1511
                        //Create our row styles
sl@61
  1512
                        this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
sl@61
  1513
                    }
sl@61
  1514
sl@61
  1515
                    MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
sl@61
  1516
                    control.AutoEllipsis = true;
sl@61
  1517
                    control.AutoSize = true;
sl@61
  1518
                    control.BackColor = System.Drawing.Color.Transparent;
sl@61
  1519
                    control.Dock = System.Windows.Forms.DockStyle.Fill;
sl@61
  1520
                    control.Location = new System.Drawing.Point(1, 1);
sl@61
  1521
                    control.Margin = new System.Windows.Forms.Padding(0);
sl@61
  1522
                    control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
sl@61
  1523
                    control.OwnTimer = false;
sl@61
  1524
                    control.PixelsPerSecond = 64;
sl@100
  1525
                    control.Separator = cds.Separator;
sl@100
  1526
                    control.MinFontSize = cds.MinFontSize;
sl@100
  1527
                    control.ScaleToFit = cds.ScaleToFit;
sl@61
  1528
                    //control.Size = new System.Drawing.Size(254, 30);
sl@61
  1529
                    //control.TabIndex = 2;
sl@61
  1530
                    control.Font = cds.Font;
sl@61
  1531
                    control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
sl@61
  1532
                    control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
sl@61
  1533
                    control.UseCompatibleTextRendering = true;
sl@61
  1534
                    //
sl@61
  1535
                    tableLayoutPanel.Controls.Add(control, i, j);
sl@61
  1536
                }
sl@61
  1537
            }
sl@38
  1538
sl@62
  1539
            CheckFontHeight();
sl@38
  1540
        }
sl@38
  1541
sl@63
  1542
sl@63
  1543
        /// <summary>
sl@63
  1544
        /// Update our display table layout.
sl@63
  1545
        /// </summary>
sl@63
  1546
        /// <param name="aLayout"></param>
sl@65
  1547
        private void UpdateTableLayoutPanel(ClientData aClient)
sl@63
  1548
        {
StephaneLenclud@106
  1549
			if (aClient == null)
StephaneLenclud@106
  1550
			{
StephaneLenclud@106
  1551
				//Just drop it
StephaneLenclud@106
  1552
				return;
StephaneLenclud@106
  1553
			}
StephaneLenclud@106
  1554
StephaneLenclud@106
  1555
sl@65
  1556
            TableLayout layout = aClient.Layout;
sl@70
  1557
            int fieldCount = 0;
sl@70
  1558
sl@63
  1559
            tableLayoutPanel.Controls.Clear();
sl@63
  1560
            tableLayoutPanel.RowStyles.Clear();
sl@63
  1561
            tableLayoutPanel.ColumnStyles.Clear();
sl@63
  1562
            tableLayoutPanel.RowCount = 0;
sl@63
  1563
            tableLayoutPanel.ColumnCount = 0;
sl@63
  1564
sl@65
  1565
            while (tableLayoutPanel.RowCount < layout.Rows.Count)
sl@63
  1566
            {
sl@63
  1567
                tableLayoutPanel.RowCount++;
sl@63
  1568
            }
sl@63
  1569
sl@65
  1570
            while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
sl@63
  1571
            {
sl@63
  1572
                tableLayoutPanel.ColumnCount++;
sl@63
  1573
            }
sl@63
  1574
sl@63
  1575
            for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
sl@63
  1576
            {
sl@63
  1577
                //Create our column styles
sl@65
  1578
                this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
sl@63
  1579
sl@63
  1580
                for (int j = 0; j < tableLayoutPanel.RowCount; j++)
sl@63
  1581
                {
sl@63
  1582
                    if (i == 0)
sl@63
  1583
                    {
sl@63
  1584
                        //Create our row styles
sl@65
  1585
                        this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
sl@63
  1586
                    }
sl@63
  1587
sl@70
  1588
                    //Check if we already have a control
sl@70
  1589
                    Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
sl@70
  1590
                    if (existingControl!=null)
sl@70
  1591
                    {
sl@70
  1592
                        //We already have a control in that cell as a results of row/col spanning
sl@70
  1593
                        //Move on to next cell then
sl@70
  1594
                        continue;
sl@70
  1595
                    }
sl@70
  1596
sl@70
  1597
                    fieldCount++;
sl@70
  1598
sl@69
  1599
                    //Check if a client field already exists for that cell
sl@69
  1600
                    if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
sl@65
  1601
                    {
sl@69
  1602
                        //No client field specified, create a text field by default
sl@72
  1603
                        aClient.Fields.Add(new DataField(aClient.Fields.Count));
sl@65
  1604
                    }
sl@68
  1605
sl@69
  1606
                    //Create a control corresponding to the field specified for that cell
sl@70
  1607
                    DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
sl@70
  1608
                    Control control = CreateControlForDataField(field);
sl@70
  1609
sl@69
  1610
                    //Add newly created control to our table layout at the specified row and column
sl@63
  1611
                    tableLayoutPanel.Controls.Add(control, i, j);
sl@70
  1612
                    //Make sure we specify row and column span for that new control
sl@70
  1613
                    tableLayoutPanel.SetRowSpan(control,field.RowSpan);
sl@70
  1614
                    tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
sl@63
  1615
                }
sl@63
  1616
            }
sl@63
  1617
sl@70
  1618
            //
sl@70
  1619
            while (aClient.Fields.Count > fieldCount)
sl@70
  1620
            {
sl@70
  1621
                //We have too much fields for this layout
sl@70
  1622
                //Just discard them until we get there
sl@70
  1623
                aClient.Fields.RemoveAt(aClient.Fields.Count-1);
sl@70
  1624
            }
sl@70
  1625
sl@63
  1626
            CheckFontHeight();
sl@63
  1627
        }
sl@63
  1628
sl@68
  1629
        /// <summary>
sl@70
  1630
        /// Check our type of data field and create corresponding control
sl@68
  1631
        /// </summary>
sl@68
  1632
        /// <param name="aField"></param>
sl@69
  1633
        private Control CreateControlForDataField(DataField aField)
sl@68
  1634
        {
sl@68
  1635
            Control control=null;
sl@75
  1636
            if (!aField.IsBitmap)
sl@68
  1637
            {
sl@68
  1638
                MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
sl@68
  1639
                label.AutoEllipsis = true;
sl@68
  1640
                label.AutoSize = true;
sl@68
  1641
                label.BackColor = System.Drawing.Color.Transparent;
sl@68
  1642
                label.Dock = System.Windows.Forms.DockStyle.Fill;
sl@68
  1643
                label.Location = new System.Drawing.Point(1, 1);
sl@68
  1644
                label.Margin = new System.Windows.Forms.Padding(0);
sl@68
  1645
                label.Name = "marqueeLabel" + aField.Index;
sl@68
  1646
                label.OwnTimer = false;
StephaneLenclud@106
  1647
                label.PixelsPerSecond = cds.ScrollingSpeedInPixelsPerSecond;
sl@100
  1648
                label.Separator = cds.Separator;
sl@100
  1649
                label.MinFontSize = cds.MinFontSize;
sl@100
  1650
                label.ScaleToFit = cds.ScaleToFit;
sl@68
  1651
                //control.Size = new System.Drawing.Size(254, 30);
sl@68
  1652
                //control.TabIndex = 2;
sl@68
  1653
                label.Font = cds.Font;
sl@68
  1654
StephaneLenclud@106
  1655
				label.TextAlign = aField.Alignment;
sl@68
  1656
                label.UseCompatibleTextRendering = true;
sl@72
  1657
                label.Text = aField.Text;
sl@68
  1658
                //
sl@68
  1659
                control = label;
sl@68
  1660
            }
sl@72
  1661
            else
sl@68
  1662
            {
sl@68
  1663
                //Create picture box
sl@68
  1664
                PictureBox picture = new PictureBox();
sl@68
  1665
                picture.AutoSize = true;
sl@68
  1666
                picture.BackColor = System.Drawing.Color.Transparent;
sl@68
  1667
                picture.Dock = System.Windows.Forms.DockStyle.Fill;
sl@68
  1668
                picture.Location = new System.Drawing.Point(1, 1);
sl@68
  1669
                picture.Margin = new System.Windows.Forms.Padding(0);
sl@68
  1670
                picture.Name = "pictureBox" + aField;
sl@68
  1671
                //Set our image
sl@72
  1672
                picture.Image = aField.Bitmap;
sl@68
  1673
                //
sl@68
  1674
                control = picture;
sl@68
  1675
            }
sl@68
  1676
sl@69
  1677
            return control;
sl@68
  1678
        }
sl@68
  1679
StephaneLenclud@103
  1680
		/// <summary>
StephaneLenclud@103
  1681
		/// Called when the user selected a new display type.
StephaneLenclud@103
  1682
		/// </summary>
StephaneLenclud@103
  1683
		/// <param name="sender"></param>
StephaneLenclud@103
  1684
		/// <param name="e"></param>
sl@46
  1685
        private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
sl@46
  1686
        {
StephaneLenclud@103
  1687
			//Store the selected display type in our settings
sl@48
  1688
            Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
sl@48
  1689
            cds.DisplayType = comboBoxDisplayType.SelectedIndex;
sl@46
  1690
            Properties.Settings.Default.Save();
StephaneLenclud@103
  1691
StephaneLenclud@103
  1692
			//Try re-opening the display connection if we were already connected.
StephaneLenclud@103
  1693
			//Otherwise just update our status to reflect display type change.
sl@51
  1694
            if (iDisplay.IsOpen())
sl@51
  1695
            {
sl@51
  1696
                OpenDisplayConnection();
sl@51
  1697
            }
sl@51
  1698
            else
sl@51
  1699
            {
sl@51
  1700
                UpdateStatus();
sl@51
  1701
            }
sl@46
  1702
        }
sl@46
  1703
sl@47
  1704
        private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
sl@47
  1705
        {
sl@47
  1706
            if (maskedTextBoxTimerInterval.Text != "")
sl@47
  1707
            {
sl@51
  1708
                int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
sl@51
  1709
sl@51
  1710
                if (interval > 0)
sl@51
  1711
                {
sl@51
  1712
                    timer.Interval = interval;
sl@51
  1713
                    cds.TimerInterval = timer.Interval;
sl@51
  1714
                    Properties.Settings.Default.Save();
sl@51
  1715
                }
sl@47
  1716
            }
sl@47
  1717
        }
sl@47
  1718
sl@100
  1719
        private void maskedTextBoxMinFontSize_TextChanged(object sender, EventArgs e)
sl@100
  1720
        {
sl@100
  1721
            if (maskedTextBoxMinFontSize.Text != "")
sl@100
  1722
            {
sl@100
  1723
                int minFontSize = Convert.ToInt32(maskedTextBoxMinFontSize.Text);
sl@100
  1724
sl@100
  1725
                if (minFontSize > 0)
sl@100
  1726
                {
sl@100
  1727
                    cds.MinFontSize = minFontSize;
sl@100
  1728
                    Properties.Settings.Default.Save();
StephaneLenclud@106
  1729
					//We need to recreate our layout for that change to take effect
StephaneLenclud@106
  1730
					UpdateTableLayoutPanel(iCurrentClientData);
sl@100
  1731
                }
sl@100
  1732
            }
sl@100
  1733
        }
sl@100
  1734
StephaneLenclud@106
  1735
StephaneLenclud@106
  1736
		private void maskedTextBoxScrollingSpeed_TextChanged(object sender, EventArgs e)
StephaneLenclud@106
  1737
		{
StephaneLenclud@106
  1738
			if (maskedTextBoxScrollingSpeed.Text != "")
StephaneLenclud@106
  1739
			{
StephaneLenclud@106
  1740
				int scrollingSpeed = Convert.ToInt32(maskedTextBoxScrollingSpeed.Text);
StephaneLenclud@106
  1741
StephaneLenclud@106
  1742
				if (scrollingSpeed > 0)
StephaneLenclud@106
  1743
				{
StephaneLenclud@106
  1744
					cds.ScrollingSpeedInPixelsPerSecond = scrollingSpeed;
StephaneLenclud@106
  1745
					Properties.Settings.Default.Save();
StephaneLenclud@106
  1746
					//We need to recreate our layout for that change to take effect
StephaneLenclud@106
  1747
					UpdateTableLayoutPanel(iCurrentClientData);
StephaneLenclud@106
  1748
				}
StephaneLenclud@106
  1749
			}
StephaneLenclud@106
  1750
		}
StephaneLenclud@106
  1751
sl@100
  1752
        private void textBoxScrollLoopSeparator_TextChanged(object sender, EventArgs e)
sl@100
  1753
        {
sl@100
  1754
            cds.Separator = textBoxScrollLoopSeparator.Text;
sl@100
  1755
            Properties.Settings.Default.Save();
StephaneLenclud@110
  1756
StephaneLenclud@110
  1757
			//Update our text fields
StephaneLenclud@110
  1758
			foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
StephaneLenclud@110
  1759
			{
StephaneLenclud@110
  1760
				ctrl.Separator = cds.Separator;
StephaneLenclud@110
  1761
			}
StephaneLenclud@110
  1762
sl@100
  1763
        }
sl@100
  1764
sl@52
  1765
        private void buttonPowerOn_Click(object sender, EventArgs e)
sl@52
  1766
        {
sl@52
  1767
            iDisplay.PowerOn();
sl@52
  1768
        }
sl@52
  1769
sl@52
  1770
        private void buttonPowerOff_Click(object sender, EventArgs e)
sl@52
  1771
        {
sl@52
  1772
            iDisplay.PowerOff();
sl@52
  1773
        }
sl@52
  1774
sl@53
  1775
        private void buttonShowClock_Click(object sender, EventArgs e)
sl@53
  1776
        {
sl@53
  1777
            iDisplay.ShowClock();
sl@53
  1778
        }
sl@53
  1779
sl@53
  1780
        private void buttonHideClock_Click(object sender, EventArgs e)
sl@53
  1781
        {
sl@53
  1782
            iDisplay.HideClock();
sl@53
  1783
        }
sl@88
  1784
sl@88
  1785
        private void buttonUpdate_Click(object sender, EventArgs e)
sl@88
  1786
        {
sl@88
  1787
            InstallUpdateSyncWithInfo();
sl@88
  1788
        }
sl@88
  1789
sl@88
  1790
sl@88
  1791
        private void InstallUpdateSyncWithInfo()
sl@88
  1792
        {
sl@88
  1793
            UpdateCheckInfo info = null;
sl@88
  1794
sl@88
  1795
            if (ApplicationDeployment.IsNetworkDeployed)
sl@88
  1796
            {
sl@88
  1797
                ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
sl@88
  1798
sl@88
  1799
                try
sl@88
  1800
                {
sl@88
  1801
                    info = ad.CheckForDetailedUpdate();
sl@88
  1802
sl@88
  1803
                }
sl@88
  1804
                catch (DeploymentDownloadException dde)
sl@88
  1805
                {
sl@88
  1806
                    MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
sl@88
  1807
                    return;
sl@88
  1808
                }
sl@88
  1809
                catch (InvalidDeploymentException ide)
sl@88
  1810
                {
sl@88
  1811
                    MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
sl@88
  1812
                    return;
sl@88
  1813
                }
sl@88
  1814
                catch (InvalidOperationException ioe)
sl@88
  1815
                {
sl@88
  1816
                    MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
sl@88
  1817
                    return;
sl@88
  1818
                }
sl@88
  1819
sl@90
  1820
				if (info.UpdateAvailable)
sl@90
  1821
				{
sl@90
  1822
					Boolean doUpdate = true;
sl@88
  1823
sl@90
  1824
					if (!info.IsUpdateRequired)
sl@90
  1825
					{
sl@90
  1826
						DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
sl@90
  1827
						if (!(DialogResult.OK == dr))
sl@90
  1828
						{
sl@90
  1829
							doUpdate = false;
sl@90
  1830
						}
sl@90
  1831
					}
sl@90
  1832
					else
sl@90
  1833
					{
sl@90
  1834
						// Display a message that the app MUST reboot. Display the minimum required version.
sl@90
  1835
						MessageBox.Show("This application has detected a mandatory update from your current " +
sl@90
  1836
							"version to version " + info.MinimumRequiredVersion.ToString() +
sl@90
  1837
							". The application will now install the update and restart.",
sl@90
  1838
							"Update Available", MessageBoxButtons.OK,
sl@90
  1839
							MessageBoxIcon.Information);
sl@90
  1840
					}
sl@88
  1841
sl@90
  1842
					if (doUpdate)
sl@90
  1843
					{
sl@90
  1844
						try
sl@90
  1845
						{
sl@90
  1846
							ad.Update();
sl@90
  1847
							MessageBox.Show("The application has been upgraded, and will now restart.");
sl@90
  1848
							Application.Restart();
sl@90
  1849
						}
sl@90
  1850
						catch (DeploymentDownloadException dde)
sl@90
  1851
						{
sl@90
  1852
							MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
sl@90
  1853
							return;
sl@90
  1854
						}
sl@90
  1855
					}
sl@90
  1856
				}
sl@90
  1857
				else
sl@90
  1858
				{
sl@90
  1859
					MessageBox.Show("You are already running the latest version.", "Application up-to-date");
sl@90
  1860
				}
sl@88
  1861
            }
sl@88
  1862
        }
sl@92
  1863
sl@94
  1864
sl@94
  1865
		/// <summary>
sl@99
  1866
		/// Used to
sl@94
  1867
		/// </summary>
sl@94
  1868
		private void SysTrayHideShow()
sl@92
  1869
		{
sl@94
  1870
			Visible = !Visible;
sl@94
  1871
			if (Visible)
sl@94
  1872
			{
sl@94
  1873
				Activate();
sl@94
  1874
				WindowState = FormWindowState.Normal;
sl@94
  1875
			}
sl@92
  1876
		}
sl@94
  1877
sl@94
  1878
		/// <summary>
sl@94
  1879
		/// Use to handle minimize events.
sl@94
  1880
		/// </summary>
sl@94
  1881
		/// <param name="sender"></param>
sl@94
  1882
		/// <param name="e"></param>
sl@94
  1883
		private void MainForm_SizeChanged(object sender, EventArgs e)
sl@94
  1884
		{
sl@94
  1885
			if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
sl@94
  1886
			{
sl@94
  1887
				if (Visible)
sl@94
  1888
				{
sl@94
  1889
					SysTrayHideShow();
sl@94
  1890
				}
sl@94
  1891
			}
sl@99
  1892
sl@94
  1893
		}
sl@94
  1894
StephaneLenclud@105
  1895
		/// <summary>
StephaneLenclud@105
  1896
		/// 
StephaneLenclud@105
  1897
		/// </summary>
StephaneLenclud@105
  1898
		/// <param name="sender"></param>
StephaneLenclud@105
  1899
		/// <param name="e"></param>
StephaneLenclud@105
  1900
		private void tableLayoutPanel_SizeChanged(object sender, EventArgs e)
StephaneLenclud@105
  1901
		{
StephaneLenclud@105
  1902
			//Our table layout size has changed which means our display size has changed.
StephaneLenclud@105
  1903
			//We need to re-create our bitmap.
StephaneLenclud@105
  1904
			iCreateBitmap = true;
StephaneLenclud@105
  1905
		}
sl@100
  1906
sl@0
  1907
    }
sl@34
  1908
sl@34
  1909
    /// <summary>
sl@34
  1910
    /// A UI thread copy of a client relevant data.
sl@34
  1911
    /// Keeping this copy in the UI thread helps us deal with threading issues.
sl@34
  1912
    /// </summary>
sl@34
  1913
    public class ClientData
sl@34
  1914
    {
sl@55
  1915
        public ClientData(string aSessionId, ICallback aCallback)
sl@34
  1916
        {
sl@34
  1917
            SessionId = aSessionId;
sl@34
  1918
            Name = "";
sl@67
  1919
            Fields = new List<DataField>();
sl@62
  1920
            Layout = new TableLayout(1, 2); //Default to one column and two rows
sl@34
  1921
            Callback = aCallback;
sl@34
  1922
        }
sl@34
  1923
sl@34
  1924
        public string SessionId { get; set; }
sl@34
  1925
        public string Name { get; set; }
sl@67
  1926
        public List<DataField> Fields { get; set; }
sl@62
  1927
        public TableLayout Layout { get; set; }
sl@55
  1928
        public ICallback Callback { get; set; }
sl@34
  1929
    }
sl@0
  1930
}