TableLayout now support row and column styles.
2 using System.Collections.Generic;
3 using System.ComponentModel;
8 using System.Threading.Tasks;
9 using System.Windows.Forms;
11 using CodeProject.Dialog;
12 using System.Drawing.Imaging;
13 using System.ServiceModel;
14 using System.Threading;
15 using System.Diagnostics;
17 using SharpDisplayClient;
20 namespace SharpDisplayManager
23 public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
24 public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
25 //Delegates are used for our thread safe method
26 public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
27 public delegate void RemoveClientDelegate(string aSessionId);
28 public delegate void SetTextDelegate(string SessionId, TextField aTextField);
29 public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
30 public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList<TextField> aTextFields);
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;
46 /// Our collection of clients
48 public Dictionary<string, ClientData> iClients;
50 ColorProcessingDelegate iColorFx;
51 CoordinateTranslationDelegate iScreenX;
52 CoordinateTranslationDelegate iScreenY;
56 LastTickTime = DateTime.Now;
57 iDisplay = new Display();
58 iClients = new Dictionary<string, ClientData>();
60 InitializeComponent();
62 //We have a bug when drawing minimized and reusing our bitmap
63 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
64 iCreateBitmap = false;
66 //this.tableLayoutPanel.CellPaint += new TableLayoutCellPaintEventHandler(tableLayoutPanel_CellPaint);
69 private void MainForm_Load(object sender, EventArgs e)
73 if (Properties.Settings.Default.DisplayConnectOnStartup)
75 OpenDisplayConnection();
80 private void tableLayoutPanel_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
82 var panel = sender as TableLayoutPanel;
83 //e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
84 var rectangle = e.CellBounds;
85 using (var pen = new Pen(Color.Black, 1))
87 pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Center;
88 pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
90 if (e.Row == (panel.RowCount - 1))
92 rectangle.Height -= 1;
95 if (e.Column == (panel.ColumnCount - 1))
100 e.Graphics.DrawRectangle(pen, rectangle);
105 private void buttonFont_Click(object sender, EventArgs e)
107 //fontDialog.ShowColor = true;
108 //fontDialog.ShowApply = true;
109 fontDialog.ShowEffects = true;
110 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
111 fontDialog.Font = label.Font;
113 fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
115 //fontDialog.ShowHelp = true;
117 //fontDlg.MaxSize = 40;
118 //fontDlg.MinSize = 22;
120 //fontDialog.Parent = this;
121 //fontDialog.StartPosition = FormStartPosition.CenterParent;
123 //DlgBox.ShowDialog(fontDialog);
125 //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
126 if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
129 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
131 //MessageBox.Show("Ok");
132 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
134 ctrl.Font = fontDialog.Font;
136 cds.Font = fontDialog.Font;
137 Properties.Settings.Default.Save();
146 void CheckFontHeight()
148 //Show font height and width
149 labelFontHeight.Text = "Font height: " + cds.Font.Height;
150 float charWidth = IsFixedWidth(cds.Font);
151 if (charWidth == 0.0f)
153 labelFontWidth.Visible = false;
157 labelFontWidth.Visible = true;
158 labelFontWidth.Text = "Font width: " + charWidth;
161 //Now check font height and show a warning if needed.
162 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
163 if (label.Font.Height > label.Height)
165 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
166 labelWarning.Visible = true;
170 labelWarning.Visible = false;
175 private void buttonCapture_Click(object sender, EventArgs e)
177 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
178 tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
179 //Bitmap bmpToSave = new Bitmap(bmp);
180 bmp.Save("D:\\capture.png");
182 ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
185 string outputFileName = "d:\\capture.png";
186 using (MemoryStream memory = new MemoryStream())
188 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
190 bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
191 byte[] bytes = memory.ToArray();
192 fs.Write(bytes, 0, bytes.Length);
199 private void CheckForRequestResults()
201 if (iDisplay.IsRequestPending())
203 switch (iDisplay.AttemptRequestCompletion())
205 case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
206 toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
207 //Issue next request then
208 iDisplay.RequestPowerSupplyStatus();
211 case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
212 if (iDisplay.PowerSupplyStatus())
214 toolStripStatusLabelPower.Text = "ON";
218 toolStripStatusLabelPower.Text = "OFF";
220 //Issue next request then
221 iDisplay.RequestDeviceId();
224 case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
225 toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
226 //No more request to issue
232 public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
234 if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
241 public static uint ColorUntouched(int aX, int aY, uint aPixel)
246 public static uint ColorInversed(int aX, int aY, uint aPixel)
251 public static uint ColorChessboard(int aX, int aY, uint aPixel)
253 if ((aX % 2 == 0) && (aY % 2 == 0))
257 else if ((aX % 2 != 0) && (aY % 2 != 0))
265 public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
267 return aBmp.Width - aX - 1;
270 public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
272 return iBmp.Height - aY - 1;
275 public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
280 public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
286 /// Select proper pixel delegates according to our current settings.
288 private void SetupPixelDelegates()
290 //Select our pixel processing routine
291 if (cds.InverseColors)
293 //iColorFx = ColorChessboard;
294 iColorFx = ColorInversed;
298 iColorFx = ColorWhiteIsOn;
301 //Select proper coordinate translation functions
302 //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
303 if (cds.ReverseScreen)
305 iScreenX = ScreenReversedX;
306 iScreenY = ScreenReversedY;
316 //This is our timer tick responsible to perform our render
317 private void timer_Tick(object sender, EventArgs e)
319 //Update our animations
320 DateTime NewTickTime = DateTime.Now;
322 //Update animation for all our marquees
323 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
325 ctrl.UpdateAnimation(LastTickTime, NewTickTime);
330 if (iDisplay.IsOpen())
332 CheckForRequestResults();
337 iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
339 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
340 //iBmp.Save("D:\\capture.png");
342 //Send it to our display
343 for (int i = 0; i < iBmp.Width; i++)
345 for (int j = 0; j < iBmp.Height; j++)
349 //Get our processed pixel coordinates
350 int x = iScreenX(iBmp, i);
351 int y = iScreenY(iBmp, j);
353 uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
354 //Apply color effects
355 color = iColorFx(x,y,color);
357 iDisplay.SetPixel(x, y, color);
362 iDisplay.SwapBuffers();
366 //Compute instant FPS
367 toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
369 LastTickTime = NewTickTime;
373 private void OpenDisplayConnection()
375 CloseDisplayConnection();
377 if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
380 iDisplay.RequestFirmwareRevision();
385 toolStripStatusLabelConnect.Text = "Connection error";
389 private void CloseDisplayConnection()
395 private void buttonOpen_Click(object sender, EventArgs e)
397 OpenDisplayConnection();
400 private void buttonClose_Click(object sender, EventArgs e)
402 CloseDisplayConnection();
405 private void buttonClear_Click(object sender, EventArgs e)
408 iDisplay.SwapBuffers();
411 private void buttonFill_Click(object sender, EventArgs e)
414 iDisplay.SwapBuffers();
417 private void trackBarBrightness_Scroll(object sender, EventArgs e)
419 cds.Brightness = trackBarBrightness.Value;
420 Properties.Settings.Default.Save();
421 iDisplay.SetBrightness(trackBarBrightness.Value);
427 /// CDS stands for Current Display Settings
429 private DisplaySettings cds
433 DisplaysSettings settings = Properties.Settings.Default.DisplaySettings;
434 if (settings == null)
436 settings = new DisplaysSettings();
438 Properties.Settings.Default.DisplaySettings = settings;
441 //Make sure all our settings have been created
442 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
444 settings.Displays.Add(new DisplaySettings());
447 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
448 return displaySettings;
453 /// Check if the given font has a fixed character pitch.
455 /// <param name="ft"></param>
456 /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
457 public float IsFixedWidth(Font ft)
459 Graphics g = CreateGraphics();
460 char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
461 float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
463 bool fixedWidth = true;
465 foreach (char c in charSizes)
466 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
477 private void UpdateStatus()
479 //Synchronize UI with settings
481 checkBoxShowBorders.Checked = cds.ShowBorders;
482 tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
484 //Set the proper font to each of our labels
485 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
487 ctrl.Font = cds.Font;
491 checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
492 checkBoxReverseScreen.Checked = cds.ReverseScreen;
493 checkBoxInverseColors.Checked = cds.InverseColors;
494 comboBoxDisplayType.SelectedIndex = cds.DisplayType;
495 timer.Interval = cds.TimerInterval;
496 maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
498 SetupPixelDelegates();
500 if (iDisplay.IsOpen())
502 //Only setup brightness if display is open
503 trackBarBrightness.Minimum = iDisplay.MinBrightness();
504 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
505 trackBarBrightness.Value = cds.Brightness;
506 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
507 trackBarBrightness.SmallChange = 1;
508 iDisplay.SetBrightness(cds.Brightness);
510 buttonFill.Enabled = true;
511 buttonClear.Enabled = true;
512 buttonOpen.Enabled = false;
513 buttonClose.Enabled = true;
514 trackBarBrightness.Enabled = true;
515 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
516 //+ " - " + iDisplay.SerialNumber();
518 if (iDisplay.SupportPowerOnOff())
520 buttonPowerOn.Enabled = true;
521 buttonPowerOff.Enabled = true;
525 buttonPowerOn.Enabled = false;
526 buttonPowerOff.Enabled = false;
529 if (iDisplay.SupportClock())
531 buttonShowClock.Enabled = true;
532 buttonHideClock.Enabled = true;
536 buttonShowClock.Enabled = false;
537 buttonHideClock.Enabled = false;
542 buttonFill.Enabled = false;
543 buttonClear.Enabled = false;
544 buttonOpen.Enabled = true;
545 buttonClose.Enabled = false;
546 trackBarBrightness.Enabled = false;
547 buttonPowerOn.Enabled = false;
548 buttonPowerOff.Enabled = false;
549 buttonShowClock.Enabled = false;
550 buttonHideClock.Enabled = false;
551 toolStripStatusLabelConnect.Text = "Disconnected";
552 toolStripStatusLabelPower.Text = "N/A";
558 private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
560 //Save our show borders setting
561 tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
562 cds.ShowBorders = checkBoxShowBorders.Checked;
563 Properties.Settings.Default.Save();
567 private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
569 //Save our connect on startup setting
570 Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
571 Properties.Settings.Default.Save();
574 private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
576 //Save our reverse screen setting
577 cds.ReverseScreen = checkBoxReverseScreen.Checked;
578 Properties.Settings.Default.Save();
579 SetupPixelDelegates();
582 private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
584 //Save our inverse colors setting
585 cds.InverseColors = checkBoxInverseColors.Checked;
586 Properties.Settings.Default.Save();
587 SetupPixelDelegates();
590 private void MainForm_Resize(object sender, EventArgs e)
592 if (WindowState == FormWindowState.Minimized)
595 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
596 iCreateBitmap = true;
600 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
606 public void StartServer()
608 iServiceHost = new ServiceHost
611 new Uri[] { new Uri("net.tcp://localhost:8001/") }
614 iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
618 public void StopServer()
620 if (iClients.Count > 0 && !iClosing)
624 BroadcastCloseEvent();
628 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
630 iClosing = false; //We make sure we force close if asked twice
635 //We removed that as it often lags for some reason
636 //iServiceHost.Close();
640 public void BroadcastCloseEvent()
642 Trace.TraceInformation("BroadcastCloseEvent - start");
644 var inactiveClients = new List<string>();
645 foreach (var client in iClients)
647 //if (client.Key != eventData.ClientName)
651 Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
652 client.Value.Callback.OnCloseOrder(/*eventData*/);
656 inactiveClients.Add(client.Key);
661 if (inactiveClients.Count > 0)
663 foreach (var client in inactiveClients)
665 iClients.Remove(client);
666 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
671 private void buttonStartClient_Click(object sender, EventArgs e)
673 Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
674 clientThread.Start();
678 private void buttonSuspend_Click(object sender, EventArgs e)
680 LastTickTime = DateTime.Now; //Reset timer to prevent jump
681 timer.Enabled = !timer.Enabled;
684 buttonSuspend.Text = "Run";
688 buttonSuspend.Text = "Pause";
692 private void buttonCloseClients_Click(object sender, EventArgs e)
694 BroadcastCloseEvent();
697 private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
706 /// <param name="aSessionId"></param>
707 /// <param name="aCallback"></param>
708 public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
710 if (this.InvokeRequired)
712 //Not in the proper thread, invoke ourselves
713 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
714 this.Invoke(d, new object[] { aSessionId, aCallback });
718 //We are in the proper thread
719 //Add this session to our collection of clients
720 ClientData newClient = new ClientData(aSessionId, aCallback);
721 Program.iMainForm.iClients.Add(aSessionId, newClient);
722 //Add this session to our UI
723 UpdateClientTreeViewNode(newClient);
730 /// <param name="aSessionId"></param>
731 public void RemoveClientThreadSafe(string aSessionId)
733 if (this.InvokeRequired)
735 //Not in the proper thread, invoke ourselves
736 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
737 this.Invoke(d, new object[] { aSessionId });
741 //We are in the proper thread
742 //Remove this session from both client collection and UI tree view
743 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
745 Program.iMainForm.iClients.Remove(aSessionId);
746 Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
749 if (iClosing && iClients.Count == 0)
751 //We were closing our form
752 //All clients are now closed
753 //Just resume our close operation
763 /// <param name="aSessionId"></param>
764 /// <param name="aTextField"></param>
765 public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
767 if (this.InvokeRequired)
769 //Not in the proper thread, invoke ourselves
770 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
771 this.Invoke(d, new object[] { aSessionId, aLayout });
775 ClientData client = iClients[aSessionId];
778 client.Layout = aLayout;
779 UpdateTableLayoutPanel(client.Layout);
781 UpdateClientTreeViewNode(client);
789 /// <param name="aLineIndex"></param>
790 /// <param name="aText"></param>
791 public void SetTextThreadSafe(string aSessionId, TextField aTextField)
793 if (this.InvokeRequired)
795 //Not in the proper thread, invoke ourselves
796 SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
797 this.Invoke(d, new object[] { aSessionId, aTextField });
801 ClientData client = iClients[aSessionId];
804 //Make sure all our texts are in place
805 while (client.Texts.Count < (aTextField.Index + 1))
807 //Add a text field with proper index
808 client.Texts.Add(new TextField(client.Texts.Count));
810 client.Texts[aTextField.Index] = aTextField;
812 //We are in the proper thread
813 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aTextField.Index];
814 label.Text = aTextField.Text;
815 label.TextAlign = aTextField.Alignment;
817 UpdateClientTreeViewNode(client);
825 /// <param name="aTexts"></param>
826 public void SetTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<TextField> aTextFields)
828 if (this.InvokeRequired)
830 //Not in the proper thread, invoke ourselves
831 SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
832 this.Invoke(d, new object[] { aSessionId, aTextFields });
836 //We are in the proper thread
837 ClientData client = iClients[aSessionId];
840 //Populate our client with the given text fields
842 foreach (TextField textField in aTextFields)
844 if (client.Texts.Count < (j + 1))
846 client.Texts.Add(textField);
850 client.Texts[j] = textField;
854 //Only support two lines for now
855 for (int i = 0; i < aTextFields.Count; i++)
857 MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aTextFields[i].Index];
858 label.Text = aTextFields[i].Text;
859 label.TextAlign = aTextFields[i].Alignment;
863 UpdateClientTreeViewNode(client);
872 /// <param name="aSessionId"></param>
873 /// <param name="aName"></param>
874 public void SetClientNameThreadSafe(string aSessionId, string aName)
876 if (this.InvokeRequired)
878 //Not in the proper thread, invoke ourselves
879 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
880 this.Invoke(d, new object[] { aSessionId, aName });
884 //We are in the proper thread
886 ClientData client = iClients[aSessionId];
891 //Update our tree-view
892 UpdateClientTreeViewNode(client);
900 /// <param name="aClient"></param>
901 private void UpdateClientTreeViewNode(ClientData aClient)
908 TreeNode node = null;
909 //Check that our client node already exists
910 //Get our client root node using its key which is our session ID
911 TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
914 //We already have a node for that client
916 //Clear children as we are going to recreate them below
921 //Client node does not exists create a new one
922 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
923 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
929 if (aClient.Name != "")
931 //We have a name, us it as text for our root node
932 node.Text = aClient.Name;
933 //Add a child with SessionId
934 node.Nodes.Add(new TreeNode(aClient.SessionId));
938 //No name, use session ID instead
939 node.Text = aClient.SessionId;
942 if (aClient.Texts.Count > 0)
944 //Create root node for our texts
945 TreeNode textsRoot = new TreeNode("Text");
946 node.Nodes.Add(textsRoot);
947 //For each text add a new entry
948 foreach (TextField field in aClient.Texts)
950 textsRoot.Nodes.Add(new TreeNode(field.Text));
958 private void buttonAddRow_Click(object sender, EventArgs e)
960 if (tableLayoutPanel.RowCount < 6)
962 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
966 private void buttonRemoveRow_Click(object sender, EventArgs e)
968 if (tableLayoutPanel.RowCount > 1)
970 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
973 UpdateTableLayoutRowStyles();
976 private void buttonAddColumn_Click(object sender, EventArgs e)
978 if (tableLayoutPanel.ColumnCount < 8)
980 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
984 private void buttonRemoveColumn_Click(object sender, EventArgs e)
986 if (tableLayoutPanel.ColumnCount > 1)
988 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
994 /// Update our table layout row styles to make sure each rows have similar height
996 private void UpdateTableLayoutRowStyles()
998 foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
1000 rowStyle.SizeType = SizeType.Percent;
1001 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
1006 /// Empty and recreate our table layout with the given number of columns and rows.
1007 /// Sizes of rows and columns are uniform.
1009 /// <param name="aColumn"></param>
1010 /// <param name="aRow"></param>
1011 private void UpdateTableLayoutPanel(int aColumn, int aRow)
1013 tableLayoutPanel.Controls.Clear();
1014 tableLayoutPanel.RowStyles.Clear();
1015 tableLayoutPanel.ColumnStyles.Clear();
1016 tableLayoutPanel.RowCount = 0;
1017 tableLayoutPanel.ColumnCount = 0;
1019 while (tableLayoutPanel.RowCount < aRow)
1021 tableLayoutPanel.RowCount++;
1024 while (tableLayoutPanel.ColumnCount < aColumn)
1026 tableLayoutPanel.ColumnCount++;
1029 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1031 //Create our column styles
1032 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
1034 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1038 //Create our row styles
1039 this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
1042 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1043 control.AutoEllipsis = true;
1044 control.AutoSize = true;
1045 control.BackColor = System.Drawing.Color.Transparent;
1046 control.Dock = System.Windows.Forms.DockStyle.Fill;
1047 control.Location = new System.Drawing.Point(1, 1);
1048 control.Margin = new System.Windows.Forms.Padding(0);
1049 control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
1050 control.OwnTimer = false;
1051 control.PixelsPerSecond = 64;
1052 control.Separator = "|";
1053 //control.Size = new System.Drawing.Size(254, 30);
1054 //control.TabIndex = 2;
1055 control.Font = cds.Font;
1056 control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
1057 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1058 control.UseCompatibleTextRendering = true;
1060 tableLayoutPanel.Controls.Add(control, i, j);
1069 /// Update our display table layout.
1071 /// <param name="aLayout"></param>
1072 private void UpdateTableLayoutPanel(TableLayout aLayout)
1074 tableLayoutPanel.Controls.Clear();
1075 tableLayoutPanel.RowStyles.Clear();
1076 tableLayoutPanel.ColumnStyles.Clear();
1077 tableLayoutPanel.RowCount = 0;
1078 tableLayoutPanel.ColumnCount = 0;
1080 while (tableLayoutPanel.RowCount < aLayout.Rows.Count)
1082 tableLayoutPanel.RowCount++;
1085 while (tableLayoutPanel.ColumnCount < aLayout.Columns.Count)
1087 tableLayoutPanel.ColumnCount++;
1090 for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
1092 //Create our column styles
1093 this.tableLayoutPanel.ColumnStyles.Add(aLayout.Columns[i]);
1095 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
1099 //Create our row styles
1100 this.tableLayoutPanel.RowStyles.Add(aLayout.Rows[j]);
1103 MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
1104 control.AutoEllipsis = true;
1105 control.AutoSize = true;
1106 control.BackColor = System.Drawing.Color.Transparent;
1107 control.Dock = System.Windows.Forms.DockStyle.Fill;
1108 control.Location = new System.Drawing.Point(1, 1);
1109 control.Margin = new System.Windows.Forms.Padding(0);
1110 control.Name = "marqueeLabelCol" + aLayout.Columns.Count + "Row" + aLayout.Rows.Count;
1111 control.OwnTimer = false;
1112 control.PixelsPerSecond = 64;
1113 control.Separator = "|";
1114 //control.Size = new System.Drawing.Size(254, 30);
1115 //control.TabIndex = 2;
1116 control.Font = cds.Font;
1117 control.Text = "ABCDEFGHIJKLMNOPQRST[0123456789]";
1118 control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
1119 control.UseCompatibleTextRendering = true;
1121 tableLayoutPanel.Controls.Add(control, i, j);
1129 private void buttonAlignLeft_Click(object sender, EventArgs e)
1131 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1133 ctrl.TextAlign = ContentAlignment.MiddleLeft;
1137 private void buttonAlignCenter_Click(object sender, EventArgs e)
1139 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1141 ctrl.TextAlign = ContentAlignment.MiddleCenter;
1145 private void buttonAlignRight_Click(object sender, EventArgs e)
1147 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
1149 ctrl.TextAlign = ContentAlignment.MiddleRight;
1153 private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
1155 Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
1156 cds.DisplayType = comboBoxDisplayType.SelectedIndex;
1157 Properties.Settings.Default.Save();
1158 if (iDisplay.IsOpen())
1160 OpenDisplayConnection();
1169 private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
1171 if (maskedTextBoxTimerInterval.Text != "")
1173 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
1177 timer.Interval = interval;
1178 cds.TimerInterval = timer.Interval;
1179 Properties.Settings.Default.Save();
1184 private void buttonPowerOn_Click(object sender, EventArgs e)
1189 private void buttonPowerOff_Click(object sender, EventArgs e)
1191 iDisplay.PowerOff();
1194 private void buttonShowClock_Click(object sender, EventArgs e)
1196 iDisplay.ShowClock();
1199 private void buttonHideClock_Click(object sender, EventArgs e)
1201 iDisplay.HideClock();
1206 /// A UI thread copy of a client relevant data.
1207 /// Keeping this copy in the UI thread helps us deal with threading issues.
1209 public class ClientData
1211 public ClientData(string aSessionId, ICallback aCallback)
1213 SessionId = aSessionId;
1215 Texts = new List<TextField>();
1216 Layout = new TableLayout(1, 2); //Default to one column and two rows
1217 Callback = aCallback;
1220 public string SessionId { get; set; }
1221 public string Name { get; set; }
1222 public List<TextField> Texts { get; set; }
1223 public TableLayout Layout { get; set; }
1224 public ICallback Callback { get; set; }