Update checks now gives notification when the application is already up-to-date.
Adding version number to main form text.
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;
16 using System.Deployment.Application;
18 using SharpDisplayClient;
21 namespace SharpDisplayManager
24 public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
25 public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
26 //Delegates are used for our thread safe method
27 public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
28 public delegate void RemoveClientDelegate(string aSessionId);
29 public delegate void SetFieldDelegate(string SessionId, DataField aField);
30 public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList<DataField> aFields);
31 public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
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)
77 if (ApplicationDeployment.IsNetworkDeployed)
79 this.Text += " - v" + ApplicationDeployment.CurrentDeployment.CurrentVersion;
83 this.Text += " - development";
88 if (Properties.Settings.Default.DisplayConnectOnStartup)
90 OpenDisplayConnection();
95 /// Set our current client.
96 /// This will take care of applying our client layout and set data fields.
98 /// <param name="aSessionId"></param>
99 void SetCurrentClient(string aSessionId)
101 if (aSessionId == iCurrentClientSessionId)
103 //Given client is already the current one.
104 //Don't bother changing anything then.
108 //Set current client ID.
109 iCurrentClientSessionId = aSessionId;
110 //Fetch and set current client data.
111 iCurrentClientData = iClients[aSessionId];
112 //Apply layout and set data fields.
113 UpdateTableLayoutPanel(iCurrentClientData);
116 private void buttonFont_Click(object sender, EventArgs e)
118 //fontDialog.ShowColor = true;
119 //fontDialog.ShowApply = true;
120 fontDialog.ShowEffects = true;
121 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
122 fontDialog.Font = label.Font;
124 fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
126 //fontDialog.ShowHelp = true;
128 //fontDlg.MaxSize = 40;
129 //fontDlg.MinSize = 22;
131 //fontDialog.Parent = this;
132 //fontDialog.StartPosition = FormStartPosition.CenterParent;
134 //DlgBox.ShowDialog(fontDialog);
136 //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
137 if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
140 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
142 //MessageBox.Show("Ok");
143 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
145 ctrl.Font = fontDialog.Font;
147 cds.Font = fontDialog.Font;
148 Properties.Settings.Default.Save();
157 void CheckFontHeight()
159 //Show font height and width
160 labelFontHeight.Text = "Font height: " + cds.Font.Height;
161 float charWidth = IsFixedWidth(cds.Font);
162 if (charWidth == 0.0f)
164 labelFontWidth.Visible = false;
168 labelFontWidth.Visible = true;
169 labelFontWidth.Text = "Font width: " + charWidth;
172 MarqueeLabel label = null;
173 //Get the first label control we can find
174 foreach (Control ctrl in tableLayoutPanel.Controls)
176 if (ctrl is MarqueeLabel)
178 label = (MarqueeLabel)ctrl;
183 //Now check font height and show a warning if needed.
184 if (label != null && label.Font.Height > label.Height)
186 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
187 labelWarning.Visible = true;
191 labelWarning.Visible = false;
196 private void buttonCapture_Click(object sender, EventArgs e)
198 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
199 tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
200 //Bitmap bmpToSave = new Bitmap(bmp);
201 bmp.Save("D:\\capture.png");
203 ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
206 string outputFileName = "d:\\capture.png";
207 using (MemoryStream memory = new MemoryStream())
209 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
211 bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
212 byte[] bytes = memory.ToArray();
213 fs.Write(bytes, 0, bytes.Length);
220 private void CheckForRequestResults()
222 if (iDisplay.IsRequestPending())
224 switch (iDisplay.AttemptRequestCompletion())
226 case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
227 toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
228 //Issue next request then
229 iDisplay.RequestPowerSupplyStatus();
232 case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
233 if (iDisplay.PowerSupplyStatus())
235 toolStripStatusLabelPower.Text = "ON";
239 toolStripStatusLabelPower.Text = "OFF";
241 //Issue next request then
242 iDisplay.RequestDeviceId();
245 case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
246 toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
247 //No more request to issue
253 public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
255 if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
262 public static uint ColorUntouched(int aX, int aY, uint aPixel)
267 public static uint ColorInversed(int aX, int aY, uint aPixel)
272 public static uint ColorChessboard(int aX, int aY, uint aPixel)
274 if ((aX % 2 == 0) && (aY % 2 == 0))
278 else if ((aX % 2 != 0) && (aY % 2 != 0))
286 public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
288 return aBmp.Width - aX - 1;
291 public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
293 return iBmp.Height - aY - 1;
296 public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
301 public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
307 /// Select proper pixel delegates according to our current settings.
309 private void SetupPixelDelegates()
311 //Select our pixel processing routine
312 if (cds.InverseColors)
314 //iColorFx = ColorChessboard;
315 iColorFx = ColorInversed;
319 iColorFx = ColorWhiteIsOn;
322 //Select proper coordinate translation functions
323 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
324 if (cds.ReverseScreen)
326 iScreenX = ScreenReversedX;
327 iScreenY = ScreenReversedY;
337 //This is our timer tick responsible to perform our render
338 private void timer_Tick(object sender, EventArgs e)
340 //Update our animations
341 DateTime NewTickTime = DateTime.Now;
343 //Update animation for all our marquees
344 foreach (Control ctrl in tableLayoutPanel.Controls)
346 if (ctrl is MarqueeLabel)
348 ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
354 if (iDisplay.IsOpen())
356 CheckForRequestResults();
361 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
363 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
364 //iBmp.Save("D:\\capture.png");
366 //Send it to our display
367 for (int i = 0; i < iBmp.Width; i++)
369 for (int j = 0; j < iBmp.Height; j++)
373 //Get our processed pixel coordinates
374 int x = iScreenX(iBmp, i);
375 int y = iScreenY(iBmp, j);
377 uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
378 //Apply color effects
379 color = iColorFx(x,y,color);
381 iDisplay.SetPixel(x, y, color);
386 iDisplay.SwapBuffers();
390 //Compute instant FPS
391 toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
393 LastTickTime = NewTickTime;
397 private void OpenDisplayConnection()
399 CloseDisplayConnection();
401 if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
404 iDisplay.RequestFirmwareRevision();
409 toolStripStatusLabelConnect.Text = "Connection error";
413 private void CloseDisplayConnection()
419 private void buttonOpen_Click(object sender, EventArgs e)
421 OpenDisplayConnection();
424 private void buttonClose_Click(object sender, EventArgs e)
426 CloseDisplayConnection();
429 private void buttonClear_Click(object sender, EventArgs e)
432 iDisplay.SwapBuffers();
435 private void buttonFill_Click(object sender, EventArgs e)
438 iDisplay.SwapBuffers();
441 private void trackBarBrightness_Scroll(object sender, EventArgs e)
443 cds.Brightness = trackBarBrightness.Value;
444 Properties.Settings.Default.Save();
445 iDisplay.SetBrightness(trackBarBrightness.Value);
451 /// CDS stands for Current Display Settings
453 private DisplaySettings cds
457 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
458 if (settings == null)
460 settings = new DisplaysSettings();
462 Properties.Settings.Default.DisplaysSettings = settings;
465 //Make sure all our settings have been created
466 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
468 settings.Displays.Add(new DisplaySettings());
471 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
472 return displaySettings;
477 /// Check if the given font has a fixed character pitch.
479 /// <param name="ft"></param>
480 /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
481 public float IsFixedWidth(Font ft)
483 Graphics g = CreateGraphics();
484 char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
485 float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
487 bool fixedWidth = true;
489 foreach (char c in charSizes)
490 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
501 private void UpdateStatus()
503 //Synchronize UI with settings
505 checkBoxShowBorders.Checked = cds.ShowBorders;
506 tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
508 //Set the proper font to each of our labels
509 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
511 ctrl.Font = cds.Font;
515 checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
516 checkBoxReverseScreen.Checked = cds.ReverseScreen;
517 checkBoxInverseColors.Checked = cds.InverseColors;
518 comboBoxDisplayType.SelectedIndex = cds.DisplayType;
519 timer.Interval = cds.TimerInterval;
520 maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
522 SetupPixelDelegates();
524 if (iDisplay.IsOpen())
526 //Only setup brightness if display is open
527 trackBarBrightness.Minimum = iDisplay.MinBrightness();
528 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
529 trackBarBrightness.Value = cds.Brightness;
530 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
531 trackBarBrightness.SmallChange = 1;
532 iDisplay.SetBrightness(cds.Brightness);
534 buttonFill.Enabled = true;
535 buttonClear.Enabled = true;
536 buttonOpen.Enabled = false;
537 buttonClose.Enabled = true;
538 trackBarBrightness.Enabled = true;
539 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
540 //+ " - " + iDisplay.SerialNumber();
542 if (iDisplay.SupportPowerOnOff())
544 buttonPowerOn.Enabled = true;
545 buttonPowerOff.Enabled = true;
549 buttonPowerOn.Enabled = false;
550 buttonPowerOff.Enabled = false;
553 if (iDisplay.SupportClock())
555 buttonShowClock.Enabled = true;
556 buttonHideClock.Enabled = true;
560 buttonShowClock.Enabled = false;
561 buttonHideClock.Enabled = false;
566 buttonFill.Enabled = false;
567 buttonClear.Enabled = false;
568 buttonOpen.Enabled = true;
569 buttonClose.Enabled = false;
570 trackBarBrightness.Enabled = false;
571 buttonPowerOn.Enabled = false;
572 buttonPowerOff.Enabled = false;
573 buttonShowClock.Enabled = false;
574 buttonHideClock.Enabled = false;
575 toolStripStatusLabelConnect.Text = "Disconnected";
576 toolStripStatusLabelPower.Text = "N/A";
582 private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
584 //Save our show borders setting
585 tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
586 cds.ShowBorders = checkBoxShowBorders.Checked;
587 Properties.Settings.Default.Save();
591 private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
593 //Save our connect on startup setting
594 Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
595 Properties.Settings.Default.Save();
598 private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
600 //Save our reverse screen setting
601 cds.ReverseScreen = checkBoxReverseScreen.Checked;
602 Properties.Settings.Default.Save();
603 SetupPixelDelegates();
606 private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
608 //Save our inverse colors setting
609 cds.InverseColors = checkBoxInverseColors.Checked;
610 Properties.Settings.Default.Save();
611 SetupPixelDelegates();
614 private void MainForm_Resize(object sender, EventArgs e)
616 if (WindowState == FormWindowState.Minimized)
619 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
620 iCreateBitmap = true;
624 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
630 public void StartServer()
632 iServiceHost = new ServiceHost
635 new Uri[] { new Uri("net.tcp://localhost:8001/") }
638 iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
642 public void StopServer()
644 if (iClients.Count > 0 && !iClosing)
648 BroadcastCloseEvent();
652 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
654 iClosing = false; //We make sure we force close if asked twice
659 //We removed that as it often lags for some reason
660 //iServiceHost.Close();
664 public void BroadcastCloseEvent()
666 Trace.TraceInformation("BroadcastCloseEvent - start");
668 var inactiveClients = new List<string>();
669 foreach (var client in iClients)
671 //if (client.Key != eventData.ClientName)
675 Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
676 client.Value.Callback.OnCloseOrder(/*eventData*/);
680 inactiveClients.Add(client.Key);
685 if (inactiveClients.Count > 0)
687 foreach (var client in inactiveClients)
689 iClients.Remove(client);
690 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
695 private void buttonStartClient_Click(object sender, EventArgs e)
697 Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
698 clientThread.Start();
702 private void buttonSuspend_Click(object sender, EventArgs e)
704 LastTickTime = DateTime.Now; //Reset timer to prevent jump
705 timer.Enabled = !timer.Enabled;
708 buttonSuspend.Text = "Run";
712 buttonSuspend.Text = "Pause";
716 private void buttonCloseClients_Click(object sender, EventArgs e)
718 BroadcastCloseEvent();
721 private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
730 /// <param name="aSessionId"></param>
731 /// <param name="aCallback"></param>
732 public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
734 if (this.InvokeRequired)
736 //Not in the proper thread, invoke ourselves
737 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
738 this.Invoke(d, new object[] { aSessionId, aCallback });
742 //We are in the proper thread
743 //Add this session to our collection of clients
744 ClientData newClient = new ClientData(aSessionId, aCallback);
745 Program.iMainForm.iClients.Add(aSessionId, newClient);
746 //Add this session to our UI
747 UpdateClientTreeViewNode(newClient);
754 /// <param name="aSessionId"></param>
755 public void RemoveClientThreadSafe(string aSessionId)
757 if (this.InvokeRequired)
759 //Not in the proper thread, invoke ourselves
760 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
761 this.Invoke(d, new object[] { aSessionId });
765 //We are in the proper thread
766 //Remove this session from both client collection and UI tree view
767 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
769 Program.iMainForm.iClients.Remove(aSessionId);
770 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
773 if (iClosing && iClients.Count == 0)
775 //We were closing our form
776 //All clients are now closed
777 //Just resume our close operation
787 /// <param name="aSessionId"></param>
788 /// <param name="aLayout"></param>
789 public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
791 if (this.InvokeRequired)
793 //Not in the proper thread, invoke ourselves
794 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
795 this.Invoke(d, new object[] { aSessionId, aLayout });
799 ClientData client = iClients[aSessionId];
802 client.Layout = aLayout;
803 UpdateTableLayoutPanel(client);
805 UpdateClientTreeViewNode(client);
813 /// <param name="aSessionId"></param>
814 /// <param name="aField"></param>
815 public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
817 if (this.InvokeRequired)
819 //Not in the proper thread, invoke ourselves
820 SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
821 this.Invoke(d, new object[] { aSessionId, aField });
825 //We are in the proper thread
826 //Call the non-thread-safe variant
827 SetClientField(aSessionId, aField);
834 /// <param name="aSessionId"></param>
835 /// <param name="aField"></param>
836 private void SetClientField(string aSessionId, DataField aField)
838 SetCurrentClient(aSessionId);
839 ClientData client = iClients[aSessionId];
842 bool somethingChanged = false;
844 //Make sure all our fields are in place
845 while (client.Fields.Count < (aField.Index + 1))
847 //Add a text field with proper index
848 client.Fields.Add(new DataField(client.Fields.Count));
849 somethingChanged = true;
852 if (client.Fields[aField.Index].IsSameLayout(aField))
854 //Same layout just update our field
855 client.Fields[aField.Index] = aField;
857 if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
859 //Text field control already in place, just change the text
860 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
861 somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
862 label.Text = aField.Text;
863 label.TextAlign = aField.Alignment;
865 else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
867 somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
868 //Bitmap field control already in place just change the bitmap
869 PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
870 pictureBox.Image = aField.Bitmap;
874 somethingChanged = true;
875 //The requested control in our layout it not of the correct type
876 //Wrong control type, re-create them all
877 UpdateTableLayoutPanel(iCurrentClientData);
882 somethingChanged = true;
883 //Different layout, need to rebuild it
884 client.Fields[aField.Index] = aField;
885 UpdateTableLayoutPanel(iCurrentClientData);
889 if (somethingChanged)
891 UpdateClientTreeViewNode(client);
899 /// <param name="aTexts"></param>
900 public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
902 if (this.InvokeRequired)
904 //Not in the proper thread, invoke ourselves
905 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
906 this.Invoke(d, new object[] { aSessionId, aFields });
910 //Put each our text fields in a label control
911 foreach (DataField field in aFields)
913 SetClientField(aSessionId, field);
921 /// <param name="aSessionId"></param>
922 /// <param name="aName"></param>
923 public void SetClientNameThreadSafe(string aSessionId, string aName)
925 if (this.InvokeRequired)
927 //Not in the proper thread, invoke ourselves
928 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
929 this.Invoke(d, new object[] { aSessionId, aName });
933 //We are in the proper thread
935 ClientData client = iClients[aSessionId];
940 //Update our tree-view
941 UpdateClientTreeViewNode(client);
949 /// <param name="aClient"></param>
950 private void UpdateClientTreeViewNode(ClientData aClient)
957 TreeNode node = null;
958 //Check that our client node already exists
959 //Get our client root node using its key which is our session ID
960 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
963 //We already have a node for that client
965 //Clear children as we are going to recreate them below
970 //Client node does not exists create a new one
971 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
972 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
978 if (aClient.Name != "")
980 //We have a name, us it as text for our root node
981 node.Text = aClient.Name;
982 //Add a child with SessionId
983 node.Nodes.Add(new TreeNode(aClient.SessionId));
987 //No name, use session ID instead
988 node.Text = aClient.SessionId;
991 if (aClient.Fields.Count > 0)
993 //Create root node for our texts
994 TreeNode textsRoot = new TreeNode("Fields");
995 node.Nodes.Add(textsRoot);
996 //For each text add a new entry
997 foreach (DataField field in aClient.Fields)
1001 DataField textField = (DataField)field;
1002 textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
1006 textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
1015 private void buttonAddRow_Click(object sender, EventArgs e)
1017 if (tableLayoutPanel.RowCount < 6)
1019 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
1023 private void buttonRemoveRow_Click(object sender, EventArgs e)
1025 if (tableLayoutPanel.RowCount > 1)
1027 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
1030 UpdateTableLayoutRowStyles();
1033 private void buttonAddColumn_Click(object sender, EventArgs e)
1035 if (tableLayoutPanel.ColumnCount < 8)
1037 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
1041 private void buttonRemoveColumn_Click(object sender, EventArgs e)
1043 if (tableLayoutPanel.ColumnCount > 1)
1045 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
1051 /// Update our table layout row styles to make sure each rows have similar height
1053 private void UpdateTableLayoutRowStyles()
1055 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1057 rowStyle.SizeType = SizeType.Percent;
1058 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1064 /// Empty and recreate our table layout with the given number of columns and rows.
1065 /// Sizes of rows and columns are uniform.
1067 /// <param name="aColumn"></param>
1068 /// <param name="aRow"></param>
1069 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1071 tableLayoutPanel.Controls.Clear();
1072 tableLayoutPanel.RowStyles.Clear();
1073 tableLayoutPanel.ColumnStyles.Clear();
1074 tableLayoutPanel.RowCount = 0;
1075 tableLayoutPanel.ColumnCount = 0;
1077 while (tableLayoutPanel.RowCount < aRow)
1079 tableLayoutPanel.RowCount++;
1082 while (tableLayoutPanel.ColumnCount < aColumn)
1084 tableLayoutPanel.ColumnCount++;
1087 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1089 //Create our column styles
1090 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1092 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1096 //Create our row styles
1097 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1100 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1101 control.AutoEllipsis = true;
1102 control.AutoSize = true;
1103 control.BackColor = System.Drawing.Color.Transparent;
1104 control.Dock = System.Windows.Forms.DockStyle.Fill;
1105 control.Location = new System.Drawing.Point(1, 1);
1106 control.Margin = new System.Windows.Forms.Padding(0);
1107 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1108 control.OwnTimer = false;
1109 control.PixelsPerSecond = 64;
1110 control.Separator = "|";
1111 //control.Size = new System.Drawing.Size(254, 30);
1112 //control.TabIndex = 2;
1113 control.Font = cds.Font;
1114 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1115 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1116 control.UseCompatibleTextRendering = true;
1118 tableLayoutPanel.Controls.Add(control, i, j);
1127 /// Update our display table layout.
1129 /// <param name="aLayout"></param>
1130 private void UpdateTableLayoutPanel(ClientData aClient)
1132 TableLayout layout = aClient.Layout;
1135 tableLayoutPanel.Controls.Clear();
1136 tableLayoutPanel.RowStyles.Clear();
1137 tableLayoutPanel.ColumnStyles.Clear();
1138 tableLayoutPanel.RowCount = 0;
1139 tableLayoutPanel.ColumnCount = 0;
1141 while (tableLayoutPanel.RowCount < layout.Rows.Count)
1143 tableLayoutPanel.RowCount++;
1146 while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
1148 tableLayoutPanel.ColumnCount++;
1151 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1153 //Create our column styles
1154 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
1156 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1160 //Create our row styles
1161 this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
1164 //Check if we already have a control
1165 Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
1166 if (existingControl!=null)
1168 //We already have a control in that cell as a results of row/col spanning
1169 //Move on to next cell then
1175 //Check if a client field already exists for that cell
1176 if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
1178 //No client field specified, create a text field by default
1179 aClient.Fields.Add(new DataField(aClient.Fields.Count));
1182 //Create a control corresponding to the field specified for that cell
1183 DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
1184 Control control = CreateControlForDataField(field);
1186 //Add newly created control to our table layout at the specified row and column
1187 tableLayoutPanel.Controls.Add(control, i, j);
1188 //Make sure we specify row and column span for that new control
1189 tableLayoutPanel.SetRowSpan(control,field.RowSpan);
1190 tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
1195 while (aClient.Fields.Count > fieldCount)
1197 //We have too much fields for this layout
1198 //Just discard them until we get there
1199 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
1206 /// Check our type of data field and create corresponding control
1208 /// <param name="aField"></param>
1209 private Control CreateControlForDataField(DataField aField)
1211 Control control=null;
1212 if (!aField.IsBitmap)
1214 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
1215 label.AutoEllipsis = true;
1216 label.AutoSize = true;
1217 label.BackColor = System.Drawing.Color.Transparent;
1218 label.Dock = System.Windows.Forms.DockStyle.Fill;
1219 label.Location = new System.Drawing.Point(1, 1);
1220 label.Margin = new System.Windows.Forms.Padding(0);
1221 label.Name = "marqueeLabel" + aField.Index;
1222 label.OwnTimer = false;
1223 label.PixelsPerSecond = 64;
1224 label.Separator = "|";
1225 //control.Size = new System.Drawing.Size(254, 30);
1226 //control.TabIndex = 2;
1227 label.Font = cds.Font;
1229 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1230 label.UseCompatibleTextRendering = true;
1231 label.Text = aField.Text;
1237 //Create picture box
1238 PictureBox picture = new PictureBox();
1239 picture.AutoSize = true;
1240 picture.BackColor = System.Drawing.Color.Transparent;
1241 picture.Dock = System.Windows.Forms.DockStyle.Fill;
1242 picture.Location = new System.Drawing.Point(1, 1);
1243 picture.Margin = new System.Windows.Forms.Padding(0);
1244 picture.Name = "pictureBox" + aField;
1246 picture.Image = aField.Bitmap;
1255 private void buttonAlignLeft_Click(object sender, EventArgs e)
1257 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1259 ctrl.TextAlign = ContentAlignment.MiddleLeft;
1263 private void buttonAlignCenter_Click(object sender, EventArgs e)
1265 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1267 ctrl.TextAlign = ContentAlignment.MiddleCenter;
1271 private void buttonAlignRight_Click(object sender, EventArgs e)
1273 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1275 ctrl.TextAlign = ContentAlignment.MiddleRight;
1279 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1281 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1282 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1283 Properties.Settings.Default.Save();
1284 if (iDisplay.IsOpen())
1286 OpenDisplayConnection();
1295 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1297 if (maskedTextBoxTimerInterval.Text != "")
1299 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1303 timer.Interval = interval;
1304 cds.TimerInterval = timer.Interval;
1305 Properties.Settings.Default.Save();
1310 private void buttonPowerOn_Click(object sender, EventArgs e)
1315 private void buttonPowerOff_Click(object sender, EventArgs e)
1317 iDisplay.PowerOff();
1320 private void buttonShowClock_Click(object sender, EventArgs e)
1322 iDisplay.ShowClock();
1325 private void buttonHideClock_Click(object sender, EventArgs e)
1327 iDisplay.HideClock();
1330 private void buttonUpdate_Click(object sender, EventArgs e)
1332 InstallUpdateSyncWithInfo();
1336 private void InstallUpdateSyncWithInfo()
1338 UpdateCheckInfo info = null;
1340 if (ApplicationDeployment.IsNetworkDeployed)
1342 ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
1346 info = ad.CheckForDetailedUpdate();
1349 catch (DeploymentDownloadException dde)
1351 MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
1354 catch (InvalidDeploymentException ide)
1356 MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
1359 catch (InvalidOperationException ioe)
1361 MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
1365 if (info.UpdateAvailable)
1367 Boolean doUpdate = true;
1369 if (!info.IsUpdateRequired)
1371 DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
1372 if (!(DialogResult.OK == dr))
1379 // Display a message that the app MUST reboot. Display the minimum required version.
1380 MessageBox.Show("This application has detected a mandatory update from your current " +
1381 "version to version " + info.MinimumRequiredVersion.ToString() +
1382 ". The application will now install the update and restart.",
1383 "Update Available", MessageBoxButtons.OK,
1384 MessageBoxIcon.Information);
1392 MessageBox.Show("The application has been upgraded, and will now restart.");
1393 Application.Restart();
1395 catch (DeploymentDownloadException dde)
1397 MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
1404 MessageBox.Show("You are already running the latest version.", "Application up-to-date");
1411 /// A UI thread copy of a client relevant data.
1412 /// Keeping this copy in the UI thread helps us deal with threading issues.
1414 public class ClientData
1416 public ClientData(string aSessionId, ICallback aCallback)
1418 SessionId = aSessionId;
1420 Fields = new List<DataField>();
1421 Layout = new TableLayout(1, 2); //Default to one column and two rows
1422 Callback = aCallback;
1425 public string SessionId { get; set; }
1426 public string Name { get; set; }
1427 public List<DataField> Fields { get; set; }
1428 public TableLayout Layout { get; set; }
1429 public ICallback Callback { get; set; }