2007-05-03 Chris Toshok <toshok@ximian.com>
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / StatusBar.cs
blob92ba5945fa336b60e9b7e07cba08b24bc73d6a73
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc.
22 // Authors:
23 // Jackson Harper (jackson@ximian.com)
26 // TODO:
27 // - Change cursor when mouse is over grip
30 using System.Collections;
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Drawing;
34 using System.Drawing.Text;
35 using System.Drawing.Imaging;
36 using System.Runtime.InteropServices;
38 namespace System.Windows.Forms {
39 #if NET_2_0
40 [ComVisible (true)]
41 [ClassInterface (ClassInterfaceType.AutoDispatch)]
42 #endif
43 [DefaultEvent("PanelClick")]
44 [Designer("System.Windows.Forms.Design.StatusBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45 [DefaultProperty("Text")]
46 public class StatusBar : Control {
47 #region Fields
48 private StatusBarPanelCollection panels;
50 private bool show_panels = false;
51 private bool sizing_grip = true;
53 #endregion // Fields
55 #region Public Constructors
56 public StatusBar ()
58 Dock = DockStyle.Bottom;
59 this.TabStop = false;
60 this.SetStyle(ControlStyles.UserPaint | ControlStyles.Selectable, false);
62 #endregion // Public Constructors
64 #region Public Instance Properties
65 [Browsable(false)]
66 [EditorBrowsable(EditorBrowsableState.Never)]
67 public override Color BackColor {
68 get { return base.BackColor; }
69 set { base.BackColor = value; }
72 [Browsable(false)]
73 [EditorBrowsable(EditorBrowsableState.Never)]
74 public override Image BackgroundImage {
75 get { return base.BackgroundImage; }
76 set { base.BackgroundImage = value; }
79 #if NET_2_0
80 [Browsable (false)]
81 [EditorBrowsable (EditorBrowsableState.Never)]
82 public override ImageLayout BackgroundImageLayout {
83 get {
84 return base.BackgroundImageLayout;
86 set {
87 base.BackgroundImageLayout = value;
90 #endif
92 [Localizable(true)]
93 [DefaultValue(DockStyle.Bottom)]
94 public override DockStyle Dock {
95 get { return base.Dock; }
96 set { base.Dock = value; }
99 #if NET_2_0
100 [EditorBrowsable (EditorBrowsableState.Never)]
101 protected override bool DoubleBuffered {
102 get {
103 return base.DoubleBuffered;
105 set {
106 base.DoubleBuffered = value;
109 #endif
110 [Localizable(true)]
111 public override Font Font {
112 get { return base.Font; }
113 set {
114 if (value == Font)
115 return;
116 base.Font = value;
117 UpdateStatusBar ();
121 [Browsable(false)]
122 [EditorBrowsable(EditorBrowsableState.Never)]
123 public override Color ForeColor {
124 get { return base.ForeColor; }
125 set { base.ForeColor = value; }
128 [Browsable(false)]
129 [EditorBrowsable(EditorBrowsableState.Never)]
130 public new ImeMode ImeMode {
131 get { return base.ImeMode; }
132 set { base.ImeMode = value; }
135 [MergableProperty(false)]
136 [Localizable(true)]
137 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
138 public StatusBarPanelCollection Panels {
139 get {
140 if (panels == null)
141 panels = new StatusBarPanelCollection (this);
142 return panels;
146 [DefaultValue(false)]
147 public bool ShowPanels {
148 get { return show_panels; }
149 set {
150 if (show_panels == value)
151 return;
152 show_panels = value;
153 UpdateStatusBar ();
157 [DefaultValue(true)]
158 public bool SizingGrip {
159 get { return sizing_grip; }
160 set {
161 if (sizing_grip == value)
162 return;
163 sizing_grip = value;
164 UpdateStatusBar ();
168 [DefaultValue(false)]
169 public new bool TabStop {
170 get { return base.TabStop; }
171 set { base.TabStop = value; }
174 [Localizable(true)]
175 public override string Text {
176 get { return base.Text; }
177 set {
178 if (value == Text)
179 return;
180 base.Text = value;
181 UpdateStatusBar ();
186 #endregion Public Instance Properties
188 #region Protected Instance Properties
189 protected override CreateParams CreateParams {
190 get {
191 return base.CreateParams;
195 protected override ImeMode DefaultImeMode {
196 get { return ImeMode.Disable; }
199 protected override Size DefaultSize {
200 get { return ThemeEngine.Current.StatusBarDefaultSize; }
203 #endregion // Protected Instance Properties
205 #region Public Instance Methods
206 public override string ToString () {
207 return base.ToString () + ", Panels.Count: " + Panels.Count +
208 (Panels.Count > 0 ? ", Panels[0]: " + Panels [0] : String.Empty);
211 #endregion // Public Instance Methods
213 #region Protected Instance Methods
214 protected override void CreateHandle ()
216 base.CreateHandle ();
219 protected override void Dispose (bool disposing) {
220 base.Dispose (disposing);
223 protected virtual void OnDrawItem (StatusBarDrawItemEventArgs e) {
224 StatusBarDrawItemEventHandler eh = (StatusBarDrawItemEventHandler)(Events [DrawItemEvent]);
225 if (eh != null)
226 eh (this, e);
229 protected override void OnHandleCreated (EventArgs e) {
230 base.OnHandleCreated (e);
231 CalcPanelSizes ();
234 protected override void OnHandleDestroyed (EventArgs e) {
235 base.OnHandleDestroyed (e);
238 protected override void OnLayout (LayoutEventArgs e) {
239 base.OnLayout (e);
242 protected override void OnMouseDown (MouseEventArgs e) {
243 if (panels == null)
244 return;
246 float prev_x = 0;
247 float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
248 for (int i = 0; i < panels.Count; i++) {
249 float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
250 if (e.X >= prev_x && e.X <= x) {
251 OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
252 e.Button, e.Clicks, e.X, e.Y));
253 break;
255 prev_x = x;
258 base.OnMouseDown (e);
261 protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e) {
262 StatusBarPanelClickEventHandler eh = (StatusBarPanelClickEventHandler)(Events [PanelClickEvent]);
263 if (eh != null)
264 eh (this, e);
267 protected override void OnResize (EventArgs e)
269 base.OnResize (e);
271 if (Width <= 0 || Height <= 0)
272 return;
274 UpdateStatusBar ();
277 protected override void WndProc(ref Message m) {
278 base.WndProc (ref m);
281 #endregion // Methods
284 #region Internal Methods
285 internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
287 OnDrawItem (e);
290 internal void UpdatePanel (StatusBarPanel panel)
292 if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
293 UpdateStatusBar ();
294 return;
297 UpdateStatusBar ();
300 internal void UpdatePanelContents (StatusBarPanel panel)
302 if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
303 UpdateStatusBar ();
304 Invalidate ();
305 return;
308 Invalidate (new Rectangle (panel.X + 2, 2, panel.Width - 4, bounds.Height - 4));
311 void UpdateStatusBar ()
313 CalcPanelSizes ();
314 Refresh ();
317 internal override void OnPaintInternal (PaintEventArgs pevent)
319 Draw (pevent.Graphics, pevent.ClipRectangle);
322 private void CalcPanelSizes ()
324 if (panels == null || !show_panels)
325 return;
327 if (Width == 0 || Height == 0)
328 return;
330 int border = 2;
331 int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
332 int taken = 0;
333 ArrayList springs = null;
335 taken = border;
336 for (int i = 0; i < panels.Count; i++) {
337 StatusBarPanel p = panels [i];
339 if (p.AutoSize == StatusBarPanelAutoSize.None) {
340 taken += p.Width;
341 taken += gap;
342 continue;
344 if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
345 int len = (int) (DeviceContext.MeasureString (p.Text, Font).Width + 0.5F);
346 p.SetWidth (len + 8);
347 taken += p.Width;
348 taken += gap;
349 continue;
351 if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
352 if (springs == null)
353 springs = new ArrayList ();
354 springs.Add (p);
355 taken += gap;
356 continue;
360 if (springs == null)
361 return;
363 int spring_total = springs.Count;
364 int total_width = Width - taken - (SizingGrip ? ThemeEngine.Current.StatusBarSizeGripWidth : 0);
365 for (int i = 0; i < spring_total; i++) {
366 StatusBarPanel p = (StatusBarPanel) springs [i];
367 int width = total_width / spring_total;
368 p.SetWidth (width >= p.MinWidth ? width : p.MinWidth);
371 taken = border;
372 for (int i = 0; i < panels.Count; i++) {
373 StatusBarPanel p = panels [i];
374 p.X = taken;
375 taken += p.Width + gap;
379 private void Draw (Graphics dc, Rectangle clip)
381 ThemeEngine.Current.DrawStatusBar (dc, clip, this);
384 #endregion // Internal Methods
387 #region Events
388 [Browsable(false)]
389 [EditorBrowsable(EditorBrowsableState.Never)]
390 public new event EventHandler BackColorChanged {
391 add { base.BackColorChanged += value; }
392 remove { base.BackColorChanged -= value; }
395 [Browsable(false)]
396 [EditorBrowsable(EditorBrowsableState.Never)]
397 public new event EventHandler BackgroundImageChanged {
398 add { base.BackgroundImageChanged += value; }
399 remove { base.BackgroundImageChanged -= value; }
402 #if NET_2_0
403 [Browsable (false)]
404 [EditorBrowsable (EditorBrowsableState.Never)]
405 public new event EventHandler BackgroundImageLayoutChanged
407 add { base.BackgroundImageLayoutChanged += value; }
408 remove { base.BackgroundImageLayoutChanged -= value; }
410 #endif
412 [Browsable(false)]
413 [EditorBrowsable(EditorBrowsableState.Never)]
414 public new event EventHandler ForeColorChanged {
415 add { base.ForeColorChanged += value; }
416 remove { base.ForeColorChanged -= value; }
419 [Browsable(false)]
420 [EditorBrowsable(EditorBrowsableState.Never)]
421 public new event EventHandler ImeModeChanged {
422 add { base.ImeModeChanged += value; }
423 remove { base.ImeModeChanged -= value; }
426 [Browsable(false)]
427 [EditorBrowsable(EditorBrowsableState.Never)]
428 public new event PaintEventHandler Paint {
429 add { base.Paint += value; }
430 remove { base.Paint -= value; }
433 static object DrawItemEvent = new object ();
434 static object PanelClickEvent = new object ();
436 public event StatusBarDrawItemEventHandler DrawItem {
437 add { Events.AddHandler (DrawItemEvent, value); }
438 remove { Events.RemoveHandler (DrawItemEvent, value); }
441 public event StatusBarPanelClickEventHandler PanelClick {
442 add { Events.AddHandler (PanelClickEvent, value); }
443 remove { Events.RemoveHandler (PanelClickEvent, value); }
445 #endregion // Events
448 #region Subclass StatusBarPanelCollection
449 #if NET_2_0
450 [ListBindable (false)]
451 #endif
452 public class StatusBarPanelCollection : IList, ICollection, IEnumerable {
453 #region Fields
454 private StatusBar owner;
455 private ArrayList panels;
456 #if NET_2_0
457 private int last_index_by_key;
458 #endif
459 #endregion // Fields
461 #region Public Constructors
462 public StatusBarPanelCollection (StatusBar owner)
464 this.owner = owner;
467 #endregion // Public Constructors
469 #region Private & Internal Methods
470 private int AddInternal (StatusBarPanel p, bool refresh) {
471 if (p == null)
472 throw new ArgumentNullException ("value");
473 if (panels == null)
474 panels = new ArrayList ();
476 int res = panels.Add (p);
477 p.SetParent (owner);
479 if (refresh) {
480 owner.CalcPanelSizes ();
481 owner.Refresh ();
484 return res;
487 #endregion // Private & Internal Methods
489 #region Public Instance Properties
490 [Browsable(false)]
491 [EditorBrowsable(EditorBrowsableState.Never)]
492 public int Count {
493 get {
494 if (panels == null)
495 return 0;
496 return panels.Count;
500 public bool IsReadOnly {
501 get { return false; }
504 public virtual StatusBarPanel this [int index] {
505 get {
506 if (index < 0 || index >= Count)
507 throw new ArgumentOutOfRangeException ("index");
508 return (StatusBarPanel) panels [index];
510 set {
511 if (value == null)
512 throw new ArgumentNullException ("index");
513 if (index < 0 || index >= Count)
514 throw new ArgumentOutOfRangeException ("index");
515 panels [index] = value;
519 #if NET_2_0
521 public virtual StatusBarPanel this [string key] {
522 get {
523 int index = IndexOfKey (key);
524 if (index >= 0 && index < Count) {
525 return (StatusBarPanel) panels [index];
527 return null;
530 #endif
532 #endregion // Public Instance Properties
534 #region Public Instance Methods
535 public virtual int Add (StatusBarPanel p) {
536 return AddInternal (p, true);
539 public virtual StatusBarPanel Add (string text) {
540 StatusBarPanel res = new StatusBarPanel ();
541 res.Text = text;
542 Add (res);
543 return res;
546 public virtual void AddRange (StatusBarPanel [] range) {
547 if (range == null)
548 throw new ArgumentNullException ("panels");
549 if (range.Length == 0)
550 return;
551 if (panels == null)
552 panels = new ArrayList (range.Length);
554 for (int i = 0; i < range.Length; i++)
555 AddInternal (range [i], false);
556 owner.Refresh ();
559 public virtual void Clear () {
560 panels.Clear ();
562 owner.Refresh ();
565 public bool Contains (StatusBarPanel panel) {
566 return panels.Contains (panel);
569 #if NET_2_0
570 public virtual bool ContainsKey (string key)
572 int index = IndexOfKey (key);
573 return index >= 0 && index < Count;
575 #endif
577 public IEnumerator GetEnumerator () {
578 return panels.GetEnumerator ();
581 public int IndexOf (StatusBarPanel panel) {
582 return panels.IndexOf (panel);
585 #if NET_2_0
586 public virtual int IndexOfKey (string key)
588 if (key == null || key == string.Empty)
589 return -1;
591 if (last_index_by_key >= 0 && last_index_by_key < Count &&
592 String.Compare (((StatusBarPanel)panels [last_index_by_key]).Name, key, StringComparison.OrdinalIgnoreCase) == 0) {
593 return last_index_by_key;
596 for (int i = 0; i < Count; i++) {
597 StatusBarPanel item;
598 item = panels [i] as StatusBarPanel;
599 if (item != null && String.Compare (item.Name, key, StringComparison.OrdinalIgnoreCase) == 0) {
600 last_index_by_key = i;
601 return i;
605 return -1;
607 #endif
609 public virtual void Insert (int index, StatusBarPanel value) {
610 if (value == null)
611 throw new ArgumentNullException ("value");
612 if (index > Count)
613 throw new ArgumentOutOfRangeException ("index");
614 // TODO: InvalidArgumentException for bad AutoSize values
615 // although it seems impossible to set it to a bad value
616 value.SetParent (owner);
617 panels [index] = value;
619 owner.Refresh ();
622 public virtual void Remove (StatusBarPanel panel) {
623 panels.Remove (panel);
626 public virtual void RemoveAt (int index) {
627 panels.RemoveAt (index);
630 #if NET_2_0
631 public virtual void RemoveByKey (string key)
633 int index = IndexOfKey (key);
634 if (index >= 0 && index < Count)
635 RemoveAt (index);
637 #endif
639 #endregion // Public Instance Methods
641 #region IList & ICollection Interfaces
642 bool ICollection.IsSynchronized {
643 get { return panels.IsSynchronized; }
646 object ICollection.SyncRoot {
647 get { return panels.SyncRoot; }
650 void ICollection.CopyTo (Array dest, int index)
652 panels.CopyTo (dest, index);
656 object IList.this [int index] {
657 get { return panels [index]; }
658 set { panels [index] = value; }
661 int IList.Add (object value) {
662 return panels.Add (value);
665 bool IList.Contains (object panel) {
666 return panels.Contains (panel);
669 int IList.IndexOf (object panel)
671 return panels.IndexOf (panel);
674 void IList.Insert (int index, object value)
676 panels.Insert (index, value);
679 bool IList.IsFixedSize {
680 get { return false; }
683 void IList.Remove (object value)
685 panels.Remove (value);
687 #endregion // IList & ICollection Interfaces
689 #endregion // Subclass StatusBarPanelCollection