2007-04-02 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / StatusStrip.cs
1 //
2 // StatusStrip.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 #if NET_2_0
29
30 using System;
31 using System.Drawing;
32 using System.ComponentModel;
33 using System.Runtime.InteropServices;
34
35 namespace System.Windows.Forms
36 {
37         [ClassInterface (ClassInterfaceType.AutoDispatch)]
38         [ComVisible (true)]
39         public class StatusStrip : ToolStrip
40         {
41                 private bool sizing_grip;
42                 
43                 public StatusStrip ()
44                 {
45                         SetStyle (ControlStyles.ResizeRedraw, true);
46                         
47                         base.CanOverflow = false;
48                         this.GripStyle = ToolStripGripStyle.Hidden;
49                         base.LayoutStyle = ToolStripLayoutStyle.Table;
50                         this.sizing_grip = true;
51                         base.Stretch = true;
52                 }
53
54                 #region Public Properties
55                 [DefaultValue (DockStyle.Bottom)]
56                 public override DockStyle Dock {
57                         get { return base.Dock; }
58                         set { base.Dock = value; }
59                 }
60
61                 [Browsable (false)]
62                 [DefaultValue (false)]
63                 public new bool CanOverflow {
64                         get { return base.CanOverflow; }
65                         set { base.CanOverflow = value; }
66                 }
67                 
68                 [DefaultValue (ToolStripGripStyle.Hidden)]
69                 public new ToolStripGripStyle GripStyle {
70                         get { return base.GripStyle; }
71                         set { base.GripStyle = value; }
72                 }
73                 
74                 [DefaultValue (ToolStripLayoutStyle.Table)]
75                 public new ToolStripLayoutStyle LayoutStyle {   
76                         get { return base.LayoutStyle; }
77                         set { base.LayoutStyle = value; }
78                 }
79                 
80                 [Browsable (false)]
81                 public new Padding Padding {
82                         get { return base.Padding; }
83                         set { base.Padding = value; }
84                 }
85                 
86                 [DefaultValue (false)]
87                 public new bool ShowItemToolTips {
88                         get { return base.ShowItemToolTips; }
89                         set { base.ShowItemToolTips = value; }
90                 }
91                 
92                 [Browsable (false)]
93                 public Rectangle SizeGripBounds {
94                         get { return new Rectangle (this.Width - 12, 0, 12, this.Height); }
95                 }
96                 
97                 [DefaultValue (true)]
98                 public bool SizingGrip {
99                         get { return this.sizing_grip; }
100                         set { this.sizing_grip = value; }
101                 }
102                 
103                 [DefaultValue (true)]
104                 public new bool Stretch {
105                         get { return base.Stretch; }
106                         set { base.Stretch = value; }
107                 }
108                 #endregion
109
110                 #region Protected Properties
111                 protected override DockStyle DefaultDock {
112                         get { return DockStyle.Bottom; }
113                 }
114
115                 protected override Padding DefaultPadding {
116                         get { return new Padding (1, 0, 14, 0); }
117                 }
118
119                 protected override bool DefaultShowItemToolTips {
120                         get { return false; }
121                 }
122
123                 protected override Size DefaultSize {
124                         get { return new Size (200, 22); }
125                 }
126                 #endregion
127
128                 #region Protected Methods
129                 protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
130                 {
131                         if (text == "-")
132                                 return new ToolStripSeparator ();
133                                 
134                         return new ToolStripLabel (text, image, false, onClick);
135                 }
136
137                 protected override void Dispose (bool disposing)
138                 {
139                         base.Dispose (disposing);
140                 }
141
142                 protected override void OnLayout (LayoutEventArgs e)
143                 {
144                         this.OnSpringTableLayoutCore ();
145                 }
146
147                 protected override void OnPaintBackground (PaintEventArgs pevent)
148                 {
149                         base.OnPaintBackground (pevent);
150                         
151                         if (this.sizing_grip)
152                                 this.Renderer.DrawStatusStripSizingGrip (new ToolStripRenderEventArgs (pevent.Graphics, this));
153                 }
154
155                 protected virtual void OnSpringTableLayoutCore ()
156                 {
157                         if (!this.Created)
158                                 return;
159
160                         ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[this.Items.Count];
161                         ToolStripItemPlacement[] placement = new ToolStripItemPlacement[this.Items.Count];
162                         Size proposedSize = new Size (0, Bounds.Height);
163                         int[] widths = new int[this.Items.Count];
164                         int total_width = 0;
165                         int toolstrip_width = DisplayRectangle.Width;
166                         int i = 0;
167                         int spring_count = 0;
168
169                         foreach (ToolStripItem tsi in this.Items) {
170                                 overflow[i] = tsi.Overflow;
171                                 widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal;
172                                 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.None : ToolStripItemPlacement.Main;
173                                 placement[i] = tsi.Available ? placement[i] : ToolStripItemPlacement.None;
174                                 total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0;
175                                 if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring)
176                                         spring_count++;
177                                         
178                                 i++;
179                         }
180
181                         while (total_width > toolstrip_width) {
182                                 bool removed_one = false;
183
184                                 // Start at the right, removing Overflow.AsNeeded first
185                                 for (int j = widths.Length - 1; j >= 0; j--)
186                                         if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
187                                                 placement[j] = ToolStripItemPlacement.None;
188                                                 total_width -= widths[j];
189                                                 removed_one = true;
190                                                 break;
191                                         }
192
193                                 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
194                                 // These are not put on the Overflow, they are simply not shown
195                                 if (!removed_one)
196                                         for (int j = widths.Length - 1; j >= 0; j--)
197                                                 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
198                                                         placement[j] = ToolStripItemPlacement.None;
199                                                         total_width -= widths[j];
200                                                         removed_one = true;
201                                                         break;
202                                                 }
203
204                                 // There's nothing left to remove, break or we will loop forever        
205                                 if (!removed_one)
206                                         break;
207                         }
208
209                         if (spring_count > 0) {
210                                 int per_item = (toolstrip_width - total_width) / spring_count;
211                                 i = 0;
212                                 
213                                 foreach (ToolStripItem tsi in this.Items) {
214                                         if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring)
215                                                 widths[i] += per_item;
216                                                 
217                                         i++;
218                                 }
219                         }
220
221                         i = 0;
222                         Point layout_pointer = new Point (this.DisplayRectangle.Left, this.DisplayRectangle.Top);
223                         int button_height = this.DisplayRectangle.Height;
224
225                         // Now we should know where everything goes, so lay everything out
226                         foreach (ToolStripItem tsi in this.Items) {
227                                 tsi.SetPlacement (placement[i]);
228
229                                 if (placement[i] == ToolStripItemPlacement.Main) {
230                                         tsi.SetBounds (new Rectangle (layout_pointer.X + tsi.Margin.Left, layout_pointer.Y + tsi.Margin.Top, widths[i] - tsi.Margin.Horizontal, button_height - tsi.Margin.Vertical));
231                                         layout_pointer.X += widths[i];
232                                 }
233
234                                 i++;
235                         }
236
237                         this.SetDisplayedItems ();
238                 }
239
240                 protected override void SetDisplayedItems ()
241                 {
242                         this.displayed_items.Clear ();
243
244                         foreach (ToolStripItem tsi in this.Items)
245                                 if (tsi.Placement == ToolStripItemPlacement.Main) {
246                                         this.displayed_items.AddNoOwnerOrLayout (tsi);
247                                         tsi.InternalVisible = true;     
248                                 } else
249                                         tsi.InternalVisible = false;
250                 }
251                 
252                 protected override void WndProc (ref Message m)
253                 {
254                         switch ((Msg)m.Msg) {
255                                 // If the mouse is over the size grip, change the cursor
256                                 case Msg.WM_MOUSEMOVE: {
257                                         if (FromParamToMouseButtons ((int) m.WParam.ToInt32()) == MouseButtons.None) {  
258                                                 Point p = new Point (LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()));
259                                                 
260                                                 if (this.SizingGrip && this.SizeGripBounds.Contains (p)) {
261                                                         this.Cursor = Cursors.SizeNESW;
262                                                         return;
263                                                 } else
264                                                         this.Cursor = Cursors.Default;
265                                         }
266
267                                         break;
268                                 }
269                                 // If the left mouse button is pushed over the size grip,
270                                 // send the WM a message to begin a window resize operation
271                                 case Msg.WM_LBUTTONDOWN: {
272                                         Point p = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ()));
273
274                                         if (this.SizingGrip && this.SizeGripBounds.Contains (p)) {
275                                                 XplatUI.SendMessage (this.FindForm().Handle, Msg.WM_NCLBUTTONDOWN, (IntPtr) HitTest.HTBOTTOMRIGHT, IntPtr.Zero);
276                                                 return;
277                                         }
278                                         
279                                         break;
280                                 }
281                         }
282
283                         base.WndProc (ref m);
284                 }
285                 #endregion
286
287                 #region Public Events
288                 [Browsable (false)]
289                 public new event EventHandler PaddingChanged {
290                         add { base.PaddingChanged += value; }
291                         remove { base.PaddingChanged -= value; }
292                 }
293                 #endregion
294         }
295 }
296 #endif