2007-03-29 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ToolBar.cs
1 // System.Windows.Forms.ToolBar.cs
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 // Author:
23 //      Ravindra (rkumar@novell.com)
24 //      Mike Kestner <mkestner@novell.com>
25 //      Everaldo Canuto <ecanuto@novell.com>
26 //
27 // Copyright (C) 2004-2006  Novell, Inc. (http://www.novell.com)
28 //
29
30 using System.Collections;
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Drawing;
34 using System.Drawing.Text;
35 using System.Drawing.Imaging;
36 using System.Runtime.InteropServices;
37
38 namespace System.Windows.Forms
39 {       
40         [DefaultEvent ("ButtonClick")]
41         [DefaultProperty ("Buttons")]
42         [Designer ("System.Windows.Forms.Design.ToolBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43         public class ToolBar : Control
44         {
45                 #region Instance Variables
46                 private bool size_specified = false;
47                 private ToolBarItem current_item;
48                 internal ToolBarItem[] items;
49                 #endregion Instance Variables
50
51                 #region Events
52                 static object ButtonClickEvent = new object ();
53                 static object ButtonDropDownEvent = new object ();
54
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                         add { Events.AddHandler (ButtonClickEvent, value); }
71                         remove {Events.RemoveHandler (ButtonClickEvent, value); }
72                 }
73
74                 public event ToolBarButtonClickEventHandler ButtonDropDown {
75                         add { Events.AddHandler (ButtonDropDownEvent, value); }
76                         remove {Events.RemoveHandler (ButtonDropDownEvent, value); }
77                 }
78
79                 [Browsable (false)]
80                 [EditorBrowsable (EditorBrowsableState.Never)]
81                 public new event EventHandler ForeColorChanged {
82                         add { base.ForeColorChanged += value; }
83                         remove { base.ForeColorChanged -= value; }
84                 }
85
86                 [Browsable (false)]
87                 [EditorBrowsable (EditorBrowsableState.Never)]
88                 public new event EventHandler ImeModeChanged {
89                         add { base.ImeModeChanged += value; }
90                         remove { base.ImeModeChanged -= value; }
91                 }
92
93                 [Browsable (false)]
94                 [EditorBrowsable (EditorBrowsableState.Never)]
95                 public new event PaintEventHandler Paint {
96                         add { base.Paint += value; }
97                         remove { base.Paint -= value; }
98                 }
99
100                 [Browsable (false)]
101                 [EditorBrowsable (EditorBrowsableState.Never)]
102                 public new event EventHandler RightToLeftChanged {
103                         add { base.RightToLeftChanged += value; }
104                         remove { base.RightToLeftChanged -= value; }
105                 }
106
107                 [Browsable (false)]
108                 [EditorBrowsable (EditorBrowsableState.Never)]
109                 public new event EventHandler TextChanged {
110                         add { base.TextChanged += value; }
111                         remove { base.TextChanged -= value; }
112                 }
113                 #endregion Events
114
115                 #region Constructor
116                 public ToolBar ()
117                 {
118                         background_color = ThemeEngine.Current.DefaultControlBackColor;
119                         foreground_color = ThemeEngine.Current.DefaultControlForeColor;
120                         buttons = new ToolBarButtonCollection (this);
121                         Dock = DockStyle.Top;
122                         
123                         GotFocus += new EventHandler (FocusChanged);
124                         LostFocus += new EventHandler (FocusChanged);
125                         MouseDown += new MouseEventHandler (ToolBar_MouseDown);
126                         MouseHover += new EventHandler (ToolBar_MouseHover);
127                         MouseLeave += new EventHandler (ToolBar_MouseLeave);
128                         MouseMove += new MouseEventHandler (ToolBar_MouseMove);
129                         MouseUp += new MouseEventHandler (ToolBar_MouseUp);
130                         BackgroundImageChanged += new EventHandler (ToolBar_BackgroundImageChanged);
131
132                         TabStop = false;
133                         
134                         SetStyle (ControlStyles.UserPaint, false);
135                         SetStyle (ControlStyles.FixedHeight, true);
136                         SetStyle (ControlStyles.FixedWidth, false);
137                 }
138                 #endregion Constructor
139
140                 #region protected Properties
141                 protected override CreateParams CreateParams {
142                         get { return base.CreateParams; }
143                 }
144
145                 protected override ImeMode DefaultImeMode {
146                         get { return ImeMode.Disable; }
147                 }
148
149                 protected override Size DefaultSize {
150                         get { return ThemeEngine.Current.ToolBarDefaultSize; }
151                 }
152                 #endregion
153
154                 ToolBarAppearance appearance = ToolBarAppearance.Normal;
155
156                 #region Public Properties
157                 [DefaultValue (ToolBarAppearance.Normal)]
158                 [Localizable (true)]
159                 public ToolBarAppearance Appearance {
160                         get { return appearance; }
161                         set {
162                                 if (value == appearance)
163                                         return;
164
165                                 appearance = value;
166                                 Redraw (true);
167                         }
168                 }
169
170                 bool autosize = true;
171
172                 [DefaultValue (true)]
173                 [Localizable (true)]
174                 public new bool AutoSize {
175                         get { return autosize; }
176                         set {
177                                 if (value == autosize)
178                                         return;
179
180                                 autosize = value;
181                                 Redraw (true);
182                         }
183                 }
184
185                 [Browsable (false)]
186                 [EditorBrowsable (EditorBrowsableState.Never)]
187                 public override Color BackColor {
188                         get { return background_color; }
189                         set {
190                                 if (value == background_color)
191                                         return;
192
193                                 background_color = value;
194                                 OnBackColorChanged (EventArgs.Empty);
195                                 Redraw (false);
196                         }
197                 }
198
199                 [Browsable (false)]
200                 [EditorBrowsable (EditorBrowsableState.Never)]
201                 public override Image BackgroundImage {
202                         get { return base.BackgroundImage; }
203                         set { base.BackgroundImage = value; }
204                 }
205
206                 [DefaultValue (BorderStyle.None)]
207                 [DispIdAttribute (-504)]
208                 public BorderStyle BorderStyle {
209                         get { return InternalBorderStyle; }
210                         set { InternalBorderStyle = value; }
211                 }
212
213                 ToolBarButtonCollection buttons;
214
215                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
216                 [Localizable (true)]
217                 [MergableProperty (false)]
218                 public ToolBarButtonCollection Buttons {
219                         get { return buttons; }
220                 }
221
222                 Size button_size;
223
224                 [Localizable (true)]
225                 [RefreshProperties (RefreshProperties.All)]
226                 public Size ButtonSize {
227                         get {
228                                 if (!button_size.IsEmpty)
229                                         return button_size; 
230                                 
231                                 if (buttons.Count == 0)
232                                         return new Size (39, 36);
233                                         
234                                 Size result = CalcButtonSize ();
235                                 if (result.IsEmpty)
236                                         return new Size (24, 22);
237                                 else
238                                         return result;
239                         }
240                         set {
241                                 size_specified = value != Size.Empty;
242                                 if (button_size == value)
243                                         return;
244
245                                 button_size = value;
246                                 Redraw (true);
247                         }
248                 }
249
250                 bool divider = true;
251
252                 [DefaultValue (true)]
253                 public bool Divider {
254                         get { return divider; }
255                         set {
256                                 if (value == divider)
257                                         return;
258
259                                 divider = value;
260                                 Redraw (false);
261                         }
262                 }
263
264                 [DefaultValue (DockStyle.Top)]
265                 [Localizable (true)]
266                 public override DockStyle Dock {
267                         get { return base.Dock; }
268                         set {
269                                 if (base.Dock == value)
270                                         return;
271                                         
272                                 if (Vertical) {
273                                         SetStyle (ControlStyles.FixedWidth, AutoSize);
274                                         SetStyle (ControlStyles.FixedHeight, false);
275                                 } else {
276                                         SetStyle (ControlStyles.FixedHeight, AutoSize);
277                                         SetStyle (ControlStyles.FixedWidth, false);
278                                 }
279                                 
280                                 LayoutToolBar ();
281                                 
282                                 base.Dock = value;
283                         }
284                 }
285
286                 bool drop_down_arrows = true;
287
288                 [DefaultValue (false)]
289                 [Localizable (true)]
290                 public bool DropDownArrows {
291                         get { return drop_down_arrows; }
292                         set {
293                                 if (value == drop_down_arrows)
294                                         return;
295
296                                 drop_down_arrows = value;
297                                 Redraw (true);
298                         }
299                 }
300
301                 [Browsable (false)]
302                 [EditorBrowsable (EditorBrowsableState.Never)]
303                 public override Color ForeColor {
304                         get { return foreground_color; }
305                         set {
306                                 if (value == foreground_color)
307                                         return;
308
309                                 foreground_color = value;
310                                 OnForeColorChanged (EventArgs.Empty);
311                                 Redraw (false);
312                         }
313                 }
314
315                 ImageList image_list;
316
317                 [DefaultValue (null)]
318                 public ImageList ImageList {
319                         get { return image_list; }
320                         set { 
321                                 if (image_list == value)
322                                         return;
323                                 image_list = value;
324                                 Redraw (true);
325                         }
326                 }
327
328                 [Browsable (false)]
329                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
330                 [EditorBrowsable (EditorBrowsableState.Advanced)]
331                 public Size ImageSize {
332                         get {
333                                 if (ImageList == null)
334                                         return Size.Empty;
335
336                                 return ImageList.ImageSize;
337                         }
338                 }
339
340                 // XXX this should probably go away and it should call
341                 // into Control.ImeMode instead.
342                 new ImeMode ime_mode = ImeMode.Disable;
343
344                 [Browsable (false)]
345                 [EditorBrowsable (EditorBrowsableState.Never)]
346                 public new ImeMode ImeMode {
347                         get { return ime_mode; }
348                         set {
349                                 if (value == ime_mode)
350                                         return;
351
352                                 ime_mode = value;
353                                 OnImeModeChanged (EventArgs.Empty);
354                         }
355                 }
356
357                 [Browsable (false)]
358                 [EditorBrowsable (EditorBrowsableState.Never)]
359                 public override RightToLeft RightToLeft {
360                         get { return base.RightToLeft; }
361                         set {
362                                 if (value == base.RightToLeft)
363                                         return;
364
365                                 base.RightToLeft = value;
366                                 OnRightToLeftChanged (EventArgs.Empty);
367                         }
368                 }
369
370                 // Default value is "false" but after make a test in .NET we get "true" result as default.  
371                 bool show_tooltips = true;
372
373                 [DefaultValue (false)]
374                 [Localizable (true)]
375                 public bool ShowToolTips {
376                         get { return show_tooltips; }
377                         set { show_tooltips = value; }
378                 }
379
380                 [DefaultValue (false)]
381                 public new bool TabStop {
382                         get { return base.TabStop; }
383                         set { base.TabStop = value; }
384                 }
385
386                 [Bindable (false)]
387                 [Browsable (false)]
388                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
389                 [EditorBrowsable (EditorBrowsableState.Never)]
390                 public override string Text {
391                         get { return base.Text; } 
392                         set {
393                                 if (value == base.Text)
394                                         return;
395
396                                 base.Text = value;
397                                 Redraw (true);
398                         }
399                 }
400
401                 ToolBarTextAlign text_alignment = ToolBarTextAlign.Underneath;
402
403                 [DefaultValue (ToolBarTextAlign.Underneath)]
404                 [Localizable (true)]
405                 public ToolBarTextAlign TextAlign {
406                         get { return text_alignment; }
407                         set {
408                                 if (value == text_alignment)
409                                         return;
410
411                                 text_alignment = value;
412                                 Redraw (true);
413                         }
414                 }
415
416                 bool wrappable = true;
417
418                 [DefaultValue (true)]
419                 [Localizable (true)]
420                 public bool Wrappable {
421                         get { return wrappable; }
422                         set {
423                                 if (value == wrappable)
424                                         return;
425
426                                 wrappable = value;
427                                 Redraw (true);
428                         }
429                 }
430                 #endregion Public Properties
431
432                 #region Public Methods
433                 public override string ToString ()
434                 {
435                         int count = this.Buttons.Count;
436
437                         if (count == 0)
438                                 return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: 0");
439                         else
440                                 return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: {0}, Buttons[0]: {1}",
441                                                       count, this.Buttons [0].ToString ());
442                 }
443                 #endregion Public Methods
444
445                 #region Protected Methods
446                 protected override void CreateHandle ()
447                 {
448                         base.CreateHandle ();
449                 }
450
451                 protected override void Dispose (bool disposing)
452                 {
453                         if (disposing)
454                                 ImageList = null;
455
456                         base.Dispose (disposing);
457                 }
458
459                 protected virtual void OnButtonClick (ToolBarButtonClickEventArgs e)
460                 {
461                         if (e.Button.Style == ToolBarButtonStyle.ToggleButton) {
462                                 if (! e.Button.Pushed)
463                                         e.Button.Pushed = true;
464                                 else
465                                         e.Button.Pushed = false;
466                         }
467                         
468                         current_item.Pressed = false;
469                         current_item.Invalidate ();
470                         
471                         ToolBarButtonClickEventHandler eh = (ToolBarButtonClickEventHandler)(Events [ButtonClickEvent]);
472                         if (eh != null)
473                                 eh (this, e);
474                 }
475
476                 protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e) 
477                 {
478                         ToolBarButtonClickEventHandler eh = (ToolBarButtonClickEventHandler)(Events [ButtonDropDownEvent]);
479                         if (eh != null)
480                                 eh (this, e);
481
482                         if (e.Button.DropDownMenu == null)
483                                 return;
484
485                         Point loc = new Point (current_item.Rectangle.X + 1, current_item.Rectangle.Bottom + 1);
486                         ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
487
488                         current_item.DDPressed = false;
489                         current_item.Hilight = false;
490                         Invalidate (current_item.Rectangle);
491                 }
492
493                 protected override void OnFontChanged (EventArgs e)
494                 {
495                         base.OnFontChanged (e);
496                         Redraw (true);
497                 }
498
499                 protected override void OnHandleCreated (EventArgs e)
500                 {
501                         base.OnHandleCreated (e);
502                 }
503
504                 protected override void OnResize (EventArgs e)
505                 {
506                         base.OnResize (e);
507                         LayoutToolBar ();
508                 }
509
510                 private int requested_size = -1;
511
512                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
513                 {
514                         if (Vertical) {
515                                 if (!AutoSize && (requested_size != width) && ((specified & BoundsSpecified.Width) != BoundsSpecified.None)) 
516                                         requested_size = width;
517                         } else {
518                                 if (!AutoSize && (requested_size != height) && ((specified & BoundsSpecified.Height) != BoundsSpecified.None)) 
519                                         requested_size = height;
520                         }
521                         
522                         base.SetBoundsCore (x, y, width, height, specified);
523                 }
524
525                 protected override void WndProc (ref Message m)
526                 {
527                         base.WndProc (ref m);
528                 }
529
530                 internal override bool InternalPreProcessMessage (ref Message msg)
531                 {
532                         if (msg.Msg == (int)Msg.WM_KEYDOWN) {
533                                 Keys key_data = (Keys)msg.WParam.ToInt32();
534                                 if (HandleKeyDown (key_data))
535                                         return true;
536                         } 
537                         return base.InternalPreProcessMessage (ref msg);
538                 }
539                         
540                 #endregion Protected Methods
541
542                 #region Private Methods
543                 private void FocusChanged (object sender, EventArgs args)
544                 {
545                         if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
546                                 return;
547
548                         ToolBarItem prelit = null;
549                         foreach (ToolBarItem item in items) {
550                                 if (item.Hilight) {
551                                         prelit = item;
552                                         break;
553                                 }
554                         }
555
556                         if (Focused && prelit == null) {
557                                 foreach (ToolBarItem item in items) {
558                                         if (item.Button.Enabled) {
559                                                 item.Hilight = true;
560                                                 break;
561                                         }
562                                 }
563                         } else if (prelit != null) {
564                                 prelit.Hilight = false;
565                         }
566                 }
567
568                 private bool HandleKeyDown (Keys key_data)
569                 {
570                         if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
571                                 return false;
572
573                         switch (key_data) {
574                                 case Keys.Left:
575                                 case Keys.Up:
576                                         HighlightButton (-1);
577                                         return true;
578                                 case Keys.Right:
579                                 case Keys.Down:
580                                         HighlightButton (1);
581                                         return true;
582                                 default:
583                                         return false;
584                         }
585                 }
586
587                 void HighlightButton (int offset)
588                 {
589                         ArrayList enabled = new ArrayList ();
590                         int count = 0;
591                         int start = -1;
592                         ToolBarItem curr_item = null;
593                         foreach (ToolBarItem item in items) {
594                                 if (item.Hilight) {
595                                         start = count;
596                                         curr_item = item;
597                                 }
598
599                                 if (item.Button.Enabled) {
600                                         enabled.Add (item);
601                                         count++;
602                                 }
603                         }
604
605                         int next = (start + offset) % count;
606                         if (next < 0)
607                                 next = count - 1;
608
609                         if (next == start)
610                                 return;
611
612                         if (curr_item != null)
613                                 curr_item.Hilight = false;
614                         (enabled [next] as ToolBarItem).Hilight = true;
615                 }
616
617                 private void ToolBar_BackgroundImageChanged (object sender, EventArgs args)
618                 {
619                         Redraw (false, true);
620                 }
621
622                 private void ToolBar_MouseDown (object sender, MouseEventArgs me)
623                 {
624                         if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
625                                 return;
626
627                         Point loc = new Point (me.X, me.Y);
628
629                         if (ItemAtPoint (loc) == null)
630                                 return;
631                         
632                         // Hide tooltip when left mouse button 
633                         if ((tip_window != null) && (tip_window.Visible) && ((me.Button & MouseButtons.Left) == MouseButtons.Left)) {
634                                 TipDownTimer.Stop ();
635                                 tip_window.Hide ();
636                         }
637                         
638                         // draw the pushed button
639                         foreach (ToolBarItem item in items) {
640                                 if (item.Button.Enabled && item.Rectangle.Contains (loc)) {
641                                         // Mark the DropDown rect as pressed.
642                                         // We don't redraw the dropdown rect.
643                                         if (item.Button.Style == ToolBarButtonStyle.DropDownButton) {
644                                                 Rectangle rect = item.Rectangle;
645                                                 if (DropDownArrows) {
646                                                         rect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
647                                                         rect.X = item.Rectangle.Right - rect.Width;
648                                                 }
649                                                 
650                                                 if (rect.Contains (loc)) {
651                                                         if (item.Button.DropDownMenu != null) {
652                                                                 item.DDPressed = true;
653                                                                 Invalidate (rect);
654                                                         }
655                                                         break;
656                                                 }
657                                         }
658                                         item.Pressed = true;
659                                         item.Inside = true;
660                                         item.Invalidate ();
661                                         break;
662                                 }
663                         }
664                 }
665
666                 private void ToolBar_MouseUp (object sender, MouseEventArgs me)
667                 {
668                         if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
669                                 return;
670
671                         Point loc = new Point (me.X, me.Y);
672
673                         // draw the normal button
674                         // Make a copy in case the list is modified during enumeration
675                         ArrayList items = new ArrayList (this.items);
676                         foreach (ToolBarItem item in items) {
677                                 if (item.Button.Enabled && item.Rectangle.Contains (loc)) {
678                                         if (item.Button.Style == ToolBarButtonStyle.DropDownButton) {
679                                                 Rectangle ddRect = item.Rectangle;
680                                                 ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
681                                                 ddRect.X = item.Rectangle.Right - ddRect.Width;
682                                                 if (ddRect.Contains (loc)) {
683                                                         current_item = item;
684                                                         if (item.DDPressed)
685                                                                 OnButtonDropDown (new ToolBarButtonClickEventArgs (item.Button));
686                                                         continue;
687                                                 }
688                                         }
689                                         // Fire a ButtonClick
690                                         current_item = item;
691                                         if ((item.Pressed) && ((me.Button & MouseButtons.Left) == MouseButtons.Left))
692                                                 OnButtonClick (new ToolBarButtonClickEventArgs (item.Button));
693                                 } else if (item.Pressed) {
694                                         item.Pressed = false;
695                                         item.Invalidate ();
696                                 }
697                         }
698                 }
699
700                 private ToolBarItem ItemAtPoint (Point pt)
701                 {
702                         foreach (ToolBarItem item in items)
703                                 if (item.Rectangle.Contains (pt)) 
704                                         return item;
705
706                         return null;
707                 }
708
709                 ToolTip.ToolTipWindow tip_window = null;
710                 Timer tipdown_timer = null;
711
712                 private void PopDownTip (object o, EventArgs args)
713                 {
714                         tip_window.Hide ();
715                 }
716
717                 private Timer TipDownTimer {
718                         get {
719                                 if (tipdown_timer == null) {
720                                         tipdown_timer = new Timer ();
721                                         tipdown_timer.Enabled = false;
722                                         tipdown_timer.Interval = 5000;
723                                         tipdown_timer.Tick += new EventHandler (PopDownTip);
724                                 }
725                                 return tipdown_timer;
726                         }
727                 }
728
729                 private void ToolBar_MouseHover (object sender, EventArgs e)
730                 {
731                         if (Capture)
732                                 return;
733
734                         if (tip_window == null)
735                                 tip_window = new ToolTip.ToolTipWindow ();
736
737                         ToolBarItem item = ItemAtPoint (PointToClient (Control.MousePosition));
738                         current_item = item;
739
740                         if (item == null || item.Button.ToolTipText.Length == 0)
741                                 return;
742
743                         tip_window.Present (this, item.Button.ToolTipText);
744                         TipDownTimer.Start ();
745                 }
746
747                 private void ToolBar_MouseLeave (object sender, EventArgs e)
748                 {
749                         if (tipdown_timer != null)
750                                 tipdown_timer.Dispose ();
751                         tipdown_timer = null;
752                         if (tip_window != null)
753                                 tip_window.Dispose ();
754                         tip_window = null;
755
756                         if (!Enabled || current_item == null) 
757                                 return;
758
759                         current_item.Hilight = false;
760                         current_item = null;
761                 }
762
763                 private void ToolBar_MouseMove (object sender, MouseEventArgs me)
764                 {
765                         if (!Enabled) 
766                                 return;
767
768                         if (tip_window != null && tip_window.Visible) {
769                                 TipDownTimer.Stop ();
770                                 TipDownTimer.Start ();
771                         }
772
773                         Point loc = new Point (me.X, me.Y);
774
775                         if (Capture) {
776                                 // If the button was pressed and we leave, release the 
777                                 // button press and vice versa
778                                 foreach (ToolBarItem item in items) {
779                                         if (item.Pressed &&
780                                             (item.Inside != item.Rectangle.Contains (loc))) {
781                                                 item.Inside = item.Rectangle.Contains (loc);
782                                                 item.Hilight = false;
783                                                 break;
784                                         }
785                                 }
786                                 return;
787                         } 
788
789                         if (current_item != null && current_item.Rectangle.Contains (loc)) {
790                                 if (appearance == ToolBarAppearance.Flat) {
791                                         if (current_item.Hilight || current_item.Button.Pushed || !current_item.Button.Enabled)
792                                                 return;
793                                         current_item.Hilight = true;
794                                 }
795                         } else {
796                                 if (tip_window != null) {
797                                         if (tip_window.Visible) {
798                                                 tip_window.Hide ();
799                                                 TipDownTimer.Stop ();
800                                         }
801                                         current_item = ItemAtPoint (loc);
802                                         if (current_item != null && current_item.Button.ToolTipText.Length > 0) {
803                                                 tip_window.Present (this, current_item.Button.ToolTipText);
804                                                 TipDownTimer.Start ();
805                                         }
806                                 }
807
808                                 if (appearance == ToolBarAppearance.Flat) {
809                                         foreach (ToolBarItem item in items) {
810                                                 if (item.Rectangle.Contains (loc) && item.Button.Enabled) {
811                                                         current_item = item;
812                                                         if (current_item.Hilight || current_item.Button.Pushed)
813                                                                 continue;
814                                                         current_item.Hilight = true;
815                                                 }
816                                                 else if (item.Hilight) {
817                                                         item.Hilight = false;
818                                                 }
819                                         }
820                                 }
821                         }
822                 }
823
824                 internal override void OnPaintInternal (PaintEventArgs pevent)
825                 {
826                         ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
827                 }
828
829                 internal void Redraw (bool recalculate)
830                 {
831                         Redraw (recalculate, true);
832                 }
833
834                 internal void Redraw (bool recalculate, bool force)
835                 {
836                         bool invalidate = true;
837                         
838                         if (recalculate)
839                                 invalidate = LayoutToolBar ();
840
841                         if (force || invalidate)
842                                 Invalidate ();
843                 }
844
845                 internal bool SizeSpecified {
846                         get { return size_specified; }
847                 }
848                 
849                 private bool Vertical {
850                         get { return (Dock == DockStyle.Left) || (Dock == DockStyle.Right); }
851                 }
852
853                 internal const int text_padding = 3;
854
855                 private Size CalcButtonSize ()
856                 {
857                         if (Buttons.Count == 0)
858                                 return Size.Empty;
859
860                         string longest_text = Buttons [0].Text;
861                         for (int i = 1; i < Buttons.Count; i++) {
862                                 if (Buttons[i].Text.Length > longest_text.Length)
863                                         longest_text = Buttons[i].Text;
864                         }
865
866                         Size size = Size.Empty;
867                         if (longest_text != null && longest_text.Length > 0) {
868                                 SizeF sz = DeviceContext.MeasureString (longest_text, Font);
869                                 if (sz != SizeF.Empty)
870                                         size = new Size ((int) Math.Ceiling (sz.Width) + 2 * text_padding, (int) Math.Ceiling (sz.Height));
871                         }
872
873                         Size img_size = ImageList == null ? new Size (16, 16) : ImageSize;
874
875                         Theme theme = ThemeEngine.Current;
876                         int imgWidth = img_size.Width + 2 * theme.ToolBarImageGripWidth; 
877                         int imgHeight = img_size.Height + 2 * theme.ToolBarImageGripWidth;
878
879                         if (text_alignment == ToolBarTextAlign.Right) {
880                                 size.Width = imgWidth + size.Width;
881                                 size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
882                         } else {
883                                 size.Height = imgHeight + size.Height;
884                                 size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
885                         }
886
887                         size.Width += theme.ToolBarImageGripWidth;
888                         size.Height += theme.ToolBarImageGripWidth;
889                         return size;
890                 }
891
892                 // Flat toolbars disregard specified sizes.  Normal toolbars grow the
893                 // button size to be at least large enough to show the image.
894                 private Size AdjustedButtonSize {
895                         get {
896                                 Size size = ButtonSize;
897                                 if (size_specified) {
898                                         if (Appearance == ToolBarAppearance.Flat)
899                                                 size = CalcButtonSize ();
900                                         else {
901                                                 int grip = ThemeEngine.Current.ToolBarImageGripWidth;
902                                                 if (size.Width < ImageSize.Width + 2 * grip )
903                                                         size.Width = ImageSize.Width + 2 * grip;
904                                                 if (size.Height < ImageSize.Height + 2 * grip)
905                                                         size.Height = ImageSize.Height + 2 * grip;
906                                         }
907                                 }
908                                 return size;
909                         }
910                 }
911
912                 private bool LayoutToolBar ()
913                 {
914                         bool changed = false;
915                         Theme theme = ThemeEngine.Current;
916                         int x = theme.ToolBarGripWidth;
917                         int y = theme.ToolBarGripWidth;
918
919                         Size adjusted_size = AdjustedButtonSize;
920                         
921                         int calculated_size = (Vertical ? adjusted_size.Width : adjusted_size.Height) + theme.ToolBarGripWidth;
922                         
923                         int separator_index = -1;
924
925                         items = new ToolBarItem [buttons.Count];
926                         
927                         for (int i = 0; i < buttons.Count; i++) {
928                                 ToolBarButton button = buttons [i];
929                                 
930                                 ToolBarItem item = new ToolBarItem (button);
931                                 items [i] = item;
932
933                                 if (!button.Visible)
934                                         continue;
935
936                                 if (size_specified && (button.Style != ToolBarButtonStyle.Separator))
937                                         changed = item.Layout (adjusted_size);
938                                 else
939                                         changed = item.Layout ();
940                                 
941                                 bool is_separator = button.Style == ToolBarButtonStyle.Separator;
942                                 
943                                 if (Vertical) {
944                                         if (y + item.Rectangle.Height < Height || is_separator || !Wrappable) {
945                                                 if (item.Location.X != x || item.Location.Y != y)
946                                                         changed = true;
947                                                 item.Location = new Point (x, y);
948                                                 y += item.Rectangle.Height;
949                                                 if (is_separator)
950                                                         separator_index = i;
951                                         } else if (separator_index > 0) {
952                                                 i = separator_index;
953                                                 separator_index = -1;
954                                                 y = theme.ToolBarGripWidth;
955                                                 x += calculated_size; 
956                                         } else {
957                                                 y = theme.ToolBarGripWidth;
958                                                 x += calculated_size; 
959                                                 if (item.Location.X != x || item.Location.Y != y)
960                                                         changed = true;
961                                                 item.Location = new Point (x, y);
962                                                 y += item.Rectangle.Height;
963                                         }
964                                 } else {
965                                         if (x + item.Rectangle.Width < Width || is_separator || !Wrappable) {
966                                                 if (item.Location.X != x || item.Location.Y != y)
967                                                         changed = true;
968                                                 item.Location = new Point (x, y);
969                                                 x += item.Rectangle.Width;
970                                                 if (is_separator)
971                                                         separator_index = i;
972                                         } else if (separator_index > 0) {
973                                                 i = separator_index;
974                                                 separator_index = -1;
975                                                 x = theme.ToolBarGripWidth;
976                                                 y += calculated_size; 
977                                         } else {
978                                                 x = theme.ToolBarGripWidth;
979                                                 y += calculated_size; 
980                                                 if (item.Location.X != x || item.Location.Y != y)
981                                                         changed = true;
982                                                 item.Location = new Point (x, y);
983                                                 x += item.Rectangle.Width;
984                                         }
985                                 }
986                         }
987                         
988                         if (Parent == null)
989                                 return changed;
990                         
991                         if (Wrappable)
992                                 calculated_size += Vertical ? x : y;
993                         
994                         if (Vertical)
995                                 Width = AutoSize ? calculated_size : requested_size;
996                         else
997                                 Height = AutoSize ? calculated_size : requested_size;
998                         
999                         return changed;
1000                 }
1001                 #endregion Private Methods
1002
1003                 #region subclass
1004                 public class ToolBarButtonCollection : IList, ICollection, IEnumerable
1005                 {
1006                         #region instance variables
1007                         private ArrayList list; // ToolBarButton list
1008                         private ToolBar owner;  // ToolBar associated to Collection
1009                         private bool redraw;    // Flag if needs to redraw after add/remove operations
1010                         #endregion
1011
1012                         #region constructors
1013                         public ToolBarButtonCollection (ToolBar owner)
1014                         {
1015                                 this.list   = new ArrayList ();
1016                                 this.owner  = owner;
1017                                 this.redraw = true;
1018                         }
1019                         #endregion
1020
1021                         #region properties
1022                         [Browsable (false)]
1023                         public int Count {
1024                                 get { return list.Count; }
1025                         }
1026
1027                         public bool IsReadOnly {
1028                                 get { return list.IsReadOnly; }
1029                         }
1030
1031                         public virtual ToolBarButton this [int index] {
1032                                 get { return (ToolBarButton) list [index]; }
1033                                 set {
1034                                         value.SetParent (owner);
1035                                         list [index] = value;
1036                                         owner.Redraw (true);
1037                                 }
1038                         }
1039
1040                         bool ICollection.IsSynchronized {
1041                                 get { return list.IsSynchronized; }
1042                         }
1043
1044                         object ICollection.SyncRoot {
1045                                 get { return list.SyncRoot; }
1046                         }
1047
1048                         bool IList.IsFixedSize {
1049                                 get { return list.IsFixedSize; }
1050                         }
1051
1052                         object IList.this [int index] {
1053                                 get { return this [index]; }
1054                                 set {
1055                                         if (! (value is ToolBarButton))
1056                                                 throw new ArgumentException("Not of type ToolBarButton", "value");
1057                                         this [index] = (ToolBarButton) value;
1058                                 }
1059                         }
1060                         #endregion
1061
1062                         #region methods
1063                         public int Add (string text)
1064                         {
1065                                 ToolBarButton button = new ToolBarButton (text);
1066                                 return this.Add (button);
1067                         }
1068
1069                         public int Add (ToolBarButton button)
1070                         {
1071                                 int result;
1072                                 button.SetParent (owner);
1073                                 result = list.Add (button);
1074                                 if (redraw)
1075                                         owner.Redraw (true);
1076                                 return result;
1077                         }
1078
1079                         public void AddRange (ToolBarButton [] buttons)
1080                         {
1081                                 try {
1082                                         redraw = false;
1083                                         foreach (ToolBarButton button in buttons)
1084                                                 Add (button);
1085                                 }
1086                                 finally {
1087                                         redraw = true;
1088                                         owner.Redraw (true);
1089                                 }
1090                         }
1091
1092                         public void Clear ()
1093                         {
1094                                 list.Clear ();
1095                                 owner.Redraw (false);
1096                         }
1097
1098                         public bool Contains (ToolBarButton button)
1099                         {
1100                                 return list.Contains (button);
1101                         }
1102
1103                         public IEnumerator GetEnumerator ()
1104                         {
1105                                 return list.GetEnumerator ();
1106                         }
1107
1108                         void ICollection.CopyTo (Array dest, int index)
1109                         {
1110                                 list.CopyTo (dest, index);
1111                         }
1112
1113                         int IList.Add (object button)
1114                         {
1115                                 if (! (button is ToolBarButton)) {
1116                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1117                                 }
1118
1119                                 return this.Add ((ToolBarButton) button);
1120                         }
1121
1122                         bool IList.Contains (object button)
1123                         {
1124                                 if (! (button is ToolBarButton)) {
1125                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1126                                 }
1127
1128                                 return this.Contains ((ToolBarButton) button);
1129                         }
1130
1131                         int IList.IndexOf (object button)
1132                         {
1133                                 if (! (button is ToolBarButton)) {
1134                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1135                                 }
1136
1137                                 return this.IndexOf ((ToolBarButton) button);
1138                         }
1139
1140                         void IList.Insert (int index, object button)
1141                         {
1142                                 if (! (button is ToolBarButton)) {
1143                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1144                                 }
1145
1146                                 this.Insert (index, (ToolBarButton) button);
1147                         }
1148
1149                         void IList.Remove (object button)
1150                         {
1151                                 if (! (button is ToolBarButton)) {
1152                                         throw new ArgumentException("Not of type ToolBarButton", "button");
1153                                 }
1154
1155                                 this.Remove ((ToolBarButton) button);
1156                         }
1157
1158                         public int IndexOf (ToolBarButton button)
1159                         {
1160                                 return list.IndexOf (button);
1161                         }
1162
1163                         public void Insert (int index, ToolBarButton button)
1164                         {
1165                                 list.Insert (index, button);
1166                                 owner.Redraw (true);
1167                         }
1168
1169                         public void Remove (ToolBarButton button)
1170                         {
1171                                 list.Remove (button);
1172                                 owner.Redraw (true);
1173                         }
1174
1175                         public void RemoveAt (int index)
1176                         {
1177                                 list.RemoveAt (index);
1178                                 owner.Redraw (true);
1179                         }
1180                         #endregion methods
1181                 }
1182                 
1183                 #endregion subclass
1184         }
1185         
1186         
1187         // Because same button can be added to toolbar multiple times, we need to maintain
1188         // a list of button information for each positions. 
1189         internal class ToolBarItem : Component
1190         {
1191                 #region Instance variables
1192                 
1193                 private ToolBar       toolbar;    // Parent toolbar
1194                 private ToolBarButton button;     // Associated toolBar button 
1195                 private Rectangle     bounds;     // Toolbar button bounds
1196                 private Rectangle     image_rect; // Image button bounds
1197                 private Rectangle     text_rect;  // Text button bounds
1198
1199                 private bool dd_pressed = false;  // to check for a mouse down on dropdown rect
1200                 private bool inside     = false;  // to handle the mouse move event with mouse pressed
1201                 private bool hilight    = false;  // to hilight buttons in flat style
1202                 private bool pressed    = false;  // this is to check for mouse down on a button
1203                 
1204                 #endregion
1205                 
1206                 #region Constructors
1207                 
1208                 public ToolBarItem (ToolBarButton button)
1209                 {
1210                         this.toolbar = button.Parent;
1211                         this.button  = button;
1212                 }
1213                 
1214                 #endregion Constructors
1215         
1216                 #region Properties
1217
1218                 public ToolBarButton Button {
1219                         get { return this.button; }
1220                 }
1221                 
1222                 public Rectangle Rectangle {
1223                         get { 
1224                                 if (!button.Visible || toolbar == null)
1225                                         return Rectangle.Empty;
1226
1227                                 if (button.Style == ToolBarButtonStyle.DropDownButton && toolbar.DropDownArrows) {
1228                                         Rectangle result = bounds;
1229                                         result.Width += ThemeEngine.Current.ToolBarDropDownWidth;
1230                                         return result;
1231                                 }
1232                                  
1233                                 return bounds;
1234                         }
1235                         set { this.bounds = value; }
1236                 }
1237
1238                 public Point Location {
1239                         get { return bounds.Location; }
1240                         set { bounds.Location = value; }
1241                 }
1242
1243                 public Rectangle ImageRectangle {
1244                         get {
1245                                 Rectangle result = image_rect;
1246                                 result.X += bounds.X;
1247                                 result.Y += bounds.Y;
1248                                 return result; 
1249                         }
1250                 }
1251                 
1252                 public Rectangle TextRectangle {
1253                         get { 
1254                                 Rectangle result = text_rect;
1255                                 result.X += bounds.X;
1256                                 result.Y += bounds.Y;
1257                                 return result; 
1258                         }
1259                 }
1260
1261                 private Size TextSize {
1262                         get {
1263                                 StringFormat text_format = new StringFormat ();
1264                                 text_format.HotkeyPrefix = HotkeyPrefix.Hide;
1265
1266                                 SizeF sz = toolbar.DeviceContext.MeasureString (button.Text, toolbar.Font, SizeF.Empty, text_format);
1267                                 if (sz == SizeF.Empty)
1268                                         return Size.Empty;
1269                                 return new Size ((int) Math.Ceiling (sz.Width) + 2 * ToolBar.text_padding, (int) Math.Ceiling (sz.Height));
1270                         }
1271                 }
1272                 
1273                 public bool Pressed {
1274                         get { return (pressed && inside); }
1275                         set { pressed = value; }
1276                 }
1277
1278                 public bool DDPressed {
1279                         get { return dd_pressed; }
1280                         set { dd_pressed = value; }
1281                 }
1282
1283                 public bool Inside {
1284                         get { return inside; }
1285                         set { inside = value; }
1286                 }
1287
1288                 public bool Hilight {
1289                         get { return hilight; }
1290                         set {
1291                                 if (hilight == value)
1292                                         return;
1293
1294                                 hilight = value;
1295                                 Invalidate ();
1296                         }
1297                 }       
1298                 
1299                 #endregion Properties
1300
1301                 #region Methods
1302                 
1303                 public Size CalculateSize ()
1304                 {
1305                         Theme theme = ThemeEngine.Current;
1306
1307                         int ht = toolbar.ButtonSize.Height + 2 * theme.ToolBarGripWidth;
1308
1309                         if (button.Style == ToolBarButtonStyle.Separator)
1310                                 return new Size (theme.ToolBarSeparatorWidth, ht);
1311
1312                         Size size = TextSize;
1313                         Size image_size = (toolbar.ImageSize == Size.Empty) ? new Size (16, 16) : toolbar.ImageSize;
1314
1315                         int image_width = image_size.Width + 2 * theme.ToolBarImageGripWidth; 
1316                         int image_height = image_size.Height + 2 * theme.ToolBarImageGripWidth; 
1317
1318                         if (toolbar.TextAlign == ToolBarTextAlign.Right) {
1319                                 size.Width =  image_width + size.Width;
1320                                 size.Height = (size.Height > image_height) ? size.Height : image_height;
1321                         } else {
1322                                 size.Height = image_height + size.Height;
1323                                 size.Width = (size.Width > image_width) ? size.Width : image_width;
1324                         }
1325
1326                         size.Width += theme.ToolBarGripWidth;
1327                         size.Height += theme.ToolBarGripWidth;
1328                         return size;
1329                 }
1330
1331                 
1332                 public bool Layout ()
1333                 {
1334                         if (toolbar == null || !button.Visible)
1335                                 return false;
1336
1337                         Size psize = toolbar.ButtonSize;
1338                         Size size = psize;
1339                         if ((!toolbar.SizeSpecified) || (button.Style == ToolBarButtonStyle.Separator)) {
1340                                 size = CalculateSize ();
1341                                 if (size.Width == 0 || size.Height == 0)
1342                                         size = psize;
1343                         }
1344                         return Layout (size);
1345                 }
1346
1347                 public bool Layout (Size size)
1348                 {
1349                         if (toolbar == null || !button.Visible)
1350                                 return false;
1351
1352                         bounds.Size = size;
1353
1354                         Size image_size = (toolbar.ImageSize == Size.Empty) ? new Size (16, 16) : toolbar.ImageSize;
1355                         int grip = ThemeEngine.Current.ToolBarImageGripWidth;
1356
1357                         Rectangle new_image_rect, new_text_rect;
1358                         
1359                         if (toolbar.TextAlign == ToolBarTextAlign.Underneath) {
1360                                 new_image_rect = new Rectangle ((bounds.Size.Width - image_size.Width) / 2 - grip, 0, image_size.Width + 2 + grip, image_size.Height + 2 * grip);
1361                                 new_text_rect = new Rectangle (0, new_image_rect.Height, bounds.Size.Width, bounds.Size.Height - new_image_rect.Height - 2 * grip);
1362                         } else {
1363                                 new_image_rect = new Rectangle (0, 0, image_size.Width + 2 * grip, image_size.Height + 2 * grip);
1364                                 new_text_rect = new Rectangle (new_image_rect.Width, 0, bounds.Size.Width - new_image_rect.Width, bounds.Size.Height - 2 * grip);
1365                         }
1366
1367                         bool changed = false;
1368
1369                         if (new_image_rect != image_rect || new_text_rect != text_rect)
1370                                 changed = true;
1371
1372                         image_rect = new_image_rect;
1373                         text_rect = new_text_rect;
1374                         
1375                         return changed;
1376                 }
1377                 
1378                 public void Invalidate ()
1379                 {
1380                         if (toolbar != null)
1381                                 toolbar.Invalidate (Rectangle);
1382                 }
1383
1384                 #endregion Methods
1385         }
1386 }