Merge pull request #268 from pcc/menudeactivate
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ToolStrip.cs
index 7eba9d22a43986715f4dcfd3fd5da323d28264d3..30c0d89f5fb40633ee7a05e3dc555e6408b74e67 100644 (file)
@@ -26,7 +26,6 @@
 //     Jonathan Pobst (monkey@jpobst.com)
 //
 
-#if NET_2_0
 using System;
 using System.Runtime.InteropServices;
 using System.ComponentModel;
@@ -43,7 +42,7 @@ namespace System.Windows.Forms
        [DefaultProperty ("Items")]
        [Designer ("System.Windows.Forms.Design.ToolStripDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
        [DesignerSerializer ("System.Windows.Forms.Design.ToolStripCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
-       public class ToolStrip : ScrollableControl, IComponent, IDisposable
+       public class ToolStrip : ScrollableControl, IComponent, IDisposable, IToolStripData
        {
                #region Private Variables
                private bool allow_item_reorder;
@@ -79,6 +78,10 @@ namespace System.Windows.Forms
                private ToolStripItem mouse_currently_over;
                internal bool menu_selected;
                private ToolStripItem tooltip_currently_showing;
+               private ToolTip.TipState tooltip_state;
+
+               const int InitialToolTipDelay = 500;
+               const int ToolTipDelay = 5000;
                #endregion
 
                #region Public Constructors
@@ -98,7 +101,7 @@ namespace System.Windows.Forms
                        this.items = new ToolStripItemCollection (this, items, true);
                        this.allow_merge = true;
                        base.AutoSize = true;
-                       base.SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
+                       this.SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
                        this.back_color = Control.DefaultBackColor;
                        this.can_overflow = true;
                        base.CausesValidation = false;
@@ -127,13 +130,13 @@ namespace System.Windows.Forms
                #endregion
 
                #region Public Properties
-               [MonoTODO ()]
+               [MonoTODO ("Stub, does nothing")]
                public override bool AllowDrop {
                        get { return base.AllowDrop; }
                        set { base.AllowDrop = value; }
                }
-               
-               [MonoTODO ()]
+
+               [MonoTODO ("Stub, does nothing")]
                [DefaultValue (false)]
                public bool AllowItemReorder {
                        get { return this.allow_item_reorder; }
@@ -143,7 +146,7 @@ namespace System.Windows.Forms
                [DefaultValue (true)]
                public bool AllowMerge {
                        get { return this.allow_merge; }
-                       set { this.allow_merge = false; }
+                       set { this.allow_merge = value; }
                }
                
                public override AnchorStyles Anchor {
@@ -335,7 +338,7 @@ namespace System.Windows.Forms
                                        if (!Enum.IsDefined (typeof (ToolStripGripStyle), value))
                                                throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripGripStyle", value));
                                        this.grip_style = value;
-                                       this.PerformLayout ();
+                                       this.PerformLayout (this, "GripStyle");
                                }
                        }
                }
@@ -403,7 +406,12 @@ namespace System.Windows.Forms
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public LayoutSettings LayoutSettings {
                        get { return this.layout_settings; }
-                       set { this.layout_settings = value; }
+                       set { 
+                               if (this.layout_settings != value) {
+                                       this.layout_settings = value;
+                                       PerformLayout (this, "LayoutSettings");
+                               }
+                       }
                }
                
                [AmbientValue (ToolStripLayoutStyle.StackWithOverflow)]
@@ -435,7 +443,7 @@ namespace System.Windows.Forms
                                                
                                        this.layout_settings = this.CreateLayoutSettings (value);
                                        
-                                       this.PerformLayout ();
+                                       this.PerformLayout (this, "LayoutStyle");
                                        this.OnLayoutStyleChanged (EventArgs.Empty);
                                }
                        }
@@ -465,7 +473,7 @@ namespace System.Windows.Forms
                                if (this.renderer != value) {
                                        this.renderer = value; 
                                        this.render_mode = ToolStripRenderMode.Custom;
-                                       this.PerformLayout ();
+                                       this.PerformLayout (this, "Renderer");
                                        this.OnRendererChanged (EventArgs.Empty);
                                }
                        }
@@ -504,7 +512,10 @@ namespace System.Windows.Forms
                [DispId(-516)]
                public new bool TabStop {
                        get { return base.TabStop; }
-                       set { base.TabStop = value; }
+                       set { 
+                               base.TabStop = value;
+                               SetStyle (ControlStyles.Selectable, value);
+                       }
                }
 
                [DefaultValue (ToolStripTextDirection.Horizontal)]
@@ -701,7 +712,7 @@ namespace System.Windows.Forms
                {
                        switch (layoutStyle) {
                                case ToolStripLayoutStyle.Flow:
-                                       return new FlowLayoutSettings ();
+                                       return new FlowLayoutSettings (this);
                                case ToolStripLayoutStyle.Table:
                                        //return new TableLayoutSettings ();
                                case ToolStripLayoutStyle.StackWithOverflow:
@@ -715,12 +726,27 @@ namespace System.Windows.Forms
                protected override void Dispose (bool disposing)
                {
                        if (!IsDisposed) {
-                               ToolStripManager.RemoveToolStrip (this);
+
+                               if(disposing) {
+                                       // Event Handler must be stopped before disposing Items.
+                                       Events.Dispose();
+
+                                       CloseToolTip (null);
+                                       // ToolStripItem.Dispose modifes the collection,
+                                       // so we iterate it in reverse order
+                                       for (int i = Items.Count - 1; i >= 0; i--)
+                                               Items [i].Dispose ();
+
+                                       if (this.overflow_button != null && this.overflow_button.drop_down != null)
+                                               this.overflow_button.drop_down.Dispose ();
+
+                                       ToolStripManager.RemoveToolStrip (this);
+                               }
                                base.Dispose (disposing);
                        }
                }
 
-               [MonoTODO ("Not called")]
+               [MonoTODO ("Stub, never called")]
                protected virtual void OnBeginDrag (EventArgs e)
                {
                        EventHandler eh = (EventHandler)(Events[BeginDragEvent]);
@@ -733,7 +759,7 @@ namespace System.Windows.Forms
                        base.OnDockChanged (e);
                }
 
-               [MonoTODO ("Not called")]
+               [MonoTODO ("Stub, never called")]
                protected virtual void OnEndDrag (EventArgs e)
                {
                        EventHandler eh = (EventHandler)(Events[EndDragEvent]);
@@ -858,22 +884,17 @@ namespace System.Windows.Forms
                                if (focused != null && focused != mouse_currently_over)
                                        this.FocusInternal (true);
 
-                               if (this is MenuStrip && !(mouse_currently_over as ToolStripMenuItem).HasDropDownItems) {
-                                       if (!menu_selected)
-                                               (this as MenuStrip).FireMenuActivate ();
-                                       
-                                       return;
-                               }
-                                       
-                               mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseDown);
-                               
                                if (this is MenuStrip && !menu_selected) {
                                        (this as MenuStrip).FireMenuActivate ();
                                        menu_selected = true;                           
                                }
+                                       
+                               mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseDown);
+                               
+                               if (this is MenuStrip && mouse_currently_over is ToolStripMenuItem && !(mouse_currently_over as ToolStripMenuItem).HasDropDownItems)
+                                       return;
                        } else {
-                               if (this is MenuStrip)
-                                       this.HideMenus (true, ToolStripDropDownCloseReason.AppClicked);
+                               this.Dismiss (ToolStripDropDownCloseReason.AppClicked);
                        }
                        
                        if (this is MenuStrip)
@@ -940,12 +961,13 @@ namespace System.Windows.Forms
                protected override void OnMouseUp (MouseEventArgs mea)
                {
                        // If we're currently over an item (set in MouseMove)
-                       if (mouse_currently_over != null) {
+                       if (mouse_currently_over != null && !(mouse_currently_over is ToolStripControlHost) && mouse_currently_over.Enabled) {
                                // Fire our ItemClicked event
                                OnItemClicked (new ToolStripItemClickedEventArgs (mouse_currently_over));
                                        
                                // Fire the item's MouseUp event
-                               mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseUp);
+                               if (mouse_currently_over != null)
+                                       mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseUp);
 
                                // The event handler may have blocked until the mouse moved off of the ToolStripItem
                                if (mouse_currently_over == null)
@@ -963,7 +985,9 @@ namespace System.Windows.Forms
                        this.OnPaintGrip (e);
 
                        // Make each item draw itself
-                       foreach (ToolStripItem tsi in this.displayed_items) {
+                       for (int i = 0; i < displayed_items.Count; i++) {
+                               ToolStripItem tsi = displayed_items[i];
+                               
                                if (tsi.Visible) {
                                        e.Graphics.TranslateTransform (tsi.Bounds.Left, tsi.Bounds.Top);
                                        tsi.FireEvent (e, ToolStripItemEventType.Paint);
@@ -987,14 +1011,14 @@ namespace System.Windows.Forms
                }
 
                [EditorBrowsable (EditorBrowsableState.Advanced)]
-               protected override void OnPaintBackground (PaintEventArgs pevent)
+               protected override void OnPaintBackground (PaintEventArgs e)
                {
-                       base.OnPaintBackground (pevent);
+                       base.OnPaintBackground (e);
 
                        Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size);
-                       ToolStripRenderEventArgs e = new ToolStripRenderEventArgs (pevent.Graphics, this, affected_bounds, SystemColors.Control);
+                       ToolStripRenderEventArgs tsrea = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, SystemColors.Control);
                        
-                       this.Renderer.DrawToolStripBackground (e);
+                       this.Renderer.DrawToolStripBackground (tsrea);
                }
 
                protected internal virtual void OnPaintGrip (PaintEventArgs e)
@@ -1046,12 +1070,15 @@ namespace System.Windows.Forms
 
                protected override void OnVisibleChanged (EventArgs e)
                {
+                       if (!Visible)
+                               CloseToolTip (null);
+
                        base.OnVisibleChanged (e);
                }
 
-               protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
+               protected override bool ProcessCmdKey (ref Message m, Keys keyData)
                {
-                       return base.ProcessCmdKey (ref msg, keyData);
+                       return base.ProcessCmdKey (ref m, keyData);
                }
 
                protected override bool ProcessDialogKey (Keys keyData)
@@ -1121,24 +1148,27 @@ namespace System.Windows.Forms
                        string code = Char.ToUpper (charCode).ToString ();
                        
                        // If any item's text starts with our letter, it gets the message
-                       if (this is MenuStrip)
+                       if ((Control.ModifierKeys & Keys.Alt) != 0 || this is ToolStripDropDownMenu)
                                foreach (ToolStripItem tsi in this.Items)
-                                       if (tsi.Enabled && tsi.Visible && !string.IsNullOrEmpty (tsi.Text) && tsi.Text.ToUpper ().StartsWith (code))
+                                       if (tsi.Enabled && tsi.Visible && !string.IsNullOrEmpty (tsi.Text) && tsi.Text.ToUpper ().StartsWith (code) && !(tsi is ToolStripControlHost))
                                                return tsi.ProcessMnemonic (charCode);
 
                        return base.ProcessMnemonic (charCode);
                }
-               
-               [MonoTODO ()]
+
+               [MonoTODO ("Stub, does nothing")]
                [EditorBrowsable (EditorBrowsableState.Advanced)]
                protected virtual void RestoreFocus ()
                {
                }
 
-               [MonoTODO ()]
                protected override void Select (bool directed, bool forward)
                {
-                       base.Select (directed, forward);
+                       foreach (ToolStripItem tsi in this.DisplayedItems)
+                               if (tsi.CanSelect) {
+                                       tsi.Select ();
+                                       break;
+                               }
                }
                
                protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
@@ -1148,7 +1178,7 @@ namespace System.Windows.Forms
 
                protected virtual void SetDisplayedItems ()
                {
-                       this.displayed_items.Clear ();
+                       this.displayed_items.ClearInternal ();
                        
                        foreach (ToolStripItem tsi in this.items)
                                if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) {
@@ -1186,9 +1216,9 @@ namespace System.Windows.Forms
                        item.Parent = parent;
                }
 
-               protected override void SetVisibleCore (bool value)
+               protected override void SetVisibleCore (bool visible)
                {
-                       base.SetVisibleCore (value);
+                       base.SetVisibleCore (visible);
                }
 
                protected override void WndProc (ref Message m)
@@ -1215,7 +1245,7 @@ namespace System.Windows.Forms
                        remove { base.AutoSizeChanged -= value; }
                }
 
-               [MonoTODO ()]
+               [MonoTODO ("Event never raised")]
                public event EventHandler BeginDrag {
                        add { Events.AddHandler (BeginDragEvent, value); }
                        remove { Events.RemoveHandler (BeginDragEvent, value); }
@@ -1247,7 +1277,7 @@ namespace System.Windows.Forms
                        remove { base.CursorChanged -= value; }
                }
 
-               [MonoTODO ()]
+               [MonoTODO ("Event never raised")]
                public event EventHandler EndDrag {
                        add { Events.AddHandler (EndDragEvent, value); }
                        remove { Events.RemoveHandler (EndDragEvent, value); }
@@ -1333,8 +1363,8 @@ namespace System.Windows.Forms
                                        tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
 
                        ToolStripItem current = GetCurrentlySelectedItem ();
-                       
-                       if (!(current is ToolStripControlHost))
+
+                       if (current != null && !(current is ToolStripControlHost))
                                this.FocusInternal (true);
 
                        if (nextItem is ToolStripControlHost)
@@ -1392,19 +1422,54 @@ namespace System.Windows.Forms
                
                internal virtual Size GetToolStripPreferredSize (Size proposedSize)
                {
-                       Size new_size = new Size (0, this.Height);
+                       Size new_size = Size.Empty;
+
+                       // TODO: This is total duct tape.  We really have to call into the correct
+                       // layout engine, do a dry run of the layout, and find out our true
+                       // preferred dimensions.
+                       if (this.LayoutStyle == ToolStripLayoutStyle.Flow) {
+                               Point currentLocation = Point.Empty;
+                               int tallest = 0;
+                               
+                               foreach (ToolStripItem tsi in items)
+                                       if (tsi.Available) {
+                                               Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
+
+                                               if ((DisplayRectangle.Width - currentLocation.X) < (tsi_preferred.Width + tsi.Margin.Horizontal)) {
 
+                                                       currentLocation.Y += tallest;
+                                                       tallest = 0;
+                                                       
+                                                       currentLocation.X = DisplayRectangle.Left;
+                                               }
+
+                                               // Offset the left margin and set the control to our point
+                                               currentLocation.Offset (tsi.Margin.Left, 0);
+                                               tallest = Math.Max (tallest, tsi_preferred.Height + tsi.Margin.Vertical);
+                                               
+                                               // Update our location pointer
+                                               currentLocation.X += tsi_preferred.Width + tsi.Margin.Right;
+                                       }
+
+                               currentLocation.Y += tallest;
+                               return new Size (currentLocation.X + this.Padding.Horizontal, currentLocation.Y + this.Padding.Vertical);
+                       }
+                               
                        if (this.orientation == Orientation.Vertical) {
                                foreach (ToolStripItem tsi in this.items)
                                        if (tsi.Available)  {
                                                Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
                                                new_size.Height += tsi_preferred.Height + tsi.Margin.Top + tsi.Margin.Bottom;
 
-                                               if (new_size.Width < (this.Padding.Horizontal + tsi_preferred.Width))
-                                                       new_size.Width = (this.Padding.Horizontal + tsi_preferred.Width);
+                                               if (new_size.Width < (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal))
+                                                       new_size.Width = (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal);
                                        }
 
                                new_size.Height += (this.GripRectangle.Height + this.GripMargin.Vertical + this.Padding.Vertical + 4);
+                               
+                               if (new_size.Width == 0)
+                                       new_size.Width = ExplicitBounds.Width;
+                                       
                                return new_size;
                        } else {
                                foreach (ToolStripItem tsi in this.items) 
@@ -1412,13 +1477,20 @@ namespace System.Windows.Forms
                                                Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
                                                new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right;
                                                
-                                               if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height))
-                                                       new_size.Height = (this.Padding.Vertical + tsi_preferred.Height);
+                                               if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical))
+                                                       new_size.Height = (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical);
                                        }
