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;
sl@0:
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@112: public delegate void PlainUpdateDelegate();
sl@62:
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@112:
sl@2:
sl@94: ///
sl@94: /// Manage run when Windows startup option
sl@94: ///
sl@92: private StartupManager iStartupManager;
sl@92:
sl@94: ///
sl@94: /// System tray icon.
sl@94: ///
sl@94: private NotifyIconAdv iNotifyIcon;
sl@94:
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();
sl@94: iNotifyIcon = new NotifyIconAdv();
sl@2:
StephaneLenclud@104: //Have our designer initialize its controls
sl@0: InitializeComponent();
StephaneLenclud@104:
StephaneLenclud@104: //Populate device types
StephaneLenclud@104: PopulateDeviceTypes();
StephaneLenclud@104:
StephaneLenclud@104: //Initial status update
sl@7: UpdateStatus();
StephaneLenclud@104:
sl@14: //We have a bug when drawing minimized and reusing our bitmap
sl@14: iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.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@106: //Setup notification icon
StephaneLenclud@106: SetupTrayIcon();
StephaneLenclud@106:
StephaneLenclud@106: // To make sure start up with minimize to tray works
StephaneLenclud@106: 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@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@122: //Make sure we resume frame rendering
StephaneLenclud@122: 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@104: //Our display was just closed, update our UI consequently
StephaneLenclud@104: 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@118: iDisplay.SetIconOnOff(Display.TMiniDisplayIconType.EMiniDisplayIconInternet, iNetworkManager.NetworkListManager.IsConnectedToInternet);
StephaneLenclud@118: iDisplay.SetIconOnOff(Display.TMiniDisplayIconType.EMiniDisplayIconNetworkSignal, 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@118: {
StephaneLenclud@118: int iconCount=iDisplay.IconCount(Display.TMiniDisplayIconType.EMiniDisplayIconNetworkSignal);
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@118: iDisplay.SetIconOn(Display.TMiniDisplayIconType.EMiniDisplayIconNetworkSignal,i);
StephaneLenclud@118: }
StephaneLenclud@118: else
StephaneLenclud@118: {
StephaneLenclud@118: iDisplay.SetIconOff(Display.TMiniDisplayIconType.EMiniDisplayIconNetworkSignal,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@112: int volumeIconCount = iDisplay.IconCount(Display.TMiniDisplayIconType.EMiniDisplayIconVolume);
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@114: iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconVolume, i, (iDisplay.IconStatusCount(Display.TMiniDisplayIconType.EMiniDisplayIconVolume) - 1)/2);
StephaneLenclud@114: }
StephaneLenclud@114: else
StephaneLenclud@114: {
StephaneLenclud@114: //Full brightness
StephaneLenclud@114: iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconVolume, i, iDisplay.IconStatusCount(Display.TMiniDisplayIconType.EMiniDisplayIconVolume) - 1);
StephaneLenclud@114: }
StephaneLenclud@112: }
StephaneLenclud@112: else
StephaneLenclud@112: {
StephaneLenclud@112: iDisplay.SetIconStatus(Display.TMiniDisplayIconType.EMiniDisplayIconVolume, i, 0);
StephaneLenclud@112: }
StephaneLenclud@112: }
StephaneLenclud@112: }
StephaneLenclud@113:
StephaneLenclud@116: //Take care our our mute icon
StephaneLenclud@116: iDisplay.SetIconOnOff(Display.TMiniDisplayIconType.EMiniDisplayIconMute, 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@104: comboBoxDisplayType.Items.Add(Display.TypeName((Display.TMiniDisplayType)i));
StephaneLenclud@106: }
StephaneLenclud@104: }
StephaneLenclud@104:
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:
sl@95: ///
sl@94: /// Access icons from embedded resources.
sl@94: ///
sl@94: ///
sl@94: ///
sl@94: public static Icon GetIcon(string name)
sl@94: {
sl@94: name = "SharpDisplayManager.Resources." + name;
sl@94:
sl@94: string[] names =
sl@94: Assembly.GetExecutingAssembly().GetManifestResourceNames();
sl@94: for (int i = 0; i < names.Length; i++)
sl@94: {
sl@94: if (names[i].Replace('\\', '.') == name)
sl@94: {
sl@94: using (Stream stream = Assembly.GetExecutingAssembly().
sl@94: GetManifestResourceStream(names[i]))
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: ///
sl@65: void SetCurrentClient(string aSessionId)
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:
sl@65: //Set current client ID.
sl@65: iCurrentClientSessionId = aSessionId;
sl@65: //Fetch and set current client data.
sl@65: iCurrentClientData = iClients[aSessionId];
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
sl@99: foreach (Control ctrl in tableLayoutPanel.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
sl@68: foreach (Control ctrl in tableLayoutPanel.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: {
sl@0: System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
sl@0: tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
sl@14: //Bitmap bmpToSave = new Bitmap(bmp);
sl@14: bmp.Save("D:\\capture.png");
sl@14:
sl@60: ((MarqueeLabel)tableLayoutPanel.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: {
sl@51: case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
sl@51: toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
sl@51: //Issue next request then
sl@51: iDisplay.RequestPowerSupplyStatus();
sl@51: break;
sl@51:
sl@12: case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
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:
sl@12: case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
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
sl@68: foreach (Control ctrl in tableLayoutPanel.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@122: iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
StephaneLenclud@122: }
StephaneLenclud@122: tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.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@104: if (!iDisplay.Open((Display.TMiniDisplayType)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;
sl@54: tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@60:
sl@60: //Set the proper font to each of our labels
sl@60: foreach (MarqueeLabel ctrl in tableLayoutPanel.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@126: labelStartFileName.Text = Properties.Settings.Default.StartFileName;
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@103: //We have a display connection
StephaneLenclud@103: //Reflect that in our UI
StephaneLenclud@103:
StephaneLenclud@103: tableLayoutPanel.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@115: checkBoxShowVolumeLabel.Enabled = iDisplay.IconCount(Display.TMiniDisplayIconType.EMiniDisplayIconVolumeLabel)>0;
StephaneLenclud@115:
StephaneLenclud@115: if (cds.ShowVolumeLabel)
StephaneLenclud@115: {
StephaneLenclud@115: iDisplay.SetIconOn(Display.TMiniDisplayIconType.EMiniDisplayIconVolumeLabel);
StephaneLenclud@115: }
StephaneLenclud@115: else
StephaneLenclud@115: {
StephaneLenclud@115: iDisplay.SetIconOff(Display.TMiniDisplayIconType.EMiniDisplayIconVolumeLabel);
StephaneLenclud@115: }
sl@7: }
sl@7: else
sl@7: {
StephaneLenclud@103: //Display is connection not available
StephaneLenclud@103: //Reflect that in our UI
StephaneLenclud@115: checkBoxShowVolumeLabel.Enabled = false;
StephaneLenclud@103: tableLayoutPanel.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
sl@13: tableLayoutPanel.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:
sl@94: 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: {
sl@14: // Do some stuff
sl@14: //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14: iCreateBitmap = true;
sl@14: }
sl@14: }
sl@14:
sl@17: private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
sl@17: {
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);
sl@30: Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.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: {
sl@97: tableLayoutPanel.Controls.Clear();
sl@97: tableLayoutPanel.RowStyles.Clear();
sl@97: tableLayoutPanel.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:
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: {
sl@52: LastTickTime = DateTime.Now; //Reset timer to prevent jump
sl@27: timer.Enabled = !timer.Enabled;
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:
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: {
sl@21:
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:
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);
sl@30: Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
sl@32: }
sl@32:
sl@97: 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: {
sl@62: client.Layout = aLayout;
sl@65: UpdateTableLayoutPanel(client);
sl@62: //
sl@62: UpdateClientTreeViewNode(client);
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:
sl@75: ///
sl@79: ///
sl@75: ///
sl@75: ///
sl@75: ///
sl@75: private void SetClientField(string aSessionId, DataField aField)
sl@79: {
sl@75: SetCurrentClient(aSessionId);
sl@75: ClientData client = iClients[aSessionId];
sl@75: if (client != null)
sl@75: {
sl@76: bool somethingChanged = false;
sl@76:
sl@75: //Make sure all our fields are in place
sl@75: while (client.Fields.Count < (aField.Index + 1))
sl@30: {
sl@75: //Add a text field with proper index
sl@75: client.Fields.Add(new DataField(client.Fields.Count));
sl@76: somethingChanged = true;
sl@75: }
sl@75:
sl@75: if (client.Fields[aField.Index].IsSameLayout(aField))
sl@75: {
sl@75: //Same layout just update our field
sl@75: client.Fields[aField.Index] = aField;
sl@75: //
sl@75: if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
sl@79: {
sl@75: //Text field control already in place, just change the text
sl@72: MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
sl@76: somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
sl@72: label.Text = aField.Text;
sl@72: label.TextAlign = aField.Alignment;
sl@68: }
sl@75: else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
sl@75: {
sl@76: somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
sl@75: //Bitmap field control already in place just change the bitmap
sl@75: PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
sl@75: pictureBox.Image = aField.Bitmap;
sl@75: }
sl@68: else
sl@68: {
sl@76: somethingChanged = true;
sl@75: //The requested control in our layout it not of the correct type
sl@68: //Wrong control type, re-create them all
sl@68: UpdateTableLayoutPanel(iCurrentClientData);
sl@68: }
sl@30: }
sl@75: else
sl@75: {
sl@76: somethingChanged = true;
sl@75: //Different layout, need to rebuild it
sl@75: client.Fields[aField.Index] = aField;
sl@75: UpdateTableLayoutPanel(iCurrentClientData);
sl@75: }
sl@75:
sl@75: //
sl@76: if (somethingChanged)
sl@76: {
sl@76: UpdateClientTreeViewNode(client);
sl@76: }
sl@30: }
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: {
sl@75: //Put each our text fields in a label control
sl@75: foreach (DataField field in aFields)
sl@30: {
sl@75: SetClientField(aSessionId, field);
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:
sl@33: ///
sl@36: ///
sl@33: ///
sl@33: ///
sl@33: private void UpdateClientTreeViewNode(ClientData aClient)
sl@33: {
sl@33: if (aClient == null)
sl@33: {
sl@33: return;
sl@33: }
sl@33:
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
sl@33: TreeNode[] nodes = treeViewClients.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
sl@33: treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
sl@33: node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
sl@33: }
sl@33:
sl@33: if (node != null)
sl@33: {
sl@33: //Change its name
sl@33: if (aClient.Name != "")
sl@33: {
sl@33: //We have a name, us 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:
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: {
sl@75: if (!field.IsBitmap)
sl@67: {
sl@72: DataField textField = (DataField)field;
sl@70: textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
sl@67: }
sl@67: else
sl@67: {
sl@72: textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
sl@70: }
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: {
sl@60: foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
sl@60: {
sl@60: rowStyle.SizeType = SizeType.Percent;
sl@60: rowStyle.Height = 100 / tableLayoutPanel.RowCount;
sl@60: }
sl@60: }
sl@60:
sl@63: ///
sl@63: /// Update our display table layout.
sl@63: ///
sl@63: ///
sl@65: private void UpdateTableLayoutPanel(ClientData aClient)
sl@63: {
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: int fieldCount = 0;
sl@70:
sl@63: tableLayoutPanel.Controls.Clear();
sl@63: tableLayoutPanel.RowStyles.Clear();
sl@63: tableLayoutPanel.ColumnStyles.Clear();
sl@63: tableLayoutPanel.RowCount = 0;
sl@63: tableLayoutPanel.ColumnCount = 0;
sl@63:
sl@65: while (tableLayoutPanel.RowCount < layout.Rows.Count)
sl@63: {
sl@63: tableLayoutPanel.RowCount++;
sl@63: }
sl@63:
sl@65: while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
sl@63: {
sl@63: tableLayoutPanel.ColumnCount++;
sl@63: }
sl@63:
sl@63: for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
sl@63: {
sl@63: //Create our column styles
sl@65: this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
sl@63:
sl@63: for (int j = 0; j < tableLayoutPanel.RowCount; j++)
sl@63: {
sl@63: if (i == 0)
sl@63: {
sl@63: //Create our row styles
sl@65: this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
sl@63: }
sl@63:
sl@70: //Check if we already have a control
sl@70: Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
sl@70: if (existingControl!=null)
sl@70: {
sl@70: //We already have a control in that cell as a results of row/col spanning
sl@70: //Move on to next cell then
sl@70: continue;
sl@70: }
sl@70:
sl@70: fieldCount++;
sl@70:
sl@69: //Check if a client field already exists for that cell
sl@69: if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
sl@65: {
sl@69: //No client field specified, create a text field by default
sl@72: aClient.Fields.Add(new DataField(aClient.Fields.Count));
sl@65: }
sl@68:
sl@69: //Create a control corresponding to the field specified for that cell
sl@70: DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
sl@70: Control control = CreateControlForDataField(field);
sl@70:
sl@69: //Add newly created control to our table layout at the specified row and column
sl@63: tableLayoutPanel.Controls.Add(control, i, j);
sl@70: //Make sure we specify row and column span for that new control
sl@70: tableLayoutPanel.SetRowSpan(control,field.RowSpan);
sl@70: tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
sl@63: }
sl@63: }
sl@63:
sl@70: //
sl@70: while (aClient.Fields.Count > fieldCount)
sl@70: {
sl@70: //We have too much fields for this layout
sl@70: //Just discard them until we get there
sl@70: aClient.Fields.RemoveAt(aClient.Fields.Count-1);
sl@70: }
sl@70:
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;
sl@75: if (!aField.IsBitmap)
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);
sl@68: label.Name = "marqueeLabel" + aField.Index;
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@106: label.TextAlign = aField.Alignment;
sl@68: label.UseCompatibleTextRendering = true;
sl@72: label.Text = aField.Text;
sl@68: //
sl@68: control = label;
sl@68: }
sl@72: else
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
sl@72: picture.Image = aField.Bitmap;
sl@68: //
sl@68: control = picture;
sl@68: }
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@110: foreach (MarqueeLabel ctrl in tableLayoutPanel.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: {
sl@90: // Display a message that the app 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@99:
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: }
sl@0: }
sl@34:
sl@34: ///
sl@34: /// A UI thread copy of a client relevant data.
sl@34: /// Keeping this copy in the UI thread helps us deal with threading issues.
sl@34: ///
sl@34: public class ClientData
sl@34: {
sl@55: public ClientData(string aSessionId, ICallback aCallback)
sl@34: {
sl@34: SessionId = aSessionId;
sl@34: Name = "";
sl@67: Fields = new List();
sl@62: Layout = new TableLayout(1, 2); //Default to one column and two rows
sl@34: Callback = aCallback;
sl@34: }
sl@34:
sl@34: public string SessionId { get; set; }
sl@34: public string Name { get; set; }
sl@67: public List Fields { get; set; }
sl@62: public TableLayout Layout { get; set; }
sl@55: public ICallback Callback { get; set; }
sl@34: }
sl@0: }