* TreeView.cs: Don't draw the selected node when we lose
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / StatusBar.cs
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.
11 //
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.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24
25 //
26 // TODO:
27 //  - Change cursor when mouse is over grip
28 //
29
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
37 namespace System.Windows.Forms {
38         [DefaultEvent("PanelClick")]
39         [Designer("System.Windows.Forms.Design.StatusBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
40         [DefaultProperty("Text")]
41         public class StatusBar : Control {
42                 #region Fields
43                 private StatusBarPanelCollection panels;
44
45                 private bool show_panels = false;
46                 private bool sizing_grip = true;
47
48                 #endregion      // Fields
49
50                 #region Public Constructors
51                 [MonoTODO("Change cursor when mouse is over grip")]
52                 public StatusBar ()
53                 {
54                         base.Dock = DockStyle.Bottom;
55                         Anchor = AnchorStyles.Top | AnchorStyles.Left;
56                         this.TabStop = false;
57                         this.SetStyle(ControlStyles.UserPaint | ControlStyles.Selectable, false);
58                 }
59                 #endregion      // Public Constructors
60
61                 #region Public Instance Properties
62                 [Browsable(false)]
63                 [EditorBrowsable(EditorBrowsableState.Never)]
64                 public Color BackColor {
65                         get { return base.BackColor; }
66                         set {
67                                 if (value == BackColor)
68                                         return;
69                                 base.BackColor = value;
70                                 if (BackColorChanged != null)
71                                         BackColorChanged (this, EventArgs.Empty);
72                                 Refresh ();
73                         }
74                 }
75
76                 [Browsable(false)]
77                 [EditorBrowsable(EditorBrowsableState.Never)]
78                 public Image BackgroundImage {
79                         get { return base.BackgroundImage; }
80                         set {
81                                 if (value == BackgroundImage)
82                                         return;
83                                 base.BackgroundImage = value;
84                                 if (BackgroundImageChanged != null)
85                                         BackgroundImageChanged (this, EventArgs.Empty);
86                         }
87                 }
88
89                 [Localizable(true)]
90                 [DefaultValue(DockStyle.Bottom)]
91                 public override DockStyle Dock {
92                         get { return base.Dock; }
93                         set {
94                                 if (value == Dock)
95                                         return;
96                                 base.Dock = value;
97                                 Refresh ();
98                         }
99                 }
100
101                 [Localizable(true)]
102                 public override Font Font {
103                         get { return base.Font; }
104                         set {
105                                 if (value == Font)
106                                         return;
107                                 base.Font = value;
108                                 Refresh ();
109                         }
110                 }
111
112                 [Browsable(false)]
113                 [EditorBrowsable(EditorBrowsableState.Never)]
114                 public Color ForeColor {
115                         get { return base.ForeColor; }
116                         set {
117                                 if (value == ForeColor)
118                                         return;
119                                 if (ForeColorChanged != null)
120                                         ForeColorChanged (this, EventArgs.Empty);
121                                 Refresh ();
122                         }
123                 }
124
125                 [Browsable(false)]
126                 [EditorBrowsable(EditorBrowsableState.Never)]
127                 public new ImeMode ImeMode {
128                         get { return base.ImeMode; }
129                         set {
130                                 if (value == ImeMode)
131                                         return;
132                                 base.ImeMode = value;
133                                 if (ImeModeChanged != null)
134                                         ImeModeChanged (this, EventArgs.Empty);
135                         }
136                 }
137
138                 [MergableProperty(false)]
139                 [Localizable(true)]
140                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
141                 public StatusBarPanelCollection Panels {
142                         get {
143                                 if (panels == null)
144                                         panels = new StatusBarPanelCollection (this);
145                                 return panels;
146                         }
147                 }
148
149                 [DefaultValue(false)]
150                 public bool ShowPanels {
151                         get { return show_panels; }
152                         set {
153                                 if (show_panels == value)
154                                         return;
155                                 show_panels = value;
156                         }
157                 }
158
159                 [DefaultValue(true)]
160                 public bool SizingGrip {
161                         get { return sizing_grip; }
162                         set {
163                                 if (sizing_grip == value)
164                                         return;
165                                 sizing_grip = value;
166                         }
167                 }
168
169                 [DefaultValue(false)]
170                 public new bool TabStop {
171                         get { return base.TabStop; }
172                         set { base.TabStop = value; }
173                 }
174
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                                 Refresh ();
183                         }
184                         
185                 }
186
187                 #endregion Public Instance Properties
188
189                 #region Protected Instance Properties
190                 protected override CreateParams CreateParams {
191                         get {
192                                 return base.CreateParams;
193                         }
194                 }
195
196                 protected override ImeMode DefaultImeMode {
197                         get { return ImeMode.Disable; }
198                 }
199
200                 protected override Size DefaultSize {
201                         get { return ThemeEngine.Current.StatusBarDefaultSize; }
202                 }
203
204                 #endregion      // Protected Instance Properties
205
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);
210                 }
211
212                 #endregion      // Public Instance Methods
213
214                 #region Protected Instance Methods
215                 protected override void CreateHandle ()
216                 {
217                         base.CreateHandle ();
218                 }
219
220                 protected override void Dispose (bool disposing) {
221                         base.Dispose (disposing);
222                 }
223
224                 protected virtual void OnDrawItem (StatusBarDrawItemEventArgs e) {
225                         if (DrawItem != null)
226                                 DrawItem (this, e);
227                 }
228
229                 protected override void OnHandleCreated (EventArgs e) {
230                         base.OnHandleCreated (e);
231                 }
232
233                 protected override void OnHandleDestroyed (EventArgs e) {
234                         base.OnHandleDestroyed (e);
235                 }
236
237                 protected override void OnLayout (LayoutEventArgs e) {
238                         base.OnLayout (e);
239                 }
240
241                 protected override void OnMouseDown (MouseEventArgs e) {
242                         if (panels == null)
243                                 return;
244
245                         float prev_x = 0;
246                         float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
247                         for (int i = 0; i < panels.Count; i++) {
248                                 float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
249                                 if (e.X >= prev_x && e.X <= x) {
250                                         OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
251                                                 e.Button, e.Clicks, e.X, e.Y));
252                                         break;
253                                 }
254                                 prev_x = x;
255                         }
256
257                         base.OnMouseDown (e);
258                 }
259
260                 protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e) {
261                         if (PanelClick != null)
262                                 PanelClick (this, e);
263                 }
264
265                 protected override void OnResize (EventArgs e)
266                 {
267                         base.OnResize (e);
268
269                         if (Width <= 0 || Height <= 0)
270                                 return;
271
272                         CalcPanelSizes ();
273                 }
274
275                 protected override void WndProc(ref Message m) {
276                         switch ((Msg) m.Msg) {
277                                 case Msg.WM_PAINT: {                            
278                                         PaintEventArgs  paint_event;
279
280                                         paint_event = XplatUI.PaintEventStart (Handle, true);
281                                         DoPaint (paint_event);
282                                         XplatUI.PaintEventEnd (Handle, true);
283                                         return;
284                                 }
285                         }
286                         base.WndProc (ref m);
287                 }
288
289                 #endregion      // Methods
290
291
292                 #region Internal Methods
293                 internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
294                 {
295                         OnDrawItem (e);
296                 }
297
298                 private void DoPaint (PaintEventArgs pevent)
299                 {
300                         if (Width <= 0 || Height <=  0 || Visible == false)
301                                 return;
302
303                         CalcPanelSizes ();
304                         Draw (pevent.Graphics, pevent.ClipRectangle);
305                 }
306
307                 private void CalcPanelSizes ()
308                 {
309                         if (panels == null || !show_panels)
310                                 return;
311
312                         if (Width == 0 || Height == 0)
313                                 return;
314
315                         int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
316                         int taken = 0;
317                         ArrayList springs = null;
318                         for (int i = 0; i < panels.Count; i++) {
319                                 StatusBarPanel p = panels [i];
320                                 if (p.AutoSize == StatusBarPanelAutoSize.None) {
321                                         taken += p.Width;
322                                         taken += gap;
323                                         continue;
324                                 }
325                                 if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
326                                         int len = (int) (DeviceContext.MeasureString (p.Text, Font).Width + 0.5F);
327                                         p.Width = (int) (len + 8);
328                                         taken += p.Width;
329                                         taken += gap;
330                                         continue;
331                                 }
332                                 if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
333                                         if (springs == null)
334                                                 springs = new ArrayList ();
335                                         springs.Add (p);
336                                         taken += gap;
337                                         continue;
338                                 }
339                         }
340
341                         if (springs == null)
342                                 return;
343
344                         int spring_total = springs.Count;
345                         int total_width = Width - taken - (SizingGrip ? ThemeEngine.Current.StatusBarSizeGripWidth : 0);
346                         for (int i = 0; i < spring_total; i++) {
347                                 StatusBarPanel p = (StatusBarPanel) springs [i];
348                                 int width = total_width / spring_total;
349                                 p.Width = (width >= p.MinWidth ? width : p.MinWidth);
350                         }
351                 }
352
353                 private void Draw (Graphics dc, Rectangle clip)
354                 {
355                         ThemeEngine.Current.DrawStatusBar (dc, this.ClientRectangle, this);
356                 }
357                 #endregion      // Internal Methods
358
359
360                 #region Events
361                 [Browsable(false)]
362                 [EditorBrowsable(EditorBrowsableState.Never)]
363                 public new event EventHandler BackColorChanged;
364
365                 [Browsable(false)]
366                 [EditorBrowsable(EditorBrowsableState.Never)]
367                 public new event EventHandler BackgroundImageChanged;
368
369                 [Browsable(false)]
370                 [EditorBrowsable(EditorBrowsableState.Never)]
371                 public new event EventHandler ForeColorChanged;
372
373                 [Browsable(false)]
374                 [EditorBrowsable(EditorBrowsableState.Never)]
375                 public new event EventHandler ImeModeChanged;
376
377                 public event StatusBarDrawItemEventHandler DrawItem;
378
379                 [Browsable(false)]
380                 [EditorBrowsable(EditorBrowsableState.Never)]
381                 public new event PaintEventHandler Paint;
382                 public event StatusBarPanelClickEventHandler PanelClick;
383                 #endregion      // Events
384                 
385
386                 #region Subclass StatusBarPanelCollection
387                 public class StatusBarPanelCollection :  IList, ICollection, IEnumerable {
388                         #region Fields
389                         private StatusBar owner;
390                         private ArrayList panels;
391                         #endregion      // Fields
392
393                         #region Public Constructors
394                         public StatusBarPanelCollection (StatusBar owner)
395                         {
396                                 this.owner = owner;
397                         }
398
399                         #endregion      // Public Constructors
400
401                         #region Private & Internal Methods
402                         private int AddInternal (StatusBarPanel p, bool refresh) {
403                                 if (p == null)
404                                         throw new ArgumentNullException ("value");
405                                 if (panels == null)
406                                         panels = new ArrayList ();
407
408                                 int res = panels.Add (p);
409                                 p.SetParent (owner);
410
411                                 if (refresh) {
412                                         owner.CalcPanelSizes ();
413                                         owner.Refresh ();
414                                 }
415
416                                 return res;
417                         }
418
419                         #endregion      // Private & Internal Methods
420
421                         #region Public Instance Properties
422                         [Browsable(false)]
423                         [EditorBrowsable(EditorBrowsableState.Never)]
424                         public virtual int Count {
425                                 get {
426                                         if (panels == null)
427                                                 return 0;
428                                         return panels.Count;
429                                 }
430                         }
431
432                         public virtual bool IsReadOnly {
433                                 get { return false; }
434                         }
435
436                         public virtual StatusBarPanel this [int index] {
437                                 get {
438                                         if (index < 0 || index >= Count)
439                                                 throw new ArgumentOutOfRangeException ("index");
440                                         return (StatusBarPanel) panels [index];
441                                 }
442                                 set {
443                                         if (value == null)
444                                                 throw new ArgumentNullException ("index");
445                                         if (index < 0 || index >= Count)
446                                                 throw new ArgumentOutOfRangeException ("index");
447                                         panels [index] = value;
448                                 }
449                         }
450
451                         #endregion      // Public Instance Properties
452
453                         #region Public Instance Methods
454                         public virtual int Add (StatusBarPanel p) {
455                                 return AddInternal (p, true);
456                         }
457
458                         public virtual StatusBarPanel Add (string text) {
459                                 StatusBarPanel res = new StatusBarPanel ();
460                                 res.Text = text;
461                                 Add (res);
462                                 return res;
463                         }
464
465                         public virtual void AddRange (StatusBarPanel [] range) {
466                                 if (range == null)
467                                         throw new ArgumentNullException ("panels");
468                                 if (range.Length == 0)
469                                         return;
470                                 if (panels == null)
471                                         panels = new ArrayList (range.Length);
472
473                                 for (int i = 0; i < range.Length; i++)
474                                         AddInternal (range [i], false);
475                                 owner.Refresh ();
476                         }
477
478                         public virtual void Clear () {
479                                 panels.Clear ();
480
481                                 owner.Refresh ();
482                         }
483
484                         public virtual bool Contains (StatusBarPanel panel) {
485                                 return panels.Contains (panel);
486                         }
487
488                         public virtual IEnumerator GetEnumerator () {
489                                 return panels.GetEnumerator ();
490                         }
491
492                         public virtual int IndexOf (StatusBarPanel panel) {
493                                 return panels.IndexOf (panel);
494                         }
495
496                         public virtual void Insert (int index, StatusBarPanel value) {
497                                 if (value == null)
498                                         throw new ArgumentNullException ("value");
499                                 if (index > Count)
500                                         throw new ArgumentOutOfRangeException ("index");
501                                 // TODO: InvalidArgumentException for bad AutoSize values
502                                 // although it seems impossible to set it to a bad value
503                                 value.SetParent (owner);
504                                 panels [index] = value;
505
506                                 owner.Refresh ();
507                         }
508
509                         public virtual void Remove (StatusBarPanel panel) {
510                                 panels.Remove (panel);
511                         }
512
513                         public virtual void RemoveAt (int index) {
514                                 panels.RemoveAt (index);
515                         }
516
517                         #endregion      // Public Instance Methods
518
519                         #region IList & ICollection Interfaces
520                         bool ICollection.IsSynchronized {
521                                 get { return panels.IsSynchronized; }
522                         }
523
524                         object ICollection.SyncRoot {
525                                 get { return panels.SyncRoot; }
526                         }
527
528                         void ICollection.CopyTo (Array dest, int index)
529                         {
530                                 panels.CopyTo (dest, index);
531                         }
532
533
534                         object IList.this [int index] {
535                                 get { return panels [index]; }
536                                 set { panels [index] = value; }
537                         }
538
539                         int IList.Add (object value) {
540                                 return panels.Add (value);
541                         }
542
543                         bool IList.Contains (object panel) {
544                                 return panels.Contains (panel);
545                         }
546
547                         int IList.IndexOf (object panel)
548                         {
549                                 return panels.IndexOf (panel);
550                         }
551
552                         void IList.Insert (int index, object value)
553                         {
554                                 panels.Insert (index, value);
555                         }
556
557                         bool IList.IsFixedSize {
558                                 get { return false; }
559                         }
560
561                         void IList.Remove (object value)
562                         {
563                                 panels.Remove (value);
564                         }
565                         #endregion      // IList & ICollection Interfaces
566                 }
567                 #endregion      // Subclass StatusBarPanelCollection
568         }
569
570 }
571