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:
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.
23 // Jackson Harper (jackson@ximian.com)
27 // - Change cursor when mouse is over grip
30 using System.Collections;
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
34 using System.Drawing.Text;
35 using System.Drawing.Imaging;
36 using System.Runtime.InteropServices;
38 namespace System.Windows.Forms {
40 [ClassInterface (ClassInterfaceType.AutoDispatch)]
41 [DefaultEvent("PanelClick")]
42 [Designer("System.Windows.Forms.Design.StatusBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43 [DefaultProperty("Text")]
44 public class StatusBar : Control {
46 private StatusBarPanelCollection panels;
48 private bool show_panels = false;
49 private bool sizing_grip = true;
51 // Stuff for panel Tooltips
52 private Timer tooltip_timer;
53 private ToolTip tooltip_window;
54 private StatusBarPanel tooltip_currently_showing;
57 #region Public Constructors
60 Dock = DockStyle.Bottom;
62 this.SetStyle(ControlStyles.UserPaint | ControlStyles.Selectable, false);
64 // For displaying/hiding tooltips
65 MouseMove += new MouseEventHandler (StatusBar_MouseMove);
66 MouseLeave += new EventHandler (StatusBar_MouseLeave);
68 #endregion // Public Constructors
70 #region Public Instance Properties
72 [EditorBrowsable(EditorBrowsableState.Never)]
73 public override Color BackColor {
74 get { return base.BackColor; }
75 set { base.BackColor = value; }
79 [EditorBrowsable(EditorBrowsableState.Never)]
80 public override Image BackgroundImage {
81 get { return base.BackgroundImage; }
82 set { base.BackgroundImage = value; }
86 [EditorBrowsable (EditorBrowsableState.Never)]
87 public override ImageLayout BackgroundImageLayout {
89 return base.BackgroundImageLayout;
92 base.BackgroundImageLayout = value;
97 [DefaultValue(DockStyle.Bottom)]
98 public override DockStyle Dock {
99 get { return base.Dock; }
100 set { base.Dock = value; }
103 [EditorBrowsable (EditorBrowsableState.Never)]
104 protected override bool DoubleBuffered {
106 return base.DoubleBuffered;
109 base.DoubleBuffered = value;
114 public override Font Font {
115 get { return base.Font; }
125 [EditorBrowsable(EditorBrowsableState.Never)]
126 public override Color ForeColor {
127 get { return base.ForeColor; }
128 set { base.ForeColor = value; }
132 [EditorBrowsable(EditorBrowsableState.Never)]
133 public new ImeMode ImeMode {
134 get { return base.ImeMode; }
135 set { base.ImeMode = value; }
138 [MergableProperty(false)]
140 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
141 public StatusBarPanelCollection Panels {
144 panels = new StatusBarPanelCollection (this);
149 [DefaultValue(false)]
150 public bool ShowPanels {
151 get { return show_panels; }
153 if (show_panels == value)
161 public bool SizingGrip {
162 get { return sizing_grip; }
164 if (sizing_grip == value)
171 [DefaultValue(false)]
172 public new bool TabStop {
173 get { return base.TabStop; }
174 set { base.TabStop = value; }
178 public override string Text {
179 get { return base.Text; }
189 #endregion Public Instance Properties
191 #region Protected Instance Properties
192 protected override CreateParams CreateParams {
194 return base.CreateParams;
198 protected override ImeMode DefaultImeMode {
199 get { return ImeMode.Disable; }
202 protected override Size DefaultSize {
203 get { return ThemeEngine.Current.StatusBarDefaultSize; }
206 #endregion // Protected Instance Properties
208 #region Public Instance Methods
209 public override string ToString () {
210 return base.ToString () + ", Panels.Count: " + Panels.Count +
211 (Panels.Count > 0 ? ", Panels[0]: " + Panels [0] : String.Empty);
214 #endregion // Public Instance Methods
216 #region Protected Instance Methods
217 protected override void CreateHandle ()
219 base.CreateHandle ();
222 protected override void Dispose (bool disposing) {
223 base.Dispose (disposing);
226 protected virtual void OnDrawItem (StatusBarDrawItemEventArgs sbdievent) {
227 StatusBarDrawItemEventHandler eh = (StatusBarDrawItemEventHandler)(Events [DrawItemEvent]);
229 eh (this, sbdievent);
232 protected override void OnHandleCreated (EventArgs e) {
233 base.OnHandleCreated (e);
237 protected override void OnHandleDestroyed (EventArgs e) {
238 base.OnHandleDestroyed (e);
241 protected override void OnLayout (LayoutEventArgs levent) {
242 base.OnLayout (levent);
245 protected override void OnMouseDown (MouseEventArgs e) {
250 float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
251 for (int i = 0; i < panels.Count; i++) {
252 float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
253 if (e.X >= prev_x && e.X <= x) {
254 OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
255 e.Button, e.Clicks, e.X, e.Y));
261 base.OnMouseDown (e);
264 protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e) {
265 StatusBarPanelClickEventHandler eh = (StatusBarPanelClickEventHandler)(Events [PanelClickEvent]);
270 protected override void OnResize (EventArgs e)
274 if (Width <= 0 || Height <= 0)
280 protected override void WndProc(ref Message m) {
281 base.WndProc (ref m);
284 #endregion // Methods
287 #region Internal Methods
288 internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
293 internal void UpdatePanel (StatusBarPanel panel)
295 if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
303 internal void UpdatePanelContents (StatusBarPanel panel)
305 if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
311 Invalidate (new Rectangle (panel.X + 2, 2, panel.Width - 4, bounds.Height - 4));
314 void UpdateStatusBar ()
320 internal override void OnPaintInternal (PaintEventArgs pevent)
322 Draw (pevent.Graphics, pevent.ClipRectangle);
325 private void CalcPanelSizes ()
327 if (panels == null || !show_panels)
330 if (Width == 0 || Height == 0)
334 int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
336 ArrayList springs = null;
339 for (int i = 0; i < panels.Count; i++) {
340 StatusBarPanel p = panels [i];
342 if (p.AutoSize == StatusBarPanelAutoSize.None) {
347 if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
348 int len = (int)(TextRenderer.MeasureString (p.Text, Font).Width + 0.5F);
349 if (p.Icon != null) {
352 p.SetWidth (len + 8);
357 if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
359 springs = new ArrayList ();
366 if (springs != null) {
367 int spring_total = springs.Count;
368 int total_width = Width - taken - (SizingGrip ? ThemeEngine.Current.StatusBarSizeGripWidth : 0);
369 for (int i = 0; i < spring_total; i++) {
370 StatusBarPanel p = (StatusBarPanel)springs[i];
371 int width = total_width / spring_total;
372 p.SetWidth(width >= p.MinWidth ? width : p.MinWidth);
377 for (int i = 0; i < panels.Count; i++) {
378 StatusBarPanel p = panels [i];
380 taken += p.Width + gap;
384 private void Draw (Graphics dc, Rectangle clip)
386 ThemeEngine.Current.DrawStatusBar (dc, clip, this);
389 #endregion // Internal Methods
391 #region Stuff for ToolTips
392 private void StatusBar_MouseMove (object sender, MouseEventArgs e)
397 StatusBarPanel p = GetPanelAtPoint (e.Location);
399 if (p != tooltip_currently_showing)
400 MouseLeftPanel (tooltip_currently_showing);
402 if (p != null && tooltip_currently_showing == null)
403 MouseEnteredPanel (p);
406 private void StatusBar_MouseLeave (object sender, EventArgs e)
408 if (tooltip_currently_showing != null)
409 MouseLeftPanel (tooltip_currently_showing);
412 private StatusBarPanel GetPanelAtPoint (Point point)
414 foreach (StatusBarPanel p in Panels)
415 if (point.X >= p.X && point.X <= (p.X + p.Width))
421 private void MouseEnteredPanel (StatusBarPanel item)
423 tooltip_currently_showing = item;
424 ToolTipTimer.Start ();
427 private void MouseLeftPanel (StatusBarPanel item)
429 ToolTipTimer.Stop ();
430 ToolTipWindow.Hide (this);
431 tooltip_currently_showing = null;
434 private Timer ToolTipTimer {
436 if (tooltip_timer == null) {
437 tooltip_timer = new Timer ();
438 tooltip_timer.Enabled = false;
439 tooltip_timer.Interval = 500;
440 tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick);
443 return tooltip_timer;
447 private ToolTip ToolTipWindow {
449 if (tooltip_window == null)
450 tooltip_window = new ToolTip ();
452 return tooltip_window;
456 private void ToolTipTimer_Tick (object o, EventArgs args)
458 string tooltip = tooltip_currently_showing.ToolTipText;
460 if (tooltip != null && tooltip.Length > 0)
461 ToolTipWindow.Present (this, tooltip);
463 ToolTipTimer.Stop ();
469 [EditorBrowsable(EditorBrowsableState.Never)]
470 public new event EventHandler BackColorChanged {
471 add { base.BackColorChanged += value; }
472 remove { base.BackColorChanged -= value; }
476 [EditorBrowsable(EditorBrowsableState.Never)]
477 public new event EventHandler BackgroundImageChanged {
478 add { base.BackgroundImageChanged += value; }
479 remove { base.BackgroundImageChanged -= value; }
483 [EditorBrowsable (EditorBrowsableState.Never)]
484 public new event EventHandler BackgroundImageLayoutChanged
486 add { base.BackgroundImageLayoutChanged += value; }
487 remove { base.BackgroundImageLayoutChanged -= value; }
491 [EditorBrowsable(EditorBrowsableState.Never)]
492 public new event EventHandler ForeColorChanged {
493 add { base.ForeColorChanged += value; }
494 remove { base.ForeColorChanged -= value; }
498 [EditorBrowsable(EditorBrowsableState.Never)]
499 public new event EventHandler ImeModeChanged {
500 add { base.ImeModeChanged += value; }
501 remove { base.ImeModeChanged -= value; }
505 [EditorBrowsable(EditorBrowsableState.Never)]
506 public new event PaintEventHandler Paint {
507 add { base.Paint += value; }
508 remove { base.Paint -= value; }
511 static object DrawItemEvent = new object ();
512 static object PanelClickEvent = new object ();
514 public event StatusBarDrawItemEventHandler DrawItem {
515 add { Events.AddHandler (DrawItemEvent, value); }
516 remove { Events.RemoveHandler (DrawItemEvent, value); }
519 public event StatusBarPanelClickEventHandler PanelClick {
520 add { Events.AddHandler (PanelClickEvent, value); }
521 remove { Events.RemoveHandler (PanelClickEvent, value); }
526 #region Subclass StatusBarPanelCollection
527 [ListBindable (false)]
528 public class StatusBarPanelCollection : IList, ICollection, IEnumerable {
530 private StatusBar owner;
531 private ArrayList panels = new ArrayList ();
532 private int last_index_by_key;
535 #region UIA Framework Events
536 static object UIACollectionChangedEvent = new object ();
538 internal event CollectionChangeEventHandler UIACollectionChanged {
539 add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
540 remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
543 internal void OnUIACollectionChanged (CollectionChangeEventArgs e)
545 CollectionChangeEventHandler eh
546 = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
552 #region Public Constructors
553 public StatusBarPanelCollection (StatusBar owner)
558 #endregion // Public Constructors
560 #region Private & Internal Methods
561 private int AddInternal (StatusBarPanel p, bool refresh) {
563 throw new ArgumentNullException ("value");
566 int res = panels.Add (p);
569 owner.CalcPanelSizes ();
573 // UIA Framework Event: Panel Added
574 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, res));
579 #endregion // Private & Internal Methods
581 #region Public Instance Properties
583 [EditorBrowsable(EditorBrowsableState.Never)]
585 get { return panels.Count; }
588 public bool IsReadOnly {
589 get { return false; }
592 public virtual StatusBarPanel this [int index] {
594 if (index < 0 || index >= Count)
595 throw new ArgumentOutOfRangeException ("index");
596 return (StatusBarPanel) panels [index];
600 throw new ArgumentNullException ("index");
601 if (index < 0 || index >= Count)
602 throw new ArgumentOutOfRangeException ("index");
604 // UIA Framework Event: Panel Removed
605 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index));
607 value.SetParent (owner);
609 panels [index] = value;
611 // UIA Framework Event: Panel Added
612 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, index));
616 public virtual StatusBarPanel this [string key] {
618 int index = IndexOfKey (key);
619 if (index >= 0 && index < Count) {
620 return (StatusBarPanel) panels [index];
626 #endregion // Public Instance Properties
628 #region Public Instance Methods
629 public virtual int Add (StatusBarPanel value) {
630 return AddInternal (value, true);
633 public virtual StatusBarPanel Add (string text) {
634 StatusBarPanel res = new StatusBarPanel ();
640 public virtual void AddRange (StatusBarPanel [] panels) {
642 throw new ArgumentNullException ("panels");
643 if (panels.Length == 0)
646 for (int i = 0; i < panels.Length; i++)
647 AddInternal (panels [i], false);
651 public virtual void Clear () {
656 // UIA Framework Event: Panel Cleared
657 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, -1));
660 public bool Contains (StatusBarPanel panel) {
661 return panels.Contains (panel);
664 public virtual bool ContainsKey (string key)
666 int index = IndexOfKey (key);
667 return index >= 0 && index < Count;
670 public IEnumerator GetEnumerator () {
671 return panels.GetEnumerator ();
674 public int IndexOf (StatusBarPanel panel) {
675 return panels.IndexOf (panel);
678 public virtual int IndexOfKey (string key)
680 if (key == null || key == string.Empty)
683 if (last_index_by_key >= 0 && last_index_by_key < Count &&
684 String.Compare (((StatusBarPanel)panels [last_index_by_key]).Name, key, StringComparison.OrdinalIgnoreCase) == 0) {
685 return last_index_by_key;
688 for (int i = 0; i < Count; i++) {
690 item = panels [i] as StatusBarPanel;
691 if (item != null && String.Compare (item.Name, key, StringComparison.OrdinalIgnoreCase) == 0) {
692 last_index_by_key = i;
700 public virtual void Insert (int index, StatusBarPanel value) {
702 throw new ArgumentNullException ("value");
704 throw new ArgumentOutOfRangeException ("index");
705 // TODO: InvalidArgumentException for bad AutoSize values
706 // although it seems impossible to set it to a bad value
707 value.SetParent (owner);
709 panels.Insert(index, value);
712 // UIA Framework Event: Panel Added
713 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, index));
716 public virtual void Remove (StatusBarPanel value) {
717 int index = IndexOf (value);
718 panels.Remove (value);
720 // UIA Framework Event: Panel Removed
722 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index));
725 public virtual void RemoveAt (int index) {
726 panels.RemoveAt (index);
728 // UIA Framework Event: Panel Removed
729 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index));
732 public virtual void RemoveByKey (string key)
734 int index = IndexOfKey (key);
735 if (index >= 0 && index < Count)
739 #endregion // Public Instance Methods
741 #region IList & ICollection Interfaces
742 bool ICollection.IsSynchronized {
743 get { return panels.IsSynchronized; }
746 object ICollection.SyncRoot {
747 get { return panels.SyncRoot; }
750 void ICollection.CopyTo (Array dest, int index)
752 panels.CopyTo (dest, index);
756 object IList.this [int index] {
757 get { return this[index]; }
759 if (!(value is StatusBarPanel))
760 throw new ArgumentException ("Value must be of type StatusBarPanel.", "value");
762 this[index] = (StatusBarPanel)value;
766 int IList.Add (object value) {
767 if (!(value is StatusBarPanel))
768 throw new ArgumentException ("Value must be of type StatusBarPanel.", "value");
770 return AddInternal ((StatusBarPanel)value, true);
773 bool IList.Contains (object panel) {
774 return panels.Contains (panel);
777 int IList.IndexOf (object panel)
779 return panels.IndexOf (panel);
782 void IList.Insert (int index, object value)
784 if (!(value is StatusBarPanel))
785 throw new ArgumentException ("Value must be of type StatusBarPanel.", "value");
787 Insert (index, (StatusBarPanel)value);
790 bool IList.IsFixedSize {
791 get { return false; }
794 void IList.Remove (object value)
796 StatusBarPanel s = value as StatusBarPanel;
799 #endregion // IList & ICollection Interfaces
801 #endregion // Subclass StatusBarPanelCollection