PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Main/LayoutDesigner/Panels/DragDropGrid.cs

#
C# | 536 lines | 464 code | 72 blank | 0 comment | 86 complexity | 236123e84ff5a37a3175665ff09104fc MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. namespace GuiLabs.LayoutDesigner
  7. {
  8. public class DragDropGrid : DragDropPanel
  9. {
  10. public readonly List<ColumnDefinition> ColumnDefinitions = new List<ColumnDefinition>();
  11. public readonly List<RowDefinition> RowDefinitions = new List<RowDefinition>();
  12. private double Spacing { get; set; }
  13. private double MinCellSize { get; set; }
  14. private double[] columns;
  15. private double[] rows;
  16. private Size[] childSizes;
  17. private readonly List<Rect> childPositions = new List<Rect>();
  18. public DragDropGrid()
  19. {
  20. Spacing = UI.Spacing;
  21. MinCellSize = Spacing;
  22. Background = Brushes.GridBackground;
  23. }
  24. protected override Size MeasureOverride(Size availableSize)
  25. {
  26. childSizes = new Size[this.Children.Count];
  27. for (int i = 0; i < childSizes.Length; i++)
  28. {
  29. this.Children[i].Measure(availableSize);
  30. childSizes[i] = this.Children[i].DesiredSize;
  31. }
  32. columns = new double[ColumnDefinitions.Count];
  33. for (int i = 0; i < ColumnDefinitions.Count; i++)
  34. {
  35. columns[i] = MinCellSize;
  36. }
  37. rows = new double[RowDefinitions.Count];
  38. for (int i = 0; i < RowDefinitions.Count; i++)
  39. {
  40. rows[i] = MinCellSize;
  41. }
  42. for (int i = 0; i < childSizes.Length; i++)
  43. {
  44. FrameworkElement child = this.Children[i] as FrameworkElement;
  45. if (child == null)
  46. {
  47. continue;
  48. }
  49. int column = Grid.GetColumn(child);
  50. int columnSpan = Grid.GetColumnSpan(child);
  51. if (columnSpan <= 1)
  52. {
  53. columns[column] = Math.Max(columns[column], childSizes[i].Width);
  54. }
  55. else
  56. {
  57. double width = (childSizes[i].Width - ((columnSpan - 1) * Spacing)) / columnSpan;
  58. for (int j = 0; j < columnSpan; j++)
  59. {
  60. columns[column + j] = Math.Max(columns[column + j], width);
  61. }
  62. }
  63. int row = Grid.GetRow(child);
  64. int rowSpan = Grid.GetRowSpan(child);
  65. if (rowSpan <= 1)
  66. {
  67. rows[row] = Math.Max(rows[row], childSizes[i].Height);
  68. }
  69. else
  70. {
  71. double height = (childSizes[i].Height - ((rowSpan - 1) * Spacing)) / rowSpan;
  72. for (int j = 0; j < rowSpan; j++)
  73. {
  74. rows[row + j] = Math.Max(rows[row + j], height);
  75. }
  76. }
  77. }
  78. var totalWidth = columns.Sum() + (columns.Length + 1) * Spacing;
  79. var totalHeight = rows.Sum() + (rows.Length + 1) * Spacing;
  80. return new Size(totalWidth, totalHeight);
  81. }
  82. protected override Size ArrangeOverride(Size finalSize)
  83. {
  84. MeasureOverride(finalSize);
  85. DistributeAvailableHorizontalSpace(finalSize);
  86. DistributeAvailableVerticalSpace(finalSize);
  87. double[] cellLeft = new double[columns.Length];
  88. double[] cellTop = new double[rows.Length];
  89. double totalWidth = Spacing;
  90. for (int i = 0; i < columns.Length; i++)
  91. {
  92. cellLeft[i] = totalWidth;
  93. totalWidth += columns[i] + Spacing;
  94. }
  95. double totalHeight = Spacing;
  96. for (int i = 0; i < rows.Length; i++)
  97. {
  98. cellTop[i] = totalHeight;
  99. totalHeight += rows[i] + Spacing;
  100. }
  101. childPositions.Clear();
  102. for (int i = 0; i < this.Children.Count; i++)
  103. {
  104. FrameworkElement child = this.Children[i] as FrameworkElement;
  105. if (child == null)
  106. {
  107. continue;
  108. }
  109. int column = Grid.GetColumn(child);
  110. int columnSpan = Grid.GetColumnSpan(child);
  111. int row = Grid.GetRow(child);
  112. int rowSpan = Grid.GetRowSpan(child);
  113. var childPosition = new Rect();
  114. childPosition.X = cellLeft[column];
  115. childPosition.Y = cellTop[row];
  116. childPosition.Width = GetAvailableWidth(column, columnSpan);
  117. childPosition.Height = GetAvailableHeight(row, rowSpan);
  118. childPositions.Add(childPosition);
  119. child.Arrange(childPosition);
  120. }
  121. return new Size(totalWidth, totalHeight);
  122. }
  123. private double GetAvailableWidth(int column, int columnSpan)
  124. {
  125. double result = 0;
  126. for (int i = 0; i < columnSpan; i++)
  127. {
  128. result += columns[column + i];
  129. }
  130. result += (columnSpan - 1) * Spacing;
  131. return result;
  132. }
  133. private double GetAvailableHeight(int row, int rowSpan)
  134. {
  135. double result = 0;
  136. for (int i = 0; i < rowSpan; i++)
  137. {
  138. result += rows[row + i];
  139. }
  140. result += (rowSpan - 1) * Spacing;
  141. return result;
  142. }
  143. private void DistributeAvailableHorizontalSpace(Size finalSize)
  144. {
  145. double extraWidth = finalSize.Width - DesiredSize.Width;
  146. if (extraWidth <= 0)
  147. {
  148. return;
  149. }
  150. double totalPie = 0;
  151. foreach (var columnDefinition in ColumnDefinitions)
  152. {
  153. if (columnDefinition.Width.IsStar)
  154. {
  155. totalPie += columnDefinition.Width.Value;
  156. }
  157. }
  158. if (totalPie == 0)
  159. {
  160. return;
  161. }
  162. for (int i = 0; i < columns.Length; i++)
  163. {
  164. var columnDefinition = ColumnDefinitions[i];
  165. if (columnDefinition.Width.IsStar)
  166. {
  167. columns[i] += extraWidth / totalPie * columnDefinition.Width.Value;
  168. }
  169. }
  170. }
  171. private void DistributeAvailableVerticalSpace(Size finalSize)
  172. {
  173. double extraHeight = finalSize.Height - DesiredSize.Height;
  174. if (extraHeight <= 0)
  175. {
  176. return;
  177. }
  178. double totalPie = 0;
  179. foreach (var rowDefinition in RowDefinitions)
  180. {
  181. if (rowDefinition.Height.IsStar)
  182. {
  183. totalPie += rowDefinition.Height.Value;
  184. }
  185. }
  186. if (totalPie == 0)
  187. {
  188. return;
  189. }
  190. for (int i = 0; i < rows.Length; i++)
  191. {
  192. var rowDefinition = RowDefinitions[i];
  193. if (rowDefinition.Height.IsStar)
  194. {
  195. rows[i] += extraHeight / totalPie * rowDefinition.Height.Value;
  196. }
  197. }
  198. }
  199. public override UIElement HitTest(Point point)
  200. {
  201. int i = 0;
  202. foreach (FrameworkElement child in Children)
  203. {
  204. if (childPositions[i].Contains(point))
  205. {
  206. return child;
  207. }
  208. i++;
  209. }
  210. return null;
  211. }
  212. public override IDropLocation GetDropLocation(Point cursor)
  213. {
  214. var dropTarget = GetDropLocationCore(cursor);
  215. return dropTarget;
  216. }
  217. private IDropLocation GetDropLocationCore(Point cursor)
  218. {
  219. IDropLocation dropTarget = null;
  220. if (DragManager.DraggedElement.IsElementInSubtree(this))
  221. {
  222. return null;
  223. }
  224. if (this.ColumnDefinitions.Count == 1
  225. && this.RowDefinitions.Count == 1
  226. && this.Children.Count == 1
  227. && this.Children[0] is ContentPanel
  228. && (this.Children[0] as ContentPanel).Children.Count == 0)
  229. {
  230. return null;
  231. }
  232. Tuple<int, PointSituationRelativeToRect, double> columnInfo = GetColumn(cursor);
  233. Tuple<int, PointSituationRelativeToRect, double> rowInfo = GetRow(cursor);
  234. if (rowInfo.Item2 == PointSituationRelativeToRect.Fill
  235. && (columnInfo.Item2 == PointSituationRelativeToRect.Before || columnInfo.Item2 == PointSituationRelativeToRect.After))
  236. {
  237. Rect rect = new Rect();
  238. rect.X = columnInfo.Item3;
  239. rect.Y = rowInfo.Item3;
  240. rect.Width = Spacing;
  241. rect.Height = rows[rowInfo.Item1];
  242. rect = GetMarkerCoordinates(rect);
  243. dropTarget = new InsertColumnGridDropLocation(
  244. this,
  245. columnInfo.Item1,
  246. rowInfo.Item1,
  247. columnInfo.Item2 == PointSituationRelativeToRect.After,
  248. rect);
  249. return dropTarget;
  250. }
  251. if (columnInfo.Item2 == PointSituationRelativeToRect.Fill
  252. && (rowInfo.Item2 == PointSituationRelativeToRect.Before || rowInfo.Item2 == PointSituationRelativeToRect.After))
  253. {
  254. Rect rect = new Rect();
  255. rect.X = columnInfo.Item3;
  256. rect.Y = rowInfo.Item3;
  257. rect.Width = columns[columnInfo.Item1];
  258. rect.Height = Spacing;
  259. rect = GetMarkerCoordinates(rect);
  260. dropTarget = new InsertRowGridDropLocation(
  261. this,
  262. columnInfo.Item1,
  263. rowInfo.Item1,
  264. rowInfo.Item2 == PointSituationRelativeToRect.After,
  265. rect);
  266. return dropTarget;
  267. }
  268. return dropTarget;
  269. }
  270. private Tuple<int, PointSituationRelativeToRect, double> GetColumn(Point cursor)
  271. {
  272. double total = Spacing;
  273. for (int i = 0; i < columns.Length; i++)
  274. {
  275. if (cursor.X < total)
  276. {
  277. return Tuple.Create(i, PointSituationRelativeToRect.Before, total - Spacing);
  278. }
  279. total += columns[i];
  280. if (cursor.X < total)
  281. {
  282. return Tuple.Create(i, PointSituationRelativeToRect.Fill, total - columns[i]);
  283. }
  284. total += Spacing;
  285. }
  286. return Tuple.Create(columns.Length - 1, PointSituationRelativeToRect.After, total - Spacing);
  287. }
  288. private Tuple<int, PointSituationRelativeToRect, double> GetRow(Point cursor)
  289. {
  290. double total = Spacing;
  291. for (int i = 0; i < rows.Length; i++)
  292. {
  293. if (cursor.Y < total)
  294. {
  295. return Tuple.Create(i, PointSituationRelativeToRect.Before, total - Spacing);
  296. }
  297. total += rows[i];
  298. if (cursor.Y < total)
  299. {
  300. return Tuple.Create(i, PointSituationRelativeToRect.Fill, total - rows[i]);
  301. }
  302. total += Spacing;
  303. }
  304. return Tuple.Create(rows.Length - 1, PointSituationRelativeToRect.After, total - Spacing);
  305. }
  306. private Rect GetMarkerCoordinates(Rect rect)
  307. {
  308. var transform = this.TransformToVisual(Designer.Instance.Canvas);
  309. rect = transform.TransformBounds(rect);
  310. return rect;
  311. }
  312. public ContentPanel FindContentPanel(int column, int row)
  313. {
  314. foreach (FrameworkElement child in this.Children)
  315. {
  316. int childColumn = Grid.GetColumn(child);
  317. int childRow = Grid.GetRow(child);
  318. if (column == childColumn && row == childRow)
  319. {
  320. var contentPanel = child as ContentPanel;
  321. return contentPanel;
  322. }
  323. }
  324. return null;
  325. }
  326. public int FindEmptyRow()
  327. {
  328. bool[,] matrix = GetOccupancyMatrixExcludingEmptyContentPanels();
  329. for (int j = this.RowDefinitions.Count - 1; j >= 0; j--)
  330. {
  331. bool allZeros = true;
  332. for (int i = 0; i < this.ColumnDefinitions.Count; i++)
  333. {
  334. if (matrix[i, j])
  335. {
  336. allZeros = false;
  337. }
  338. }
  339. if (allZeros)
  340. {
  341. return j;
  342. }
  343. }
  344. return -1;
  345. }
  346. public int FindEmptyColumn()
  347. {
  348. bool[,] matrix = GetOccupancyMatrixExcludingEmptyContentPanels();
  349. for (int i = this.ColumnDefinitions.Count - 1; i >= 0; i--)
  350. {
  351. bool allZeros = true;
  352. for (int j = 0; j < this.RowDefinitions.Count; j++)
  353. {
  354. if (matrix[i, j])
  355. {
  356. allZeros = false;
  357. }
  358. }
  359. if (allZeros)
  360. {
  361. return i;
  362. }
  363. }
  364. return -1;
  365. }
  366. public void InsertColumnDefinitionCore(ColumnDefinition columnDefinition, int columnIndex)
  367. {
  368. foreach (FrameworkElement child in this.Children)
  369. {
  370. int childColumn = Grid.GetColumn(child);
  371. if (childColumn >= columnIndex)
  372. {
  373. Grid.SetColumn(child, childColumn + 1);
  374. }
  375. }
  376. this.ColumnDefinitions.Insert(columnIndex, columnDefinition);
  377. for (int i = 0; i < this.RowDefinitions.Count; i++)
  378. {
  379. ContentPanel cell = new ContentPanel();
  380. Grid.SetColumn(cell, columnIndex);
  381. Grid.SetRow(cell, i);
  382. this.Children.Add(cell);
  383. }
  384. }
  385. public void RemoveColumnDefinitionCore(int columnIndex)
  386. {
  387. this.ColumnDefinitions.RemoveAt(columnIndex);
  388. foreach (FrameworkElement child in this.Children.ToArray())
  389. {
  390. int childColumn = Grid.GetColumn(child);
  391. if (childColumn == columnIndex)
  392. {
  393. this.Children.Remove(child);
  394. }
  395. if (childColumn > columnIndex)
  396. {
  397. Grid.SetColumn(child, childColumn - 1);
  398. }
  399. }
  400. }
  401. public void InsertRowDefinitionCore(RowDefinition rowDefinition, int rowIndex)
  402. {
  403. foreach (FrameworkElement child in this.Children)
  404. {
  405. int childRow = Grid.GetRow(child);
  406. if (childRow >= rowIndex)
  407. {
  408. Grid.SetRow(child, childRow + 1);
  409. }
  410. }
  411. this.RowDefinitions.Insert(rowIndex, rowDefinition);
  412. for (int i = 0; i < this.ColumnDefinitions.Count; i++)
  413. {
  414. ContentPanel cell = new ContentPanel();
  415. Grid.SetColumn(cell, i);
  416. Grid.SetRow(cell, rowIndex);
  417. this.Children.Add(cell);
  418. }
  419. }
  420. public void RemoveRowDefinitionCore(int rowIndex)
  421. {
  422. this.RowDefinitions.RemoveAt(rowIndex);
  423. foreach (FrameworkElement child in this.Children.ToArray())
  424. {
  425. int childRow = Grid.GetRow(child);
  426. if (childRow == rowIndex)
  427. {
  428. this.Children.Remove(child);
  429. }
  430. if (childRow > rowIndex)
  431. {
  432. Grid.SetRow(child, childRow - 1);
  433. }
  434. }
  435. }
  436. private bool[,] GetOccupancyMatrixExcludingEmptyContentPanels()
  437. {
  438. bool[,] matrix = new bool[this.ColumnDefinitions.Count, this.RowDefinitions.Count];
  439. foreach (FrameworkElement child in this.Children)
  440. {
  441. ContentPanel contentPanel = child as ContentPanel;
  442. if (contentPanel != null && contentPanel.Children.Count == 0)
  443. {
  444. continue;
  445. }
  446. int column = Grid.GetColumn(child);
  447. int row = Grid.GetRow(child);
  448. matrix[column, row] = true;
  449. }
  450. return matrix;
  451. }
  452. private bool[,] GetOccupancyMatrix()
  453. {
  454. bool[,] matrix = new bool[this.ColumnDefinitions.Count, this.RowDefinitions.Count];
  455. foreach (FrameworkElement child in this.Children)
  456. {
  457. int column = Grid.GetColumn(child);
  458. int row = Grid.GetRow(child);
  459. matrix[column, row] = true;
  460. }
  461. return matrix;
  462. }
  463. }
  464. }