Rename Managed.Windows.Forms to System.Windows.Forms for consistency.
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / ToolStripSplitStackLayout.cs
1 //
2 // ToolStripSplitStackLayout.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 (monkey@jpobst.com)
27 //
28
29 using System;
30 using System.Drawing;
31 using System.Windows.Forms.Layout;
32
33 namespace System.Windows.Forms
34 {
35         class ToolStripSplitStackLayout : LayoutEngine
36         {
37                 public override bool Layout (object container, LayoutEventArgs args)
38                 {
39                         if (container is ToolStrip)
40                         {
41                                 ToolStrip ts = (ToolStrip)container;
42
43                                 if (ts.Items == null)
44                                         return false;
45                                         
46                                 Rectangle ts_rect = ts.DisplayRectangle;
47
48                                 // Mono hasn't yet implemented ToolStripLayoutStyle.Table, so it comes here
49                                 // for layout.  The default (minimal) Table layout is 1 column, any number of rows,
50                                 // which translates effectively to Vertical orientation.
51                                 if (ts.Orientation == Orientation.Horizontal && ts.LayoutStyle != ToolStripLayoutStyle.Table)
52                                         LayoutHorizontalToolStrip (ts, ts_rect);
53                                 else
54                                         LayoutVerticalToolStrip (ts, ts_rect);
55                                         
56                                 return false;
57                         } else  {
58                                 ToolStripContentPanel ts = (ToolStripContentPanel)container;
59                                 int x = ts.DisplayRectangle.Left;
60                                 int y = ts.DisplayRectangle.Top;
61
62                                 foreach (ToolStrip tsi in ts.Controls) {
63                                         Rectangle new_bounds = new Rectangle ();
64
65                                         x += tsi.Margin.Left;
66
67                                         new_bounds.Location = new Point (x, y + tsi.Margin.Top);
68                                         new_bounds.Height = ts.DisplayRectangle.Height - tsi.Margin.Vertical;
69                                         new_bounds.Width = tsi.GetToolStripPreferredSize (new Size (0, new_bounds.Height)).Width;
70
71                                         tsi.Width = new_bounds.Width + 12;
72
73                                         x += new_bounds.Width + tsi.Margin.Right;
74                                 }
75                         }
76
77                         return false;
78                 }
79                 
80                 private void LayoutHorizontalToolStrip (ToolStrip ts, Rectangle bounds)
81                 {
82                         //if (!ts.Visible) return;
83                         
84                         ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count];
85                         ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count];
86                         Size proposedSize = new Size (0, bounds.Height);
87                         int[] widths = new int[ts.Items.Count];
88                         int total_width = 0;
89                         int toolstrip_width = bounds.Width;
90                         int i = 0;
91                         bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
92                         bool need_overflow = false;
93                         
94                         foreach (ToolStripItem tsi in ts.Items) {
95                                 overflow[i] = tsi.Overflow;
96                                 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main;
97                                 widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal;
98                                 if (!tsi.Available)
99                                         placement[i] = ToolStripItemPlacement.None;
100                                 total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0;
101                                 
102                                 if (placement[i] == ToolStripItemPlacement.Overflow)
103                                         need_overflow = true;
104                                 i++;
105                         }
106
107                         // This is needed for a button set to Overflow = Always
108                         if (need_overflow) {
109                                 ts.OverflowButton.Visible = true;
110                                 ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height));
111                                 toolstrip_width -= ts.OverflowButton.Width;
112                         } else
113                                 ts.OverflowButton.Visible = false;
114                         
115                         while (total_width > toolstrip_width) {
116                                 // If we can overflow, get our overflow button setup, and subtract it's width
117                                 // from our available width                             
118                                 if (can_overflow && !ts.OverflowButton.Visible) {
119                                         ts.OverflowButton.Visible = true;
120                                         ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height));
121                                         toolstrip_width -= ts.OverflowButton.Width;
122                                 }                                       
123                                 
124                                 bool removed_one = false;
125                                 
126                                 // Start at the right, removing Overflow.AsNeeded first
127                                 for (int j = widths.Length - 1; j >= 0; j--)
128                                         if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
129                                                 placement[j] = ToolStripItemPlacement.Overflow;
130                                                 total_width -= widths[j];
131                                                 removed_one = true;
132                                                 break;
133                                         }
134                         
135                                 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
136                                 // These are not put on the Overflow, they are simply not shown
137                                 if (!removed_one)
138                                         for (int j = widths.Length - 1; j >= 0; j--)
139                                                 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
140                                                         placement[j] = ToolStripItemPlacement.None;
141                                                         total_width -= widths[j];
142                                                         removed_one = true;
143                                                         break;
144                                                 }
145
146                                 // There's nothing left to remove, break or we will loop forever        
147                                 if (!removed_one)
148                                         break;
149                         }
150
151                         i = 0;
152                         Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top);
153                         Point end_layout_pointer = new Point (ts.DisplayRectangle.Right, ts.DisplayRectangle.Top);
154                         int button_height = ts.DisplayRectangle.Height;
155                         
156                         // Now we should know where everything goes, so lay everything out
157                         foreach (ToolStripItem tsi in ts.Items) {
158                                 tsi.SetPlacement (placement[i]);
159                                 
160                                 if (placement[i] == ToolStripItemPlacement.Main) {
161                                         if (tsi.Alignment == ToolStripItemAlignment.Left) {
162                                                 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));
163                                                 start_layout_pointer.X += widths[i];
164                                         } else {
165                                                 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));
166                                                 end_layout_pointer.X -= widths[i];
167                                         }                       
168                                 }
169                         
170                                 i++;
171                         }                       
172                 }
173
174                 private void LayoutVerticalToolStrip (ToolStrip ts, Rectangle bounds)
175                 {
176                         if (!ts.Visible) return;
177
178                         ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count];
179                         ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count];
180                         Size proposedSize = new Size (bounds.Width, 0);
181                         int[] heights = new int[ts.Items.Count];
182                         int[] widths = new int[ts.Items.Count]; // needed if ts.LayoutStyle == ToolStripLayoutStyle.Table
183                         int total_height = 0;
184                         int toolstrip_height = bounds.Height;
185                         int i = 0;
186                         bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
187
188                         foreach (ToolStripItem tsi in ts.Items) {
189                                 overflow[i] = tsi.Overflow;
190                                 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main;
191                                 var size = tsi.GetPreferredSize (proposedSize);
192                                 heights[i] = size.Height + tsi.Margin.Vertical;
193                                 widths[i] = size.Width + tsi.Margin.Horizontal;
194                                 if (!tsi.Available)
195                                         placement[i] = ToolStripItemPlacement.None;
196                                 total_height += placement[i] == ToolStripItemPlacement.Main ? heights[i] : 0;
197                                 i++;
198                         }
199
200                         ts.OverflowButton.Visible = false;
201
202                         while (total_height > toolstrip_height) {
203                                 // If we can overflow, get our overflow button setup, and subtract it's width
204                                 // from our available width                             
205                                 if (can_overflow && !ts.OverflowButton.Visible) {
206                                         ts.OverflowButton.Visible = true;
207                                         ts.OverflowButton.SetBounds (new Rectangle (0, ts.Height - 16,  ts.Width, 16));
208                                         toolstrip_height -= ts.OverflowButton.Height;
209                                 }
210
211                                 bool removed_one = false;
212
213                                 // Start at the right, removing Overflow.AsNeeded first
214                                 for (int j = heights.Length - 1; j >= 0; j--)
215                                         if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
216                                                 placement[j] = ToolStripItemPlacement.Overflow;
217                                                 total_height -= heights[j];
218                                                 removed_one = true;
219                                                 break;
220                                         }
221
222                                 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
223                                 // These are not put on the Overflow, they are simply not shown
224                                 if (!removed_one)
225                                         for (int j = heights.Length - 1; j >= 0; j--)
226                                                 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
227                                                         placement[j] = ToolStripItemPlacement.None;
228                                                         total_height -= heights[j];
229                                                         removed_one = true;
230                                                         break;
231                                                 }
232                                         
233                                 // There's nothing left to remove, break or we will loop forever        
234                                 if (!removed_one)
235                                         break;
236                         }
237
238                         i = 0;
239                         Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top);
240                         Point end_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Bottom);
241                         int button_width = ts.DisplayRectangle.Width;
242
243                         // Now we should know where everything goes, so lay everything out
244                         foreach (ToolStripItem tsi in ts.Items) {
245                                 tsi.SetPlacement (placement[i]);
246                                 // Table layout is defined to lay out items flush left.
247                                 if (ts.LayoutStyle == ToolStripLayoutStyle.Table)
248                                         button_width = widths[i];
249
250                                 if (placement[i] == ToolStripItemPlacement.Main) {
251                                         if (tsi.Alignment == ToolStripItemAlignment.Left) {
252                                                 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));
253                                                 start_layout_pointer.Y += heights[i];
254                                         } else {
255                                                 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));
256                                                 start_layout_pointer.Y += heights[i];
257                                         }
258                                 }
259
260                                 i++;
261                         }
262                 }
263         }
264 }