Auto Start should work.
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;
61 private StartupManager iStartupManager;
65 iCurrentClientSessionId = "";
66 iCurrentClientData = null;
67 LastTickTime = DateTime.Now;
68 iDisplay = new Display();
69 iClients = new Dictionary<string, ClientData>();
70 iStartupManager = new StartupManager();
72 InitializeComponent();
74 //We have a bug when drawing minimized and reusing our bitmap
75 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
76 iCreateBitmap = false;
79 private void MainForm_Load(object sender, EventArgs e)
81 if (ApplicationDeployment.IsNetworkDeployed)
83 this.Text += " - v" + ApplicationDeployment.CurrentDeployment.CurrentVersion;
87 this.Text += " - development";
92 if (Properties.Settings.Default.DisplayConnectOnStartup)
94 OpenDisplayConnection();
98 checkBoxAutoStart.Checked=iStartupManager.Startup;
102 /// Set our current client.
103 /// This will take care of applying our client layout and set data fields.
105 /// <param name="aSessionId"></param>
106 void SetCurrentClient(string aSessionId)
108 if (aSessionId == iCurrentClientSessionId)
110 //Given client is already the current one.
111 //Don't bother changing anything then.
115 //Set current client ID.
116 iCurrentClientSessionId = aSessionId;
117 //Fetch and set current client data.
118 iCurrentClientData = iClients[aSessionId];
119 //Apply layout and set data fields.
120 UpdateTableLayoutPanel(iCurrentClientData);
123 private void buttonFont_Click(object sender, EventArgs e)
125 //fontDialog.ShowColor = true;
126 //fontDialog.ShowApply = true;
127 fontDialog.ShowEffects = true;
128 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
129 fontDialog.Font = label.Font;
131 fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
133 //fontDialog.ShowHelp = true;
135 //fontDlg.MaxSize = 40;
136 //fontDlg.MinSize = 22;
138 //fontDialog.Parent = this;
139 //fontDialog.StartPosition = FormStartPosition.CenterParent;
141 //DlgBox.ShowDialog(fontDialog);
143 //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
144 if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
147 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
149 //MessageBox.Show("Ok");
150 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
152 ctrl.Font = fontDialog.Font;
154 cds.Font = fontDialog.Font;
155 Properties.Settings.Default.Save();
164 void CheckFontHeight()
166 //Show font height and width
167 labelFontHeight.Text = "Font height: " + cds.Font.Height;
168 float charWidth = IsFixedWidth(cds.Font);
169 if (charWidth == 0.0f)
171 labelFontWidth.Visible = false;
175 labelFontWidth.Visible = true;
176 labelFontWidth.Text = "Font width: " + charWidth;
179 MarqueeLabel label = null;
180 //Get the first label control we can find
181 foreach (Control ctrl in tableLayoutPanel.Controls)
183 if (ctrl is MarqueeLabel)
185 label = (MarqueeLabel)ctrl;
190 //Now check font height and show a warning if needed.
191 if (label != null && label.Font.Height > label.Height)
193 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
194 labelWarning.Visible = true;
198 labelWarning.Visible = false;
203 private void buttonCapture_Click(object sender, EventArgs e)
205 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
206 tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
207 //Bitmap bmpToSave = new Bitmap(bmp);
208 bmp.Save("D:\\capture.png");
210 ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
213 string outputFileName = "d:\\capture.png";
214 using (MemoryStream memory = new MemoryStream())
216 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
218 bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
219 byte[] bytes = memory.ToArray();
220 fs.Write(bytes, 0, bytes.Length);
227 private void CheckForRequestResults()
229 if (iDisplay.IsRequestPending())
231 switch (iDisplay.AttemptRequestCompletion())
233 case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
234 toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
235 //Issue next request then
236 iDisplay.RequestPowerSupplyStatus();
239 case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
240 if (iDisplay.PowerSupplyStatus())
242 toolStripStatusLabelPower.Text = "ON";
246 toolStripStatusLabelPower.Text = "OFF";
248 //Issue next request then
249 iDisplay.RequestDeviceId();
252 case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
253 toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
254 //No more request to issue
260 public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
262 if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
269 public static uint ColorUntouched(int aX, int aY, uint aPixel)
274 public static uint ColorInversed(int aX, int aY, uint aPixel)
279 public static uint ColorChessboard(int aX, int aY, uint aPixel)
281 if ((aX % 2 == 0) && (aY % 2 == 0))
285 else if ((aX % 2 != 0) && (aY % 2 != 0))
293 public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
295 return aBmp.Width - aX - 1;
298 public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
300 return iBmp.Height - aY - 1;
303 public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
308 public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
314 /// Select proper pixel delegates according to our current settings.
316 private void SetupPixelDelegates()
318 //Select our pixel processing routine
319 if (cds.InverseColors)
321 //iColorFx = ColorChessboard;
322 iColorFx = ColorInversed;
326 iColorFx = ColorWhiteIsOn;
329 //Select proper coordinate translation functions
330 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
331 if (cds.ReverseScreen)
333 iScreenX = ScreenReversedX;
334 iScreenY = ScreenReversedY;
344 //This is our timer tick responsible to perform our render
345 private void timer_Tick(object sender, EventArgs e)
347 //Update our animations
348 DateTime NewTickTime = DateTime.Now;
350 //Update animation for all our marquees
351 foreach (Control ctrl in tableLayoutPanel.Controls)
353 if (ctrl is MarqueeLabel)
355 ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
361 if (iDisplay.IsOpen())
363 CheckForRequestResults();
368 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
370 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
371 //iBmp.Save("D:\\capture.png");
373 //Send it to our display
374 for (int i = 0; i < iBmp.Width; i++)
376 for (int j = 0; j < iBmp.Height; j++)
380 //Get our processed pixel coordinates
381 int x = iScreenX(iBmp, i);
382 int y = iScreenY(iBmp, j);
384 uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
385 //Apply color effects
386 color = iColorFx(x,y,color);
388 iDisplay.SetPixel(x, y, color);
393 iDisplay.SwapBuffers();
397 //Compute instant FPS
398 toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
400 LastTickTime = NewTickTime;
404 private void OpenDisplayConnection()
406 CloseDisplayConnection();
408 if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
411 iDisplay.RequestFirmwareRevision();
416 toolStripStatusLabelConnect.Text = "Connection error";
420 private void CloseDisplayConnection()
426 private void buttonOpen_Click(object sender, EventArgs e)
428 OpenDisplayConnection();
431 private void buttonClose_Click(object sender, EventArgs e)
433 CloseDisplayConnection();
436 private void buttonClear_Click(object sender, EventArgs e)
439 iDisplay.SwapBuffers();
442 private void buttonFill_Click(object sender, EventArgs e)
445 iDisplay.SwapBuffers();
448 private void trackBarBrightness_Scroll(object sender, EventArgs e)
450 cds.Brightness = trackBarBrightness.Value;
451 Properties.Settings.Default.Save();
452 iDisplay.SetBrightness(trackBarBrightness.Value);
458 /// CDS stands for Current Display Settings
460 private DisplaySettings cds
464 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
465 if (settings == null)
467 settings = new DisplaysSettings();
469 Properties.Settings.Default.DisplaysSettings = settings;
472 //Make sure all our settings have been created
473 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
475 settings.Displays.Add(new DisplaySettings());
478 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
479 return displaySettings;
484 /// Check if the given font has a fixed character pitch.
486 /// <param name="ft"></param>
487 /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
488 public float IsFixedWidth(Font ft)
490 Graphics g = CreateGraphics();
491 char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
492 float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
494 bool fixedWidth = true;
496 foreach (char c in charSizes)
497 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
508 private void UpdateStatus()
510 //Synchronize UI with settings
512 checkBoxShowBorders.Checked = cds.ShowBorders;
513 tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
515 //Set the proper font to each of our labels
516 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
518 ctrl.Font = cds.Font;
522 checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
523 checkBoxReverseScreen.Checked = cds.ReverseScreen;
524 checkBoxInverseColors.Checked = cds.InverseColors;
525 comboBoxDisplayType.SelectedIndex = cds.DisplayType;
526 timer.Interval = cds.TimerInterval;
527 maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
529 SetupPixelDelegates();
531 if (iDisplay.IsOpen())
533 //Only setup brightness if display is open
534 trackBarBrightness.Minimum = iDisplay.MinBrightness();
535 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
536 trackBarBrightness.Value = cds.Brightness;
537 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
538 trackBarBrightness.SmallChange = 1;
539 iDisplay.SetBrightness(cds.Brightness);
541 buttonFill.Enabled = true;
542 buttonClear.Enabled = true;
543 buttonOpen.Enabled = false;
544 buttonClose.Enabled = true;
545 trackBarBrightness.Enabled = true;
546 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
547 //+ " - " + iDisplay.SerialNumber();
549 if (iDisplay.SupportPowerOnOff())
551 buttonPowerOn.Enabled = true;
552 buttonPowerOff.Enabled = true;
556 buttonPowerOn.Enabled = false;
557 buttonPowerOff.Enabled = false;
560 if (iDisplay.SupportClock())
562 buttonShowClock.Enabled = true;
563 buttonHideClock.Enabled = true;
567 buttonShowClock.Enabled = false;
568 buttonHideClock.Enabled = false;
573 buttonFill.Enabled = false;
574 buttonClear.Enabled = false;
575 buttonOpen.Enabled = true;
576 buttonClose.Enabled = false;
577 trackBarBrightness.Enabled = false;
578 buttonPowerOn.Enabled = false;
579 buttonPowerOff.Enabled = false;
580 buttonShowClock.Enabled = false;
581 buttonHideClock.Enabled = false;
582 toolStripStatusLabelConnect.Text = "Disconnected";
583 toolStripStatusLabelPower.Text = "N/A";
589 private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
591 //Save our show borders setting
592 tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
593 cds.ShowBorders = checkBoxShowBorders.Checked;
594 Properties.Settings.Default.Save();
598 private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
600 //Save our connect on startup setting
601 Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
602 Properties.Settings.Default.Save();
605 private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
607 //Save our reverse screen setting
608 cds.ReverseScreen = checkBoxReverseScreen.Checked;
609 Properties.Settings.Default.Save();
610 SetupPixelDelegates();
613 private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
615 //Save our inverse colors setting
616 cds.InverseColors = checkBoxInverseColors.Checked;
617 Properties.Settings.Default.Save();
618 SetupPixelDelegates();
621 private void MainForm_Resize(object sender, EventArgs e)
623 if (WindowState == FormWindowState.Minimized)
626 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
627 iCreateBitmap = true;
631 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
637 public void StartServer()
639 iServiceHost = new ServiceHost
642 new Uri[] { new Uri("net.tcp://localhost:8001/") }
645 iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
649 public void StopServer()
651 if (iClients.Count > 0 && !iClosing)
655 BroadcastCloseEvent();
659 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
661 iClosing = false; //We make sure we force close if asked twice
666 //We removed that as it often lags for some reason
667 //iServiceHost.Close();
671 public void BroadcastCloseEvent()
673 Trace.TraceInformation("BroadcastCloseEvent - start");
675 var inactiveClients = new List<string>();
676 foreach (var client in iClients)
678 //if (client.Key != eventData.ClientName)
682 Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
683 client.Value.Callback.OnCloseOrder(/*eventData*/);
687 inactiveClients.Add(client.Key);
692 if (inactiveClients.Count > 0)
694 foreach (var client in inactiveClients)
696 iClients.Remove(client);
697 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
702 private void buttonStartClient_Click(object sender, EventArgs e)
704 Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
705 clientThread.Start();
709 private void buttonSuspend_Click(object sender, EventArgs e)
711 LastTickTime = DateTime.Now; //Reset timer to prevent jump
712 timer.Enabled = !timer.Enabled;
715 buttonSuspend.Text = "Run";
719 buttonSuspend.Text = "Pause";
723 private void buttonCloseClients_Click(object sender, EventArgs e)
725 BroadcastCloseEvent();
728 private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
737 /// <param name="aSessionId"></param>
738 /// <param name="aCallback"></param>
739 public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
741 if (this.InvokeRequired)
743 //Not in the proper thread, invoke ourselves
744 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
745 this.Invoke(d, new object[] { aSessionId, aCallback });
749 //We are in the proper thread
750 //Add this session to our collection of clients
751 ClientData newClient = new ClientData(aSessionId, aCallback);
752 Program.iMainForm.iClients.Add(aSessionId, newClient);
753 //Add this session to our UI
754 UpdateClientTreeViewNode(newClient);
761 /// <param name="aSessionId"></param>
762 public void RemoveClientThreadSafe(string aSessionId)
764 if (this.InvokeRequired)
766 //Not in the proper thread, invoke ourselves
767 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
768 this.Invoke(d, new object[] { aSessionId });
772 //We are in the proper thread
773 //Remove this session from both client collection and UI tree view
774 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
776 Program.iMainForm.iClients.Remove(aSessionId);
777 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
780 if (iClosing && iClients.Count == 0)
782 //We were closing our form
783 //All clients are now closed
784 //Just resume our close operation
794 /// <param name="aSessionId"></param>
795 /// <param name="aLayout"></param>
796 public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
798 if (this.InvokeRequired)
800 //Not in the proper thread, invoke ourselves
801 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
802 this.Invoke(d, new object[] { aSessionId, aLayout });
806 ClientData client = iClients[aSessionId];
809 client.Layout = aLayout;
810 UpdateTableLayoutPanel(client);
812 UpdateClientTreeViewNode(client);
820 /// <param name="aSessionId"></param>
821 /// <param name="aField"></param>
822 public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
824 if (this.InvokeRequired)
826 //Not in the proper thread, invoke ourselves
827 SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
828 this.Invoke(d, new object[] { aSessionId, aField });
832 //We are in the proper thread
833 //Call the non-thread-safe variant
834 SetClientField(aSessionId, aField);
841 /// <param name="aSessionId"></param>
842 /// <param name="aField"></param>
843 private void SetClientField(string aSessionId, DataField aField)
845 SetCurrentClient(aSessionId);
846 ClientData client = iClients[aSessionId];
849 bool somethingChanged = false;
851 //Make sure all our fields are in place
852 while (client.Fields.Count < (aField.Index + 1))
854 //Add a text field with proper index
855 client.Fields.Add(new DataField(client.Fields.Count));
856 somethingChanged = true;
859 if (client.Fields[aField.Index].IsSameLayout(aField))
861 //Same layout just update our field
862 client.Fields[aField.Index] = aField;
864 if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
866 //Text field control already in place, just change the text
867 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
868 somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
869 label.Text = aField.Text;
870 label.TextAlign = aField.Alignment;
872 else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
874 somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
875 //Bitmap field control already in place just change the bitmap
876 PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
877 pictureBox.Image = aField.Bitmap;
881 somethingChanged = true;
882 //The requested control in our layout it not of the correct type
883 //Wrong control type, re-create them all
884 UpdateTableLayoutPanel(iCurrentClientData);
889 somethingChanged = true;
890 //Different layout, need to rebuild it
891 client.Fields[aField.Index] = aField;
892 UpdateTableLayoutPanel(iCurrentClientData);
896 if (somethingChanged)
898 UpdateClientTreeViewNode(client);
906 /// <param name="aTexts"></param>
907 public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
909 if (this.InvokeRequired)
911 //Not in the proper thread, invoke ourselves
912 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
913 this.Invoke(d, new object[] { aSessionId, aFields });
917 //Put each our text fields in a label control
918 foreach (DataField field in aFields)
920 SetClientField(aSessionId, field);
928 /// <param name="aSessionId"></param>
929 /// <param name="aName"></param>
930 public void SetClientNameThreadSafe(string aSessionId, string aName)
932 if (this.InvokeRequired)
934 //Not in the proper thread, invoke ourselves
935 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
936 this.Invoke(d, new object[] { aSessionId, aName });
940 //We are in the proper thread
942 ClientData client = iClients[aSessionId];
947 //Update our tree-view
948 UpdateClientTreeViewNode(client);
956 /// <param name="aClient"></param>
957 private void UpdateClientTreeViewNode(ClientData aClient)
964 TreeNode node = null;
965 //Check that our client node already exists
966 //Get our client root node using its key which is our session ID
967 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
970 //We already have a node for that client
972 //Clear children as we are going to recreate them below
977 //Client node does not exists create a new one
978 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
979 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
985 if (aClient.Name != "")
987 //We have a name, us it as text for our root node
988 node.Text = aClient.Name;
989 //Add a child with SessionId
990 node.Nodes.Add(new TreeNode(aClient.SessionId));
994 //No name, use session ID instead
995 node.Text = aClient.SessionId;
998 if (aClient.Fields.Count > 0)
1000 //Create root node for our texts
1001 TreeNode textsRoot = new TreeNode("Fields");
1002 node.Nodes.Add(textsRoot);
1003 //For each text add a new entry
1004 foreach (DataField field in aClient.Fields)
1006 if (!field.IsBitmap)
1008 DataField textField = (DataField)field;
1009 textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
1013 textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
1022 private void buttonAddRow_Click(object sender, EventArgs e)
1024 if (tableLayoutPanel.RowCount < 6)
1026 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
1030 private void buttonRemoveRow_Click(object sender, EventArgs e)
1032 if (tableLayoutPanel.RowCount > 1)
1034 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
1037 UpdateTableLayoutRowStyles();
1040 private void buttonAddColumn_Click(object sender, EventArgs e)
1042 if (tableLayoutPanel.ColumnCount < 8)
1044 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
1048 private void buttonRemoveColumn_Click(object sender, EventArgs e)
1050 if (tableLayoutPanel.ColumnCount > 1)
1052 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
1058 /// Update our table layout row styles to make sure each rows have similar height
1060 private void UpdateTableLayoutRowStyles()
1062 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1064 rowStyle.SizeType = SizeType.Percent;
1065 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1071 /// Empty and recreate our table layout with the given number of columns and rows.
1072 /// Sizes of rows and columns are uniform.
1074 /// <param name="aColumn"></param>
1075 /// <param name="aRow"></param>
1076 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1078 tableLayoutPanel.Controls.Clear();
1079 tableLayoutPanel.RowStyles.Clear();
1080 tableLayoutPanel.ColumnStyles.Clear();
1081 tableLayoutPanel.RowCount = 0;
1082 tableLayoutPanel.ColumnCount = 0;
1084 while (tableLayoutPanel.RowCount < aRow)
1086 tableLayoutPanel.RowCount++;
1089 while (tableLayoutPanel.ColumnCount < aColumn)
1091 tableLayoutPanel.ColumnCount++;
1094 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1096 //Create our column styles
1097 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1099 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1103 //Create our row styles
1104 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1107 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1108 control.AutoEllipsis = true;
1109 control.AutoSize = true;
1110 control.BackColor = System.Drawing.Color.Transparent;
1111 control.Dock = System.Windows.Forms.DockStyle.Fill;
1112 control.Location = new System.Drawing.Point(1, 1);
1113 control.Margin = new System.Windows.Forms.Padding(0);
1114 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1115 control.OwnTimer = false;
1116 control.PixelsPerSecond = 64;
1117 control.Separator = "|";
1118 //control.Size = new System.Drawing.Size(254, 30);
1119 //control.TabIndex = 2;
1120 control.Font = cds.Font;
1121 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1122 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1123 control.UseCompatibleTextRendering = true;
1125 tableLayoutPanel.Controls.Add(control, i, j);
1134 /// Update our display table layout.
1136 /// <param name="aLayout"></param>
1137 private void UpdateTableLayoutPanel(ClientData aClient)
1139 TableLayout layout = aClient.Layout;
1142 tableLayoutPanel.Controls.Clear();
1143 tableLayoutPanel.RowStyles.Clear();
1144 tableLayoutPanel.ColumnStyles.Clear();
1145 tableLayoutPanel.RowCount = 0;
1146 tableLayoutPanel.ColumnCount = 0;
1148 while (tableLayoutPanel.RowCount < layout.Rows.Count)
1150 tableLayoutPanel.RowCount++;
1153 while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
1155 tableLayoutPanel.ColumnCount++;
1158 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1160 //Create our column styles
1161 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
1163 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1167 //Create our row styles
1168 this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
1171 //Check if we already have a control
1172 Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
1173 if (existingControl!=null)
1175 //We already have a control in that cell as a results of row/col spanning
1176 //Move on to next cell then
1182 //Check if a client field already exists for that cell
1183 if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
1185 //No client field specified, create a text field by default
1186 aClient.Fields.Add(new DataField(aClient.Fields.Count));
1189 //Create a control corresponding to the field specified for that cell
1190 DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
1191 Control control = CreateControlForDataField(field);
1193 //Add newly created control to our table layout at the specified row and column
1194 tableLayoutPanel.Controls.Add(control, i, j);
1195 //Make sure we specify row and column span for that new control
1196 tableLayoutPanel.SetRowSpan(control,field.RowSpan);
1197 tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
1202 while (aClient.Fields.Count > fieldCount)
1204 //We have too much fields for this layout
1205 //Just discard them until we get there
1206 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
1213 /// Check our type of data field and create corresponding control
1215 /// <param name="aField"></param>
1216 private Control CreateControlForDataField(DataField aField)
1218 Control control=null;
1219 if (!aField.IsBitmap)
1221 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
1222 label.AutoEllipsis = true;
1223 label.AutoSize = true;
1224 label.BackColor = System.Drawing.Color.Transparent;
1225 label.Dock = System.Windows.Forms.DockStyle.Fill;
1226 label.Location = new System.Drawing.Point(1, 1);
1227 label.Margin = new System.Windows.Forms.Padding(0);
1228 label.Name = "marqueeLabel" + aField.Index;
1229 label.OwnTimer = false;
1230 label.PixelsPerSecond = 64;
1231 label.Separator = "|";
1232 //control.Size = new System.Drawing.Size(254, 30);
1233 //control.TabIndex = 2;
1234 label.Font = cds.Font;
1236 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1237 label.UseCompatibleTextRendering = true;
1238 label.Text = aField.Text;
1244 //Create picture box
1245 PictureBox picture = new PictureBox();
1246 picture.AutoSize = true;
1247 picture.BackColor = System.Drawing.Color.Transparent;
1248 picture.Dock = System.Windows.Forms.DockStyle.Fill;
1249 picture.Location = new System.Drawing.Point(1, 1);
1250 picture.Margin = new System.Windows.Forms.Padding(0);
1251 picture.Name = "pictureBox" + aField;
1253 picture.Image = aField.Bitmap;
1262 private void buttonAlignLeft_Click(object sender, EventArgs e)
1264 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1266 ctrl.TextAlign = ContentAlignment.MiddleLeft;
1270 private void buttonAlignCenter_Click(object sender, EventArgs e)
1272 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1274 ctrl.TextAlign = ContentAlignment.MiddleCenter;
1278 private void buttonAlignRight_Click(object sender, EventArgs e)
1280 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1282 ctrl.TextAlign = ContentAlignment.MiddleRight;
1286 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1288 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1289 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1290 Properties.Settings.Default.Save();
1291 if (iDisplay.IsOpen())
1293 OpenDisplayConnection();
1302 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1304 if (maskedTextBoxTimerInterval.Text != "")
1306 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1310 timer.Interval = interval;
1311 cds.TimerInterval = timer.Interval;
1312 Properties.Settings.Default.Save();
1317 private void buttonPowerOn_Click(object sender, EventArgs e)
1322 private void buttonPowerOff_Click(object sender, EventArgs e)
1324 iDisplay.PowerOff();
1327 private void buttonShowClock_Click(object sender, EventArgs e)
1329 iDisplay.ShowClock();
1332 private void buttonHideClock_Click(object sender, EventArgs e)
1334 iDisplay.HideClock();
1337 private void buttonUpdate_Click(object sender, EventArgs e)
1339 InstallUpdateSyncWithInfo();
1343 private void InstallUpdateSyncWithInfo()
1345 UpdateCheckInfo info = null;
1347 if (ApplicationDeployment.IsNetworkDeployed)
1349 ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
1353 info = ad.CheckForDetailedUpdate();
1356 catch (DeploymentDownloadException dde)
1358 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);
1361 catch (InvalidDeploymentException ide)
1363 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);
1366 catch (InvalidOperationException ioe)
1368 MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
1372 if (info.UpdateAvailable)
1374 Boolean doUpdate = true;
1376 if (!info.IsUpdateRequired)
1378 DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
1379 if (!(DialogResult.OK == dr))
1386 // Display a message that the app MUST reboot. Display the minimum required version.
1387 MessageBox.Show("This application has detected a mandatory update from your current " +
1388 "version to version " + info.MinimumRequiredVersion.ToString() +
1389 ". The application will now install the update and restart.",
1390 "Update Available", MessageBoxButtons.OK,
1391 MessageBoxIcon.Information);
1399 MessageBox.Show("The application has been upgraded, and will now restart.");
1400 Application.Restart();
1402 catch (DeploymentDownloadException dde)
1404 MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
1411 MessageBox.Show("You are already running the latest version.", "Application up-to-date");
1416 private void checkBoxAutoStart_CheckedChanged(object sender, EventArgs e)
1418 iStartupManager.Startup = checkBoxAutoStart.Checked;
1423 /// A UI thread copy of a client relevant data.
1424 /// Keeping this copy in the UI thread helps us deal with threading issues.
1426 public class ClientData
1428 public ClientData(string aSessionId, ICallback aCallback)
1430 SessionId = aSessionId;
1432 Fields = new List<DataField>();
1433 Layout = new TableLayout(1, 2); //Default to one column and two rows
1434 Callback = aCallback;
1437 public string SessionId { get; set; }
1438 public string Name { get; set; }
1439 public List<DataField> Fields { get; set; }
1440 public TableLayout Layout { get; set; }
1441 public ICallback Callback { get; set; }