Advertisement
Guest User

Untitled

a guest
Aug 18th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.54 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using Qoden.Util;
  5. using Qoden.Validation;
  6.  
  7. namespace Qoden.UI
  8. {
  9. public enum LinearLayoutDirection
  10. {
  11. TopBottom, BottomTop, LeftRight, RightLeft
  12. }
  13.  
  14. /**
  15. * Layout builder performs layout in a coordinate system where
  16. * primary layout direction is positive X axis and overflow layout direction
  17. * is Y axis. Once done it performs reverse transform to get coordinates in
  18. * coordinate system associated with view.
  19. *
  20. **/
  21. /// <summary>
  22. /// Linear layout builder.
  23. /// </summary>
  24. public class LinearLayoutBuilder
  25. {
  26. RectangleF _layoutSpaceBounds, _layoutBounds, _originalBounds;
  27. PointF _layoutOrigin;
  28.  
  29. float _maxSize;
  30. Matrix2d _layoutToView, _viewToLayout;
  31. LayoutBuilder _layoutBuilder;
  32. List<IViewLayoutBox> _views = new List<IViewLayoutBox>();
  33.  
  34. public bool Flow { get; set; }
  35.  
  36. public LinearLayoutBuilder(LayoutBuilder layoutBuilder, LinearLayoutDirection layoutDirection, LinearLayoutDirection? flowDirection = null, RectangleF? bounds = null)
  37. {
  38. Assert.Argument(layoutBuilder, nameof(layoutBuilder)).NotNull();
  39. flowDirection = flowDirection ?? DefaultFlowDirection(layoutDirection);
  40. _layoutBuilder = layoutBuilder;
  41. _maxSize = 0;
  42. _originalBounds = bounds ?? _layoutBuilder.OuterBounds;
  43. _layoutBounds = new RectangleF(PointF.Empty, SizeF.Empty);
  44. _layoutToView = LayoutTransform(_originalBounds, layoutDirection, flowDirection.Value);
  45. _viewToLayout = _layoutToView.Inverted();
  46. _layoutSpaceBounds = _viewToLayout.Transform(_originalBounds);
  47. _layoutOrigin = _layoutSpaceBounds.Location;
  48. }
  49.  
  50. public IViewLayoutBox Add(LayoutParams layoutParams)
  51. {
  52. Assert.State(_layoutBuilder).NotNull("Layout is not started. Did you call StartLayout?");
  53.  
  54. var layoutResult = LayoutView(_layoutOrigin, ref layoutParams);
  55. var newLayoutOrigin = layoutResult.NewLayoutOrigin;
  56. if (Flow && newLayoutOrigin.X - LayoutStep > _layoutSpaceBounds.Right)
  57. {
  58. var nextLine = new PointF(_layoutSpaceBounds.X, _layoutOrigin.Y + _maxSize + FlowStep);
  59. layoutResult = LayoutView(nextLine, ref layoutParams);
  60. newLayoutOrigin = layoutResult.NewLayoutOrigin;
  61. if (newLayoutOrigin.X > _layoutSpaceBounds.Right)
  62. {
  63. newLayoutOrigin.X = _layoutSpaceBounds.X;
  64. newLayoutOrigin.Y = _layoutOrigin.Y + layoutResult.LayoutViewFrame.Height + FlowStep;
  65. }
  66. }
  67. _layoutBounds = RectangleF.Union(_layoutBounds, layoutResult.ViewLayoutBox.Frame());
  68. _maxSize = Math.Max(_maxSize, layoutResult.LayoutViewFrame.Height);
  69. _layoutOrigin = newLayoutOrigin;
  70.  
  71. return layoutResult.ViewLayoutBox;
  72. }
  73.  
  74. public RectangleF LayoutBounds => new RectangleF(_originalBounds.Location, _layoutBounds.Size);
  75.  
  76. public void AddOverflow()
  77. {
  78. _layoutOrigin = new PointF(_layoutSpaceBounds.X, _layoutOrigin.Y + _maxSize + FlowStep);
  79. _maxSize = 0;
  80. }
  81.  
  82. public float LayoutStep { get; set; } = 0;
  83. public float FlowStep { get; set; } = 0;
  84. public IEnumerable<IViewLayoutBox> Views => _views;
  85.  
  86. struct LayoutViewResult
  87. {
  88. public IViewLayoutBox ViewLayoutBox;
  89. public RectangleF LayoutViewFrame;
  90. public PointF NewLayoutOrigin;
  91. }
  92.  
  93. private LayoutViewResult LayoutView(PointF layoutOrigin, ref LayoutParams layoutParams)
  94. {
  95. var freeSpaceSize = new SizeF(_layoutSpaceBounds.Right - layoutOrigin.X, _layoutSpaceBounds.Bottom - layoutOrigin.Y);
  96. //Free space available a view in layout coordinates
  97. var freeSpace = new RectangleF(layoutOrigin, freeSpaceSize);
  98. //Free space available for a view in view coordinates
  99. var viewFreeSpace = _layoutToView.Transform(freeSpace);
  100. //Area which view wants to occupy in view coordinates
  101. var viewBox = _layoutBuilder.View(layoutParams.View, viewFreeSpace);
  102. _views.Add(viewBox);
  103. layoutParams.Layout(viewBox);
  104. //Area which view wants to occupy in layout coordinates
  105. var layoutFrame = _viewToLayout.Transform(viewBox.Frame());
  106. //Space required for view starting from layout origin in layout coordinates
  107. var viewFrame = new RectangleF(layoutOrigin, new SizeF(layoutFrame.Right - layoutOrigin.X, layoutFrame.Bottom - layoutOrigin.Y));
  108. var newLayoutOrigin = new PointF(viewFrame.Right + LayoutStep, viewFrame.Top);
  109.  
  110. return new LayoutViewResult()
  111. {
  112. ViewLayoutBox = viewBox,
  113. NewLayoutOrigin = newLayoutOrigin,
  114. LayoutViewFrame = viewFrame
  115. };
  116. }
  117.  
  118. /*
  119. * Calculates transform matrix from layout coordinate system to view coordinate system.
  120. */
  121. private static Matrix2d LayoutTransform(RectangleF bounds, LinearLayoutDirection layoutDirection, LinearLayoutDirection flowDirection)
  122. {
  123. switch (layoutDirection)
  124. {
  125. case LinearLayoutDirection.LeftRight:
  126. switch (flowDirection)
  127. {
  128. case LinearLayoutDirection.TopBottom:
  129. return new Matrix2d();
  130. case LinearLayoutDirection.BottomTop:
  131. return Matrix2d.Translation(0, bounds.Height) * Matrix2d.Stretch(1, -1);
  132. }
  133. break;
  134. case LinearLayoutDirection.RightLeft:
  135. switch (flowDirection)
  136. {
  137. case LinearLayoutDirection.TopBottom:
  138. return Matrix2d.Translation(bounds.Width, 0) * Matrix2d.Stretch(-1, 1);
  139. case LinearLayoutDirection.BottomTop:
  140. return Matrix2d.Translation(bounds.Width, bounds.Height) * Matrix2d.Stretch(-1, -1);
  141. }
  142. break;
  143. case LinearLayoutDirection.TopBottom:
  144. switch (flowDirection)
  145. {
  146. case LinearLayoutDirection.LeftRight:
  147. return Matrix2d.Rotation(90) * Matrix2d.Stretch(1, -1);
  148. case LinearLayoutDirection.RightLeft:
  149. return Matrix2d.Translation(bounds.Width, 0) * Matrix2d.Rotation(90);
  150. }
  151. break;
  152. case LinearLayoutDirection.BottomTop:
  153. switch (flowDirection)
  154. {
  155. case LinearLayoutDirection.LeftRight:
  156. return Matrix2d.Translation(0, bounds.Height) * Matrix2d.Rotation(-90);
  157. case LinearLayoutDirection.RightLeft:
  158. return Matrix2d.Translation(bounds.Width, bounds.Height) * Matrix2d.Stretch(-1, 1) * Matrix2d.Rotation(-90);
  159. }
  160. break;
  161. }
  162. var message = $"Layout direction {layoutDirection} is not compatible with flow direction {flowDirection}";
  163. throw new ArgumentException(message);
  164. }
  165.  
  166. private static LinearLayoutDirection DefaultFlowDirection(LinearLayoutDirection layoutDirection)
  167. {
  168. switch (layoutDirection)
  169. {
  170. case LinearLayoutDirection.LeftRight:
  171. return LinearLayoutDirection.TopBottom;
  172. case LinearLayoutDirection.TopBottom:
  173. return LinearLayoutDirection.LeftRight;
  174. case LinearLayoutDirection.RightLeft:
  175. return LinearLayoutDirection.TopBottom;
  176. case LinearLayoutDirection.BottomTop:
  177. return LinearLayoutDirection.LeftRight;
  178. default:
  179. throw new ArgumentException("Unknown layout direction");
  180. }
  181. }
  182. }
  183.  
  184. public struct LayoutParams
  185. {
  186. IViewGeometry _view;
  187. Action<IViewLayoutBox> _layout;
  188.  
  189. public LayoutParams(IViewGeometry view) : this(view, DefaultLayout)
  190. {
  191. }
  192.  
  193. public LayoutParams(IViewGeometry view, Action<IViewLayoutBox> layoutAction)
  194. {
  195. Assert.Argument(view, nameof(view)).NotNull();
  196. Assert.Argument(layoutAction, nameof(layoutAction)).NotNull();
  197. _view = view;
  198. _layout = layoutAction ?? DefaultLayout;
  199. }
  200.  
  201. public IViewGeometry View
  202. {
  203. get => _view;
  204. set
  205. {
  206. _view = Assert.Property(value).NotNull().Value;
  207. }
  208. }
  209.  
  210. public Action<IViewLayoutBox> Layout
  211. {
  212. get => _layout;
  213. set
  214. {
  215. Assert.Property(value).NotNull();
  216. _layout = value;
  217. }
  218. }
  219.  
  220. static void DefaultLayout(IViewLayoutBox obj)
  221. {
  222. obj.AutoSize().Left(0).Top(0);
  223. }
  224. }
  225.  
  226. public static class LinearLayoutBuilder_LayoutBuilder_Extensions
  227. {
  228. public static LinearLayoutBuilder LinearLayout(this LayoutBuilder layoutBuilder, LinearLayoutDirection layoutDirection, LinearLayoutDirection? flowDirection = null, RectangleF? bounds = null)
  229. {
  230. return new LinearLayoutBuilder(layoutBuilder, layoutDirection, flowDirection, bounds);
  231. }
  232. }
  233. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement