2006-12-26 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ToolBar.cs
index 16c3dfe15ff3a761c55d33bf5132eabb34a83f27..27af4c0709d50b80e7c35b41467e99ad2b4269e4 100644 (file)
@@ -1,4 +1,3 @@
-//
 // System.Windows.Forms.ToolBar.cs
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 //
 // Author:
 //     Ravindra (rkumar@novell.com)
+//     Mike Kestner <mkestner@novell.com>
 //
 // TODO:
 //   - Tooltip
 //
-// Copyright (C) Novell, Inc. 2004 (http://www.novell.com)
+// Copyright (C) 2004-2006  Novell, Inc. (http://www.novell.com)
 //
 
 
@@ -47,81 +47,93 @@ namespace System.Windows.Forms
        public class ToolBar : Control
        {
                #region Instance Variables
-               internal ToolBarAppearance      appearance;
-               internal bool                   autosize;
-               internal ToolBarButtonCollection buttons;
-               internal Size                   buttonSize;
-               internal bool                   divider;
-               internal bool                   dropDownArrows;
-               internal ImageList              imageList;
-               internal ImeMode                imeMode;
-               internal bool                   showToolTips;
-               internal ToolBarTextAlign       textAlignment;
-               internal bool                   wrappable;        // flag to make the toolbar wrappable
-               internal bool                   redraw;           // flag to force redrawing the control
-               private bool                    size_specified;   // flag to know if button size is fixed.
-               internal ToolBarButton          currentButton; // the highlighted button
+               bool size_specified = false;
+               ToolBarButton current_button;
                #endregion Instance Variables
 
                #region Events
+               static object ButtonClickEvent = new object ();
+               static object ButtonDropDownEvent = new object ();
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler BackColorChanged;
+               public new event EventHandler BackColorChanged {
+                       add { base.BackColorChanged += value; }
+                       remove { base.BackColorChanged -= value; }
+               }
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler BackgroundImageChanged;
+               public new event EventHandler BackgroundImageChanged {
+                       add { base.BackgroundImageChanged += value; }
+                       remove { base.BackgroundImageChanged -= value; }
+               }
+
+               public event ToolBarButtonClickEventHandler ButtonClick {
+                       add { Events.AddHandler (ButtonClickEvent, value); }
+                       remove {Events.RemoveHandler (ButtonClickEvent, value); }
+               }
 
-               public event ToolBarButtonClickEventHandler ButtonClick;
-               public event ToolBarButtonClickEventHandler ButtonDropDown;
+               public event ToolBarButtonClickEventHandler ButtonDropDown {
+                       add { Events.AddHandler (ButtonDropDownEvent, value); }
+                       remove {Events.RemoveHandler (ButtonDropDownEvent, value); }
+               }
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler ForeColorChanged;
+               public new event EventHandler ForeColorChanged {
+                       add { base.ForeColorChanged += value; }
+                       remove { base.ForeColorChanged -= value; }
+               }
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler ImeModeChanged;
+               public new event EventHandler ImeModeChanged {
+                       add { base.ImeModeChanged += value; }
+                       remove { base.ImeModeChanged -= value; }
+               }
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event PaintEventHandler Paint;
+               public new event PaintEventHandler Paint {
+                       add { base.Paint += value; }
+                       remove { base.Paint -= value; }
+               }
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler RightToLeftChanged;
+               public new event EventHandler RightToLeftChanged {
+                       add { base.RightToLeftChanged += value; }
+                       remove { base.RightToLeftChanged -= value; }
+               }
 
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new event EventHandler TextChanged;
+               public new event EventHandler TextChanged {
+                       add { base.TextChanged += value; }
+                       remove { base.TextChanged -= value; }
+               }
                #endregion Events
 
                #region Constructor
                public ToolBar ()
                {
-                       appearance = ToolBarAppearance.Normal;
-                       autosize = true;
                        background_color = ThemeEngine.Current.DefaultControlBackColor;
-                       border_style = BorderStyle.None;
-                       buttons = new ToolBarButtonCollection (this);
-                       buttonSize = Size.Empty;
-                       divider = true;
-                       dropDownArrows = false;
                        foreground_color = ThemeEngine.Current.DefaultControlForeColor;
-                       showToolTips = false;
-                       textAlignment = ToolBarTextAlign.Underneath;
-                       wrappable = true;
+                       buttons = new ToolBarButtonCollection (this);
                        dock_style = DockStyle.Top;
-                       redraw = true;
-                       size_specified = false;
                        
-                       // event handlers
-                       this.MouseDown += new MouseEventHandler (ToolBar_MouseDown);
-                       this.MouseLeave += new EventHandler (ToolBar_MouseLeave);
-                       this.MouseMove += new MouseEventHandler (ToolBar_MouseMove);
-                       this.MouseUp += new MouseEventHandler (ToolBar_MouseUp);
-                       base.Paint += new PaintEventHandler (ToolBar_Paint);
-
+                       GotFocus += new EventHandler (FocusChanged);
+                       LostFocus += new EventHandler (FocusChanged);
+                       MouseDown += new MouseEventHandler (ToolBar_MouseDown);
+                       MouseHover += new EventHandler (ToolBar_MouseHover);
+                       MouseLeave += new EventHandler (ToolBar_MouseLeave);
+                       MouseMove += new MouseEventHandler (ToolBar_MouseMove);
+                       MouseUp += new MouseEventHandler (ToolBar_MouseUp);
+                       BackgroundImageChanged += new EventHandler (ToolBar_BackgroundImageChanged);
+
+                       TabStop = false;
+                       
                        SetStyle (ControlStyles.UserPaint, false);
                        SetStyle (ControlStyles.FixedHeight, true);
                }
@@ -142,6 +154,8 @@ namespace System.Windows.Forms
                }
                #endregion
 
