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