/mcs/class/Managed.Windows.Forms/System.Windows.Forms/StatusStrip.cs
C# | 313 lines | 224 code | 51 blank | 38 comment | 38 complexity | d4df8fa716502e7660c68853c5a63c19 MD5 | raw file
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
29using System;
30using System.Drawing;
31using System.ComponentModel;
32using System.Runtime.InteropServices;
33
34namespace System.Windows.Forms
35{
36 [ClassInterface (ClassInterfaceType.AutoDispatch)]
37 [ComVisible (true)]
38 public class StatusStrip : ToolStrip
39 {
40 private bool sizing_grip;
41
42 public StatusStrip ()
43 {
44 SetStyle (ControlStyles.ResizeRedraw, true);
45
46 base.CanOverflow = false;
47 this.GripStyle = ToolStripGripStyle.Hidden;
48 base.LayoutStyle = ToolStripLayoutStyle.Table;
49 base.RenderMode = ToolStripRenderMode.System;
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 override AccessibleObject CreateAccessibilityInstance ()
130 {
131 return new StatusStripAccessibleObject ();
132 }
133
134 protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
135 {
136 if (text == "-")
137 return new ToolStripSeparator ();
138
139 return new ToolStripLabel (text, image, false, onClick);
140 }
141
142 protected override void Dispose (bool disposing)
143 {
144 base.Dispose (disposing);
145 }
146
147 protected override void OnLayout (LayoutEventArgs levent)
148 {
149 this.OnSpringTableLayoutCore ();
150 this.Invalidate ();
151 }
152
153 protected override void OnPaintBackground (PaintEventArgs e)
154 {
155 base.OnPaintBackground (e);
156
157 if (this.sizing_grip)
158 this.Renderer.DrawStatusStripSizingGrip (new ToolStripRenderEventArgs (e.Graphics, this, Bounds, SystemColors.Control));
159 }
160
161 protected virtual void OnSpringTableLayoutCore ()
162 {
163 if (!this.Created)
164 return;
165
166 ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[this.Items.Count];
167 ToolStripItemPlacement[] placement = new ToolStripItemPlacement[this.Items.Count];
168 Size proposedSize = new Size (0, Bounds.Height);
169 int[] widths = new int[this.Items.Count];
170 int total_width = 0;
171 int toolstrip_width = DisplayRectangle.Width;
172 int i = 0;
173 int spring_count = 0;
174
175 foreach (ToolStripItem tsi in this.Items) {
176 overflow[i] = tsi.Overflow;
177 widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal;
178 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.None : ToolStripItemPlacement.Main;
179 placement[i] = tsi.Available && tsi.InternalVisible ? placement[i] : ToolStripItemPlacement.None;
180 total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0;
181 if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring)
182 spring_count++;
183
184 i++;
185 }
186
187 while (total_width > toolstrip_width) {
188 bool removed_one = false;
189
190 // Start at the right, removing Overflow.AsNeeded first
191 for (int j = widths.Length - 1; j >= 0; j--)
192 if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
193 placement[j] = ToolStripItemPlacement.None;
194 total_width -= widths[j];
195 removed_one = true;
196 break;
197 }
198
199 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
200 // These are not put on the Overflow, they are simply not shown
201 if (!removed_one)
202 for (int j = widths.Length - 1; j >= 0; j--)
203 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
204 placement[j] = ToolStripItemPlacement.None;
205 total_width -= widths[j];
206 removed_one = true;
207 break;
208 }
209
210 // There's nothing left to remove, break or we will loop forever
211 if (!removed_one)
212 break;
213 }
214
215 if (spring_count > 0) {
216 int per_item = (toolstrip_width - total_width) / spring_count;
217 i = 0;
218
219 foreach (ToolStripItem tsi in this.Items) {
220 if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring)
221 widths[i] += per_item;
222
223 i++;
224 }
225 }
226
227 i = 0;
228 Point layout_pointer = new Point (this.DisplayRectangle.Left, this.DisplayRectangle.Top);
229 int button_height = this.DisplayRectangle.Height;
230
231 // Now we should know where everything goes, so lay everything out
232 foreach (ToolStripItem tsi in this.Items) {
233 tsi.SetPlacement (placement[i]);
234
235 if (placement[i] == ToolStripItemPlacement.Main) {
236 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));
237 layout_pointer.X += widths[i];
238 }
239
240 i++;
241 }
242
243 this.SetDisplayedItems ();
244 }
245
246 protected override void SetDisplayedItems ()
247 {
248 // Only clean the internal collection, without modifying Owner/Parent on items.
249 this.displayed_items.ClearInternal ();
250
251 foreach (ToolStripItem tsi in this.Items)
252 if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) {
253 this.displayed_items.AddNoOwnerOrLayout (tsi);
254 tsi.Parent = this;
255 }
256 }
257
258 protected override void WndProc (ref Message m)
259 {
260 switch ((Msg)m.Msg) {
261 // If the mouse is over the size grip, change the cursor
262 case Msg.WM_MOUSEMOVE: {
263 if (FromParamToMouseButtons ((int) m.WParam.ToInt32()) == MouseButtons.None) {
264 Point p = new Point (LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()));
265
266 if (this.SizingGrip && this.SizeGripBounds.Contains (p)) {
267 this.Cursor = Cursors.SizeNWSE;
268 return;
269 } else
270 this.Cursor = Cursors.Default;
271 }
272
273 break;
274 }
275 // If the left mouse button is pushed over the size grip,
276 // send the WM a message to begin a window resize operation
277 case Msg.WM_LBUTTONDOWN: {
278 Point p = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ()));
279 Form form = FindForm ();
280
281 if (this.SizingGrip && this.SizeGripBounds.Contains (p)) {
282 // For top level forms it's not enoug to send a NCLBUTTONDOWN message, so
283 // we make a direct call to our XplatUI engine.
284 if (!form.IsMdiChild)
285 XplatUI.BeginMoveResize (form.Handle);
286
287 XplatUI.SendMessage (form.Handle, Msg.WM_NCLBUTTONDOWN, (IntPtr) HitTest.HTBOTTOMRIGHT, IntPtr.Zero);
288 return;
289 }
290
291 break;
292 }
293 }
294
295 base.WndProc (ref m);
296 }
297 #endregion
298
299 #region Public Events
300 [Browsable (false)]
301 public new event EventHandler PaddingChanged {
302 add { base.PaddingChanged += value; }
303 remove { base.PaddingChanged -= value; }
304 }
305 #endregion
306
307 #region StatusStripAccessibleObject
308 private class StatusStripAccessibleObject : AccessibleObject
309 {
310 }
311 #endregion
312 }
313}