FlowLayout.cs 23 KB

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