HoneycombPanel.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. namespace HandyControl.Controls;
  5. public class HoneycombPanel : Panel
  6. {
  7. private double _unitLength;
  8. private HoneycombStuffer _stuffer;
  9. private static int GetXCount(int count)
  10. {
  11. if (count == 0) return 0;
  12. count -= 1;
  13. var index = (int) Math.Floor(Math.Pow((12.0 * count + 25) / 36, 0.5) - 5.0 / 6);
  14. var valeIndex = 3 * index * index + 5 * index;
  15. var centerValue = valeIndex + 2;
  16. return count >= centerValue
  17. ? 4 * index + 6
  18. : count > valeIndex
  19. ? 4 * index + 4
  20. : 4 * index + 2;
  21. }
  22. private static int GetYCount(int count)
  23. {
  24. if (count == 0) return 0;
  25. count -= 1;
  26. var index = (int) Math.Floor(Math.Pow(count / 3.0 + 0.25, 0.5) - 0.5);
  27. var valeIndex = 3 * index * index + 3 * index;
  28. return count > valeIndex
  29. ? 2 * index + 2
  30. : 2 * index;
  31. }
  32. /*
  33. * layout order
  34. *
  35. * ● ●
  36. * (7) (8)
  37. *
  38. * ● ● ●
  39. * (6) (1) (9)
  40. *
  41. * ● ● ● ...
  42. * (5) (0) (2)
  43. *
  44. * ● ● ...
  45. * (4) (3)
  46. *
  47. */
  48. protected override Size MeasureOverride(Size availableSize)
  49. {
  50. var maxSize = new Size();
  51. foreach (UIElement child in InternalChildren)
  52. {
  53. if (child != null)
  54. {
  55. child.Measure(availableSize);
  56. maxSize.Width = Math.Max(maxSize.Width, child.DesiredSize.Width);
  57. maxSize.Height = Math.Max(maxSize.Height, child.DesiredSize.Height);
  58. }
  59. }
  60. _unitLength = Math.Max(maxSize.Width, maxSize.Height) / 2;
  61. var xCount = GetXCount(InternalChildren.Count);
  62. var yCount = GetYCount(InternalChildren.Count);
  63. var availableWidth = xCount * _unitLength;
  64. var availableHeight = yCount * Math.Pow(3, 0.5) * _unitLength + _unitLength * 2;
  65. return new Size(availableWidth, availableHeight);
  66. }
  67. protected override Size ArrangeOverride(Size finalSize)
  68. {
  69. var childLength = _unitLength * 2;
  70. _stuffer = new HoneycombStuffer(new Rect(finalSize.Width / 2 - _unitLength,
  71. finalSize.Height / 2 - _unitLength, childLength, childLength));
  72. foreach (UIElement child in InternalChildren)
  73. {
  74. child.Arrange(_stuffer.Move());
  75. }
  76. return finalSize;
  77. }
  78. private class HoneycombStuffer
  79. {
  80. private int _turns;
  81. private int _maxIndex;
  82. private int _currentIndex = -1;
  83. private readonly double _offsetX;
  84. private readonly double _offsetY;
  85. private Rect _childBounds;
  86. private readonly double[] _offsetXArr;
  87. private readonly double[] _offsetYArr;
  88. public HoneycombStuffer(Rect childBounds)
  89. {
  90. _childBounds = childBounds;
  91. _offsetX = childBounds.Width / 2;
  92. _offsetY = Math.Pow(3, 0.5) * _offsetX;
  93. _offsetXArr = new[]
  94. {
  95. 2 * _offsetX,
  96. _offsetX,
  97. -_offsetX,
  98. -2 * _offsetX,
  99. -_offsetX,
  100. _offsetX
  101. };
  102. _offsetYArr = new[]
  103. {
  104. 0,
  105. _offsetY,
  106. _offsetY,
  107. 0,
  108. -_offsetY,
  109. -_offsetY
  110. };
  111. }
  112. public Rect Move()
  113. {
  114. _currentIndex++;
  115. if (_currentIndex > _maxIndex)
  116. {
  117. _turns++;
  118. _maxIndex = _turns * 6 - 1;
  119. _currentIndex = 0;
  120. _childBounds.Offset(_offsetX, -_offsetY);
  121. return _childBounds;
  122. }
  123. if (_turns > 0)
  124. {
  125. var index = _currentIndex / _turns;
  126. _childBounds.Offset(_offsetXArr[index], _offsetYArr[index]);
  127. }
  128. return _childBounds;
  129. }
  130. }
  131. }