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)
31 using System.Windows.Forms.Layout;
33 namespace System.Windows.Forms
35 class ToolStripSplitStackLayout : LayoutEngine
37 public override bool Layout (object container, LayoutEventArgs args)
39 if (container is ToolStrip)
41 ToolStrip ts = (ToolStrip)container;
46 Rectangle ts_rect = ts.DisplayRectangle;
48 if (ts.Orientation == Orientation.Horizontal)
49 LayoutHorizontalToolStrip (ts, ts_rect);
51 LayoutVerticalToolStrip (ts, ts_rect);
55 ToolStripContentPanel ts = (ToolStripContentPanel)container;
56 int x = ts.DisplayRectangle.Left;
57 int y = ts.DisplayRectangle.Top;
59 foreach (ToolStrip tsi in ts.Controls) {
60 Rectangle new_bounds = new Rectangle ();
64 new_bounds.Location = new Point (x, y + tsi.Margin.Top);
65 new_bounds.Height = ts.DisplayRectangle.Height - tsi.Margin.Vertical;
66 new_bounds.Width = tsi.GetToolStripPreferredSize (new Size (0, new_bounds.Height)).Width;
68 tsi.Width = new_bounds.Width + 12;
70 x += new_bounds.Width + tsi.Margin.Right;
77 private void LayoutHorizontalToolStrip (ToolStrip ts, Rectangle bounds)
79 //if (!ts.Visible) return;
81 ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count];
82 ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count];
83 Size proposedSize = new Size (0, bounds.Height);
84 int[] widths = new int[ts.Items.Count];
86 int toolstrip_width = bounds.Width;
88 bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
89 bool need_overflow = false;
91 foreach (ToolStripItem tsi in ts.Items) {
92 overflow[i] = tsi.Overflow;
93 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main;
94 widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal;
96 placement[i] = ToolStripItemPlacement.None;
97 total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0;
99 if (placement[i] == ToolStripItemPlacement.Overflow)
100 need_overflow = true;
104 // This is needed for a button set to Overflow = Always
106 ts.OverflowButton.Visible = true;
107 ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height));
108 toolstrip_width -= ts.OverflowButton.Width;
110 ts.OverflowButton.Visible = false;
112 while (total_width > toolstrip_width) {
113 // If we can overflow, get our overflow button setup, and subtract it's width
114 // from our available width
115 if (can_overflow && !ts.OverflowButton.Visible) {
116 ts.OverflowButton.Visible = true;
117 ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height));
118 toolstrip_width -= ts.OverflowButton.Width;
121 bool removed_one = false;
123 // Start at the right, removing Overflow.AsNeeded first
124 for (int j = widths.Length - 1; j >= 0; j--)
125 if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
126 placement[j] = ToolStripItemPlacement.Overflow;
127 total_width -= widths[j];
132 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
133 // These are not put on the Overflow, they are simply not shown
135 for (int j = widths.Length - 1; j >= 0; j--)
136 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
137 placement[j] = ToolStripItemPlacement.None;
138 total_width -= widths[j];
143 // There's nothing left to remove, break or we will loop forever
149 Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top);
150 Point end_layout_pointer = new Point (ts.DisplayRectangle.Right, ts.DisplayRectangle.Top);
151 int button_height = ts.DisplayRectangle.Height;
153 // Now we should know where everything goes, so lay everything out
154 foreach (ToolStripItem tsi in ts.Items) {
155 tsi.SetPlacement (placement[i]);
157 if (placement[i] == ToolStripItemPlacement.Main) {
158 if (tsi.Alignment == ToolStripItemAlignment.Left) {
159 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));
160 start_layout_pointer.X += widths[i];
162 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));
163 end_layout_pointer.X -= widths[i];
171 private void LayoutVerticalToolStrip (ToolStrip ts, Rectangle bounds)
173 if (!ts.Visible) return;
175 ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count];
176 ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count];
177 Size proposedSize = new Size (bounds.Width, 0);
178 int[] heights = new int[ts.Items.Count];
179 int total_height = 0;
180 int toolstrip_height = bounds.Height;
182 bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
184 foreach (ToolStripItem tsi in ts.Items) {
185 overflow[i] = tsi.Overflow;
186 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main;
187 heights[i] = tsi.GetPreferredSize (proposedSize).Height + tsi.Margin.Vertical;
189 placement[i] = ToolStripItemPlacement.None;
190 total_height += placement[i] == ToolStripItemPlacement.Main ? heights[i] : 0;
194 ts.OverflowButton.Visible = false;
196 while (total_height > toolstrip_height) {
197 // If we can overflow, get our overflow button setup, and subtract it's width
198 // from our available width
199 if (can_overflow && !ts.OverflowButton.Visible) {
200 ts.OverflowButton.Visible = true;
201 ts.OverflowButton.SetBounds (new Rectangle (0, ts.Height - 16, ts.Width, 16));
202 toolstrip_height -= ts.OverflowButton.Height;
205 bool removed_one = false;
207 // Start at the right, removing Overflow.AsNeeded first
208 for (int j = heights.Length - 1; j >= 0; j--)
209 if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
210 placement[j] = ToolStripItemPlacement.Overflow;
211 total_height -= heights[j];
216 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
217 // These are not put on the Overflow, they are simply not shown
219 for (int j = heights.Length - 1; j >= 0; j--)
220 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
221 placement[j] = ToolStripItemPlacement.None;
222 total_height -= heights[j];
227 // There's nothing left to remove, break or we will loop forever
233 Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top);
234 Point end_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Bottom);
235 int button_width = ts.DisplayRectangle.Width;
237 // Now we should know where everything goes, so lay everything out
238 foreach (ToolStripItem tsi in ts.Items) {
239 tsi.SetPlacement (placement[i]);
241 if (placement[i] == ToolStripItemPlacement.Main) {
242 if (tsi.Alignment == ToolStripItemAlignment.Left) {
243 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));
244 start_layout_pointer.Y += heights[i];
246 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));
247 start_layout_pointer.Y += heights[i];