2006-07-20 Mike Kestner <mkestner@novell.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ToolBar.cs
1 // System.Windows.Forms.ToolBar.cs
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 // Author:
23 //      Ravindra (rkumar@novell.com)
24 //      Mike Kestner <mkestner@novell.com>
25 //
26 // TODO:
27 //   - Tooltip
28 //
29 // Copyright (C) 2004-2006  Novell, Inc. (http://www.novell.com)
30 //
31
32
33 // NOT COMPLETE
34
35 using System.Collections;
36 using System.ComponentModel;
37 using System.ComponentModel.Design;
38 using System.Drawing;
39 using System.Drawing.Imaging;
40 using System.Runtime.InteropServices;
41
42 namespace System.Windows.Forms
43 {       
44         [DefaultEvent ("ButtonClick")]
45         [DefaultProperty ("Buttons")]
46         [Designer ("System.Windows.Forms.Design.ToolBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
47         public class ToolBar : Control
48         {
49                 #region Instance Variables
50                 bool size_specified = false;
51                 ToolBarButton current_button;
52                 #endregion Instance Variables
53
54                 #region Events
55                 [Browsable (false)]
56                 [EditorBrowsable (EditorBrowsableState.Never)]
57                 public new event EventHandler BackColorChanged {
58                         add { base.BackColorChanged += value; }
59                         remove { base.BackColorChanged -= value; }
60                 }
61
62                 [Browsable (false)]
63                 [EditorBrowsable (EditorBrowsableState.Never)]
64                 public new event EventHandler BackgroundImageChanged {
65                         add { base.BackgroundImageChanged += value; }
66                         remove { base.BackgroundImageChanged -= value; }
67                 }
68
69                 public event ToolBarButtonClickEventHandler ButtonClick;
70                 public event ToolBarButtonClickEventHandler ButtonDropDown;
71
72                 [Browsable (false)]
73                 [EditorBrowsable (EditorBrowsableState.Never)]
74                 public new event EventHandler ForeColorChanged {
75                         add { base.ForeColorChanged += value; }
76                         remove { base.ForeColorChanged -= value; }
77                 }
78
79                 [Browsable (false)]
80                 [EditorBrowsable (EditorBrowsableState.Never)]
81                 public new event EventHandler ImeModeChanged {
82                         add { base.ImeModeChanged += value; }
83                         remove { base.ImeModeChanged -= value; }
84                 }
85
86                 [Browsable (false)]
87                 [EditorBrowsable (EditorBrowsableState.Never)]
88                 public new event PaintEventHandler Paint {
89                         add { base.Paint += value; }
90                         remove { base.Paint -= value; }
91                 }
92
93                 [Browsable (false)]
94                 [EditorBrowsable (EditorBrowsableState.Never)]
95                 public new event EventHandler RightToLeftChanged {
96                         add { base.RightToLeftChanged += value; }
97                         remove { base.RightToLeftChanged -= value; }
98                 }
99
100                 [Browsable (false)]
101                 [EditorBrowsable (EditorBrowsableState.Never)]
102                 public new event EventHandler TextChanged {
103                         add { base.TextChanged += value; }
104                         remove { base.TextChanged -= value; }
105                 }
106                 #endregion Events
107
108                 #region Constructor
109                 public ToolBar ()
110                 {
111                         background_color = ThemeEngine.Current.DefaultControlBackColor;
112                         foreground_color = ThemeEngine.Current.DefaultControlForeColor;
113                         buttons = new ToolBarButtonCollection (this);
114                         dock_style = DockStyle.Top;
115                         
116                         GotFocus += new EventHandler (FocusChanged);
117                         LostFocus += new EventHandler (FocusChanged);
118                         MouseDown += new MouseEventHandler (ToolBar_MouseDown);
119                         MouseLeave += new EventHandler (ToolBar_MouseLeave);
120                         MouseMove += new MouseEventHandler (ToolBar_MouseMove);
121                         MouseUp += new MouseEventHandler (ToolBar_MouseUp);
122
123                         SetStyle (ControlStyles.UserPaint, false);
124                         SetStyle (ControlStyles.FixedHeight, true);
125                 }
126                 #endregion Constructor
127
128                 #region protected Properties
129                 protected override CreateParams CreateParams 
130                 {
131                         get { return base.CreateParams; }
132                 }
133
134                 protected override ImeMode DefaultImeMode {
135                         get { return ImeMode.Disable; }
136                 }
137
138                 protected override Size DefaultSize {
139                         get { return ThemeEngine.Current.ToolBarDefaultSize; }
140                 }
141                 #endregion
142
143                 ToolBarAppearance appearance = ToolBarAppearance.Normal;
144
145                 #region Public Properties
146                 [DefaultValue (ToolBarAppearance.Normal)]
147                 [Localizable (true)]
148                 public ToolBarAppearance Appearance {
149                         get { return appearance; }
150                         set {
151                                 if (value == appearance)
152                                         return;
153
154                                 appearance = value;
155                                 Redraw (true);
156                         }
157                 }
158
159                 bool autosize = true;
160
161                 [DefaultValue (true)]
162                 [Localizable (true)]
163                 public bool AutoSize {
164                         get { return autosize; }
165                         set {
166                                 if (value == autosize)
167                                         return;
168
169                                 autosize = value;
170                                 Redraw (true);
171                         }
172                 }
173
174                 [Browsable (false)]
175                 [EditorBrowsable (EditorBrowsableState.Never)]
176                 public override Color BackColor {
177                         get { return background_color; }
178                         set {
179                                 if (value == background_color)
180                                         return;
181
182                                 background_color = value;
183                                 OnBackColorChanged (EventArgs.Empty);
184                                 Redraw (false);
185                         }
186                 }
187
188                 [Browsable (false)]
189                 [EditorBrowsable (EditorBrowsableState.Never)]
190                 public override Image BackgroundImage {
191                         get { return background_image; }
192                         set {
193                                 if (value == background_image)
194                                         return;
195
196                                 background_image = value;
197                                 OnBackgroundImageChanged (EventArgs.Empty);
198                                 Redraw (false);
199                         }
200                 }
201
202                 [DefaultValue (BorderStyle.None)]
203                 [DispIdAttribute (-504)]
204                 public BorderStyle BorderStyle {
205                         get { return InternalBorderStyle; }
206                         set { InternalBorderStyle = value; }
207                 }
208
209                 ToolBarButtonCollection buttons;
210
211                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
212                 [Localizable (true)]
213                 [MergableProperty (false)]
214                 public ToolBarButtonCollection Buttons {
215                         get { return buttons; }
216                 }
217
218                 Size button_size;
219
220                 [Localizable (true)]
221                 [RefreshProperties (RefreshProperties.All)]
222                 public Size ButtonSize {
223                         get {
224                                 if (button_size.IsEmpty) {
225                                         if (buttons.Count == 0)
226                                                 return new Size (24, 22);
227                                         Size result = CalcButtonSize ();
228                                         if (result.IsEmpty)
229                                                 return new Size (24, 22);
230                                         else
231                                                 return result;
232                                 }
233                                 return button_size;
234                         }
235                         set {
236                                 size_specified = value != Size.Empty;
237                                 if (button_size == value)
238                                         return;
239
240                                 button_size = value;
241                                 Redraw (true);
242                         }
243                 }
244
245                 bool divider = true;
246
247                 [DefaultValue (true)]
248                 public bool Divider {
249                         get { return divider; }
250                         set {
251                                 if (value == divider)
252                                         return;
253
254                                 divider = value;
255                                 Redraw (false);
256                         }
257                 }
258
259                 [DefaultValue (DockStyle.Top)]
260                 [Localizable (true)]
261                 public override DockStyle Dock {
262                         get { return base.Dock; }
263                         set { base.Dock = value; } 
264                 }
265
266                 bool drop_down_arrows = false;
267
268                 [DefaultValue (false)]
269                 [Localizable (true)]
270                 public bool DropDownArrows {
271                         get { return drop_down_arrows; }
272                         set {
273                                 if (value == drop_down_arrows)
274                                         return;
275
276                                 drop_down_arrows = value;
277                                 Redraw (true);
278                         }
279                 }
280
281                 [Browsable (false)]
282                 [EditorBrowsable (EditorBrowsableState.Never)]
283                 public override Color ForeColor {
284                         get { return foreground_color; }
285                         set {
286                                 if (value == foreground_color)
287                                         return;
288
289                                 foreground_color = value;
290                                 OnForeColorChanged (EventArgs.Empty);
291                                 Redraw (false);
292                         }
293                 }
294
295                 ImageList image_list;
296
297                 [DefaultValue (null)]
298                 public ImageList ImageList {
299                         get { return image_list; }
300                         set { 
301                                 if (image_list == value)
302                                         return;
303                                 image_list = value;
304                                 Redraw (true);
305                         }
306                 }
307
308                 [Browsable (false)]
309                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310                 [EditorBrowsable (EditorBrowsableState.Advanced)]
311                 public Size ImageSize {
312                         get {
313                                 if (ImageList == null)
314                                         return Size.Empty;
315
316                                 return ImageList.ImageSize;
317                         }
318                 }
319
320                 ImeMode ime_mode;
321
322                 [Browsable (false)]
323                 [EditorBrowsable (EditorBrowsableState.Never)]
324                 public new ImeMode ImeMode {
325                         get { return ime_mode; }
326                         set {
327                                 if (value == ime_mode)
328                                         return;
329
330                                 ime_mode = value;
331                                 OnImeModeChanged (EventArgs.Empty);
332                         }
333                 }
334
335                 [Browsable (false)]
336                 [EditorBrowsable (EditorBrowsableState.Never)]
337                 public override RightToLeft RightToLeft {
338                         get { return base.RightToLeft; }
339                         set {
340                                 if (value == base.RightToLeft)
341                                         return;
342
343                                 base.RightToLeft = value;
344                                 OnRightToLeftChanged (EventArgs.Empty);
345                         }
346                 }
347
348                 bool show_tooltips = false;
349
350                 [DefaultValue (false)]
351                 [Localizable (true)]
352                 public bool ShowToolTips {
353                         get { return show_tooltips; }
354                         set { show_tooltips = value; }
355                 }
356
357                 [DefaultValue (false)]
358                 public new bool TabStop {
359                         get { return base.TabStop; }
360                         set { base.TabStop = value; }
361                 }
362
363                 [Bindable (false)]
364                 [Browsable (false)]
365                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
366                 [EditorBrowsable (EditorBrowsableState.Never)]
367                 public override string Text {
368                         get { return text; } 
369                         set {
370                                 if (value == text)
371                                         return;
372
373                                 text = value;
374                                 Redraw (true);
375                                 OnTextChanged (EventArgs.Empty);
376                         }
377                 }
378
379                 ToolBarTextAlign text_alignment = ToolBarTextAlign.Underneath;
380
381                 [DefaultValue (ToolBarTextAlign.Underneath)]
382                 [Localizable (true)]
383                 public ToolBarTextAlign TextAlign {
384                         get { return text_alignment; }
385                         set {
386                                 if (value == text_alignment)
387                                         return;
388
389                                 text_alignment = value;
390                                 Redraw (true);
391                         }
392                 }
393
394                 bool wrappable = true;
395
396                 [DefaultValue (true)]
397                 [Localizable (true)]
398                 public bool Wrappable {
399                         get { return wrappable; }
400                         set {
401                                 if (value == wrappable)
402                                         return;
403
404                                 wrappable = value;
405                                 Redraw (true);
406                         }
407                 }
408                 #endregion Public Properties
409
410                 #region Public Methods
411                 public override string ToString ()
412                 {
413                         int count = this.Buttons.Count;
414
415                         if (count == 0)
416                                 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: 0");
417                         else
418                                 return string.Format ("System.Windows.Forms.ToolBar, Button.Count: {0}, Buttons[0]: {1}",
419                                                       count, this.Buttons [0].ToString ());
420                 }
421                 #endregion Public Methods
422
423                 #region Protected Methods
424                 protected override void CreateHandle ()
425                 {
426                         base.CreateHandle ();
427                 }
428
429                 protected override void Dispose (bool disposing)
430                 {
431                         if (disposing)
432                                 ImageList = null;
433
434                         base.Dispose (disposing);
435                 }
436
437                 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
438                 {
439                         if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
440                                 if (! e.Button.Pushed)
441                                         e.Button.Pushed = true;
442                                 else
443                                         e.Button.Pushed = false;
444                         }
445                         e.Button.pressed = false;
446
447                         Invalidate (e.Button.Rectangle);
448                         Redraw (false);
449
450                         if (ButtonClick != null)
451                                 ButtonClick (this, e);
452                 }
453
454                 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e) 
455                 {
456                         if (ButtonDropDown != null)
457                                 ButtonDropDown (this, e);
458
459                         if (e.Button.DropDownMenu == null)
460                                 return;
461
462                         Point loc = new Point (e.Button.Rectangle.X + 1, e.Button.Rectangle.Bottom + 1);
463                         ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
464
465                         e.Button.dd_pressed = false;
466                         Invalidate (e.Button.Rectangle);
467                 }
468
469                 protected override void OnFontChanged (EventArgs e)
470                 {
471                         base.OnFontChanged (e);
472                         Redraw (true);
473                 }
474
475                 protected override void OnHandleCreated (EventArgs e)
476                 {
477                         base.OnHandleCreated (e);
478                 }
479
480                 protected override void OnResize (EventArgs e)
481                 {
482                         base.OnResize (e);
483
484                         if (Width <= 0 || Height <= 0 || !Visible)
485                                 return;
486
487                         Redraw (true);
488                 }
489
490                 bool height_specified = false;
491                 int requested_height = -1;
492
493                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
494                 {
495                         if ((specified & BoundsSpecified.Height) != 0) {
496                                 requested_height = height;
497                                 height_specified = true;
498                         }
499                         base.SetBoundsCore (x, y, width, height, specified);
500                 }
501
502                 protected override void WndProc (ref Message m)
503                 {
504                         base.WndProc (ref m);
505                 }
506
507                 internal override bool InternalPreProcessMessage (ref Message msg)
508                 {
509                         if (msg.Msg == (int)Msg.WM_KEYDOWN) {
510                                 Keys key_data = (Keys)msg.WParam.ToInt32();
511                                 if (HandleKeyDown (key_data))
512                                         return true;
513                         } 
514                         return base.InternalPreProcessMessage (ref msg);
515                 }
516                         
517                 #endregion Protected Methods
518
519                 #region Private Methods
520                 private void FocusChanged (object sender, EventArgs args)
521                 {
522                         if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
523                                 return;
524
525                         ToolBarButton prelit = null;
526                         foreach (ToolBarButton b in Buttons)
527                                 if (b.Hilight) {
528                                         prelit = b;
529                                         break;
530                                 }
531
532                         if (Focused && prelit == null)
533                                 foreach (ToolBarButton btn in Buttons) {
534                                         if (btn.Enabled) {
535                                                 btn.Hilight = true;
536                                                 break;
537                                         }
538                                 }
539                         else if (prelit != null)
540                                 prelit.Hilight = false;
541                 }
542
543                 private bool HandleKeyDown (Keys key_data)
544                 {
545                         if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
546                                 return false;
547
548                         switch (key_data) {
549                         case Keys.Left:
550                         case Keys.Up:
551                                 HighlightButton (-1);
552                                 return true;
553                         case Keys.Right:
554                         case Keys.Down:
555                                 HighlightButton (1);
556                                 return true;
557                         default:
558                                 return false;
559                         }
560                 }
561
562                 void HighlightButton (int offset)
563                 {
564                         ArrayList enabled = new ArrayList ();
565                         int count = 0;
566                         int start = -1;
567                         ToolBarButton curr_button = null;
568                         foreach (ToolBarButton btn in Buttons) {
569                                 if (btn.Hilight) {
570                                         start = count;
571                                         curr_button = btn;
572                                 }
573
574                                 if (btn.Enabled) {
575                                         enabled.Add (btn);
576                                         count++;
577                                 }
578                         }
579
580                         int next = (start + offset) % count;
581                         if (next < 0)
582                                 next = count - 1;
583
584                         if (next == start)
585                                 return;
586
587                         if (curr_button != null)
588                                 curr_button.Hilight = false;
589                         (enabled [next] as ToolBarButton).Hilight = true;
590                 }
591
592                 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
593                 {
594                         if (!Enabled) 
595                                 return;
596
597                         Point loc = new Point (me.X, me.Y);
598
599                         // draw the pushed button
600                         foreach (ToolBarButton button in buttons) {
601                                 if (button.Enabled && button.Rectangle.Contains (loc)) {
602                                         // Mark the DropDown rect as pressed.
603                                         // We don't redraw the dropdown rect.
604                                         if (button.Style == ToolBarButtonStyle.DropDownButton) {
605                                                 Rectangle rect = button.Rectangle;
606                                                 rect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
607                                                 rect.X = button.Rectangle.Right - rect.Width;
608                                                 if (rect.Contains (loc)) {
609                                                         if (button.DropDownMenu != null) {
610                                                                 button.dd_pressed = true;
611                                                                 Invalidate (rect);
612                                                         }
613                                                         break;
614                                                 }
615                                         }
616                                         button.pressed = true;
617                                         button.inside = true;
618                                         Invalidate (button.Rectangle);
619                                         break;
620                                 }
621                         }
622                 }
623
624                 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
625                 {
626                         if (!Enabled) 
627                                 return;
628
629                         Point loc = new Point (me.X, me.Y);
630
631                         // draw the normal button
632                         // Make a copy in case the list is modified during enumeration
633                         ArrayList buttons = new ArrayList (this.buttons);
634                         foreach (ToolBarButton button in buttons) {
635                                 if (button.Enabled && button.Rectangle.Contains (loc)) {
636                                         if (button.Style == ToolBarButtonStyle.DropDownButton) {
637                                                 Rectangle ddRect = button.Rectangle;
638                                                 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
639                                                 ddRect.X = button.Rectangle.Right - ddRect.Width;
640                                                 if (ddRect.Contains (loc)) {
641                                                         if (button.dd_pressed)
642                                                                 OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
643                                                         continue;
644                                                 }
645                                         }
646                                         // Fire a ButtonClick
647                                         if (button.pressed)
648                                                 OnButtonClick (new ToolBarButtonClickEventArgs (button));
649                                 } else if (button.pressed) {
650                                         button.pressed = false;
651                                         Invalidate (button.Rectangle);
652                                 }
653                         }
654                 }
655
656                 private void ToolBar_MouseLeave (object sender, EventArgs e)
657                 {
658                         if (!Enabled || appearance != ToolBarAppearance.Flat || current_button == null) 
659                                 return;
660
661                         if (current_button.Hilight) {
662                                 current_button.Hilight = false;
663                                 Invalidate (current_button.Rectangle);
664                                 Redraw (false);
665                         }
666                         current_button = null;
667                 }
668
669                 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
670                 {
671                         if (!Enabled) 
672                                 return;
673
674                         Point loc = new Point (me.X, me.Y);
675
676                         if (this.Capture) {
677                                 // If the button was pressed and we leave, release the 
678                                 // button press and vice versa
679                                 foreach (ToolBarButton button in buttons) {
680                                         if (button.pressed &&
681                                             (button.inside != button.Rectangle.Contains (loc))) {
682                                                 button.inside = button.Rectangle.Contains (loc);
683                                                 button.Hilight = false;
684                                                 Invalidate (button.Rectangle);
685                                                 Redraw (false);
686                                                 break;
687                                         }
688                                 }
689                         }
690                         // following is only for flat style toolbar
691                         else if (appearance == ToolBarAppearance.Flat) {
692                                 if (current_button != null && current_button.Rectangle.Contains (loc)) {
693                                         if (current_button.Hilight || current_button.Pushed)
694                                                 return;
695                                         current_button.Hilight = true;
696                                         Invalidate (current_button.Rectangle);
697                                         Redraw (false);
698                                 }
699                                 else {
700                                         foreach (ToolBarButton button in buttons) {
701                                                 if (button.Rectangle.Contains (loc) && button.Enabled) {
702                                                         current_button = button;
703                                                         if (current_button.Hilight || current_button.Pushed)
704                                                                 continue;
705                                                         current_button.Hilight = true;
706                                                         Invalidate (current_button.Rectangle);
707                                                         Redraw (false);
708                                                 }
709                                                 else if (button.Hilight) {
710                                                         button.Hilight = false;
711                                                         Invalidate (button.Rectangle);
712                                                         Redraw (false);
713                                                 }
714                                         }
715                                 }
716                         }
717                 }
718
719                 internal override void OnPaintInternal (PaintEventArgs pevent)
720                 {
721                         ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
722                 }
723
724                 internal void Redraw (bool recalculate)
725                 {
726                         if (recalculate)
727                                 Layout ();
728
729                         Refresh ();
730                 }
731
732                 internal bool SizeSpecified {
733                         get { return size_specified; }
734                 }
735
736                 const int text_padding = 3;
737
738                 private Size CalcButtonSize ()
739                 {
740                         if (Buttons.Count == 0)
741                                 return Size.Empty;
742
743                         string longest_text = Buttons [0].Text;
744                         for (int i = 1; i < Buttons.Count; i++) {
745                                 if (Buttons[i].Text.Length > longest_text.Length)
746                                         longest_text = Buttons[i].Text;
747                         }
748
749                         Size size = Size.Empty;
750                         if (longest_text != null && longest_text.Length > 0) {
751                                 SizeF sz = DeviceContext.MeasureString (longest_text, Font);
752                                 if (sz != SizeF.Empty)
753                                         size = new Size ((int) Math.Ceiling (sz.Width) + 2 * text_padding, (int) Math.Ceiling (sz.Height));
754                         }
755
756                         Size img_size = ImageList == null ? new Size (16, 16) : ImageSize;
757
758                         Theme theme = ThemeEngine.Current;
759                         int imgWidth = img_size.Width + 2 * theme.ToolBarImageGripWidth; 
760                         int imgHeight = img_size.Height + 2 * theme.ToolBarImageGripWidth;
761
762                         if (text_alignment == ToolBarTextAlign.Right) {
763                                 size.Width = imgWidth + size.Width;
764                                 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
765                         } else {
766                                 size.Height = imgHeight + size.Height;
767                                 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
768                         }
769
770                         size.Width += theme.ToolBarImageGripWidth;
771                         size.Height += theme.ToolBarImageGripWidth;
772                         return size;
773                 }
774
775                 // Flat toolbars disregard specified sizes.  Normal toolbars grow the
776                 // button size to be at least large enough to show the image.
777                 Size AdjustedButtonSize {
778                         get {
779                                 Size size = ButtonSize;
780                                 if (size_specified) {
781                                         if (Appearance == ToolBarAppearance.Flat)
782                                                 size = CalcButtonSize ();
783                                         else {
784                                                 int grip = ThemeEngine.Current.ToolBarImageGripWidth;
785                                                 if (size.Width < ImageSize.Width + 2 * grip )
786                                                         size.Width = ImageSize.Width + 2 * grip;
787                                                 if (size.Height < ImageSize.Height + 2 * grip)
788                                                         size.Height = ImageSize.Height + 2 * grip;
789                                         }
790                                 }
791                                 return size;
792                         }
793                 }
794
795                 void Layout ()
796                 {
797                         Theme theme = ThemeEngine.Current;
798                         int x = theme.ToolBarGripWidth;
799                         int y = theme.ToolBarGripWidth;
800
801                         Size button_size = AdjustedButtonSize;
802
803                         int ht = button_size.Height + theme.ToolBarGripWidth;
804
805                         if (Wrappable && Parent != null) {
806                                 int separator_index = -1;
807
808                                 for (int i = 0; i < buttons.Count; i++) {
809                                         ToolBarButton button = buttons [i];
810
811                                         if (!button.Visible)
812                                                 continue;
813
814                                         if (size_specified)
815                                                 button.Layout (button_size);
816                                         else
817                                                 button.Layout ();
818
819                                         bool is_separator = button.Style == ToolBarButtonStyle.Separator;
820
821                                         if (x + button.Rectangle.Width < Width || is_separator) {
822                                                 button.Location = new Point (x, y);
823                                                 x += button.Rectangle.Width;
824                                                 if (is_separator)
825                                                         separator_index = i;
826                                         } else if (separator_index > 0) { 
827                                                 i = separator_index;
828                                                 separator_index = -1;
829                                                 x = theme.ToolBarGripWidth;
830                                                 y += ht; 
831                                         } else {
832                                                 x = theme.ToolBarGripWidth;
833                                                 y += ht; 
834                                                 button.Location = new Point (x, y);
835                                                 x += button.Rectangle.Width;
836                                         }
837                                 }
838                                 if (AutoSize)
839                                         Height = y + ht;
840                         } else {
841                                 if (AutoSize)
842                                         Height = ht;
843                                 else if (!height_specified)
844                                         Height = DefaultSize.Height;
845                                 foreach (ToolBarButton button in buttons) {
846                                         if (size_specified)
847                                                 button.Layout (button_size);
848                                         else
849                                                 button.Layout ();
850                                         button.Location = new Point (x, y);
851                                         x += button.Rectangle.Width;
852                                 }
853                         }
854                 }
855                 #endregion Private Methods
856
857                 #region subclass
858                 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
859                 {
860                         #region instance variables
861                         private ArrayList list;
862                         private ToolBar owner;
863                         #endregion
864
865                         #region constructors
866                         public ToolBarButtonCollection (ToolBar owner)
867                         {
868                                 this.owner = owner;
869                                 list = new ArrayList ();
870                         }
871                         #endregion
872
873                         #region properties
874                         [Browsable (false)]
875                         public int Count {
876                                 get { return list.Count; }
877                         }
878
879                         public bool IsReadOnly {
880                                 get { return list.IsReadOnly; }
881                         }
882
883                         public virtual ToolBarButton this [int index] {
884                                 get { return (ToolBarButton) list [index]; }
885                                 set {
886                                         value.SetParent (owner);
887                                         list [index] = value;
888                                         owner.Redraw (true);
889                                 }
890                         }
891
892                         bool ICollection.IsSynchronized {
893                                 get { return list.IsSynchronized; }
894                         }
895
896                         object ICollection.SyncRoot {
897                                 get { return list.SyncRoot; }
898                         }
899
900                         bool IList.IsFixedSize {
901                                 get { return list.IsFixedSize; }
902                         }
903
904                         object IList.this [int index] {
905                                 get { return this [index]; }
906                                 set {
907                                         if (! (value is ToolBarButton))
908                                                 throw new ArgumentException("Not of type ToolBarButton", "value");
909                                         this [index] = (ToolBarButton) value;
910                                 }
911                         }
912                         #endregion
913
914                         #region methods
915                         public int Add (string text)
916                         {
917                                 ToolBarButton button = new ToolBarButton (text);
918                                 return this.Add (button);
919                         }
920
921                         public int Add (ToolBarButton button)
922                         {
923                                 int result;
924                                 button.SetParent (owner);
925                                 result = list.Add (button);
926                                 owner.Redraw (true);
927                                 return result;
928                         }
929
930                         public void AddRange (ToolBarButton [] buttons)
931                         {
932                                 foreach (ToolBarButton button in buttons)
933                                         Add (button);
934                         }
935
936                         public void Clear ()
937                         {
938                                 list.Clear ();
939                                 owner.Redraw (false);
940                         }
941
942                         public bool Contains (ToolBarButton button)
943                         {
944                                 return list.Contains (button);
945                         }
946
947                         public IEnumerator GetEnumerator ()
948                         {
949                                 return list.GetEnumerator ();
950                         }
951
952                         void ICollection.CopyTo (Array dest, int index)
953                         {
954                                 list.CopyTo (dest, index);
955                         }
956
957                         int IList.Add (object button)
958                         {
959                                 if (! (button is ToolBarButton)) {
960                                         throw new ArgumentException("Not of type ToolBarButton", "button");
961                                 }
962
963                                 return this.Add ((ToolBarButton) button);
964                         }
965
966                         bool IList.Contains (object button)
967                         {
968                                 if (! (button is ToolBarButton)) {
969                                         throw new ArgumentException("Not of type ToolBarButton", "button");
970                                 }
971
972                                 return this.Contains ((ToolBarButton) button);
973                         }
974
975                         int IList.IndexOf (object button)
976                         {
977                                 if (! (button is ToolBarButton)) {
978                                         throw new ArgumentException("Not of type ToolBarButton", "button");
979                                 }
980
981                                 return this.IndexOf ((ToolBarButton) button);
982                         }
983
984                         void IList.Insert (int index, object button)
985                         {
986                                 if (! (button is ToolBarButton)) {
987                                         throw new ArgumentException("Not of type ToolBarButton", "button");
988                                 }
989
990                                 this.Insert (index, (ToolBarButton) button);
991                         }
992
993                         void IList.Remove (object button)
994                         {
995                                 if (! (button is ToolBarButton)) {
996                                         throw new ArgumentException("Not of type ToolBarButton", "button");
997                                 }
998
999                                 this.Remove ((ToolBarButton) button);
1000                         }
1001
1002                         public int IndexOf (ToolBarButton button)
1003                         {
1004                                 return list.IndexOf (button);
1005                         }
1006
1007                         public void Insert (int index, ToolBarButton button)
1008                         {
1009                                 list.Insert (index, button);
1010                                 owner.Redraw (true);
1011                         }
1012
1013                         public void Remove (ToolBarButton button)
1014                         {
1015                                 list.Remove (button);
1016                                 owner.Redraw (true);
1017                         }
1018
1019                         public void RemoveAt (int index)
1020                         {
1021                                 list.RemoveAt (index);
1022                                 owner.Redraw (true);
1023                         }
1024                         #endregion methods
1025                 }
1026                 #endregion subclass
1027         }
1028 }