X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FManaged.Windows.Forms%2FSystem.Windows.Forms.Layout%2FFlowLayout.cs;h=df5884c61ae2ccd17d635507cb38c7b89aca5836;hb=04389482bc32c3db2883f639ec5a7df86fe8eb66;hp=321e3c62a5e7fda2e2023cc9ed9e02fe0966bd2a;hpb=cccbf6a4b7152c24fafc319e77060a4723a8560e;p=mono.git diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs index 321e3c62a5e..df5884c61ae 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs @@ -1,305 +1,591 @@ -// -// FlowLayout.cs -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2006 Jonathan Pobst -// -// Authors: -// Jonathan Pobst (monkey@jpobst.com) -// - -#if NET_2_0 -using System; -using System.Collections.Generic; -using System.Drawing; - -namespace System.Windows.Forms.Layout -{ - class FlowLayout : LayoutEngine - { - public FlowLayout () - { - } - - public override void InitLayout (object child, BoundsSpecified specified) - { - base.InitLayout (child, specified); - } - - public override bool Layout (object container, LayoutEventArgs args) - { - Control parent = container as Control; - FlowLayoutSettings settings = (parent as FlowLayoutPanel).LayoutSettings; - - // Nothing to layout, exit method - if (parent.Controls.Count == 0) return false; - - // Use DisplayRectangle so that parent.Padding is honored. - Rectangle parentDisplayRectangle = parent.DisplayRectangle; - Point currentLocation; - - // Set our starting point based on flow direction - switch (settings.FlowDirection) { - case FlowDirection.BottomUp: - currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom); - break; - case FlowDirection.LeftToRight: - case FlowDirection.TopDown: - default: - currentLocation = parentDisplayRectangle.Location; - break; - case FlowDirection.RightToLeft: - currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top); - break; - } - - bool forceFlowBreak = false; - - List rowControls = new List (); - - foreach (Control c in parent.Controls) { - // Only apply layout to visible controls. - if (!c.Visible) { continue; } - - // Resize any AutoSize controls to their preferred size - if (c.AutoSize == true) - c.Size = c.GetPreferredSize (c.Size); - - switch (settings.FlowDirection) { - case FlowDirection.BottomUp: - // Decide if it's time to start a new column - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { - - currentLocation.X = FinishColumn (rowControls); - currentLocation.Y = parentDisplayRectangle.Bottom; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the right margin and set the control to our point - currentLocation.Offset (0, c.Margin.Bottom * -1); - c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height); - - // Update our location pointer - currentLocation.Y -= (c.Height + c.Margin.Top); - break; - case FlowDirection.LeftToRight: - default: - // Decide if it's time to start a new row - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((parentDisplayRectangle.Width - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { - - currentLocation.Y = FinishRow (rowControls); - currentLocation.X = parentDisplayRectangle.Left; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the left margin and set the control to our point - currentLocation.Offset (c.Margin.Left, 0); - c.Location = new Point (currentLocation.X, currentLocation.Y + c.Margin.Top); - - // Update our location pointer - currentLocation.X += c.Width + c.Margin.Right; - break; - case FlowDirection.RightToLeft: - // Decide if it's time to start a new row - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { - - currentLocation.Y = FinishRow (rowControls); - currentLocation.X = parentDisplayRectangle.Right; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the right margin and set the control to our point - currentLocation.Offset (c.Margin.Right * -1, 0); - c.Location = new Point (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top); - - // Update our location pointer - currentLocation.X -= (c.Width + c.Margin.Left); - break; - case FlowDirection.TopDown: - // Decide if it's time to start a new column - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((parentDisplayRectangle.Height - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { - - currentLocation.X = FinishColumn (rowControls); - currentLocation.Y = parentDisplayRectangle.Top; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the top margin and set the control to our point - currentLocation.Offset (0, c.Margin.Top); - c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y); - - // Update our location pointer - currentLocation.Y += c.Height + c.Margin.Bottom; - break; - } - // Add it to our list of things to adjust the second dimension of - rowControls.Add (c); - - // If user set a flowbreak on this control, it will be the last one in this row/column - if (settings.GetFlowBreak (c)) - forceFlowBreak = true; - } - - // Set the control heights/widths for the last row/column - if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft) - FinishRow (rowControls); - else - FinishColumn (rowControls); - - return false; - } - - // Calculate the heights of the controls, returns the y coordinate of the greatest height it uses - private int FinishRow (List row) - { - // Nothing to do - if (row.Count == 0) return 0; - - int rowTop = int.MaxValue; - int rowBottom = 0; - bool allDockFill = true; - bool noAuto = true; - - // Special semantics if all controls are Dock.Fill/Anchor:Top,Bottom or AutoSize = true - foreach (Control c in row) { - if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - allDockFill = false; - if (c.AutoSize == true) - noAuto = false; - } - - // Find the tallest control with a concrete height - foreach (Control c in row) { - 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)) - rowBottom = c.Bottom + c.Margin.Bottom; - if (c.Top - c.Margin.Top < rowTop) - rowTop = c.Top - c.Margin.Top; - } - - // Find the tallest control that is AutoSize = true - if (rowBottom == 0) - foreach (Control c in row) - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true)) - rowBottom = c.Bottom + c.Margin.Bottom; - - // Find the tallest control that is Dock = Fill - if (rowBottom == 0) - foreach (Control c in row) - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill)) - rowBottom = c.Bottom + c.Margin.Bottom; - - // Set the new heights for each control - foreach (Control c in row) - if (allDockFill && noAuto) - c.Height = 0; - else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - c.Height = rowBottom - c.Top - c.Margin.Bottom; - else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - c.Top = rowBottom - c.Margin.Bottom - c.Height; - else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)) - continue; - else - c.Top = ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop; - - // Return bottom y of this row used - if (rowBottom == 0) - return rowTop; - - return rowBottom; - } - - // Calculate the widths of the controls, returns the x coordinate of the greatest width it uses - private int FinishColumn (List col) - { - // Nothing to do - if (col.Count == 0) return 0; - - int rowLeft = int.MaxValue; - int rowRight = 0; - bool allDockFill = true; - bool noAuto = true; - - // Special semantics if all controls are Dock.Fill/Anchor:Left,Right or AutoSize = true - foreach (Control c in col) { - if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - allDockFill = false; - if (c.AutoSize == true) - noAuto = false; - } - - // Find the widest control with a concrete width - foreach (Control c in col) { - 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)) - rowRight = c.Right + c.Margin.Right; - if (c.Left - c.Margin.Left < rowLeft) - rowLeft = c.Left - c.Margin.Left; - } - - // Find the widest control that is AutoSize = true - if (rowRight == 0) - foreach (Control c in col) - if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true)) - rowRight = c.Right + c.Margin.Right; - - // Find the widest control that is Dock = Fill - if (rowRight == 0) - foreach (Control c in col) - if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill)) - rowRight = c.Right + c.Margin.Right; - - // Set the new widths for each control - foreach (Control c in col) - if (allDockFill && noAuto) - c.Width = 0; - else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - c.Width = rowRight - c.Left - c.Margin.Right; - else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - c.Left = rowRight - c.Margin.Right - c.Width; - else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)) - continue; - else - c.Left = ((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft; - - // Return rightmost x of this row used - if (rowRight == 0) - return rowLeft; - - return rowRight; - } - } -} +// +// FlowLayout.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +#if NET_2_0 +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace System.Windows.Forms.Layout +{ + class FlowLayout : LayoutEngine + { + private static FlowLayoutSettings default_settings = new FlowLayoutSettings (); + + public FlowLayout () + { + } + + public override void InitLayout (object child, BoundsSpecified specified) + { + base.InitLayout (child, specified); + } + + public override bool Layout (object container, LayoutEventArgs args) + { + if (container is ToolStripPanel) + return false; + + if (container is ToolStrip) + return LayoutToolStrip ((ToolStrip)container); + + Control parent = container as Control; + + FlowLayoutSettings settings; + if (parent is FlowLayoutPanel) + settings = (parent as FlowLayoutPanel).LayoutSettings; + else + settings = default_settings; + + // Nothing to layout, exit method + if (parent.Controls.Count == 0) return false; + + // Use DisplayRectangle so that parent.Padding is honored. + Rectangle parentDisplayRectangle = parent.DisplayRectangle; + Point currentLocation; + + // Set our starting point based on flow direction + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom); + break; + case FlowDirection.LeftToRight: + case FlowDirection.TopDown: + default: + currentLocation = parentDisplayRectangle.Location; + break; + case FlowDirection.RightToLeft: + currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top); + break; + } + + bool forceFlowBreak = false; + + List rowControls = new List (); + + foreach (Control c in parent.Controls) { + // Only apply layout to visible controls. + if (!c.Visible) { continue; } + + // Resize any AutoSize controls to their preferred size + if (c.AutoSize == true) { + Size new_size = c.GetPreferredSize (c.Size); + c.SetBoundsInternal (c.Left, c.Top, new_size.Width, new_size.Height, BoundsSpecified.None); + } + + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowControls); + currentLocation.Y = parentDisplayRectangle.Bottom; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the right margin and set the control to our point + currentLocation.Offset (0, c.Margin.Bottom * -1); + c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.Y -= (c.Height + c.Margin.Top); + break; + case FlowDirection.LeftToRight: + default: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents && !(parent is ToolStripPanel)) + if ((parentDisplayRectangle.Width + parentDisplayRectangle.Left - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowControls); + currentLocation.X = parentDisplayRectangle.Left; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the left margin and set the control to our point + currentLocation.Offset (c.Margin.Left, 0); + c.SetBoundsInternal (currentLocation.X, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.X += c.Width + c.Margin.Right; + break; + case FlowDirection.RightToLeft: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowControls); + currentLocation.X = parentDisplayRectangle.Right; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the right margin and set the control to our point + currentLocation.Offset (c.Margin.Right * -1, 0); + c.SetBoundsInternal (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.X -= (c.Width + c.Margin.Left); + break; + case FlowDirection.TopDown: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents) + if ((parentDisplayRectangle.Height + parentDisplayRectangle.Top - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowControls); + currentLocation.Y = parentDisplayRectangle.Top; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the top margin and set the control to our point + currentLocation.Offset (0, c.Margin.Top); + c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.Y += c.Height + c.Margin.Bottom; + break; + } + // Add it to our list of things to adjust the second dimension of + rowControls.Add (c); + + // If user set a flowbreak on this control, it will be the last one in this row/column + if (settings.GetFlowBreak (c)) + forceFlowBreak = true; + } + + // Set the control heights/widths for the last row/column + if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft) + FinishRow (rowControls); + else + FinishColumn (rowControls); + + return false; + } + + // Calculate the heights of the controls, returns the y coordinate of the greatest height it uses + private int FinishRow (List row) + { + // Nothing to do + if (row.Count == 0) return 0; + + int rowTop = int.MaxValue; + int rowBottom = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all controls are Dock.Fill/Anchor:Top,Bottom or AutoSize = true + foreach (Control c in row) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the tallest control with a concrete height + foreach (Control c in row) { + 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)) + rowBottom = c.Bottom + c.Margin.Bottom; + if (c.Top - c.Margin.Top < rowTop) + rowTop = c.Top - c.Margin.Top; + } + + // Find the tallest control that is AutoSize = true + if (rowBottom == 0) + foreach (Control c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Find the tallest control that is Dock = Fill + if (rowBottom == 0) + foreach (Control c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Set the new heights for each control + foreach (Control c in row) + if (allDockFill && noAuto) + c.SetBoundsInternal (c.Left, c.Top, c.Width, 0, BoundsSpecified.None); + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.SetBoundsInternal (c.Left, c.Top, c.Width, rowBottom - c.Top - c.Margin.Bottom, BoundsSpecified.None); + else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.SetBoundsInternal (c.Left, rowBottom - c.Margin.Bottom - c.Height, c.Width, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)) + continue; + else + 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); + + // Return bottom y of this row used + if (rowBottom == 0) + return rowTop; + + return rowBottom; + } + + // Calculate the widths of the controls, returns the x coordinate of the greatest width it uses + private int FinishColumn (List col) + { + // Nothing to do + if (col.Count == 0) return 0; + + int rowLeft = int.MaxValue; + int rowRight = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all controls are Dock.Fill/Anchor:Left,Right or AutoSize = true + foreach (Control c in col) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the widest control with a concrete width + foreach (Control c in col) { + 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)) + rowRight = c.Right + c.Margin.Right; + if (c.Left - c.Margin.Left < rowLeft) + rowLeft = c.Left - c.Margin.Left; + } + + // Find the widest control that is AutoSize = true + if (rowRight == 0) + foreach (Control c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowRight = c.Right + c.Margin.Right; + + // Find the widest control that is Dock = Fill + if (rowRight == 0) + foreach (Control c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill)) + rowRight = c.Right + c.Margin.Right; + + // Set the new widths for each control + foreach (Control c in col) + if (allDockFill && noAuto) + c.SetBoundsInternal (c.Left, c.Top, 0, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.SetBoundsInternal (c.Left, c.Top, rowRight - c.Left - c.Margin.Right, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.SetBoundsInternal (rowRight - c.Margin.Right - c.Width, c.Top, c.Width, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)) + continue; + else + 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); + + // Return rightmost x of this row used + if (rowRight == 0) + return rowLeft; + + return rowRight; + } + + #region Layout for ToolStrip + // ToolStrips use the same FlowLayout, but is made up of ToolStripItems which + // are Components instead of Controls, so we have to duplicate this login for + // ToolStripItems. + private bool LayoutToolStrip (ToolStrip parent) + { + FlowLayoutSettings settings; + settings = (FlowLayoutSettings)parent.LayoutSettings; + + // Nothing to layout, exit method + if (parent.Items.Count == 0) return false; + + foreach (ToolStripItem tsi in parent.Items) + tsi.SetPlacement (ToolStripItemPlacement.Main); + + // Use DisplayRectangle so that parent.Padding is honored. + Rectangle parentDisplayRectangle = parent.DisplayRectangle; + Point currentLocation; + + // Set our starting point based on flow direction + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom); + break; + case FlowDirection.LeftToRight: + case FlowDirection.TopDown: + default: + currentLocation = parentDisplayRectangle.Location; + break; + case FlowDirection.RightToLeft: + currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top); + break; + } + + bool forceFlowBreak = false; + + List rowControls = new List (); + + foreach (ToolStripItem c in parent.Items) { + // Only apply layout to visible controls. + if (!c.Available) { continue; } + + // Resize any AutoSize controls to their preferred size + if (c.AutoSize == true) + c.SetBounds (new Rectangle (c.Location, c.GetPreferredSize (c.Size))); + + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowControls); + currentLocation.Y = parentDisplayRectangle.Bottom; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the right margin and set the control to our point + currentLocation.Offset (0, c.Margin.Bottom * -1); + c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height); + + // Update our location pointer + currentLocation.Y -= (c.Height + c.Margin.Top); + break; + case FlowDirection.LeftToRight: + default: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents) + if ((parentDisplayRectangle.Width - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowControls); + currentLocation.X = parentDisplayRectangle.Left; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the left margin and set the control to our point + currentLocation.Offset (c.Margin.Left, 0); + c.Location = new Point (currentLocation.X, currentLocation.Y + c.Margin.Top); + + // Update our location pointer + currentLocation.X += c.Width + c.Margin.Right; + break; + case FlowDirection.RightToLeft: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowControls); + currentLocation.X = parentDisplayRectangle.Right; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the right margin and set the control to our point + currentLocation.Offset (c.Margin.Right * -1, 0); + c.Location = new Point (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top); + + // Update our location pointer + currentLocation.X -= (c.Width + c.Margin.Left); + break; + case FlowDirection.TopDown: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true + if (settings.WrapContents) + if ((parentDisplayRectangle.Height - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowControls); + currentLocation.Y = parentDisplayRectangle.Top; + + forceFlowBreak = false; + rowControls.Clear (); + } + + // Offset the top margin and set the control to our point + currentLocation.Offset (0, c.Margin.Top); + c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y); + + // Update our location pointer + currentLocation.Y += c.Height + c.Margin.Bottom; + break; + } + // Add it to our list of things to adjust the second dimension of + rowControls.Add (c); + + // If user set a flowbreak on this control, it will be the last one in this row/column + if (settings.GetFlowBreak (c)) + forceFlowBreak = true; + } + + int final_height = 0; + + // Set the control heights/widths for the last row/column + if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft) + final_height = FinishRow (rowControls); + else + FinishColumn (rowControls); + + if (final_height > 0) + parent.SetBoundsInternal (parent.Left, parent.Top, parent.Width, final_height + parent.Padding.Bottom, BoundsSpecified.None); + + return false; + + } + + // Calculate the heights of the controls, returns the y coordinate of the greatest height it uses + private int FinishRow (List row) + { + // Nothing to do + if (row.Count == 0) return 0; + + int rowTop = int.MaxValue; + int rowBottom = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all controls are Dock.Fill/Anchor:Top,Bottom or AutoSize = true + foreach (ToolStripItem c in row) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the tallest control with a concrete height + foreach (ToolStripItem c in row) { + 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)) + rowBottom = c.Bottom + c.Margin.Bottom; + if (c.Top - c.Margin.Top < rowTop) + rowTop = c.Top - c.Margin.Top; + } + + // Find the tallest control that is AutoSize = true + if (rowBottom == 0) + foreach (ToolStripItem c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Find the tallest control that is Dock = Fill + if (rowBottom == 0) + foreach (ToolStripItem c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Set the new heights for each control + foreach (ToolStripItem c in row) + if (allDockFill && noAuto) + c.Height = 0; + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.Height = rowBottom - c.Top - c.Margin.Bottom; + else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.Top = rowBottom - c.Margin.Bottom - c.Height; + else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)) + continue; + else + c.Top = ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop; + + // Return bottom y of this row used + if (rowBottom == 0) + return rowTop; + + return rowBottom; + } + + // Calculate the widths of the controls, returns the x coordinate of the greatest width it uses + private int FinishColumn (List col) + { + // Nothing to do + if (col.Count == 0) return 0; + + int rowLeft = int.MaxValue; + int rowRight = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all controls are Dock.Fill/Anchor:Left,Right or AutoSize = true + foreach (ToolStripItem c in col) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the widest control with a concrete width + foreach (ToolStripItem c in col) { + 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)) + rowRight = c.Right + c.Margin.Right; + if (c.Left - c.Margin.Left < rowLeft) + rowLeft = c.Left - c.Margin.Left; + } + + // Find the widest control that is AutoSize = true + if (rowRight == 0) + foreach (ToolStripItem c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowRight = c.Right + c.Margin.Right; + + // Find the widest control that is Dock = Fill + if (rowRight == 0) + foreach (ToolStripItem c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill)) + rowRight = c.Right + c.Margin.Right; + + // Set the new widths for each control + foreach (ToolStripItem c in col) + if (allDockFill && noAuto) + c.Width = 0; + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.Width = rowRight - c.Left - c.Margin.Right; + else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.Left = rowRight - c.Margin.Right - c.Width; + else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)) + continue; + else + c.Left = ((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft; + + // Return rightmost x of this row used + if (rowRight == 0) + return rowLeft; + + return rowRight; + } + #endregion + } +} #endif \ No newline at end of file