FlowLayout.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. //
  2. // FlowLayout.cs
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. // Copyright (c) 2006 Jonathan Pobst
  24. //
  25. // Authors:
  26. // Jonathan Pobst ([email protected])
  27. //
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Drawing;
  31. namespace System.Windows.Forms.Layout
  32. {
  33. class FlowLayout : LayoutEngine
  34. {
  35. private static FlowLayoutSettings default_settings = new FlowLayoutSettings ();
  36. public FlowLayout ()
  37. {
  38. }
  39. public override void InitLayout (object child, BoundsSpecified specified)
  40. {
  41. base.InitLayout (child, specified);
  42. }
  43. public override bool Layout (object container, LayoutEventArgs args)
  44. {
  45. if (container is ToolStripPanel)
  46. return false;
  47. if (container is ToolStrip)
  48. return LayoutToolStrip ((ToolStrip)container);
  49. Control parent = container as Control;
  50. FlowLayoutSettings settings;
  51. if (parent is FlowLayoutPanel)
  52. settings = (parent as FlowLayoutPanel).LayoutSettings;
  53. else
  54. settings = default_settings;
  55. // Nothing to layout, exit method
  56. if (parent.Controls.Count == 0) return false;
  57. // Use DisplayRectangle so that parent.Padding is honored.
  58. Rectangle parentDisplayRectangle = parent.DisplayRectangle;
  59. Point currentLocation;
  60. // Set our starting point based on flow direction
  61. switch (settings.FlowDirection) {
  62. case FlowDirection.BottomUp:
  63. currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom);
  64. break;
  65. case FlowDirection.LeftToRight:
  66. case FlowDirection.TopDown:
  67. default:
  68. currentLocation = parentDisplayRectangle.Location;
  69. break;
  70. case FlowDirection.RightToLeft:
  71. currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top);
  72. break;
  73. }
  74. bool forceFlowBreak = false;
  75. List<Control> rowControls = new List<Control> ();
  76. foreach (Control c in parent.Controls) {
  77. // Only apply layout to visible controls.
  78. if (!c.Visible) { continue; }
  79. // Resize any AutoSize controls to their preferred size
  80. if (c.AutoSize == true) {
  81. Size new_size = c.GetPreferredSize (c.Size);
  82. c.SetBoundsInternal (c.Left, c.Top, new_size.Width, new_size.Height, BoundsSpecified.None);
  83. }
  84. switch (settings.FlowDirection) {
  85. case FlowDirection.BottomUp:
  86. // Decide if it's time to start a new column
  87. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  88. if (settings.WrapContents)
  89. if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
  90. currentLocation.X = FinishColumn (rowControls);
  91. currentLocation.Y = parentDisplayRectangle.Bottom;
  92. forceFlowBreak = false;
  93. rowControls.Clear ();
  94. }
  95. // Offset the right margin and set the control to our point
  96. currentLocation.Offset (0, c.Margin.Bottom * -1);
  97. c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height, c.Width, c.Height, BoundsSpecified.None);
  98. // Update our location pointer
  99. currentLocation.Y -= (c.Height + c.Margin.Top);
  100. break;
  101. case FlowDirection.LeftToRight:
  102. default:
  103. // Decide if it's time to start a new row
  104. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  105. if (settings.WrapContents && !(parent is ToolStripPanel))
  106. if ((parentDisplayRectangle.Width + parentDisplayRectangle.Left - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
  107. currentLocation.Y = FinishRow (rowControls);
  108. currentLocation.X = parentDisplayRectangle.Left;
  109. forceFlowBreak = false;
  110. rowControls.Clear ();
  111. }
  112. // Offset the left margin and set the control to our point
  113. currentLocation.Offset (c.Margin.Left, 0);
  114. c.SetBoundsInternal (currentLocation.X, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None);
  115. // Update our location pointer
  116. currentLocation.X += c.Width + c.Margin.Right;
  117. break;
  118. case FlowDirection.RightToLeft:
  119. // Decide if it's time to start a new row
  120. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  121. if (settings.WrapContents)
  122. if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
  123. currentLocation.Y = FinishRow (rowControls);
  124. currentLocation.X = parentDisplayRectangle.Right;
  125. forceFlowBreak = false;
  126. rowControls.Clear ();
  127. }
  128. // Offset the right margin and set the control to our point
  129. currentLocation.Offset (c.Margin.Right * -1, 0);
  130. c.SetBoundsInternal (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None);
  131. // Update our location pointer
  132. currentLocation.X -= (c.Width + c.Margin.Left);
  133. break;
  134. case FlowDirection.TopDown:
  135. // Decide if it's time to start a new column
  136. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  137. if (settings.WrapContents)
  138. if ((parentDisplayRectangle.Height + parentDisplayRectangle.Top - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
  139. currentLocation.X = FinishColumn (rowControls);
  140. currentLocation.Y = parentDisplayRectangle.Top;
  141. forceFlowBreak = false;
  142. rowControls.Clear ();
  143. }
  144. // Offset the top margin and set the control to our point
  145. currentLocation.Offset (0, c.Margin.Top);
  146. c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y, c.Width, c.Height, BoundsSpecified.None);
  147. // Update our location pointer
  148. currentLocation.Y += c.Height + c.Margin.Bottom;
  149. break;
  150. }
  151. // Add it to our list of things to adjust the second dimension of
  152. rowControls.Add (c);
  153. // If user set a flowbreak on this control, it will be the last one in this row/column
  154. if (settings.GetFlowBreak (c))
  155. forceFlowBreak = true;
  156. }
  157. // Set the control heights/widths for the last row/column
  158. if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft)
  159. FinishRow (rowControls);
  160. else
  161. FinishColumn (rowControls);
  162. return false;
  163. }
  164. // Calculate the heights of the controls, returns the y coordinate of the greatest height it uses
  165. private int FinishRow (List<Control> row)
  166. {
  167. // Nothing to do
  168. if (row.Count == 0) return 0;
  169. int rowTop = int.MaxValue;
  170. int rowBottom = 0;
  171. bool allDockFill = true;
  172. bool noAuto = true;
  173. // Special semantics if all controls are Dock.Fill/Anchor:Top,Bottom or AutoSize = true
  174. foreach (Control c in row) {
  175. if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
  176. allDockFill = false;
  177. if (c.AutoSize == true)
  178. noAuto = false;
  179. }
  180. // Find the tallest control with a concrete height
  181. foreach (Control c in row) {
  182. if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true))
  183. rowBottom = c.Bottom + c.Margin.Bottom;
  184. if (c.Top - c.Margin.Top < rowTop)
  185. rowTop = c.Top - c.Margin.Top;
  186. }
  187. // Find the tallest control that is AutoSize = true
  188. if (rowBottom == 0)
  189. foreach (Control c in row)
  190. if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true))
  191. rowBottom = c.Bottom + c.Margin.Bottom;
  192. // Find the tallest control that is Dock = Fill
  193. if (rowBottom == 0)
  194. foreach (Control c in row)
  195. if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill))
  196. rowBottom = c.Bottom + c.Margin.Bottom;
  197. // Set the new heights for each control
  198. foreach (Control c in row)
  199. if (allDockFill && noAuto)
  200. c.SetBoundsInternal (c.Left, c.Top, c.Width, 0, BoundsSpecified.None);
  201. else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
  202. c.SetBoundsInternal (c.Left, c.Top, c.Width, rowBottom - c.Top - c.Margin.Bottom, BoundsSpecified.None);
  203. else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
  204. c.SetBoundsInternal (c.Left, rowBottom - c.Margin.Bottom - c.Height, c.Width, c.Height, BoundsSpecified.None);
  205. else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top))
  206. continue;
  207. else
  208. c.SetBoundsInternal (c.Left, ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop, c.Width, c.Height, BoundsSpecified.None);
  209. // Return bottom y of this row used
  210. if (rowBottom == 0)
  211. return rowTop;
  212. return rowBottom;
  213. }
  214. // Calculate the widths of the controls, returns the x coordinate of the greatest width it uses
  215. private int FinishColumn (List<Control> col)
  216. {
  217. // Nothing to do
  218. if (col.Count == 0) return 0;
  219. int rowLeft = int.MaxValue;
  220. int rowRight = 0;
  221. bool allDockFill = true;
  222. bool noAuto = true;
  223. // Special semantics if all controls are Dock.Fill/Anchor:Left,Right or AutoSize = true
  224. foreach (Control c in col) {
  225. if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
  226. allDockFill = false;
  227. if (c.AutoSize == true)
  228. noAuto = false;
  229. }
  230. // Find the widest control with a concrete width
  231. foreach (Control c in col) {
  232. if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true))
  233. rowRight = c.Right + c.Margin.Right;
  234. if (c.Left - c.Margin.Left < rowLeft)
  235. rowLeft = c.Left - c.Margin.Left;
  236. }
  237. // Find the widest control that is AutoSize = true
  238. if (rowRight == 0)
  239. foreach (Control c in col)
  240. if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true))
  241. rowRight = c.Right + c.Margin.Right;
  242. // Find the widest control that is Dock = Fill
  243. if (rowRight == 0)
  244. foreach (Control c in col)
  245. if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill))
  246. rowRight = c.Right + c.Margin.Right;
  247. // Set the new widths for each control
  248. foreach (Control c in col)
  249. if (allDockFill && noAuto)
  250. c.SetBoundsInternal (c.Left, c.Top, 0, c.Height, BoundsSpecified.None);
  251. else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
  252. c.SetBoundsInternal (c.Left, c.Top, rowRight - c.Left - c.Margin.Right, c.Height, BoundsSpecified.None);
  253. else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
  254. c.SetBoundsInternal (rowRight - c.Margin.Right - c.Width, c.Top, c.Width, c.Height, BoundsSpecified.None);
  255. else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left))
  256. continue;
  257. else
  258. c.SetBoundsInternal (((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft, c.Top, c.Width, c.Height, BoundsSpecified.None);
  259. // Return rightmost x of this row used
  260. if (rowRight == 0)
  261. return rowLeft;
  262. return rowRight;
  263. }
  264. #region Layout for ToolStrip
  265. // ToolStrips use the same FlowLayout, but is made up of ToolStripItems which
  266. // are Components instead of Controls, so we have to duplicate this login for
  267. // ToolStripItems.
  268. private bool LayoutToolStrip (ToolStrip parent)
  269. {
  270. FlowLayoutSettings settings;
  271. settings = (FlowLayoutSettings)parent.LayoutSettings;
  272. // Nothing to layout, exit method
  273. if (parent.Items.Count == 0) return false;
  274. foreach (ToolStripItem tsi in parent.Items)
  275. tsi.SetPlacement (ToolStripItemPlacement.Main);
  276. // Use DisplayRectangle so that parent.Padding is honored.
  277. Rectangle parentDisplayRectangle = parent.DisplayRectangle;
  278. Point currentLocation;
  279. // Set our starting point based on flow direction
  280. switch (settings.FlowDirection) {
  281. case FlowDirection.BottomUp:
  282. currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom);
  283. break;
  284. case FlowDirection.LeftToRight:
  285. case FlowDirection.TopDown:
  286. default:
  287. currentLocation = parentDisplayRectangle.Location;
  288. break;
  289. case FlowDirection.RightToLeft:
  290. currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top);
  291. break;
  292. }
  293. bool forceFlowBreak = false;
  294. List<ToolStripItem> rowControls = new List<ToolStripItem> ();
  295. foreach (ToolStripItem c in parent.Items) {
  296. // Only apply layout to visible controls.
  297. if (!c.Available) { continue; }
  298. // Resize any AutoSize controls to their preferred size
  299. if (c.AutoSize == true)
  300. c.SetBounds (new Rectangle (c.Location, c.GetPreferredSize (c.Size)));
  301. switch (settings.FlowDirection) {
  302. case FlowDirection.BottomUp:
  303. // Decide if it's time to start a new column
  304. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  305. if (settings.WrapContents)
  306. if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
  307. currentLocation.X = FinishColumn (rowControls);
  308. currentLocation.Y = parentDisplayRectangle.Bottom;
  309. forceFlowBreak = false;
  310. rowControls.Clear ();
  311. }
  312. // Offset the right margin and set the control to our point
  313. currentLocation.Offset (0, c.Margin.Bottom * -1);
  314. c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height);
  315. // Update our location pointer
  316. currentLocation.Y -= (c.Height + c.Margin.Top);
  317. break;
  318. case FlowDirection.LeftToRight:
  319. default:
  320. // Decide if it's time to start a new row
  321. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  322. if (settings.WrapContents)
  323. if ((parentDisplayRectangle.Width - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
  324. currentLocation.Y = FinishRow (rowControls);
  325. currentLocation.X = parentDisplayRectangle.Left;
  326. forceFlowBreak = false;
  327. rowControls.Clear ();
  328. }
  329. // Offset the left margin and set the control to our point
  330. currentLocation.Offset (c.Margin.Left, 0);
  331. c.Location = new Point (currentLocation.X, currentLocation.Y + c.Margin.Top);
  332. // Update our location pointer
  333. currentLocation.X += c.Width + c.Margin.Right;
  334. break;
  335. case FlowDirection.RightToLeft:
  336. // Decide if it's time to start a new row
  337. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  338. if (settings.WrapContents)
  339. if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) {
  340. currentLocation.Y = FinishRow (rowControls);
  341. currentLocation.X = parentDisplayRectangle.Right;
  342. forceFlowBreak = false;
  343. rowControls.Clear ();
  344. }
  345. // Offset the right margin and set the control to our point
  346. currentLocation.Offset (c.Margin.Right * -1, 0);
  347. c.Location = new Point (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top);
  348. // Update our location pointer
  349. currentLocation.X -= (c.Width + c.Margin.Left);
  350. break;
  351. case FlowDirection.TopDown:
  352. // Decide if it's time to start a new column
  353. // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true
  354. if (settings.WrapContents)
  355. if ((parentDisplayRectangle.Height - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) {
  356. currentLocation.X = FinishColumn (rowControls);
  357. currentLocation.Y = parentDisplayRectangle.Top;
  358. forceFlowBreak = false;
  359. rowControls.Clear ();
  360. }
  361. // Offset the top margin and set the control to our point
  362. currentLocation.Offset (0, c.Margin.Top);
  363. c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y);
  364. // Update our location pointer
  365. currentLocation.Y += c.Height + c.Margin.Bottom;
  366. break;
  367. }
  368. // Add it to our list of things to adjust the second dimension of
  369. rowControls.Add (c);
  370. // If user set a flowbreak on this control, it will be the last one in this row/column
  371. if (settings.GetFlowBreak (c))
  372. forceFlowBreak = true;
  373. }
  374. int final_height = 0;
  375. // Set the control heights/widths for the last row/column
  376. if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft)
  377. final_height = FinishRow (rowControls);
  378. else
  379. FinishColumn (rowControls);
  380. if (final_height > 0)
  381. parent.SetBoundsInternal (parent.Left, parent.Top, parent.Width, final_height + parent.Padding.Bottom, BoundsSpecified.None);
  382. return false;
  383. }
  384. // Calculate the heights of the controls, returns the y coordinate of the greatest height it uses
  385. private int FinishRow (List<ToolStripItem> row)
  386. {
  387. // Nothing to do
  388. if (row.Count == 0) return 0;
  389. int rowTop = int.MaxValue;
  390. int rowBottom = 0;
  391. bool allDockFill = true;
  392. bool noAuto = true;
  393. // Special semantics if all controls are Dock.Fill/Anchor:Top,Bottom or AutoSize = true
  394. foreach (ToolStripItem c in row) {
  395. if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
  396. allDockFill = false;
  397. if (c.AutoSize == true)
  398. noAuto = false;
  399. }
  400. // Find the tallest control with a concrete height
  401. foreach (ToolStripItem c in row) {
  402. if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true))
  403. rowBottom = c.Bottom + c.Margin.Bottom;
  404. if (c.Top - c.Margin.Top < rowTop)
  405. rowTop = c.Top - c.Margin.Top;
  406. }
  407. // Find the tallest control that is AutoSize = true
  408. if (rowBottom == 0)
  409. foreach (ToolStripItem c in row)
  410. if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true))
  411. rowBottom = c.Bottom + c.Margin.Bottom;
  412. // Find the tallest control that is Dock = Fill
  413. if (rowBottom == 0)
  414. foreach (ToolStripItem c in row)
  415. if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill))
  416. rowBottom = c.Bottom + c.Margin.Bottom;
  417. // Set the new heights for each control
  418. foreach (ToolStripItem c in row)
  419. if (allDockFill && noAuto)
  420. c.Height = 0;
  421. else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
  422. c.Height = rowBottom - c.Top - c.Margin.Bottom;
  423. else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom))
  424. c.Top = rowBottom - c.Margin.Bottom - c.Height;
  425. else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top))
  426. continue;
  427. else
  428. c.Top = ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop;
  429. // Return bottom y of this row used
  430. if (rowBottom == 0)
  431. return rowTop;
  432. return rowBottom;
  433. }
  434. // Calculate the widths of the controls, returns the x coordinate of the greatest width it uses
  435. private int FinishColumn (List<ToolStripItem> col)
  436. {
  437. // Nothing to do
  438. if (col.Count == 0) return 0;
  439. int rowLeft = int.MaxValue;
  440. int rowRight = 0;
  441. bool allDockFill = true;
  442. bool noAuto = true;
  443. // Special semantics if all controls are Dock.Fill/Anchor:Left,Right or AutoSize = true
  444. foreach (ToolStripItem c in col) {
  445. if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
  446. allDockFill = false;
  447. if (c.AutoSize == true)
  448. noAuto = false;
  449. }
  450. // Find the widest control with a concrete width
  451. foreach (ToolStripItem c in col) {
  452. if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true))
  453. rowRight = c.Right + c.Margin.Right;
  454. if (c.Left - c.Margin.Left < rowLeft)
  455. rowLeft = c.Left - c.Margin.Left;
  456. }
  457. // Find the widest control that is AutoSize = true
  458. if (rowRight == 0)
  459. foreach (ToolStripItem c in col)
  460. if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true))
  461. rowRight = c.Right + c.Margin.Right;
  462. // Find the widest control that is Dock = Fill
  463. if (rowRight == 0)
  464. foreach (ToolStripItem c in col)
  465. if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill))
  466. rowRight = c.Right + c.Margin.Right;
  467. // Set the new widths for each control
  468. foreach (ToolStripItem c in col)
  469. if (allDockFill && noAuto)
  470. c.Width = 0;
  471. else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
  472. c.Width = rowRight - c.Left - c.Margin.Right;
  473. else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right))
  474. c.Left = rowRight - c.Margin.Right - c.Width;
  475. else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left))
  476. continue;
  477. else
  478. c.Left = ((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft;
  479. // Return rightmost x of this row used
  480. if (rowRight == 0)
  481. return rowLeft;
  482. return rowRight;
  483. }
  484. #endregion
  485. }
  486. }