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 SetFieldDelegate(string SessionId, DataField aField);
29 public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList<DataField> aFields);
30 public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
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 SetFieldDelegate d = new SetFieldDelegate(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 bool somethingChanged = false;
834 //Make sure all our fields are in place
835 while (client.Fields.Count < (aField.Index + 1))
837 //Add a text field with proper index
838 client.Fields.Add(new DataField(client.Fields.Count));
839 somethingChanged = true;
842 if (client.Fields[aField.Index].IsSameLayout(aField))
844 //Same layout just update our field
845 client.Fields[aField.Index] = aField;
847 if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
849 //Text field control already in place, just change the text
850 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
851 somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
852 label.Text = aField.Text;
853 label.TextAlign = aField.Alignment;
855 else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
857 somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
858 //Bitmap field control already in place just change the bitmap
859 PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
860 pictureBox.Image = aField.Bitmap;
864 somethingChanged = true;
865 //The requested control in our layout it not of the correct type
866 //Wrong control type, re-create them all
867 UpdateTableLayoutPanel(iCurrentClientData);
872 somethingChanged = true;
873 //Different layout, need to rebuild it
874 client.Fields[aField.Index] = aField;
875 UpdateTableLayoutPanel(iCurrentClientData);
879 if (somethingChanged)
881 UpdateClientTreeViewNode(client);
889 /// <param name="aTexts"></param>
890 public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
892 if (this.InvokeRequired)
894 //Not in the proper thread, invoke ourselves
895 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
896 this.Invoke(d, new object[] { aSessionId, aFields });
900 //Put each our text fields in a label control
901 foreach (DataField field in aFields)
903 SetClientField(aSessionId, field);
911 /// <param name="aSessionId"></param>
912 /// <param name="aName"></param>
913 public void SetClientNameThreadSafe(string aSessionId, string aName)
915 if (this.InvokeRequired)
917 //Not in the proper thread, invoke ourselves
918 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
919 this.Invoke(d, new object[] { aSessionId, aName });
923 //We are in the proper thread
925 ClientData client = iClients[aSessionId];
930 //Update our tree-view
931 UpdateClientTreeViewNode(client);
939 /// <param name="aClient"></param>
940 private void UpdateClientTreeViewNode(ClientData aClient)
947 TreeNode node = null;
948 //Check that our client node already exists
949 //Get our client root node using its key which is our session ID
950 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
953 //We already have a node for that client
955 //Clear children as we are going to recreate them below
960 //Client node does not exists create a new one
961 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
962 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
968 if (aClient.Name != "")
970 //We have a name, us it as text for our root node
971 node.Text = aClient.Name;
972 //Add a child with SessionId
973 node.Nodes.Add(new TreeNode(aClient.SessionId));
977 //No name, use session ID instead
978 node.Text = aClient.SessionId;
981 if (aClient.Fields.Count > 0)
983 //Create root node for our texts
984 TreeNode textsRoot = new TreeNode("Fields");
985 node.Nodes.Add(textsRoot);
986 //For each text add a new entry
987 foreach (DataField field in aClient.Fields)
991 DataField textField = (DataField)field;
992 textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
996 textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
1005 private void buttonAddRow_Click(object sender, EventArgs e)
1007 if (tableLayoutPanel.RowCount < 6)
1009 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
1013 private void buttonRemoveRow_Click(object sender, EventArgs e)
1015 if (tableLayoutPanel.RowCount > 1)
1017 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
1020 UpdateTableLayoutRowStyles();
1023 private void buttonAddColumn_Click(object sender, EventArgs e)
1025 if (tableLayoutPanel.ColumnCount < 8)
1027 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
1031 private void buttonRemoveColumn_Click(object sender, EventArgs e)
1033 if (tableLayoutPanel.ColumnCount > 1)
1035 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
1041 /// Update our table layout row styles to make sure each rows have similar height
1043 private void UpdateTableLayoutRowStyles()
1045 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1047 rowStyle.SizeType = SizeType.Percent;
1048 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1054 /// Empty and recreate our table layout with the given number of columns and rows.
1055 /// Sizes of rows and columns are uniform.
1057 /// <param name="aColumn"></param>
1058 /// <param name="aRow"></param>
1059 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1061 tableLayoutPanel.Controls.Clear();
1062 tableLayoutPanel.RowStyles.Clear();
1063 tableLayoutPanel.ColumnStyles.Clear();
1064 tableLayoutPanel.RowCount = 0;
1065 tableLayoutPanel.ColumnCount = 0;
1067 while (tableLayoutPanel.RowCount < aRow)
1069 tableLayoutPanel.RowCount++;
1072 while (tableLayoutPanel.ColumnCount < aColumn)
1074 tableLayoutPanel.ColumnCount++;
1077 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1079 //Create our column styles
1080 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1082 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1086 //Create our row styles
1087 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1090 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1091 control.AutoEllipsis = true;
1092 control.AutoSize = true;
1093 control.BackColor = System.Drawing.Color.Transparent;
1094 control.Dock = System.Windows.Forms.DockStyle.Fill;
1095 control.Location = new System.Drawing.Point(1, 1);
1096 control.Margin = new System.Windows.Forms.Padding(0);
1097 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1098 control.OwnTimer = false;
1099 control.PixelsPerSecond = 64;
1100 control.Separator = "|";
1101 //control.Size = new System.Drawing.Size(254, 30);
1102 //control.TabIndex = 2;
1103 control.Font = cds.Font;
1104 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1105 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1106 control.UseCompatibleTextRendering = true;
1108 tableLayoutPanel.Controls.Add(control, i, j);
1117 /// Update our display table layout.
1119 /// <param name="aLayout"></param>
1120 private void UpdateTableLayoutPanel(ClientData aClient)
1122 TableLayout layout = aClient.Layout;
1125 tableLayoutPanel.Controls.Clear();
1126 tableLayoutPanel.RowStyles.Clear();
1127 tableLayoutPanel.ColumnStyles.Clear();
1128 tableLayoutPanel.RowCount = 0;
1129 tableLayoutPanel.ColumnCount = 0;
1131 while (tableLayoutPanel.RowCount < layout.Rows.Count)
1133 tableLayoutPanel.RowCount++;
1136 while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
1138 tableLayoutPanel.ColumnCount++;
1141 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1143 //Create our column styles
1144 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
1146 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1150 //Create our row styles
1151 this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
1154 //Check if we already have a control
1155 Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
1156 if (existingControl!=null)
1158 //We already have a control in that cell as a results of row/col spanning
1159 //Move on to next cell then
1165 //Check if a client field already exists for that cell
1166 if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
1168 //No client field specified, create a text field by default
1169 aClient.Fields.Add(new DataField(aClient.Fields.Count));
1172 //Create a control corresponding to the field specified for that cell
1173 DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
1174 Control control = CreateControlForDataField(field);
1176 //Add newly created control to our table layout at the specified row and column
1177 tableLayoutPanel.Controls.Add(control, i, j);
1178 //Make sure we specify row and column span for that new control
1179 tableLayoutPanel.SetRowSpan(control,field.RowSpan);
1180 tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
1185 while (aClient.Fields.Count > fieldCount)
1187 //We have too much fields for this layout
1188 //Just discard them until we get there
1189 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
1196 /// Check our type of data field and create corresponding control
1198 /// <param name="aField"></param>
1199 private Control CreateControlForDataField(DataField aField)
1201 Control control=null;
1202 if (!aField.IsBitmap)
1204 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
1205 label.AutoEllipsis = true;
1206 label.AutoSize = true;
1207 label.BackColor = System.Drawing.Color.Transparent;
1208 label.Dock = System.Windows.Forms.DockStyle.Fill;
1209 label.Location = new System.Drawing.Point(1, 1);
1210 label.Margin = new System.Windows.Forms.Padding(0);
1211 label.Name = "marqueeLabel" + aField.Index;
1212 label.OwnTimer = false;
1213 label.PixelsPerSecond = 64;
1214 label.Separator = "|";
1215 //control.Size = new System.Drawing.Size(254, 30);
1216 //control.TabIndex = 2;
1217 label.Font = cds.Font;
1219 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1220 label.UseCompatibleTextRendering = true;
1221 label.Text = aField.Text;
1227 //Create picture box
1228 PictureBox picture = new PictureBox();
1229 picture.AutoSize = true;
1230 picture.BackColor = System.Drawing.Color.Transparent;
1231 picture.Dock = System.Windows.Forms.DockStyle.Fill;
1232 picture.Location = new System.Drawing.Point(1, 1);
1233 picture.Margin = new System.Windows.Forms.Padding(0);
1234 picture.Name = "pictureBox" + aField;
1236 picture.Image = aField.Bitmap;
1245 private void buttonAlignLeft_Click(object sender, EventArgs e)
1247 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1249 ctrl.TextAlign = ContentAlignment.MiddleLeft;
1253 private void buttonAlignCenter_Click(object sender, EventArgs e)
1255 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1257 ctrl.TextAlign = ContentAlignment.MiddleCenter;
1261 private void buttonAlignRight_Click(object sender, EventArgs e)
1263 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1265 ctrl.TextAlign = ContentAlignment.MiddleRight;
1269 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1271 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1272 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1273 Properties.Settings.Default.Save();
1274 if (iDisplay.IsOpen())
1276 OpenDisplayConnection();
1285 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1287 if (maskedTextBoxTimerInterval.Text != "")
1289 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1293 timer.Interval = interval;
1294 cds.TimerInterval = timer.Interval;
1295 Properties.Settings.Default.Save();
1300 private void buttonPowerOn_Click(object sender, EventArgs e)
1305 private void buttonPowerOff_Click(object sender, EventArgs e)
1307 iDisplay.PowerOff();
1310 private void buttonShowClock_Click(object sender, EventArgs e)
1312 iDisplay.ShowClock();
1315 private void buttonHideClock_Click(object sender, EventArgs e)
1317 iDisplay.HideClock();
1322 /// A UI thread copy of a client relevant data.
1323 /// Keeping this copy in the UI thread helps us deal with threading issues.
1325 public class ClientData
1327 public ClientData(string aSessionId, ICallback aCallback)
1329 SessionId = aSessionId;
1331 Fields = new List<DataField>();
1332 Layout = new TableLayout(1, 2); //Default to one column and two rows
1333 Callback = aCallback;
1336 public string SessionId { get; set; }
1337 public string Name { get; set; }
1338 public List<DataField> Fields { get; set; }
1339 public TableLayout Layout { get; set; }
1340 public ICallback Callback { get; set; }