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)
32 using System.ComponentModel;
33 using System.Runtime.InteropServices;
35 namespace System.Windows.Forms
37 [ClassInterface (ClassInterfaceType.AutoDispatch)]
39 public class StatusStrip : ToolStrip
41 private bool sizing_grip;
45 SetStyle (ControlStyles.ResizeRedraw, true);
47 base.CanOverflow = false;
48 this.GripStyle = ToolStripGripStyle.Hidden;
49 base.LayoutStyle = ToolStripLayoutStyle.Table;
50 base.RenderMode = ToolStripRenderMode.System;
51 this.sizing_grip = true;
55 #region Public Properties
56 [DefaultValue (DockStyle.Bottom)]
57 public override DockStyle Dock {
58 get { return base.Dock; }
59 set { base.Dock = value; }
63 [DefaultValue (false)]
64 public new bool CanOverflow {
65 get { return base.CanOverflow; }
66 set { base.CanOverflow = value; }
69 [DefaultValue (ToolStripGripStyle.Hidden)]
70 public new ToolStripGripStyle GripStyle {
71 get { return base.GripStyle; }
72 set { base.GripStyle = value; }
75 [DefaultValue (ToolStripLayoutStyle.Table)]
76 public new ToolStripLayoutStyle LayoutStyle {
77 get { return base.LayoutStyle; }
78 set { base.LayoutStyle = value; }
82 public new Padding Padding {
83 get { return base.Padding; }
84 set { base.Padding = value; }
87 [DefaultValue (false)]
88 public new bool ShowItemToolTips {
89 get { return base.ShowItemToolTips; }
90 set { base.ShowItemToolTips = value; }
94 public Rectangle SizeGripBounds {
95 get { return new Rectangle (this.Width - 12, 0, 12, this.Height); }
99 public bool SizingGrip {
100 get { return this.sizing_grip; }
101 set { this.sizing_grip = value; }
104 [DefaultValue (true)]
105 public new bool Stretch {
106 get { return base.Stretch; }
107 set { base.Stretch = value; }
111 #region Protected Properties
112 protected override DockStyle DefaultDock {
113 get { return DockStyle.Bottom; }
116 protected override Padding DefaultPadding {
117 get { return new Padding (1, 0, 14, 0); }
120 protected override bool DefaultShowItemToolTips {
121 get { return false; }
124 protected override Size DefaultSize {
125 get { return new Size (200, 22); }
129 #region Protected Methods
130 protected override AccessibleObject CreateAccessibilityInstance ()
132 return new StatusStripAccessibleObject ();
135 protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
138 return new ToolStripSeparator ();
140 return new ToolStripLabel (text, image, false, onClick);
143 protected override void Dispose (bool disposing)
145 base.Dispose (disposing);
148 protected override void OnLayout (LayoutEventArgs levent)
150 this.OnSpringTableLayoutCore ();
154 protected override void OnPaintBackground (PaintEventArgs e)
156 base.OnPaintBackground (e);
158 if (this.sizing_grip)
159 this.Renderer.DrawStatusStripSizingGrip (new ToolStripRenderEventArgs (e.Graphics, this, Bounds, SystemColors.Control));
162 protected virtual void OnSpringTableLayoutCore ()
167 ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[this.Items.Count];
168 ToolStripItemPlacement[] placement = new ToolStripItemPlacement[this.Items.Count];
169 Size proposedSize = new Size (0, Bounds.Height);
170 int[] widths = new int[this.Items.Count];
172 int toolstrip_width = DisplayRectangle.Width;
174 int spring_count = 0;
176 foreach (ToolStripItem tsi in this.Items) {
177 overflow[i] = tsi.Overflow;
178 widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal;
179 placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.None : ToolStripItemPlacement.Main;
180 placement[i] = tsi.Available && tsi.InternalVisible ? placement[i] : ToolStripItemPlacement.None;
181 total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0;
182 if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring)
188 while (total_width > toolstrip_width) {
189 bool removed_one = false;
191 // Start at the right, removing Overflow.AsNeeded first
192 for (int j = widths.Length - 1; j >= 0; j--)
193 if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) {
194 placement[j] = ToolStripItemPlacement.None;
195 total_width -= widths[j];
200 // If we didn't remove any AsNeeded ones, we have to start removing Never ones
201 // These are not put on the Overflow, they are simply not shown
203 for (int j = widths.Length - 1; j >= 0; j--)
204 if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) {
205 placement[j] = ToolStripItemPlacement.None;
206 total_width -= widths[j];
211 // There's nothing left to remove, break or we will loop forever
216 if (spring_count > 0) {
217 int per_item = (toolstrip_width - total_width) / spring_count;
220 foreach (ToolStripItem tsi in this.Items) {
221 if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring)
222 widths[i] += per_item;
229 Point layout_pointer = new Point (this.DisplayRectangle.Left, this.DisplayRectangle.Top);
230 int button_height = this.DisplayRectangle.Height;
232 // Now we should know where everything goes, so lay everything out
233 foreach (ToolStripItem tsi in this.Items) {
234 tsi.SetPlacement (placement[i]);
236 if (placement[i] == ToolStripItemPlacement.Main) {
237 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));
238 layout_pointer.X += widths[i];
244 this.SetDisplayedItems ();
247 protected override void SetDisplayedItems ()
249 // Only clean the internal collection, without modifying Owner/Parent on items.
250 this.displayed_items.ClearInternal ();
252 foreach (ToolStripItem tsi in this.Items)
253 if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) {
254 this.displayed_items.AddNoOwnerOrLayout (tsi);
259 protected override void WndProc (ref Message m)
261 switch ((Msg)m.Msg) {
262 // If the mouse is over the size grip, change the cursor
263 case Msg.WM_MOUSEMOVE: {
264 if (FromParamToMouseButtons ((int) m.WParam.ToInt32()) == MouseButtons.None) {
265 Point p = new Point (LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()));
267 if (this.SizingGrip && this.SizeGripBounds.Contains (p)) {
268 this.Cursor = Cursors.SizeNWSE;
271 this.Cursor = Cursors.Default;
276 // If the left mouse button is pushed over the size grip,
277 // send the WM a message to begin a window resize operation
278 case Msg.WM_LBUTTONDOWN: {
279 Point p = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ()));
280 Form form = FindForm ();
282 if (this.SizingGrip && this.SizeGripBounds.Contains (p)) {
283 // For top level forms it's not enoug to send a NCLBUTTONDOWN message, so
284 // we make a direct call to our XplatUI engine.
285 if (!form.IsMdiChild)
286 XplatUI.BeginMoveResize (form.Handle);
288 XplatUI.SendMessage (form.Handle, Msg.WM_NCLBUTTONDOWN, (IntPtr) HitTest.HTBOTTOMRIGHT, IntPtr.Zero);
296 base.WndProc (ref m);
300 #region Public Events
302 public new event EventHandler PaddingChanged {
303 add { base.PaddingChanged += value; }
304 remove { base.PaddingChanged -= value; }
308 #region StatusStripAccessibleObject
309 private class StatusStripAccessibleObject : AccessibleObject