* ImageList.cs: When the image stream is set pull all the images
[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)]
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                 internal Rectangle paint_area = new Rectangle ();
49                 #endregion      // Fields
50
51                 #region Public Constructors
52                 [MonoTODO("Change cursor when mouse is over grip")]
53                 public StatusBar ()
54                 {
55                         base.Dock = DockStyle.Bottom;
56                         Anchor = AnchorStyles.Top | AnchorStyles.Left;
57                         this.TabStop = 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                         UpdateArea ();
233                         Draw();
234                 }
235
236                 protected override void OnHandleDestroyed (EventArgs e) {
237                         base.OnHandleDestroyed (e);
238                 }
239
240                 protected override void OnLayout (LayoutEventArgs e) {
241                         base.OnLayout (e);
242                 }
243
244                 protected override void OnMouseDown (MouseEventArgs e) {
245                         if (panels == null)
246                                 return;
247
248                         float prev_x = 0;
249                         float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
250                         for (int i = 0; i < panels.Count; i++) {
251                                 float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
252                                 if (e.X >= prev_x && e.X <= x) {
253                                         OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
254                                                 e.Button, e.Clicks, e.X, e.Y));
255                                         break;
256                                 }
257                                 prev_x = x;
258                         }
259
260                         base.OnMouseDown (e);
261                 }
262
263                 protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e) {
264                         if (PanelClick != null)
265                                 PanelClick (this, e);
266                 }
267
268                 protected override void OnResize (EventArgs e)
269                 {
270                         base.OnResize (e);
271
272                         if (Width <= 0 || Height <= 0)
273                                 return;
274
275                         UpdateArea ();
276                         CalcPanelSizes ();
277                         Draw ();
278                 }
279
280                 protected override void WndProc(ref Message m) {
281                         switch ((Msg) m.Msg) {
282                                 case Msg.WM_PAINT: {                            
283                                         PaintEventArgs  paint_event;
284
285                                         paint_event = XplatUI.PaintEventStart (Handle);
286                                         DoPaint (paint_event);
287                                         XplatUI.PaintEventEnd (Handle);
288                                         return;
289                                 }
290                         }
291                         base.WndProc (ref m);
292                 }
293
294                 #endregion      // Methods
295
296
297                 #region Internal Methods
298                 internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
299                 {
300                         OnDrawItem (e);
301                 }
302
303                 private void DoPaint (PaintEventArgs pevent)
304                 {
305                        if (Width <= 0 || Height <=  0 || Visible == false)
306                                return;
307
308                        UpdateArea ();
309                        CalcPanelSizes ();
310                        Draw();
311                        pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
312                 }
313
314                 private void CalcPanelSizes ()
315                 {
316                         if (panels == null || !show_panels)
317                                 return;
318
319                         if (Width == 0 || Height == 0)
320                                 return;
321
322                         int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
323                         int taken = 0;
324                         ArrayList springs = null;
325                         for (int i = 0; i < panels.Count; i++) {
326                                 StatusBarPanel p = panels [i];
327                                 if (p.AutoSize == StatusBarPanelAutoSize.None) {
328                                         taken += p.Width;
329                                         taken += gap;
330                                         continue;
331                                 }
332                                 if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
333                                         if (DeviceContext == null)
334                                                 CreateBuffers (Width, Height);
335                                         int len = (int) (DeviceContext.MeasureString (p.Text, Font).Width + 0.5F);
336                                         p.Width = (int) (len * 1.5F);
337                                         taken += p.Width;
338                                         taken += gap;
339                                         continue;
340                                 }
341                                 if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
342                                         if (springs == null)
343                                                 springs = new ArrayList ();
344                                         springs.Add (p);
345                                         taken += gap;
346                                         continue;
347                                 }
348                         }
349
350                         if (springs == null)
351                                 return;
352
353                         int spring_total = springs.Count;
354                         int total_width = Width - taken - ThemeEngine.Current.StatusBarSizeGripWidth;
355                         for (int i = 0; i < spring_total; i++) {
356                                 StatusBarPanel p = (StatusBarPanel) springs [i];
357                                 p.Width = total_width / spring_total;
358                         }
359                 }
360
361                 private void UpdateArea ()
362                 {
363                         paint_area.X = paint_area.Y = 0;
364                         paint_area.Width = Width;
365                         paint_area.Height = Height;
366                 }
367
368                 private void Draw ()
369                 {
370                         ThemeEngine.Current.DrawStatusBar (DeviceContext, this.ClientRectangle, this);
371                 }
372                 #endregion      // Internal Methods
373
374
375                 #region Events
376                 [Browsable(false)]
377                 [EditorBrowsable(EditorBrowsableState.Never)]
378                 public new event EventHandler BackColorChanged;
379
380                 [Browsable(false)]
381                 [EditorBrowsable(EditorBrowsableState.Never)]
382                 public new event EventHandler BackgroundImageChanged;
383
384                 [Browsable(false)]
385                 [EditorBrowsable(EditorBrowsableState.Never)]
386                 public new event EventHandler ForeColorChanged;
387
388                 [Browsable(false)]
389                 [EditorBrowsable(EditorBrowsableState.Never)]
390                 public new event EventHandler ImeModeChanged;
391
392                 public event StatusBarDrawItemEventHandler DrawItem;
393
394                 [Browsable(false)]
395                 [EditorBrowsable(EditorBrowsableState.Never)]
396                 public new event PaintEventHandler Paint;
397                 public event StatusBarPanelClickEventHandler PanelClick;
398                 #endregion      // Events
399                 
400
401                 #region Subclass StatusBarPanelCollection
402                 public class StatusBarPanelCollection :  IList, ICollection, IEnumerable {
403                         #region Fields
404                         private StatusBar owner;
405                         private ArrayList panels;
406                         #endregion      // Fields
407
408                         #region Public Constructors
409                         public StatusBarPanelCollection (StatusBar owner)
410                         {
411                                 this.owner = owner;
412                         }
413
414                         #endregion      // Public Constructors
415
416                         #region Private & Internal Methods
417                         private int AddInternal (StatusBarPanel p, bool refresh) {
418                                 if (p == null)
419                                         throw new ArgumentNullException ("value");
420                                 if (panels == null)
421                                         panels = new ArrayList ();
422
423                                 int res = panels.Add (p);
424                                 p.SetParent (owner);
425
426                                 if (refresh) {
427                                         owner.CalcPanelSizes ();
428                                         owner.Refresh ();
429                                 }
430
431                                 return res;
432                         }
433
434                         #endregion      // Private & Internal Methods
435
436                         #region Public Instance Properties
437                         [Browsable(false)]
438                         [EditorBrowsable(EditorBrowsableState.Never)]
439                         public virtual int Count {
440                                 get {
441                                         if (panels == null)
442                                                 return 0;
443                                         return panels.Count;
444                                 }
445                         }
446
447                         public virtual bool IsReadOnly {
448                                 get { return false; }
449                         }
450
451                         public virtual StatusBarPanel this [int index] {
452                                 get {
453                                         if (index < 0 || index >= Count)
454                                                 throw new ArgumentOutOfRangeException ("index");
455                                         return (StatusBarPanel) panels [index];
456                                 }
457                                 set {
458                                         if (value == null)
459                                                 throw new ArgumentNullException ("index");
460                                         if (index < 0 || index >= Count)
461                                                 throw new ArgumentOutOfRangeException ("index");
462                                         panels [index] = value;
463                                 }
464                         }
465
466                         #endregion      // Public Instance Properties
467
468                         #region Public Instance Methods
469                         public virtual int Add (StatusBarPanel p) {
470                                 return AddInternal (p, true);
471                         }
472
473                         public virtual StatusBarPanel Add (string text) {
474                                 StatusBarPanel res = new StatusBarPanel ();
475                                 res.Text = text;
476                                 Add (res);
477                                 return res;
478                         }
479
480                         public virtual void AddRange (StatusBarPanel [] range) {
481                                 if (range == null)
482                                         throw new ArgumentNullException ("panels");
483                                 if (range.Length == 0)
484                                         return;
485                                 if (panels == null)
486                                         panels = new ArrayList (range.Length);
487
488                                 for (int i = 0; i < range.Length; i++)
489                                         AddInternal (range [i], false);
490                                 owner.Refresh ();
491                         }
492
493                         public virtual void Clear () {
494                                 panels.Clear ();
495
496                                 owner.Refresh ();
497                         }
498
499                         public virtual bool Contains (StatusBarPanel panel) {
500                                 return panels.Contains (panel);
501                         }
502
503                         public virtual IEnumerator GetEnumerator () {
504                                 return panels.GetEnumerator ();
505                         }
506
507                         public virtual int IndexOf (StatusBarPanel panel) {
508                                 return panels.IndexOf (panel);
509                         }
510
511                         public virtual void Insert (int index, StatusBarPanel value) {
512                                 if (value == null)
513                                         throw new ArgumentNullException ("value");
514                                 if (index > Count)
515                                         throw new ArgumentOutOfRangeException ("index");
516                                 // TODO: InvalidArgumentException for bad AutoSize values
517                                 // although it seems impossible to set it to a bad value
518                                 value.SetParent (owner);
519                                 panels [index] = value;
520
521                                 owner.Refresh ();
522                         }
523
524                         public virtual void Remove (StatusBarPanel panel) {
525                                 panels.Remove (panel);
526                         }
527
528                         public virtual void RemoveAt (int index) {
529                                 panels.RemoveAt (index);
530                         }
531
532                         #endregion      // Public Instance Methods
533
534                         #region IList & ICollection Interfaces
535                         bool ICollection.IsSynchronized {
536                                 get { return panels.IsSynchronized; }
537                         }
538
539                         object ICollection.SyncRoot {
540                                 get { return panels.SyncRoot; }
541                         }
542
543                         void ICollection.CopyTo (Array dest, int index)
544                         {
545                                 panels.CopyTo (dest, index);
546                         }
547
548
549                         object IList.this [int index] {
550                                 get { return panels [index]; }
551                                 set { panels [index] = value; }
552                         }
553
554                         int IList.Add (object value) {
555                                 return panels.Add (value);
556                         }
557
558                         bool IList.Contains (object panel) {
559                                 return panels.Contains (panel);
560                         }
561
562                         int IList.IndexOf (object panel)
563                         {
564                                 return panels.IndexOf (panel);
565                         }
566
567                         void IList.Insert (int index, object value)
568                         {
569                                 panels.Insert (index, value);
570                         }
571
572                         bool IList.IsFixedSize {
573                                 get { return false; }
574                         }
575
576                         void IList.Remove (object value)
577                         {
578                                 panels.Remove (value);
579                         }
580                         #endregion      // IList & ICollection Interfaces
581                 }
582                 #endregion      // Subclass StatusBarPanelCollection
583         }
584
585 }
586