2007-03-19 Chris Toshok <toshok@ximian.com>
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / StatusBar.cs
blobbd19bde9169ca59a275f0f0857b2b16ce6f89288
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 [Browsable (false)]
101 [EditorBrowsable (EditorBrowsableState.Never)]
102 protected override bool DoubleBuffered {
103 get {
104 return base.DoubleBuffered;
106 set {
107 base.DoubleBuffered = value;
110 #endif
111 [Localizable(true)]
112 public override Font Font {
113 get { return base.Font; }
114 set {
115 if (value == Font)
116 return;
117 base.Font = value;
118 UpdateStatusBar ();
122 [Browsable(false)]
123 [EditorBrowsable(EditorBrowsableState.Never)]
124 public override Color ForeColor {
125 get { return base.ForeColor; }
126 set { base.ForeColor = value; }
129 [Browsable(false)]
130 [EditorBrowsable(EditorBrowsableState.Never)]
131 public new ImeMode ImeMode {
132 get { return base.ImeMode; }
133 set { base.ImeMode = value; }
136 [MergableProperty(false)]
137 [Localizable(true)]
138 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
139 public StatusBarPanelCollection Panels {
140 get {
141 if (panels == null)
142 panels = new StatusBarPanelCollection (this);
143 return panels;
147 [DefaultValue(false)]
148 public bool ShowPanels {
149 get { return show_panels; }
150 set {
151 if (show_panels == value)
152 return;
153 show_panels = value;
154 UpdateStatusBar ();
158 [DefaultValue(true)]
159 public bool SizingGrip {
160 get { return sizing_grip; }
161 set {
162 if (sizing_grip == value)
163 return;
164 sizing_grip = value;
165 UpdateStatusBar ();
169 [DefaultValue(false)]
170 public new bool TabStop {
171 get { return base.TabStop; }
172 set { base.TabStop = value; }
175 [Localizable(true)]
176 public override string Text {
177 get { return base.Text; }
178 set {
179 if (value == Text)
180 return;
181 base.Text = value;
182 UpdateStatusBar ();
187 #endregion Public Instance Properties
189 #region Protected Instance Properties
190 protected override CreateParams CreateParams {
191 get {
192 return base.CreateParams;
196 protected override ImeMode DefaultImeMode {
197 get { return ImeMode.Disable; }
200 protected override Size DefaultSize {
201 get { return ThemeEngine.Current.StatusBarDefaultSize; }
204 #endregion // Protected Instance Properties
206 #region Public Instance Methods
207 public override string ToString () {
208 return base.ToString () + ", Panels.Count: " + Panels.Count +
209 (Panels.Count > 0 ? ", Panels[0]: " + Panels [0] : String.Empty);
212 #endregion // Public Instance Methods
214 #region Protected Instance Methods
215 protected override void CreateHandle ()
217 base.CreateHandle ();
220 protected override void Dispose (bool disposing) {
221 base.Dispose (disposing);
224 protected virtual void OnDrawItem (StatusBarDrawItemEventArgs e) {
225 StatusBarDrawItemEventHandler eh = (StatusBarDrawItemEventHandler)(Events [DrawItemEvent]);
226 if (eh != null)
227 eh (this, e);
230 protected override void OnHandleCreated (EventArgs e) {
231 base.OnHandleCreated (e);
232 CalcPanelSizes ();
235 protected override void OnHandleDestroyed (EventArgs e) {
236 base.OnHandleDestroyed (e);
239 protected override void OnLayout (LayoutEventArgs e) {
240 base.OnLayout (e);
243 protected override void OnMouseDown (MouseEventArgs e) {
244 if (panels == null)
245 return;
247 float prev_x = 0;
248 float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
249 for (int i = 0; i < panels.Count; i++) {
250 float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
251 if (e.X >= prev_x && e.X <= x) {
252 OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
253 e.Button, e.Clicks, e.X, e.Y));
254 break;
256 prev_x = x;
259 base.OnMouseDown (e);
262 protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e) {
263 StatusBarPanelClickEventHandler eh = (StatusBarPanelClickEventHandler)(Events [PanelClickEvent]);
264 if (eh != null)
265 eh (this, e);
268 protected override void OnResize (EventArgs e)
270 base.OnResize (e);
272 if (Width <= 0 || Height <= 0)
273 return;
275 UpdateStatusBar ();
278 protected override void WndProc(ref Message m) {
279 base.WndProc (ref m);
282 #endregion // Methods
285 #region Internal Methods
286 internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
288 OnDrawItem (e);
291 internal void UpdatePanel (StatusBarPanel panel)
293 if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
294 UpdateStatusBar ();
295 return;
298 UpdateStatusBar ();
301 internal void UpdatePanelContents (StatusBarPanel panel)
303 if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
304 UpdateStatusBar ();
305 Invalidate ();
306 return;
309 Invalidate (new Rectangle (panel.X + 2, 2, panel.Width - 4, bounds.Height - 4));
312 void UpdateStatusBar ()
314 CalcPanelSizes ();
315 Refresh ();
318 internal override void OnPaintInternal (PaintEventArgs pevent)
320 Draw (pevent.Graphics, pevent.ClipRectangle);
323 private void CalcPanelSizes ()
325 if (panels == null || !show_panels)
326 return;
328 if (Width == 0 || Height == 0)
329 return;
331 int border = 2;
332 int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
333 int taken = 0;
334 ArrayList springs = null;
336 taken = border;
337 for (int i = 0; i < panels.Count; i++) {
338 StatusBarPanel p = panels [i];
340 if (p.AutoSize == StatusBarPanelAutoSize.None) {
341 taken += p.Width;
342 taken += gap;
343 continue;
345 if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
346 int len = (int) (DeviceContext.MeasureString (p.Text, Font).Width + 0.5F);
347 p.SetWidth (len + 8);
348 taken += p.Width;
349 taken += gap;
350 continue;
352 if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
353 if (springs == null)
354 springs = new ArrayList ();
355 springs.Add (p);
356 taken += gap;
357 continue;
361 if (springs == null)
362 return;
364 int spring_total = springs.Count;
365 int total_width = Width - taken - (SizingGrip ? ThemeEngine.Current.StatusBarSizeGripWidth : 0);
366 for (int i = 0; i < spring_total; i++) {
367 StatusBarPanel p = (StatusBarPanel) springs [i];
368 int width = total_width / spring_total;
369 p.SetWidth (width >= p.MinWidth ? width : p.MinWidth);
372 taken = border;
373 for (int i = 0; i < panels.Count; i++) {
374 StatusBarPanel p = panels [i];
375 p.X = taken;
376 taken += p.Width + gap;
380 private void Draw (Graphics dc, Rectangle clip)
382 ThemeEngine.Current.DrawStatusBar (dc, clip, this);
385 #endregion // Internal Methods
388 #region Events
389 [Browsable(false)]
390 [EditorBrowsable(EditorBrowsableState.Never)]
391 public new event EventHandler BackColorChanged {
392 add { base.BackColorChanged += value; }
393 remove { base.BackColorChanged -= value; }
396 [Browsable(false)]
397 [EditorBrowsable(EditorBrowsableState.Never)]
398 public new event EventHandler BackgroundImageChanged {
399 add { base.BackgroundImageChanged += value; }
400 remove { base.BackgroundImageChanged -= value; }
403 #if NET_2_0
404 [Browsable (false)]
405 [EditorBrowsable (EditorBrowsableState.Never)]
406 public new event EventHandler BackgroundImageLayoutChanged
408 add { base.BackgroundImageLayoutChanged += value; }
409 remove { base.BackgroundImageLayoutChanged -= value; }
411 #endif
413 [Browsable(false)]
414 [EditorBrowsable(EditorBrowsableState.Never)]
415 public new event EventHandler ForeColorChanged {
416 add { base.ForeColorChanged += value; }
417 remove { base.ForeColorChanged -= value; }
420 [Browsable(false)]
421 [EditorBrowsable(EditorBrowsableState.Never)]
422 public new event EventHandler ImeModeChanged {
423 add { base.ImeModeChanged += value; }
424 remove { base.ImeModeChanged -= value; }
427 [Browsable(false)]
428 [EditorBrowsable(EditorBrowsableState.Never)]
429 public new event PaintEventHandler Paint {
430 add { base.Paint += value; }
431 remove { base.Paint -= value; }
434 static object DrawItemEvent = new object ();
435 static object PanelClickEvent = new object ();
437 public event StatusBarDrawItemEventHandler DrawItem {
438 add { Events.AddHandler (DrawItemEvent, value); }
439 remove { Events.RemoveHandler (DrawItemEvent, value); }
442 public event StatusBarPanelClickEventHandler PanelClick {
443 add { Events.AddHandler (PanelClickEvent, value); }
444 remove { Events.RemoveHandler (PanelClickEvent, value); }
446 #endregion // Events
449 #region Subclass StatusBarPanelCollection
450 #if NET_2_0
451 [ListBindable (false)]
452 #endif
453 public class StatusBarPanelCollection : IList, ICollection, IEnumerable {
454 #region Fields
455 private StatusBar owner;
456 private ArrayList panels;
457 #if NET_2_0
458 private int last_index_by_key;
459 #endif
460 #endregion // Fields
462 #region Public Constructors
463 public StatusBarPanelCollection (StatusBar owner)
465 this.owner = owner;
468 #endregion // Public Constructors
470 #region Private & Internal Methods
471 private int AddInternal (StatusBarPanel p, bool refresh) {
472 if (p == null)
473 throw new ArgumentNullException ("value");
474 if (panels == null)
475 panels = new ArrayList ();
477 int res = panels.Add (p);
478 p.SetParent (owner);
480 if (refresh) {
481 owner.CalcPanelSizes ();
482 owner.Refresh ();
485 return res;
488 #endregion // Private & Internal Methods
490 #region Public Instance Properties
491 [Browsable(false)]
492 [EditorBrowsable(EditorBrowsableState.Never)]
493 public int Count {
494 get {
495 if (panels == null)
496 return 0;
497 return panels.Count;
501 public bool IsReadOnly {
502 get { return false; }
505 public virtual StatusBarPanel this [int index] {
506 get {
507 if (index < 0 || index >= Count)
508 throw new ArgumentOutOfRangeException ("index");
509 return (StatusBarPanel) panels [index];
511 set {
512 if (value == null)
513 throw new ArgumentNullException ("index");
514 if (index < 0 || index >= Count)
515 throw new ArgumentOutOfRangeException ("index");
516 panels [index] = value;
520 #if NET_2_0
522 public virtual StatusBarPanel this [string key] {
523 get {
524 int index = IndexOfKey (key);
525 if (index >= 0 && index < Count) {
526 return (StatusBarPanel) panels [index];
528 return null;
531 #endif
533 #endregion // Public Instance Properties
535 #region Public Instance Methods
536 public virtual int Add (StatusBarPanel p) {
537 return AddInternal (p, true);
540 public virtual StatusBarPanel Add (string text) {
541 StatusBarPanel res = new StatusBarPanel ();
542 res.Text = text;
543 Add (res);
544 return res;
547 public virtual void AddRange (StatusBarPanel [] range) {
548 if (range == null)
549 throw new ArgumentNullException ("panels");
550 if (range.Length == 0)
551 return;
552 if (panels == null)
553 panels = new ArrayList (range.Length);
555 for (int i = 0; i < range.Length; i++)
556 AddInternal (range [i], false);
557 owner.Refresh ();
560 public virtual void Clear () {
561 panels.Clear ();
563 owner.Refresh ();
566 public bool Contains (StatusBarPanel panel) {
567 return panels.Contains (panel);
570 #if NET_2_0
571 public virtual bool ContainsKey (string key)
573 int index = IndexOfKey (key);
574 return index >= 0 && index < Count;
576 #endif
578 public IEnumerator GetEnumerator () {
579 return panels.GetEnumerator ();
582 public int IndexOf (StatusBarPanel panel) {
583 return panels.IndexOf (panel);
586 #if NET_2_0
587 public virtual int IndexOfKey (string key)
589 if (key == null || key == string.Empty)
590 return -1;
592 if (last_index_by_key >= 0 && last_index_by_key < Count &&
593 String.Compare (((StatusBarPanel)panels [last_index_by_key]).Name, key, StringComparison.OrdinalIgnoreCase) == 0) {
594 return last_index_by_key;
597 for (int i = 0; i < Count; i++) {
598 StatusBarPanel item;
599 item = panels [i] as StatusBarPanel;
600 if (item != null && String.Compare (item.Name, key, StringComparison.OrdinalIgnoreCase) == 0) {
601 last_index_by_key = i;
602 return i;
606 return -1;
608 #endif
610 public virtual void Insert (int index, StatusBarPanel value) {
611 if (value == null)
612 throw new ArgumentNullException ("value");
613 if (index > Count)
614 throw new ArgumentOutOfRangeException ("index");
615 // TODO: InvalidArgumentException for bad AutoSize values
616 // although it seems impossible to set it to a bad value
617 value.SetParent (owner);
618 panels [index] = value;
620 owner.Refresh ();
623 public virtual void Remove (StatusBarPanel panel) {
624 panels.Remove (panel);
627 public virtual void RemoveAt (int index) {
628 panels.RemoveAt (index);
631 #if NET_2_0
632 public virtual void RemoveByKey (string key)
634 int index = IndexOfKey (key);
635 if (index >= 0 && index < Count)
636 RemoveAt (index);
638 #endif
640 #endregion // Public Instance Methods
642 #region IList & ICollection Interfaces
643 bool ICollection.IsSynchronized {
644 get { return panels.IsSynchronized; }
647 object ICollection.SyncRoot {
648 get { return panels.SyncRoot; }
651 void ICollection.CopyTo (Array dest, int index)
653 panels.CopyTo (dest, index);
657 object IList.this [int index] {
658 get { return panels [index]; }
659 set { panels [index] = value; }
662 int IList.Add (object value) {
663 return panels.Add (value);
666 bool IList.Contains (object panel) {
667 return panels.Contains (panel);
670 int IList.IndexOf (object panel)
672 return panels.IndexOf (panel);
675 void IList.Insert (int index, object value)
677 panels.Insert (index, value);
680 bool IList.IsFixedSize {
681 get { return false; }
684 void IList.Remove (object value)
686 panels.Remove (value);
688 #endregion // IList & ICollection Interfaces
690 #endregion // Subclass StatusBarPanelCollection