LayoutOptions.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. using System;
  2. using System.Drawing;
  3. using System.Drawing.Text;
  4. using System.Windows.Forms;
  5. namespace Microsoft.Windows.Forms.Layout
  6. {
  7. /// <summary>
  8. /// 布局操作类
  9. /// </summary>
  10. public static class LayoutOptions
  11. {
  12. private static TextImageRelation[] m_ImageAlignToRelation;//图片对齐方式转换为文本图片相对位置所需数组
  13. private static ContentAlignment[][] m_RtlTranslateAlignment;//左右反转样式翻译对齐方式所需数组
  14. /// <summary>
  15. /// 静态构造,初始化字段
  16. /// </summary>
  17. static LayoutOptions()
  18. {
  19. TextImageRelation[] relationArray = new TextImageRelation[11];
  20. relationArray[0] = TextImageRelation.ImageBeforeText | TextImageRelation.ImageAboveText;
  21. relationArray[1] = TextImageRelation.ImageAboveText;
  22. relationArray[2] = TextImageRelation.TextBeforeImage | TextImageRelation.ImageAboveText;
  23. relationArray[4] = TextImageRelation.ImageBeforeText;
  24. relationArray[6] = TextImageRelation.TextBeforeImage;
  25. relationArray[8] = TextImageRelation.ImageBeforeText | TextImageRelation.TextAboveImage;
  26. relationArray[9] = TextImageRelation.TextAboveImage;
  27. relationArray[10] = TextImageRelation.TextBeforeImage | TextImageRelation.TextAboveImage;
  28. m_ImageAlignToRelation = relationArray;
  29. m_RtlTranslateAlignment = new ContentAlignment[][]
  30. {
  31. new ContentAlignment[] { ContentAlignment.TopLeft, ContentAlignment.TopRight },
  32. new ContentAlignment[] { ContentAlignment.MiddleLeft, ContentAlignment.MiddleRight },
  33. new ContentAlignment[] { ContentAlignment.BottomLeft, ContentAlignment.BottomRight }
  34. };
  35. }
  36. /// <summary>
  37. /// Rtl翻译Align
  38. /// </summary>
  39. /// <param name="align">要被翻译的对齐方式</param>
  40. /// <param name="rtl">左右反转样式</param>
  41. /// <returns>翻译后的对齐方式</returns>
  42. public static ContentAlignment RtlTranslateAlignment(ContentAlignment align, RightToLeft rtl)
  43. {
  44. if (rtl == RightToLeft.Yes)
  45. {
  46. for (int i = 0; i < 3; i++)
  47. {
  48. if (m_RtlTranslateAlignment[i][0] == align)
  49. return m_RtlTranslateAlignment[i][1];
  50. if (m_RtlTranslateAlignment[i][1] == align)
  51. return m_RtlTranslateAlignment[i][0];
  52. }
  53. }
  54. return align;
  55. }
  56. /// <summary>
  57. /// Rtl翻译Relation
  58. /// </summary>
  59. /// <param name="relation">文本图片相对位置</param>
  60. /// <param name="rtl">左右反转样式</param>
  61. /// <returns>翻译后的文本图片相对位置</returns>
  62. public static TextImageRelation RtlTranslateRelation(TextImageRelation relation, RightToLeft rtl)
  63. {
  64. if (rtl == RightToLeft.Yes)
  65. {
  66. if (relation == TextImageRelation.ImageBeforeText)
  67. return TextImageRelation.TextBeforeImage;
  68. if (relation == TextImageRelation.TextBeforeImage)
  69. return TextImageRelation.ImageBeforeText;
  70. }
  71. return relation;
  72. }
  73. /// <summary>
  74. /// 图片对齐方式转换为文本图片相对位置
  75. /// </summary>
  76. /// <param name="align">图片对齐方式</param>
  77. /// <returns>文本图片相对位置</returns>
  78. public static TextImageRelation ImageAlignToRelation(ContentAlignment align)
  79. {
  80. return m_ImageAlignToRelation[LayoutUtils.ContentAlignmentToIndex(align)];
  81. }
  82. /// <summary>
  83. /// 文本对齐方式转换为文本图片相对位置
  84. /// </summary>
  85. /// <param name="align">文本对齐方式</param>
  86. /// <returns>文本图片相对位置</returns>
  87. public static TextImageRelation TextAlignToRelation(ContentAlignment align)
  88. {
  89. return LayoutUtils.GetOppositeTextImageRelation(ImageAlignToRelation(align));
  90. }
  91. /// <summary>
  92. /// 获取绘制格式
  93. /// </summary>
  94. /// <param name="align">对齐方式</param>
  95. /// <param name="rtl">左右反转</param>
  96. /// <returns>绘制格式</returns>
  97. public static StringFormat GetStringFormat(ContentAlignment align, RightToLeft rtl)
  98. {
  99. StringFormat format = DefaultTheme.StringFormat;
  100. switch (align)
  101. {
  102. case ContentAlignment.TopLeft:
  103. format.LineAlignment = StringAlignment.Near;
  104. format.Alignment = StringAlignment.Near;
  105. break;
  106. case ContentAlignment.TopCenter:
  107. format.LineAlignment = StringAlignment.Near;
  108. format.Alignment = StringAlignment.Center;
  109. break;
  110. case ContentAlignment.TopRight:
  111. format.LineAlignment = StringAlignment.Near;
  112. format.Alignment = StringAlignment.Far;
  113. break;
  114. case ContentAlignment.MiddleLeft:
  115. format.LineAlignment = StringAlignment.Center;
  116. format.Alignment = StringAlignment.Near;
  117. break;
  118. case ContentAlignment.MiddleCenter:
  119. format.LineAlignment = StringAlignment.Center;
  120. format.Alignment = StringAlignment.Center;
  121. break;
  122. case ContentAlignment.MiddleRight:
  123. format.LineAlignment = StringAlignment.Center;
  124. format.Alignment = StringAlignment.Far;
  125. break;
  126. case ContentAlignment.BottomLeft:
  127. format.LineAlignment = StringAlignment.Far;
  128. format.Alignment = StringAlignment.Near;
  129. break;
  130. case ContentAlignment.BottomCenter:
  131. format.LineAlignment = StringAlignment.Far;
  132. format.Alignment = StringAlignment.Center;
  133. break;
  134. case ContentAlignment.BottomRight:
  135. format.LineAlignment = StringAlignment.Far;
  136. format.Alignment = StringAlignment.Far;
  137. break;
  138. default:
  139. break;
  140. }
  141. if (rtl == RightToLeft.Yes)
  142. format.FormatFlags = StringFormatFlags.DirectionRightToLeft;
  143. format.HotkeyPrefix = HotkeyPrefix.Show;
  144. return format;
  145. }
  146. /// <summary>
  147. /// 获取绘制格式
  148. /// </summary>
  149. /// <param name="align">对齐方式</param>
  150. /// <param name="rtl">左右反转</param>
  151. /// <returns>绘制格式</returns>
  152. public static TextFormatFlags GetTextFormatFlags(ContentAlignment align, RightToLeft rtl)
  153. {
  154. TextFormatFlags flags = TextFormatFlags.WordBreak;
  155. switch (align)
  156. {
  157. case ContentAlignment.TopLeft:
  158. flags |= TextFormatFlags.Top | TextFormatFlags.Left;
  159. break;
  160. case ContentAlignment.TopCenter:
  161. flags |= TextFormatFlags.Top | TextFormatFlags.HorizontalCenter;
  162. break;
  163. case ContentAlignment.TopRight:
  164. flags |= TextFormatFlags.Top | TextFormatFlags.Right;
  165. break;
  166. case ContentAlignment.MiddleLeft:
  167. flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Left;
  168. break;
  169. case ContentAlignment.MiddleCenter:
  170. flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter;
  171. break;
  172. case ContentAlignment.MiddleRight:
  173. flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
  174. break;
  175. case ContentAlignment.BottomLeft:
  176. flags |= TextFormatFlags.Bottom | TextFormatFlags.Left;
  177. break;
  178. case ContentAlignment.BottomCenter:
  179. flags |= TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter;
  180. break;
  181. case ContentAlignment.BottomRight:
  182. flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
  183. break;
  184. default:
  185. break;
  186. }
  187. if (rtl == RightToLeft.Yes)
  188. flags |= TextFormatFlags.RightToLeft | TextFormatFlags.Right;
  189. return flags;
  190. }
  191. /// <summary>
  192. /// 测试文本大小
  193. /// </summary>
  194. /// <param name="layout">布局对象</param>
  195. /// <param name="proposedSize">可提供的大小</param>
  196. /// <returns>文本大小</returns>
  197. public static Size GetTextSize(LayoutData layout, Size proposedSize)
  198. {
  199. return Size.Ceiling(layout.Graphics.MeasureString(layout.Text, layout.Font, new SizeF((float)proposedSize.Width, (float)proposedSize.Height), layout.CurrentStringFormat));
  200. }
  201. /// <summary>
  202. /// 布局文本和图片,每调用一次,执行一次布局操作
  203. /// </summary>
  204. /// <param name="layout">布局对象</param>
  205. public static void LayoutTextAndImage(LayoutData layout)
  206. {
  207. if (((layout.ImageSize == Size.Empty) || (layout.Text == null)) || ((layout.Text.Length == 0) || (layout.CurrentTextImageRelation == TextImageRelation.Overlay)))
  208. {
  209. Size imageSize = layout.ImageSize;
  210. Size textSize = GetTextSize(layout, layout.CurrentClientRectangle.Size);
  211. layout.OutImageBounds = LayoutUtils.Align(imageSize, layout.CurrentClientRectangle, layout.CurrentImageAlign);
  212. layout.OutTextBounds = LayoutUtils.Align(textSize, layout.CurrentClientRectangle, layout.CurrentTextAlign);
  213. }
  214. else
  215. {
  216. Size proposedSize = LayoutUtils.SubAlignedRegion(layout.CurrentClientRectangle.Size, layout.ImageSize, layout.CurrentTextImageRelation);//减去图片空间后的大小
  217. Size textSize = GetTextSize(layout, proposedSize);//文本大小
  218. Size textImageSize = LayoutUtils.AddAlignedRegion(textSize, layout.ImageSize, layout.CurrentTextImageRelation);//两个大小相加
  219. Rectangle containerRect = layout.CurrentClientRectangle;//能包含layout.CurrentClientRectangle,textImageSize的最小容器
  220. containerRect.Size = LayoutUtils.UnionSizes(layout.CurrentClientRectangle.Size, textImageSize);//获取两个Size中的最大值(分别计算宽和高)
  221. Rectangle textImageRect = LayoutUtils.Align(textImageSize, containerRect, ContentAlignment.MiddleCenter);//居中
  222. bool imageNoOverlay = (ImageAlignToRelation(layout.CurrentImageAlign) & layout.CurrentTextImageRelation) != TextImageRelation.Overlay;
  223. bool textNoOverlay = (TextAlignToRelation(layout.CurrentTextAlign) & layout.CurrentTextImageRelation) != TextImageRelation.Overlay;
  224. Rectangle imageBounds;
  225. Rectangle textBounds;
  226. if (imageNoOverlay)
  227. {
  228. LayoutUtils.SplitRegion(containerRect, layout.ImageSize, (AnchorStyles)layout.CurrentTextImageRelation, out imageBounds, out textBounds);
  229. }
  230. else if (textNoOverlay)
  231. {
  232. LayoutUtils.SplitRegion(containerRect, textSize, (AnchorStyles)LayoutUtils.GetOppositeTextImageRelation(layout.CurrentTextImageRelation), out textBounds, out imageBounds);
  233. }
  234. else
  235. {
  236. LayoutUtils.SplitRegion(textImageRect, layout.ImageSize, (AnchorStyles)layout.CurrentTextImageRelation, out imageBounds, out textBounds);
  237. LayoutUtils.ExpandRegionsToFillBounds(containerRect, (AnchorStyles)layout.CurrentTextImageRelation, ref imageBounds, ref textBounds);//扩展
  238. }
  239. layout.OutImageBounds = LayoutUtils.Align(layout.ImageSize, imageBounds, layout.CurrentImageAlign);
  240. layout.OutTextBounds = LayoutUtils.Align(textSize, textBounds, layout.CurrentTextAlign);
  241. }
  242. //调整
  243. switch (layout.CurrentTextImageRelation)
  244. {
  245. case TextImageRelation.TextBeforeImage:
  246. case TextImageRelation.ImageBeforeText:
  247. {
  248. int num = Math.Min(layout.OutTextBounds.Bottom, layout.CurrentClientRectangle.Bottom);
  249. layout.OutTextBounds.Y = Math.Max(Math.Min(layout.OutTextBounds.Y, layout.CurrentClientRectangle.Y + ((layout.CurrentClientRectangle.Height - layout.OutTextBounds.Height) / 2)), layout.CurrentClientRectangle.Y);
  250. layout.OutTextBounds.Height = num - layout.OutTextBounds.Y;
  251. break;
  252. }
  253. case TextImageRelation.TextAboveImage:
  254. case TextImageRelation.ImageAboveText:
  255. {
  256. int num2 = Math.Min(layout.OutTextBounds.Right, layout.CurrentClientRectangle.Right);
  257. layout.OutTextBounds.X = Math.Max(Math.Min(layout.OutTextBounds.X, layout.CurrentClientRectangle.X + ((layout.CurrentClientRectangle.Width - layout.OutTextBounds.Width) / 2)), layout.CurrentClientRectangle.X);
  258. layout.OutTextBounds.Width = num2 - layout.OutTextBounds.X;
  259. break;
  260. }
  261. default:
  262. break;
  263. }
  264. if ((layout.CurrentTextImageRelation == TextImageRelation.ImageBeforeText) && (layout.OutImageBounds.Size.Width != 0))
  265. {
  266. layout.OutImageBounds.Width = Math.Max(0, Math.Min(layout.CurrentClientRectangle.Width - layout.OutTextBounds.Width, layout.OutImageBounds.Width));
  267. layout.OutTextBounds.X = layout.OutImageBounds.X + layout.OutImageBounds.Width;
  268. }
  269. if ((layout.CurrentTextImageRelation == TextImageRelation.ImageAboveText) && (layout.OutImageBounds.Size.Height != 0))
  270. {
  271. layout.OutImageBounds.Height = Math.Max(0, Math.Min(layout.CurrentClientRectangle.Height - layout.OutTextBounds.Height, layout.OutImageBounds.Height));
  272. layout.OutTextBounds.Y = layout.OutImageBounds.Y + layout.OutImageBounds.Height;
  273. }
  274. layout.OutTextBounds = Rectangle.Intersect(layout.OutTextBounds, layout.CurrentClientRectangle);
  275. //
  276. int num3 = Math.Min(layout.OutTextBounds.Bottom, layout.CurrentClientRectangle.Bottom);
  277. layout.OutTextBounds.Y = Math.Max(layout.OutTextBounds.Y, layout.CurrentClientRectangle.Y);
  278. layout.OutTextBounds.Height = num3 - layout.OutTextBounds.Y;
  279. //偏移
  280. layout.OutImageBounds.Offset(layout.ImageOffset);
  281. layout.OutTextBounds.Offset(layout.TextOffset);
  282. }
  283. }
  284. }