-                       }
+                                       
+                               new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4);
+
+                               if (new_size.Height == 0)
+                                       new_size.Height = ExplicitBounds.Height;
 
-                       new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4);
-                       return new_size;
+                               if (this is StatusStrip)
+                                       new_size.Height = Math.Max (new_size.Height, 22);
+                                       
+                               return new_size;
+                       }
                }
                
                internal virtual ToolStrip GetTopLevelToolStrip ()
@@ -1431,17 +1503,6 @@ namespace System.Windows.Forms
                        this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.ItemClicked);
                }
                
-               internal void HideMenus (bool release, ToolStripDropDownCloseReason reason)
-               {
-                       if (this is MenuStrip && release && menu_selected)
-                               (this as MenuStrip).FireMenuDeactivate ();
-                               
-                       if (release)
-                               menu_selected = false;
-                               
-                       NotifySelectedChanged (null);
-               }
-
                internal void NotifySelectedChanged (ToolStripItem tsi)
                {
                        foreach (ToolStripItem tsi2 in this.DisplayedItems)
@@ -1526,6 +1587,9 @@ namespace System.Windows.Forms
                {
                        ToolStripItem next_item = this.GetNextItem (start, forward ? ArrowDirection.Right : ArrowDirection.Left);
                        
+                       if (next_item == null)
+                               return next_item;
+                               
                        this.ChangeSelection (next_item);
 
                        if (next_item is ToolStripControlHost)
@@ -1537,25 +1601,33 @@ namespace System.Windows.Forms
                #region Stuff for ToolTips
                private void MouseEnteredItem (ToolStripItem item)
                {
-                       if (this.show_item_tool_tips) {
+                       if (this.show_item_tool_tips && !(item is ToolStripTextBox)) {
+                               ToolTipTimer.Interval = InitialToolTipDelay;
+                               tooltip_state = ToolTip.TipState.Initial;
                                tooltip_currently_showing = item;
                                ToolTipTimer.Start ();
                        }
                }
-               
-               private void MouseLeftItem (ToolStripItem item)
+       
+               private void CloseToolTip (ToolStripItem item)
                {
                        ToolTipTimer.Stop ();
                        ToolTipWindow.Hide (this);
                        tooltip_currently_showing = null;
+                       tooltip_state = ToolTip.TipState.Down;
                }
-               
+
+               private void MouseLeftItem (ToolStripItem item)
+               {
+                       CloseToolTip (item);
+               }
+
                private Timer ToolTipTimer {
                        get {
                                if (tooltip_timer == null) {
                                        tooltip_timer = new Timer ();
                                        tooltip_timer.Enabled = false;
-                                       tooltip_timer.Interval = 500;
+                                       tooltip_timer.Interval = InitialToolTipDelay;
                                        tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick);
                                }
                                
@@ -1572,16 +1644,32 @@ namespace System.Windows.Forms
                        }
                }
                
-               private void ToolTipTimer_Tick (object o, EventArgs args)
+               private void ShowToolTip ()
                {
                        string tooltip = tooltip_currently_showing.GetToolTip ();
                        
-                       if (!string.IsNullOrEmpty (tooltip))
+                       if (!string.IsNullOrEmpty (tooltip)) {
                                ToolTipWindow.Present (this, tooltip);
+                               ToolTipTimer.Interval = ToolTipDelay;
+                               ToolTipTimer.Start ();
+                               tooltip_state = ToolTip.TipState.Show;
+                       }
 
                        tooltip_currently_showing.FireEvent (EventArgs.Empty, ToolStripItemEventType.MouseHover);
+               }
 
+               private void ToolTipTimer_Tick (object o, EventArgs args)
+               {
                        ToolTipTimer.Stop ();
+
+                       switch (tooltip_state) {
+                               case ToolTip.TipState.Initial:
+                                       ShowToolTip ();
+                                       break;
+                               case ToolTip.TipState.Show:
+                                       CloseToolTip (null);
+                                       break;
+                       }
                }
                #endregion
 
@@ -1695,4 +1783,3 @@ namespace System.Windows.Forms
                #endregion
        }
 }
-#endif