+               ToolBarAppearance appearance = ToolBarAppearance.Normal;
+
                #region Public Properties
                [DefaultValue (ToolBarAppearance.Normal)]
                [Localizable (true)]
@@ -152,13 +166,15 @@ namespace System.Windows.Forms
                                        return;
 
                                appearance = value;
-                               Redraw (false);
+                               Redraw (true);
                        }
                }
 
+               bool autosize = true;
+
                [DefaultValue (true)]
                [Localizable (true)]
-               public bool AutoSize {
+               public new bool AutoSize {
                        get { return autosize; }
                        set {
                                if (value == autosize)
@@ -178,8 +194,7 @@ namespace System.Windows.Forms
                                        return;
 
                                background_color = value;
-                               if (BackColorChanged != null)
-                                       BackColorChanged (this, new EventArgs ());
+                               OnBackColorChanged (EventArgs.Empty);
                                Redraw (false);
                        }
                }
@@ -187,16 +202,8 @@ namespace System.Windows.Forms
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
                public override Image BackgroundImage {
-                       get { return background_image; }
-                       set {
-                               if (value == background_image)
-                                       return;
-
-                               background_image = value;
-                               if (BackgroundImageChanged != null)
-                                       BackgroundImageChanged (this, new EventArgs ());
-                               Redraw (false);
-                       }
+                       get { return base.BackgroundImage; }
+                       set { base.BackgroundImage = value; }
                }
 
                [DefaultValue (BorderStyle.None)]
@@ -206,6 +213,8 @@ namespace System.Windows.Forms
                        set { InternalBorderStyle = value; }
                }
 
+               ToolBarButtonCollection buttons;
+
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
                [Localizable (true)]
                [MergableProperty (false)]
@@ -213,28 +222,35 @@ namespace System.Windows.Forms
                        get { return buttons; }
                }
 
+               Size button_size;
+
                [Localizable (true)]
                [RefreshProperties (RefreshProperties.All)]
                public Size ButtonSize {
                        get {
-                               if (buttonSize.IsEmpty) {
+                               if (button_size.IsEmpty) {
                                        if (buttons.Count == 0)
-                                               return new Size (39, 36);
+                                               return new Size (24, 22);
+                                       Size result = CalcButtonSize ();
+                                       if (result.IsEmpty)
+                                               return new Size (24, 22);
                                        else
-                                               return CalcButtonSize ();
+                                               return result;
                                }
-                               return buttonSize;
+                               return button_size;
                        }
                        set {
-                               if (buttonSize.Width == value.Width && buttonSize.Height == value.Height)
+                               size_specified = value != Size.Empty;
+                               if (button_size == value)
                                        return;
 
-                                       buttonSize = value;
-                                       size_specified = true;
-                                       Redraw (true);
+                               button_size = value;
+                               Redraw (true);
                        }
                }
 
+               bool divider = true;
+
                [DefaultValue (true)]
                public bool Divider {
                        get { return divider; }
@@ -254,15 +270,17 @@ namespace System.Windows.Forms
                        set { base.Dock = value; } 
                }
 
+               bool drop_down_arrows = true;
+
                [DefaultValue (false)]
                [Localizable (true)]
                public bool DropDownArrows {
-                       get { return dropDownArrows; }
+                       get { return drop_down_arrows; }
                        set {
-                               if (value == dropDownArrows)
+                               if (value == drop_down_arrows)
                                        return;
 
-                               dropDownArrows = value;
+                               drop_down_arrows = value;
                                Redraw (true);
                        }
                }
@@ -276,16 +294,22 @@ namespace System.Windows.Forms
                                        return;
 
                                foreground_color = value;
-                               if (ForeColorChanged != null)
-                                       ForeColorChanged (this, new EventArgs ());
+                               OnForeColorChanged (EventArgs.Empty);
                                Redraw (false);
                        }
                }
 
+               ImageList image_list;
+
                [DefaultValue (null)]
                public ImageList ImageList {
-                       get { return imageList; }
-                       set { imageList = value; }
+                       get { return image_list; }
+                       set { 
+                               if (image_list == value)
+                                       return;
+                               image_list = value;
+                               Redraw (true);
+                       }
                }
 
                [Browsable (false)]
@@ -293,24 +317,27 @@ namespace System.Windows.Forms
                [EditorBrowsable (EditorBrowsableState.Advanced)]
                public Size ImageSize {
                        get {
-                               if (imageList == null)
+                               if (ImageList == null)
                                        return Size.Empty;
 
-                               return imageList.ImageSize;
+                               return ImageList.ImageSize;
                        }
                }
 
+               // XXX this should probably go away and it should call
+               // into Control.ImeMode instead.
+               new ImeMode ime_mode = ImeMode.Disable;
+
                [Browsable (false)]
                [EditorBrowsable (EditorBrowsableState.Never)]
                public new ImeMode ImeMode {
-                       get { return imeMode; }
+                       get { return ime_mode; }
                        set {
-                               if (value == imeMode)
+                               if (value == ime_mode)
                                        return;
 
-                               imeMode = value;
-                               if (ImeModeChanged != null)
-                                       ImeModeChanged (this, new EventArgs ());
+                               ime_mode = value;
+                               OnImeModeChanged (EventArgs.Empty);
                        }
                }
 
@@ -323,16 +350,18 @@ namespace System.Windows.Forms
                                        return;
 
                                base.RightToLeft = value;
-                               if (RightToLeftChanged != null)
-                                       RightToLeftChanged (this, new EventArgs ());
+                               OnRightToLeftChanged (EventArgs.Empty);
                        }
                }
 
