LayoutUtils.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. namespace Microsoft.Windows.Forms.Layout
  5. {
  6. /// <summary>
  7. /// 布局工具类
  8. /// </summary>
  9. public static class LayoutUtils
  10. {
  11. /// <summary>
  12. /// <para>0*****1*****2</para>
  13. /// <para>* *</para>
  14. /// <para>* *</para>
  15. /// <para>4 5 6</para>
  16. /// <para>* *</para>
  17. /// <para>* *</para>
  18. /// <para>8*****9*****10</para>
  19. /// <para>获取对齐方式的索引,如上图</para>
  20. /// </summary>
  21. /// <param name="alignment">对齐方式</param>
  22. /// <returns>索引</returns>
  23. public static int ContentAlignmentToIndex(ContentAlignment alignment)
  24. {
  25. int num = xContentAlignmentToIndex(((int)alignment) & 15);//取0-3位,如果等于4返回3,其余不变
  26. int num2 = xContentAlignmentToIndex((((int)alignment) >> 4) & 15);//4-7,如果等于4返回3,其余不变
  27. int num3 = xContentAlignmentToIndex((((int)alignment) >> 8) & 15);//8-11,如果等于4返回3,其余不变
  28. int num4 = (((((num2 != 0) ? 4 : 0) | ((num3 != 0) ? 8 : 0)) | num) | num2) | num3;
  29. num4--;
  30. return num4;
  31. }
  32. /// <summary>
  33. /// 上面方法的辅助
  34. /// </summary>
  35. /// <param name="threeBitFlag">4bit数字</param>
  36. /// <returns>如果等于4返回3,其余不变</returns>
  37. private static byte xContentAlignmentToIndex(int threeBitFlag)
  38. {
  39. return ((threeBitFlag == 4) ? ((byte)3) : ((byte)threeBitFlag));
  40. }
  41. /// <summary>
  42. /// 获取反向的文本图片相对位置
  43. /// </summary>
  44. /// <param name="relation">文本图片相对位置</param>
  45. /// <returns>反向的文本图片相对位置</returns>
  46. public static TextImageRelation GetOppositeTextImageRelation(TextImageRelation relation)
  47. {
  48. return (TextImageRelation)GetOppositeAnchor((AnchorStyles)relation);
  49. }
  50. /// <summary>
  51. /// 获取反向的锚定方式
  52. /// </summary>
  53. /// <param name="anchor">锚定方式</param>
  54. /// <returns>反向的锚定方式</returns>
  55. private static AnchorStyles GetOppositeAnchor(AnchorStyles anchor)
  56. {
  57. AnchorStyles none = AnchorStyles.None;
  58. if (anchor != AnchorStyles.None)
  59. {
  60. for (int i = 1; i <= 8; i = i << 1)
  61. {
  62. switch ((anchor & (AnchorStyles)i))
  63. {
  64. case AnchorStyles.Top:
  65. none |= AnchorStyles.Bottom;
  66. break;
  67. case AnchorStyles.Bottom:
  68. none |= AnchorStyles.Top;
  69. break;
  70. case AnchorStyles.Left:
  71. none |= AnchorStyles.Right;
  72. break;
  73. case AnchorStyles.Right:
  74. none |= AnchorStyles.Left;
  75. break;
  76. }
  77. }
  78. }
  79. return none;
  80. }
  81. /// <summary>
  82. /// 在矩形指定位置划出指定大小的区域
  83. /// </summary>
  84. /// <param name="size">大小</param>
  85. /// <param name="rect">矩形</param>
  86. /// <param name="align">对齐方式</param>
  87. /// <returns>划定区域</returns>
  88. public static Rectangle Align(Size size, Rectangle rect, ContentAlignment align)
  89. {
  90. return VAlign(size, HAlign(size, rect, align), align);
  91. }
  92. /// <summary>
  93. /// 调整X坐标和宽度,使宽度为size的宽度,在水平方向上移动对齐到矩形
  94. /// </summary>
  95. /// <param name="size">大小</param>
  96. /// <param name="rect">矩形</param>
  97. /// <param name="align">水平对齐方式</param>
  98. /// <returns>新矩形</returns>
  99. public static Rectangle HAlign(Size size, Rectangle rect, ContentAlignment align)
  100. {
  101. if ((align & (ContentAlignment.BottomRight | ContentAlignment.MiddleRight | ContentAlignment.TopRight)) != ((ContentAlignment)0))
  102. {
  103. rect.X += rect.Width - size.Width;
  104. }
  105. else if ((align & (ContentAlignment.BottomCenter | ContentAlignment.MiddleCenter | ContentAlignment.TopCenter)) != ((ContentAlignment)0))
  106. {
  107. rect.X += (rect.Width - size.Width) / 2;
  108. }
  109. rect.Width = size.Width;
  110. return rect;
  111. }
  112. /// <summary>
  113. /// 调整Y坐标和高度,使高度为size的高度,在垂直方向上移动对齐到矩形
  114. /// </summary>
  115. /// <param name="size">大小</param>
  116. /// <param name="rect">矩形</param>
  117. /// <param name="align">垂直对齐方式</param>
  118. /// <returns>新矩形</returns>
  119. public static Rectangle VAlign(Size size, Rectangle rect, ContentAlignment align)
  120. {
  121. if ((align & (ContentAlignment.BottomRight | ContentAlignment.BottomCenter | ContentAlignment.BottomLeft)) != ((ContentAlignment)0))
  122. {
  123. rect.Y += rect.Height - size.Height;
  124. }
  125. else if ((align & (ContentAlignment.MiddleRight | ContentAlignment.MiddleCenter | ContentAlignment.MiddleLeft)) != ((ContentAlignment)0))
  126. {
  127. rect.Y += (rect.Height - size.Height) / 2;
  128. }
  129. rect.Height = size.Height;
  130. return rect;
  131. }
  132. /// <summary>
  133. /// 在矩形指定位置划出指定大小的区域
  134. /// </summary>
  135. /// <param name="size">大小</param>
  136. /// <param name="rect">矩形</param>
  137. /// <param name="align">对齐方式</param>
  138. /// <returns>划定区域</returns>
  139. public static RectangleF Align(SizeF size, RectangleF rect, ContentAlignment align)
  140. {
  141. return VAlign(size, HAlign(size, rect, align), align);
  142. }
  143. /// <summary>
  144. /// 调整X坐标和宽度,使宽度为size的宽度,在水平方向上移动对齐到矩形
  145. /// </summary>
  146. /// <param name="size">大小</param>
  147. /// <param name="rect">矩形</param>
  148. /// <param name="align">水平对齐方式</param>
  149. /// <returns>新矩形</returns>
  150. public static RectangleF HAlign(SizeF size, RectangleF rect, ContentAlignment align)
  151. {
  152. if ((align & (ContentAlignment.BottomRight | ContentAlignment.MiddleRight | ContentAlignment.TopRight)) != ((ContentAlignment)0))
  153. {
  154. rect.X += rect.Width - size.Width;
  155. }
  156. else if ((align & (ContentAlignment.BottomCenter | ContentAlignment.MiddleCenter | ContentAlignment.TopCenter)) != ((ContentAlignment)0))
  157. {
  158. rect.X += (rect.Width - size.Width) / 2f;
  159. }
  160. rect.Width = size.Width;
  161. return rect;
  162. }
  163. /// <summary>
  164. /// 调整Y坐标和高度,使高度为size的高度,在垂直方向上移动对齐到矩形
  165. /// </summary>
  166. /// <param name="size">大小</param>
  167. /// <param name="rect">矩形</param>
  168. /// <param name="align">垂直对齐方式</param>
  169. /// <returns>新矩形</returns>
  170. public static RectangleF VAlign(SizeF size, RectangleF rect, ContentAlignment align)
  171. {
  172. if ((align & (ContentAlignment.BottomRight | ContentAlignment.BottomCenter | ContentAlignment.BottomLeft)) != ((ContentAlignment)0))
  173. {
  174. rect.Y += rect.Height - size.Height;
  175. }
  176. else if ((align & (ContentAlignment.MiddleRight | ContentAlignment.MiddleCenter | ContentAlignment.MiddleLeft)) != ((ContentAlignment)0))
  177. {
  178. rect.Y += (rect.Height - size.Height) / 2f;
  179. }
  180. rect.Height = size.Height;
  181. return rect;
  182. }
  183. /// <summary>
  184. /// 调整X坐标和宽度,使宽度为size的宽度,在水平方向上移动对齐到矩形
  185. /// </summary>
  186. /// <param name="size">大小</param>
  187. /// <param name="rect">矩形</param>
  188. /// <param name="align">水平对齐方式</param>
  189. /// <returns>新矩形</returns>
  190. public static Rectangle HAlign(Size size, Rectangle rect, HorizontalAlignment align)
  191. {
  192. if ((align & HorizontalAlignment.Right) != 0)
  193. {
  194. rect.X += rect.Width - size.Width;
  195. }
  196. else if ((align & HorizontalAlignment.Center) != 0)
  197. {
  198. rect.X += (rect.Width - size.Width) / 2;
  199. }
  200. rect.Width = size.Width;
  201. return rect;
  202. }
  203. /// <summary>
  204. /// 调整X坐标和宽度,使宽度为size的宽度,在水平方向上移动对齐到矩形
  205. /// </summary>
  206. /// <param name="size">大小</param>
  207. /// <param name="rect">矩形</param>
  208. /// <param name="align">水平对齐方式</param>
  209. /// <returns>新矩形</returns>
  210. public static RectangleF HAlign(SizeF size, RectangleF rect, HorizontalAlignment align)
  211. {
  212. if ((align & HorizontalAlignment.Right) != 0)
  213. {
  214. rect.X += rect.Width - size.Width;
  215. }
  216. else if ((align & HorizontalAlignment.Center) != 0)
  217. {
  218. rect.X += (rect.Width - size.Width) / 2f;
  219. }
  220. rect.Width = size.Width;
  221. return rect;
  222. }
  223. /// <summary>
  224. /// 从容器大小中减去指定大小by关系.重叠关系(需要预先手动排除)
  225. /// </summary>
  226. /// <param name="containerSize">容器大小</param>
  227. /// <param name="contentSize">内容大小</param>
  228. /// <param name="relation">容器内容关系</param>
  229. /// <returns>新大小</returns>
  230. public static Size SubAlignedRegion(Size containerSize, Size contentSize, TextImageRelation relation)
  231. {
  232. return SubAlignedRegionCore(containerSize, contentSize, IsVerticalRelation(relation));
  233. }
  234. /// <summary>
  235. /// 从容器大小中减去指定大小by是否上下关系.重叠关系(需要预先手动排除)
  236. /// </summary>
  237. /// <param name="containerSize">容器大小</param>
  238. /// <param name="contentSize">内容大小</param>
  239. /// <param name="vertical">是否垂直关系</param>
  240. /// <returns>新大小</returns>
  241. public static Size SubAlignedRegionCore(Size containerSize, Size contentSize, bool vertical)
  242. {
  243. if (vertical)
  244. {
  245. containerSize.Height -= contentSize.Height;
  246. }
  247. else
  248. {
  249. containerSize.Width -= contentSize.Width;
  250. }
  251. return containerSize;
  252. }
  253. /// <summary>
  254. /// 是否垂直关系
  255. /// </summary>
  256. /// <param name="relation">文本图片相对位置</param>
  257. /// <returns>是垂直关系返回true,否则返回false</returns>
  258. public static bool IsVerticalRelation(TextImageRelation relation)
  259. {
  260. return ((relation & (TextImageRelation.TextAboveImage | TextImageRelation.ImageAboveText)) != TextImageRelation.Overlay);
  261. }
  262. /// <summary>
  263. /// 两个大小相加,by关系.重叠关系(需要预先手动排除)
  264. /// </summary>
  265. /// <param name="contentSize1">内容大小1</param>
  266. /// <param name="contentSize2">内容大小2</param>
  267. /// <param name="relation">两个内容关系</param>
  268. /// <returns>新大小</returns>
  269. public static Size AddAlignedRegion(Size contentSize1, Size contentSize2, TextImageRelation relation)
  270. {
  271. return AddAlignedRegionCore(contentSize1, contentSize2, IsVerticalRelation(relation));
  272. }
  273. /// <summary>
  274. /// 两个大小相加,by是否上下关系.重叠关系(需要预先手动排除)
  275. /// </summary>
  276. /// <param name="contentSize1">内容大小1</param>
  277. /// <param name="contentSize2">内容大小2</param>
  278. /// <param name="vertical">是否吹关系</param>
  279. /// <returns>新大小</returns>
  280. public static Size AddAlignedRegionCore(Size contentSize1, Size contentSize2, bool vertical)
  281. {
  282. if (vertical)
  283. {
  284. contentSize1.Width = Math.Max(contentSize1.Width, contentSize2.Width);
  285. contentSize1.Height += contentSize2.Height;
  286. }
  287. else
  288. {
  289. contentSize1.Width += contentSize2.Width;
  290. contentSize1.Height = Math.Max(contentSize1.Height, contentSize2.Height);
  291. }
  292. return contentSize1;
  293. }
  294. /// <summary>
  295. /// 获取两个重叠的Size的最小容器的大小
  296. /// </summary>
  297. /// <param name="a">大小1</param>
  298. /// <param name="b">大小2</param>
  299. /// <returns>容器大小</returns>
  300. public static Size UnionSizes(Size a, Size b)
  301. {
  302. return new Size(Math.Max(a.Width, b.Width), Math.Max(a.Height, b.Height));
  303. }
  304. /// <summary>
  305. /// 按锚定方式分割矩形
  306. /// </summary>
  307. /// <param name="bounds">要被分割的矩形</param>
  308. /// <param name="contentSize">内容大小</param>
  309. /// <param name="anchor">锚定方式</param>
  310. /// <param name="region1">第一个矩形</param>
  311. /// <param name="region2">第二个矩形</param>
  312. public static void SplitRegion(Rectangle bounds, Size contentSize, AnchorStyles anchor, out Rectangle region1, out Rectangle region2)
  313. {
  314. region1 = region2 = bounds;
  315. switch (anchor)
  316. {
  317. case AnchorStyles.Top:
  318. region1.Height = contentSize.Height;
  319. region2.Y += contentSize.Height;
  320. region2.Height -= contentSize.Height;
  321. return;
  322. case AnchorStyles.Bottom:
  323. region1.Y += bounds.Height - contentSize.Height;
  324. region1.Height = contentSize.Height;
  325. region2.Height -= contentSize.Height;
  326. break;
  327. case (AnchorStyles.Bottom | AnchorStyles.Top):
  328. break;
  329. case AnchorStyles.Left:
  330. region1.Width = contentSize.Width;
  331. region2.X += contentSize.Width;
  332. region2.Width -= contentSize.Width;
  333. return;
  334. case AnchorStyles.Right:
  335. region1.X += bounds.Width - contentSize.Width;
  336. region1.Width = contentSize.Width;
  337. region2.Width -= contentSize.Width;
  338. return;
  339. default:
  340. return;
  341. }
  342. }
  343. /// <summary>
  344. /// 将region2按anchor锚定到bounds,将region1按反转的anchor锚定到bounds
  345. /// </summary>
  346. /// <param name="bounds">容器矩形</param>
  347. /// <param name="anchor">锚定方式</param>
  348. /// <param name="region1">矩形1</param>
  349. /// <param name="region2">矩形2</param>
  350. public static void ExpandRegionsToFillBounds(Rectangle bounds, AnchorStyles anchor, ref Rectangle region1, ref Rectangle region2)
  351. {
  352. switch (anchor)
  353. {
  354. case AnchorStyles.Top:
  355. region1 = SubstituteSpecifiedBounds(bounds, region1, AnchorStyles.Bottom);
  356. region2 = SubstituteSpecifiedBounds(bounds, region2, AnchorStyles.Top);
  357. return;
  358. case AnchorStyles.Bottom:
  359. region1 = SubstituteSpecifiedBounds(bounds, region1, AnchorStyles.Top);
  360. region2 = SubstituteSpecifiedBounds(bounds, region2, AnchorStyles.Bottom);
  361. break;
  362. case (AnchorStyles.Bottom | AnchorStyles.Top):
  363. break;
  364. case AnchorStyles.Left:
  365. region1 = SubstituteSpecifiedBounds(bounds, region1, AnchorStyles.Right);
  366. region2 = SubstituteSpecifiedBounds(bounds, region2, AnchorStyles.Left);
  367. return;
  368. case AnchorStyles.Right:
  369. region1 = SubstituteSpecifiedBounds(bounds, region1, AnchorStyles.Left);
  370. region2 = SubstituteSpecifiedBounds(bounds, region2, AnchorStyles.Right);
  371. return;
  372. default:
  373. return;
  374. }
  375. }
  376. /// <summary>
  377. /// 锚定内容矩形到容器矩形
  378. /// </summary>
  379. /// <param name="containerBounds">容器矩形</param>
  380. /// <param name="contentBounds">内容矩形</param>
  381. /// <param name="anchor">锚定方式</param>
  382. /// <returns>新矩形</returns>
  383. private static Rectangle SubstituteSpecifiedBounds(Rectangle containerBounds, Rectangle contentBounds, AnchorStyles anchor)
  384. {
  385. int left = ((anchor & AnchorStyles.Left) != AnchorStyles.None) ? contentBounds.Left : containerBounds.Left;
  386. int top = ((anchor & AnchorStyles.Top) != AnchorStyles.None) ? contentBounds.Top : containerBounds.Top;
  387. int right = ((anchor & AnchorStyles.Right) != AnchorStyles.None) ? contentBounds.Right : containerBounds.Right;
  388. int bottom = ((anchor & AnchorStyles.Bottom) != AnchorStyles.None) ? contentBounds.Bottom : containerBounds.Bottom;
  389. return Rectangle.FromLTRB(left, top, right, bottom);
  390. }
  391. }
  392. }