New test.
[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                         MouseHover += new EventHandler (ToolBar_MouseHover);
120                         MouseLeave += new EventHandler (ToolBar_MouseLeave);
121                         MouseMove += new MouseEventHandler (ToolBar_MouseMove);
122                         MouseUp += new MouseEventHandler (ToolBar_MouseUp);
123
124                         TabStop = false;
125                         
126                         SetStyle (ControlStyles.UserPaint, false);
127                         SetStyle (ControlStyles.FixedHeight, true);
128                 }
129                 #endregion Constructor
130
131                 #region protected Properties
132                 protected override CreateParams CreateParams 
133                 {
134                         get { return base.CreateParams; }
135                 }
136
137                 protected override ImeMode DefaultImeMode {
138                         get { return ImeMode.Disable; }
139                 }
140
141                 protected override Size DefaultSize {
142                         get { return ThemeEngine.Current.ToolBarDefaultSize; }
143                 }
144                 #endregion
145
146                 ToolBarAppearance appearance = ToolBarAppearance.Normal;
147
148                 #region Public Properties
149                 [DefaultValue (ToolBarAppearance.Normal)]
150                 [Localizable (true)]
151                 public ToolBarAppearance Appearance {
152                         get { return appearance; }
153                         set {
154                                 if (value == appearance)
155                                         return;
156
157                                 appearance = value;
158                                 Redraw (true);
159                         }
160                 }
161
162                 bool autosize = true;
163
164                 [DefaultValue (true)]
165                 [Localizable (true)]
166                 public bool AutoSize {
167                         get { return autosize; }
168                         set {
169                                 if (value == autosize)
170                                         return;
171
172                                 autosize = value;
173                                 Redraw (true);
174                         }
175                 }
176
177                 [Browsable (false)]
178                 [EditorBrowsable (EditorBrowsableState.Never)]
179                 public override Color BackColor {
180                         get { return background_color; }
181                         set {
182                                 if (value == background_color)
183                                         return;
184
185                                 background_color = value;
186                                 OnBackColorChanged (EventArgs.Empty);
187                                 Redraw (false);
188                         }
189                 }
190
191                 [Browsable (false)]
192                 [EditorBrowsable (EditorBrowsableState.Never)]
193                 public override Image BackgroundImage {
194                         get { return background_image; }
195                         set {
196                                 if (value == background_image)
197                                         return;
198
199                                 background_image = value;
200                                 OnBackgroundImageChanged (EventArgs.Empty);
201                                 Redraw (false);
202                         }
203                 }
204
205                 [DefaultValue (BorderStyle.None)]
206                 [DispIdAttribute (-504)]
207                 public BorderStyle BorderStyle {
208                         get { return InternalBorderStyle; }
209                         set { InternalBorderStyle = value; }
210                 }
211
212                 ToolBarButtonCollection buttons;
213
214                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
215                 [Localizable (true)]
216                 [MergableProperty (false)]
217                 public ToolBarButtonCollection Buttons {
218                         get { return buttons; }
219                 }
220
221                 Size button_size;
222
223                 [Localizable (true)]
224                 [RefreshProperties (RefreshProperties.All)]
225                 public Size ButtonSize {
226                         get {
227                                 if (button_size.IsEmpty) {
228                                         if (buttons.Count == 0)
229                                                 return new Size (24, 22);
230                                         Size result = CalcButtonSize ();
231                                         if (result.IsEmpty)
232                                                 return new Size (24, 22);
233                                         else
234                                                 return result;
235                                 }
236                                 return button_size;
237                         }
238                         set {
239                                 size_specified = value != Size.Empty;
240                                 if (button_size == value)
241                                         return;
242
243                                 button_size = value;
244                                 Redraw (true);
245                         }
246                 }
247
248                 bool divider = true;
249
250                 [DefaultValue (true)]
251                 public bool Divider {
252                         get { return divider; }
253                         set {
254                                 if (value == divider)
255                                         return;
256
257                                 divider = value;
258                                 Redraw (false);
259                         }
260                 }
261
262                 [DefaultValue (DockStyle.Top)]
263                 [Localizable (true)]
264                 public override DockStyle Dock {
265                         get { return base.Dock; }
266                         set { base.Dock = value; } 
267                 }
268
269                 bool drop_down_arrows = true;
270
271                 [DefaultValue (false)]
272                 [Localizable (true)]
273                 public bool DropDownArrows {
274                         get { return drop_down_arrows; }
275                         set {
276                                 if (value == drop_down_arrows)
277                                         return;
278
279                                 drop_down_arrows = value;
280                                 Redraw (true);
281                         }
282                 }
283
284                 [Browsable (false)]
285                 [EditorBrowsable (EditorBrowsableState.Never)]
286                 public override Color ForeColor {
287                         get { return foreground_color; }
288                         set {
289                                 if (value == foreground_color)
290                                         return;
291
292                                 foreground_color = value;
293                                 OnForeColorChanged (EventArgs.Empty);
294                                 Redraw (false);
295                         }
296                 }
297
298                 ImageList image_list;
299
300                 [DefaultValue (null)]
301                 public ImageList ImageList {
302                         get { return image_list; }
303                         set { 
304                                 if (image_list == value)
305                                         return;
306                                 image_list = value;
307                                 Redraw (true);
308                         }
309                 }
310
311                 [Browsable (false)]
312                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
313                 [EditorBrowsable (EditorBrowsableState.Advanced)]
314                 public Size ImageSize {
315                         get {
316                                 if (ImageList == null)
317                                         return Size.Empty;
318
319                                 return ImageList.ImageSize;
320                         }
321                 }
322
323                 ImeMode ime_mode;
324
325                 [Browsable (false)]
326                 [EditorBrowsable (EditorBrowsableState.Never)]
327                 public new ImeMode ImeMode {
328                         get { return ime_mode; }
329                         set {
330                                 if (value == ime_mode)
331                                         return;
332
333                                 ime_mode = value;
334                                 OnImeModeChanged (EventArgs.Empty);
335                         }
336                 }
337
338                 [Browsable (false)]
339                 [EditorBrowsable (EditorBrowsableState.Never)]
340                 public override RightToLeft RightToLeft {
341                         get { return base.RightToLeft; }
342                         set {
343                                 if (value == base.RightToLeft)
344                                         return;
345
346                                 base.RightToLeft = value;
347                                 OnRightToLeftChanged (EventArgs.Empty);
348                         }
349                 }
350
351                 bool show_tooltips = false;
352
353                 [DefaultValue (false)]
354                 [Localizable (true)]
355                 public bool ShowToolTips {
356                         get { return show_tooltips; }
357                         set { show_tooltips = value; }
358                 }
359
360                 [DefaultValue (false)]
361                 public new bool TabStop {
362                         get { return base.TabStop; }
363                         set { base.TabStop = value; }
364                 }
365
366                 [Bindable (false)]
367                 [Browsable (false)]
368                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
369                 [EditorBrowsable (EditorBrowsableState.Never)]
370                 public override string Text {
371                         get { return text; } 
372                         set {
373                                 if (value == text)
374                                         return;
375
376                                 text = value;
377                                 Redraw (true);
378                                 OnTextChanged (EventArgs.Empty);
379                         }
380                 }
381
382                 ToolBarTextAlign text_alignment = ToolBarTextAlign.Underneath;
383
384                 [DefaultValue (ToolBarTextAlign.Underneath)]
385                 [Localizable (true)]
386                 public ToolBarTextAlign TextAlign {
387                         get { return text_alignment; }
388                         set {
389                                 if (value == text_alignment)
390                                         return;
391
392                                 text_alignment = value;
393                                 Redraw (true);
394                         }
395                 }
396
397                 bool wrappable = true;
398
399                 [DefaultValue (true)]
400                 [Localizable (true)]
401                 public bool Wrappable {
402                         get { return wrappable; }
403                         set {
404                                 if (value == wrappable)
405                                         return;
406
407                                 wrappable = value;
408                                 Redraw (true);
409                         }
410                 }
411                 #endregion Public Properties
412
413                 #region Public Methods
414                 public override string ToString ()
415                 {
416                         int count = this.Buttons.Count;
417
418                         if (count == 0)
419                                 return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: 0");
420                         else
421                                 return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: {0}, Buttons[0]: {1}",
422                                                       count, this.Buttons [0].ToString ());
423                 }
424                 #endregion Public Methods
425
426                 #region Protected Methods
427                 protected override void CreateHandle ()
428                 {
429                         base.CreateHandle ();
430                 }
431
432                 protected override void Dispose (bool disposing)
433                 {
434                         if (disposing)
435                                 ImageList = null;
436
437                         base.Dispose (disposing);
438                 }
439
440                 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
441                 {
442                         if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
443                                 if (! e.Button.Pushed)
444                                         e.Button.Pushed = true;
445                                 else
446                                         e.Button.Pushed = false;
447                         }
448                         e.Button.pressed = false;
449
450                         e.Button.Invalidate ();
451
452                         if (ButtonClick != null)
453                                 ButtonClick (this, e);
454                 }
455
456                 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e) 
457                 {
458                         if (ButtonDropDown != null)
459                                 ButtonDropDown (this, e);
460
461                         if (e.Button.DropDownMenu == null)
462                                 return;
463
464                         Point loc = new Point (e.Button.Rectangle.X + 1, e.Button.Rectangle.Bottom + 1);
465                         ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
466
467                         e.Button.dd_pressed = false;
468                         Invalidate (e.Button.Rectangle);
469                 }
470
471                 protected override void OnFontChanged (EventArgs e)
472                 {
473                         base.OnFontChanged (e);
474                         Redraw (true);
475                 }
476
477                 protected override void OnHandleCreated (EventArgs e)
478                 {
479                         base.OnHandleCreated (e);
480                 }
481
482                 protected override void OnResize (EventArgs e)
483                 {
484                         base.OnResize (e);
485
486                         if (Width <= 0 || Height <= 0 || !Visible)
487                                 return;
488
489                         Redraw (true, background_image != null);
490                 }
491
492                 int requested_height = -1;
493
494                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
495                 {
496                         // New height requested
497                         if (!AutoSize && (requested_height != height) && ((specified & BoundsSpecified.Height) != BoundsSpecified.None)) 
498                                 requested_height = height;
499                         
500                         base.SetBoundsCore (x, y, width, height, specified);
501                 }
502
503                 protected override void WndProc (ref Message m)
504                 {
505                         base.WndProc (ref m);
506                 }
507
508                 internal override bool InternalPreProcessMessage (ref Message msg)
509                 {
510                         if (msg.Msg == (int)Msg.WM_KEYDOWN) {
511                                 Keys key_data = (Keys)msg.WParam.ToInt32();
512                                 if (HandleKeyDown (key_data))
513                                         return true;
514                         } 
515                         return base.InternalPreProcessMessage (ref msg);
516                 }
517                         
518                 #endregion Protected Methods
519
520                 #region Private Methods
521                 private void FocusChanged (object sender, EventArgs args)
522                 {
523                         if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
524                                 return;
525
526                         ToolBarButton prelit = null;
527                         foreach (ToolBarButton b in Buttons)
528                                 if (b.Hilight) {
529                                         prelit = b;
530                                         break;
531                                 }
532
533                         if (Focused && prelit == null)
534                                 foreach (ToolBarButton btn in Buttons) {
535                                         if (btn.Enabled) {
536                                                 btn.Hilight = true;
537                                                 break;
538                                         }
539                                 }
540                         else if (prelit != null)
541                                 prelit.Hilight = false;
542                 }
543
544                 private bool HandleKeyDown (Keys key_data)
545                 {
546                         if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
547                                 return false;
548
549                         switch (key_data) {
550                         case Keys.Left:
551                         case Keys.Up:
552                                 HighlightButton (-1);
553                                 return true;
554                         case Keys.Right:
555                         case Keys.Down:
556                                 HighlightButton (1);
557                                 return true;
558                         default:
559                                 return false;
560                         }
561                 }
562
563                 void HighlightButton (int offset)
564                 {
565                         ArrayList enabled = new ArrayList ();
566                         int count = 0;
567                         int start = -1;
568                         ToolBarButton curr_button = null;
569                         foreach (ToolBarButton btn in Buttons) {
570                                 if (btn.Hilight) {
571                                         start = count;
572                                         curr_button = btn;
573                                 }
574
575                                 if (btn.Enabled) {
576                                         enabled.Add (btn);
577                                         count++;
578                                 }
579                         }
580
581                         int next = (start + offset) % count;
582                         if (next < 0)
583                                 next = count - 1;
584
585                         if (next == start)
586                                 return;
587
588                         if (curr_button != null)
589                                 curr_button.Hilight = false;
590                         (enabled [next] as ToolBarButton).Hilight = true;
591                 }
592
593                 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
594                 {
595                         if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
596                                 return;
597
598                         Point loc = new Point (me.X, me.Y);
599
600                         if (ButtonAtPoint (loc) == null)
601                                 return;
602                         
603                         // Hide tooltip when left mouse button 
604                         if ((tip_window != null) && (tip_window.Visible) && ((me.Button & MouseButtons.Left) == MouseButtons.Left)) {
605                                 TipDownTimer.Stop ();
606                                 tip_window.Hide ();
607                         }
608                         
609                         // draw the pushed button
610                         foreach (ToolBarButton button in buttons) {
611                                 if (button.Enabled && button.Rectangle.Contains (loc)) {
612                                         // Mark the DropDown rect as pressed.
613                                         // We don't redraw the dropdown rect.
614                                         if (button.Style == ToolBarButtonStyle.DropDownButton) {
615                                                 Rectangle rect = button.Rectangle;
616                                                 if (DropDownArrows) {
617                                                         rect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
618                                                         rect.X = button.Rectangle.Right - rect.Width;
619                                                 }
620                                                 
621                                                 if (rect.Contains (loc)) {
622                                                         if (button.DropDownMenu != null) {
623                                                                 button.dd_pressed = true;
624                                                                 Invalidate (rect);
625                                                         }
626                                                         break;
627                                                 }
628                                         }
629                                         button.pressed = true;
630                                         button.inside = true;
631                                         button.Invalidate ();
632                                         break;
633                                 }
634                         }
635                 }
636
637                 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
638                 {
639                         if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
640                                 return;
641
642                         Point loc = new Point (me.X, me.Y);
643
644                         // draw the normal button
645                         // Make a copy in case the list is modified during enumeration
646                         ArrayList buttons = new ArrayList (this.buttons);
647                         foreach (ToolBarButton button in buttons) {
648                                 if (button.Enabled && button.Rectangle.Contains (loc)) {
649                                         if (button.Style == ToolBarButtonStyle.DropDownButton) {
650                                                 Rectangle ddRect = button.Rectangle;
651                                                 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
652                                                 ddRect.X = button.Rectangle.Right - ddRect.Width;
653                                                 if (ddRect.Contains (loc)) {
654                                                         if (button.dd_pressed)
655                                                                 OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
656                                                         continue;
657                                                 }
658                                         }
659                                         // Fire a ButtonClick
660                                         if ((button.pressed) && ((me.Button & MouseButtons.Left) == MouseButtons.Left))
661                                                 OnButtonClick (new ToolBarButtonClickEventArgs (button));
662                                 } else if (button.pressed) {
663                                         button.pressed = false;
664                                         button.Invalidate ();
665                                 }
666                         }
667                 }
668
669                 private ToolBarButton ButtonAtPoint (Point pt)
670                 {
671                         foreach (ToolBarButton button in buttons)
672                                 if (button.Rectangle.Contains (pt)) 
673                                         return button;
674
675                         return null;
676                 }
677
678                 ToolTip.ToolTipWindow tip_window = null;
679                 Timer tipdown_timer = null;
680
681                 private void PopDownTip (object o, EventArgs args)
682                 {
683                         tip_window.Hide ();
684                 }
685
686                 private Timer TipDownTimer {
687                         get {
688                                 if (tipdown_timer == null) {
689                                         tipdown_timer = new Timer ();
690                                         tipdown_timer.Enabled = false;
691                                         tipdown_timer.Interval = 5000;
692                                         tipdown_timer.Tick += new EventHandler (PopDownTip);
693                                 }
694                                 return tipdown_timer;
695                         }
696                 }
697
698                 private void ToolBar_MouseHover (object sender, EventArgs e)
699                 {
700                         if (Capture)
701                                 return;
702
703                         if (tip_window == null)
704                                 tip_window = new ToolTip.ToolTipWindow ();
705
706                         ToolBarButton btn = ButtonAtPoint (PointToClient (Control.MousePosition));
707                         current_button = btn;
708
709                         if (btn == null || btn.ToolTipText.Length == 0)
710                                 return;
711
712                         tip_window.Present (this, btn.ToolTipText);
713                         TipDownTimer.Start ();
714                 }
715
716                 private void ToolBar_MouseLeave (object sender, EventArgs e)
717                 {
718                         if (tipdown_timer != null)
719                                 tipdown_timer.Dispose ();
720                         tipdown_timer = null;
721                         if (tip_window != null)
722                                 tip_window.Dispose ();
723                         tip_window = null;
724
725                         if (!Enabled || current_button == null) 
726                                 return;
727
728                         current_button.Hilight = false;
729                         current_button = null;
730                 }
731
732                 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
733                 {
734                         if (!Enabled) 
735                                 return;
736
737                         if (tip_window != null && tip_window.Visible) {
738                                 TipDownTimer.Stop ();
739                                 TipDownTimer.Start ();
740                         }
741
742                         Point loc = new Point (me.X, me.Y);
743
744                         if (Capture) {
745                                 // If the button was pressed and we leave, release the 
746                                 // button press and vice versa
747                                 foreach (ToolBarButton button in buttons) {
748                                         if (button.pressed &&
749                                             (button.inside != button.Rectangle.Contains (loc))) {
750                                                 button.inside = button.Rectangle.Contains (loc);
751                                                 button.Hilight = false;
752                                                 break;
753                                         }
754                                 }
755                                 return;
756                         } 
757
758                         if (current_button != null && current_button.Rectangle.Contains (loc)) {
759                                 if (appearance == ToolBarAppearance.Flat) {
760                                         if (current_button.Hilight || current_button.Pushed || !current_button.Enabled)
761                                                 return;
762                                         current_button.Hilight = true;
763                                 }
764                         } else {
765                                 if (tip_window != null) {
766                                         if (tip_window.Visible) {
767                                                 tip_window.Hide ();
768                                                 TipDownTimer.Stop ();
769                                         }
770                                         current_button = ButtonAtPoint (loc);
771                                         if (current_button != null && current_button.ToolTipText.Length > 0) {
772                                                 tip_window.Present (this, current_button.ToolTipText);
773                                                 TipDownTimer.Start ();
774                                         }
775                                 }
776
777                                 if (appearance == ToolBarAppearance.Flat) {
778                                         foreach (ToolBarButton button in buttons) {
779                                                 if (button.Rectangle.Contains (loc) && button.Enabled) {
780                                                         current_button = button;
781                                                         if (current_button.Hilight || current_button.Pushed)
782                                                                 continue;
783                                                         current_button.Hilight = true;
784                                                 }
785                                                 else if (button.Hilight) {
786                                                         button.Hilight = false;
787                                                 }
788                                         }
789                                 }
790                         }
791                 }
792
793                 internal override void OnPaintInternal (PaintEventArgs pevent)
794                 {
795                         ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
796                 }
797
798                 internal void Redraw (bool recalculate)
799                 {
800                         Redraw (recalculate, true);
801                 }
802
803                 internal void Redraw (bool recalculate, bool force)
804                 {
805                         bool invalidate = true;
806                         if (recalculate) {
807                                 invalidate = Layout ();
808                         }
809
810                         if (force || invalidate)
811                                 Invalidate ();
812                 }
813
814                 internal bool SizeSpecified {
815                         get { return size_specified; }
816                 }
817
818                 const int text_padding = 3;
819
820                 private Size CalcButtonSize ()
821                 {
822                         if (Buttons.Count == 0)
823                                 return Size.Empty;
824
825                         string longest_text = Buttons [0].Text;
826                         for (int i = 1; i < Buttons.Count; i++) {
827                                 if (Buttons[i].Text.Length > longest_text.Length)
828                                         longest_text = Buttons[i].Text;
829                         }
830
831                         Size size = Size.Empty;
832                         if (longest_text != null && longest_text.Length > 0) {
833                                 SizeF sz = DeviceContext.MeasureString (longest_text, Font);
834                                 if (sz != SizeF.Empty)
835                                         size = new Size ((int) Math.Ceiling (sz.Width) + 2 * text_padding, (int) Math.Ceiling (sz.Height));
836                         }
837
838                         Size img_size = ImageList == null ? new Size (16, 16) : ImageSize;
839
840                         Theme theme = ThemeEngine.Current;
841                         int imgWidth = img_size.Width + 2 * theme.ToolBarImageGripWidth; 
842                         int imgHeight = img_size.Height + 2 * theme.ToolBarImageGripWidth;
843
844                         if (text_alignment == ToolBarTextAlign.Right) {
845                                 size.Width = imgWidth + size.Width;
846                                 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
847                         } else {
848                                 size.Height = imgHeight + size.Height;
849                                 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
850                         }
851
852                         size.Width += theme.ToolBarImageGripWidth;
853                         size.Height += theme.ToolBarImageGripWidth;
854                         return size;
855                 }
856
857                 // Flat toolbars disregard specified sizes.  Normal toolbars grow the
858                 // button size to be at least large enough to show the image.
859                 Size AdjustedButtonSize {
860                         get {
861                                 Size size = ButtonSize;
862                                 if (size_specified) {
863                                         if (Appearance == ToolBarAppearance.Flat)
864                                                 size = CalcButtonSize ();
865                                         else {
866                                                 int grip = ThemeEngine.Current.ToolBarImageGripWidth;
867                                                 if (size.Width < ImageSize.Width + 2 * grip )
868                                                         size.Width = ImageSize.Width + 2 * grip;
869                                                 if (size.Height < ImageSize.Height + 2 * grip)
870                                                         size.Height = ImageSize.Height + 2 * grip;
871                                         }
872                                 }
873                                 return size;
874                         }
875                 }
876
877                 bool Layout ()
878                 {
879                         if (Parent == null)
880                                 return false;
881                         
882                         bool changed = false;
883                         Theme theme = ThemeEngine.Current;
884                         int x = theme.ToolBarGripWidth;
885                         int y = theme.ToolBarGripWidth;
886
887                         int ht = AdjustedButtonSize.Height + theme.ToolBarGripWidth;
888
889                         int separator_index = -1;
890
891                         for (int i = 0; i < buttons.Count; i++) {
892                                 ToolBarButton button = buttons [i];
893
894                                 if (!button.Visible)
895                                         continue;
896
897                                 if (size_specified && (button.Style != ToolBarButtonStyle.Separator)) {
898                                         if (button.Layout (button_size))
899                                                 changed = true;
900                                 }
901                                 else {
902                                         if (button.Layout ())
903                                                 changed = true;
904                                 }
905
906                                 bool is_separator = button.Style == ToolBarButtonStyle.Separator;
907
908                                 if (x + button.Rectangle.Width < Width || is_separator || !Wrappable) {
909                                         if (button.Location.X != x || button.Location.Y != y)
910                                                 changed = true;
911                                         button.Location = new Point (x, y);
912                                         x += button.Rectangle.Width;
913                                         if (is_separator)
914                                                 separator_index = i;
915                                 } else if (separator_index > 0) { 
916                                         i = separator_index;
917                                         separator_index = -1;
918                                         x = theme.ToolBarGripWidth;
919                                         y += ht; 
920                                 } else {
921                                         x = theme.ToolBarGripWidth;
922                                         y += ht; 
923                                         if (button.Location.X != x || button.Location.Y != y)
924                                                 changed = true;
925                                         button.Location = new Point (x, y);
926                                         x += button.Rectangle.Width;
927                                 }
928                         }
929                         if (AutoSize)
930                                 Height = ht + (Wrappable ? y : 0);
931                         else
932                                 Height = requested_height;
933                         
934                         return changed;
935                 }
936                 #endregion Private Methods
937
938                 #region subclass
939                 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
940                 {
941                         #region instance variables
942                         private ArrayList list;
943                         private ToolBar owner;
944                         private bool redraw;
945                         #endregion
946
947                         #region constructors
948                         public ToolBarButtonCollection (ToolBar owner)
949                         {
950                                 this.owner = owner;
951                                 list = new ArrayList ();
952                                 redraw = true;
953                         }
954                         #endregion
955
956                         #region properties
957                         [Browsable (false)]
958                         public int Count {
959                                 get { return list.Count; }
960                         }
961
962                         public bool IsReadOnly {
963                                 get { return list.IsReadOnly; }
964                         }
965
966                         public virtual ToolBarButton this [int index] {
967                                 get { return (ToolBarButton) list [index]; }
968                                 set {
969                                         value.SetParent (owner);
970                                         list [index] = value;
971                                         owner.Redraw (true);
972                                 }
973                         }
974
975                         bool ICollection.IsSynchronized {
976                                 get { return list.IsSynchronized; }
977                         }
978
979                         object ICollection.SyncRoot {
980                                 get { return list.SyncRoot; }
981                         }
982
983                         bool IList.IsFixedSize {
984                                 get { return list.IsFixedSize; }
985                         }
986
987                         object IList.this [int index] {
988                                 get { return this [index]; }
989                                 set {
990                                         if (! (value is ToolBarButton))
991                                                 throw new ArgumentException("Not of type ToolBarButton", "value");
992                                         this [index] = (ToolBarButton) value;
993                                 }
994                         }
995                         #endregion
996
997                         #region methods
998                         public int Add (string text)
999                         {
1000                                 ToolBarButton button = new ToolBarButton (text);
1001                                 return this.Add (button);
1002                         }
1003
1004                         public int Add (ToolBarButton button)
1005                         {
1006                                 int result;
1007                                 button.SetParent (owner);
1008                                 result = list.Add (button);
1009                                 if (redraw)
1010                                         owner.Redraw (true);
1011                                 return result;
1012                         }
1013
1014                         public void AddRange (ToolBarButton [] buttons)
1015                         {
1016                                 try {
1017                                         redraw = false;
1018                                         foreach (ToolBarButton button in buttons)
1019                                                 Add (button);
1020                                 }
1021                                 finally {
1022                                         redraw = true;
1023                                         owner.Redraw (true);
1024                                 }
1025                         }
1026
1027                         public void Clear ()
1028                         {
1029                                 list.Clear ();
1030                                 owner.Redraw (false);
1031                         }
1032
1033                         public bool Contains (ToolBarButton button)
1034                         {
1035                                 return list.Contains (button);
1036                         }
1037
1038                         public IEnumerator GetEnumerator ()
1039                         {
1040                                 return list.GetEnumerator ();
1041                         }
1042
1043                         void ICollection.CopyTo (Array dest, int index)
1044                         {
1045                                 list.CopyTo (dest, index);
1046                         }
1047
1048                         int IList.Add (object button)
1049                         {
1050                                 if (! (button is ToolBarButton)) {
1051                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1052                                 }
1053
1054                                 return this.Add ((ToolBarButton) button);
1055                         }
1056
1057                         bool IList.Contains (object button)
1058                         {
1059                                 if (! (button is ToolBarButton)) {
1060                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1061                                 }
1062
1063                                 return this.Contains ((ToolBarButton) button);
1064                         }
1065
1066                         int IList.IndexOf (object button)
1067                         {
1068                                 if (! (button is ToolBarButton)) {
1069                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1070                                 }
1071
1072                                 return this.IndexOf ((ToolBarButton) button);
1073                         }
1074
1075                         void IList.Insert (int index, object button)
1076                         {
1077                                 if (! (button is ToolBarButton)) {
1078                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1079                                 }
1080
1081                                 this.Insert (index, (ToolBarButton) button);
1082                         }
1083
1084                         void IList.Remove (object button)
1085                         {
1086                                 if (! (button is ToolBarButton)) {
1087                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1088                                 }
1089
1090                                 this.Remove ((ToolBarButton) button);
1091                         }
1092
1093                         public int IndexOf (ToolBarButton button)
1094                         {
1095                                 return list.IndexOf (button);
1096                         }
1097
1098                         public void Insert (int index, ToolBarButton button)
1099                         {
1100                                 list.Insert (index, button);
1101                                 owner.Redraw (true);
1102                         }
1103
1104                         public void Remove (ToolBarButton button)
1105                         {
1106                                 list.Remove (button);
1107                                 owner.Redraw (true);
1108                         }
1109
1110                         public void RemoveAt (int index)
1111                         {
1112                                 list.RemoveAt (index);
1113                                 owner.Redraw (true);
1114                         }
1115                         #endregion methods
1116                 }
1117                 #endregion subclass
1118         }
1119 }