QAGrid.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. using System.Windows;
  2. using System.Windows.Controls;
  3. using System.Windows.Media;
  4. using InABox.Core;
  5. using Button = System.Windows.Controls.Button;
  6. using Color = System.Windows.Media.Color;
  7. using ComboBox = System.Windows.Controls.ComboBox;
  8. using HorizontalAlignment = System.Windows.HorizontalAlignment;
  9. using Label = System.Windows.Controls.Label;
  10. using SystemColors = System.Windows.SystemColors;
  11. using TextBox = System.Windows.Controls.TextBox;
  12. using UserControl = System.Windows.Controls.UserControl;
  13. namespace InABox.WPF
  14. {
  15. public class QAGrid : UserControl
  16. {
  17. public delegate void QAFormChangedEvent(object sender, Dictionary<Guid, object> values);
  18. private readonly Dictionary<QAQuestion, Border> borders = new();
  19. private readonly Grid MasterGrid;
  20. public QAGrid()
  21. {
  22. BorderBrush = new SolidColorBrush(Colors.Gray);
  23. BorderThickness = new Thickness(0.75);
  24. MasterGrid = new Grid();
  25. MasterGrid.Background = new SolidColorBrush(Colors.WhiteSmoke);
  26. MasterGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.25F, GridUnitType.Star) });
  27. MasterGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.25F, GridUnitType.Star) });
  28. MasterGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Auto) });
  29. MasterGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Star) });
  30. MasterGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Auto) });
  31. Content = MasterGrid;
  32. }
  33. public bool Preview { get; set; }
  34. public QAFormChangedEvent OnChanged { get; set; }
  35. private object GetValue(Dictionary<Guid, object> values, Guid guid)
  36. {
  37. if (values.ContainsKey(guid))
  38. return values[guid];
  39. return "";
  40. }
  41. private Border CreateHeader(string title)
  42. {
  43. var label = new Label
  44. {
  45. Content = title,
  46. FontSize = 16.0F,
  47. HorizontalAlignment = HorizontalAlignment.Center,
  48. VerticalAlignment = VerticalAlignment.Center
  49. };
  50. var border = new Border
  51. {
  52. CornerRadius = new CornerRadius(10.0F, 10.0F, 0.0F, 0.0F),
  53. BorderThickness = new Thickness(1.0F),
  54. BorderBrush = SystemColors.WindowFrameBrush,
  55. Background = SystemColors.WindowBrush,
  56. Margin = new Thickness(5.0F, 5.0F, 5.0F, 2.0F),
  57. Padding = new Thickness(5.0F)
  58. };
  59. border.SetValue(Grid.ColumnProperty, MasterGrid.ColumnDefinitions.Count - 1);
  60. border.SetValue(Grid.RowProperty, 0);
  61. border.Child = label;
  62. MasterGrid.Children.Add(border);
  63. return border;
  64. }
  65. private Thickness GetMargin(Grid grid)
  66. {
  67. if (grid.RowDefinitions.Count == 0)
  68. return new Thickness(2.0F, 0.0F, 2.0F, 0.0F);
  69. return new Thickness(4.0F, 3.0F, 4.0F, 3.0F);
  70. }
  71. public static Color InterpolateColors(Color color1, Color color2, float percentage)
  72. {
  73. double a1 = color1.A / 255.0, r1 = color1.R / 255.0, g1 = color1.G / 255.0, b1 = color1.B / 255.0;
  74. double a2 = color2.A / 255.0, r2 = color2.R / 255.0, g2 = color2.G / 255.0, b2 = color2.B / 255.0;
  75. var a3 = Convert.ToByte((a1 + (a2 - a1) * percentage) * 255);
  76. var r3 = Convert.ToByte((r1 + (r2 - r1) * percentage) * 255);
  77. var g3 = Convert.ToByte((g1 + (g2 - g1) * percentage) * 255);
  78. var b3 = Convert.ToByte((b1 + (b2 - b1) * percentage) * 255);
  79. return Color.FromArgb(a3, r3, g3, b3);
  80. }
  81. private Color GetBorder(QAQuestion question, Dictionary<Guid, object> answers)
  82. {
  83. var parameters = question.ParseParameters();
  84. var bAnswerRequired = question.Answer != QAAnswer.Comment &&
  85. (!parameters.ContainsKey("Default") || string.IsNullOrWhiteSpace(parameters["Default"]));
  86. if (bAnswerRequired && (!answers.ContainsKey(question.ID) || answers[question.ID] == null))
  87. return Colors.Red;
  88. return Colors.Transparent;
  89. }
  90. public void CollapseMargins()
  91. {
  92. MasterGrid.ColumnDefinitions.First().Width = new GridLength(0.0F);
  93. MasterGrid.ColumnDefinitions.Last().Width = new GridLength(0.0F);
  94. }
  95. private void Changed(Dictionary<Guid, object> values)
  96. {
  97. OnChanged?.Invoke(this, values);
  98. foreach (var question in borders.Keys)
  99. {
  100. var color = GetBorder(question, values);
  101. borders[question].BorderBrush = new SolidColorBrush(color);
  102. borders[question].Background = new SolidColorBrush(InterpolateColors(color, Colors.Transparent, 0.8F));
  103. }
  104. }
  105. private Border CreateBorder(Grid grid, QAQuestion check, Dictionary<Guid, object> values)
  106. {
  107. var border = new Border();
  108. border.SetValue(Grid.ColumnProperty, 0);
  109. border.SetValue(Grid.RowProperty, grid.RowDefinitions.Count);
  110. border.Padding = new Thickness(2.0F);
  111. var color = GetBorder(check, values);
  112. border.BorderBrush = new SolidColorBrush(color);
  113. border.Background = new SolidColorBrush(InterpolateColors(color, Colors.Transparent, 0.8F));
  114. border.BorderThickness = new Thickness(1.5F);
  115. border.Margin = new Thickness(0F, 2F, 0F, 2F);
  116. border.CornerRadius = new CornerRadius(5.0F);
  117. grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Auto) });
  118. grid.Children.Add(border);
  119. return border;
  120. }
  121. private Border CreateCommentPanel(Grid grid, QAQuestion check, Dictionary<Guid, object> values, int number)
  122. {
  123. var border = CreateBorder(grid, check, values);
  124. var row = new Grid();
  125. row.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Star) });
  126. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0F, GridUnitType.Star) });
  127. var label = new TextBlock
  128. {
  129. Text = check.Question,
  130. FontSize = 14.0F,
  131. TextAlignment = TextAlignment.Center,
  132. TextWrapping = TextWrapping.Wrap,
  133. VerticalAlignment = VerticalAlignment.Center,
  134. Margin = GetMargin(grid),
  135. Padding = new Thickness(10)
  136. };
  137. label.SetValue(Grid.RowProperty, 0);
  138. label.SetValue(Grid.ColumnProperty, 0);
  139. row.Children.Add(label);
  140. border.Child = row;
  141. return border;
  142. }
  143. private Border CreateChoicePanel(Grid grid, QAQuestion check, Dictionary<Guid, object> values, int number)
  144. {
  145. var border = CreateBorder(grid, check, values);
  146. var row = new Grid();
  147. row.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Auto) });
  148. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0F, GridUnitType.Star) });
  149. var label = new TextBlock
  150. {
  151. Text = string.Format("{0}. {1}", number, check.Question),
  152. FontSize = 14.0F,
  153. Margin = GetMargin(grid),
  154. VerticalAlignment = VerticalAlignment.Center,
  155. TextAlignment = TextAlignment.Left,
  156. TextWrapping = TextWrapping.Wrap
  157. };
  158. label.SetValue(Grid.RowProperty, 0);
  159. label.SetValue(Grid.ColumnProperty, 0);
  160. row.Children.Add(label);
  161. if (!string.IsNullOrEmpty(check.Parameters))
  162. {
  163. var parameters = check.ParseParameters();
  164. var buttons = parameters["Options"].Split(',');
  165. var colors = parameters["Colors"].Split(',');
  166. var value = GetValue(values, check.ID).ToString();
  167. if (string.IsNullOrWhiteSpace(value))
  168. value = parameters["Default"];
  169. for (var i = 0; i < buttons.Length; i++)
  170. if (!string.IsNullOrWhiteSpace(buttons[i]))
  171. {
  172. var brush = new SolidColorBrush(Colors.WhiteSmoke);
  173. try
  174. {
  175. brush = new BrushConverter().ConvertFromString(colors[i]) as SolidColorBrush;
  176. }
  177. catch (Exception e)
  178. {
  179. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  180. }
  181. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80.0F) });
  182. var button = new Button
  183. {
  184. Content = buttons[i],
  185. FontSize = 14.0F,
  186. Margin = GetMargin(grid),
  187. Height = 40,
  188. Background = buttons[i].Equals(value) ? brush : new SolidColorBrush(Colors.WhiteSmoke),
  189. Tag = brush
  190. };
  191. button.Click += (o, e) =>
  192. {
  193. values[check.ID] = button.Content.ToString();
  194. foreach (var other in row.Children)
  195. if (other is Button)
  196. {
  197. if (other == button)
  198. ((Button)other).Background = (SolidColorBrush)button.Tag;
  199. else
  200. ((Button)other).Background = new SolidColorBrush(Colors.WhiteSmoke);
  201. }
  202. Changed(values);
  203. };
  204. button.SetValue(Grid.RowProperty, 0);
  205. button.SetValue(Grid.ColumnProperty, i + 1);
  206. row.Children.Add(button);
  207. }
  208. }
  209. border.Child = row;
  210. return border;
  211. }
  212. private Border CreateNumberPanel(Grid grid, QAQuestion check, Dictionary<Guid, object> values, int number)
  213. {
  214. var border = CreateBorder(grid, check, values);
  215. var row = new Grid();
  216. row.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Star) });
  217. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0F, GridUnitType.Star) });
  218. var label = new TextBlock
  219. {
  220. Text = string.Format("{0}. {1}", number, check.Question),
  221. FontSize = 14.0F,
  222. Margin = GetMargin(grid),
  223. VerticalAlignment = VerticalAlignment.Center,
  224. TextAlignment = TextAlignment.Left,
  225. TextWrapping = TextWrapping.Wrap
  226. };
  227. label.SetValue(Grid.RowProperty, 0);
  228. label.SetValue(Grid.ColumnProperty, 0);
  229. row.Children.Add(label);
  230. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(160.0F) });
  231. var editor = new TextBox
  232. {
  233. Margin = GetMargin(grid),
  234. TextAlignment = TextAlignment.Center,
  235. VerticalContentAlignment = VerticalAlignment.Center,
  236. Height = 40,
  237. FontSize = 14.0F
  238. };
  239. editor.SetValue(Grid.RowProperty, 0);
  240. editor.SetValue(Grid.ColumnProperty, 1);
  241. row.Children.Add(editor);
  242. var def = "";
  243. if (!string.IsNullOrEmpty(check.Parameters))
  244. {
  245. var parameters = check.ParseParameters();
  246. def = parameters["Default"];
  247. }
  248. var value = GetValue(values, check.ID).ToString();
  249. editor.Text = string.IsNullOrWhiteSpace(value) ? def : value;
  250. editor.TextChanged += (o, e) =>
  251. {
  252. values[check.ID] = editor.Text;
  253. Changed(values);
  254. };
  255. border.Child = row;
  256. return border;
  257. }
  258. private Border CreateTextPanel(Grid grid, QAQuestion check, Dictionary<Guid, object> values, int number)
  259. {
  260. var border = CreateBorder(grid, check, values);
  261. var row = new Grid();
  262. row.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Star) });
  263. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0F, GridUnitType.Star) });
  264. var label = new TextBlock
  265. {
  266. Text = string.Format("{0}. {1}", number, check.Question),
  267. FontSize = 14.0F,
  268. Margin = GetMargin(grid),
  269. VerticalAlignment = VerticalAlignment.Center,
  270. TextAlignment = TextAlignment.Left,
  271. TextWrapping = TextWrapping.Wrap
  272. };
  273. label.SetValue(Grid.RowProperty, 0);
  274. label.SetValue(Grid.ColumnProperty, 0);
  275. row.Children.Add(label);
  276. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(320.0F, GridUnitType.Pixel) });
  277. var editor = new TextBox
  278. {
  279. Margin = GetMargin(grid),
  280. TextAlignment = TextAlignment.Center,
  281. VerticalContentAlignment = VerticalAlignment.Center,
  282. Height = 40,
  283. FontSize = 14.0F
  284. };
  285. editor.SetValue(Grid.RowProperty, 0);
  286. editor.SetValue(Grid.ColumnProperty, 1);
  287. row.Children.Add(editor);
  288. var def = "";
  289. if (!string.IsNullOrEmpty(check.Parameters))
  290. {
  291. var parameters = check.ParseParameters();
  292. def = parameters["Default"];
  293. }
  294. var value = GetValue(values, check.ID).ToString();
  295. editor.Text = string.IsNullOrWhiteSpace(value) ? def : value;
  296. editor.TextChanged += (o, e) =>
  297. {
  298. values[check.ID] = editor.Text;
  299. Changed(values);
  300. };
  301. border.Child = row;
  302. return border;
  303. }
  304. private Border CreateComboPanel(Grid grid, QAQuestion check, Dictionary<Guid, object> values, int number)
  305. {
  306. var border = CreateBorder(grid, check, values);
  307. var row = new Grid();
  308. row.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0F, GridUnitType.Star) });
  309. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0F, GridUnitType.Star) });
  310. var label = new TextBlock
  311. {
  312. Text = string.Format("{0}. {1}", number, check.Question),
  313. FontSize = 14.0F,
  314. Margin = GetMargin(grid),
  315. VerticalAlignment = VerticalAlignment.Center,
  316. TextAlignment = TextAlignment.Left,
  317. TextWrapping = TextWrapping.Wrap
  318. };
  319. label.SetValue(Grid.RowProperty, 0);
  320. label.SetValue(Grid.ColumnProperty, 0);
  321. row.Children.Add(label);
  322. row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(320.0F, GridUnitType.Pixel) });
  323. var editor = new ComboBox
  324. {
  325. Margin = GetMargin(grid),
  326. HorizontalContentAlignment = HorizontalAlignment.Left,
  327. VerticalContentAlignment = VerticalAlignment.Center,
  328. Height = 40
  329. };
  330. editor.SetValue(Grid.RowProperty, 0);
  331. editor.SetValue(Grid.ColumnProperty, 1);
  332. row.Children.Add(editor);
  333. if (!string.IsNullOrEmpty(check.Parameters))
  334. {
  335. var parameters = check.ParseParameters();
  336. var options = parameters["Options"].Split(',');
  337. var def = parameters["Default"];
  338. for (var i = 0; i < options.Length; i++)
  339. editor.Items.Add(options[i]);
  340. var value = GetValue(values, check.ID).ToString();
  341. editor.SelectedIndex = editor.Items.IndexOf(string.IsNullOrWhiteSpace(value) ? def : value);
  342. }
  343. editor.SelectionChanged += (o, e) =>
  344. {
  345. values[check.ID] = editor.SelectedIndex >= 0 ? editor.Items[editor.SelectedIndex].ToString() : "";
  346. Changed(values);
  347. };
  348. border.Child = row;
  349. return border;
  350. }
  351. public void Clear()
  352. {
  353. borders.Clear();
  354. MasterGrid.Children.Clear();
  355. MasterGrid.ColumnDefinitions.Clear();
  356. MasterGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.25F, GridUnitType.Star) });
  357. MasterGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.25F, GridUnitType.Star) });
  358. }
  359. public void LoadChecks(string title, IEnumerable<QAQuestion> checks, Dictionary<Guid, object> values)
  360. {
  361. var sections = new List<string>();
  362. foreach (var check in checks)
  363. {
  364. var section = string.IsNullOrWhiteSpace(check.Section) ? title : check.Section;
  365. if (!sections.Contains(section))
  366. sections.Add(section);
  367. }
  368. if (!sections.Any())
  369. sections.Add(title);
  370. foreach (var section in sections)
  371. {
  372. var header = CreateHeader(section);
  373. var border = new Border
  374. {
  375. CornerRadius = new CornerRadius(0.0F, 0.0F, 0.0F, 0.0F),
  376. BorderThickness = new Thickness(1.0F),
  377. BorderBrush = SystemColors.WindowFrameBrush,
  378. Background = SystemColors.WindowBrush,
  379. Margin = new Thickness(5.0F, 0.0F, 5.0F, 5.0F),
  380. Padding = new Thickness(10.0F, 10.0F, 5.0F, 10.0F)
  381. };
  382. border.SetValue(Grid.RowProperty, 1);
  383. border.SetValue(Grid.ColumnProperty, MasterGrid.ColumnDefinitions.Count - 1);
  384. if (MasterGrid.ColumnDefinitions.Count > 2)
  385. {
  386. header.Margin = new Thickness(0.0F, 5.0F, 5.0F, 2.0F);
  387. border.Margin = new Thickness(0.0F, 0.0F, 5.0F, 5.0F);
  388. CollapseMargins();
  389. }
  390. MasterGrid.ColumnDefinitions.Insert(MasterGrid.ColumnDefinitions.Count - 1,
  391. new ColumnDefinition { Width = new GridLength(1F, GridUnitType.Star) });
  392. MasterGrid.Children.Add(border);
  393. var scroll = new ScrollViewer
  394. {
  395. VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
  396. HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
  397. Padding = new Thickness(0.0F, 0.0F, 5.0F, 0.0F)
  398. };
  399. border.Child = scroll;
  400. var grid = new Grid();
  401. var i = 1;
  402. if (!checks.Any())
  403. {
  404. var check = new QAQuestion
  405. {
  406. Answer = QAAnswer.Comment,
  407. Question = "There are no checks defined for this form",
  408. Parameters = ""
  409. };
  410. borders[check] = CreateCommentPanel(grid, check, values, i);
  411. }
  412. else
  413. {
  414. foreach (var check in checks)
  415. {
  416. Border element = null;
  417. if (check.Answer == QAAnswer.Comment)
  418. element = CreateCommentPanel(grid, check, values, i);
  419. else if (check.Answer == QAAnswer.Choice)
  420. element = CreateChoicePanel(grid, check, values, i++);
  421. else if (check.Answer == QAAnswer.Number)
  422. element = CreateNumberPanel(grid, check, values, i++);
  423. else if (check.Answer == QAAnswer.Text)
  424. element = CreateTextPanel(grid, check, values, i++);
  425. else if (check.Answer == QAAnswer.Combo)
  426. element = CreateComboPanel(grid, check, values, i++);
  427. if (element != null)
  428. borders[check] = element;
  429. }
  430. }
  431. scroll.Content = grid;
  432. }
  433. }
  434. }
  435. }