sl@0: 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@25: // sl@25: using SharpDisplayClient; sl@55: using SharpDisplay; sl@0: sl@0: namespace SharpDisplayManager sl@0: { sl@0: public partial class MainForm : Form 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@21: /// sl@21: /// Our collection of clients sl@21: /// sl@33: public Dictionary iClients; sl@29: public bool iClosing; sl@2: sl@0: public MainForm() sl@0: { sl@2: LastTickTime = DateTime.Now; sl@3: iDisplay = new Display(); sl@33: iClients = new Dictionary(); sl@2: sl@0: InitializeComponent(); sl@7: UpdateStatus(); 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@57: // sl@57: //this.tableLayoutPanel.CellPaint += new TableLayoutCellPaintEventHandler(tableLayoutPanel_CellPaint); sl@0: } sl@0: sl@13: private void MainForm_Load(object sender, EventArgs e) sl@13: { sl@17: StartServer(); sl@17: sl@13: if (Properties.Settings.Default.DisplayConnectOnStartup) sl@13: { sl@46: OpenDisplayConnection(); sl@13: } sl@13: } sl@13: sl@57: //Testing that stuff sl@57: private void tableLayoutPanel_CellPaint(object sender, TableLayoutCellPaintEventArgs e) sl@57: { sl@57: var panel = sender as TableLayoutPanel; sl@57: //e.Graphics.SmoothingMode = SmoothingMode.HighQuality; sl@57: var rectangle = e.CellBounds; sl@57: using (var pen = new Pen(Color.Black, 1)) sl@57: { sl@57: pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Center; sl@57: pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; sl@57: sl@57: if (e.Row == (panel.RowCount - 1)) sl@57: { sl@57: rectangle.Height -= 1; sl@57: } sl@57: sl@57: if (e.Column == (panel.ColumnCount - 1)) sl@57: { sl@57: rectangle.Width -= 1; sl@57: } sl@57: sl@57: e.Graphics.DrawRectangle(pen, rectangle); sl@57: } sl@57: } sl@57: sl@13: 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@11: fontDialog.Font = marqueeLabelTop.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@0: sl@4: //MsgBox.Show("MessageBox MsgBox", "MsgBox caption"); sl@0: sl@0: //MessageBox.Show("Ok"); sl@4: marqueeLabelTop.Font = fontDialog.Font; sl@4: marqueeLabelBottom.Font = fontDialog.Font; 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@54: //Now check font height and show a warning if needed. sl@37: if (marqueeLabelBottom.Font.Height > marqueeLabelBottom.Height) sl@37: { sl@37: labelWarning.Text = "WARNING: Selected font is too height by " + (marqueeLabelBottom.Font.Height - marqueeLabelBottom.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@17: marqueeLabelTop.Text = "Sweet"; 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@16: sl@57: public delegate uint ColorProcessingDelegate(uint aPixel); sl@57: sl@57: public static uint ColorUntouched(uint aPixel) sl@57: { sl@57: return aPixel; sl@57: } sl@57: sl@57: public static uint ColorInversed(uint aPixel) sl@57: { sl@57: return ~aPixel; sl@57: } sl@57: sl@16: public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt); 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@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: sl@2: marqueeLabelTop.UpdateAnimation(LastTickTime, NewTickTime); sl@2: marqueeLabelBottom.UpdateAnimation(LastTickTime, NewTickTime); sl@2: sl@4: //Update our display sl@4: if (iDisplay.IsOpen()) sl@4: { sl@12: CheckForRequestResults(); sl@12: sl@22: //Draw to bitmap sl@14: if (iCreateBitmap) sl@14: { sl@14: iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb); sl@14: } sl@14: tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle); sl@14: //iBmp.Save("D:\\capture.png"); sl@16: sl@57: sl@57: //Select our pixel processing routine sl@57: ColorProcessingDelegate colorFx; sl@57: sl@57: if (cds.InverseColors) sl@57: { sl@57: colorFx = ColorInversed; sl@57: } sl@57: else sl@57: { sl@57: colorFx = ColorUntouched; sl@57: } sl@57: sl@16: //Select proper coordinate translation functions sl@16: //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels sl@16: CoordinateTranslationDelegate screenX; sl@16: CoordinateTranslationDelegate screenY; sl@16: sl@48: if (cds.ReverseScreen) sl@16: { sl@16: screenX = ScreenReversedX; sl@16: screenY = ScreenReversedY; sl@16: } sl@16: else sl@16: { sl@16: screenX = ScreenX; sl@16: screenY = ScreenY; sl@16: } sl@22: sl@7: //Send it to our display sl@14: for (int i = 0; i < iBmp.Width; i++) sl@4: { sl@14: for (int j = 0; j < iBmp.Height; j++) sl@4: { sl@4: unchecked sl@4: { sl@14: uint color = (uint)iBmp.GetPixel(i, j).ToArgb(); sl@57: //Apply color effects sl@57: color = colorFx(color); sl@14: //For some reason when the app is minimized in the task bar only the alpha of our color is set. sl@14: //Thus that strange test for rendering to work both when the app is in the task bar and when it isn't. sl@57: //iDisplay.SetPixel(screenX(iBmp, i), screenY(iBmp, j), Convert.ToInt32(!(color != 0xFF000000))); sl@57: iDisplay.SetPixel(screenX(iBmp, i), screenY(iBmp, j), color); sl@4: } sl@4: } sl@4: } sl@4: sl@4: iDisplay.SwapBuffers(); sl@4: 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: sl@46: private void OpenDisplayConnection() sl@3: { sl@46: CloseDisplayConnection(); sl@46: sl@48: if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType)) sl@3: { sl@7: UpdateStatus(); sl@51: iDisplay.RequestFirmwareRevision(); sl@3: } sl@7: else sl@7: { sl@7: UpdateStatus(); sl@7: toolStripStatusLabelConnect.Text = "Connection error"; sl@7: } sl@46: } sl@7: sl@46: private void CloseDisplayConnection() sl@46: { sl@46: iDisplay.Close(); sl@46: UpdateStatus(); 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@50: DisplaysSettings settings = Properties.Settings.Default.DisplaySettings; sl@51: if (settings == null) sl@51: { sl@51: settings = new DisplaysSettings(); sl@51: settings.Init(); sl@51: Properties.Settings.Default.DisplaySettings = 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: sl@7: private void UpdateStatus() sl@7: { sl@48: //Synchronize UI with settings sl@48: //Load settings sl@54: sl@54: checkBoxShowBorders.Checked = cds.ShowBorders; sl@54: tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None); sl@48: marqueeLabelTop.Font = cds.Font; sl@48: marqueeLabelBottom.Font = cds.Font; sl@54: CheckFontHeight(); sl@48: checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup; sl@48: checkBoxReverseScreen.Checked = cds.ReverseScreen; sl@57: checkBoxInverseColors.Checked = cds.InverseColors; sl@48: comboBoxDisplayType.SelectedIndex = cds.DisplayType; sl@48: timer.Interval = cds.TimerInterval; sl@48: maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString(); sl@48: sl@48: sl@7: if (iDisplay.IsOpen()) sl@7: { sl@48: //Only setup brightness if display is open sl@48: trackBarBrightness.Minimum = iDisplay.MinBrightness(); sl@48: trackBarBrightness.Maximum = iDisplay.MaxBrightness(); sl@48: trackBarBrightness.Value = cds.Brightness; sl@48: trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5); sl@48: trackBarBrightness.SmallChange = 1; sl@48: iDisplay.SetBrightness(cds.Brightness); 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: } sl@7: } sl@7: else sl@7: { 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: } sl@7: } sl@9: sl@13: 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@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@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@57: } sl@57: 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: { 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@21: } sl@21: sl@25: private void buttonStartClient_Click(object sender, EventArgs e) sl@25: { sl@25: Thread clientThread = new Thread(SharpDisplayClient.Program.Main); sl@25: clientThread.Start(); sl@36: BringToFront(); 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: //Delegates are used for our thread safe method sl@55: public delegate void AddClientDelegate(string aSessionId, ICallback aCallback); sl@30: public delegate void RemoveClientDelegate(string aSessionId); sl@43: public delegate void SetTextDelegate(string SessionId, TextField aTextField); sl@43: public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList aTextFields); sl@32: public delegate void SetClientNameDelegate(string aSessionId, string aName); 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@32: if (iClosing && iClients.Count == 0) sl@32: { sl@32: //We were closing our form sl@32: //All clients are now closed sl@32: //Just resume our close operation sl@32: iClosing = false; sl@32: Close(); sl@32: } sl@30: } sl@30: } sl@30: sl@30: /// sl@36: /// sl@30: /// sl@30: /// sl@30: /// sl@43: public void SetTextThreadSafe(string aSessionId, TextField aTextField) sl@30: { sl@33: if (this.InvokeRequired) sl@30: { sl@30: //Not in the proper thread, invoke ourselves sl@30: SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe); sl@43: this.Invoke(d, new object[] { aSessionId, aTextField }); sl@30: } sl@30: else sl@30: { sl@34: ClientData client = iClients[aSessionId]; sl@34: if (client != null) sl@30: { sl@34: //Make sure all our texts are in place sl@43: while (client.Texts.Count < (aTextField.Index + 1)) sl@34: { sl@43: //Add a text field with proper index sl@43: client.Texts.Add(new TextField(client.Texts.Count)); sl@34: } sl@43: client.Texts[aTextField.Index] = aTextField; sl@34: sl@34: //We are in the proper thread sl@34: //Only support two lines for now sl@43: if (aTextField.Index == 0) sl@34: { sl@43: marqueeLabelTop.Text = aTextField.Text; sl@43: marqueeLabelTop.TextAlign = aTextField.Alignment; sl@34: } sl@43: else if (aTextField.Index == 1) sl@34: { sl@43: marqueeLabelBottom.Text = aTextField.Text; sl@43: marqueeLabelBottom.TextAlign = aTextField.Alignment; sl@34: } sl@34: sl@34: sl@34: UpdateClientTreeViewNode(client); sl@30: } sl@30: } sl@30: } sl@30: sl@30: /// sl@36: /// sl@30: /// sl@30: /// sl@43: public void SetTextsThreadSafe(string aSessionId, System.Collections.Generic.IList aTextFields) sl@30: { sl@33: if (this.InvokeRequired) sl@30: { sl@30: //Not in the proper thread, invoke ourselves sl@30: SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe); sl@43: this.Invoke(d, new object[] { aSessionId, aTextFields }); sl@30: } sl@30: else sl@30: { sl@43: //We are in the proper thread sl@34: ClientData client = iClients[aSessionId]; sl@34: if (client != null) sl@30: { sl@43: //Populate our client with the given text fields sl@34: int j = 0; sl@43: foreach (TextField textField in aTextFields) sl@30: { sl@34: if (client.Texts.Count < (j + 1)) sl@34: { sl@43: client.Texts.Add(textField); sl@34: } sl@34: else sl@34: { sl@43: client.Texts[j] = textField; sl@34: } sl@34: j++; sl@54: } sl@34: //Only support two lines for now sl@43: for (int i = 0; i < aTextFields.Count; i++) sl@30: { sl@43: if (aTextFields[i].Index == 0) sl@34: { sl@43: marqueeLabelTop.Text = aTextFields[i].Text; sl@43: marqueeLabelTop.TextAlign = aTextFields[i].Alignment; sl@34: } sl@43: else if (aTextFields[i].Index == 1) sl@34: { sl@43: marqueeLabelBottom.Text = aTextFields[i].Text; sl@43: marqueeLabelBottom.TextAlign = aTextFields[i].Alignment; sl@34: } sl@30: } sl@34: sl@34: sl@34: UpdateClientTreeViewNode(client); sl@30: } sl@30: } sl@32: } sl@30: sl@32: sl@32: /// sl@36: /// sl@32: /// sl@32: /// 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@33: if (aClient.Texts.Count > 0) sl@33: { sl@33: //Create root node for our texts sl@33: TreeNode textsRoot = new TreeNode("Text"); sl@33: node.Nodes.Add(textsRoot); sl@33: //For each text add a new entry sl@43: foreach (TextField field in aClient.Texts) sl@33: { sl@43: textsRoot.Nodes.Add(new TreeNode(field.Text)); sl@33: } sl@32: } sl@34: sl@34: node.ExpandAll(); sl@32: } sl@30: } sl@17: sl@38: private void buttonAddRow_Click(object sender, EventArgs e) sl@38: { sl@38: if (tableLayoutPanel.RowCount < 6) sl@38: { sl@38: tableLayoutPanel.RowCount++; sl@38: CheckFontHeight(); sl@38: } sl@38: } sl@38: sl@38: private void buttonRemoveRow_Click(object sender, EventArgs e) sl@38: { sl@38: if (tableLayoutPanel.RowCount > 1) sl@38: { sl@38: tableLayoutPanel.RowCount--; sl@38: CheckFontHeight(); sl@38: } sl@38: } sl@38: sl@38: private void buttonAddColumn_Click(object sender, EventArgs e) sl@38: { sl@38: if (tableLayoutPanel.ColumnCount < 8) sl@38: { sl@38: tableLayoutPanel.ColumnCount++; sl@38: //CheckFontHeight(); sl@38: } sl@38: } sl@38: sl@38: private void buttonRemoveColumn_Click(object sender, EventArgs e) sl@38: { sl@38: if (tableLayoutPanel.ColumnCount > 1) sl@38: { sl@38: tableLayoutPanel.ColumnCount--; sl@38: //CheckFontHeight(); sl@38: } sl@38: } sl@38: sl@41: private void buttonAlignLeft_Click(object sender, EventArgs e) sl@41: { sl@41: marqueeLabelTop.TextAlign = ContentAlignment.MiddleLeft; sl@41: marqueeLabelBottom.TextAlign = ContentAlignment.MiddleLeft; sl@41: } sl@41: sl@41: private void buttonAlignCenter_Click(object sender, EventArgs e) sl@41: { sl@41: marqueeLabelTop.TextAlign = ContentAlignment.MiddleCenter; sl@41: marqueeLabelBottom.TextAlign = ContentAlignment.MiddleCenter; sl@41: } sl@41: sl@41: private void buttonAlignRight_Click(object sender, EventArgs e) sl@41: { sl@41: marqueeLabelTop.TextAlign = ContentAlignment.MiddleRight; sl@41: marqueeLabelBottom.TextAlign = ContentAlignment.MiddleRight; sl@41: } sl@36: sl@46: private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e) sl@46: { sl@48: Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex; sl@48: cds.DisplayType = comboBoxDisplayType.SelectedIndex; sl@46: Properties.Settings.Default.Save(); 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: 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@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: { sl@53: iDisplay.ShowClock(); sl@53: } sl@53: sl@53: private void buttonHideClock_Click(object sender, EventArgs e) sl@53: { sl@53: iDisplay.HideClock(); sl@53: } sl@53: 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@43: Texts = new List(); sl@34: Callback = aCallback; sl@34: } sl@34: sl@34: public string SessionId { get; set; } sl@34: public string Name { get; set; } sl@43: public List Texts { get; set; } sl@55: public ICallback Callback { get; set; } sl@34: } sl@0: }