Cleaning up control creation code.
2 using System.Collections.Generic;
3 using System.ComponentModel;
8 using System.Threading.Tasks;
9 using System.Windows.Forms;
11 using CodeProject.Dialog;
12 using System.Drawing.Imaging;
13 using System.ServiceModel;
14 using System.Threading;
15 using System.Diagnostics;
17 using SharpDisplayClient;
20 namespace SharpDisplayManager
23 public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
24 public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
25 //Delegates are used for our thread safe method
26 public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
27 public delegate void RemoveClientDelegate(string aSessionId);
28 public delegate void SetTextDelegate(string SessionId, TextField aTextField);
29 public delegate void SetBitmapDelegate(string SessionId, BitmapField aTextField);
30 public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
31 public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList<TextField> aTextFields);
32 public delegate void SetClientNameDelegate(string aSessionId, string aName);
36 /// Our Display manager main form
38 public partial class MainForm : Form
41 DateTime LastTickTime;
43 System.Drawing.Bitmap iBmp;
44 bool iCreateBitmap; //Workaround render to bitmap issues when minimized
45 ServiceHost iServiceHost;
46 // Our collection of clients sorted by session id.
47 public Dictionary<string, ClientData> iClients;
48 // The name of the client which informations are currently displayed.
49 public string iCurrentClientSessionId;
50 ClientData iCurrentClientData;
53 //Function pointer for pixel color filtering
54 ColorProcessingDelegate iColorFx;
55 //Function pointer for pixel X coordinate intercept
56 CoordinateTranslationDelegate iScreenX;
57 //Function pointer for pixel Y coordinate intercept
58 CoordinateTranslationDelegate iScreenY;
62 iCurrentClientSessionId = "";
63 iCurrentClientData = null;
64 LastTickTime = DateTime.Now;
65 iDisplay = new Display();
66 iClients = new Dictionary<string, ClientData>();
68 InitializeComponent();
70 //We have a bug when drawing minimized and reusing our bitmap
71 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
72 iCreateBitmap = false;
75 private void MainForm_Load(object sender, EventArgs e)
79 if (Properties.Settings.Default.DisplayConnectOnStartup)
81 OpenDisplayConnection();
86 /// Set our current client.
87 /// This will take care of applying our client layout and set data fields.
89 /// <param name="aSessionId"></param>
90 void SetCurrentClient(string aSessionId)
92 if (aSessionId == iCurrentClientSessionId)
94 //Given client is already the current one.
95 //Don't bother changing anything then.
99 //Set current client ID.
100 iCurrentClientSessionId = aSessionId;
101 //Fetch and set current client data.
102 iCurrentClientData = iClients[aSessionId];
103 //Apply layout and set data fields.
104 UpdateTableLayoutPanel(iCurrentClientData);
107 private void buttonFont_Click(object sender, EventArgs e)
109 //fontDialog.ShowColor = true;
110 //fontDialog.ShowApply = true;
111 fontDialog.ShowEffects = true;
112 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
113 fontDialog.Font = label.Font;
115 fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
117 //fontDialog.ShowHelp = true;
119 //fontDlg.MaxSize = 40;
120 //fontDlg.MinSize = 22;
122 //fontDialog.Parent = this;
123 //fontDialog.StartPosition = FormStartPosition.CenterParent;
125 //DlgBox.ShowDialog(fontDialog);
127 //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
128 if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
131 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
133 //MessageBox.Show("Ok");
134 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
136 ctrl.Font = fontDialog.Font;
138 cds.Font = fontDialog.Font;
139 Properties.Settings.Default.Save();
148 void CheckFontHeight()
150 //Show font height and width
151 labelFontHeight.Text = "Font height: " + cds.Font.Height;
152 float charWidth = IsFixedWidth(cds.Font);
153 if (charWidth == 0.0f)
155 labelFontWidth.Visible = false;
159 labelFontWidth.Visible = true;
160 labelFontWidth.Text = "Font width: " + charWidth;
163 MarqueeLabel label = null;
164 //Get the first label control we can find
165 foreach (Control ctrl in tableLayoutPanel.Controls)
167 if (ctrl is MarqueeLabel)
169 label = (MarqueeLabel)ctrl;
174 //Now check font height and show a warning if needed.
175 if (label != null && label.Font.Height > label.Height)
177 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
178 labelWarning.Visible = true;
182 labelWarning.Visible = false;
187 private void buttonCapture_Click(object sender, EventArgs e)
189 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
190 tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
191 //Bitmap bmpToSave = new Bitmap(bmp);
192 bmp.Save("D:\\capture.png");
194 ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
197 string outputFileName = "d:\\capture.png";
198 using (MemoryStream memory = new MemoryStream())
200 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
202 bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
203 byte[] bytes = memory.ToArray();
204 fs.Write(bytes, 0, bytes.Length);
211 private void CheckForRequestResults()
213 if (iDisplay.IsRequestPending())
215 switch (iDisplay.AttemptRequestCompletion())
217 case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
218 toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
219 //Issue next request then
220 iDisplay.RequestPowerSupplyStatus();
223 case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
224 if (iDisplay.PowerSupplyStatus())
226 toolStripStatusLabelPower.Text = "ON";
230 toolStripStatusLabelPower.Text = "OFF";
232 //Issue next request then
233 iDisplay.RequestDeviceId();
236 case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
237 toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
238 //No more request to issue
244 public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
246 if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
253 public static uint ColorUntouched(int aX, int aY, uint aPixel)
258 public static uint ColorInversed(int aX, int aY, uint aPixel)
263 public static uint ColorChessboard(int aX, int aY, uint aPixel)
265 if ((aX % 2 == 0) && (aY % 2 == 0))
269 else if ((aX % 2 != 0) && (aY % 2 != 0))
277 public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
279 return aBmp.Width - aX - 1;
282 public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
284 return iBmp.Height - aY - 1;
287 public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
292 public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
298 /// Select proper pixel delegates according to our current settings.
300 private void SetupPixelDelegates()
302 //Select our pixel processing routine
303 if (cds.InverseColors)
305 //iColorFx = ColorChessboard;
306 iColorFx = ColorInversed;
310 iColorFx = ColorWhiteIsOn;
313 //Select proper coordinate translation functions
314 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
315 if (cds.ReverseScreen)
317 iScreenX = ScreenReversedX;
318 iScreenY = ScreenReversedY;
328 //This is our timer tick responsible to perform our render
329 private void timer_Tick(object sender, EventArgs e)
331 //Update our animations
332 DateTime NewTickTime = DateTime.Now;
334 //Update animation for all our marquees
335 foreach (Control ctrl in tableLayoutPanel.Controls)
337 if (ctrl is MarqueeLabel)
339 ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
345 if (iDisplay.IsOpen())
347 CheckForRequestResults();
352 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
354 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
355 //iBmp.Save("D:\\capture.png");
357 //Send it to our display
358 for (int i = 0; i < iBmp.Width; i++)
360 for (int j = 0; j < iBmp.Height; j++)
364 //Get our processed pixel coordinates
365 int x = iScreenX(iBmp, i);
366 int y = iScreenY(iBmp, j);
368 uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
369 //Apply color effects
370 color = iColorFx(x,y,color);
372 iDisplay.SetPixel(x, y, color);
377 iDisplay.SwapBuffers();
381 //Compute instant FPS
382 toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
384 LastTickTime = NewTickTime;
388 private void OpenDisplayConnection()
390 CloseDisplayConnection();
392 if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
395 iDisplay.RequestFirmwareRevision();
400 toolStripStatusLabelConnect.Text = "Connection error";
404 private void CloseDisplayConnection()
410 private void buttonOpen_Click(object sender, EventArgs e)
412 OpenDisplayConnection();
415 private void buttonClose_Click(object sender, EventArgs e)
417 CloseDisplayConnection();
420 private void buttonClear_Click(object sender, EventArgs e)
423 iDisplay.SwapBuffers();
426 private void buttonFill_Click(object sender, EventArgs e)
429 iDisplay.SwapBuffers();
432 private void trackBarBrightness_Scroll(object sender, EventArgs e)
434 cds.Brightness = trackBarBrightness.Value;
435 Properties.Settings.Default.Save();
436 iDisplay.SetBrightness(trackBarBrightness.Value);
442 /// CDS stands for Current Display Settings
444 private DisplaySettings cds
448 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
449 if (settings == null)
451 settings = new DisplaysSettings();
453 Properties.Settings.Default.DisplaysSettings = settings;
456 //Make sure all our settings have been created
457 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
459 settings.Displays.Add(new DisplaySettings());
462 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
463 return displaySettings;
468 /// Check if the given font has a fixed character pitch.
470 /// <param name="ft"></param>
471 /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
472 public float IsFixedWidth(Font ft)
474 Graphics g = CreateGraphics();
475 char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
476 float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
478 bool fixedWidth = true;
480 foreach (char c in charSizes)
481 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
492 private void UpdateStatus()
494 //Synchronize UI with settings
496 checkBoxShowBorders.Checked = cds.ShowBorders;
497 tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
499 //Set the proper font to each of our labels
500 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
502 ctrl.Font = cds.Font;
506 checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
507 checkBoxReverseScreen.Checked = cds.ReverseScreen;
508 checkBoxInverseColors.Checked = cds.InverseColors;
509 comboBoxDisplayType.SelectedIndex = cds.DisplayType;
510 timer.Interval = cds.TimerInterval;
511 maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
513 SetupPixelDelegates();
515 if (iDisplay.IsOpen())
517 //Only setup brightness if display is open
518 trackBarBrightness.Minimum = iDisplay.MinBrightness();
519 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
520 trackBarBrightness.Value = cds.Brightness;
521 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
522 trackBarBrightness.SmallChange = 1;
523 iDisplay.SetBrightness(cds.Brightness);
525 buttonFill.Enabled = true;
526 buttonClear.Enabled = true;
527 buttonOpen.Enabled = false;
528 buttonClose.Enabled = true;
529 trackBarBrightness.Enabled = true;
530 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
531 //+ " - " + iDisplay.SerialNumber();
533 if (iDisplay.SupportPowerOnOff())
535 buttonPowerOn.Enabled = true;
536 buttonPowerOff.Enabled = true;
540 buttonPowerOn.Enabled = false;
541 buttonPowerOff.Enabled = false;
544 if (iDisplay.SupportClock())
546 buttonShowClock.Enabled = true;
547 buttonHideClock.Enabled = true;
551 buttonShowClock.Enabled = false;
552 buttonHideClock.Enabled = false;
557 buttonFill.Enabled = false;
558 buttonClear.Enabled = false;
559 buttonOpen.Enabled = true;
560 buttonClose.Enabled = false;
561 trackBarBrightness.Enabled = false;
562 buttonPowerOn.Enabled = false;
563 buttonPowerOff.Enabled = false;
564 buttonShowClock.Enabled = false;
565 buttonHideClock.Enabled = false;
566 toolStripStatusLabelConnect.Text = "Disconnected";
567 toolStripStatusLabelPower.Text = "N/A";
573 private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
575 //Save our show borders setting
576 tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
577 cds.ShowBorders = checkBoxShowBorders.Checked;
578 Properties.Settings.Default.Save();
582 private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
584 //Save our connect on startup setting
585 Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
586 Properties.Settings.Default.Save();
589 private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
591 //Save our reverse screen setting
592 cds.ReverseScreen = checkBoxReverseScreen.Checked;
593 Properties.Settings.Default.Save();
594 SetupPixelDelegates();
597 private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
599 //Save our inverse colors setting
600 cds.InverseColors = checkBoxInverseColors.Checked;
601 Properties.Settings.Default.Save();
602 SetupPixelDelegates();
605 private void MainForm_Resize(object sender, EventArgs e)
607 if (WindowState == FormWindowState.Minimized)
610 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
611 iCreateBitmap = true;
615 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
621 public void StartServer()
623 iServiceHost = new ServiceHost
626 new Uri[] { new Uri("net.tcp://localhost:8001/") }
629 iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
633 public void StopServer()
635 if (iClients.Count > 0 && !iClosing)
639 BroadcastCloseEvent();
643 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
645 iClosing = false; //We make sure we force close if asked twice
650 //We removed that as it often lags for some reason
651 //iServiceHost.Close();
655 public void BroadcastCloseEvent()
657 Trace.TraceInformation("BroadcastCloseEvent - start");
659 var inactiveClients = new List<string>();
660 foreach (var client in iClients)
662 //if (client.Key != eventData.ClientName)
666 Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
667 client.Value.Callback.OnCloseOrder(/*eventData*/);
671 inactiveClients.Add(client.Key);
676 if (inactiveClients.Count > 0)
678 foreach (var client in inactiveClients)
680 iClients.Remove(client);
681 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
686 private void buttonStartClient_Click(object sender, EventArgs e)
688 Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
689 clientThread.Start();
693 private void buttonSuspend_Click(object sender, EventArgs e)
695 LastTickTime = DateTime.Now; //Reset timer to prevent jump
696 timer.Enabled = !timer.Enabled;
699 buttonSuspend.Text = "Run";
703 buttonSuspend.Text = "Pause";
707 private void buttonCloseClients_Click(object sender, EventArgs e)
709 BroadcastCloseEvent();
712 private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
721 /// <param name="aSessionId"></param>
722 /// <param name="aCallback"></param>
723 public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
725 if (this.InvokeRequired)
727 //Not in the proper thread, invoke ourselves
728 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
729 this.Invoke(d, new object[] { aSessionId, aCallback });
733 //We are in the proper thread
734 //Add this session to our collection of clients
735 ClientData newClient = new ClientData(aSessionId, aCallback);
736 Program.iMainForm.iClients.Add(aSessionId, newClient);
737 //Add this session to our UI
738 UpdateClientTreeViewNode(newClient);
745 /// <param name="aSessionId"></param>
746 public void RemoveClientThreadSafe(string aSessionId)
748 if (this.InvokeRequired)
750 //Not in the proper thread, invoke ourselves
751 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
752 this.Invoke(d, new object[] { aSessionId });
756 //We are in the proper thread
757 //Remove this session from both client collection and UI tree view
758 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
760 Program.iMainForm.iClients.Remove(aSessionId);
761 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
764 if (iClosing && iClients.Count == 0)
766 //We were closing our form
767 //All clients are now closed
768 //Just resume our close operation
778 /// <param name="aSessionId"></param>
779 /// <param name="aTextField"></param>
780 public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
782 if (this.InvokeRequired)
784 //Not in the proper thread, invoke ourselves
785 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
786 this.Invoke(d, new object[] { aSessionId, aLayout });
790 ClientData client = iClients[aSessionId];
793 client.Layout = aLayout;
794 UpdateTableLayoutPanel(client);
796 UpdateClientTreeViewNode(client);
804 /// <param name="aSessionId"></param>
805 /// <param name="aTextField"></param>
806 public void SetClientTextThreadSafe(string aSessionId, TextField aTextField)
808 if (this.InvokeRequired)
810 //Not in the proper thread, invoke ourselves
811 SetTextDelegate d = new SetTextDelegate(SetClientTextThreadSafe);
812 this.Invoke(d, new object[] { aSessionId, aTextField });
816 SetCurrentClient(aSessionId);
817 ClientData client = iClients[aSessionId];
820 //Make sure all our texts are in place
821 while (client.Fields.Count < (aTextField.Index + 1))
823 //Add a text field with proper index
824 client.Fields.Add(new TextField(client.Fields.Count));
826 client.Fields[aTextField.Index] = aTextField;
828 //We are in the proper thread
829 if (tableLayoutPanel.Controls[aTextField.Index] is MarqueeLabel)
831 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aTextField.Index];
832 label.Text = aTextField.Text;
833 label.TextAlign = aTextField.Alignment;
837 //Wrong control type, re-create them all
838 UpdateTableLayoutPanel(iCurrentClientData);
841 UpdateClientTreeViewNode(client);
849 /// <param name="aTexts"></param>
850 public void SetClientTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<TextField> aTextFields)
852 if (this.InvokeRequired)
854 //Not in the proper thread, invoke ourselves
855 SetTextsDelegate d = new SetTextsDelegate(SetClientTextsThreadSafe);
856 this.Invoke(d, new object[] { aSessionId, aTextFields });
860 SetCurrentClient(aSessionId);
861 //We are in the proper thread
862 ClientData client = iClients[aSessionId];
865 //Populate our client with the given text fields
867 foreach (TextField textField in aTextFields)
869 if (client.Fields.Count < (j + 1))
871 client.Fields.Add(textField);
875 client.Fields[j] = textField;
879 //Put each our text fields in a label control
880 foreach (TextField field in aTextFields)
882 if (tableLayoutPanel.Controls[field.Index] is MarqueeLabel)
884 //Proper control type just update the text
885 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[field.Index];
886 label.Text = field.Text;
887 label.TextAlign = field.Alignment;
891 //Wrong control for the given field
892 //Update our layout thus re-creating our controls
893 UpdateTableLayoutPanel(iCurrentClientData);
894 break; //No need to keep on looping layout update will take care of everything
899 UpdateClientTreeViewNode(client);
907 /// <param name="aSessionId"></param>
908 /// <param name="aTextField"></param>
909 public void SetClientBitmapThreadSafe(string aSessionId, BitmapField aBitmapField)
911 if (this.InvokeRequired)
913 //Not in the proper thread, invoke ourselves
914 SetBitmapDelegate d = new SetBitmapDelegate(SetClientBitmapThreadSafe);
915 this.Invoke(d, new object[] { aSessionId, aBitmapField });
919 SetCurrentClient(aSessionId);
920 ClientData client = iClients[aSessionId];
923 //Make sure all our texts are in place
924 while (client.Fields.Count < (aBitmapField.Index + 1))
926 //Add a text field with proper index
927 client.Fields.Add(new TextField(client.Fields.Count));
930 client.Fields[aBitmapField.Index] = aBitmapField;
932 //We are in the proper thread
933 if (tableLayoutPanel.Controls[aBitmapField.Index] is PictureBox)
935 PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aBitmapField.Index];
936 pictureBox.Image = aBitmapField.Bitmap;
940 //Wrong control type re-create them all
941 UpdateTableLayoutPanel(iCurrentClientData);
944 UpdateClientTreeViewNode(client);
954 /// <param name="aSessionId"></param>
955 /// <param name="aName"></param>
956 public void SetClientNameThreadSafe(string aSessionId, string aName)
958 if (this.InvokeRequired)
960 //Not in the proper thread, invoke ourselves
961 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
962 this.Invoke(d, new object[] { aSessionId, aName });
966 //We are in the proper thread
968 ClientData client = iClients[aSessionId];
973 //Update our tree-view
974 UpdateClientTreeViewNode(client);
982 /// <param name="aClient"></param>
983 private void UpdateClientTreeViewNode(ClientData aClient)
990 TreeNode node = null;
991 //Check that our client node already exists
992 //Get our client root node using its key which is our session ID
993 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
996 //We already have a node for that client
998 //Clear children as we are going to recreate them below
1003 //Client node does not exists create a new one
1004 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
1005 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
1011 if (aClient.Name != "")
1013 //We have a name, us it as text for our root node
1014 node.Text = aClient.Name;
1015 //Add a child with SessionId
1016 node.Nodes.Add(new TreeNode(aClient.SessionId));
1020 //No name, use session ID instead
1021 node.Text = aClient.SessionId;
1024 if (aClient.Fields.Count > 0)
1026 //Create root node for our texts
1027 TreeNode textsRoot = new TreeNode("Text");
1028 node.Nodes.Add(textsRoot);
1029 //For each text add a new entry
1030 foreach (DataField field in aClient.Fields)
1032 if (field is TextField)
1034 TextField textField = (TextField)field;
1035 textsRoot.Nodes.Add(new TreeNode(textField.Text));
1037 else if (field is BitmapField)
1039 textsRoot.Nodes.Add(new TreeNode("[Bitmap Field]"));
1043 textsRoot.Nodes.Add(new TreeNode("[Unknown Field Type]"));
1052 private void buttonAddRow_Click(object sender, EventArgs e)
1054 if (tableLayoutPanel.RowCount < 6)
1056 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
1060 private void buttonRemoveRow_Click(object sender, EventArgs e)
1062 if (tableLayoutPanel.RowCount > 1)
1064 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
1067 UpdateTableLayoutRowStyles();
1070 private void buttonAddColumn_Click(object sender, EventArgs e)
1072 if (tableLayoutPanel.ColumnCount < 8)
1074 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
1078 private void buttonRemoveColumn_Click(object sender, EventArgs e)
1080 if (tableLayoutPanel.ColumnCount > 1)
1082 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
1088 /// Update our table layout row styles to make sure each rows have similar height
1090 private void UpdateTableLayoutRowStyles()
1092 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1094 rowStyle.SizeType = SizeType.Percent;
1095 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1100 /// Empty and recreate our table layout with the given number of columns and rows.
1101 /// Sizes of rows and columns are uniform.
1103 /// <param name="aColumn"></param>
1104 /// <param name="aRow"></param>
1105 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1107 tableLayoutPanel.Controls.Clear();
1108 tableLayoutPanel.RowStyles.Clear();
1109 tableLayoutPanel.ColumnStyles.Clear();
1110 tableLayoutPanel.RowCount = 0;
1111 tableLayoutPanel.ColumnCount = 0;
1113 while (tableLayoutPanel.RowCount < aRow)
1115 tableLayoutPanel.RowCount++;
1118 while (tableLayoutPanel.ColumnCount < aColumn)
1120 tableLayoutPanel.ColumnCount++;
1123 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1125 //Create our column styles
1126 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1128 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1132 //Create our row styles
1133 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1136 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1137 control.AutoEllipsis = true;
1138 control.AutoSize = true;
1139 control.BackColor = System.Drawing.Color.Transparent;
1140 control.Dock = System.Windows.Forms.DockStyle.Fill;
1141 control.Location = new System.Drawing.Point(1, 1);
1142 control.Margin = new System.Windows.Forms.Padding(0);
1143 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1144 control.OwnTimer = false;
1145 control.PixelsPerSecond = 64;
1146 control.Separator = "|";
1147 //control.Size = new System.Drawing.Size(254, 30);
1148 //control.TabIndex = 2;
1149 control.Font = cds.Font;
1150 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1151 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1152 control.UseCompatibleTextRendering = true;
1154 tableLayoutPanel.Controls.Add(control, i, j);
1163 /// Update our display table layout.
1165 /// <param name="aLayout"></param>
1166 private void UpdateTableLayoutPanel(ClientData aClient)
1168 TableLayout layout = aClient.Layout;
1170 tableLayoutPanel.Controls.Clear();
1171 tableLayoutPanel.RowStyles.Clear();
1172 tableLayoutPanel.ColumnStyles.Clear();
1173 tableLayoutPanel.RowCount = 0;
1174 tableLayoutPanel.ColumnCount = 0;
1176 while (tableLayoutPanel.RowCount < layout.Rows.Count)
1178 tableLayoutPanel.RowCount++;
1181 while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
1183 tableLayoutPanel.ColumnCount++;
1186 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1188 //Create our column styles
1189 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
1191 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1195 //Create our row styles
1196 this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
1199 //Check if a client field already exists for that cell
1200 if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
1202 //No client field specified, create a text field by default
1203 aClient.Fields.Add(new TextField(aClient.Fields.Count));
1206 //Create a control corresponding to the field specified for that cell
1207 Control control = CreateControlForDataField(aClient.Fields[tableLayoutPanel.Controls.Count]);
1208 //Add newly created control to our table layout at the specified row and column
1209 tableLayoutPanel.Controls.Add(control, i, j);
1219 /// <param name="aField"></param>
1220 private Control CreateControlForDataField(DataField aField)
1222 Control control=null;
1223 if (aField is TextField)
1225 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
1226 label.AutoEllipsis = true;
1227 label.AutoSize = true;
1228 label.BackColor = System.Drawing.Color.Transparent;
1229 label.Dock = System.Windows.Forms.DockStyle.Fill;
1230 label.Location = new System.Drawing.Point(1, 1);
1231 label.Margin = new System.Windows.Forms.Padding(0);
1232 label.Name = "marqueeLabel" + aField.Index;
1233 label.OwnTimer = false;
1234 label.PixelsPerSecond = 64;
1235 label.Separator = "|";
1236 //control.Size = new System.Drawing.Size(254, 30);
1237 //control.TabIndex = 2;
1238 label.Font = cds.Font;
1240 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1241 label.UseCompatibleTextRendering = true;
1242 TextField textField = (TextField)aField;
1243 label.Text = textField.Text;
1247 else if (aField is BitmapField)
1249 //Create picture box
1250 PictureBox picture = new PictureBox();
1251 picture.AutoSize = true;
1252 picture.BackColor = System.Drawing.Color.Transparent;
1253 picture.Dock = System.Windows.Forms.DockStyle.Fill;
1254 picture.Location = new System.Drawing.Point(1, 1);
1255 picture.Margin = new System.Windows.Forms.Padding(0);
1256 picture.Name = "pictureBox" + aField;
1258 BitmapField bitmapField = (BitmapField)aField;
1259 picture.Image = bitmapField.Bitmap;
1268 private void buttonAlignLeft_Click(object sender, EventArgs e)
1270 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1272 ctrl.TextAlign = ContentAlignment.MiddleLeft;
1276 private void buttonAlignCenter_Click(object sender, EventArgs e)
1278 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1280 ctrl.TextAlign = ContentAlignment.MiddleCenter;
1284 private void buttonAlignRight_Click(object sender, EventArgs e)
1286 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1288 ctrl.TextAlign = ContentAlignment.MiddleRight;
1292 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1294 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1295 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1296 Properties.Settings.Default.Save();
1297 if (iDisplay.IsOpen())
1299 OpenDisplayConnection();
1308 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1310 if (maskedTextBoxTimerInterval.Text != "")
1312 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1316 timer.Interval = interval;
1317 cds.TimerInterval = timer.Interval;
1318 Properties.Settings.Default.Save();
1323 private void buttonPowerOn_Click(object sender, EventArgs e)
1328 private void buttonPowerOff_Click(object sender, EventArgs e)
1330 iDisplay.PowerOff();
1333 private void buttonShowClock_Click(object sender, EventArgs e)
1335 iDisplay.ShowClock();
1338 private void buttonHideClock_Click(object sender, EventArgs e)
1340 iDisplay.HideClock();
1345 /// A UI thread copy of a client relevant data.
1346 /// Keeping this copy in the UI thread helps us deal with threading issues.
1348 public class ClientData
1350 public ClientData(string aSessionId, ICallback aCallback)
1352 SessionId = aSessionId;
1354 Fields = new List<DataField>();
1355 Layout = new TableLayout(1, 2); //Default to one column and two rows
1356 Callback = aCallback;
1359 public string SessionId { get; set; }
1360 public string Name { get; set; }
1361 public List<DataField> Fields { get; set; }
1362 public TableLayout Layout { get; set; }
1363 public ICallback Callback { get; set; }