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 if (!IsDisposed
&& disposing
)
225 if (tooltip_timer
!= null)
226 tooltip_timer
.Dispose();
228 if (tooltip_window
!= null)
229 tooltip_window
.Dispose();
231 if (panels
!= null) {
232 var copiedPanels
= new StatusBarPanel
[panels
.Count
];
233 ((ICollection
) panels
).CopyTo (copiedPanels
, 0);
236 foreach (StatusBarPanel panel
in copiedPanels
) {
242 base.Dispose (disposing
);
245 protected virtual void OnDrawItem (StatusBarDrawItemEventArgs sbdievent
) {
246 StatusBarDrawItemEventHandler eh
= (StatusBarDrawItemEventHandler
)(Events
[DrawItemEvent
]);
248 eh (this, sbdievent
);
251 protected override void OnHandleCreated (EventArgs e
) {
252 base.OnHandleCreated (e
);
256 protected override void OnHandleDestroyed (EventArgs e
) {
257 base.OnHandleDestroyed (e
);
260 protected override void OnLayout (LayoutEventArgs levent
) {
261 base.OnLayout (levent
);
264 protected override void OnMouseDown (MouseEventArgs e
) {
269 float gap
= ThemeEngine
.Current
.StatusBarHorzGapWidth
;
270 for (int i
= 0; i
< panels
.Count
; i
++) {
271 float x
= panels
[i
].Width
+ prev_x
+ (i
== panels
.Count
- 1 ? gap
: gap
/ 2);
272 if (e
.X
>= prev_x
&& e
.X
<= x
) {
273 OnPanelClick (new StatusBarPanelClickEventArgs (panels
[i
],
274 e
.Button
, e
.Clicks
, e
.X
, e
.Y
));
280 base.OnMouseDown (e
);
283 protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e
) {
284 StatusBarPanelClickEventHandler eh
= (StatusBarPanelClickEventHandler
)(Events
[PanelClickEvent
]);
289 protected override void OnResize (EventArgs e
)
293 if (Width
<= 0 || Height
<= 0)
299 protected override void WndProc(ref Message m
) {
300 base.WndProc (ref m
);
303 #endregion // Methods
306 #region Internal Methods
307 internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e
)
312 internal void UpdatePanel (StatusBarPanel panel
)
314 if (panel
.AutoSize
== StatusBarPanelAutoSize
.Contents
) {
322 internal void UpdatePanelContents (StatusBarPanel panel
)
324 if (panel
.AutoSize
== StatusBarPanelAutoSize
.Contents
) {
330 Invalidate (new Rectangle (panel
.X
+ 2, 2, panel
.Width
- 4, bounds
.Height
- 4));
333 void UpdateStatusBar ()
339 internal override void OnPaintInternal (PaintEventArgs pevent
)
341 Draw (pevent
.Graphics
, pevent
.ClipRectangle
);
344 private void CalcPanelSizes ()
346 if (panels
== null || !show_panels
)
349 if (Width
== 0 || Height
== 0)
353 int gap
= ThemeEngine
.Current
.StatusBarHorzGapWidth
;
355 ArrayList springs
= null;
358 for (int i
= 0; i
< panels
.Count
; i
++) {
359 StatusBarPanel p
= panels
[i
];
361 if (p
.AutoSize
== StatusBarPanelAutoSize
.None
) {
366 if (p
.AutoSize
== StatusBarPanelAutoSize
.Contents
) {
367 int len
= (int)(TextRenderer
.MeasureString (p
.Text
, Font
).Width
+ 0.5F
);
368 if (p
.Icon
!= null) {
371 p
.SetWidth (len
+ 8);
376 if (p
.AutoSize
== StatusBarPanelAutoSize
.Spring
) {
378 springs
= new ArrayList ();
385 if (springs
!= null) {
386 int spring_total
= springs
.Count
;
387 int total_width
= Width
- taken
- (SizingGrip
? ThemeEngine
.Current
.StatusBarSizeGripWidth
: 0);
388 for (int i
= 0; i
< spring_total
; i
++) {
389 StatusBarPanel p
= (StatusBarPanel
)springs
[i
];
390 int width
= total_width
/ spring_total
;
391 p
.SetWidth(width
>= p
.MinWidth
? width
: p
.MinWidth
);
396 for (int i
= 0; i
< panels
.Count
; i
++) {
397 StatusBarPanel p
= panels
[i
];
399 taken
+= p
.Width
+ gap
;
403 private void Draw (Graphics dc
, Rectangle clip
)
405 ThemeEngine
.Current
.DrawStatusBar (dc
, clip
, this);
408 #endregion // Internal Methods
410 #region Stuff for ToolTips
411 private void StatusBar_MouseMove (object sender
, MouseEventArgs e
)
416 StatusBarPanel p
= GetPanelAtPoint (e
.Location
);
418 if (p
!= tooltip_currently_showing
)
419 MouseLeftPanel (tooltip_currently_showing
);
421 if (p
!= null && tooltip_currently_showing
== null)
422 MouseEnteredPanel (p
);
425 private void StatusBar_MouseLeave (object sender
, EventArgs e
)
427 if (tooltip_currently_showing
!= null)
428 MouseLeftPanel (tooltip_currently_showing
);
431 private StatusBarPanel
GetPanelAtPoint (Point point
)
433 foreach (StatusBarPanel p
in Panels
)
434 if (point
.X
>= p
.X
&& point
.X
<= (p
.X
+ p
.Width
))
440 private void MouseEnteredPanel (StatusBarPanel item
)
442 tooltip_currently_showing
= item
;
443 ToolTipTimer
.Start ();
446 private void MouseLeftPanel (StatusBarPanel item
)
448 ToolTipTimer
.Stop ();
449 ToolTipWindow
.Hide (this);
450 tooltip_currently_showing
= null;
453 private Timer ToolTipTimer
{
455 if (tooltip_timer
== null) {
456 tooltip_timer
= new Timer ();
457 tooltip_timer
.Enabled
= false;
458 tooltip_timer
.Interval
= 500;
459 tooltip_timer
.Tick
+= new EventHandler (ToolTipTimer_Tick
);
462 return tooltip_timer
;
466 private ToolTip ToolTipWindow
{
468 if (tooltip_window
== null)
469 tooltip_window
= new ToolTip ();
471 return tooltip_window
;
475 private void ToolTipTimer_Tick (object o
, EventArgs args
)
477 string tooltip
= tooltip_currently_showing
.ToolTipText
;
479 if (tooltip
!= null && tooltip
.Length
> 0)
480 ToolTipWindow
.Present (this, tooltip
);
482 ToolTipTimer
.Stop ();
488 [EditorBrowsable(EditorBrowsableState
.Never
)]
489 public new event EventHandler BackColorChanged
{
490 add { base.BackColorChanged += value; }
491 remove { base.BackColorChanged -= value; }
495 [EditorBrowsable(EditorBrowsableState
.Never
)]
496 public new event EventHandler BackgroundImageChanged
{
497 add { base.BackgroundImageChanged += value; }
498 remove { base.BackgroundImageChanged -= value; }
502 [EditorBrowsable (EditorBrowsableState
.Never
)]
503 public new event EventHandler BackgroundImageLayoutChanged
505 add { base.BackgroundImageLayoutChanged += value; }
506 remove { base.BackgroundImageLayoutChanged -= value; }
510 [EditorBrowsable(EditorBrowsableState
.Never
)]
511 public new event EventHandler ForeColorChanged
{
512 add { base.ForeColorChanged += value; }
513 remove { base.ForeColorChanged -= value; }
517 [EditorBrowsable(EditorBrowsableState
.Never
)]
518 public new event EventHandler ImeModeChanged
{
519 add { base.ImeModeChanged += value; }
520 remove { base.ImeModeChanged -= value; }
524 [EditorBrowsable(EditorBrowsableState
.Never
)]
525 public new event PaintEventHandler Paint
{
526 add { base.Paint += value; }
527 remove { base.Paint -= value; }
530 static object DrawItemEvent
= new object ();
531 static object PanelClickEvent
= new object ();
533 public event StatusBarDrawItemEventHandler DrawItem
{
534 add { Events.AddHandler (DrawItemEvent, value); }
535 remove { Events.RemoveHandler (DrawItemEvent, value); }
538 public event StatusBarPanelClickEventHandler PanelClick
{
539 add { Events.AddHandler (PanelClickEvent, value); }
540 remove { Events.RemoveHandler (PanelClickEvent, value); }
545 #region Subclass StatusBarPanelCollection
546 [ListBindable (false)]
547 public class StatusBarPanelCollection
: IList
, ICollection
, IEnumerable
{
549 private StatusBar owner
;
550 private ArrayList panels
= new ArrayList ();
551 private int last_index_by_key
;
554 #region UIA Framework Events
555 static object UIACollectionChangedEvent
= new object ();
557 internal event CollectionChangeEventHandler UIACollectionChanged
{
558 add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
559 remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
562 internal void OnUIACollectionChanged (CollectionChangeEventArgs e
)
564 CollectionChangeEventHandler eh
565 = (CollectionChangeEventHandler
) owner
.Events
[UIACollectionChangedEvent
];
571 #region Public Constructors
572 public StatusBarPanelCollection (StatusBar owner
)
577 #endregion // Public Constructors
579 #region Private & Internal Methods
580 private int AddInternal (StatusBarPanel p
, bool refresh
) {
582 throw new ArgumentNullException ("value");
585 int res
= panels
.Add (p
);
588 owner
.CalcPanelSizes ();
592 // UIA Framework Event: Panel Added
593 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Add
, res
));
598 #endregion // Private & Internal Methods
600 #region Public Instance Properties
602 [EditorBrowsable(EditorBrowsableState
.Never
)]
604 get { return panels.Count; }
607 public bool IsReadOnly
{
608 get { return false; }
611 public virtual StatusBarPanel
this [int index
] {
613 if (index
< 0 || index
>= Count
)
614 throw new ArgumentOutOfRangeException ("index");
615 return (StatusBarPanel
) panels
[index
];
619 throw new ArgumentNullException ("index");
620 if (index
< 0 || index
>= Count
)
621 throw new ArgumentOutOfRangeException ("index");
623 // UIA Framework Event: Panel Removed
624 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Remove
, index
));
626 value.SetParent (owner
);
628 panels
[index
] = value;
630 // UIA Framework Event: Panel Added
631 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Add
, index
));
635 public virtual StatusBarPanel
this [string key
] {
637 int index
= IndexOfKey (key
);
638 if (index
>= 0 && index
< Count
) {
639 return (StatusBarPanel
) panels
[index
];
645 #endregion // Public Instance Properties
647 #region Public Instance Methods
648 public virtual int Add (StatusBarPanel
value) {
649 return AddInternal (value, true);
652 public virtual StatusBarPanel
Add (string text
) {
653 StatusBarPanel res
= new StatusBarPanel ();
659 public virtual void AddRange (StatusBarPanel
[] panels
) {
661 throw new ArgumentNullException ("panels");
662 if (panels
.Length
== 0)
665 for (int i
= 0; i
< panels
.Length
; i
++)
666 AddInternal (panels
[i
], false);
670 public virtual void Clear () {
675 // UIA Framework Event: Panel Cleared
676 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Refresh
, -1));
679 public bool Contains (StatusBarPanel panel
) {
680 return panels
.Contains (panel
);
683 public virtual bool ContainsKey (string key
)
685 int index
= IndexOfKey (key
);
686 return index
>= 0 && index
< Count
;
689 public IEnumerator
GetEnumerator () {
690 return panels
.GetEnumerator ();
693 public int IndexOf (StatusBarPanel panel
) {
694 return panels
.IndexOf (panel
);
697 public virtual int IndexOfKey (string key
)
699 if (key
== null || key
== string.Empty
)
702 if (last_index_by_key
>= 0 && last_index_by_key
< Count
&&
703 String
.Compare (((StatusBarPanel
)panels
[last_index_by_key
]).Name
, key
, StringComparison
.OrdinalIgnoreCase
) == 0) {
704 return last_index_by_key
;
707 for (int i
= 0; i
< Count
; i
++) {
709 item
= panels
[i
] as StatusBarPanel
;
710 if (item
!= null && String
.Compare (item
.Name
, key
, StringComparison
.OrdinalIgnoreCase
) == 0) {
711 last_index_by_key
= i
;
719 public virtual void Insert (int index
, StatusBarPanel
value) {
721 throw new ArgumentNullException ("value");
723 throw new ArgumentOutOfRangeException ("index");
724 // TODO: InvalidArgumentException for bad AutoSize values
725 // although it seems impossible to set it to a bad value
726 value.SetParent (owner
);
728 panels
.Insert(index
, value);
731 // UIA Framework Event: Panel Added
732 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Add
, index
));
735 public virtual void Remove (StatusBarPanel
value) {
736 int index
= IndexOf (value);
737 panels
.Remove (value);
739 // UIA Framework Event: Panel Removed
741 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Remove
, index
));
744 public virtual void RemoveAt (int index
) {
745 panels
.RemoveAt (index
);
747 // UIA Framework Event: Panel Removed
748 OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction
.Remove
, index
));
751 public virtual void RemoveByKey (string key
)
753 int index
= IndexOfKey (key
);
754 if (index
>= 0 && index
< Count
)
758 #endregion // Public Instance Methods
760 #region IList & ICollection Interfaces
761 bool ICollection
.IsSynchronized
{
762 get { return panels.IsSynchronized; }
765 object ICollection
.SyncRoot
{
766 get { return panels.SyncRoot; }
769 void ICollection
.CopyTo (Array dest
, int index
)
771 panels
.CopyTo (dest
, index
);
775 object IList
.this [int index
] {
776 get { return this[index]; }
778 if (!(value is StatusBarPanel
))
779 throw new ArgumentException ("Value must be of type StatusBarPanel.", "value");
781 this[index
] = (StatusBarPanel
)value;
785 int IList
.Add (object value) {
786 if (!(value is StatusBarPanel
))
787 throw new ArgumentException ("Value must be of type StatusBarPanel.", "value");
789 return AddInternal ((StatusBarPanel
)value, true);
792 bool IList
.Contains (object panel
) {
793 return panels
.Contains (panel
);
796 int IList
.IndexOf (object panel
)
798 return panels
.IndexOf (panel
);
801 void IList
.Insert (int index
, object value)
803 if (!(value is StatusBarPanel
))
804 throw new ArgumentException ("Value must be of type StatusBarPanel.", "value");
806 Insert (index
, (StatusBarPanel
)value);
809 bool IList
.IsFixedSize
{
810 get { return false; }
813 void IList
.Remove (object value)
815 StatusBarPanel s
= value as StatusBarPanel
;
818 #endregion // IList & ICollection Interfaces
820 #endregion // Subclass StatusBarPanelCollection