Ground work for supporting generic field and bitmap ones.
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 //Now check font height and show a warning if needed.
164 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
165 if (label.Font.Height > label.Height)
167 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
168 labelWarning.Visible = true;
172 labelWarning.Visible = false;
177 private void buttonCapture_Click(object sender, EventArgs e)
179 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
180 tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
181 //Bitmap bmpToSave = new Bitmap(bmp);
182 bmp.Save("D:\\capture.png");
184 ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
187 string outputFileName = "d:\\capture.png";
188 using (MemoryStream memory = new MemoryStream())
190 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
192 bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
193 byte[] bytes = memory.ToArray();
194 fs.Write(bytes, 0, bytes.Length);
201 private void CheckForRequestResults()
203 if (iDisplay.IsRequestPending())
205 switch (iDisplay.AttemptRequestCompletion())
207 case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
208 toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
209 //Issue next request then
210 iDisplay.RequestPowerSupplyStatus();
213 case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
214 if (iDisplay.PowerSupplyStatus())
216 toolStripStatusLabelPower.Text = "ON";
220 toolStripStatusLabelPower.Text = "OFF";
222 //Issue next request then
223 iDisplay.RequestDeviceId();
226 case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
227 toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
228 //No more request to issue
234 public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
236 if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
243 public static uint ColorUntouched(int aX, int aY, uint aPixel)
248 public static uint ColorInversed(int aX, int aY, uint aPixel)
253 public static uint ColorChessboard(int aX, int aY, uint aPixel)
255 if ((aX % 2 == 0) && (aY % 2 == 0))
259 else if ((aX % 2 != 0) && (aY % 2 != 0))
267 public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
269 return aBmp.Width - aX - 1;
272 public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
274 return iBmp.Height - aY - 1;
277 public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
282 public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
288 /// Select proper pixel delegates according to our current settings.
290 private void SetupPixelDelegates()
292 //Select our pixel processing routine
293 if (cds.InverseColors)
295 //iColorFx = ColorChessboard;
296 iColorFx = ColorInversed;
300 iColorFx = ColorWhiteIsOn;
303 //Select proper coordinate translation functions
304 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
305 if (cds.ReverseScreen)
307 iScreenX = ScreenReversedX;
308 iScreenY = ScreenReversedY;
318 //This is our timer tick responsible to perform our render
319 private void timer_Tick(object sender, EventArgs e)
321 //Update our animations
322 DateTime NewTickTime = DateTime.Now;
324 //Update animation for all our marquees
325 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
327 ctrl.UpdateAnimation(LastTickTime, NewTickTime);
332 if (iDisplay.IsOpen())
334 CheckForRequestResults();
339 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
341 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
342 //iBmp.Save("D:\\capture.png");
344 //Send it to our display
345 for (int i = 0; i < iBmp.Width; i++)
347 for (int j = 0; j < iBmp.Height; j++)
351 //Get our processed pixel coordinates
352 int x = iScreenX(iBmp, i);
353 int y = iScreenY(iBmp, j);
355 uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
356 //Apply color effects
357 color = iColorFx(x,y,color);
359 iDisplay.SetPixel(x, y, color);
364 iDisplay.SwapBuffers();
368 //Compute instant FPS
369 toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
371 LastTickTime = NewTickTime;
375 private void OpenDisplayConnection()
377 CloseDisplayConnection();
379 if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
382 iDisplay.RequestFirmwareRevision();
387 toolStripStatusLabelConnect.Text = "Connection error";
391 private void CloseDisplayConnection()
397 private void buttonOpen_Click(object sender, EventArgs e)
399 OpenDisplayConnection();
402 private void buttonClose_Click(object sender, EventArgs e)
404 CloseDisplayConnection();
407 private void buttonClear_Click(object sender, EventArgs e)
410 iDisplay.SwapBuffers();
413 private void buttonFill_Click(object sender, EventArgs e)
416 iDisplay.SwapBuffers();
419 private void trackBarBrightness_Scroll(object sender, EventArgs e)
421 cds.Brightness = trackBarBrightness.Value;
422 Properties.Settings.Default.Save();
423 iDisplay.SetBrightness(trackBarBrightness.Value);
429 /// CDS stands for Current Display Settings
431 private DisplaySettings cds
435 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
436 if (settings == null)
438 settings = new DisplaysSettings();
440 Properties.Settings.Default.DisplaysSettings = settings;
443 //Make sure all our settings have been created
444 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
446 settings.Displays.Add(new DisplaySettings());
449 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
450 return displaySettings;
455 /// Check if the given font has a fixed character pitch.
457 /// <param name="ft"></param>
458 /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
459 public float IsFixedWidth(Font ft)
461 Graphics g = CreateGraphics();
462 char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
463 float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
465 bool fixedWidth = true;
467 foreach (char c in charSizes)
468 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
479 private void UpdateStatus()
481 //Synchronize UI with settings
483 checkBoxShowBorders.Checked = cds.ShowBorders;
484 tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
486 //Set the proper font to each of our labels
487 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
489 ctrl.Font = cds.Font;
493 checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
494 checkBoxReverseScreen.Checked = cds.ReverseScreen;
495 checkBoxInverseColors.Checked = cds.InverseColors;
496 comboBoxDisplayType.SelectedIndex = cds.DisplayType;
497 timer.Interval = cds.TimerInterval;
498 maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
500 SetupPixelDelegates();
502 if (iDisplay.IsOpen())
504 //Only setup brightness if display is open
505 trackBarBrightness.Minimum = iDisplay.MinBrightness();
506 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
507 trackBarBrightness.Value = cds.Brightness;
508 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
509 trackBarBrightness.SmallChange = 1;
510 iDisplay.SetBrightness(cds.Brightness);
512 buttonFill.Enabled = true;
513 buttonClear.Enabled = true;
514 buttonOpen.Enabled = false;
515 buttonClose.Enabled = true;
516 trackBarBrightness.Enabled = true;
517 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
518 //+ " - " + iDisplay.SerialNumber();
520 if (iDisplay.SupportPowerOnOff())
522 buttonPowerOn.Enabled = true;
523 buttonPowerOff.Enabled = true;
527 buttonPowerOn.Enabled = false;
528 buttonPowerOff.Enabled = false;
531 if (iDisplay.SupportClock())
533 buttonShowClock.Enabled = true;
534 buttonHideClock.Enabled = true;
538 buttonShowClock.Enabled = false;
539 buttonHideClock.Enabled = false;
544 buttonFill.Enabled = false;
545 buttonClear.Enabled = false;
546 buttonOpen.Enabled = true;
547 buttonClose.Enabled = false;
548 trackBarBrightness.Enabled = false;
549 buttonPowerOn.Enabled = false;
550 buttonPowerOff.Enabled = false;
551 buttonShowClock.Enabled = false;
552 buttonHideClock.Enabled = false;
553 toolStripStatusLabelConnect.Text = "Disconnected";
554 toolStripStatusLabelPower.Text = "N/A";
560 private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
562 //Save our show borders setting
563 tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
564 cds.ShowBorders = checkBoxShowBorders.Checked;
565 Properties.Settings.Default.Save();
569 private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
571 //Save our connect on startup setting
572 Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
573 Properties.Settings.Default.Save();
576 private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
578 //Save our reverse screen setting
579 cds.ReverseScreen = checkBoxReverseScreen.Checked;
580 Properties.Settings.Default.Save();
581 SetupPixelDelegates();
584 private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
586 //Save our inverse colors setting
587 cds.InverseColors = checkBoxInverseColors.Checked;
588 Properties.Settings.Default.Save();
589 SetupPixelDelegates();
592 private void MainForm_Resize(object sender, EventArgs e)
594 if (WindowState == FormWindowState.Minimized)
597 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
598 iCreateBitmap = true;
602 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
608 public void StartServer()
610 iServiceHost = new ServiceHost
613 new Uri[] { new Uri("net.tcp://localhost:8001/") }
616 iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
620 public void StopServer()
622 if (iClients.Count > 0 && !iClosing)
626 BroadcastCloseEvent();
630 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
632 iClosing = false; //We make sure we force close if asked twice
637 //We removed that as it often lags for some reason
638 //iServiceHost.Close();
642 public void BroadcastCloseEvent()
644 Trace.TraceInformation("BroadcastCloseEvent - start");
646 var inactiveClients = new List<string>();
647 foreach (var client in iClients)
649 //if (client.Key != eventData.ClientName)
653 Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
654 client.Value.Callback.OnCloseOrder(/*eventData*/);
658 inactiveClients.Add(client.Key);
663 if (inactiveClients.Count > 0)
665 foreach (var client in inactiveClients)
667 iClients.Remove(client);
668 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
673 private void buttonStartClient_Click(object sender, EventArgs e)
675 Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
676 clientThread.Start();
680 private void buttonSuspend_Click(object sender, EventArgs e)
682 LastTickTime = DateTime.Now; //Reset timer to prevent jump
683 timer.Enabled = !timer.Enabled;
686 buttonSuspend.Text = "Run";
690 buttonSuspend.Text = "Pause";
694 private void buttonCloseClients_Click(object sender, EventArgs e)
696 BroadcastCloseEvent();
699 private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
708 /// <param name="aSessionId"></param>
709 /// <param name="aCallback"></param>
710 public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
712 if (this.InvokeRequired)
714 //Not in the proper thread, invoke ourselves
715 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
716 this.Invoke(d, new object[] { aSessionId, aCallback });
720 //We are in the proper thread
721 //Add this session to our collection of clients
722 ClientData newClient = new ClientData(aSessionId, aCallback);
723 Program.iMainForm.iClients.Add(aSessionId, newClient);
724 //Add this session to our UI
725 UpdateClientTreeViewNode(newClient);
732 /// <param name="aSessionId"></param>
733 public void RemoveClientThreadSafe(string aSessionId)
735 if (this.InvokeRequired)
737 //Not in the proper thread, invoke ourselves
738 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
739 this.Invoke(d, new object[] { aSessionId });
743 //We are in the proper thread
744 //Remove this session from both client collection and UI tree view
745 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
747 Program.iMainForm.iClients.Remove(aSessionId);
748 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
751 if (iClosing && iClients.Count == 0)
753 //We were closing our form
754 //All clients are now closed
755 //Just resume our close operation
765 /// <param name="aSessionId"></param>
766 /// <param name="aTextField"></param>
767 public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
769 if (this.InvokeRequired)
771 //Not in the proper thread, invoke ourselves
772 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
773 this.Invoke(d, new object[] { aSessionId, aLayout });
777 ClientData client = iClients[aSessionId];
780 client.Layout = aLayout;
781 UpdateTableLayoutPanel(client);
783 UpdateClientTreeViewNode(client);
791 /// <param name="aSessionId"></param>
792 /// <param name="aTextField"></param>
793 public void SetClientTextThreadSafe(string aSessionId, TextField aTextField)
795 if (this.InvokeRequired)
797 //Not in the proper thread, invoke ourselves
798 SetTextDelegate d = new SetTextDelegate(SetClientTextThreadSafe);
799 this.Invoke(d, new object[] { aSessionId, aTextField });
803 SetCurrentClient(aSessionId);
804 ClientData client = iClients[aSessionId];
807 //Make sure all our texts are in place
808 while (client.Fields.Count < (aTextField.Index + 1))
810 //Add a text field with proper index
811 client.Fields.Add(new TextField(client.Fields.Count));
813 client.Fields[aTextField.Index] = aTextField;
815 //We are in the proper thread
816 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aTextField.Index];
817 label.Text = aTextField.Text;
818 label.TextAlign = aTextField.Alignment;
820 UpdateClientTreeViewNode(client);
828 /// <param name="aTexts"></param>
829 public void SetClientTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<TextField> aTextFields)
831 if (this.InvokeRequired)
833 //Not in the proper thread, invoke ourselves
834 SetTextsDelegate d = new SetTextsDelegate(SetClientTextsThreadSafe);
835 this.Invoke(d, new object[] { aSessionId, aTextFields });
839 SetCurrentClient(aSessionId);
840 //We are in the proper thread
841 ClientData client = iClients[aSessionId];
844 //Populate our client with the given text fields
846 foreach (TextField textField in aTextFields)
848 if (client.Fields.Count < (j + 1))
850 client.Fields.Add(textField);
854 client.Fields[j] = textField;
858 //Put each our text fields in a label control
859 for (int i = 0; i < aTextFields.Count; i++)
861 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aTextFields[i].Index];
862 label.Text = aTextFields[i].Text;
863 label.TextAlign = aTextFields[i].Alignment;
867 UpdateClientTreeViewNode(client);
875 /// <param name="aSessionId"></param>
876 /// <param name="aTextField"></param>
877 public void SetClientBitmapThreadSafe(string aSessionId, BitmapField aBitmapField)
879 if (this.InvokeRequired)
881 //Not in the proper thread, invoke ourselves
882 SetBitmapDelegate d = new SetBitmapDelegate(SetClientBitmapThreadSafe);
883 this.Invoke(d, new object[] { aSessionId, aBitmapField });
887 SetCurrentClient(aSessionId);
888 ClientData client = iClients[aSessionId];
891 //Make sure all our texts are in place
892 while (client.Fields.Count < (aBitmapField.Index + 1))
894 //Add a text field with proper index
895 client.Fields.Add(new TextField(client.Fields.Count));
898 client.Fields[aBitmapField.Index] = aBitmapField;
900 //We are in the proper thread
901 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aBitmapField.Index];
902 label.Text = "Bitmap";
904 UpdateClientTreeViewNode(client);
914 /// <param name="aSessionId"></param>
915 /// <param name="aName"></param>
916 public void SetClientNameThreadSafe(string aSessionId, string aName)
918 if (this.InvokeRequired)
920 //Not in the proper thread, invoke ourselves
921 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
922 this.Invoke(d, new object[] { aSessionId, aName });
926 //We are in the proper thread
928 ClientData client = iClients[aSessionId];
933 //Update our tree-view
934 UpdateClientTreeViewNode(client);
942 /// <param name="aClient"></param>
943 private void UpdateClientTreeViewNode(ClientData aClient)
950 TreeNode node = null;
951 //Check that our client node already exists
952 //Get our client root node using its key which is our session ID
953 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
956 //We already have a node for that client
958 //Clear children as we are going to recreate them below
963 //Client node does not exists create a new one
964 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
965 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
971 if (aClient.Name != "")
973 //We have a name, us it as text for our root node
974 node.Text = aClient.Name;
975 //Add a child with SessionId
976 node.Nodes.Add(new TreeNode(aClient.SessionId));
980 //No name, use session ID instead
981 node.Text = aClient.SessionId;
984 if (aClient.Fields.Count > 0)
986 //Create root node for our texts
987 TreeNode textsRoot = new TreeNode("Text");
988 node.Nodes.Add(textsRoot);
989 //For each text add a new entry
990 foreach (DataField field in aClient.Fields)
992 if (field is TextField)
994 TextField textField = (TextField)field;
995 textsRoot.Nodes.Add(new TreeNode(textField.Text));
997 else if (field is BitmapField)
999 textsRoot.Nodes.Add(new TreeNode("[Bitmap Field]"));
1003 textsRoot.Nodes.Add(new TreeNode("[Unknown Field Type]"));
1012 private void buttonAddRow_Click(object sender, EventArgs e)
1014 if (tableLayoutPanel.RowCount < 6)
1016 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
1020 private void buttonRemoveRow_Click(object sender, EventArgs e)
1022 if (tableLayoutPanel.RowCount > 1)
1024 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
1027 UpdateTableLayoutRowStyles();
1030 private void buttonAddColumn_Click(object sender, EventArgs e)
1032 if (tableLayoutPanel.ColumnCount < 8)
1034 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
1038 private void buttonRemoveColumn_Click(object sender, EventArgs e)
1040 if (tableLayoutPanel.ColumnCount > 1)
1042 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
1048 /// Update our table layout row styles to make sure each rows have similar height
1050 private void UpdateTableLayoutRowStyles()
1052 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1054 rowStyle.SizeType = SizeType.Percent;
1055 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1060 /// Empty and recreate our table layout with the given number of columns and rows.
1061 /// Sizes of rows and columns are uniform.
1063 /// <param name="aColumn"></param>
1064 /// <param name="aRow"></param>
1065 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1067 tableLayoutPanel.Controls.Clear();
1068 tableLayoutPanel.RowStyles.Clear();
1069 tableLayoutPanel.ColumnStyles.Clear();
1070 tableLayoutPanel.RowCount = 0;
1071 tableLayoutPanel.ColumnCount = 0;
1073 while (tableLayoutPanel.RowCount < aRow)
1075 tableLayoutPanel.RowCount++;
1078 while (tableLayoutPanel.ColumnCount < aColumn)
1080 tableLayoutPanel.ColumnCount++;
1083 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1085 //Create our column styles
1086 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1088 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1092 //Create our row styles
1093 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1096 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1097 control.AutoEllipsis = true;
1098 control.AutoSize = true;
1099 control.BackColor = System.Drawing.Color.Transparent;
1100 control.Dock = System.Windows.Forms.DockStyle.Fill;
1101 control.Location = new System.Drawing.Point(1, 1);
1102 control.Margin = new System.Windows.Forms.Padding(0);
1103 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1104 control.OwnTimer = false;
1105 control.PixelsPerSecond = 64;
1106 control.Separator = "|";
1107 //control.Size = new System.Drawing.Size(254, 30);
1108 //control.TabIndex = 2;
1109 control.Font = cds.Font;
1110 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1111 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1112 control.UseCompatibleTextRendering = true;
1114 tableLayoutPanel.Controls.Add(control, i, j);
1123 /// Update our display table layout.
1125 /// <param name="aLayout"></param>
1126 private void UpdateTableLayoutPanel(ClientData aClient)
1128 TableLayout layout = aClient.Layout;
1130 tableLayoutPanel.Controls.Clear();
1131 tableLayoutPanel.RowStyles.Clear();
1132 tableLayoutPanel.ColumnStyles.Clear();
1133 tableLayoutPanel.RowCount = 0;
1134 tableLayoutPanel.ColumnCount = 0;
1136 while (tableLayoutPanel.RowCount < layout.Rows.Count)
1138 tableLayoutPanel.RowCount++;
1141 while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
1143 tableLayoutPanel.ColumnCount++;
1146 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1148 //Create our column styles
1149 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
1151 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1155 //Create our row styles
1156 this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
1159 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1160 control.AutoEllipsis = true;
1161 control.AutoSize = true;
1162 control.BackColor = System.Drawing.Color.Transparent;
1163 control.Dock = System.Windows.Forms.DockStyle.Fill;
1164 control.Location = new System.Drawing.Point(1, 1);
1165 control.Margin = new System.Windows.Forms.Padding(0);
1166 control.Name = "marqueeLabelCol" + layout.Columns.Count + "Row" + layout.Rows.Count;
1167 control.OwnTimer = false;
1168 control.PixelsPerSecond = 64;
1169 control.Separator = "|";
1170 //control.Size = new System.Drawing.Size(254, 30);
1171 //control.TabIndex = 2;
1172 control.Font = cds.Font;
1174 //If we already have a text for that field
1175 if (aClient.Fields.Count > tableLayoutPanel.Controls.Count)
1177 DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
1178 if (field is TextField)
1180 TextField textField = (TextField)field;
1181 control.Text = textField.Text;
1185 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1186 control.UseCompatibleTextRendering = true;
1188 tableLayoutPanel.Controls.Add(control, i, j);
1196 private void buttonAlignLeft_Click(object sender, EventArgs e)
1198 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1200 ctrl.TextAlign = ContentAlignment.MiddleLeft;
1204 private void buttonAlignCenter_Click(object sender, EventArgs e)
1206 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1208 ctrl.TextAlign = ContentAlignment.MiddleCenter;
1212 private void buttonAlignRight_Click(object sender, EventArgs e)
1214 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1216 ctrl.TextAlign = ContentAlignment.MiddleRight;
1220 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1222 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1223 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1224 Properties.Settings.Default.Save();
1225 if (iDisplay.IsOpen())
1227 OpenDisplayConnection();
1236 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1238 if (maskedTextBoxTimerInterval.Text != "")
1240 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1244 timer.Interval = interval;
1245 cds.TimerInterval = timer.Interval;
1246 Properties.Settings.Default.Save();
1251 private void buttonPowerOn_Click(object sender, EventArgs e)
1256 private void buttonPowerOff_Click(object sender, EventArgs e)
1258 iDisplay.PowerOff();
1261 private void buttonShowClock_Click(object sender, EventArgs e)
1263 iDisplay.ShowClock();
1266 private void buttonHideClock_Click(object sender, EventArgs e)
1268 iDisplay.HideClock();
1273 /// A UI thread copy of a client relevant data.
1274 /// Keeping this copy in the UI thread helps us deal with threading issues.
1276 public class ClientData
1278 public ClientData(string aSessionId, ICallback aCallback)
1280 SessionId = aSessionId;
1282 Fields = new List<DataField>();
1283 Layout = new TableLayout(1, 2); //Default to one column and two rows
1284 Callback = aCallback;
1287 public string SessionId { get; set; }
1288 public string Name { get; set; }
1289 public List<DataField> Fields { get; set; }
1290 public TableLayout Layout { get; set; }
1291 public ICallback Callback { get; set; }