+               // Default value is "false" but after make a test in .NET we get "true" result as default.  
+               bool show_tooltips = true;
+
                [DefaultValue (false)]
                [Localizable (true)]
                public bool ShowToolTips {
-                       get { return showToolTips; }
-                       set { showToolTips = value; }
+                       get { return show_tooltips; }
+                       set { show_tooltips = value; }
                }
 
                [DefaultValue (false)]
@@ -346,31 +375,33 @@ namespace System.Windows.Forms
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [EditorBrowsable (EditorBrowsableState.Never)]
                public override string Text {
-                       get { return text; } 
+                       get { return base.Text; } 
                        set {
-                               if (value == text)
+                               if (value == base.Text)
                                        return;
 
-                               text = value;
+                               base.Text = value;
                                Redraw (true);
-                               if (TextChanged != null)
-                                       TextChanged (this, new EventArgs ());
                        }
                }
 
+               ToolBarTextAlign text_alignment = ToolBarTextAlign.Underneath;
+
                [DefaultValue (ToolBarTextAlign.Underneath)]
                [Localizable (true)]
                public ToolBarTextAlign TextAlign {
-                       get { return textAlignment; }
+                       get { return text_alignment; }
                        set {
-                               if (value == textAlignment)
+                               if (value == text_alignment)
                                        return;
 
-                               textAlignment = value;
+                               text_alignment = value;
                                Redraw (true);
                        }
                }
 
