2 // ToolStripSplitStackLayout.cs
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:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
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.
23 // Copyright (c) 2006 Jonathan Pobst
26 // Jonathan Pobst (monkey@jpobst.com)
32 using System.Windows.Forms.Layout;
34 namespace System.Windows.Forms
36 class ToolStripSplitStackLayout : LayoutEngine
38 public override bool Layout (object container, LayoutEventArgs args)
40 if (container is ToolStrip)
42 ToolStrip ts = (ToolStrip)container;
47 Rectangle ts_rect = ts.DisplayRectangle;
49 if (ts.Orientation == Orientation.Horizontal)
50 LayoutHorizontalToolStrip (ts, ts_rect);
52 LayoutVerticalToolStrip (ts, ts_rect);
56 ToolStripContentPanel ts = (ToolStripContentPanel)container;
57 int x = ts.DisplayRectangle.Left;
58 int y = ts.DisplayRectangle.Top;
60 foreach (ToolStrip tsi in ts.Controls) {
61 Rectangle new_bounds = new Rectangle ();
65 new_bounds.Location = new Point (x, y + tsi.Margin.Top);
66 new_bounds.Height = ts.DisplayRectangle.Height - tsi.Margin.Vertical;
67 new_bounds.Width = tsi.GetToolStripPreferredSize (new Size (0, new_bounds.Height)).Width;
69 tsi.Width = new_bounds.Width + 12;
71 x += new_bounds.Width + tsi.Margin.Right;
78 private void LayoutHorizontalToolStrip (ToolStrip ts, Rectangle bounds)
80 //if (!ts.Visible) return;
82 ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count];
83 ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count];
84 Size proposedSize = new Size (0, bounds.Height);
85 int[] widths = new int[ts.Items.Count];
87 int toolstrip_width = bounds.Width;
89 bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
90 bool need_overflow = false;
92 foreach (ToolStripItem tsi in ts.Items) {
93 overflow[i] = tsi.Overflow;
94 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main;
95 widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal;
97 placement[i] = ToolStripItemPlacement.None;
98 total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0;
100 if (placement[i] == ToolStripItemPlacement.Overflow)
101 need_overflow = true;
105 // This is needed for a button set to Overflow = Always
107 ts.OverflowButton.Visible = true;
108 ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height));
109 toolstrip_width -= ts.OverflowButton.Width;
111 ts.OverflowButton.Visible = false;
113 while (total_width > toolstrip_width) {
114 // If we can overflow, get our overflow button setup, and subtract it's width
115 // from our available width
116 if (can_overflow && !ts.OverflowButton.Visible) {
117 ts.OverflowButton.Visible = true;
118 ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height));
119 toolstrip_width -= ts.OverflowButton.Width;
122 bool removed_one = false;
124 // Start at the right, removing Overflow.AsNeeded first
125 for (int j = widths.Length - 1; j >= 0; j--)
126 if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
127 placement[j] = ToolStripItemPlacement.Overflow;
128 total_width -= widths[j];
133 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
134 // These are not put on the Overflow, they are simply not shown
136 for (int j = widths.Length - 1; j >= 0; j--)
137 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
138 placement[j] = ToolStripItemPlacement.None;
139 total_width -= widths[j];
144 // There's nothing left to remove, break or we will loop forever
150 Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top);
151 Point end_layout_pointer = new Point (ts.DisplayRectangle.Right, ts.DisplayRectangle.Top);
152 int button_height = ts.DisplayRectangle.Height;
154 // Now we should know where everything goes, so lay everything out
155 foreach (ToolStripItem tsi in ts.Items) {
156 tsi.SetPlacement (placement[i]);
158 if (placement[i] == ToolStripItemPlacement.Main) {
159 if (tsi.Alignment == ToolStripItemAlignment.Left) {
160 tsi.SetBounds (new Rectangle (start_layout_pointer.X + tsi.Margin.Left, start_layout_pointer.Y + tsi.Margin.Top, widths[i] - tsi.Margin.Horizontal, button_height - tsi.Margin.Vertical));
161 start_layout_pointer.X += widths[i];
163 tsi.SetBounds (new Rectangle (end_layout_pointer.X - tsi.Margin.Right - tsi.Width, end_layout_pointer.Y + tsi.Margin.Top, widths[i] - tsi.Margin.Horizontal, button_height - tsi.Margin.Vertical));
164 end_layout_pointer.X -= widths[i];
172 private void LayoutVerticalToolStrip (ToolStrip ts, Rectangle bounds)
174 if (!ts.Visible) return;
176 ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count];
177 ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count];
178 Size proposedSize = new Size (bounds.Width, 0);
179 int[] heights = new int[ts.Items.Count];
180 int total_height = 0;
181 int toolstrip_height = bounds.Height;
183 bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
185 foreach (ToolStripItem tsi in ts.Items) {
186 overflow[i] = tsi.Overflow;
187 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main;
188 heights[i] = tsi.GetPreferredSize (proposedSize).Height + tsi.Margin.Vertical;
190 placement[i] = ToolStripItemPlacement.None;
191 total_height += placement[i] == ToolStripItemPlacement.Main ? heights[i] : 0;
195 ts.OverflowButton.Visible = false;
197 while (total_height > toolstrip_height) {
198 // If we can overflow, get our overflow button setup, and subtract it's width
199 // from our available width
200 if (can_overflow && !ts.OverflowButton.Visible) {
201 ts.OverflowButton.Visible = true;
202 ts.OverflowButton.SetBounds (new Rectangle (0, ts.Height - 16, ts.Width, 16));
203 toolstrip_height -= ts.OverflowButton.Height;
206 bool removed_one = false;
208 // Start at the right, removing Overflow.AsNeeded first
209 for (int j = heights.Length - 1; j >= 0; j--)
210 if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
211 placement[j] = ToolStripItemPlacement.Overflow;
212 total_height -= heights[j];
217 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
218 // These are not put on the Overflow, they are simply not shown
220 for (int j = heights.Length - 1; j >= 0; j--)
221 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
222 placement[j] = ToolStripItemPlacement.None;
223 total_height -= heights[j];
228 // There's nothing left to remove, break or we will loop forever
234 Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top);
235 Point end_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Bottom);
236 int button_width = ts.DisplayRectangle.Width;
238 // Now we should know where everything goes, so lay everything out
239 foreach (ToolStripItem tsi in ts.Items) {
240 tsi.SetPlacement (placement[i]);
242 if (placement[i] == ToolStripItemPlacement.Main) {
243 if (tsi.Alignment == ToolStripItemAlignment.Left) {
244 tsi.SetBounds (new Rectangle (start_layout_pointer.X + tsi.Margin.Left, start_layout_pointer.Y + tsi.Margin.Top, button_width - tsi.Margin.Horizontal, heights[i] - tsi.Margin.Vertical));
245 start_layout_pointer.Y += heights[i];
247 tsi.SetBounds (new Rectangle (end_layout_pointer.X + tsi.Margin.Left, end_layout_pointer.Y - tsi.Margin.Bottom - tsi.Height, button_width - tsi.Margin.Horizontal, heights[i] - tsi.Margin.Vertical));
248 start_layout_pointer.Y += heights[i];