Removing specific functions for setting text and bitmap.
Now having a generic functions for setting any kind of fields.
Thus bitmaps can now be set together with text fields in a single server call.
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, DataField aField);
29 public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
30 public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList<DataField> aFields);
31 public delegate void SetClientNameDelegate(string aSessionId, string aName);
35 /// Our Display manager main form
37 public partial class MainForm : Form
40 DateTime LastTickTime;
42 System.Drawing.Bitmap iBmp;
43 bool iCreateBitmap; //Workaround render to bitmap issues when minimized
44 ServiceHost iServiceHost;
45 // Our collection of clients sorted by session id.
46 public Dictionary<string, ClientData> iClients;
47 // The name of the client which informations are currently displayed.
48 public string iCurrentClientSessionId;
49 ClientData iCurrentClientData;
52 //Function pointer for pixel color filtering
53 ColorProcessingDelegate iColorFx;
54 //Function pointer for pixel X coordinate intercept
55 CoordinateTranslationDelegate iScreenX;
56 //Function pointer for pixel Y coordinate intercept
57 CoordinateTranslationDelegate iScreenY;
61 iCurrentClientSessionId = "";
62 iCurrentClientData = null;
63 LastTickTime = DateTime.Now;
64 iDisplay = new Display();
65 iClients = new Dictionary<string, ClientData>();
67 InitializeComponent();
69 //We have a bug when drawing minimized and reusing our bitmap
70 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
71 iCreateBitmap = false;
74 private void MainForm_Load(object sender, EventArgs e)
78 if (Properties.Settings.Default.DisplayConnectOnStartup)
80 OpenDisplayConnection();
85 /// Set our current client.
86 /// This will take care of applying our client layout and set data fields.
88 /// <param name="aSessionId"></param>
89 void SetCurrentClient(string aSessionId)
91 if (aSessionId == iCurrentClientSessionId)
93 //Given client is already the current one.
94 //Don't bother changing anything then.
98 //Set current client ID.
99 iCurrentClientSessionId = aSessionId;
100 //Fetch and set current client data.
101 iCurrentClientData = iClients[aSessionId];
102 //Apply layout and set data fields.
103 UpdateTableLayoutPanel(iCurrentClientData);
106 private void buttonFont_Click(object sender, EventArgs e)
108 //fontDialog.ShowColor = true;
109 //fontDialog.ShowApply = true;
110 fontDialog.ShowEffects = true;
111 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
112 fontDialog.Font = label.Font;
114 fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
116 //fontDialog.ShowHelp = true;
118 //fontDlg.MaxSize = 40;
119 //fontDlg.MinSize = 22;
121 //fontDialog.Parent = this;
122 //fontDialog.StartPosition = FormStartPosition.CenterParent;
124 //DlgBox.ShowDialog(fontDialog);
126 //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
127 if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
130 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
132 //MessageBox.Show("Ok");
133 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
135 ctrl.Font = fontDialog.Font;
137 cds.Font = fontDialog.Font;
138 Properties.Settings.Default.Save();
147 void CheckFontHeight()
149 //Show font height and width
150 labelFontHeight.Text = "Font height: " + cds.Font.Height;
151 float charWidth = IsFixedWidth(cds.Font);
152 if (charWidth == 0.0f)
154 labelFontWidth.Visible = false;
158 labelFontWidth.Visible = true;
159 labelFontWidth.Text = "Font width: " + charWidth;
162 MarqueeLabel label = null;
163 //Get the first label control we can find
164 foreach (Control ctrl in tableLayoutPanel.Controls)
166 if (ctrl is MarqueeLabel)
168 label = (MarqueeLabel)ctrl;
173 //Now check font height and show a warning if needed.
174 if (label != null && label.Font.Height > label.Height)
176 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
177 labelWarning.Visible = true;
181 labelWarning.Visible = false;
186 private void buttonCapture_Click(object sender, EventArgs e)
188 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
189 tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
190 //Bitmap bmpToSave = new Bitmap(bmp);
191 bmp.Save("D:\\capture.png");
193 ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
196 string outputFileName = "d:\\capture.png";
197 using (MemoryStream memory = new MemoryStream())
199 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
201 bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
202 byte[] bytes = memory.ToArray();
203 fs.Write(bytes, 0, bytes.Length);
210 private void CheckForRequestResults()
212 if (iDisplay.IsRequestPending())
214 switch (iDisplay.AttemptRequestCompletion())
216 case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
217 toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
218 //Issue next request then
219 iDisplay.RequestPowerSupplyStatus();
222 case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
223 if (iDisplay.PowerSupplyStatus())
225 toolStripStatusLabelPower.Text = "ON";
229 toolStripStatusLabelPower.Text = "OFF";
231 //Issue next request then
232 iDisplay.RequestDeviceId();
235 case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
236 toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
237 //No more request to issue
243 public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
245 if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
252 public static uint ColorUntouched(int aX, int aY, uint aPixel)
257 public static uint ColorInversed(int aX, int aY, uint aPixel)
262 public static uint ColorChessboard(int aX, int aY, uint aPixel)
264 if ((aX % 2 == 0) && (aY % 2 == 0))
268 else if ((aX % 2 != 0) && (aY % 2 != 0))
276 public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
278 return aBmp.Width - aX - 1;
281 public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
283 return iBmp.Height - aY - 1;
286 public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
291 public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
297 /// Select proper pixel delegates according to our current settings.
299 private void SetupPixelDelegates()
301 //Select our pixel processing routine
302 if (cds.InverseColors)
304 //iColorFx = ColorChessboard;
305 iColorFx = ColorInversed;
309 iColorFx = ColorWhiteIsOn;
312 //Select proper coordinate translation functions
313 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
314 if (cds.ReverseScreen)
316 iScreenX = ScreenReversedX;
317 iScreenY = ScreenReversedY;
327 //This is our timer tick responsible to perform our render
328 private void timer_Tick(object sender, EventArgs e)
330 //Update our animations
331 DateTime NewTickTime = DateTime.Now;
333 //Update animation for all our marquees
334 foreach (Control ctrl in tableLayoutPanel.Controls)
336 if (ctrl is MarqueeLabel)
338 ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
344 if (iDisplay.IsOpen())
346 CheckForRequestResults();
351 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
353 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
354 //iBmp.Save("D:\\capture.png");
356 //Send it to our display
357 for (int i = 0; i < iBmp.Width; i++)
359 for (int j = 0; j < iBmp.Height; j++)
363 //Get our processed pixel coordinates
364 int x = iScreenX(iBmp, i);
365 int y = iScreenY(iBmp, j);
367 uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
368 //Apply color effects
369 color = iColorFx(x,y,color);
371 iDisplay.SetPixel(x, y, color);
376 iDisplay.SwapBuffers();
380 //Compute instant FPS
381 toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
383 LastTickTime = NewTickTime;
387 private void OpenDisplayConnection()
389 CloseDisplayConnection();
391 if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
394 iDisplay.RequestFirmwareRevision();
399 toolStripStatusLabelConnect.Text = "Connection error";
403 private void CloseDisplayConnection()
409 private void buttonOpen_Click(object sender, EventArgs e)
411 OpenDisplayConnection();
414 private void buttonClose_Click(object sender, EventArgs e)
416 CloseDisplayConnection();
419 private void buttonClear_Click(object sender, EventArgs e)
422 iDisplay.SwapBuffers();
425 private void buttonFill_Click(object sender, EventArgs e)
428 iDisplay.SwapBuffers();
431 private void trackBarBrightness_Scroll(object sender, EventArgs e)
433 cds.Brightness = trackBarBrightness.Value;
434 Properties.Settings.Default.Save();
435 iDisplay.SetBrightness(trackBarBrightness.Value);
441 /// CDS stands for Current Display Settings
443 private DisplaySettings cds
447 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
448 if (settings == null)
450 settings = new DisplaysSettings();
452 Properties.Settings.Default.DisplaysSettings = settings;
455 //Make sure all our settings have been created
456 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
458 settings.Displays.Add(new DisplaySettings());
461 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
462 return displaySettings;
467 /// Check if the given font has a fixed character pitch.
469 /// <param name="ft"></param>
470 /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
471 public float IsFixedWidth(Font ft)
473 Graphics g = CreateGraphics();
474 char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
475 float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
477 bool fixedWidth = true;
479 foreach (char c in charSizes)
480 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
491 private void UpdateStatus()
493 //Synchronize UI with settings
495 checkBoxShowBorders.Checked = cds.ShowBorders;
496 tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
498 //Set the proper font to each of our labels
499 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
501 ctrl.Font = cds.Font;
505 checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
506 checkBoxReverseScreen.Checked = cds.ReverseScreen;
507 checkBoxInverseColors.Checked = cds.InverseColors;
508 comboBoxDisplayType.SelectedIndex = cds.DisplayType;
509 timer.Interval = cds.TimerInterval;
510 maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
512 SetupPixelDelegates();
514 if (iDisplay.IsOpen())
516 //Only setup brightness if display is open
517 trackBarBrightness.Minimum = iDisplay.MinBrightness();
518 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
519 trackBarBrightness.Value = cds.Brightness;
520 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
521 trackBarBrightness.SmallChange = 1;
522 iDisplay.SetBrightness(cds.Brightness);
524 buttonFill.Enabled = true;
525 buttonClear.Enabled = true;
526 buttonOpen.Enabled = false;
527 buttonClose.Enabled = true;
528 trackBarBrightness.Enabled = true;
529 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
530 //+ " - " + iDisplay.SerialNumber();
532 if (iDisplay.SupportPowerOnOff())
534 buttonPowerOn.Enabled = true;
535 buttonPowerOff.Enabled = true;
539 buttonPowerOn.Enabled = false;
540 buttonPowerOff.Enabled = false;
543 if (iDisplay.SupportClock())
545 buttonShowClock.Enabled = true;
546 buttonHideClock.Enabled = true;
550 buttonShowClock.Enabled = false;
551 buttonHideClock.Enabled = false;
556 buttonFill.Enabled = false;
557 buttonClear.Enabled = false;
558 buttonOpen.Enabled = true;
559 buttonClose.Enabled = false;
560 trackBarBrightness.Enabled = false;
561 buttonPowerOn.Enabled = false;
562 buttonPowerOff.Enabled = false;
563 buttonShowClock.Enabled = false;
564 buttonHideClock.Enabled = false;
565 toolStripStatusLabelConnect.Text = "Disconnected";
566 toolStripStatusLabelPower.Text = "N/A";
572 private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
574 //Save our show borders setting
575 tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
576 cds.ShowBorders = checkBoxShowBorders.Checked;
577 Properties.Settings.Default.Save();
581 private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
583 //Save our connect on startup setting
584 Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
585 Properties.Settings.Default.Save();
588 private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
590 //Save our reverse screen setting
591 cds.ReverseScreen = checkBoxReverseScreen.Checked;
592 Properties.Settings.Default.Save();
593 SetupPixelDelegates();
596 private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
598 //Save our inverse colors setting
599 cds.InverseColors = checkBoxInverseColors.Checked;
600 Properties.Settings.Default.Save();
601 SetupPixelDelegates();
604 private void MainForm_Resize(object sender, EventArgs e)
606 if (WindowState == FormWindowState.Minimized)
609 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
610 iCreateBitmap = true;
614 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
620 public void StartServer()
622 iServiceHost = new ServiceHost
625 new Uri[] { new Uri("net.tcp://localhost:8001/") }
628 iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
632 public void StopServer()
634 if (iClients.Count > 0 && !iClosing)
638 BroadcastCloseEvent();
642 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
644 iClosing = false; //We make sure we force close if asked twice
649 //We removed that as it often lags for some reason
650 //iServiceHost.Close();
654 public void BroadcastCloseEvent()
656 Trace.TraceInformation("BroadcastCloseEvent - start");
658 var inactiveClients = new List<string>();
659 foreach (var client in iClients)
661 //if (client.Key != eventData.ClientName)
665 Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
666 client.Value.Callback.OnCloseOrder(/*eventData*/);
670 inactiveClients.Add(client.Key);
675 if (inactiveClients.Count > 0)
677 foreach (var client in inactiveClients)
679 iClients.Remove(client);
680 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
685 private void buttonStartClient_Click(object sender, EventArgs e)
687 Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
688 clientThread.Start();
692 private void buttonSuspend_Click(object sender, EventArgs e)
694 LastTickTime = DateTime.Now; //Reset timer to prevent jump
695 timer.Enabled = !timer.Enabled;
698 buttonSuspend.Text = "Run";
702 buttonSuspend.Text = "Pause";
706 private void buttonCloseClients_Click(object sender, EventArgs e)
708 BroadcastCloseEvent();
711 private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
720 /// <param name="aSessionId"></param>
721 /// <param name="aCallback"></param>
722 public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
724 if (this.InvokeRequired)
726 //Not in the proper thread, invoke ourselves
727 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
728 this.Invoke(d, new object[] { aSessionId, aCallback });
732 //We are in the proper thread
733 //Add this session to our collection of clients
734 ClientData newClient = new ClientData(aSessionId, aCallback);
735 Program.iMainForm.iClients.Add(aSessionId, newClient);
736 //Add this session to our UI
737 UpdateClientTreeViewNode(newClient);
744 /// <param name="aSessionId"></param>
745 public void RemoveClientThreadSafe(string aSessionId)
747 if (this.InvokeRequired)
749 //Not in the proper thread, invoke ourselves
750 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
751 this.Invoke(d, new object[] { aSessionId });
755 //We are in the proper thread
756 //Remove this session from both client collection and UI tree view
757 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
759 Program.iMainForm.iClients.Remove(aSessionId);
760 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
763 if (iClosing && iClients.Count == 0)
765 //We were closing our form
766 //All clients are now closed
767 //Just resume our close operation
777 /// <param name="aSessionId"></param>
778 /// <param name="aLayout"></param>
779 public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
781 if (this.InvokeRequired)
783 //Not in the proper thread, invoke ourselves
784 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
785 this.Invoke(d, new object[] { aSessionId, aLayout });
789 ClientData client = iClients[aSessionId];
792 client.Layout = aLayout;
793 UpdateTableLayoutPanel(client);
795 UpdateClientTreeViewNode(client);
803 /// <param name="aSessionId"></param>
804 /// <param name="aField"></param>
805 public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
807 if (this.InvokeRequired)
809 //Not in the proper thread, invoke ourselves
810 SetTextDelegate d = new SetTextDelegate(SetClientFieldThreadSafe);
811 this.Invoke(d, new object[] { aSessionId, aField });
815 //We are in the proper thread
816 //Call the non-thread-safe variant
817 SetClientField(aSessionId, aField);
824 /// <param name="aSessionId"></param>
825 /// <param name="aField"></param>
826 private void SetClientField(string aSessionId, DataField aField)
828 SetCurrentClient(aSessionId);
829 ClientData client = iClients[aSessionId];
832 //Make sure all our fields are in place
833 while (client.Fields.Count < (aField.Index + 1))
835 //Add a text field with proper index
836 client.Fields.Add(new DataField(client.Fields.Count));
839 if (client.Fields[aField.Index].IsSameLayout(aField))
841 //Same layout just update our field
842 client.Fields[aField.Index] = aField;
844 if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
846 //Text field control already in place, just change the text
847 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
848 label.Text = aField.Text;
849 label.TextAlign = aField.Alignment;
851 else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
853 //Bitmap field control already in place just change the bitmap
854 PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
855 pictureBox.Image = aField.Bitmap;
859 //The requested control in our layout it not of the correct type
860 //Wrong control type, re-create them all
861 UpdateTableLayoutPanel(iCurrentClientData);
866 //Different layout, need to rebuild it
867 client.Fields[aField.Index] = aField;
868 UpdateTableLayoutPanel(iCurrentClientData);
872 UpdateClientTreeViewNode(client);
879 /// <param name="aTexts"></param>
880 public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
882 if (this.InvokeRequired)
884 //Not in the proper thread, invoke ourselves
885 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
886 this.Invoke(d, new object[] { aSessionId, aFields });
890 //Put each our text fields in a label control
891 foreach (DataField field in aFields)
893 SetClientField(aSessionId, field);
901 /// <param name="aSessionId"></param>
902 /// <param name="aName"></param>
903 public void SetClientNameThreadSafe(string aSessionId, string aName)
905 if (this.InvokeRequired)
907 //Not in the proper thread, invoke ourselves
908 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
909 this.Invoke(d, new object[] { aSessionId, aName });
913 //We are in the proper thread
915 ClientData client = iClients[aSessionId];
920 //Update our tree-view
921 UpdateClientTreeViewNode(client);
929 /// <param name="aClient"></param>
930 private void UpdateClientTreeViewNode(ClientData aClient)
937 TreeNode node = null;
938 //Check that our client node already exists
939 //Get our client root node using its key which is our session ID
940 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
943 //We already have a node for that client
945 //Clear children as we are going to recreate them below
950 //Client node does not exists create a new one
951 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
952 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
958 if (aClient.Name != "")
960 //We have a name, us it as text for our root node
961 node.Text = aClient.Name;
962 //Add a child with SessionId
963 node.Nodes.Add(new TreeNode(aClient.SessionId));
967 //No name, use session ID instead
968 node.Text = aClient.SessionId;
971 if (aClient.Fields.Count > 0)
973 //Create root node for our texts
974 TreeNode textsRoot = new TreeNode("Fields");
975 node.Nodes.Add(textsRoot);
976 //For each text add a new entry
977 foreach (DataField field in aClient.Fields)
981 DataField textField = (DataField)field;
982 textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
986 textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
995 private void buttonAddRow_Click(object sender, EventArgs e)
997 if (tableLayoutPanel.RowCount < 6)
999 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
1003 private void buttonRemoveRow_Click(object sender, EventArgs e)
1005 if (tableLayoutPanel.RowCount > 1)
1007 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
1010 UpdateTableLayoutRowStyles();
1013 private void buttonAddColumn_Click(object sender, EventArgs e)
1015 if (tableLayoutPanel.ColumnCount < 8)
1017 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
1021 private void buttonRemoveColumn_Click(object sender, EventArgs e)
1023 if (tableLayoutPanel.ColumnCount > 1)
1025 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
1031 /// Update our table layout row styles to make sure each rows have similar height
1033 private void UpdateTableLayoutRowStyles()
1035 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1037 rowStyle.SizeType = SizeType.Percent;
1038 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1044 /// Empty and recreate our table layout with the given number of columns and rows.
1045 /// Sizes of rows and columns are uniform.
1047 /// <param name="aColumn"></param>
1048 /// <param name="aRow"></param>
1049 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1051 tableLayoutPanel.Controls.Clear();
1052 tableLayoutPanel.RowStyles.Clear();
1053 tableLayoutPanel.ColumnStyles.Clear();
1054 tableLayoutPanel.RowCount = 0;
1055 tableLayoutPanel.ColumnCount = 0;
1057 while (tableLayoutPanel.RowCount < aRow)
1059 tableLayoutPanel.RowCount++;
1062 while (tableLayoutPanel.ColumnCount < aColumn)
1064 tableLayoutPanel.ColumnCount++;
1067 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1069 //Create our column styles
1070 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1072 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1076 //Create our row styles
1077 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1080 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1081 control.AutoEllipsis = true;
1082 control.AutoSize = true;
1083 control.BackColor = System.Drawing.Color.Transparent;
1084 control.Dock = System.Windows.Forms.DockStyle.Fill;
1085 control.Location = new System.Drawing.Point(1, 1);
1086 control.Margin = new System.Windows.Forms.Padding(0);
1087 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1088 control.OwnTimer = false;
1089 control.PixelsPerSecond = 64;
1090 control.Separator = "|";
1091 //control.Size = new System.Drawing.Size(254, 30);
1092 //control.TabIndex = 2;
1093 control.Font = cds.Font;
1094 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1095 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1096 control.UseCompatibleTextRendering = true;
1098 tableLayoutPanel.Controls.Add(control, i, j);
1107 /// Update our display table layout.
1109 /// <param name="aLayout"></param>
1110 private void UpdateTableLayoutPanel(ClientData aClient)
1112 TableLayout layout = aClient.Layout;
1115 tableLayoutPanel.Controls.Clear();
1116 tableLayoutPanel.RowStyles.Clear();
1117 tableLayoutPanel.ColumnStyles.Clear();
1118 tableLayoutPanel.RowCount = 0;
1119 tableLayoutPanel.ColumnCount = 0;
1121 while (tableLayoutPanel.RowCount < layout.Rows.Count)
1123 tableLayoutPanel.RowCount++;
1126 while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
1128 tableLayoutPanel.ColumnCount++;
1131 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1133 //Create our column styles
1134 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
1136 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1140 //Create our row styles
1141 this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
1144 //Check if we already have a control
1145 Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
1146 if (existingControl!=null)
1148 //We already have a control in that cell as a results of row/col spanning
1149 //Move on to next cell then
1155 //Check if a client field already exists for that cell
1156 if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
1158 //No client field specified, create a text field by default
1159 aClient.Fields.Add(new DataField(aClient.Fields.Count));
1162 //Create a control corresponding to the field specified for that cell
1163 DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
1164 Control control = CreateControlForDataField(field);
1166 //Add newly created control to our table layout at the specified row and column
1167 tableLayoutPanel.Controls.Add(control, i, j);
1168 //Make sure we specify row and column span for that new control
1169 tableLayoutPanel.SetRowSpan(control,field.RowSpan);
1170 tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
1175 while (aClient.Fields.Count > fieldCount)
1177 //We have too much fields for this layout
1178 //Just discard them until we get there
1179 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
1186 /// Check our type of data field and create corresponding control
1188 /// <param name="aField"></param>
1189 private Control CreateControlForDataField(DataField aField)
1191 Control control=null;
1192 if (!aField.IsBitmap)
1194 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
1195 label.AutoEllipsis = true;
1196 label.AutoSize = true;
1197 label.BackColor = System.Drawing.Color.Transparent;
1198 label.Dock = System.Windows.Forms.DockStyle.Fill;
1199 label.Location = new System.Drawing.Point(1, 1);
1200 label.Margin = new System.Windows.Forms.Padding(0);
1201 label.Name = "marqueeLabel" + aField.Index;
1202 label.OwnTimer = false;
1203 label.PixelsPerSecond = 64;
1204 label.Separator = "|";
1205 //control.Size = new System.Drawing.Size(254, 30);
1206 //control.TabIndex = 2;
1207 label.Font = cds.Font;
1209 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1210 label.UseCompatibleTextRendering = true;
1211 label.Text = aField.Text;
1217 //Create picture box
1218 PictureBox picture = new PictureBox();
1219 picture.AutoSize = true;
1220 picture.BackColor = System.Drawing.Color.Transparent;
1221 picture.Dock = System.Windows.Forms.DockStyle.Fill;
1222 picture.Location = new System.Drawing.Point(1, 1);
1223 picture.Margin = new System.Windows.Forms.Padding(0);
1224 picture.Name = "pictureBox" + aField;
1226 picture.Image = aField.Bitmap;
1235 private void buttonAlignLeft_Click(object sender, EventArgs e)
1237 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1239 ctrl.TextAlign = ContentAlignment.MiddleLeft;
1243 private void buttonAlignCenter_Click(object sender, EventArgs e)
1245 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1247 ctrl.TextAlign = ContentAlignment.MiddleCenter;
1251 private void buttonAlignRight_Click(object sender, EventArgs e)
1253 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1255 ctrl.TextAlign = ContentAlignment.MiddleRight;
1259 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1261 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1262 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1263 Properties.Settings.Default.Save();
1264 if (iDisplay.IsOpen())
1266 OpenDisplayConnection();
1275 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1277 if (maskedTextBoxTimerInterval.Text != "")
1279 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1283 timer.Interval = interval;
1284 cds.TimerInterval = timer.Interval;
1285 Properties.Settings.Default.Save();
1290 private void buttonPowerOn_Click(object sender, EventArgs e)
1295 private void buttonPowerOff_Click(object sender, EventArgs e)
1297 iDisplay.PowerOff();
1300 private void buttonShowClock_Click(object sender, EventArgs e)
1302 iDisplay.ShowClock();
1305 private void buttonHideClock_Click(object sender, EventArgs e)
1307 iDisplay.HideClock();
1312 /// A UI thread copy of a client relevant data.
1313 /// Keeping this copy in the UI thread helps us deal with threading issues.
1315 public class ClientData
1317 public ClientData(string aSessionId, ICallback aCallback)
1319 SessionId = aSessionId;
1321 Fields = new List<DataField>();
1322 Layout = new TableLayout(1, 2); //Default to one column and two rows
1323 Callback = aCallback;
1326 public string SessionId { get; set; }
1327 public string Name { get; set; }
1328 public List<DataField> Fields { get; set; }
1329 public TableLayout Layout { get; set; }
1330 public ICallback Callback { get; set; }