+               bool wrappable = true;
+
                [DefaultValue (true)]
                [Localizable (true)]
                public bool Wrappable {
@@ -391,47 +422,13 @@ namespace System.Windows.Forms
                        int count = this.Buttons.Count;
 
                        if (count == 0)
-                               return string.Format ("System.Windows.Forms.ToolBar, Button.Count: 0");
+                               return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: 0");
                        else
-                               return string.Format ("System.Windows.Forms.ToolBar, Button.Count: {0}, Buttons[0]: {1}",
+                               return string.Format ("System.Windows.Forms.ToolBar, Buttons.Count: {0}, Buttons[0]: {1}",
                                                      count, this.Buttons [0].ToString ());
                }
                #endregion Public Methods
 
-               #region Internal Methods
-               internal Rectangle GetChildBounds (ToolBarButton button)
-               {
-                       if (button.Style == ToolBarButtonStyle.Separator)
-                               return new Rectangle (button.Location.X, button.Location.Y, 
-                                                     ThemeEngine.Current.ToolBarSeparatorWidth, this.ButtonSize.Height);
-
-                       if (size_specified)
-                               return new Rectangle (button.Location, this.ButtonSize);
-
-                       SizeF sz = this.DeviceContext.MeasureString (button.Text, this.Font);
-                       Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
-
-                       if (imageList != null) {
-                               // adjustment for the image grip 
-                               int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth; 
-                               int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth; 
-
-                               if (textAlignment == ToolBarTextAlign.Right) {
-                                       size.Width =  imgWidth + size.Width;
-                                       size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
-                               }
-                               else {
-                                       size.Height = imgHeight + size.Height;
-                                       size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
-                               }
-                       }
-                       if (button.Style == ToolBarButtonStyle.DropDownButton && this.dropDownArrows)
-                               size.Width += ThemeEngine.Current.ToolBarDropDownWidth;
-
-                       return new Rectangle (button.Location, size);
-               }
-               #endregion Internal Methods
-
                #region Protected Methods
                protected override void CreateHandle ()
                {
@@ -441,7 +438,7 @@ namespace System.Windows.Forms
                protected override void Dispose (bool disposing)
                {
                        if (disposing)
-                               imageList = null;
+                               ImageList = null;
 
                        base.Dispose (disposing);
                }
@@ -456,29 +453,27 @@ namespace System.Windows.Forms
                        }
                        e.Button.pressed = false;
 
-                       Invalidate (e.Button.Rectangle);
-                       Redraw (false);
+                       e.Button.Invalidate ();
 
-                       if (ButtonClick != null)
-                               ButtonClick (this, e);
-                       else
-                               return;
+                       ToolBarButtonClickEventHandler eh = (ToolBarButtonClickEventHandler)(Events [ButtonClickEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected virtual void OnButtonDropDown (ToolBarButtonClickEventArgs e) 
                {
-                       // Reset the flag set on DropDown
-                       e.Button.dd_pressed = false;
-
-                       if (ButtonDropDown != null)
-                               ButtonDropDown (this, e);
+                       ToolBarButtonClickEventHandler eh = (ToolBarButtonClickEventHandler)(Events [ButtonDropDownEvent]);
+                       if (eh != null)
+                               eh (this, e);
 
                        if (e.Button.DropDownMenu == null)
                                return;
 
-                       Point loc = new Point (e.Button.Location.X + 1,
-                                              e.Button.Rectangle.Bottom + 2);
+                       Point loc = new Point (e.Button.Rectangle.X + 1, e.Button.Rectangle.Bottom + 1);
                        ((ContextMenu) e.Button.DropDownMenu).Show (this, loc);
+
+                       e.Button.dd_pressed = false;
+                       Invalidate (e.Button.Rectangle);
                }
 
                protected override void OnFontChanged (EventArgs e)
@@ -496,14 +491,20 @@ namespace System.Windows.Forms
                {
                        base.OnResize (e);
 
-                       if (this.Width <= 0 || this.Height <= 0 || this.Visible == false)
+                       if (Width <= 0 || Height <= 0 || !Visible)
                                return;
 
-                       Redraw (true);
+                       Redraw (true, BackgroundImage != null);
                }
 
+               int requested_height = -1;
+
                protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
                {
+                       // New height requested
+                       if (!AutoSize && (requested_height != height) && ((specified & BoundsSpecified.Height) != BoundsSpecified.None)) 
+                               requested_height = height;
+                       
                        base.SetBoundsCore (x, y, width, height, specified);
                }
 
@@ -512,39 +513,135 @@ namespace System.Windows.Forms
                        base.WndProc (ref m);
                }
 
+               internal override bool InternalPreProcessMessage (ref Message msg)
+               {
+                       if (msg.Msg == (int)Msg.WM_KEYDOWN) {
+                               Keys key_data = (Keys)msg.WParam.ToInt32();
+                               if (HandleKeyDown (key_data))
+                                       return true;
+                       } 
+                       return base.InternalPreProcessMessage (ref msg);
+               }
+                       
                #endregion Protected Methods
 
                #region Private Methods
+               private void FocusChanged (object sender, EventArgs args)
+               {
+                       if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
+                               return;
+
+                       ToolBarButton prelit = null;
+                       foreach (ToolBarButton b in Buttons)
+                               if (b.Hilight) {
+                                       prelit = b;
+                                       break;
+                               }
+
+                       if (Focused && prelit == null)
+                               foreach (ToolBarButton btn in Buttons) {
+                                       if (btn.Enabled) {
+                                               btn.Hilight = true;
+                                               break;
+                                       }
+                               }
+                       else if (prelit != null)
+                               prelit.Hilight = false;
+               }
+
+               private bool HandleKeyDown (Keys key_data)
+               {
+                       if (Appearance != ToolBarAppearance.Flat || Buttons.Count == 0)
+                               return false;
+
+                       switch (key_data) {
+                       case Keys.Left:
+                       case Keys.Up:
+                               HighlightButton (-1);
+                               return true;
+                       case Keys.Right:
+                       case Keys.Down:
+                               HighlightButton (1);
+                               return true;
+                       default:
+                               return false;
+                       }
+               }
+
+               void HighlightButton (int offset)
+               {
+                       ArrayList enabled = new ArrayList ();
+                       int count = 0;
+                       int start = -1;
+                       ToolBarButton curr_button = null;
+                       foreach (ToolBarButton btn in Buttons) {
+                               if (btn.Hilight) {
+                                       start = count;
+                                       curr_button = btn;
+                               }
+
+                               if (btn.Enabled) {
+                                       enabled.Add (btn);
+                                       count++;
+                               }
+                       }
+
+                       int next = (start + offset) % count;
+                       if (next < 0)
+                               next = count - 1;
+
+                       if (next == start)
+                               return;
+
+                       if (curr_button != null)
+                               curr_button.Hilight = false;
+                       (enabled [next] as ToolBarButton).Hilight = true;
+               }
+
+               private void ToolBar_BackgroundImageChanged (object sender, EventArgs args)
+               {
+                       Redraw (false);
+               }
+
                private void ToolBar_MouseDown (object sender, MouseEventArgs me)
                {
-                       if (! this.Enabled) return;
+                       if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
+                               return;
 
-                       Point hit = new Point (me.X, me.Y);
-                       this.Capture = true;
+                       Point loc = new Point (me.X, me.Y);
 
+                       if (ButtonAtPoint (loc) == null)
+                               return;
+                       
+                       // Hide tooltip when left mouse button 
+                       if ((tip_window != null) && (tip_window.Visible) && ((me.Button & MouseButtons.Left) == MouseButtons.Left)) {
+                               TipDownTimer.Stop ();
+                               tip_window.Hide ();
+                       }
+                       
                        // draw the pushed button
                        foreach (ToolBarButton button in buttons) {
-                               if (button.Enabled && button.Rectangle.Contains (hit)) {
+                               if (button.Enabled && button.Rectangle.Contains (loc)) {
                                        // Mark the DropDown rect as pressed.
                                        // We don't redraw the dropdown rect.
                                        if (button.Style == ToolBarButtonStyle.DropDownButton) {
-                                               Rectangle ddRect = Rectangle.Empty;
                                                Rectangle rect = button.Rectangle;
-                                               ddRect.Height = rect.Height;
-                                               ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
-                                               ddRect.X = rect.X + rect.Width - ddRect.Width;
-                                               ddRect.Y = rect.Y;
-                                               if (ddRect.Contains (hit)) {
-                                                       button.dd_pressed = true;
+                                               if (DropDownArrows) {
+                                                       rect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
+                                                       rect.X = button.Rectangle.Right - rect.Width;
+                                               }
+                                               
+                                               if (rect.Contains (loc)) {
+                                                       if (button.DropDownMenu != null) {
+                                                               button.dd_pressed = true;
+                                                               Invalidate (rect);
+                                                       }
                                                        break;
                                                }
                                        }
-                                       // If it is not dropdown then we treat it as a normal
-                                       // button press.
                                        button.pressed = true;
                                        button.inside = true;
-                                       Invalidate (button.Rectangle);
-                                       Redraw (false);
+                                       button.Invalidate ();
                                        break;
                                }
                        }
@@ -552,265 +649,300 @@ namespace System.Windows.Forms
 
                private void ToolBar_MouseUp (object sender, MouseEventArgs me)
                {
-                       if (! this.Enabled) return;
+                       if ((!Enabled) || ((me.Button & MouseButtons.Left) == 0))
+                               return;
 
-                       Point hit = new Point (me.X, me.Y);
-                       this.Capture = false;
+                       Point loc = new Point (me.X, me.Y);
 
                        // draw the normal button
+                       // Make a copy in case the list is modified during enumeration
+                       ArrayList buttons = new ArrayList (this.buttons);
                        foreach (ToolBarButton button in buttons) {
-                               if (button.Enabled && button.Rectangle.Contains (hit)) {
+                               if (button.Enabled && button.Rectangle.Contains (loc)) {
                                        if (button.Style == ToolBarButtonStyle.DropDownButton) {
-                                               Rectangle ddRect = Rectangle.Empty;
-                                               Rectangle rect = button.Rectangle;
-                                               ddRect.Height = rect.Height;
+                                               Rectangle ddRect = button.Rectangle;
                                                ddRect.Width = ThemeEngine.Current.ToolBarDropDownWidth;
-                                               ddRect.X = rect.X + rect.Width - ddRect.Width;
-                                               ddRect.Y = rect.Y;
-                                               // Fire a ButtonDropDown event
-                                               if (ddRect.Contains (hit)) {
+                                               ddRect.X = button.Rectangle.Right - ddRect.Width;
+                                               if (ddRect.Contains (loc)) {
                                                        if (button.dd_pressed)
-                                                               this.OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
+                                                               OnButtonDropDown (new ToolBarButtonClickEventArgs (button));
                                                        continue;
                                                }
                                        }
                                        // Fire a ButtonClick
-                                       if (button.pressed)
-                                               this.OnButtonClick (new ToolBarButtonClickEventArgs (button));
-                               }
-                               // Clear the button press flags, if any
-                               else if (button.pressed) {
+                                       if ((button.pressed) && ((me.Button & MouseButtons.Left) == MouseButtons.Left))
+                                               OnButtonClick (new ToolBarButtonClickEventArgs (button));
+                               } else if (button.pressed) {
                                        button.pressed = false;
-                                       Invalidate (button.Rectangle);
-                                       Redraw (false);
+                                       button.Invalidate ();
                                }
                        }
                }
 
-               private void ToolBar_MouseLeave (object sender, EventArgs e)
+               private ToolBarButton ButtonAtPoint (Point pt)
                {
-                       if (! this.Enabled || appearance != ToolBarAppearance.Flat) return;
+                       foreach (ToolBarButton button in buttons)
+                               if (button.Rectangle.Contains (pt)) 
+                                       return button;
 
-                       if (currentButton != null && currentButton.Hilight) {
-                               currentButton.Hilight = false;
-                               Invalidate (currentButton.Rectangle);
-                               Redraw (false);
+                       return null;
+               }
+
+               ToolTip.ToolTipWindow tip_window = null;
+               Timer tipdown_timer = null;
+
+               private void PopDownTip (object o, EventArgs args)
+               {
+                       tip_window.Hide ();
+               }
+
+               private Timer TipDownTimer {
+                       get {
+                               if (tipdown_timer == null) {
+                                       tipdown_timer = new Timer ();
+                                       tipdown_timer.Enabled = false;
+                                       tipdown_timer.Interval = 5000;
+                                       tipdown_timer.Tick += new EventHandler (PopDownTip);
+                               }
+                               return tipdown_timer;
                        }
-                       currentButton = null;
+               }
+
+               private void ToolBar_MouseHover (object sender, EventArgs e)
+               {
+                       if (Capture)
+                               return;
+
+                       if (tip_window == null)
+                               tip_window = new ToolTip.ToolTipWindow ();
+
+                       ToolBarButton btn = ButtonAtPoint (PointToClient (Control.MousePosition));
+                       current_button = btn;
+
+                       if (btn == null || btn.ToolTipText.Length == 0)
+                               return;
+
+                       tip_window.Present (this, btn.ToolTipText);
+                       TipDownTimer.Start ();
+               }
+
+               private void ToolBar_MouseLeave (object sender, EventArgs e)
+               {
+                       if (tipdown_timer != null)
+                               tipdown_timer.Dispose ();
+                       tipdown_timer = null;
+                       if (tip_window != null)
+                               tip_window.Dispose ();
+                       tip_window = null;
+
+                       if (!Enabled || current_button == null) 
+                               return;
+
+                       current_button.Hilight = false;
+                       current_button = null;
                }
 
                private void ToolBar_MouseMove (object sender, MouseEventArgs me)
                {
-                       if (! this.Enabled) return;
+                       if (!Enabled) 
+                               return;
 
-                       Point hit = new Point (me.X, me.Y);
+                       if (tip_window != null && tip_window.Visible) {
+                               TipDownTimer.Stop ();
+                               TipDownTimer.Start ();
+                       }
+
+                       Point loc = new Point (me.X, me.Y);
 
-                       if (this.Capture) {
+                       if (Capture) {
                                // If the button was pressed and we leave, release the 
                                // button press and vice versa
                                foreach (ToolBarButton button in buttons) {
                                        if (button.pressed &&
-                                           (button.inside != button.Rectangle.Contains (hit))) {
-                                               button.inside = button.Rectangle.Contains (hit);
+                                           (button.inside != button.Rectangle.Contains (loc))) {
+                                               button.inside = button.Rectangle.Contains (loc);
                                                button.Hilight = false;
-                                               Invalidate (button.Rectangle);
-                                               Redraw (false);
                                                break;
                                        }
                                }
-                       }
-                       // following is only for flat style toolbar
-                       else if (appearance == ToolBarAppearance.Flat) {
-                               if (currentButton != null && currentButton.Rectangle.Contains (hit)) {
-                                       if (currentButton.Hilight || currentButton.Pushed)
+                               return;
+                       } 
+
+                       if (current_button != null && current_button.Rectangle.Contains (loc)) {
+                               if (appearance == ToolBarAppearance.Flat) {
+                                       if (current_button.Hilight || current_button.Pushed || !current_button.Enabled)
                                                return;
-                                       currentButton.Hilight = true;
-                                       Invalidate (currentButton.Rectangle);
-                                       Redraw (false);
+                                       current_button.Hilight = true;
                                }
-                               else {
+                       } else {
+                               if (tip_window != null) {
+                                       if (tip_window.Visible) {
+                                               tip_window.Hide ();
+                                               TipDownTimer.Stop ();
+                                       }
+                                       current_button = ButtonAtPoint (loc);
+                                       if (current_button != null && current_button.ToolTipText.Length > 0) {
+                                               tip_window.Present (this, current_button.ToolTipText);
+                                               TipDownTimer.Start ();
+                                       }
+                               }
+
+                               if (appearance == ToolBarAppearance.Flat) {
                                        foreach (ToolBarButton button in buttons) {
-                                               if (button.Rectangle.Contains (hit) && button.Enabled) {
-                                                       currentButton = button;
-                                                       if (currentButton.Hilight || currentButton.Pushed)
+                                               if (button.Rectangle.Contains (loc) && button.Enabled) {
+                                                       current_button = button;
+                                                       if (current_button.Hilight || current_button.Pushed)
                                                                continue;
-                                                       currentButton.Hilight = true;
-                                                       Invalidate (currentButton.Rectangle);
-                                                       Redraw (false);
+                                                       current_button.Hilight = true;
                                                }
                                                else if (button.Hilight) {
                                                        button.Hilight = false;
-                                                       Invalidate (button.Rectangle);
-                                                       Redraw (false);
                                                }
                                        }
                                }
                        }
                }
 
-               private void ToolBar_Paint (object sender, PaintEventArgs pevent)
+               internal override void OnPaintInternal (PaintEventArgs pevent)
                {
-                       if (this.Width <= 0 || this.Height <=  0 || this.Visible == false)
-                               return;
-
-                       if (redraw) {
-                               ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
-                               redraw = false;
-                       }
-
-                       if (Paint != null) {
-                               Paint (this, pevent);
-                       }
+                       ThemeEngine.Current.DrawToolBar (pevent.Graphics, pevent.ClipRectangle, this);
                }
 
                internal void Redraw (bool recalculate)
                {
+                       Redraw (recalculate, true);
+               }
+
+               internal void Redraw (bool recalculate, bool force)
+               {
+                       bool invalidate = true;
                        if (recalculate) {
-                               CalcToolBar ();
+                               invalidate = LayoutToolBar ();
                        }
 
-                       redraw = true;
-                       Refresh ();
+                       if (force || invalidate)
+                               Invalidate ();
                }
 
+               internal bool SizeSpecified {
+                       get { return size_specified; }
+               }
+
+               const int text_padding = 3;
+
                private Size CalcButtonSize ()
                {
-                       String longestText = buttons [0].Text;
-                       for (int i = 1; i < buttons.Count; i++) {
-                               if (buttons[i].Text.Length > longestText.Length)
-                                       longestText = buttons[i].Text;
+                       if (Buttons.Count == 0)
+                               return Size.Empty;
+
+                       string longest_text = Buttons [0].Text;
+                       for (int i = 1; i < Buttons.Count; i++) {
+                               if (Buttons[i].Text.Length > longest_text.Length)
+                                       longest_text = Buttons[i].Text;
                        }
 
-                       SizeF sz = this.DeviceContext.MeasureString (longestText, this.Font);
-                       Size size = new Size ((int) Math.Ceiling (sz.Width), (int) Math.Ceiling (sz.Height));
+                       Size size = Size.Empty;
+                       if (longest_text != null && longest_text.Length > 0) {
+                               SizeF sz = DeviceContext.MeasureString (longest_text, Font);
+                               if (sz != SizeF.Empty)
+                                       size = new Size ((int) Math.Ceiling (sz.Width) + 2 * text_padding, (int) Math.Ceiling (sz.Height));
+                       }
 
-                       if (imageList != null) {
-                               // adjustment for the image grip 
-                               int imgWidth = this.ImageSize.Width + 2 * ThemeEngine.Current.ToolBarImageGripWidth; 
-                               int imgHeight = this.ImageSize.Height + 2 * ThemeEngine.Current.ToolBarImageGripWidth;
+                       Size img_size = ImageList == null ? new Size (16, 16) : ImageSize;
 
-                               if (textAlignment == ToolBarTextAlign.Right) {
-                                       size.Width = imgWidth + size.Width;
-                                       size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
-                               }
-                               else {
-                                       size.Height = imgHeight + size.Height;
-                                       size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
-                               }
+                       Theme theme = ThemeEngine.Current;
+                       int imgWidth = img_size.Width + 2 * theme.ToolBarImageGripWidth; 
+                       int imgHeight = img_size.Height + 2 * theme.ToolBarImageGripWidth;
+
+                       if (text_alignment == ToolBarTextAlign.Right) {
+                               size.Width = imgWidth + size.Width;
+                               size.Height = (size.Height > imgHeight) ? size.Height : imgHeight;
+                       } else {
+                               size.Height = imgHeight + size.Height;
+                               size.Width = (size.Width > imgWidth) ? size.Width : imgWidth;
                        }
+
+                       size.Width += theme.ToolBarImageGripWidth;
+                       size.Height += theme.ToolBarImageGripWidth;
                        return size;
                }
 
-               /* Checks for the separators and sets the location of a button and its wrapper flag */
-               private void CalcToolBar ()
-               {
-                       int wd = this.Width;             // the amount of space we have for rest of the buttons
-                       int ht = this.ButtonSize.Height; // all buttons are displayed with the same height
-                       Point loc;                       // the location to place the next button, leave the space for border
-                       loc = new Point (ThemeEngine.Current.ToolBarGripWidth, ThemeEngine.Current.ToolBarGripWidth);
-
-                       // clear all the wrappers if toolbar is not wrappable
-                       if (! wrappable && ! autosize) {
-                               if (this.Height != this.DefaultSize.Height)
-                                       this.Height = this.DefaultSize.Height;
-                               foreach (ToolBarButton button in buttons) {
-                                       button.Location = loc;
-                                       button.Wrapper = false;
-                                       loc.X = loc.X + button.Rectangle.Width;
-                               }
-                       }
-                       else if (! wrappable) { // autosizeable
-                               if (ht != this.Height)
-                                       this.Height = ht;
-                               foreach (ToolBarButton button in buttons) {
-                                       button.Location = loc;
-                                       button.Wrapper = false;
-                                       loc.X = loc.X + button.Rectangle.Width;
-                               }
-                       }
-                       else { // wrappable
-                               bool seenSeparator = false;
-                               int separatorIndex = -1;
-                               ToolBarButton button;
-
-                               for (int i = 0; i < buttons.Count; i++) {
-                                       button = buttons [i];
-                                       if (button.Visible) {
-                                               if (button.Style == ToolBarButtonStyle.Separator) {
-                                                       wd -= ThemeEngine.Current.ToolBarSeparatorWidth;
-                                                       if (wd > 0) {
-                                                               button.Wrapper = false; // clear the old flag in case it was set
-                                                               button.Location = loc;
-                                                               loc.X = loc.X + ThemeEngine.Current.ToolBarSeparatorWidth;
-                                                       }
-                                                       else {
-                                                               button.Wrapper = true;
-                                                               button.Location = loc;
-                                                               loc.X = ThemeEngine.Current.ToolBarGripWidth;
-                                                               wd = this.Width;
-                                                               // we need space to draw horizontal separator
-                                                               loc.Y = loc.Y + ThemeEngine.Current.ToolBarSeparatorWidth + ht; 
-                                                       }
-                                                       seenSeparator = true;
-                                                       separatorIndex = i;
-                                               }
-                                               else {
-                                                       Rectangle rect = button.Rectangle;
-                                                       wd -= rect.Width;
-                                                       if (wd > 0) {
-                                                               button.Wrapper = false;
-                                                               button.Location = loc;
-                                                               loc.X = loc.X + rect.Width;
-                                                       }
-                                                       else if (seenSeparator) { 
-                                                               // wrap at the separator and reassign the locations
-                                                               i = separatorIndex; // for loop is going to increment it
-                                                               buttons [separatorIndex].Wrapper = true;
-                                                               seenSeparator = false;
-                                                               separatorIndex = -1;
-                                                               loc.X = ThemeEngine.Current.ToolBarGripWidth;
-                                                               // we need space to draw horizontal separator
-                                                               loc.Y = loc.Y + ht + ThemeEngine.Current.ToolBarSeparatorWidth; 
-                                                               wd = this.Width;
-                                                               continue;
-                                                       }
-                                                       else {
-                                                               button.Wrapper = true;
-                                                               wd = this.Width;
-                                                               loc.X = 0;
-                                                               loc.Y += ht;
-                                                               button.Location = loc;
-                                                               loc.X = loc.X + rect.Width;
-                                                       }
-                                               }
+               // Flat toolbars disregard specified sizes.  Normal toolbars grow the
+               // button size to be at least large enough to show the image.
+               Size AdjustedButtonSize {
+                       get {
+                               Size size = ButtonSize;
+                               if (size_specified) {
+                                       if (Appearance == ToolBarAppearance.Flat)
+                                               size = CalcButtonSize ();
+                                       else {
+                                               int grip = ThemeEngine.Current.ToolBarImageGripWidth;
+                                               if (size.Width < ImageSize.Width + 2 * grip )
+                                                       size.Width = ImageSize.Width + 2 * grip;
+                                               if (size.Height < ImageSize.Height + 2 * grip)
+                                                       size.Height = ImageSize.Height + 2 * grip;
                                        }
-                                       else // don't consider invisible buttons
-                                               continue;
                                }
-                               /* adjust the control height, if we are autosizeable */
-                               if (autosize) // wrappable
-                                       if (this.Height != (loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth))
-                                               this.Height = loc.Y + ht + ThemeEngine.Current.ToolBarGripWidth;
+                               return size;
                        }
                }
 
-               private void DumpToolBar (string msg)
+               bool LayoutToolBar ()
                {
-                       Console.WriteLine (msg);
-                       Console.WriteLine ("ToolBar: name: " + this.Text);
-                       Console.WriteLine ("ToolBar: wd, ht: " + this.Size);
-                       Console.WriteLine ("ToolBar: img size: " + this.ImageSize);
-                       Console.WriteLine ("ToolBar: button sz: " + this.buttonSize);
-                       Console.WriteLine ("ToolBar: textalignment: "+ this.TextAlign);
-                       Console.WriteLine ("ToolBar: appearance: "+ this.Appearance);
-                       Console.WriteLine ("ToolBar: wrappable: "+ this.Wrappable);
-                       Console.WriteLine ("ToolBar: buttons count: " + this.Buttons.Count);
-
-                       int i= 0;       
-                       foreach (ToolBarButton b in buttons) {
-                               Console.WriteLine ("ToolBar: button [{0}]:",i++);
-                               b.Dump ();
+                       bool changed = false;
+                       Theme theme = ThemeEngine.Current;
+                       int x = theme.ToolBarGripWidth;
+                       int y = theme.ToolBarGripWidth;
+
+                       Size adjusted_size = AdjustedButtonSize;
+                       int ht = adjusted_size.Height + theme.ToolBarGripWidth;
+
+                       int separator_index = -1;
+
+                       for (int i = 0; i < buttons.Count; i++) {
+                               ToolBarButton button = buttons [i];
+
+                               if (!button.Visible)
+                                       continue;
+
+                               if (size_specified && (button.Style != ToolBarButtonStyle.Separator))
+                                       changed = button.Layout (adjusted_size);
+                               else
+                                       changed = button.Layout ();
+                               
+                               bool is_separator = button.Style == ToolBarButtonStyle.Separator;
+
+                               if (x + button.Rectangle.Width < Width || is_separator || !Wrappable) {
+                                       if (button.Location.X != x || button.Location.Y != y)
+                                               changed = true;
+                                       button.Location = new Point (x, y);
+                                       x += button.Rectangle.Width;
+                                       if (is_separator)
+                                               separator_index = i;
+                               } else if (separator_index > 0) {
+                                       i = separator_index;
+                                       separator_index = -1;
+                                       x = theme.ToolBarGripWidth;
+                                       y += ht; 
+                               } else {
+                                       x = theme.ToolBarGripWidth;
+                                       y += ht; 
+                                       if (button.Location.X != x || button.Location.Y != y)
+                                               changed = true;
+                                       button.Location = new Point (x, y);
+                                       x += button.Rectangle.Width;
+                               }
                        }
+                       
+                       if (Parent == null)
+                               return changed;
+                       
+                       if (AutoSize)
+                               Height = ht + (Wrappable ? y : 0);
+                       else
+                               Height = requested_height;
+                       
+                       return changed;
                }
                #endregion Private Methods
 
@@ -818,47 +950,49 @@ namespace System.Windows.Forms
                public class ToolBarButtonCollection : IList, ICollection, IEnumerable
                {
                        #region instance variables
-                       private ArrayList buttonsList;
+                       private ArrayList list;
                        private ToolBar owner;
+                       private bool redraw;
                        #endregion
 
                        #region constructors
                        public ToolBarButtonCollection (ToolBar owner)
                        {
                                this.owner = owner;
-                               this.buttonsList = new ArrayList ();
+                               list = new ArrayList ();
+                               redraw = true;
                        }
                        #endregion
 
                        #region properties
                        [Browsable (false)]
-                       public virtual int Count {
-                               get { return buttonsList.Count; }
+                       public int Count {
+                               get { return list.Count; }
                        }
 
-                       public virtual bool IsReadOnly {
-                               get { return buttonsList.IsReadOnly; }
+                       public bool IsReadOnly {
+                               get { return list.IsReadOnly; }
                        }
 
                        public virtual ToolBarButton this [int index] {
-                               get { return (ToolBarButton) buttonsList [index]; }
+                               get { return (ToolBarButton) list [index]; }
                                set {
                                        value.SetParent (owner);
-                                       buttonsList [index] = value;
+                                       list [index] = value;
                                        owner.Redraw (true);
                                }
                        }
 
                        bool ICollection.IsSynchronized {
-                               get { return buttonsList.IsSynchronized; }
+                               get { return list.IsSynchronized; }
                        }
 
                        object ICollection.SyncRoot {
-                               get { return buttonsList.SyncRoot; }
+                               get { return list.SyncRoot; }
                        }
 
                        bool IList.IsFixedSize {
-                               get { return buttonsList.IsFixedSize; }
+                               get { return list.IsFixedSize; }
                        }
 
                        object IList.this [int index] {
@@ -882,36 +1016,44 @@ namespace System.Windows.Forms
                        {
                                int result;
                                button.SetParent (owner);
-                               result = buttonsList.Add (button);
-                               owner.Redraw (true);
+                               result = list.Add (button);
+                               if (redraw)
+                                       owner.Redraw (true);
                                return result;
                        }
 
                        public void AddRange (ToolBarButton [] buttons)
                        {
-                               foreach (ToolBarButton button in buttons)
-                                       Add (button);
+                               try {
+                                       redraw = false;
+                                       foreach (ToolBarButton button in buttons)
+                                               Add (button);
+                               }
+                               finally {
+                                       redraw = true;
+                                       owner.Redraw (true);
+                               }
                        }
 
-                       public virtual void Clear ()
+                       public void Clear ()
                        {
-                               buttonsList.Clear ();
+                               list.Clear ();
                                owner.Redraw (false);
                        }
 
                        public bool Contains (ToolBarButton button)
                        {
-                               return buttonsList.Contains (button);
+                               return list.Contains (button);
                        }
 
-                       public virtual IEnumerator GetEnumerator ()
+                       public IEnumerator GetEnumerator ()
                        {
-                               return buttonsList.GetEnumerator ();
+                               return list.GetEnumerator ();
                        }
 
                        void ICollection.CopyTo (Array dest, int index)
                        {
-                               buttonsList.CopyTo (dest, index);
+                               list.CopyTo (dest, index);
                        }
 
                        int IList.Add (object button)
@@ -961,24 +1103,24 @@ namespace System.Windows.Forms
 
                        public int IndexOf (ToolBarButton button)
                        {
-                               return buttonsList.IndexOf (button);
+                               return list.IndexOf (button);
                        }
 
                        public void Insert (int index, ToolBarButton button)
                        {
-                               buttonsList.Insert (index, button);
+                               list.Insert (index, button);
                                owner.Redraw (true);
                        }
 
                        public void Remove (ToolBarButton button)
                        {
-                               buttonsList.Remove (button);
+                               list.Remove (button);
                                owner.Redraw (true);
                        }
 
-                       public virtual void RemoveAt (int index)
+                       public void RemoveAt (int index)
                        {
-                               buttonsList.RemoveAt (index);
+                               list.RemoveAt (index);
                                owner.Redraw (true);
                        }
                        #endregion methods