* TabControl.cs: Show the tooltip depending on the value
[mono.git] / mcs / class / Managed.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 #if NET_2_0
30 using System;
31 using System.Drawing;
32 using System.Windows.Forms.Layout;
33
34 namespace System.Windows.Forms
35 {
36         class ToolStripSplitStackLayout : LayoutEngine
37         {
38                 public override bool Layout (object container, LayoutEventArgs args)
39                 {
40                         if (container is ToolStrip)
41                         {
42                                 ToolStrip ts = (ToolStrip)container;
43
44                                 if (ts.Items == null)
45                                         return false;
46                                         
47                                 Rectangle ts_rect = ts.DisplayRectangle;
48                                         
49                                 if (ts.Orientation == Orientation.Horizontal)                                   
50                                         LayoutHorizontalToolStrip (ts, ts_rect);
51                                 else
52                                         LayoutVerticalToolStrip (ts, ts_rect);
53                                         
54                                 return false;
55                         } else  {
56                                 ToolStripContentPanel ts = (ToolStripContentPanel)container;
57                                 int x = ts.DisplayRectangle.Left;
58                                 int y = ts.DisplayRectangle.Top;
59
60                                 foreach (ToolStrip tsi in ts.Controls) {
61                                         Rectangle new_bounds = new Rectangle ();
62
63                                         x += tsi.Margin.Left;
64
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;
68
69                                         tsi.Width = new_bounds.Width + 12;
70
71                                         x += new_bounds.Width + tsi.Margin.Right;
72                                 }
73                         }
74
75                         return false;
76                 }
77                 
78                 private void LayoutHorizontalToolStrip (ToolStrip ts, Rectangle bounds)
79                 {
80                         //if (!ts.Visible) return;
81                         
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];
86                         int total_width = 0;
87                         int toolstrip_width = bounds.Width;
88                         int i = 0;
89                         bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
90                         bool need_overflow = false;
91                         
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;
96                                 if (!tsi.Available)
97                                         placement[i] = ToolStripItemPlacement.None;
98                                 total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0;
99                                 
100                                 if (placement[i] == ToolStripItemPlacement.Overflow)
101                                         need_overflow = true;
102                                 i++;
103                         }
104
105                         // This is needed for a button set to Overflow = Always
106                         if (need_overflow) {
107                                 ts.OverflowButton.Visible = true;
108                                 ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height));
109                                 toolstrip_width -= ts.OverflowButton.Width;
110                         } else
111                                 ts.OverflowButton.Visible = false;
112                         
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;
120                                 }                                       
121                                 
122                                 bool removed_one = false;
123                                 
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];
129                                                 removed_one = true;
130                                                 break;
131                                         }
132                         
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
135                                 if (!removed_one)
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];
140                                                         removed_one = true;
141                                                         break;
142                                                 }
143
144                                 // There's nothing left to remove, break or we will loop forever        
145                                 if (!removed_one)
146                                         break;
147                         }
148
149                         i = 0;
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;
153                         
154                         // Now we should know where everything goes, so lay everything out
155                         foreach (ToolStripItem tsi in ts.Items) {
156                                 tsi.SetPlacement (placement[i]);
157                                 
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];
162                                         } else {
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];
165                                         }                       
166                                 }
167                         
168                                 i++;
169                         }                       
170                 }
171
172                 private void LayoutVerticalToolStrip (ToolStrip ts, Rectangle bounds)
173                 {
174                         if (!ts.Visible) return;
175
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;
182                         int i = 0;
183                         bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip);
184
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;
189                                 if (!tsi.Available)
190                                         placement[i] = ToolStripItemPlacement.None;
191                                 total_height += placement[i] == ToolStripItemPlacement.Main ? heights[i] : 0;
192                                 i++;
193                         }
194
195                         ts.OverflowButton.Visible = false;
196
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;
204                                 }
205
206                                 bool removed_one = false;
207
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];
213                                                 removed_one = true;
214                                                 break;
215                                         }
216
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
219                                 if (!removed_one)
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];
224                                                         removed_one = true;
225                                                         break;
226                                                 }
227                                         
228                                 // There's nothing left to remove, break or we will loop forever        
229                                 if (!removed_one)
230                                         break;
231                         }
232
233                         i = 0;
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;
237
238                         // Now we should know where everything goes, so lay everything out
239                         foreach (ToolStripItem tsi in ts.Items) {
240                                 tsi.SetPlacement (placement[i]);
241
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];
246                                         } else {
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];
249                                         }
250                                 }
251
252                                 i++;
253                         }
254                 }
255         }
256 }
257 #endif