StephaneLenclud@123: //
StephaneLenclud@123: // Copyright (C) 2014-2015 Stéphane Lenclud.
StephaneLenclud@123: //
StephaneLenclud@123: // This file is part of SharpDisplayManager.
StephaneLenclud@123: //
StephaneLenclud@123: // SharpDisplayManager is free software: you can redistribute it and/or modify
StephaneLenclud@123: // it under the terms of the GNU General Public License as published by
StephaneLenclud@123: // the Free Software Foundation, either version 3 of the License, or
StephaneLenclud@123: // (at your option) any later version.
StephaneLenclud@123: //
StephaneLenclud@123: // SharpDisplayManager is distributed in the hope that it will be useful,
StephaneLenclud@123: // but WITHOUT ANY WARRANTY; without even the implied warranty of
StephaneLenclud@123: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
StephaneLenclud@123: // GNU General Public License for more details.
StephaneLenclud@123: //
StephaneLenclud@123: // You should have received a copy of the GNU General Public License
StephaneLenclud@123: // along with SharpDisplayManager. If not, see .
StephaneLenclud@123: //
StephaneLenclud@123:
StephaneLenclud@123: using System;
sl@0: using System.Collections.Generic;
sl@0: using System.ComponentModel;
sl@0: using System.Data;
sl@0: using System.Drawing;
sl@0: using System.Linq;
sl@0: using System.Text;
sl@0: using System.Threading.Tasks;
sl@0: using System.Windows.Forms;
sl@14: using System.IO;
sl@0: using CodeProject.Dialog;
sl@14: using System.Drawing.Imaging;
sl@17: using System.ServiceModel;
sl@25: using System.Threading;
sl@31: using System.Diagnostics;
sl@88: using System.Deployment.Application;
sl@94: using System.Reflection;
StephaneLenclud@112: //NAudio
StephaneLenclud@112: using NAudio.CoreAudioApi;
StephaneLenclud@112: using NAudio.CoreAudioApi.Interfaces;
StephaneLenclud@112: using System.Runtime.InteropServices;
StephaneLenclud@117: //Network
StephaneLenclud@117: using NETWORKLIST;
sl@25: //
sl@25: using SharpDisplayClient;
sl@55: using SharpDisplay;
StephaneLenclud@135: using MiniDisplayInterop;
StephaneLenclud@171: using SharpLib.Display;
StephaneLenclud@124:
sl@0: namespace SharpDisplayManager
sl@0: {
sl@58: //Types declarations
sl@58: public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
sl@58: public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
sl@62: //Delegates are used for our thread safe method
sl@62: public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
sl@62: public delegate void RemoveClientDelegate(string aSessionId);
sl@79: public delegate void SetFieldDelegate(string SessionId, DataField aField);
sl@79: public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList aFields);
sl@62: public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
sl@62: public delegate void SetClientNameDelegate(string aSessionId, string aName);
StephaneLenclud@184: public delegate void SetClientPriorityDelegate(string aSessionId, uint aPriority);
StephaneLenclud@184: public delegate void PlainUpdateDelegate();
StephaneLenclud@167: public delegate void WndProcDelegate(ref Message aMessage);
sl@58:
sl@58: ///
sl@58: /// Our Display manager main form
sl@58: ///
StephaneLenclud@126: [System.ComponentModel.DesignerCategory("Form")]
StephaneLenclud@126: public partial class MainForm : MainFormHid, IMMNotificationClient
sl@0: {
sl@2: DateTime LastTickTime;
sl@3: Display iDisplay;
sl@14: System.Drawing.Bitmap iBmp;
sl@14: bool iCreateBitmap; //Workaround render to bitmap issues when minimized
sl@17: ServiceHost iServiceHost;
sl@65: // Our collection of clients sorted by session id.
sl@33: public Dictionary iClients;
sl@65: // The name of the client which informations are currently displayed.
sl@65: public string iCurrentClientSessionId;
sl@65: ClientData iCurrentClientData;
sl@65: //
sl@29: public bool iClosing;
StephaneLenclud@122: //
StephaneLenclud@122: public bool iSkipFrameRendering;
sl@65: //Function pointer for pixel color filtering
sl@58: ColorProcessingDelegate iColorFx;
sl@65: //Function pointer for pixel X coordinate intercept
sl@58: CoordinateTranslationDelegate iScreenX;
sl@65: //Function pointer for pixel Y coordinate intercept
sl@58: CoordinateTranslationDelegate iScreenY;
StephaneLenclud@112: //NAudio
StephaneLenclud@112: private MMDeviceEnumerator iMultiMediaDeviceEnumerator;
StephaneLenclud@112: private MMDevice iMultiMediaDevice;
StephaneLenclud@117: //Network
StephaneLenclud@117: private NetworkManager iNetworkManager;
StephaneLenclud@167:
StephaneLenclud@167: ///
StephaneLenclud@167: /// CEC - Consumer Electronic Control.
StephaneLenclud@167: /// Notably used to turn TV on and off as Windows broadcast monitor on and off notifications.
StephaneLenclud@167: ///
StephaneLenclud@167: private ConsumerElectronicControl iCecManager;
StephaneLenclud@112:
sl@94: ///
sl@94: /// Manage run when Windows startup option
sl@94: ///
sl@92: private StartupManager iStartupManager;
sl@92:
sl@94: ///
StephaneLenclud@179: /// System notification icon used to hide our application from the task bar.
sl@94: ///
StephaneLenclud@173: private SharpLib.Notification.Control iNotifyIcon;
sl@94:
StephaneLenclud@167: ///
StephaneLenclud@194: /// System recording notification icon.
StephaneLenclud@179: ///
StephaneLenclud@179: private SharpLib.Notification.Control iRecordingNotification;
StephaneLenclud@179:
StephaneLenclud@179:
StephaneLenclud@179: ///
StephaneLenclud@167: /// Allow user to receive window messages;
StephaneLenclud@167: ///
StephaneLenclud@167: public event WndProcDelegate OnWndProc;
StephaneLenclud@167:
sl@0: public MainForm()
sl@0: {
StephaneLenclud@122: iSkipFrameRendering = false;
StephaneLenclud@122: iClosing = false;
sl@65: iCurrentClientSessionId = "";
sl@65: iCurrentClientData = null;
sl@2: LastTickTime = DateTime.Now;
StephaneLenclud@104: //Instantiate our display and register for events notifications
sl@3: iDisplay = new Display();
StephaneLenclud@104: iDisplay.OnOpened += OnDisplayOpened;
StephaneLenclud@104: iDisplay.OnClosed += OnDisplayClosed;
StephaneLenclud@104: //
StephaneLenclud@104: iClients = new Dictionary();
sl@92: iStartupManager = new StartupManager();
StephaneLenclud@173: iNotifyIcon = new SharpLib.Notification.Control();
StephaneLenclud@179: iRecordingNotification = new SharpLib.Notification.Control();
sl@2:
StephaneLenclud@179: //Have our designer initialize its controls
sl@0: InitializeComponent();
StephaneLenclud@104:
StephaneLenclud@104: //Populate device types
StephaneLenclud@104: PopulateDeviceTypes();
StephaneLenclud@104:
StephaneLenclud@152: //Populate optical drives
StephaneLenclud@152: PopulateOpticalDrives();
StephaneLenclud@152:
StephaneLenclud@104: //Initial status update
sl@7: UpdateStatus();
StephaneLenclud@104:
sl@14: //We have a bug when drawing minimized and reusing our bitmap
StephaneLenclud@158: //Though I could not reproduce it on Windows 10
StephaneLenclud@175: iBmp = new System.Drawing.Bitmap(iTableLayoutPanel.Width, iTableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14: iCreateBitmap = false;
sl@94:
StephaneLenclud@104: //Minimize our window if desired
sl@94: if (Properties.Settings.Default.StartMinimized)
sl@94: {
sl@94: WindowState = FormWindowState.Minimized;
sl@94: }
sl@94:
sl@0: }
sl@0:
sl@94: ///
StephaneLenclud@106: ///
StephaneLenclud@106: ///
StephaneLenclud@106: ///
StephaneLenclud@106: ///
StephaneLenclud@106: private void MainForm_Load(object sender, EventArgs e)
StephaneLenclud@106: {
StephaneLenclud@106: //Check if we are running a Click Once deployed application
StephaneLenclud@106: if (ApplicationDeployment.IsNetworkDeployed)
StephaneLenclud@106: {
StephaneLenclud@106: //This is a proper Click Once installation, fetch and show our version number
StephaneLenclud@106: this.Text += " - v" + ApplicationDeployment.CurrentDeployment.CurrentVersion;
StephaneLenclud@106: }
StephaneLenclud@106: else
StephaneLenclud@106: {
StephaneLenclud@106: //Not a proper Click Once installation, assuming development build then
StephaneLenclud@106: this.Text += " - development";
StephaneLenclud@106: }
StephaneLenclud@106:
StephaneLenclud@112: //NAudio
StephaneLenclud@112: iMultiMediaDeviceEnumerator = new MMDeviceEnumerator();
StephaneLenclud@117: iMultiMediaDeviceEnumerator.RegisterEndpointNotificationCallback(this);
StephaneLenclud@112: UpdateAudioDeviceAndMasterVolumeThreadSafe();
StephaneLenclud@112:
StephaneLenclud@117: //Network
StephaneLenclud@117: iNetworkManager = new NetworkManager();
StephaneLenclud@117: iNetworkManager.OnConnectivityChanged += OnConnectivityChanged;
StephaneLenclud@117: UpdateNetworkStatus();
StephaneLenclud@117:
StephaneLenclud@167: //CEC
StephaneLenclud@167: iCecManager = new ConsumerElectronicControl();
StephaneLenclud@167: OnWndProc += iCecManager.OnWndProc;
StephaneLenclud@168: ResetCec();
StephaneLenclud@168:
StephaneLenclud@167:
StephaneLenclud@167: //Setup notification icon
StephaneLenclud@167: SetupTrayIcon();
StephaneLenclud@106:
StephaneLenclud@179: //Setup recording notification
StephaneLenclud@179: SetupRecordingNotification();
StephaneLenclud@179:
StephaneLenclud@179: // To make sure start up with minimize to tray works
StephaneLenclud@179: if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
StephaneLenclud@106: {
StephaneLenclud@106: Visible = false;
StephaneLenclud@106: }
StephaneLenclud@106:
StephaneLenclud@106: #if !DEBUG
StephaneLenclud@106: //When not debugging we want the screen to be empty until a client takes over
StephaneLenclud@106: ClearLayout();
StephaneLenclud@106: #else
StephaneLenclud@106: //When developing we want at least one client for testing
StephaneLenclud@106: StartNewClient("abcdefghijklmnopqrst-0123456789","ABCDEFGHIJKLMNOPQRST-0123456789");
StephaneLenclud@106: #endif
StephaneLenclud@106:
StephaneLenclud@106: //Open display connection on start-up if needed
StephaneLenclud@106: if (Properties.Settings.Default.DisplayConnectOnStartup)
StephaneLenclud@106: {
StephaneLenclud@106: OpenDisplayConnection();
StephaneLenclud@106: }
StephaneLenclud@106:
StephaneLenclud@106: //Start our server so that we can get client requests
StephaneLenclud@106: StartServer();
StephaneLenclud@124:
StephaneLenclud@124: //Register for HID events
StephaneLenclud@124: RegisterHidDevices();
StephaneLenclud@194:
StephaneLenclud@194: //Start Idle client if needed
StephaneLenclud@194: if (Properties.Settings.Default.StartIdleClient)
StephaneLenclud@194: {
StephaneLenclud@194: StartIdleClient();
StephaneLenclud@194: }
StephaneLenclud@106: }
StephaneLenclud@106:
StephaneLenclud@106: ///
StephaneLenclud@104: /// Called when our display is opened.
StephaneLenclud@104: ///
StephaneLenclud@104: ///
StephaneLenclud@104: private void OnDisplayOpened(Display aDisplay)
StephaneLenclud@104: {
StephaneLenclud@187: //Make sure we resume frame rendering
StephaneLenclud@187: iSkipFrameRendering = false;
StephaneLenclud@122:
StephaneLenclud@105: //Set our screen size now that our display is connected
StephaneLenclud@105: //Our panelDisplay is the container of our tableLayoutPanel
StephaneLenclud@105: //tableLayoutPanel will resize itself to fit the client size of our panelDisplay
StephaneLenclud@105: //panelDisplay needs an extra 2 pixels for borders on each sides
StephaneLenclud@105: //tableLayoutPanel will eventually be the exact size of our display
StephaneLenclud@105: Size size = new Size(iDisplay.WidthInPixels() + 2, iDisplay.HeightInPixels() + 2);
StephaneLenclud@105: panelDisplay.Size = size;
StephaneLenclud@105:
StephaneLenclud@104: //Our display was just opened, update our UI
StephaneLenclud@104: UpdateStatus();
StephaneLenclud@104: //Initiate asynchronous request
StephaneLenclud@104: iDisplay.RequestFirmwareRevision();
StephaneLenclud@108:
StephaneLenclud@117: //Audio
StephaneLenclud@112: UpdateMasterVolumeThreadSafe();
StephaneLenclud@117: //Network
StephaneLenclud@117: UpdateNetworkStatus();
StephaneLenclud@112:
StephaneLenclud@108: #if DEBUG
StephaneLenclud@108: //Testing icon in debug, no arm done if icon not supported
StephaneLenclud@109: //iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconRecording, 0, 1);
StephaneLenclud@112: //iDisplay.SetAllIconsStatus(2);
StephaneLenclud@108: #endif
StephaneLenclud@108:
StephaneLenclud@104: }
StephaneLenclud@104:
StephaneLenclud@104: ///
StephaneLenclud@104: /// Called when our display is closed.
StephaneLenclud@104: ///
StephaneLenclud@104: ///
StephaneLenclud@104: private void OnDisplayClosed(Display aDisplay)
StephaneLenclud@104: {
StephaneLenclud@187: //Our display was just closed, update our UI consequently
StephaneLenclud@187: UpdateStatus();
StephaneLenclud@104: }
StephaneLenclud@117:
StephaneLenclud@117: public void OnConnectivityChanged(NetworkManager aNetwork, NLM_CONNECTIVITY newConnectivity)
StephaneLenclud@117: {
StephaneLenclud@117: //Update network status
StephaneLenclud@117: UpdateNetworkStatus();
StephaneLenclud@117: }
StephaneLenclud@117:
StephaneLenclud@117: ///
StephaneLenclud@117: /// Update our Network Status
StephaneLenclud@117: ///
StephaneLenclud@117: private void UpdateNetworkStatus()
StephaneLenclud@117: {
StephaneLenclud@117: if (iDisplay.IsOpen())
StephaneLenclud@117: {
StephaneLenclud@135: iDisplay.SetIconOnOff(MiniDisplay.IconType.Internet, iNetworkManager.NetworkListManager.IsConnectedToInternet);
StephaneLenclud@135: iDisplay.SetIconOnOff(MiniDisplay.IconType.NetworkSignal, iNetworkManager.NetworkListManager.IsConnected);
StephaneLenclud@117: }
StephaneLenclud@117: }
StephaneLenclud@117:
StephaneLenclud@117:
StephaneLenclud@118: int iLastNetworkIconIndex = 0;
StephaneLenclud@118: int iUpdateCountSinceLastNetworkAnimation = 0;
StephaneLenclud@118:
StephaneLenclud@118: ///
StephaneLenclud@118: ///
StephaneLenclud@118: ///
StephaneLenclud@118: private void UpdateNetworkSignal(DateTime aLastTickTime, DateTime aNewTickTime)
StephaneLenclud@118: {
StephaneLenclud@118: iUpdateCountSinceLastNetworkAnimation++;
StephaneLenclud@118: iUpdateCountSinceLastNetworkAnimation = iUpdateCountSinceLastNetworkAnimation % 4;
StephaneLenclud@118:
StephaneLenclud@118: if (iDisplay.IsOpen() && iNetworkManager.NetworkListManager.IsConnected && iUpdateCountSinceLastNetworkAnimation==0)
StephaneLenclud@135: {
StephaneLenclud@135: int iconCount = iDisplay.IconCount(MiniDisplay.IconType.NetworkSignal);
StephaneLenclud@120: if (iconCount <= 0)
StephaneLenclud@120: {
StephaneLenclud@120: //Prevents div by zero and other undefined behavior
StephaneLenclud@120: return;
StephaneLenclud@120: }
StephaneLenclud@118: iLastNetworkIconIndex++;
StephaneLenclud@119: iLastNetworkIconIndex = iLastNetworkIconIndex % (iconCount*2);
StephaneLenclud@118: for (int i=0;i 3) && !(i == 1 && iLastNetworkIconIndex > 4))
StephaneLenclud@118: {
StephaneLenclud@135: iDisplay.SetIconOn(MiniDisplay.IconType.NetworkSignal, i);
StephaneLenclud@118: }
StephaneLenclud@118: else
StephaneLenclud@118: {
StephaneLenclud@135: iDisplay.SetIconOff(MiniDisplay.IconType.NetworkSignal, i);
StephaneLenclud@118: }
StephaneLenclud@118: }
StephaneLenclud@118: }
StephaneLenclud@118: }
StephaneLenclud@118:
StephaneLenclud@118:
StephaneLenclud@118:
StephaneLenclud@112: ///
StephaneLenclud@112: /// Receive volume change notification and reflect changes on our slider.
StephaneLenclud@112: ///
StephaneLenclud@112: ///
StephaneLenclud@112: public void OnVolumeNotificationThreadSafe(AudioVolumeNotificationData data)
StephaneLenclud@112: {
StephaneLenclud@112: UpdateMasterVolumeThreadSafe();
StephaneLenclud@112: }
StephaneLenclud@112:
StephaneLenclud@112: ///
StephaneLenclud@112: /// Update master volume when user moves our slider.
StephaneLenclud@112: ///
StephaneLenclud@112: ///
StephaneLenclud@112: ///
StephaneLenclud@112: private void trackBarMasterVolume_Scroll(object sender, EventArgs e)
StephaneLenclud@112: {
StephaneLenclud@116: //Just like Windows Volume Mixer we unmute if the volume is adjusted
StephaneLenclud@116: iMultiMediaDevice.AudioEndpointVolume.Mute = false;
StephaneLenclud@116: //Set volume level according to our volume slider new position
StephaneLenclud@112: iMultiMediaDevice.AudioEndpointVolume.MasterVolumeLevelScalar = trackBarMasterVolume.Value / 100.0f;
StephaneLenclud@112: }
StephaneLenclud@112:
StephaneLenclud@113:
StephaneLenclud@113: ///
StephaneLenclud@113: /// Mute check box changed.
StephaneLenclud@113: ///
StephaneLenclud@113: ///
StephaneLenclud@113: ///
StephaneLenclud@113: private void checkBoxMute_CheckedChanged(object sender, EventArgs e)
StephaneLenclud@113: {
StephaneLenclud@113: iMultiMediaDevice.AudioEndpointVolume.Mute = checkBoxMute.Checked;
StephaneLenclud@113: }
StephaneLenclud@113:
StephaneLenclud@112: ///
StephaneLenclud@112: /// Device State Changed
StephaneLenclud@112: ///
StephaneLenclud@112: public void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)] string deviceId, [MarshalAs(UnmanagedType.I4)] DeviceState newState){}
StephaneLenclud@112:
StephaneLenclud@112: ///
StephaneLenclud@112: /// Device Added
StephaneLenclud@112: ///
StephaneLenclud@112: public void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId) { }
StephaneLenclud@112:
StephaneLenclud@112: ///
StephaneLenclud@112: /// Device Removed
StephaneLenclud@112: ///
StephaneLenclud@112: public void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)] string deviceId) { }
StephaneLenclud@112:
StephaneLenclud@112: ///
StephaneLenclud@112: /// Default Device Changed
StephaneLenclud@112: ///
StephaneLenclud@112: public void OnDefaultDeviceChanged(DataFlow flow, Role role, [MarshalAs(UnmanagedType.LPWStr)] string defaultDeviceId)
StephaneLenclud@112: {
StephaneLenclud@112: if (role == Role.Multimedia && flow == DataFlow.Render)
StephaneLenclud@112: {
StephaneLenclud@112: UpdateAudioDeviceAndMasterVolumeThreadSafe();
StephaneLenclud@112: }
StephaneLenclud@112: }
StephaneLenclud@112:
StephaneLenclud@112: ///
StephaneLenclud@112: /// Property Value Changed
StephaneLenclud@112: ///
StephaneLenclud@112: ///
StephaneLenclud@112: ///
StephaneLenclud@112: public void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId, PropertyKey key){}
StephaneLenclud@112:
StephaneLenclud@112:
StephaneLenclud@112:
StephaneLenclud@112:
StephaneLenclud@112: ///
StephaneLenclud@116: /// Update master volume indicators based our current system states.
StephaneLenclud@116: /// This typically includes volume levels and mute status.
StephaneLenclud@112: ///
StephaneLenclud@112: private void UpdateMasterVolumeThreadSafe()
StephaneLenclud@112: {
StephaneLenclud@112: if (this.InvokeRequired)
StephaneLenclud@112: {
StephaneLenclud@112: //Not in the proper thread, invoke ourselves
StephaneLenclud@112: PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateMasterVolumeThreadSafe);
StephaneLenclud@112: this.Invoke(d, new object[] { });
StephaneLenclud@112: return;
StephaneLenclud@112: }
StephaneLenclud@112:
StephaneLenclud@113: //Update volume slider
StephaneLenclud@112: float volumeLevelScalar = iMultiMediaDevice.AudioEndpointVolume.MasterVolumeLevelScalar;
StephaneLenclud@112: trackBarMasterVolume.Value = Convert.ToInt32(volumeLevelScalar * 100);
StephaneLenclud@113: //Update mute checkbox
StephaneLenclud@113: checkBoxMute.Checked = iMultiMediaDevice.AudioEndpointVolume.Mute;
StephaneLenclud@112:
StephaneLenclud@116: //If our display connection is open we need to update its icons
StephaneLenclud@112: if (iDisplay.IsOpen())
StephaneLenclud@112: {
StephaneLenclud@116: //First take care our our volume level icons
StephaneLenclud@135: int volumeIconCount = iDisplay.IconCount(MiniDisplay.IconType.Volume);
StephaneLenclud@112: if (volumeIconCount > 0)
StephaneLenclud@114: {
StephaneLenclud@116: //Compute current volume level from system level and the number of segments in our display volume bar.
StephaneLenclud@116: //That tells us how many segments in our volume bar needs to be turned on.
StephaneLenclud@116: float currentVolume = volumeLevelScalar * volumeIconCount;
StephaneLenclud@116: int segmentOnCount = Convert.ToInt32(currentVolume);
StephaneLenclud@116: //Check if our segment count was rounded up, this will later be used for half brightness segment
StephaneLenclud@116: bool roundedUp = segmentOnCount > currentVolume;
StephaneLenclud@114:
StephaneLenclud@112: for (int i = 0; i < volumeIconCount; i++)
StephaneLenclud@112: {
StephaneLenclud@116: if (i < segmentOnCount)
StephaneLenclud@112: {
StephaneLenclud@116: //If we are dealing with our last segment and our segment count was rounded up then we will use half brightness.
StephaneLenclud@116: if (i == segmentOnCount - 1 && roundedUp)
StephaneLenclud@114: {
StephaneLenclud@114: //Half brightness
StephaneLenclud@135: iDisplay.SetIconStatus(MiniDisplay.IconType.Volume, i, (iDisplay.IconStatusCount(MiniDisplay.IconType.Volume) - 1) / 2);
StephaneLenclud@114: }
StephaneLenclud@114: else
StephaneLenclud@114: {
StephaneLenclud@114: //Full brightness
StephaneLenclud@135: iDisplay.SetIconStatus(MiniDisplay.IconType.Volume, i, iDisplay.IconStatusCount(MiniDisplay.IconType.Volume) - 1);
StephaneLenclud@114: }
StephaneLenclud@112: }
StephaneLenclud@112: else
StephaneLenclud@112: {
StephaneLenclud@135: iDisplay.SetIconStatus(MiniDisplay.IconType.Volume, i, 0);
StephaneLenclud@112: }
StephaneLenclud@112: }
StephaneLenclud@112: }
StephaneLenclud@113:
Stephane@182: //Take care of our mute icon
StephaneLenclud@135: iDisplay.SetIconOnOff(MiniDisplay.IconType.Mute, iMultiMediaDevice.AudioEndpointVolume.Mute);
StephaneLenclud@112: }
StephaneLenclud@112:
StephaneLenclud@112: }
StephaneLenclud@112:
StephaneLenclud@112: ///
StephaneLenclud@112: ///
StephaneLenclud@112: ///
StephaneLenclud@112: private void UpdateAudioDeviceAndMasterVolumeThreadSafe()
StephaneLenclud@112: {
StephaneLenclud@112: if (this.InvokeRequired)
StephaneLenclud@112: {
StephaneLenclud@112: //Not in the proper thread, invoke ourselves
StephaneLenclud@112: PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateAudioDeviceAndMasterVolumeThreadSafe);
StephaneLenclud@112: this.Invoke(d, new object[] { });
StephaneLenclud@112: return;
StephaneLenclud@112: }
StephaneLenclud@112:
StephaneLenclud@112: //We are in the correct thread just go ahead.
StephaneLenclud@112: try
StephaneLenclud@112: {
StephaneLenclud@112: //Get our master volume
StephaneLenclud@112: iMultiMediaDevice = iMultiMediaDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
StephaneLenclud@116: //Update our label
StephaneLenclud@116: labelDefaultAudioDevice.Text = iMultiMediaDevice.FriendlyName;
StephaneLenclud@116:
StephaneLenclud@112: //Show our volume in our track bar
StephaneLenclud@112: UpdateMasterVolumeThreadSafe();
StephaneLenclud@112:
StephaneLenclud@112: //Register to get volume modifications
StephaneLenclud@112: iMultiMediaDevice.AudioEndpointVolume.OnVolumeNotification += OnVolumeNotificationThreadSafe;
StephaneLenclud@112: //
StephaneLenclud@112: trackBarMasterVolume.Enabled = true;
StephaneLenclud@112: }
StephaneLenclud@112: catch (Exception ex)
StephaneLenclud@112: {
StephaneLenclud@112: Debug.WriteLine("Exception thrown in UpdateAudioDeviceAndMasterVolume");
StephaneLenclud@112: Debug.WriteLine(ex.ToString());
StephaneLenclud@112: //Something went wrong S/PDIF device ca throw exception I guess
StephaneLenclud@112: trackBarMasterVolume.Enabled = false;
StephaneLenclud@112: }
StephaneLenclud@112: }
StephaneLenclud@104:
StephaneLenclud@104: ///
StephaneLenclud@104: ///
StephaneLenclud@104: ///
StephaneLenclud@104: private void PopulateDeviceTypes()
StephaneLenclud@104: {
StephaneLenclud@104: int count = Display.TypeCount();
StephaneLenclud@104:
StephaneLenclud@106: for (int i = 0; i < count; i++)
StephaneLenclud@104: {
StephaneLenclud@135: comboBoxDisplayType.Items.Add(Display.TypeName((MiniDisplay.Type)i));
StephaneLenclud@106: }
StephaneLenclud@104: }
StephaneLenclud@104:
StephaneLenclud@152: ///
StephaneLenclud@152: ///
StephaneLenclud@152: ///
StephaneLenclud@152: private void PopulateOpticalDrives()
StephaneLenclud@152: {
StephaneLenclud@152: //Reset our list of drives
StephaneLenclud@152: comboBoxOpticalDrives.Items.Clear();
StephaneLenclud@153: comboBoxOpticalDrives.Items.Add("None");
StephaneLenclud@152:
StephaneLenclud@152: //Go through each drives on our system and collected the optical ones in our list
StephaneLenclud@152: DriveInfo[] allDrives = DriveInfo.GetDrives();
StephaneLenclud@152: foreach (DriveInfo d in allDrives)
StephaneLenclud@152: {
StephaneLenclud@157: Debug.WriteLine("Drive " + d.Name);
StephaneLenclud@152: Debug.WriteLine(" Drive type: {0}", d.DriveType);
StephaneLenclud@152:
StephaneLenclud@152: if (d.DriveType==DriveType.CDRom)
StephaneLenclud@152: {
StephaneLenclud@152: //This is an optical drive, add it now
StephaneLenclud@152: comboBoxOpticalDrives.Items.Add(d.Name.Substring(0,2));
StephaneLenclud@152: }
StephaneLenclud@153: }
StephaneLenclud@152: }
StephaneLenclud@152:
StephaneLenclud@152: ///
StephaneLenclud@152: ///
StephaneLenclud@152: ///
StephaneLenclud@152: ///
StephaneLenclud@152: public string OpticalDriveToEject()
StephaneLenclud@152: {
StephaneLenclud@153: return comboBoxOpticalDrives.SelectedItem.ToString();
StephaneLenclud@152: }
StephaneLenclud@152:
StephaneLenclud@152:
StephaneLenclud@152:
StephaneLenclud@104: ///
sl@99: ///
sl@94: ///
sl@95: private void SetupTrayIcon()
sl@95: {
sl@95: iNotifyIcon.Icon = GetIcon("vfd.ico");
sl@95: iNotifyIcon.Text = "Sharp Display Manager";
sl@95: iNotifyIcon.Visible = true;
sl@95:
sl@95: //Double click toggles visibility - typically brings up the application
sl@95: iNotifyIcon.DoubleClick += delegate(object obj, EventArgs args)
sl@95: {
sl@95: SysTrayHideShow();
sl@95: };
sl@95:
sl@95: //Adding a context menu, useful to be able to exit the application
sl@95: ContextMenu contextMenu = new ContextMenu();
sl@95: //Context menu item to toggle visibility
sl@95: MenuItem hideShowItem = new MenuItem("Hide/Show");
sl@95: hideShowItem.Click += delegate(object obj, EventArgs args)
sl@95: {
sl@95: SysTrayHideShow();
sl@95: };
sl@95: contextMenu.MenuItems.Add(hideShowItem);
sl@95:
sl@95: //Context menu item separator
sl@95: contextMenu.MenuItems.Add(new MenuItem("-"));
sl@95:
sl@95: //Context menu exit item
sl@95: MenuItem exitItem = new MenuItem("Exit");
sl@95: exitItem.Click += delegate(object obj, EventArgs args)
sl@95: {
sl@95: Application.Exit();
sl@95: };
sl@95: contextMenu.MenuItems.Add(exitItem);
sl@95:
sl@95: iNotifyIcon.ContextMenu = contextMenu;
sl@95: }
sl@95:
StephaneLenclud@178: ///
StephaneLenclud@179: ///
StephaneLenclud@179: ///
StephaneLenclud@179: private void SetupRecordingNotification()
StephaneLenclud@179: {
StephaneLenclud@179: iRecordingNotification.Icon = GetIcon("record.ico");
StephaneLenclud@179: iRecordingNotification.Text = "No recording";
StephaneLenclud@180: iRecordingNotification.Visible = false;
StephaneLenclud@179: }
StephaneLenclud@179:
StephaneLenclud@179: ///
StephaneLenclud@178: /// Access icons from embedded resources.
StephaneLenclud@178: ///
StephaneLenclud@178: ///
StephaneLenclud@178: ///
StephaneLenclud@178: public static Icon GetIcon(string aName)
sl@94: {
StephaneLenclud@178: string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
StephaneLenclud@178: foreach (string name in names)
sl@94: {
StephaneLenclud@178: //Find a resource name that ends with the given name
StephaneLenclud@178: if (name.EndsWith(aName))
sl@94: {
StephaneLenclud@178: using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
sl@94: {
sl@94: return new Icon(stream);
sl@94: }
sl@94: }
sl@94: }
sl@94:
sl@94: return null;
sl@94: }
sl@94:
sl@94:
sl@65: ///
sl@65: /// Set our current client.
sl@65: /// This will take care of applying our client layout and set data fields.
sl@65: ///
sl@65: ///
StephaneLenclud@141: void SetCurrentClient(string aSessionId, bool aForce=false)
sl@57: {
sl@65: if (aSessionId == iCurrentClientSessionId)
sl@57: {
sl@65: //Given client is already the current one.
sl@65: //Don't bother changing anything then.
sl@65: return;
sl@65: }
sl@57:
StephaneLenclud@185: ClientData requestedClientData = iClients[aSessionId];
StephaneLenclud@141:
StephaneLenclud@141: //Check when was the last time we switched to that client
StephaneLenclud@142: if (iCurrentClientData != null)
StephaneLenclud@141: {
StephaneLenclud@185: //Do not switch client if priority of current client is higher
StephaneLenclud@185: if (!aForce && requestedClientData.Priority < iCurrentClientData.Priority)
StephaneLenclud@185: {
StephaneLenclud@185: return;
StephaneLenclud@185: }
StephaneLenclud@185:
StephaneLenclud@185:
StephaneLenclud@142: double lastSwitchToClientSecondsAgo = (DateTime.Now - iCurrentClientData.LastSwitchTime).TotalSeconds;
StephaneLenclud@142: //TODO: put that hard coded value as a client property
StephaneLenclud@142: //Clients should be able to define how often they can be interrupted
StephaneLenclud@142: //Thus a background client can set this to zero allowing any other client to interrupt at any time
StephaneLenclud@142: //We could also compute this delay by looking at the requests frequencies?
StephaneLenclud@185: if (!aForce &&
StephaneLenclud@185: requestedClientData.Priority == iCurrentClientData.Priority && //Time sharing is only if clients have the same priority
StephaneLenclud@185: (lastSwitchToClientSecondsAgo < 30)) //Make sure a client is on for at least 30 seconds
StephaneLenclud@142: {
StephaneLenclud@142: //Don't switch clients too often
StephaneLenclud@142: return;
StephaneLenclud@142: }
StephaneLenclud@141: }
StephaneLenclud@141:
sl@65: //Set current client ID.
sl@65: iCurrentClientSessionId = aSessionId;
StephaneLenclud@141: //Set the time we last switched to that client
StephaneLenclud@141: iClients[aSessionId].LastSwitchTime = DateTime.Now;
sl@65: //Fetch and set current client data.
StephaneLenclud@185: iCurrentClientData = requestedClientData;
sl@65: //Apply layout and set data fields.
sl@65: UpdateTableLayoutPanel(iCurrentClientData);
sl@57: }
sl@57:
sl@0: private void buttonFont_Click(object sender, EventArgs e)
sl@0: {
sl@0: //fontDialog.ShowColor = true;
sl@0: //fontDialog.ShowApply = true;
sl@0: fontDialog.ShowEffects = true;
sl@99: fontDialog.Font = cds.Font;
sl@28:
sl@28: fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
sl@28:
sl@0: //fontDialog.ShowHelp = true;
sl@0:
sl@0: //fontDlg.MaxSize = 40;
sl@0: //fontDlg.MinSize = 22;
sl@0:
sl@0: //fontDialog.Parent = this;
sl@0: //fontDialog.StartPosition = FormStartPosition.CenterParent;
sl@0:
sl@0: //DlgBox.ShowDialog(fontDialog);
sl@0:
sl@0: //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
sl@0: if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
sl@0: {
sl@99: //Set the fonts to all our labels in our layout
StephaneLenclud@175: foreach (Control ctrl in iTableLayoutPanel.Controls)
sl@99: {
sl@99: if (ctrl is MarqueeLabel)
sl@99: {
sl@99: ((MarqueeLabel)ctrl).Font = fontDialog.Font;
sl@99: }
sl@99: }
sl@0:
sl@99: //Save font settings
sl@48: cds.Font = fontDialog.Font;
sl@8: Properties.Settings.Default.Save();
sl@36: //
sl@37: CheckFontHeight();
sl@37: }
sl@37: }
sl@36:
sl@37: ///
sl@38: ///
sl@37: ///
sl@37: void CheckFontHeight()
sl@37: {
sl@54: //Show font height and width
sl@54: labelFontHeight.Text = "Font height: " + cds.Font.Height;
sl@54: float charWidth = IsFixedWidth(cds.Font);
sl@54: if (charWidth == 0.0f)
sl@54: {
sl@54: labelFontWidth.Visible = false;
sl@54: }
sl@54: else
sl@54: {
sl@54: labelFontWidth.Visible = true;
sl@54: labelFontWidth.Text = "Font width: " + charWidth;
sl@54: }
sl@54:
sl@70: MarqueeLabel label = null;
sl@68: //Get the first label control we can find
StephaneLenclud@175: foreach (Control ctrl in iTableLayoutPanel.Controls)
sl@68: {
sl@68: if (ctrl is MarqueeLabel)
sl@68: {
sl@68: label = (MarqueeLabel)ctrl;
sl@68: break;
sl@68: }
sl@68: }
sl@68:
sl@54: //Now check font height and show a warning if needed.
sl@68: if (label != null && label.Font.Height > label.Height)
sl@37: {
sl@60: labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
sl@37: labelWarning.Visible = true;
sl@0: }
sl@37: else
sl@37: {
sl@37: labelWarning.Visible = false;
sl@37: }
sl@37:
sl@0: }
sl@0:
sl@0: private void buttonCapture_Click(object sender, EventArgs e)
sl@0: {
StephaneLenclud@175: System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(iTableLayoutPanel.Width, iTableLayoutPanel.Height);
StephaneLenclud@175: iTableLayoutPanel.DrawToBitmap(bmp, iTableLayoutPanel.ClientRectangle);
sl@14: //Bitmap bmpToSave = new Bitmap(bmp);
sl@14: bmp.Save("D:\\capture.png");
sl@14:
StephaneLenclud@175: ((MarqueeLabel)iTableLayoutPanel.Controls[0]).Text = "Captured";
sl@17:
sl@14: /*
sl@14: string outputFileName = "d:\\capture.png";
sl@14: using (MemoryStream memory = new MemoryStream())
sl@14: {
sl@14: using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
sl@14: {
sl@14: bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
sl@14: byte[] bytes = memory.ToArray();
sl@14: fs.Write(bytes, 0, bytes.Length);
sl@14: }
sl@14: }
sl@14: */
sl@14:
sl@0: }
sl@2:
sl@12: private void CheckForRequestResults()
sl@12: {
sl@12: if (iDisplay.IsRequestPending())
sl@12: {
sl@12: switch (iDisplay.AttemptRequestCompletion())
sl@12: {
StephaneLenclud@135: case MiniDisplay.Request.FirmwareRevision:
sl@51: toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
sl@51: //Issue next request then
sl@51: iDisplay.RequestPowerSupplyStatus();
sl@51: break;
sl@51:
StephaneLenclud@135: case MiniDisplay.Request.PowerSupplyStatus:
sl@12: if (iDisplay.PowerSupplyStatus())
sl@12: {
sl@12: toolStripStatusLabelPower.Text = "ON";
sl@12: }
sl@12: else
sl@12: {
sl@12: toolStripStatusLabelPower.Text = "OFF";
sl@12: }
sl@12: //Issue next request then
sl@12: iDisplay.RequestDeviceId();
sl@12: break;
sl@12:
StephaneLenclud@135: case MiniDisplay.Request.DeviceId:
sl@12: toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
sl@12: //No more request to issue
sl@12: break;
sl@12: }
sl@12: }
sl@12: }
sl@12:
sl@58: public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
sl@58: {
sl@58: if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
sl@58: {
sl@58: return 0xFFFFFFFF;
sl@58: }
sl@58: return 0x00000000;
sl@58: }
sl@16:
sl@58: public static uint ColorUntouched(int aX, int aY, uint aPixel)
sl@57: {
sl@57: return aPixel;
sl@57: }
sl@57:
sl@58: public static uint ColorInversed(int aX, int aY, uint aPixel)
sl@57: {
sl@57: return ~aPixel;
sl@57: }
sl@57:
sl@58: public static uint ColorChessboard(int aX, int aY, uint aPixel)
sl@58: {
sl@58: if ((aX % 2 == 0) && (aY % 2 == 0))
sl@58: {
sl@58: return ~aPixel;
sl@58: }
sl@58: else if ((aX % 2 != 0) && (aY % 2 != 0))
sl@58: {
sl@58: return ~aPixel;
sl@58: }
sl@58: return 0x00000000;
sl@58: }
sl@58:
sl@16:
sl@16: public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
sl@16: {
sl@16: return aBmp.Width - aX - 1;
sl@16: }
sl@16:
sl@16: public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
sl@16: {
sl@16: return iBmp.Height - aY - 1;
sl@16: }
sl@16:
sl@16: public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
sl@16: {
sl@16: return aX;
sl@16: }
sl@16:
sl@16: public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
sl@16: {
sl@16: return aY;
sl@16: }
sl@16:
sl@58: ///
sl@58: /// Select proper pixel delegates according to our current settings.
sl@58: ///
sl@58: private void SetupPixelDelegates()
sl@58: {
sl@59: //Select our pixel processing routine
sl@58: if (cds.InverseColors)
sl@58: {
sl@58: //iColorFx = ColorChessboard;
sl@58: iColorFx = ColorInversed;
sl@58: }
sl@58: else
sl@58: {
sl@58: iColorFx = ColorWhiteIsOn;
sl@58: }
sl@58:
sl@58: //Select proper coordinate translation functions
sl@58: //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
sl@58: if (cds.ReverseScreen)
sl@58: {
sl@58: iScreenX = ScreenReversedX;
sl@58: iScreenY = ScreenReversedY;
sl@58: }
sl@58: else
sl@58: {
sl@58: iScreenX = ScreenX;
sl@58: iScreenY = ScreenY;
sl@58: }
sl@58:
sl@58: }
sl@16:
sl@16: //This is our timer tick responsible to perform our render
sl@2: private void timer_Tick(object sender, EventArgs e)
sl@14: {
sl@2: //Update our animations
sl@2: DateTime NewTickTime = DateTime.Now;
sl@2:
StephaneLenclud@118: UpdateNetworkSignal(LastTickTime, NewTickTime);
StephaneLenclud@118:
sl@60: //Update animation for all our marquees
StephaneLenclud@175: foreach (Control ctrl in iTableLayoutPanel.Controls)
sl@60: {
sl@68: if (ctrl is MarqueeLabel)
sl@68: {
sl@68: ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
sl@68: }
sl@60: }
sl@60:
sl@4: //Update our display
sl@4: if (iDisplay.IsOpen())
sl@4: {
sl@12: CheckForRequestResults();
sl@12:
StephaneLenclud@122: //Check if frame rendering is needed
StephaneLenclud@122: //Typically used when showing clock
StephaneLenclud@122: if (!iSkipFrameRendering)
StephaneLenclud@122: {
StephaneLenclud@122: //Draw to bitmap
StephaneLenclud@122: if (iCreateBitmap)
StephaneLenclud@122: {
StephaneLenclud@175: iBmp = new System.Drawing.Bitmap(iTableLayoutPanel.Width, iTableLayoutPanel.Height, PixelFormat.Format32bppArgb);
StephaneLenclud@158: iCreateBitmap = false;
StephaneLenclud@158: }
StephaneLenclud@175: iTableLayoutPanel.DrawToBitmap(iBmp, iTableLayoutPanel.ClientRectangle);
StephaneLenclud@122: //iBmp.Save("D:\\capture.png");
sl@16:
StephaneLenclud@122: //Send it to our display
StephaneLenclud@122: for (int i = 0; i < iBmp.Width; i++)
StephaneLenclud@122: {
StephaneLenclud@122: for (int j = 0; j < iBmp.Height; j++)
StephaneLenclud@122: {
StephaneLenclud@122: unchecked
StephaneLenclud@122: {
StephaneLenclud@122: //Get our processed pixel coordinates
StephaneLenclud@122: int x = iScreenX(iBmp, i);
StephaneLenclud@122: int y = iScreenY(iBmp, j);
StephaneLenclud@122: //Get pixel color
StephaneLenclud@122: uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
StephaneLenclud@122: //Apply color effects
StephaneLenclud@122: color = iColorFx(x, y, color);
StephaneLenclud@122: //Now set our pixel
StephaneLenclud@122: iDisplay.SetPixel(x, y, color);
StephaneLenclud@122: }
StephaneLenclud@122: }
StephaneLenclud@122: }
sl@4:
StephaneLenclud@122: iDisplay.SwapBuffers();
StephaneLenclud@122: }
sl@4: }
sl@8:
sl@8: //Compute instant FPS
sl@47: toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
sl@8:
sl@8: LastTickTime = NewTickTime;
sl@8:
sl@2: }
sl@3:
StephaneLenclud@103: ///
StephaneLenclud@103: /// Attempt to establish connection with our display hardware.
StephaneLenclud@103: ///
sl@46: private void OpenDisplayConnection()
sl@3: {
sl@46: CloseDisplayConnection();
sl@46:
StephaneLenclud@135: if (!iDisplay.Open((MiniDisplay.Type)cds.DisplayType))
StephaneLenclud@104: {
StephaneLenclud@104: UpdateStatus();
StephaneLenclud@104: toolStripStatusLabelConnect.Text = "Connection error";
sl@7: }
sl@46: }
sl@7:
sl@46: private void CloseDisplayConnection()
sl@46: {
StephaneLenclud@104: //Status will be updated upon receiving the closed event
StephaneLenclud@122:
StephaneLenclud@122: if (iDisplay == null || !iDisplay.IsOpen())
StephaneLenclud@122: {
StephaneLenclud@122: return;
StephaneLenclud@122: }
StephaneLenclud@122:
StephaneLenclud@122: //Do not clear if we gave up on rendering already.
StephaneLenclud@122: //This means we will keep on displaying clock on MDM166AA for instance.
StephaneLenclud@122: if (!iSkipFrameRendering)
StephaneLenclud@122: {
StephaneLenclud@122: iDisplay.Clear();
StephaneLenclud@122: iDisplay.SwapBuffers();
StephaneLenclud@122: }
StephaneLenclud@122:
StephaneLenclud@122: iDisplay.SetAllIconsStatus(0); //Turn off all icons
sl@46: iDisplay.Close();
sl@46: }
sl@46:
sl@46: private void buttonOpen_Click(object sender, EventArgs e)
sl@46: {
sl@46: OpenDisplayConnection();
sl@3: }
sl@3:
sl@3: private void buttonClose_Click(object sender, EventArgs e)
sl@3: {
sl@46: CloseDisplayConnection();
sl@3: }
sl@3:
sl@3: private void buttonClear_Click(object sender, EventArgs e)
sl@3: {
sl@3: iDisplay.Clear();
sl@3: iDisplay.SwapBuffers();
sl@3: }
sl@3:
sl@3: private void buttonFill_Click(object sender, EventArgs e)
sl@3: {
sl@3: iDisplay.Fill();
sl@3: iDisplay.SwapBuffers();
sl@3: }
sl@3:
sl@3: private void trackBarBrightness_Scroll(object sender, EventArgs e)
sl@3: {
sl@48: cds.Brightness = trackBarBrightness.Value;
sl@9: Properties.Settings.Default.Save();
sl@3: iDisplay.SetBrightness(trackBarBrightness.Value);
sl@9:
sl@3: }
sl@7:
sl@48:
sl@48: ///
sl@48: /// CDS stands for Current Display Settings
sl@48: ///
sl@50: private DisplaySettings cds
sl@48: {
sl@48: get
sl@48: {
sl@65: DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
sl@51: if (settings == null)
sl@51: {
sl@51: settings = new DisplaysSettings();
sl@51: settings.Init();
sl@65: Properties.Settings.Default.DisplaysSettings = settings;
sl@51: }
sl@48:
sl@48: //Make sure all our settings have been created
sl@48: while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
sl@48: {
sl@50: settings.Displays.Add(new DisplaySettings());
sl@48: }
sl@48:
sl@50: DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
sl@48: return displaySettings;
sl@48: }
sl@48: }
sl@48:
sl@54: ///
sl@54: /// Check if the given font has a fixed character pitch.
sl@54: ///
sl@54: ///
sl@54: /// 0.0f if this is not a monospace font, otherwise returns the character width.
sl@54: public float IsFixedWidth(Font ft)
sl@54: {
sl@54: Graphics g = CreateGraphics();
sl@54: char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
sl@54: float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
sl@54:
sl@54: bool fixedWidth = true;
sl@54:
sl@54: foreach (char c in charSizes)
sl@54: if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
sl@54: fixedWidth = false;
sl@54:
sl@54: if (fixedWidth)
sl@54: {
sl@54: return charWidth;
sl@54: }
sl@54:
sl@54: return 0.0f;
sl@54: }
sl@54:
StephaneLenclud@103: ///
StephaneLenclud@103: /// Synchronize UI with settings
StephaneLenclud@103: ///
sl@7: private void UpdateStatus()
StephaneLenclud@103: {
sl@48: //Load settings
sl@54: checkBoxShowBorders.Checked = cds.ShowBorders;
StephaneLenclud@175: iTableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@60:
sl@60: //Set the proper font to each of our labels
StephaneLenclud@175: foreach (MarqueeLabel ctrl in iTableLayoutPanel.Controls)
sl@60: {
sl@60: ctrl.Font = cds.Font;
sl@60: }
sl@60:
sl@54: CheckFontHeight();
sl@96: //Check if "run on Windows startup" is enabled
sl@96: checkBoxAutoStart.Checked = iStartupManager.Startup;
sl@96: //
sl@48: checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
sl@94: checkBoxMinimizeToTray.Checked = Properties.Settings.Default.MinimizeToTray;
sl@94: checkBoxStartMinimized.Checked = Properties.Settings.Default.StartMinimized;
StephaneLenclud@194: iCheckBoxStartIdleClient.Checked = Properties.Settings.Default.StartIdleClient;
StephaneLenclud@194: labelStartFileName.Text = Properties.Settings.Default.StartFileName;
StephaneLenclud@194:
StephaneLenclud@153:
StephaneLenclud@153: //Try find our drive in our drive list
StephaneLenclud@153: int opticalDriveItemIndex=0;
StephaneLenclud@153: bool driveNotFound = true;
StephaneLenclud@153: string opticalDriveToEject=Properties.Settings.Default.OpticalDriveToEject;
StephaneLenclud@153: foreach (object item in comboBoxOpticalDrives.Items)
StephaneLenclud@153: {
StephaneLenclud@154: if (opticalDriveToEject == item.ToString())
StephaneLenclud@153: {
StephaneLenclud@153: comboBoxOpticalDrives.SelectedIndex = opticalDriveItemIndex;
StephaneLenclud@153: driveNotFound = false;
StephaneLenclud@153: break;
StephaneLenclud@153: }
StephaneLenclud@153: opticalDriveItemIndex++;
StephaneLenclud@153: }
StephaneLenclud@153:
StephaneLenclud@153: if (driveNotFound)
StephaneLenclud@153: {
StephaneLenclud@153: //We could not find the drive we had saved.
StephaneLenclud@153: //Select "None" then.
StephaneLenclud@153: comboBoxOpticalDrives.SelectedIndex = 0;
StephaneLenclud@153: }
StephaneLenclud@153:
StephaneLenclud@168: //CEC settings
StephaneLenclud@168: checkBoxCecEnabled.Checked = Properties.Settings.Default.CecEnabled;
StephaneLenclud@168: checkBoxCecMonitorOn.Checked = Properties.Settings.Default.CecMonitorOn;
StephaneLenclud@168: checkBoxCecMonitorOff.Checked = Properties.Settings.Default.CecMonitorOff;
StephaneLenclud@168: comboBoxHdmiPort.SelectedIndex = Properties.Settings.Default.CecHdmiPort - 1;
StephaneLenclud@153:
StephaneLenclud@168: //Mini Display settings
sl@48: checkBoxReverseScreen.Checked = cds.ReverseScreen;
sl@57: checkBoxInverseColors.Checked = cds.InverseColors;
StephaneLenclud@115: checkBoxShowVolumeLabel.Checked = cds.ShowVolumeLabel;
sl@100: checkBoxScaleToFit.Checked = cds.ScaleToFit;
sl@100: maskedTextBoxMinFontSize.Enabled = cds.ScaleToFit;
sl@100: labelMinFontSize.Enabled = cds.ScaleToFit;
sl@100: maskedTextBoxMinFontSize.Text = cds.MinFontSize.ToString();
StephaneLenclud@106: maskedTextBoxScrollingSpeed.Text = cds.ScrollingSpeedInPixelsPerSecond.ToString();
sl@48: comboBoxDisplayType.SelectedIndex = cds.DisplayType;
sl@48: timer.Interval = cds.TimerInterval;
sl@48: maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
sl@100: textBoxScrollLoopSeparator.Text = cds.Separator;
sl@58: //
sl@58: SetupPixelDelegates();
sl@48:
sl@7: if (iDisplay.IsOpen())
sl@7: {
StephaneLenclud@187: //We have a display connection
StephaneLenclud@187: //Reflect that in our UI
StephaneLenclud@187: StartTimer();
StephaneLenclud@103:
StephaneLenclud@175: iTableLayoutPanel.Enabled = true;
StephaneLenclud@105: panelDisplay.Enabled = true;
StephaneLenclud@103:
sl@48: //Only setup brightness if display is open
sl@48: trackBarBrightness.Minimum = iDisplay.MinBrightness();
sl@48: trackBarBrightness.Maximum = iDisplay.MaxBrightness();
StephaneLenclud@105: if (cds.Brightness < iDisplay.MinBrightness() || cds.Brightness > iDisplay.MaxBrightness())
StephaneLenclud@105: {
StephaneLenclud@105: //Brightness out of range, this can occur when using auto-detect
StephaneLenclud@105: //Use max brightness instead
StephaneLenclud@105: trackBarBrightness.Value = iDisplay.MaxBrightness();
StephaneLenclud@105: iDisplay.SetBrightness(iDisplay.MaxBrightness());
StephaneLenclud@105: }
StephaneLenclud@105: else
StephaneLenclud@105: {
StephaneLenclud@105: trackBarBrightness.Value = cds.Brightness;
StephaneLenclud@105: iDisplay.SetBrightness(cds.Brightness);
StephaneLenclud@105: }
StephaneLenclud@105:
StephaneLenclud@105: //Try compute the steps to something that makes sense
sl@48: trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
sl@48: trackBarBrightness.SmallChange = 1;
StephaneLenclud@105:
sl@48: //
sl@7: buttonFill.Enabled = true;
sl@7: buttonClear.Enabled = true;
sl@7: buttonOpen.Enabled = false;
sl@7: buttonClose.Enabled = true;
sl@7: trackBarBrightness.Enabled = true;
sl@10: toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
sl@10: //+ " - " + iDisplay.SerialNumber();
sl@52:
sl@52: if (iDisplay.SupportPowerOnOff())
sl@52: {
sl@52: buttonPowerOn.Enabled = true;
sl@52: buttonPowerOff.Enabled = true;
sl@52: }
sl@52: else
sl@52: {
sl@52: buttonPowerOn.Enabled = false;
sl@52: buttonPowerOff.Enabled = false;
sl@52: }
sl@53:
sl@53: if (iDisplay.SupportClock())
sl@53: {
sl@53: buttonShowClock.Enabled = true;
sl@53: buttonHideClock.Enabled = true;
sl@53: }
sl@53: else
sl@53: {
sl@53: buttonShowClock.Enabled = false;
sl@53: buttonHideClock.Enabled = false;
sl@53: }
StephaneLenclud@115:
StephaneLenclud@115:
StephaneLenclud@115: //Check if Volume Label is supported. To date only MDM166AA supports that crap :)
StephaneLenclud@135: checkBoxShowVolumeLabel.Enabled = iDisplay.IconCount(MiniDisplay.IconType.VolumeLabel)>0;
StephaneLenclud@115:
StephaneLenclud@115: if (cds.ShowVolumeLabel)
StephaneLenclud@115: {
StephaneLenclud@135: iDisplay.SetIconOn(MiniDisplay.IconType.VolumeLabel);
StephaneLenclud@115: }
StephaneLenclud@115: else
StephaneLenclud@115: {
StephaneLenclud@135: iDisplay.SetIconOff(MiniDisplay.IconType.VolumeLabel);
StephaneLenclud@115: }
sl@7: }
sl@7: else
sl@7: {
StephaneLenclud@187: //Display connection not available
StephaneLenclud@187: //Reflect that in our UI
StephaneLenclud@187: #if DEBUG
StephaneLenclud@187: //In debug start our timer even if we don't have a display connection
StephaneLenclud@187: StartTimer();
StephaneLenclud@187: #else
StephaneLenclud@187: //In production environment we don't need our timer if no display connection
StephaneLenclud@187: StopTimer();
StephaneLenclud@187: #endif
StephaneLenclud@187: checkBoxShowVolumeLabel.Enabled = false;
StephaneLenclud@175: iTableLayoutPanel.Enabled = false;
StephaneLenclud@105: panelDisplay.Enabled = false;
sl@7: buttonFill.Enabled = false;
sl@7: buttonClear.Enabled = false;
sl@7: buttonOpen.Enabled = true;
sl@7: buttonClose.Enabled = false;
sl@7: trackBarBrightness.Enabled = false;
sl@52: buttonPowerOn.Enabled = false;
sl@52: buttonPowerOff.Enabled = false;
sl@53: buttonShowClock.Enabled = false;
sl@53: buttonHideClock.Enabled = false;
sl@9: toolStripStatusLabelConnect.Text = "Disconnected";
sl@48: toolStripStatusLabelPower.Text = "N/A";
sl@7: }
StephaneLenclud@106:
sl@7: }
sl@9:
sl@13:
StephaneLenclud@115: ///
StephaneLenclud@115: ///
StephaneLenclud@115: ///
StephaneLenclud@115: ///
StephaneLenclud@115: ///
StephaneLenclud@115: private void checkBoxShowVolumeLabel_CheckedChanged(object sender, EventArgs e)
StephaneLenclud@115: {
StephaneLenclud@115: cds.ShowVolumeLabel = checkBoxShowVolumeLabel.Checked;
StephaneLenclud@115: Properties.Settings.Default.Save();
StephaneLenclud@115: UpdateStatus();
StephaneLenclud@115: }
sl@13:
sl@9: private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
sl@9: {
sl@16: //Save our show borders setting
StephaneLenclud@175: iTableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@48: cds.ShowBorders = checkBoxShowBorders.Checked;
sl@9: Properties.Settings.Default.Save();
sl@57: CheckFontHeight();
sl@9: }
sl@13:
sl@13: private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
sl@13: {
sl@16: //Save our connect on startup setting
sl@13: Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
sl@13: Properties.Settings.Default.Save();
sl@13: }
sl@13:
sl@94: private void checkBoxMinimizeToTray_CheckedChanged(object sender, EventArgs e)
sl@94: {
sl@94: //Save our "Minimize to tray" setting
sl@94: Properties.Settings.Default.MinimizeToTray = checkBoxMinimizeToTray.Checked;
sl@94: Properties.Settings.Default.Save();
sl@94:
sl@94: }
sl@94:
sl@94: private void checkBoxStartMinimized_CheckedChanged(object sender, EventArgs e)
sl@94: {
sl@94: //Save our "Start minimized" setting
sl@94: Properties.Settings.Default.StartMinimized = checkBoxStartMinimized.Checked;
sl@94: Properties.Settings.Default.Save();
sl@94: }
sl@94:
StephaneLenclud@194: private void checkBoxStartIdleClient_CheckedChanged(object sender, EventArgs e)
StephaneLenclud@194: {
StephaneLenclud@194: Properties.Settings.Default.StartIdleClient = iCheckBoxStartIdleClient.Checked;
StephaneLenclud@194: Properties.Settings.Default.Save();
StephaneLenclud@194: }
StephaneLenclud@194:
StephaneLenclud@194: private void checkBoxAutoStart_CheckedChanged(object sender, EventArgs e)
sl@94: {
sl@94: iStartupManager.Startup = checkBoxAutoStart.Checked;
sl@94: }
sl@94:
sl@94:
sl@16: private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
sl@16: {
sl@16: //Save our reverse screen setting
sl@48: cds.ReverseScreen = checkBoxReverseScreen.Checked;
sl@16: Properties.Settings.Default.Save();
sl@58: SetupPixelDelegates();
sl@16: }
sl@16:
sl@57: private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
sl@57: {
sl@57: //Save our inverse colors setting
sl@57: cds.InverseColors = checkBoxInverseColors.Checked;
sl@57: Properties.Settings.Default.Save();
sl@58: SetupPixelDelegates();
sl@57: }
sl@57:
sl@100: private void checkBoxScaleToFit_CheckedChanged(object sender, EventArgs e)
sl@100: {
sl@100: //Save our scale to fit setting
sl@100: cds.ScaleToFit = checkBoxScaleToFit.Checked;
sl@100: Properties.Settings.Default.Save();
sl@100: //
sl@100: labelMinFontSize.Enabled = cds.ScaleToFit;
sl@100: maskedTextBoxMinFontSize.Enabled = cds.ScaleToFit;
sl@100: }
sl@100:
sl@14: private void MainForm_Resize(object sender, EventArgs e)
sl@14: {
sl@14: if (WindowState == FormWindowState.Minimized)
sl@14: {
StephaneLenclud@158: // To workaround our empty bitmap bug on Windows 7 we need to recreate our bitmap when the application is minimized
StephaneLenclud@158: // That's apparently not needed on Windows 10 but we better leave it in place.
sl@14: iCreateBitmap = true;
sl@14: }
sl@14: }
sl@14:
sl@17: private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
sl@17: {
StephaneLenclud@167: iCecManager.Stop();
StephaneLenclud@117: iNetworkManager.Dispose();
StephaneLenclud@105: CloseDisplayConnection();
sl@17: StopServer();
sl@32: e.Cancel = iClosing;
sl@17: }
sl@17:
sl@17: public void StartServer()
sl@17: {
sl@17: iServiceHost = new ServiceHost
sl@17: (
sl@55: typeof(Session),
sl@20: new Uri[] { new Uri("net.tcp://localhost:8001/") }
sl@17: );
sl@17:
sl@55: iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
sl@17: iServiceHost.Open();
sl@17: }
sl@17:
sl@17: public void StopServer()
sl@17: {
sl@32: if (iClients.Count > 0 && !iClosing)
sl@29: {
sl@29: //Tell our clients
sl@32: iClosing = true;
sl@29: BroadcastCloseEvent();
sl@29: }
sl@32: else if (iClosing)
sl@32: {
sl@32: if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
sl@32: {
sl@32: iClosing = false; //We make sure we force close if asked twice
sl@32: }
sl@32: }
sl@32: else
sl@36: {
sl@32: //We removed that as it often lags for some reason
sl@32: //iServiceHost.Close();
sl@32: }
sl@17: }
sl@17:
sl@21: public void BroadcastCloseEvent()
sl@21: {
sl@31: Trace.TraceInformation("BroadcastCloseEvent - start");
sl@31:
sl@21: var inactiveClients = new List();
sl@21: foreach (var client in iClients)
sl@21: {
sl@21: //if (client.Key != eventData.ClientName)
sl@21: {
sl@21: try
sl@21: {
sl@31: Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
sl@33: client.Value.Callback.OnCloseOrder(/*eventData*/);
sl@21: }
sl@21: catch (Exception ex)
sl@21: {
sl@21: inactiveClients.Add(client.Key);
sl@21: }
sl@21: }
sl@21: }
sl@21:
sl@21: if (inactiveClients.Count > 0)
sl@21: {
sl@21: foreach (var client in inactiveClients)
sl@21: {
sl@21: iClients.Remove(client);
StephaneLenclud@188: Program.iMainForm.iTreeViewClients.Nodes.Remove(Program.iMainForm.iTreeViewClients.Nodes.Find(client, false)[0]);
sl@21: }
sl@21: }
sl@97:
sl@97: if (iClients.Count==0)
sl@97: {
sl@97: ClearLayout();
sl@97: }
sl@21: }
sl@21:
sl@97: ///
sl@97: /// Just remove all our fields.
sl@97: ///
sl@97: private void ClearLayout()
sl@97: {
StephaneLenclud@175: iTableLayoutPanel.Controls.Clear();
StephaneLenclud@175: iTableLayoutPanel.RowStyles.Clear();
StephaneLenclud@175: iTableLayoutPanel.ColumnStyles.Clear();
StephaneLenclud@122: iCurrentClientData = null;
sl@97: }
sl@97:
StephaneLenclud@106: ///
StephaneLenclud@106: /// Just launch a demo client.
StephaneLenclud@106: ///
StephaneLenclud@106: private void StartNewClient(string aTopText = "", string aBottomText = "")
StephaneLenclud@106: {
StephaneLenclud@106: Thread clientThread = new Thread(SharpDisplayClient.Program.MainWithParams);
StephaneLenclud@106: SharpDisplayClient.StartParams myParams = new SharpDisplayClient.StartParams(new Point(this.Right, this.Top),aTopText,aBottomText);
StephaneLenclud@106: clientThread.Start(myParams);
StephaneLenclud@106: BringToFront();
StephaneLenclud@106: }
StephaneLenclud@106:
StephaneLenclud@189: ///
StephaneLenclud@189: /// Just launch our idle client.
StephaneLenclud@189: ///
StephaneLenclud@189: private void StartIdleClient(string aTopText = "", string aBottomText = "")
StephaneLenclud@189: {
StephaneLenclud@189: Thread clientThread = new Thread(SharpDisplayIdleClient.Program.MainWithParams);
StephaneLenclud@189: SharpDisplayIdleClient.StartParams myParams = new SharpDisplayIdleClient.StartParams(new Point(this.Right, this.Top), aTopText, aBottomText);
StephaneLenclud@189: clientThread.Start(myParams);
StephaneLenclud@189: BringToFront();
StephaneLenclud@189: }
StephaneLenclud@189:
StephaneLenclud@189:
sl@25: private void buttonStartClient_Click(object sender, EventArgs e)
sl@25: {
StephaneLenclud@106: StartNewClient();
sl@25: }
sl@25:
sl@27: private void buttonSuspend_Click(object sender, EventArgs e)
sl@27: {
StephaneLenclud@187: ToggleTimer();
StephaneLenclud@187: }
StephaneLenclud@187:
StephaneLenclud@187: private void StartTimer()
StephaneLenclud@187: {
StephaneLenclud@187: LastTickTime = DateTime.Now; //Reset timer to prevent jump
StephaneLenclud@187: timer.Enabled = true;
StephaneLenclud@187: UpdateSuspendButton();
StephaneLenclud@187: }
StephaneLenclud@187:
StephaneLenclud@187: private void StopTimer()
StephaneLenclud@187: {
StephaneLenclud@187: LastTickTime = DateTime.Now; //Reset timer to prevent jump
StephaneLenclud@187: timer.Enabled = false;
StephaneLenclud@187: UpdateSuspendButton();
StephaneLenclud@187: }
StephaneLenclud@187:
StephaneLenclud@187: private void ToggleTimer()
StephaneLenclud@187: {
sl@52: LastTickTime = DateTime.Now; //Reset timer to prevent jump
sl@27: timer.Enabled = !timer.Enabled;
StephaneLenclud@187: UpdateSuspendButton();
StephaneLenclud@187: }
StephaneLenclud@187:
StephaneLenclud@187: private void UpdateSuspendButton()
StephaneLenclud@187: {
sl@27: if (!timer.Enabled)
sl@27: {
sl@52: buttonSuspend.Text = "Run";
sl@27: }
sl@27: else
sl@27: {
sl@27: buttonSuspend.Text = "Pause";
sl@27: }
sl@27: }
sl@27:
StephaneLenclud@187:
sl@29: private void buttonCloseClients_Click(object sender, EventArgs e)
sl@29: {
sl@29: BroadcastCloseEvent();
sl@29: }
sl@29:
sl@30: private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
sl@30: {
StephaneLenclud@141: //Root node must have at least one child
StephaneLenclud@141: if (e.Node.Nodes.Count == 0)
StephaneLenclud@141: {
StephaneLenclud@141: return;
StephaneLenclud@141: }
sl@21:
StephaneLenclud@141: //If the selected node is the root node of a client then switch to it
StephaneLenclud@141: string sessionId=e.Node.Nodes[0].Text; //First child of a root node is the sessionId
StephaneLenclud@141: if (iClients.ContainsKey(sessionId)) //Check that's actually what we are looking at
StephaneLenclud@141: {
StephaneLenclud@141: //We have a valid session just switch to that client
StephaneLenclud@141: SetCurrentClient(sessionId,true);
StephaneLenclud@141: }
StephaneLenclud@141:
sl@30: }
sl@30:
sl@36:
sl@30: ///
sl@36: ///
sl@30: ///
sl@30: ///
sl@30: ///
sl@55: public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
sl@30: {
sl@33: if (this.InvokeRequired)
sl@30: {
sl@30: //Not in the proper thread, invoke ourselves
sl@30: AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
sl@30: this.Invoke(d, new object[] { aSessionId, aCallback });
sl@30: }
sl@30: else
sl@30: {
sl@30: //We are in the proper thread
sl@30: //Add this session to our collection of clients
sl@33: ClientData newClient = new ClientData(aSessionId, aCallback);
sl@33: Program.iMainForm.iClients.Add(aSessionId, newClient);
sl@30: //Add this session to our UI
sl@33: UpdateClientTreeViewNode(newClient);
sl@30: }
sl@30: }
sl@30:
Stephane@186:
Stephane@186: ///
Stephane@186: /// Find the client with the highest priority if any.
Stephane@186: ///
Stephane@186: /// Our highest priority client or null if not a single client is connected.
Stephane@186: public ClientData FindHighestPriorityClient()
Stephane@186: {
Stephane@186: ClientData highestPriorityClient = null;
Stephane@186: foreach (var client in iClients)
Stephane@186: {
Stephane@186: if (highestPriorityClient == null || client.Value.Priority > highestPriorityClient.Priority)
Stephane@186: {
Stephane@186: highestPriorityClient = client.Value;
Stephane@186: }
Stephane@186: }
Stephane@186:
Stephane@186: return highestPriorityClient;
Stephane@186: }
Stephane@186:
sl@30: ///
sl@36: ///
sl@30: ///
sl@30: ///
sl@30: public void RemoveClientThreadSafe(string aSessionId)
sl@30: {
sl@33: if (this.InvokeRequired)
sl@30: {
sl@30: //Not in the proper thread, invoke ourselves
sl@30: RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
sl@30: this.Invoke(d, new object[] { aSessionId });
sl@30: }
sl@30: else
sl@30: {
sl@30: //We are in the proper thread
sl@33: //Remove this session from both client collection and UI tree view
sl@30: if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
sl@30: {
sl@30: Program.iMainForm.iClients.Remove(aSessionId);
StephaneLenclud@188: Program.iMainForm.iTreeViewClients.Nodes.Remove(Program.iMainForm.iTreeViewClients.Nodes.Find(aSessionId, false)[0]);
StephaneLenclud@188: //Update recording status too whenever a client is removed
StephaneLenclud@188: UpdateRecordingNotification();
sl@32: }
sl@32:
Stephane@186: if (iCurrentClientSessionId == aSessionId)
Stephane@186: {
Stephane@186: //The current client is closing
Stephane@186: iCurrentClientData = null;
Stephane@186: //Find the client with the highest priority and set it as current
Stephane@186: ClientData newCurrentClient = FindHighestPriorityClient();
Stephane@186: if (newCurrentClient!=null)
Stephane@186: {
Stephane@186: SetCurrentClient(newCurrentClient.SessionId, true);
Stephane@186: }
Stephane@186: }
Stephane@186:
Stephane@186: if (iClients.Count == 0)
sl@97: {
sl@97: //Clear our screen when last client disconnects
sl@97: ClearLayout();
sl@97:
sl@97: if (iClosing)
sl@97: {
sl@97: //We were closing our form
sl@97: //All clients are now closed
sl@97: //Just resume our close operation
sl@97: iClosing = false;
sl@97: Close();
sl@97: }
sl@97: }
sl@30: }
sl@30: }
sl@30:
sl@30: ///
sl@36: ///
sl@30: ///
sl@62: ///
sl@72: ///
sl@62: public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
sl@62: {
sl@62: if (this.InvokeRequired)
sl@62: {
sl@62: //Not in the proper thread, invoke ourselves
sl@62: SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
sl@62: this.Invoke(d, new object[] { aSessionId, aLayout });
sl@62: }
sl@62: else
sl@62: {
sl@62: ClientData client = iClients[aSessionId];
sl@62: if (client != null)
sl@62: {
StephaneLenclud@148: //Don't change a thing if the layout is the same
StephaneLenclud@148: if (!client.Layout.IsSameAs(aLayout))
StephaneLenclud@148: {
StephaneLenclud@158: Debug.Print("SetClientLayoutThreadSafe: Layout updated.");
StephaneLenclud@148: //Set our client layout then
StephaneLenclud@148: client.Layout = aLayout;
StephaneLenclud@175: //So that next time we update all our fields at ones
StephaneLenclud@175: client.HasNewLayout = true;
StephaneLenclud@158: //Layout has changed clear our fields then
StephaneLenclud@158: client.Fields.Clear();
StephaneLenclud@148: //
StephaneLenclud@148: UpdateClientTreeViewNode(client);
StephaneLenclud@148: }
StephaneLenclud@158: else
StephaneLenclud@158: {
StephaneLenclud@158: Debug.Print("SetClientLayoutThreadSafe: Layout has not changed.");
StephaneLenclud@158: }
sl@62: }
sl@62: }
sl@62: }
sl@62:
sl@62: ///
sl@62: ///
sl@62: ///
sl@67: ///
sl@72: ///
sl@75: public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
sl@30: {
sl@33: if (this.InvokeRequired)
sl@30: {
sl@30: //Not in the proper thread, invoke ourselves
sl@79: SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
sl@72: this.Invoke(d, new object[] { aSessionId, aField });
sl@30: }
sl@30: else
sl@30: {
sl@75: //We are in the proper thread
sl@75: //Call the non-thread-safe variant
sl@75: SetClientField(aSessionId, aField);
sl@75: }
sl@75: }
sl@75:
StephaneLenclud@176:
StephaneLenclud@176:
StephaneLenclud@176:
sl@75: ///
StephaneLenclud@175: /// Set a data field in the given client.
sl@75: ///
sl@75: ///
sl@75: ///
sl@75: private void SetClientField(string aSessionId, DataField aField)
StephaneLenclud@141: {
StephaneLenclud@141: //TODO: should check if the field actually changed?
StephaneLenclud@141:
sl@75: ClientData client = iClients[aSessionId];
StephaneLenclud@141: bool layoutChanged = false;
StephaneLenclud@148: bool contentChanged = true;
StephaneLenclud@141:
StephaneLenclud@176: //Fetch our field index
StephaneLenclud@176: int fieldIndex = client.FindSameFieldIndex(aField);
StephaneLenclud@176:
StephaneLenclud@176: if (fieldIndex < 0)
sl@75: {
StephaneLenclud@176: //No corresponding field, just bail out
StephaneLenclud@176: return;
StephaneLenclud@141: }
sl@76:
StephaneLenclud@175: //Keep our previous field in there
StephaneLenclud@176: DataField previousField = client.Fields[fieldIndex];
StephaneLenclud@176: //Just update that field then
StephaneLenclud@176: client.Fields[fieldIndex] = aField;
StephaneLenclud@148:
StephaneLenclud@176: if (!aField.IsTableField)
StephaneLenclud@176: {
StephaneLenclud@176: //We are done then if that field is not in our table layout
StephaneLenclud@176: return;
StephaneLenclud@176: }
StephaneLenclud@176:
StephaneLenclud@176: TableField tableField = (TableField) aField;
StephaneLenclud@172:
StephaneLenclud@175: if (previousField.IsSameLayout(aField))
StephaneLenclud@141: {
StephaneLenclud@141: //If we are updating a field in our current client we need to update it in our panel
StephaneLenclud@141: if (aSessionId == iCurrentClientSessionId)
sl@30: {
StephaneLenclud@176: Control ctrl=iTableLayoutPanel.GetControlFromPosition(tableField.Column, tableField.Row);
StephaneLenclud@176: if (aField.IsTextField && ctrl is MarqueeLabel)
sl@79: {
StephaneLenclud@172: TextField textField=(TextField)aField;
sl@75: //Text field control already in place, just change the text
StephaneLenclud@176: MarqueeLabel label = (MarqueeLabel)ctrl;
StephaneLenclud@172: contentChanged = (label.Text != textField.Text || label.TextAlign != textField.Alignment);
StephaneLenclud@172: label.Text = textField.Text;
StephaneLenclud@172: label.TextAlign = textField.Alignment;
sl@68: }
StephaneLenclud@176: else if (aField.IsBitmapField && ctrl is PictureBox)
sl@75: {
StephaneLenclud@172: BitmapField bitmapField = (BitmapField)aField;
StephaneLenclud@148: contentChanged = true; //TODO: Bitmap comp or should we leave that to clients?
sl@75: //Bitmap field control already in place just change the bitmap
StephaneLenclud@176: PictureBox pictureBox = (PictureBox)ctrl;
StephaneLenclud@172: pictureBox.Image = bitmapField.Bitmap;
sl@75: }
sl@68: else
sl@68: {
StephaneLenclud@141: layoutChanged = true;
sl@68: }
sl@30: }
StephaneLenclud@141: }
StephaneLenclud@141: else
StephaneLenclud@148: {
StephaneLenclud@141: layoutChanged = true;
StephaneLenclud@141: }
StephaneLenclud@141:
StephaneLenclud@148: //If either content or layout changed we need to update our tree view to reflect the changes
StephaneLenclud@148: if (contentChanged || layoutChanged)
StephaneLenclud@141: {
StephaneLenclud@141: UpdateClientTreeViewNode(client);
StephaneLenclud@148: //
StephaneLenclud@148: if (layoutChanged)
sl@75: {
StephaneLenclud@148: Debug.Print("Layout changed");
StephaneLenclud@148: //Our layout has changed, if we are already the current client we need to update our panel
StephaneLenclud@148: if (aSessionId == iCurrentClientSessionId)
StephaneLenclud@148: {
StephaneLenclud@148: //Apply layout and set data fields.
StephaneLenclud@148: UpdateTableLayoutPanel(iCurrentClientData);
StephaneLenclud@148: }
sl@75: }
StephaneLenclud@158: else
StephaneLenclud@158: {
StephaneLenclud@158: Debug.Print("Layout has not changed.");
StephaneLenclud@158: }
StephaneLenclud@158: }
StephaneLenclud@158: else
StephaneLenclud@158: {
StephaneLenclud@158: Debug.Print("WARNING: content and layout have not changed!");
StephaneLenclud@141: }
sl@75:
StephaneLenclud@141: //When a client field is set we try switching to this client to present the new information to our user
StephaneLenclud@141: SetCurrentClient(aSessionId);
sl@30: }
sl@30:
sl@30: ///
sl@36: ///
sl@30: ///
sl@30: ///
sl@75: public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList aFields)
sl@30: {
sl@33: if (this.InvokeRequired)
sl@30: {
sl@30: //Not in the proper thread, invoke ourselves
sl@75: SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
sl@72: this.Invoke(d, new object[] { aSessionId, aFields });
sl@30: }
sl@30: else
sl@30: {
StephaneLenclud@175: ClientData client = iClients[aSessionId];
StephaneLenclud@175:
StephaneLenclud@175: if (client.HasNewLayout)
sl@30: {
StephaneLenclud@175: //TODO: Assert client.Count == 0
StephaneLenclud@175: //Our layout was just changed
StephaneLenclud@175: //Do some special handling to avoid re-creating our panel N times, once for each fields
StephaneLenclud@175: client.HasNewLayout = false;
StephaneLenclud@175: //Just set all our fields then
StephaneLenclud@175: client.Fields.AddRange(aFields);
StephaneLenclud@175: //Try switch to that client
StephaneLenclud@175: SetCurrentClient(aSessionId);
StephaneLenclud@175:
StephaneLenclud@175: //If we are updating the current client update our panel
StephaneLenclud@175: if (aSessionId == iCurrentClientSessionId)
StephaneLenclud@175: {
StephaneLenclud@175: //Apply layout and set data fields.
StephaneLenclud@175: UpdateTableLayoutPanel(iCurrentClientData);
StephaneLenclud@175: }
StephaneLenclud@176:
StephaneLenclud@176: UpdateClientTreeViewNode(client);
StephaneLenclud@175: }
StephaneLenclud@175: else
StephaneLenclud@175: {
StephaneLenclud@175: //Put each our text fields in a label control
StephaneLenclud@175: foreach (DataField field in aFields)
StephaneLenclud@175: {
StephaneLenclud@175: SetClientField(aSessionId, field);
StephaneLenclud@175: }
sl@30: }
sl@30: }
sl@32: }
sl@30:
sl@67: ///
sl@67: ///
sl@67: ///
sl@67: ///
sl@32: ///
sl@32: public void SetClientNameThreadSafe(string aSessionId, string aName)
sl@32: {
sl@32: if (this.InvokeRequired)
sl@32: {
sl@32: //Not in the proper thread, invoke ourselves
sl@32: SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
sl@32: this.Invoke(d, new object[] { aSessionId, aName });
sl@32: }
sl@32: else
sl@32: {
sl@32: //We are in the proper thread
sl@33: //Get our client
sl@33: ClientData client = iClients[aSessionId];
sl@33: if (client != null)
sl@32: {
sl@33: //Set its name
sl@33: client.Name = aName;
sl@33: //Update our tree-view
sl@33: UpdateClientTreeViewNode(client);
sl@33: }
sl@33: }
sl@33: }
sl@33:
StephaneLenclud@184: ///
StephaneLenclud@184: public void SetClientPriorityThreadSafe(string aSessionId, uint aPriority)
StephaneLenclud@184: {
StephaneLenclud@184: if (this.InvokeRequired)
StephaneLenclud@184: {
StephaneLenclud@184: //Not in the proper thread, invoke ourselves
StephaneLenclud@184: SetClientPriorityDelegate d = new SetClientPriorityDelegate(SetClientPriorityThreadSafe);
StephaneLenclud@184: this.Invoke(d, new object[] { aSessionId, aPriority });
StephaneLenclud@184: }
StephaneLenclud@184: else
StephaneLenclud@184: {
StephaneLenclud@184: //We are in the proper thread
StephaneLenclud@184: //Get our client
StephaneLenclud@184: ClientData client = iClients[aSessionId];
StephaneLenclud@184: if (client != null)
StephaneLenclud@184: {
StephaneLenclud@184: //Set its name
StephaneLenclud@184: client.Priority = aPriority;
StephaneLenclud@184: //Update our tree-view
StephaneLenclud@184: UpdateClientTreeViewNode(client);
Stephane@186: //Change our current client as per new priority
Stephane@186: ClientData newCurrentClient = FindHighestPriorityClient();
Stephane@186: if (newCurrentClient!=null)
Stephane@186: {
Stephane@186: SetCurrentClient(newCurrentClient.SessionId);
Stephane@186: }
StephaneLenclud@184: }
StephaneLenclud@184: }
StephaneLenclud@184: }
StephaneLenclud@184:
sl@33: ///
StephaneLenclud@183: ///
StephaneLenclud@183: ///
StephaneLenclud@183: ///
StephaneLenclud@183: ///
StephaneLenclud@183: ///
StephaneLenclud@183: public static string Truncate(string value, int maxChars)
StephaneLenclud@183: {
StephaneLenclud@183: return value.Length <= maxChars ? value : value.Substring(0, maxChars-3) + "...";
StephaneLenclud@183: }
StephaneLenclud@183:
StephaneLenclud@183: ///
StephaneLenclud@180: /// Update our recording notification.
StephaneLenclud@180: ///
StephaneLenclud@180: private void UpdateRecordingNotification()
StephaneLenclud@180: {
StephaneLenclud@180: //Go through each
StephaneLenclud@180: bool activeRecording = false;
StephaneLenclud@180: string text="";
StephaneLenclud@180: RecordingField recField=new RecordingField();
StephaneLenclud@180: foreach (var client in iClients)
StephaneLenclud@180: {
StephaneLenclud@180: RecordingField rec=(RecordingField)client.Value.FindSameFieldAs(recField);
StephaneLenclud@180: if (rec!=null && rec.IsActive)
StephaneLenclud@180: {
StephaneLenclud@180: activeRecording = true;
StephaneLenclud@183: //Don't break cause we are collecting the names/texts.
StephaneLenclud@183: if (!String.IsNullOrEmpty(rec.Text))
StephaneLenclud@183: {
StephaneLenclud@183: text += (rec.Text + "\n");
StephaneLenclud@183: }
StephaneLenclud@183: else
StephaneLenclud@183: {
StephaneLenclud@183: //Not text for that recording, use client name instead
StephaneLenclud@183: text += client.Value.Name + " recording\n";
StephaneLenclud@183: }
StephaneLenclud@183:
StephaneLenclud@180: }
StephaneLenclud@180: }
StephaneLenclud@180:
StephaneLenclud@183: //Update our text no matter what, can't have more than 63 characters otherwise it throws an exception.
StephaneLenclud@183: iRecordingNotification.Text = Truncate(text,63);
StephaneLenclud@183:
StephaneLenclud@180: //Change visibility of notification if needed
StephaneLenclud@180: if (iRecordingNotification.Visible != activeRecording)
StephaneLenclud@183: {
StephaneLenclud@180: iRecordingNotification.Visible = activeRecording;
Stephane@182: //Assuming the notification icon is in sync with our display icon
Stephane@182: //Take care of our REC icon
StephaneLenclud@183: if (iDisplay.IsOpen())
StephaneLenclud@183: {
StephaneLenclud@183: iDisplay.SetIconOnOff(MiniDisplay.IconType.Recording, activeRecording);
StephaneLenclud@183: }
StephaneLenclud@180: }
StephaneLenclud@180: }
StephaneLenclud@180:
StephaneLenclud@180: ///
sl@36: ///
sl@33: ///
sl@33: ///
sl@33: private void UpdateClientTreeViewNode(ClientData aClient)
sl@33: {
StephaneLenclud@148: Debug.Print("UpdateClientTreeViewNode");
StephaneLenclud@148:
sl@33: if (aClient == null)
sl@33: {
sl@33: return;
sl@33: }
sl@33:
StephaneLenclud@180: //Hook in record icon update too
StephaneLenclud@180: UpdateRecordingNotification();
StephaneLenclud@180:
sl@33: TreeNode node = null;
sl@33: //Check that our client node already exists
sl@33: //Get our client root node using its key which is our session ID
StephaneLenclud@188: TreeNode[] nodes = iTreeViewClients.Nodes.Find(aClient.SessionId, false);
sl@33: if (nodes.Count()>0)
sl@33: {
sl@33: //We already have a node for that client
sl@33: node = nodes[0];
sl@33: //Clear children as we are going to recreate them below
sl@33: node.Nodes.Clear();
sl@33: }
sl@33: else
sl@33: {
sl@33: //Client node does not exists create a new one
StephaneLenclud@188: iTreeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
StephaneLenclud@188: node = iTreeViewClients.Nodes.Find(aClient.SessionId, false)[0];
sl@33: }
sl@33:
sl@33: if (node != null)
sl@33: {
sl@33: //Change its name
StephaneLenclud@184: if (!String.IsNullOrEmpty(aClient.Name))
sl@33: {
StephaneLenclud@184: //We have a name, use it as text for our root node
sl@33: node.Text = aClient.Name;
sl@32: //Add a child with SessionId
sl@33: node.Nodes.Add(new TreeNode(aClient.SessionId));
sl@33: }
sl@33: else
sl@33: {
sl@33: //No name, use session ID instead
sl@33: node.Text = aClient.SessionId;
sl@33: }
sl@36:
StephaneLenclud@184: //Display client priority
StephaneLenclud@184: node.Nodes.Add(new TreeNode("Priority: " + aClient.Priority));
StephaneLenclud@184:
sl@67: if (aClient.Fields.Count > 0)
sl@33: {
sl@33: //Create root node for our texts
sl@70: TreeNode textsRoot = new TreeNode("Fields");
sl@33: node.Nodes.Add(textsRoot);
sl@33: //For each text add a new entry
sl@67: foreach (DataField field in aClient.Fields)
sl@33: {
StephaneLenclud@172: if (field.IsTextField)
sl@67: {
StephaneLenclud@172: TextField textField = (TextField)field;
sl@70: textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
sl@67: }
StephaneLenclud@172: else if (field.IsBitmapField)
sl@67: {
sl@72: textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
sl@70: }
StephaneLenclud@172: else if (field.IsRecordingField)
StephaneLenclud@172: {
StephaneLenclud@177: RecordingField recordingField = (RecordingField)field;
StephaneLenclud@177: textsRoot.Nodes.Add(new TreeNode("[Recording]" + recordingField.IsActive));
StephaneLenclud@172: }
sl@33: }
sl@32: }
sl@34:
sl@34: node.ExpandAll();
sl@32: }
sl@30: }
sl@17:
sl@60: ///
sl@60: /// Update our table layout row styles to make sure each rows have similar height
sl@60: ///
sl@60: private void UpdateTableLayoutRowStyles()
sl@60: {
StephaneLenclud@175: foreach (RowStyle rowStyle in iTableLayoutPanel.RowStyles)
sl@60: {
sl@60: rowStyle.SizeType = SizeType.Percent;
StephaneLenclud@175: rowStyle.Height = 100 / iTableLayoutPanel.RowCount;
sl@60: }
sl@60: }
sl@60:
sl@63: ///
sl@63: /// Update our display table layout.
StephaneLenclud@175: /// Will instanciated every field control as defined by our client.
StephaneLenclud@175: /// Fields must be specified by rows from the left.
sl@63: ///
sl@63: ///
sl@65: private void UpdateTableLayoutPanel(ClientData aClient)
sl@63: {
StephaneLenclud@175: Debug.Print("UpdateTableLayoutPanel");
StephaneLenclud@148:
StephaneLenclud@106: if (aClient == null)
StephaneLenclud@106: {
StephaneLenclud@106: //Just drop it
StephaneLenclud@106: return;
StephaneLenclud@106: }
StephaneLenclud@106:
StephaneLenclud@106:
sl@65: TableLayout layout = aClient.Layout;
sl@70:
StephaneLenclud@141: //First clean our current panel
StephaneLenclud@175: iTableLayoutPanel.Controls.Clear();
StephaneLenclud@175: iTableLayoutPanel.RowStyles.Clear();
StephaneLenclud@175: iTableLayoutPanel.ColumnStyles.Clear();
StephaneLenclud@175: iTableLayoutPanel.RowCount = 0;
StephaneLenclud@175: iTableLayoutPanel.ColumnCount = 0;
sl@63:
StephaneLenclud@175: //Then recreate our rows...
StephaneLenclud@175: while (iTableLayoutPanel.RowCount < layout.Rows.Count)
sl@63: {
StephaneLenclud@175: iTableLayoutPanel.RowCount++;
sl@63: }
sl@63:
StephaneLenclud@175: // ...and columns
StephaneLenclud@175: while (iTableLayoutPanel.ColumnCount < layout.Columns.Count)
sl@63: {
StephaneLenclud@175: iTableLayoutPanel.ColumnCount++;
sl@63: }
sl@63:
StephaneLenclud@175: //For each column
StephaneLenclud@175: for (int i = 0; i < iTableLayoutPanel.ColumnCount; i++)
sl@63: {
sl@63: //Create our column styles
StephaneLenclud@175: this.iTableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
sl@63:
StephaneLenclud@175: //For each rows
StephaneLenclud@175: for (int j = 0; j < iTableLayoutPanel.RowCount; j++)
sl@63: {
sl@63: if (i == 0)
sl@63: {
sl@63: //Create our row styles
StephaneLenclud@175: this.iTableLayoutPanel.RowStyles.Add(layout.Rows[j]);
sl@63: }
StephaneLenclud@176: else
sl@70: {
sl@70: continue;
sl@70: }
sl@63: }
sl@63: }
sl@63:
StephaneLenclud@176: //For each field
StephaneLenclud@176: foreach (DataField field in aClient.Fields)
sl@70: {
StephaneLenclud@176: if (!field.IsTableField)
StephaneLenclud@176: {
StephaneLenclud@176: //That field is not taking part in our table layout skip it
StephaneLenclud@176: continue;
StephaneLenclud@176: }
StephaneLenclud@176:
StephaneLenclud@176: TableField tableField = (TableField)field;
StephaneLenclud@176:
StephaneLenclud@176: //Create a control corresponding to the field specified for that cell
StephaneLenclud@176: Control control = CreateControlForDataField(tableField);
StephaneLenclud@176:
StephaneLenclud@176: //Add newly created control to our table layout at the specified row and column
StephaneLenclud@176: iTableLayoutPanel.Controls.Add(control, tableField.Column, tableField.Row);
StephaneLenclud@176: //Make sure we specify column and row span for that new control
StephaneLenclud@176: iTableLayoutPanel.SetColumnSpan(control, tableField.ColumnSpan);
StephaneLenclud@176: iTableLayoutPanel.SetRowSpan(control, tableField.RowSpan);
sl@70: }
sl@70:
StephaneLenclud@176:
sl@63: CheckFontHeight();
sl@63: }
sl@63:
sl@68: ///
sl@70: /// Check our type of data field and create corresponding control
sl@68: ///
sl@68: ///
sl@69: private Control CreateControlForDataField(DataField aField)
sl@68: {
sl@68: Control control=null;
StephaneLenclud@172: if (aField.IsTextField)
sl@68: {
sl@68: MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
sl@68: label.AutoEllipsis = true;
sl@68: label.AutoSize = true;
sl@68: label.BackColor = System.Drawing.Color.Transparent;
sl@68: label.Dock = System.Windows.Forms.DockStyle.Fill;
sl@68: label.Location = new System.Drawing.Point(1, 1);
sl@68: label.Margin = new System.Windows.Forms.Padding(0);
StephaneLenclud@176: label.Name = "marqueeLabel" + aField;
sl@68: label.OwnTimer = false;
StephaneLenclud@106: label.PixelsPerSecond = cds.ScrollingSpeedInPixelsPerSecond;
sl@100: label.Separator = cds.Separator;
sl@100: label.MinFontSize = cds.MinFontSize;
sl@100: label.ScaleToFit = cds.ScaleToFit;
sl@68: //control.Size = new System.Drawing.Size(254, 30);
sl@68: //control.TabIndex = 2;
sl@68: label.Font = cds.Font;
sl@68:
StephaneLenclud@172: TextField field = (TextField)aField;
StephaneLenclud@172: label.TextAlign = field.Alignment;
sl@68: label.UseCompatibleTextRendering = true;
StephaneLenclud@172: label.Text = field.Text;
sl@68: //
sl@68: control = label;
sl@68: }
StephaneLenclud@172: else if (aField.IsBitmapField)
sl@68: {
sl@68: //Create picture box
sl@68: PictureBox picture = new PictureBox();
sl@68: picture.AutoSize = true;
sl@68: picture.BackColor = System.Drawing.Color.Transparent;
sl@68: picture.Dock = System.Windows.Forms.DockStyle.Fill;
sl@68: picture.Location = new System.Drawing.Point(1, 1);
sl@68: picture.Margin = new System.Windows.Forms.Padding(0);
sl@68: picture.Name = "pictureBox" + aField;
sl@68: //Set our image
StephaneLenclud@172: BitmapField field = (BitmapField)aField;
StephaneLenclud@172: picture.Image = field.Bitmap;
sl@68: //
sl@68: control = picture;
sl@68: }
StephaneLenclud@172: //TODO: Handle recording field?
sl@68:
sl@69: return control;
sl@68: }
sl@68:
StephaneLenclud@103: ///
StephaneLenclud@103: /// Called when the user selected a new display type.
StephaneLenclud@103: ///
StephaneLenclud@103: ///
StephaneLenclud@103: ///
sl@46: private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
sl@46: {
StephaneLenclud@103: //Store the selected display type in our settings
sl@48: Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
sl@48: cds.DisplayType = comboBoxDisplayType.SelectedIndex;
sl@46: Properties.Settings.Default.Save();
StephaneLenclud@103:
StephaneLenclud@103: //Try re-opening the display connection if we were already connected.
StephaneLenclud@103: //Otherwise just update our status to reflect display type change.
sl@51: if (iDisplay.IsOpen())
sl@51: {
sl@51: OpenDisplayConnection();
sl@51: }
sl@51: else
sl@51: {
sl@51: UpdateStatus();
sl@51: }
sl@46: }
sl@46:
sl@47: private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
sl@47: {
sl@47: if (maskedTextBoxTimerInterval.Text != "")
sl@47: {
sl@51: int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
sl@51:
sl@51: if (interval > 0)
sl@51: {
sl@51: timer.Interval = interval;
sl@51: cds.TimerInterval = timer.Interval;
sl@51: Properties.Settings.Default.Save();
sl@51: }
sl@47: }
sl@47: }
sl@47:
sl@100: private void maskedTextBoxMinFontSize_TextChanged(object sender, EventArgs e)
sl@100: {
sl@100: if (maskedTextBoxMinFontSize.Text != "")
sl@100: {
sl@100: int minFontSize = Convert.ToInt32(maskedTextBoxMinFontSize.Text);
sl@100:
sl@100: if (minFontSize > 0)
sl@100: {
sl@100: cds.MinFontSize = minFontSize;
sl@100: Properties.Settings.Default.Save();
StephaneLenclud@106: //We need to recreate our layout for that change to take effect
StephaneLenclud@106: UpdateTableLayoutPanel(iCurrentClientData);
sl@100: }
sl@100: }
sl@100: }
sl@100:
StephaneLenclud@106:
StephaneLenclud@106: private void maskedTextBoxScrollingSpeed_TextChanged(object sender, EventArgs e)
StephaneLenclud@106: {
StephaneLenclud@106: if (maskedTextBoxScrollingSpeed.Text != "")
StephaneLenclud@106: {
StephaneLenclud@106: int scrollingSpeed = Convert.ToInt32(maskedTextBoxScrollingSpeed.Text);
StephaneLenclud@106:
StephaneLenclud@106: if (scrollingSpeed > 0)
StephaneLenclud@106: {
StephaneLenclud@106: cds.ScrollingSpeedInPixelsPerSecond = scrollingSpeed;
StephaneLenclud@106: Properties.Settings.Default.Save();
StephaneLenclud@106: //We need to recreate our layout for that change to take effect
StephaneLenclud@106: UpdateTableLayoutPanel(iCurrentClientData);
StephaneLenclud@106: }
StephaneLenclud@106: }
StephaneLenclud@106: }
StephaneLenclud@106:
sl@100: private void textBoxScrollLoopSeparator_TextChanged(object sender, EventArgs e)
sl@100: {
sl@100: cds.Separator = textBoxScrollLoopSeparator.Text;
sl@100: Properties.Settings.Default.Save();
StephaneLenclud@110:
StephaneLenclud@110: //Update our text fields
StephaneLenclud@175: foreach (MarqueeLabel ctrl in iTableLayoutPanel.Controls)
StephaneLenclud@110: {
StephaneLenclud@110: ctrl.Separator = cds.Separator;
StephaneLenclud@110: }
StephaneLenclud@110:
sl@100: }
sl@100:
sl@52: private void buttonPowerOn_Click(object sender, EventArgs e)
sl@52: {
sl@52: iDisplay.PowerOn();
sl@52: }
sl@52:
sl@52: private void buttonPowerOff_Click(object sender, EventArgs e)
sl@52: {
sl@52: iDisplay.PowerOff();
sl@52: }
sl@52:
sl@53: private void buttonShowClock_Click(object sender, EventArgs e)
sl@53: {
StephaneLenclud@122: ShowClock();
sl@53: }
sl@53:
sl@53: private void buttonHideClock_Click(object sender, EventArgs e)
sl@53: {
StephaneLenclud@122: HideClock();
sl@53: }
sl@88:
sl@88: private void buttonUpdate_Click(object sender, EventArgs e)
sl@88: {
sl@88: InstallUpdateSyncWithInfo();
sl@88: }
sl@88:
StephaneLenclud@122: ///
StephaneLenclud@122: ///
StephaneLenclud@122: ///
StephaneLenclud@122: void ShowClock()
StephaneLenclud@122: {
StephaneLenclud@122: if (!iDisplay.IsOpen())
StephaneLenclud@122: {
StephaneLenclud@122: return;
StephaneLenclud@122: }
StephaneLenclud@122:
StephaneLenclud@122: //Devices like MDM166AA don't support windowing and frame rendering must be stopped while showing our clock
StephaneLenclud@122: iSkipFrameRendering = true;
StephaneLenclud@122: //Clear our screen
StephaneLenclud@122: iDisplay.Clear();
StephaneLenclud@122: iDisplay.SwapBuffers();
StephaneLenclud@122: //Then show our clock
StephaneLenclud@122: iDisplay.ShowClock();
StephaneLenclud@122: }
StephaneLenclud@122:
StephaneLenclud@122: ///
StephaneLenclud@122: ///
StephaneLenclud@122: ///
StephaneLenclud@122: void HideClock()
StephaneLenclud@122: {
StephaneLenclud@122: if (!iDisplay.IsOpen())
StephaneLenclud@122: {
StephaneLenclud@122: return;
StephaneLenclud@122: }
StephaneLenclud@122:
StephaneLenclud@122: //Devices like MDM166AA don't support windowing and frame rendering must be stopped while showing our clock
StephaneLenclud@122: iSkipFrameRendering = false;
StephaneLenclud@122: iDisplay.HideClock();
StephaneLenclud@122: }
sl@88:
sl@88: private void InstallUpdateSyncWithInfo()
sl@88: {
sl@88: UpdateCheckInfo info = null;
sl@88:
sl@88: if (ApplicationDeployment.IsNetworkDeployed)
sl@88: {
sl@88: ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
sl@88:
sl@88: try
sl@88: {
sl@88: info = ad.CheckForDetailedUpdate();
sl@88:
sl@88: }
sl@88: catch (DeploymentDownloadException dde)
sl@88: {
sl@88: 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: return;
sl@88: }
sl@88: catch (InvalidDeploymentException ide)
sl@88: {
sl@88: 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: return;
sl@88: }
sl@88: catch (InvalidOperationException ioe)
sl@88: {
sl@88: MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
sl@88: return;
sl@88: }
sl@88:
sl@90: if (info.UpdateAvailable)
sl@90: {
sl@90: Boolean doUpdate = true;
sl@88:
sl@90: if (!info.IsUpdateRequired)
sl@90: {
sl@90: DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
sl@90: if (!(DialogResult.OK == dr))
sl@90: {
sl@90: doUpdate = false;
sl@90: }
sl@90: }
sl@90: else
sl@90: {
StephaneLenclud@187: // Display a message that the application MUST reboot. Display the minimum required version.
sl@90: MessageBox.Show("This application has detected a mandatory update from your current " +
sl@90: "version to version " + info.MinimumRequiredVersion.ToString() +
sl@90: ". The application will now install the update and restart.",
sl@90: "Update Available", MessageBoxButtons.OK,
sl@90: MessageBoxIcon.Information);
sl@90: }
sl@88:
sl@90: if (doUpdate)
sl@90: {
sl@90: try
sl@90: {
sl@90: ad.Update();
sl@90: MessageBox.Show("The application has been upgraded, and will now restart.");
sl@90: Application.Restart();
sl@90: }
sl@90: catch (DeploymentDownloadException dde)
sl@90: {
sl@90: MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
sl@90: return;
sl@90: }
sl@90: }
sl@90: }
sl@90: else
sl@90: {
sl@90: MessageBox.Show("You are already running the latest version.", "Application up-to-date");
sl@90: }
sl@88: }
sl@88: }
sl@92:
sl@94:
sl@94: ///
sl@99: /// Used to
sl@94: ///
sl@94: private void SysTrayHideShow()
sl@92: {
sl@94: Visible = !Visible;
sl@94: if (Visible)
sl@94: {
sl@94: Activate();
sl@94: WindowState = FormWindowState.Normal;
sl@94: }
sl@92: }
sl@94:
sl@94: ///
sl@94: /// Use to handle minimize events.
sl@94: ///
sl@94: ///
sl@94: ///
sl@94: private void MainForm_SizeChanged(object sender, EventArgs e)
sl@94: {
sl@94: if (WindowState == FormWindowState.Minimized && Properties.Settings.Default.MinimizeToTray)
sl@94: {
sl@94: if (Visible)
sl@94: {
sl@94: SysTrayHideShow();
sl@94: }
sl@94: }
sl@94: }
sl@94:
StephaneLenclud@105: ///
StephaneLenclud@105: ///
StephaneLenclud@105: ///
StephaneLenclud@105: ///
StephaneLenclud@105: ///
StephaneLenclud@105: private void tableLayoutPanel_SizeChanged(object sender, EventArgs e)
StephaneLenclud@105: {
StephaneLenclud@105: //Our table layout size has changed which means our display size has changed.
StephaneLenclud@105: //We need to re-create our bitmap.
StephaneLenclud@105: iCreateBitmap = true;
StephaneLenclud@105: }
StephaneLenclud@126:
StephaneLenclud@126: ///
StephaneLenclud@126: ///
StephaneLenclud@126: ///
StephaneLenclud@126: ///
StephaneLenclud@126: ///
StephaneLenclud@126: private void buttonSelectFile_Click(object sender, EventArgs e)
StephaneLenclud@126: {
StephaneLenclud@126: //openFileDialog1.InitialDirectory = "c:\\";
StephaneLenclud@126: //openFileDialog.Filter = "EXE files (*.exe)|*.exe|All files (*.*)|*.*";
StephaneLenclud@126: //openFileDialog.FilterIndex = 1;
StephaneLenclud@126: openFileDialog.RestoreDirectory = true;
StephaneLenclud@126:
StephaneLenclud@126: if (DlgBox.ShowDialog(openFileDialog) == DialogResult.OK)
StephaneLenclud@126: {
StephaneLenclud@126: labelStartFileName.Text = openFileDialog.FileName;
StephaneLenclud@126: Properties.Settings.Default.StartFileName = openFileDialog.FileName;
StephaneLenclud@126: Properties.Settings.Default.Save();
StephaneLenclud@126: }
StephaneLenclud@126: }
StephaneLenclud@153:
StephaneLenclud@153: ///
StephaneLenclud@153: ///
StephaneLenclud@153: ///
StephaneLenclud@153: ///
StephaneLenclud@153: ///
StephaneLenclud@153: private void comboBoxOpticalDrives_SelectedIndexChanged(object sender, EventArgs e)
StephaneLenclud@153: {
StephaneLenclud@153: //Save the optical drive the user selected for ejection
StephaneLenclud@153: Properties.Settings.Default.OpticalDriveToEject = comboBoxOpticalDrives.SelectedItem.ToString();
StephaneLenclud@153: Properties.Settings.Default.Save();
StephaneLenclud@153: }
StephaneLenclud@167:
StephaneLenclud@167: ///
StephaneLenclud@167: /// Broadcast messages to subscribers.
StephaneLenclud@167: ///
StephaneLenclud@167: ///
StephaneLenclud@167: protected override void WndProc(ref Message aMessage)
StephaneLenclud@167: {
StephaneLenclud@167: if (OnWndProc!=null)
StephaneLenclud@167: {
StephaneLenclud@167: OnWndProc(ref aMessage);
StephaneLenclud@167: }
StephaneLenclud@167:
StephaneLenclud@167: base.WndProc(ref aMessage);
StephaneLenclud@167: }
StephaneLenclud@168:
StephaneLenclud@168: private void checkBoxCecEnabled_CheckedChanged(object sender, EventArgs e)
StephaneLenclud@168: {
StephaneLenclud@168: //Save CEC enabled status
StephaneLenclud@168: Properties.Settings.Default.CecEnabled = checkBoxCecEnabled.Checked;
StephaneLenclud@168: Properties.Settings.Default.Save();
StephaneLenclud@168: //
StephaneLenclud@168: ResetCec();
StephaneLenclud@168: }
StephaneLenclud@168:
StephaneLenclud@168: private void comboBoxHdmiPort_SelectedIndexChanged(object sender, EventArgs e)
StephaneLenclud@168: {
StephaneLenclud@168: //Save CEC HDMI port
StephaneLenclud@168: Properties.Settings.Default.CecHdmiPort = Convert.ToByte(comboBoxHdmiPort.SelectedIndex);
StephaneLenclud@168: Properties.Settings.Default.CecHdmiPort++;
StephaneLenclud@168: Properties.Settings.Default.Save();
StephaneLenclud@168: //
StephaneLenclud@168: ResetCec();
StephaneLenclud@168: }
StephaneLenclud@168:
StephaneLenclud@168: private void checkBoxCecMonitorOff_CheckedChanged(object sender, EventArgs e)
StephaneLenclud@168: {
StephaneLenclud@168: Properties.Settings.Default.CecMonitorOff = checkBoxCecMonitorOff.Checked;
StephaneLenclud@168: Properties.Settings.Default.Save();
StephaneLenclud@168: //
StephaneLenclud@168: ResetCec();
StephaneLenclud@168: }
StephaneLenclud@168:
StephaneLenclud@168: private void checkBoxCecMonitorOn_CheckedChanged(object sender, EventArgs e)
StephaneLenclud@168: {
StephaneLenclud@168: Properties.Settings.Default.CecMonitorOn = checkBoxCecMonitorOn.Checked;
StephaneLenclud@168: Properties.Settings.Default.Save();
StephaneLenclud@168: //
StephaneLenclud@168: ResetCec();
StephaneLenclud@168: }
StephaneLenclud@168:
StephaneLenclud@168: ///
StephaneLenclud@168: ///
StephaneLenclud@168: ///
StephaneLenclud@168: private void ResetCec()
StephaneLenclud@168: {
StephaneLenclud@168: if (iCecManager==null)
StephaneLenclud@168: {
StephaneLenclud@168: //Thus skipping initial UI setup
StephaneLenclud@168: return;
StephaneLenclud@168: }
StephaneLenclud@168:
StephaneLenclud@168: iCecManager.Stop();
StephaneLenclud@168: //
StephaneLenclud@168: if (Properties.Settings.Default.CecEnabled)
StephaneLenclud@168: {
StephaneLenclud@168: iCecManager.Start(Handle, "CEC",
StephaneLenclud@168: Properties.Settings.Default.CecHdmiPort,
StephaneLenclud@168: Properties.Settings.Default.CecMonitorOn,
StephaneLenclud@168: Properties.Settings.Default.CecMonitorOff);
StephaneLenclud@168: }
StephaneLenclud@168: }
StephaneLenclud@189:
StephaneLenclud@189: private void ButtonStartIdleClient_Click(object sender, EventArgs e)
StephaneLenclud@189: {
StephaneLenclud@189: StartIdleClient();
StephaneLenclud@189: }
sl@0: }
sl@0: }