2009-03-26 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ToolStrip.cs
1 //
2 // ToolStrip.cs
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Copyright (c) 2006 Jonathan Pobst
24 //
25 // Authors:
26 //      Jonathan Pobst (monkey@jpobst.com)
27 //
28
29 #if NET_2_0
30 using System;
31 using System.Runtime.InteropServices;
32 using System.ComponentModel;
33 using System.Drawing;
34 using System.Windows.Forms.Layout;
35 using System.Collections.Generic;
36 using System.ComponentModel.Design.Serialization;
37
38 namespace System.Windows.Forms
39 {
40         [ComVisible (true)]
41         [ClassInterface (ClassInterfaceType.AutoDispatch)]
42         [DefaultEvent ("ItemClicked")]
43         [DefaultProperty ("Items")]
44         [Designer ("System.Windows.Forms.Design.ToolStripDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45         [DesignerSerializer ("System.Windows.Forms.Design.ToolStripCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
46         public class ToolStrip : ScrollableControl, IComponent, IDisposable, IToolStripData
47         {
48                 #region Private Variables
49                 private bool allow_item_reorder;
50                 private bool allow_merge;
51                 private Color back_color;
52                 private bool can_overflow;
53                 private ToolStrip currently_merged_with;
54                 private ToolStripDropDownDirection default_drop_down_direction;
55                 internal ToolStripItemCollection displayed_items;
56                 private Color fore_color;
57                 private Padding grip_margin;
58                 private ToolStripGripStyle grip_style;
59                 private List<ToolStripItem> hidden_merged_items;
60                 private ImageList image_list;
61                 private Size image_scaling_size;
62                 private bool is_currently_merged;
63                 private ToolStripItemCollection items;
64                 private bool keyboard_active;
65                 private LayoutEngine layout_engine;
66                 private LayoutSettings layout_settings;
67                 private ToolStripLayoutStyle layout_style;
68                 private Orientation orientation;
69                 private ToolStripOverflowButton overflow_button;
70                 private List<ToolStripItem> pre_merge_items;
71                 private ToolStripRenderer renderer;
72                 private ToolStripRenderMode render_mode;
73                 private ToolStripTextDirection text_direction;
74                 private Timer tooltip_timer;
75                 private ToolTip tooltip_window;
76                 private bool show_item_tool_tips;
77                 private bool stretch;
78
79                 private ToolStripItem mouse_currently_over;
80                 internal bool menu_selected;
81                 private ToolStripItem tooltip_currently_showing;
82                 #endregion
83
84                 #region Public Constructors
85                 public ToolStrip () : this (null)
86                 {
87                 }
88
89                 public ToolStrip (params ToolStripItem[] items) : base ()
90                 {
91                         SetStyle (ControlStyles.AllPaintingInWmPaint, true);
92                         SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
93                         SetStyle (ControlStyles.Selectable, false);
94                         SetStyle (ControlStyles.SupportsTransparentBackColor, true);
95
96                         this.SuspendLayout ();
97                         
98                         this.items = new ToolStripItemCollection (this, items, true);
99                         this.allow_merge = true;
100                         base.AutoSize = true;
101                         this.SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
102                         this.back_color = Control.DefaultBackColor;
103                         this.can_overflow = true;
104                         base.CausesValidation = false;
105                         this.default_drop_down_direction = ToolStripDropDownDirection.BelowRight;
106                         this.displayed_items = new ToolStripItemCollection (this, null, true);
107                         this.Dock = this.DefaultDock;
108                         base.Font = new Font ("Tahoma", 8.25f);
109                         this.fore_color = Control.DefaultForeColor;
110                         this.grip_margin = this.DefaultGripMargin;
111                         this.grip_style = ToolStripGripStyle.Visible;
112                         this.image_scaling_size = new Size (16, 16);
113                         this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
114                         this.orientation = Orientation.Horizontal;
115                         if (!(this is ToolStripDropDown))
116                                 this.overflow_button = new ToolStripOverflowButton (this);
117                         this.renderer = null;
118                         this.render_mode = ToolStripRenderMode.ManagerRenderMode;
119                         this.show_item_tool_tips = this.DefaultShowItemToolTips;
120                         base.TabStop = false;
121                         this.text_direction = ToolStripTextDirection.Horizontal;
122                         this.ResumeLayout ();
123                         
124                         // Register with the ToolStripManager
125                         ToolStripManager.AddToolStrip (this);
126                 }
127                 #endregion
128
129                 #region Public Properties
130                 [MonoTODO ()]
131                 public override bool AllowDrop {
132                         get { return base.AllowDrop; }
133                         set { base.AllowDrop = value; }
134                 }
135                 
136                 [MonoTODO ()]
137                 [DefaultValue (false)]
138                 public bool AllowItemReorder {
139                         get { return this.allow_item_reorder; }
140                         set { this.allow_item_reorder = value; }
141                 }
142                 
143                 [DefaultValue (true)]
144                 public bool AllowMerge {
145                         get { return this.allow_merge; }
146                         set { this.allow_merge = value; }
147                 }
148                 
149                 public override AnchorStyles Anchor {
150                         get { return base.Anchor; }
151                         set { base.Anchor = value; }
152                 }
153
154                 [Browsable (false)]
155                 [EditorBrowsable (EditorBrowsableState.Never)]
156                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
157                 public override bool AutoScroll {
158                         get { return base.AutoScroll; }
159                         set { base.AutoScroll = value; }
160                 }
161
162                 [Browsable (false)]
163                 [EditorBrowsable (EditorBrowsableState.Never)]
164                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
165                 public new Size AutoScrollMargin {
166                         get { return base.AutoScrollMargin; }
167                         set { base.AutoScrollMargin = value; }
168                 }
169
170                 [Browsable (false)]
171                 [EditorBrowsable (EditorBrowsableState.Never)]
172                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
173                 public new Size AutoScrollMinSize {
174                         get { return base.AutoScrollMinSize; }
175                         set { base.AutoScrollMinSize = value; }
176                 }
177
178                 [Browsable (false)]
179                 [EditorBrowsable (EditorBrowsableState.Never)]
180                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
181                 public new Point AutoScrollPosition {
182                         get { return base.AutoScrollPosition; }
183                         set { base.AutoScrollPosition = value; }
184                 }
185
186                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
187                 [Browsable (true)]
188                 [EditorBrowsable (EditorBrowsableState.Always)]
189                 [DefaultValue (true)]
190                 public override bool AutoSize {
191                         get { return base.AutoSize; }
192                         set { base.AutoSize = value; }
193                 }
194                 
195                 new public Color BackColor {
196                         get { return this.back_color; }
197                         set { this.back_color = value; }
198                 }
199
200                 public override BindingContext BindingContext {
201                         get { return base.BindingContext; }
202                         set { base.BindingContext = value; }
203                 }
204                 
205                 [DefaultValue (true)]
206                 public bool CanOverflow {
207                         get { return this.can_overflow; }
208                         set { this.can_overflow = value; }
209                 }
210                 
211                 [Browsable (false)]
212                 [DefaultValue (false)]
213                 public new bool CausesValidation {
214                         get { return base.CausesValidation; }
215                         set { base.CausesValidation = value; }
216                 }
217                 
218                 [EditorBrowsable (EditorBrowsableState.Never)]
219                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
220                 public new ControlCollection Controls {
221                         get { return base.Controls; }
222                 }
223
224                 [Browsable (false)]
225                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
226                 public override Cursor Cursor {
227                         get { return base.Cursor; }
228                         set { base.Cursor = value; }
229                 }
230                 
231                 [Browsable (false)]
232                 public virtual ToolStripDropDownDirection DefaultDropDownDirection {
233                         get { return this.default_drop_down_direction; }
234                         set { 
235                                 if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value))
236                                         throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value));
237                                         
238                                 this.default_drop_down_direction = value;
239                         }
240                 }
241
242                 public override Rectangle DisplayRectangle {
243                         get {
244                                 if (this.orientation == Orientation.Horizontal)
245                                         if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
246                                                 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
247                                         else
248                                                 return new Rectangle (this.GripRectangle.Right + this.GripMargin.Right, this.Padding.Top, this.Width - this.Padding.Horizontal - this.GripRectangle.Right - this.GripMargin.Right, this.Height - this.Padding.Vertical);
249                                 else
250                                         if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
251                                                 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
252                                         else
253                                                 return new Rectangle (this.Padding.Left, this.GripRectangle.Bottom + this.GripMargin.Bottom + this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical - this.GripRectangle.Bottom - this.GripMargin.Bottom);
254                         }
255                 }
256
257                 [DefaultValue (DockStyle.Top)]
258                 public override DockStyle Dock {
259                         get { return base.Dock; }
260                         set {
261                                 if (base.Dock != value) {
262                                         base.Dock = value;
263                                         
264                                         switch (value) {
265                                                 case DockStyle.Top:
266                                                 case DockStyle.Bottom:
267                                                 case DockStyle.None:
268                                                         this.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
269                                                         break;
270                                                 case DockStyle.Left:
271                                                 case DockStyle.Right:
272                                                         this.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow;
273                                                         break;
274                                         }
275                                 }
276                         }
277                 }
278
279                 public override Font Font {
280                         get { return base.Font; }
281                         set { 
282                                 if (base.Font != value) {
283                                         base.Font = value;
284                                         
285                                         foreach (ToolStripItem tsi in this.Items)
286                                                 tsi.OnOwnerFontChanged (EventArgs.Empty);
287                                 }
288                          }
289                 }
290                 
291                 [Browsable (false)]
292                 public new Color ForeColor {
293                         get { return this.fore_color; }
294                         set { 
295                                 if (this.fore_color != value) {
296                                         this.fore_color = value; 
297                                         this.OnForeColorChanged (EventArgs.Empty); 
298                                 }
299                         }
300                 }
301
302                 [Browsable (false)]
303                 public ToolStripGripDisplayStyle GripDisplayStyle {
304                         get { return this.orientation == Orientation.Vertical ? ToolStripGripDisplayStyle.Horizontal : ToolStripGripDisplayStyle.Vertical; }
305                 }
306
307                 public Padding GripMargin {
308                         get { return this.grip_margin; }
309                         set { 
310                                 if (this.grip_margin != value) {
311                                         this.grip_margin = value; 
312                                         this.PerformLayout (); 
313                                 }
314                         }
315                 }
316
317                 [Browsable (false)]
318                 public Rectangle GripRectangle {
319                         get {
320                                 if (this.grip_style == ToolStripGripStyle.Hidden)
321                                         return Rectangle.Empty;
322
323                                 if (this.orientation == Orientation.Horizontal)
324                                         return new Rectangle (this.grip_margin.Left + this.Padding.Left, this.Padding.Top, 3, this.Height);
325                                 else
326                                         return new Rectangle (this.Padding.Left, this.grip_margin.Top + this.Padding.Top, this.Width, 3);
327                         }
328                 }
329
330                 [DefaultValue (ToolStripGripStyle.Visible)]
331                 public ToolStripGripStyle GripStyle {
332                         get { return this.grip_style; }
333                         set {
334                                 if (this.grip_style != value) {
335                                         if (!Enum.IsDefined (typeof (ToolStripGripStyle), value))
336                                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripGripStyle", value));
337                                         this.grip_style = value;
338                                         this.PerformLayout (this, "GripStyle");
339                                 }
340                         }
341                 }
342
343                 [Browsable (false)]
344                 [EditorBrowsable (EditorBrowsableState.Never)]
345                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
346                 public new bool HasChildren {
347                         get { return base.HasChildren; }
348                 }
349
350                 [Browsable (false)]
351                 [EditorBrowsable (EditorBrowsableState.Never)]
352                 public new HScrollProperties HorizontalScroll {
353                         get { return base.HorizontalScroll; }
354                 }
355                 
356                 [Browsable (false)]
357                 [DefaultValue (null)]
358                 public ImageList ImageList {
359                         get { return this.image_list; }
360                         set { this.image_list = value; }
361                 }
362
363                 [DefaultValue ("{Width=16, Height=16}")]
364                 public Size ImageScalingSize {
365                         get { return this.image_scaling_size; }
366                         set { this.image_scaling_size = value; }
367                 }
368
369                 [MonoTODO ("Always returns false, dragging not implemented yet.")]
370                 [Browsable (false)]
371                 [EditorBrowsable (EditorBrowsableState.Advanced)]
372                 public bool IsCurrentlyDragging {
373                         get { return false; }
374                 }
375                 
376                 [Browsable (false)]
377                 public bool IsDropDown {
378                         get {
379                                 if (this is ToolStripDropDown)
380                                         return true;
381
382                                 return false;
383                         }
384                 }
385
386                 [MergableProperty (false)]
387                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
388                 public virtual ToolStripItemCollection Items {
389                         get { return this.items; }
390                 }
391
392                 public override LayoutEngine LayoutEngine {
393                         get { 
394                                  if (layout_engine == null)
395                                         this.layout_engine = new ToolStripSplitStackLayout ();
396                                         
397                                  return this.layout_engine;
398                         }
399                 }
400
401                 [Browsable (false)]
402                 [DefaultValue (null)]
403                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
404                 public LayoutSettings LayoutSettings {
405                         get { return this.layout_settings; }
406                         set { 
407                                 if (this.layout_settings != value) {
408                                         this.layout_settings = value;
409                                         PerformLayout (this, "LayoutSettings");
410                                 }
411                         }
412                 }
413                 
414                 [AmbientValue (ToolStripLayoutStyle.StackWithOverflow)]
415                 public ToolStripLayoutStyle LayoutStyle {
416                         get { return layout_style; }
417                         set {
418                                 if (this.layout_style != value) {
419                                         if (!Enum.IsDefined (typeof (ToolStripLayoutStyle), value))
420                                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripLayoutStyle", value));
421
422                                         this.layout_style = value;
423
424                                         if (this.layout_style == ToolStripLayoutStyle.Flow)
425                                                 this.layout_engine = new FlowLayout ();
426                                         else
427                                                 this.layout_engine = new ToolStripSplitStackLayout ();
428
429                                         if (this.layout_style == ToolStripLayoutStyle.StackWithOverflow) {
430                                                 if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right)
431                                                         this.layout_style = ToolStripLayoutStyle.VerticalStackWithOverflow;
432                                                 else
433                                                         this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
434                                         }
435
436                                         if (this.layout_style == ToolStripLayoutStyle.HorizontalStackWithOverflow)
437                                                 this.orientation = Orientation.Horizontal;
438                                         else if (this.layout_style == ToolStripLayoutStyle.VerticalStackWithOverflow)
439                                                 this.orientation = Orientation.Vertical;
440                                                 
441                                         this.layout_settings = this.CreateLayoutSettings (value);
442                                         
443                                         this.PerformLayout (this, "LayoutStyle");
444                                         this.OnLayoutStyleChanged (EventArgs.Empty);
445                                 }
446                         }
447                 }
448
449                 [Browsable (false)]
450                 public Orientation Orientation {
451                         get { return this.orientation; }
452                 }
453
454                 [Browsable (false)]
455                 [EditorBrowsable (EditorBrowsableState.Advanced)]
456                 public ToolStripOverflowButton OverflowButton {
457                         get { return this.overflow_button; }
458                 }
459                 
460                 [Browsable (false)]
461                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
462                 public ToolStripRenderer Renderer {
463                         get { 
464                                 if (this.render_mode == ToolStripRenderMode.ManagerRenderMode)
465                                         return ToolStripManager.Renderer;
466                                         
467                                 return this.renderer; 
468                         }
469                         set { 
470                                 if (this.renderer != value) {
471                                         this.renderer = value; 
472                                         this.render_mode = ToolStripRenderMode.Custom;
473                                         this.PerformLayout (this, "Renderer");
474                                         this.OnRendererChanged (EventArgs.Empty);
475                                 }
476                         }
477                 }
478
479                 public ToolStripRenderMode RenderMode {
480                         get { return this.render_mode; }
481                         set {
482                                 if (!Enum.IsDefined (typeof (ToolStripRenderMode), value))
483                                         throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripRenderMode", value));
484
485                                 if (value == ToolStripRenderMode.Custom && this.renderer == null)
486                                         throw new NotSupportedException ("Must set Renderer property before setting RenderMode to Custom");
487                                 else if (value == ToolStripRenderMode.Professional)
488                                         this.Renderer = new ToolStripProfessionalRenderer ();
489                                 else if (value == ToolStripRenderMode.System)
490                                         this.Renderer = new ToolStripSystemRenderer ();
491                                         
492                                 this.render_mode = value;
493                         }
494                 }
495
496                 [DefaultValue (true)]
497                 public bool ShowItemToolTips {
498                         get { return this.show_item_tool_tips; }
499                         set { this.show_item_tool_tips = value; }
500                 }
501                 
502                 [DefaultValue (false)]
503                 public bool Stretch {
504                         get { return this.stretch; }
505                         set { this.stretch = value; }
506                 }
507                 
508                 [DefaultValue (false)]
509                 [DispId(-516)]
510                 public new bool TabStop {
511                         get { return base.TabStop; }
512                         set { 
513                                 base.TabStop = value;
514                                 SetStyle (ControlStyles.Selectable, value);
515                         }
516                 }
517
518                 [DefaultValue (ToolStripTextDirection.Horizontal)]
519                 public virtual ToolStripTextDirection TextDirection {
520                         get { return this.text_direction; }
521                         set {
522                                 if (!Enum.IsDefined (typeof (ToolStripTextDirection), value))
523                                         throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripTextDirection", value));
524
525                                 if (this.text_direction != value) {
526                                         this.text_direction = value;
527                                         
528                                         this.PerformLayout (this, "TextDirection");
529                                                 
530                                         this.Invalidate ();
531                                 }
532                         }
533                 }
534
535                 [Browsable (false)]
536                 [EditorBrowsable (EditorBrowsableState.Never)]
537                 public new VScrollProperties VerticalScroll {
538                         get { return base.VerticalScroll; }
539                 }
540                 #endregion
541
542                 #region Protected Properties
543                 protected virtual DockStyle DefaultDock { get { return DockStyle.Top; } }
544                 protected virtual Padding DefaultGripMargin { get { return new Padding (2); } }
545                 protected override Padding DefaultMargin { get { return Padding.Empty; } }
546                 protected override Padding DefaultPadding { get { return new Padding (0, 0, 1, 0); } }
547                 protected virtual bool DefaultShowItemToolTips { get { return true; } }
548                 protected override Size DefaultSize { get { return new Size (100, 25); } }
549                 protected internal virtual ToolStripItemCollection DisplayedItems { get { return this.displayed_items; } }
550                 protected internal virtual Size MaxItemSize {
551                         get { return new Size (Width - (GripStyle == ToolStripGripStyle.Hidden ? 1 : 8), Height); }
552                 }
553                 #endregion
554
555                 #region Public Methods
556                 [EditorBrowsable (EditorBrowsableState.Never)]
557                 public new Control GetChildAtPoint (Point point)
558                 {
559                         return base.GetChildAtPoint (point);
560                 }
561
562                 [EditorBrowsable (EditorBrowsableState.Never)]
563                 public new Control GetChildAtPoint (Point pt, GetChildAtPointSkip skipValue)
564                 {
565                         return base.GetChildAtPoint (pt, skipValue);
566                 }
567                 
568                 public ToolStripItem GetItemAt (Point point)
569                 {
570                         foreach (ToolStripItem tsi in this.displayed_items)
571                                 if (tsi.Visible && tsi.Bounds.Contains (point))
572                                         return tsi;
573
574                         return null;
575                 }
576
577                 public ToolStripItem GetItemAt (int x, int y)
578                 {
579                         return GetItemAt (new Point (x, y));
580                 }
581
582                 public virtual ToolStripItem GetNextItem (ToolStripItem start, ArrowDirection direction)
583                 {
584                         if (!Enum.IsDefined (typeof (ArrowDirection), direction))
585                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ArrowDirection", direction));
586
587                         ToolStripItem current_best = null;
588                         int current_best_point;
589                         
590                         switch (direction) {
591                                 case ArrowDirection.Right:
592                                         current_best_point = int.MaxValue;
593
594                                         if (start != null)
595                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
596                                                         if (loop_tsi.Left >= start.Right && loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
597                                                                 current_best = loop_tsi;
598                                                                 current_best_point = loop_tsi.Left;
599                                                         }
600                                                         
601                                         if (current_best == null)
602                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
603                                                         if (loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
604                                                                 current_best = loop_tsi;
605                                                                 current_best_point = loop_tsi.Left;
606                                                         }
607                                                         
608                                         break;
609                                 case ArrowDirection.Up:
610                                         current_best_point = int.MinValue;
611
612                                         if (start != null)
613                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
614                                                         if (loop_tsi.Bottom <= start.Top && loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
615                                                                 current_best = loop_tsi;
616                                                                 current_best_point = loop_tsi.Top;
617                                                         }
618
619                                         if (current_best == null)
620                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
621                                                         if (loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
622                                                                 current_best = loop_tsi;
623                                                                 current_best_point = loop_tsi.Top;
624                                                         }
625
626                                         break;
627                                 case ArrowDirection.Left:
628                                         current_best_point = int.MinValue;
629
630                                         if (start != null)
631                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
632                                                         if (loop_tsi.Right <= start.Left && loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
633                                                                 current_best = loop_tsi;
634                                                                 current_best_point = loop_tsi.Left;
635                                                         }
636
637                                         if (current_best == null)
638                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
639                                                         if (loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
640                                                                 current_best = loop_tsi;
641                                                                 current_best_point = loop_tsi.Left;
642                                                         }
643
644                                         break;
645                                 case ArrowDirection.Down:
646                                         current_best_point = int.MaxValue;
647
648                                         if (start != null) 
649                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
650                                                         if (loop_tsi.Top >= start.Bottom && loop_tsi.Bottom < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
651                                                                 current_best = loop_tsi;
652                                                                 current_best_point = loop_tsi.Top;
653                                                         }
654
655                                         if (current_best == null)
656                                                 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
657                                                         if (loop_tsi.Top < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
658                                                                 current_best = loop_tsi;
659                                                                 current_best_point = loop_tsi.Top;
660                                                         }
661
662                                         break;
663                         }
664
665                         return current_best;
666                 }
667
668                 [EditorBrowsable (EditorBrowsableState.Never)]
669                 public void ResetMinimumSize ()
670                 {
671                         this.MinimumSize = new Size (-1, -1);
672                 }
673
674                 [EditorBrowsable (EditorBrowsableState.Never)]
675                 public new void SetAutoScrollMargin (int x, int y)
676                 {
677                         base.SetAutoScrollMargin (x, y);
678                 }
679                 
680                 public override string ToString ()
681                 {
682                         return String.Format ("{0}, Name: {1}, Items: {2}", base.ToString(), this.Name, this.items.Count.ToString ());
683                 }
684                 #endregion
685
686                 #region Protected Methods
687                 protected override AccessibleObject CreateAccessibilityInstance ()
688                 {
689                         return new ToolStripAccessibleObject (this);
690                 }
691                 
692                 protected override ControlCollection CreateControlsInstance ()
693                 {
694                         return base.CreateControlsInstance ();
695                 }
696
697                 protected internal virtual ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
698                 {
699                         if (text == "-")
700                                 return new ToolStripSeparator ();
701
702                         if (this is ToolStripDropDown)
703                                 return new ToolStripMenuItem (text, image, onClick);
704                                 
705                         return new ToolStripButton (text, image, onClick);
706                 }
707
708                 protected virtual LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle layoutStyle)
709                 {
710                         switch (layoutStyle) {
711                                 case ToolStripLayoutStyle.Flow:
712                                         return new FlowLayoutSettings (this);
713                                 case ToolStripLayoutStyle.Table:
714                                         //return new TableLayoutSettings ();
715                                 case ToolStripLayoutStyle.StackWithOverflow:
716                                 case ToolStripLayoutStyle.HorizontalStackWithOverflow:
717                                 case ToolStripLayoutStyle.VerticalStackWithOverflow:
718                                 default:
719                                         return null;
720                         }
721                 }
722                 
723                 protected override void Dispose (bool disposing)
724                 {
725                         if (!IsDisposed) {
726                                 // ToolStripItem.Dispose modifes the collection,
727                                 // so we iterate it in reverse order
728                                 for (int i = Items.Count - 1; i >= 0; i--)
729                                         Items [i].Dispose ();
730                                         
731                                 if (this.overflow_button != null && this.overflow_button.drop_down != null)
732                                         this.overflow_button.drop_down.Dispose ();
733
734                                 ToolStripManager.RemoveToolStrip (this);
735                                 base.Dispose (disposing);
736                         }
737                 }
738
739                 [MonoTODO ("Not called")]
740                 protected virtual void OnBeginDrag (EventArgs e)
741                 {
742                         EventHandler eh = (EventHandler)(Events[BeginDragEvent]);
743                         if (eh != null)
744                                 eh (this, e);
745                 }
746                 
747                 protected override void OnDockChanged (EventArgs e)
748                 {
749                         base.OnDockChanged (e);
750                 }
751
752                 [MonoTODO ("Not called")]
753                 protected virtual void OnEndDrag (EventArgs e)
754                 {
755                         EventHandler eh = (EventHandler)(Events[EndDragEvent]);
756                         if (eh != null)
757                                 eh (this, e);
758                 }
759
760                 protected override bool IsInputChar (char charCode)
761                 {
762                         return base.IsInputChar (charCode);
763                 }
764
765                 protected override bool IsInputKey (Keys keyData)
766                 {
767                         return base.IsInputKey (keyData);
768                 }
769                 
770                 protected override void OnEnabledChanged (EventArgs e)
771                 {
772                         base.OnEnabledChanged (e);
773                         
774                         foreach (ToolStripItem tsi in this.Items)
775                                 tsi.OnParentEnabledChanged (EventArgs.Empty);
776                 }
777
778                 protected override void OnFontChanged (EventArgs e)
779                 {
780                         base.OnFontChanged (e);
781                 }
782
783                 protected override void OnHandleCreated (EventArgs e)
784                 {
785                         base.OnHandleCreated (e);
786                 }
787
788                 protected override void OnHandleDestroyed (EventArgs e)
789                 {
790                         base.OnHandleDestroyed (e);
791                 }
792
793                 protected override void OnInvalidated (InvalidateEventArgs e)
794                 {
795                         base.OnInvalidated (e);
796                 }
797
798                 protected internal virtual void OnItemAdded (ToolStripItemEventArgs e)
799                 {
800                         if (e.Item.InternalVisible)
801                                 e.Item.Available = true;
802                                 
803                         e.Item.SetPlacement (ToolStripItemPlacement.Main);
804                         
805                         if (this.Created)
806                                 this.PerformLayout ();
807                         
808                         ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemAddedEvent]);
809                         if (eh != null)
810                                 eh (this, e);
811                 }
812
813                 protected virtual void OnItemClicked (ToolStripItemClickedEventArgs e)
814                 {
815                         if (this.KeyboardActive)
816                                 ToolStripManager.SetActiveToolStrip (null, false);
817                         
818                         ToolStripItemClickedEventHandler eh = (ToolStripItemClickedEventHandler)(Events [ItemClickedEvent]);
819                         if (eh != null)
820                                 eh (this, e);
821                 }
822
823                 protected internal virtual void OnItemRemoved (ToolStripItemEventArgs e)
824                 {
825                         ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemRemovedEvent]);
826                         if (eh != null)
827                                 eh (this, e);
828                 }
829
830                 protected override void OnLayout (LayoutEventArgs e)
831                 {
832                         base.OnLayout (e);
833
834                         this.SetDisplayedItems ();
835                         this.OnLayoutCompleted (EventArgs.Empty);
836                         this.Invalidate ();
837                 }
838
839                 protected virtual void OnLayoutCompleted (EventArgs e)
840                 {
841                         EventHandler eh = (EventHandler)(Events [LayoutCompletedEvent]);
842                         if (eh != null)
843                                 eh (this, e);
844                 }
845
846                 protected virtual void OnLayoutStyleChanged (EventArgs e)
847                 {
848                         EventHandler eh = (EventHandler)(Events[LayoutStyleChangedEvent]);
849                         if (eh != null)
850                                 eh (this, e);
851                 }
852
853                 protected override void OnLeave (EventArgs e)
854                 {
855                         base.OnLeave (e);
856                 }
857
858                 protected override void OnLostFocus (EventArgs e)
859                 {
860                         base.OnLostFocus (e);
861                 }
862
863                 protected override void OnMouseCaptureChanged (EventArgs e)
864                 {
865                         base.OnMouseCaptureChanged (e);
866                 }
867                 
868                 protected override void OnMouseDown (MouseEventArgs mea)
869                 {
870                         if (mouse_currently_over != null)
871                         {
872                                 ToolStripItem focused = GetCurrentlyFocusedItem ();
873
874                                 if (focused != null && focused != mouse_currently_over)
875                                         this.FocusInternal (true);
876
877                                 if (this is MenuStrip && !menu_selected) {
878                                         (this as MenuStrip).FireMenuActivate ();
879                                         menu_selected = true;                           
880                                 }
881                                         
882                                 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseDown);
883                                 
884                                 if (this is MenuStrip && mouse_currently_over is ToolStripMenuItem && !(mouse_currently_over as ToolStripMenuItem).HasDropDownItems)
885                                         return;
886                         } else {
887                                 if (this is MenuStrip)
888                                         this.HideMenus (true, ToolStripDropDownCloseReason.AppClicked);
889                         }
890                         
891                         if (this is MenuStrip)
892                                 this.Capture = false;
893
894                         base.OnMouseDown (mea);
895                 }
896
897                 protected override void OnMouseLeave (EventArgs e)
898                 {
899                         if (mouse_currently_over != null) {
900                                 MouseLeftItem (mouse_currently_over);
901                                 mouse_currently_over.FireEvent (e, ToolStripItemEventType.MouseLeave);
902                                 mouse_currently_over = null;
903                         }
904
905                         base.OnMouseLeave (e);
906                 }
907
908                 protected override void OnMouseMove (MouseEventArgs mea)
909                 {
910                         ToolStripItem tsi;
911                         // Find the item we are now 
912                         if (this.overflow_button != null && this.overflow_button.Visible && this.overflow_button.Bounds.Contains (mea.Location))
913                                 tsi = this.overflow_button;
914                         else
915                                 tsi = this.GetItemAt (mea.X, mea.Y);
916
917                         if (tsi != null) {
918                                 // If we were already hovering on this item, just send a mouse move
919                                 if (tsi == mouse_currently_over) 
920                                         tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
921                                 else {
922                                         // If we were over a different item, fire a mouse leave on it
923                                         if (mouse_currently_over != null) {
924                                                 MouseLeftItem (tsi);
925                                                 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
926                                         }
927                                         
928                                         // Set the new item we are currently over
929                                         mouse_currently_over = tsi;
930                                         
931                                         // Fire mouse enter and mouse move
932                                         tsi.FireEvent (mea, ToolStripItemEventType.MouseEnter);
933                                         MouseEnteredItem (tsi);
934                                         tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
935
936                                         // If we're over something with a drop down, show it
937                                         if (menu_selected && mouse_currently_over.Enabled && mouse_currently_over is ToolStripDropDownItem && (mouse_currently_over as ToolStripDropDownItem).HasDropDownItems)
938                                                 (mouse_currently_over as ToolStripDropDownItem).ShowDropDown ();
939                                 }
940                         } else {
941                                 // We're not over anything now, just fire the mouse leave on what we used to be over
942                                 if (mouse_currently_over != null) {
943                                         MouseLeftItem (tsi);
944                                         mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
945                                         mouse_currently_over = null;
946                                 }
947                         }
948                         
949                         base.OnMouseMove (mea);
950                 }
951
952                 protected override void OnMouseUp (MouseEventArgs mea)
953                 {
954                         // If we're currently over an item (set in MouseMove)
955                         if (mouse_currently_over != null && !(mouse_currently_over is ToolStripControlHost) && mouse_currently_over.Enabled) {
956                                 // Fire our ItemClicked event
957                                 OnItemClicked (new ToolStripItemClickedEventArgs (mouse_currently_over));
958                                         
959                                 // Fire the item's MouseUp event
960                                 if (mouse_currently_over != null)
961                                         mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseUp);
962
963                                 // The event handler may have blocked until the mouse moved off of the ToolStripItem
964                                 if (mouse_currently_over == null)
965                                         return;
966                         }
967
968                         base.OnMouseUp (mea);
969                 }
970
971                 protected override void OnPaint (PaintEventArgs e)
972                 {
973                         base.OnPaint (e);
974
975                         // Draw the grip
976                         this.OnPaintGrip (e);
977
978                         // Make each item draw itself
979                         for (int i = 0; i < displayed_items.Count; i++) {
980                                 ToolStripItem tsi = displayed_items[i];
981                                 
982                                 if (tsi.Visible) {
983                                         e.Graphics.TranslateTransform (tsi.Bounds.Left, tsi.Bounds.Top);
984                                         tsi.FireEvent (e, ToolStripItemEventType.Paint);
985                                         e.Graphics.ResetTransform ();
986                                 }
987                         }
988
989                         // Paint the Overflow button if it's visible
990                         if (this.overflow_button != null && this.overflow_button.Visible) {
991                                 e.Graphics.TranslateTransform (this.overflow_button.Bounds.Left, this.overflow_button.Bounds.Top);
992                                 this.overflow_button.FireEvent (e, ToolStripItemEventType.Paint);
993                                 e.Graphics.ResetTransform ();
994                         }
995
996                         Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size);
997
998                         ToolStripRenderEventArgs pevent = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, Color.Empty);
999                         pevent.InternalConnectedArea = CalculateConnectedArea ();
1000
1001                         this.Renderer.DrawToolStripBorder (pevent);
1002                 }
1003
1004                 [EditorBrowsable (EditorBrowsableState.Advanced)]
1005                 protected override void OnPaintBackground (PaintEventArgs e)
1006                 {
1007                         base.OnPaintBackground (e);
1008
1009                         Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size);
1010                         ToolStripRenderEventArgs tsrea = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, SystemColors.Control);
1011                         
1012                         this.Renderer.DrawToolStripBackground (tsrea);
1013                 }
1014
1015                 protected internal virtual void OnPaintGrip (PaintEventArgs e)
1016                 {
1017                         // Never draw a grip with these two layouts
1018                         if (this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
1019                                 return;
1020                         
1021                         PaintEventHandler eh = (PaintEventHandler)(Events [PaintGripEvent]);
1022                         if (eh != null)
1023                                 eh (this, e);
1024
1025                         if (!(this is MenuStrip)) {
1026                                 if (this.orientation == Orientation.Horizontal)
1027                                         e.Graphics.TranslateTransform (2, 0);
1028                                 else
1029                                         e.Graphics.TranslateTransform (0, 2);
1030                         }
1031
1032                         this.Renderer.DrawGrip (new ToolStripGripRenderEventArgs (e.Graphics, this, this.GripRectangle, this.GripDisplayStyle, this.grip_style));
1033                         e.Graphics.ResetTransform ();
1034                 }
1035
1036                 protected virtual void OnRendererChanged (EventArgs e)
1037                 {
1038                         EventHandler eh = (EventHandler)(Events [RendererChangedEvent]);
1039                         if (eh != null)
1040                                 eh (this, e);
1041                 }
1042
1043                 [EditorBrowsable (EditorBrowsableState.Advanced)]
1044                 protected override void OnRightToLeftChanged (EventArgs e)
1045                 {
1046                         base.OnRightToLeftChanged (e);
1047
1048                         foreach (ToolStripItem tsi in this.Items)
1049                                 tsi.OnParentRightToLeftChanged (e);
1050                 }
1051
1052                 protected override void OnScroll (ScrollEventArgs se)
1053                 {
1054                         base.OnScroll (se);
1055                 }
1056                 
1057                 protected override void OnTabStopChanged (EventArgs e)
1058                 {
1059                         base.OnTabStopChanged (e);
1060                 }
1061
1062                 protected override void OnVisibleChanged (EventArgs e)
1063                 {
1064                         base.OnVisibleChanged (e);
1065                 }
1066
1067                 protected override bool ProcessCmdKey (ref Message m, Keys keyData)
1068                 {
1069                         return base.ProcessCmdKey (ref m, keyData);
1070                 }
1071
1072                 protected override bool ProcessDialogKey (Keys keyData)
1073                 {
1074                         if (!this.KeyboardActive)
1075                                 return false;
1076                                 
1077                         // Give each item a chance to handle the key
1078                         foreach (ToolStripItem tsi in this.Items)
1079                                 if (tsi.ProcessDialogKey (keyData))
1080                                         return true;
1081                         
1082                         // See if I want to handle it
1083                         if (this.ProcessArrowKey (keyData))
1084                                 return true;
1085                         
1086                         ToolStrip ts = null;
1087                         
1088                         switch (keyData) {
1089                                 case Keys.Escape:
1090                                         this.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1091                                         return true;
1092                         
1093                                 case Keys.Control | Keys.Tab:
1094                                         ts = ToolStripManager.GetNextToolStrip (this, true);
1095                                         
1096                                         if (ts != null) {
1097                                                 foreach (ToolStripItem tsi in this.Items)
1098                                                         tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1099
1100                                                 ToolStripManager.SetActiveToolStrip (ts, true);
1101                                                 ts.SelectNextToolStripItem (null, true);
1102                                         }
1103                                         
1104                                         return true;
1105                                 case Keys.Control | Keys.Shift | Keys.Tab:
1106                                         ts = ToolStripManager.GetNextToolStrip (this, false);
1107
1108                                         if (ts != null) {
1109                                                 foreach (ToolStripItem tsi in this.Items)
1110                                                         tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1111
1112                                                 ToolStripManager.SetActiveToolStrip (ts, true);
1113                                                 ts.SelectNextToolStripItem (null, true);
1114                                         }
1115                                         
1116                                         return true;
1117                                 case Keys.Down:
1118                                 case Keys.Up:
1119                                 case Keys.Left:
1120                                 case Keys.Right:
1121                                         if (GetCurrentlySelectedItem () is ToolStripControlHost)
1122                                                 return false;
1123                                         break;
1124                         }
1125
1126                         return base.ProcessDialogKey (keyData);
1127                 }
1128
1129                 protected override bool ProcessMnemonic (char charCode)
1130                 {
1131                         // If any item has an explicit mnemonic, it gets the message
1132                         foreach (ToolStripItem tsi in this.Items)
1133                                 if (tsi.Enabled && tsi.Visible && !string.IsNullOrEmpty (tsi.Text) && Control.IsMnemonic (charCode, tsi.Text))
1134                                         return tsi.ProcessMnemonic (charCode);
1135
1136                         string code = Char.ToUpper (charCode).ToString ();
1137                         
1138                         // If any item's text starts with our letter, it gets the message
1139                         if (this is ToolStripDropDownMenu)
1140                                 foreach (ToolStripItem tsi in this.Items)
1141                                         if (tsi.Enabled && tsi.Visible && !string.IsNullOrEmpty (tsi.Text) && tsi.Text.ToUpper ().StartsWith (code) && !(tsi is ToolStripControlHost))
1142                                                 return tsi.ProcessMnemonic (charCode);
1143
1144                         return base.ProcessMnemonic (charCode);
1145                 }
1146                 
1147                 [MonoTODO ()]
1148                 [EditorBrowsable (EditorBrowsableState.Advanced)]
1149                 protected virtual void RestoreFocus ()
1150                 {
1151                 }
1152
1153                 [MonoTODO ()]
1154                 protected override void Select (bool directed, bool forward)
1155                 {
1156                         foreach (ToolStripItem tsi in this.DisplayedItems)
1157                                 if (tsi.CanSelect) {
1158                                         tsi.Select ();
1159                                         break;
1160                                 }
1161                 }
1162                 
1163                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1164                 {
1165                         base.SetBoundsCore (x, y, width, height, specified);
1166                 }
1167
1168                 protected virtual void SetDisplayedItems ()
1169                 {
1170                         this.displayed_items.Clear ();
1171                         
1172                         foreach (ToolStripItem tsi in this.items)
1173                                 if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) {
1174                                         this.displayed_items.AddNoOwnerOrLayout (tsi);
1175                                         tsi.Parent = this; 
1176                                 }
1177                                 else if (tsi.Placement == ToolStripItemPlacement.Overflow)
1178                                         tsi.Parent = this.OverflowButton.DropDown; 
1179                         
1180                         if (this.OverflowButton != null)
1181                                 this.OverflowButton.DropDown.SetDisplayedItems ();
1182                 }
1183
1184                 protected internal void SetItemLocation (ToolStripItem item, Point location)
1185                 {
1186                         if (item == null)
1187                                 throw new ArgumentNullException ("item");
1188                                 
1189                         if (item.Owner != this)
1190                                 throw new NotSupportedException ("The item is not owned by this ToolStrip");
1191                                 
1192                         item.SetBounds (new Rectangle (location, item.Size));
1193                 }
1194                 
1195                 protected internal static void SetItemParent (ToolStripItem item, ToolStrip parent)
1196                 {
1197                         if (item.Owner != null) {
1198                                 item.Owner.Items.RemoveNoOwnerOrLayout (item);
1199
1200                                 if (item.Owner is ToolStripOverflow)
1201                                         (item.Owner as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
1202                         }
1203                         
1204                         parent.Items.AddNoOwnerOrLayout (item);
1205                         item.Parent = parent;
1206                 }
1207
1208                 protected override void SetVisibleCore (bool visible)
1209                 {
1210                         base.SetVisibleCore (visible);
1211                 }
1212
1213                 protected override void WndProc (ref Message m)
1214                 {
1215                         base.WndProc (ref m);
1216                 }
1217                 #endregion
1218
1219                 #region Public Events
1220                 static object BeginDragEvent = new object ();
1221                 static object EndDragEvent = new object ();
1222                 static object ItemAddedEvent = new object ();
1223                 static object ItemClickedEvent = new object ();
1224                 static object ItemRemovedEvent = new object ();
1225                 static object LayoutCompletedEvent = new object ();
1226                 static object LayoutStyleChangedEvent = new object ();
1227                 static object PaintGripEvent = new object ();
1228                 static object RendererChangedEvent = new object ();
1229
1230                 [Browsable (true)]
1231                 [EditorBrowsable (EditorBrowsableState.Always)]
1232                 public new event EventHandler AutoSizeChanged {
1233                         add { base.AutoSizeChanged += value; }
1234                         remove { base.AutoSizeChanged -= value; }
1235                 }
1236
1237                 [MonoTODO ()]
1238                 public event EventHandler BeginDrag {
1239                         add { Events.AddHandler (BeginDragEvent, value); }
1240                         remove { Events.RemoveHandler (BeginDragEvent, value); }
1241                 }
1242
1243                 [Browsable (false)]
1244                 public new event EventHandler CausesValidationChanged {
1245                         add { base.CausesValidationChanged += value; }
1246                         remove { base.CausesValidationChanged -= value; }
1247                 }
1248
1249                 [Browsable (false)]
1250                 [EditorBrowsable (EditorBrowsableState.Never)]
1251                 public new event ControlEventHandler ControlAdded {
1252                         add { base.ControlAdded += value; }
1253                         remove { base.ControlAdded -= value; }
1254                 }
1255
1256                 [Browsable (false)]
1257                 [EditorBrowsable (EditorBrowsableState.Never)]
1258                 public new event ControlEventHandler ControlRemoved {
1259                         add { base.ControlRemoved += value; }
1260                         remove { base.ControlRemoved -= value; }
1261                 }
1262                 
1263                 [Browsable (false)]
1264                 public new event EventHandler CursorChanged {
1265                         add { base.CursorChanged += value; }
1266                         remove { base.CursorChanged -= value; }
1267                 }
1268
1269                 [MonoTODO ()]
1270                 public event EventHandler EndDrag {
1271                         add { Events.AddHandler (EndDragEvent, value); }
1272                         remove { Events.RemoveHandler (EndDragEvent, value); }
1273                 }
1274
1275                 [Browsable (false)]
1276                 public new event EventHandler ForeColorChanged {
1277                         add { base.ForeColorChanged += value; }
1278                         remove { base.ForeColorChanged -= value; }
1279                 }
1280
1281                 public event ToolStripItemEventHandler ItemAdded {
1282                         add { Events.AddHandler (ItemAddedEvent, value); }
1283                         remove { Events.RemoveHandler (ItemAddedEvent, value); }
1284                 }
1285
1286                 public event ToolStripItemClickedEventHandler ItemClicked {
1287                         add { Events.AddHandler (ItemClickedEvent, value); }
1288                         remove { Events.RemoveHandler (ItemClickedEvent, value); }
1289                 }
1290
1291                 public event ToolStripItemEventHandler ItemRemoved {
1292                         add { Events.AddHandler (ItemRemovedEvent, value); }
1293                         remove { Events.RemoveHandler (ItemRemovedEvent, value); }
1294                 }
1295
1296                 public event EventHandler LayoutCompleted {
1297                         add { Events.AddHandler (LayoutCompletedEvent, value); }
1298                         remove { Events.RemoveHandler (LayoutCompletedEvent, value); }
1299                 }
1300
1301                 public event EventHandler LayoutStyleChanged {
1302                         add { Events.AddHandler (LayoutStyleChangedEvent, value); }
1303                         remove { Events.RemoveHandler (LayoutStyleChangedEvent, value); }
1304                 }
1305
1306                 public event PaintEventHandler PaintGrip {
1307                         add { Events.AddHandler (PaintGripEvent, value); }
1308                         remove { Events.RemoveHandler (PaintGripEvent, value); }
1309                 }
1310
1311                 public event EventHandler RendererChanged {
1312                         add { Events.AddHandler (RendererChangedEvent, value); }
1313                         remove { Events.RemoveHandler (RendererChangedEvent, value); }
1314                 }
1315                 #endregion
1316
1317                 #region Internal Properties
1318                 internal virtual bool KeyboardActive
1319                 {
1320                         get { return this.keyboard_active; }
1321                         set {
1322                                 if (this.keyboard_active != value) {
1323                                         this.keyboard_active = value;
1324                                         
1325                                         if (value)
1326                                                 Application.KeyboardCapture = this;
1327                                         else if (Application.KeyboardCapture == this) {
1328                                                 Application.KeyboardCapture = null;
1329                                                 ToolStripManager.ActivatedByKeyboard = false;
1330                                         }
1331                                         
1332                                         // Redraw for mnemonic underlines
1333                                         this.Invalidate ();
1334                                 }
1335                         }
1336                 }
1337                 #endregion
1338                 
1339                 #region Private Methods
1340                 internal virtual Rectangle CalculateConnectedArea ()
1341                 {
1342                         return Rectangle.Empty;
1343                 }
1344                 
1345                 internal void ChangeSelection (ToolStripItem nextItem)
1346                 {
1347                         if (Application.KeyboardCapture != this)
1348                                 ToolStripManager.SetActiveToolStrip (this, ToolStripManager.ActivatedByKeyboard);
1349                                 
1350                         foreach (ToolStripItem tsi in this.Items)
1351                                 if (tsi != nextItem)
1352                                         tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1353
1354                         ToolStripItem current = GetCurrentlySelectedItem ();
1355
1356                         if (current != null && !(current is ToolStripControlHost))
1357                                 this.FocusInternal (true);
1358
1359                         if (nextItem is ToolStripControlHost)
1360                                 (nextItem as ToolStripControlHost).Focus ();
1361
1362                         nextItem.Select ();
1363                         
1364                         if (nextItem.Parent is MenuStrip && (nextItem.Parent as MenuStrip).MenuDroppedDown)
1365                                 (nextItem as ToolStripMenuItem).HandleAutoExpansion ();
1366                 }
1367                 
1368                 internal virtual void Dismiss ()
1369                 {
1370                         this.Dismiss (ToolStripDropDownCloseReason.AppClicked);
1371                 }
1372                 
1373                 internal virtual void Dismiss (ToolStripDropDownCloseReason reason)
1374                 {
1375                         // Release our stranglehold on the keyboard
1376                         this.KeyboardActive = false;
1377                         
1378                         // Set our drop down flag to false;
1379                         this.menu_selected = false;
1380                         
1381                         // Make sure all of our items are deselected and repainted
1382                         foreach (ToolStripItem tsi in this.Items)
1383                                 tsi.Dismiss (reason);
1384                                 
1385                         // We probably need to redraw for mnemonic underlines
1386                         this.Invalidate ();
1387                 }
1388
1389                 internal ToolStripItem GetCurrentlySelectedItem ()
1390                 {
1391                         foreach (ToolStripItem tsi in this.DisplayedItems)
1392                                 if (tsi.Selected)
1393                                         return tsi;
1394                                         
1395                         return null;
1396                 }
1397                 
1398                 internal ToolStripItem GetCurrentlyFocusedItem ()
1399                 {
1400                         foreach (ToolStripItem tsi in this.DisplayedItems)
1401                                 if ((tsi is ToolStripControlHost) && (tsi as ToolStripControlHost).Control.Focused)
1402                                         return tsi;
1403
1404                         return null;
1405                 }
1406
1407                 internal override Size GetPreferredSizeCore (Size proposedSize)
1408                 {
1409                         return GetToolStripPreferredSize (proposedSize);
1410                 }
1411                 
1412                 internal virtual Size GetToolStripPreferredSize (Size proposedSize)
1413                 {
1414                         Size new_size = Size.Empty;
1415
1416                         // TODO: This is total duct tape.  We really have to call into the correct
1417                         // layout engine, do a dry run of the layout, and find out our true
1418                         // preferred dimensions.
1419                         if (this.LayoutStyle == ToolStripLayoutStyle.Flow) {
1420                                 Point currentLocation = Point.Empty;
1421                                 int tallest = 0;
1422                                 
1423                                 foreach (ToolStripItem tsi in items) {
1424                                         if ((DisplayRectangle.Width - currentLocation.X) < (tsi.Width + tsi.Margin.Horizontal)) {
1425
1426                                                 currentLocation.Y += tallest;
1427                                                 tallest = 0;
1428                                                 
1429                                                 currentLocation.X = DisplayRectangle.Left;
1430                                         }
1431
1432                                         // Offset the left margin and set the control to our point
1433                                         currentLocation.Offset (tsi.Margin.Left, 0);
1434                                         tallest = Math.Max (tallest, tsi.Height + tsi.Margin.Vertical);
1435                                         
1436                                         // Update our location pointer
1437                                         currentLocation.X += tsi.Width + tsi.Margin.Right;
1438                                 }
1439
1440                                 currentLocation.Y += tallest;
1441                                 return new Size (currentLocation.X, currentLocation.Y);
1442                         }
1443                                 
1444                         if (this.orientation == Orientation.Vertical) {
1445                                 foreach (ToolStripItem tsi in this.items)
1446                                         if (tsi.Available)  {
1447                                                 Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
1448                                                 new_size.Height += tsi_preferred.Height + tsi.Margin.Top + tsi.Margin.Bottom;
1449
1450                                                 if (new_size.Width < (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal))
1451                                                         new_size.Width = (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal);
1452                                         }
1453
1454                                 new_size.Height += (this.GripRectangle.Height + this.GripMargin.Vertical + this.Padding.Vertical + 4);
1455                                 
1456                                 if (new_size.Width == 0)
1457                                         new_size.Width = ExplicitBounds.Width;
1458                                         
1459                                 return new_size;
1460                         } else {
1461                                 foreach (ToolStripItem tsi in this.items) 
1462                                         if (tsi.Available) {
1463                                                 Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
1464                                                 new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right;
1465                                                 
1466                                                 if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical))
1467                                                         new_size.Height = (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical);
1468                                         }
1469                                         
1470                                 new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4);
1471
1472                                 if (new_size.Height == 0)
1473                                         new_size.Height = ExplicitBounds.Height;
1474
1475                                 if (this is StatusStrip)
1476                                         new_size.Height = Math.Max (new_size.Height, 22);
1477                                         
1478                                 return new_size;
1479                         }
1480                 }
1481                 
1482                 internal virtual ToolStrip GetTopLevelToolStrip ()
1483                 {
1484                         return this;
1485                 }
1486                 
1487                 internal virtual void HandleItemClick (ToolStripItem dismissingItem)
1488                 {
1489                         this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.ItemClicked);
1490                 }
1491                 
1492                 internal void HideMenus (bool release, ToolStripDropDownCloseReason reason)
1493                 {
1494                         if (this is MenuStrip && release && menu_selected)
1495                                 (this as MenuStrip).FireMenuDeactivate ();
1496                                 
1497                         if (release)
1498                                 menu_selected = false;
1499                                 
1500                         NotifySelectedChanged (null);
1501                 }
1502
1503                 internal void NotifySelectedChanged (ToolStripItem tsi)
1504                 {
1505                         foreach (ToolStripItem tsi2 in this.DisplayedItems)
1506                                 if (tsi != tsi2)
1507                                         if (tsi2 is ToolStripDropDownItem)
1508                                                 (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1509
1510                         if (this.OverflowButton != null) {
1511                                 ToolStripItemCollection tsic = this.OverflowButton.DropDown.DisplayedItems;
1512                                 
1513                                 foreach (ToolStripItem tsi2 in tsic)
1514                                         if (tsi != tsi2)
1515                                                 if (tsi2 is ToolStripDropDownItem)
1516                                                         (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1517                         
1518                                 this.OverflowButton.HideDropDown ();
1519                         }
1520                         
1521                         foreach (ToolStripItem tsi2 in this.Items)
1522                                 if (tsi != tsi2)
1523                                         tsi2.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1524                 }
1525                 
1526                 internal virtual bool OnMenuKey ()
1527                 {
1528                         return false;
1529                 }
1530
1531                 internal virtual bool ProcessArrowKey (Keys keyData)
1532                 {
1533                         ToolStripItem tsi;
1534                         
1535                         switch (keyData) {
1536                                 case Keys.Right:
1537                                         tsi = this.GetCurrentlySelectedItem ();
1538                                         
1539                                         if (tsi is ToolStripControlHost)
1540                                                 return false;
1541                                         
1542                                         tsi = this.SelectNextToolStripItem (tsi, true);
1543                                         
1544                                         if (tsi is ToolStripControlHost)
1545                                                 (tsi as ToolStripControlHost).Focus ();
1546                                                 
1547                                         return true;
1548                                 case Keys.Tab:
1549                                         tsi = this.GetCurrentlySelectedItem ();
1550
1551                                         tsi = this.SelectNextToolStripItem (tsi, true);
1552
1553                                         if (tsi is ToolStripControlHost)
1554                                                 (tsi as ToolStripControlHost).Focus ();
1555                                                 
1556                                         return true;
1557                                 case Keys.Left:
1558                                         tsi = this.GetCurrentlySelectedItem ();
1559
1560                                         if (tsi is ToolStripControlHost)
1561                                                 return false;
1562
1563                                         tsi = this.SelectNextToolStripItem (tsi, false);
1564
1565                                         if (tsi is ToolStripControlHost)
1566                                                 (tsi as ToolStripControlHost).Focus ();
1567
1568                                         return true;
1569                                 case Keys.Shift | Keys.Tab:
1570                                         tsi = this.GetCurrentlySelectedItem ();
1571                                         
1572                                         tsi = this.SelectNextToolStripItem (tsi, false);
1573
1574                                         if (tsi is ToolStripControlHost)
1575                                                 (tsi as ToolStripControlHost).Focus ();
1576
1577                                         return true;
1578                         }
1579
1580                         return false;
1581                 }
1582
1583                 internal virtual ToolStripItem SelectNextToolStripItem (ToolStripItem start, bool forward)
1584                 {
1585                         ToolStripItem next_item = this.GetNextItem (start, forward ? ArrowDirection.Right : ArrowDirection.Left);
1586                         
1587                         if (next_item == null)
1588                                 return next_item;
1589                                 
1590                         this.ChangeSelection (next_item);
1591
1592                         if (next_item is ToolStripControlHost)
1593                                 (next_item as ToolStripControlHost).Focus ();
1594                 
1595                         return next_item;
1596                 }
1597
1598                 #region Stuff for ToolTips
1599                 private void MouseEnteredItem (ToolStripItem item)
1600                 {
1601                         if (this.show_item_tool_tips && !(item is ToolStripTextBox)) {
1602                                 tooltip_currently_showing = item;
1603                                 ToolTipTimer.Start ();
1604                         }
1605                 }
1606                 
1607                 private void MouseLeftItem (ToolStripItem item)
1608                 {
1609                         ToolTipTimer.Stop ();
1610                         ToolTipWindow.Hide (this);
1611                         tooltip_currently_showing = null;
1612                 }
1613                 
1614                 private Timer ToolTipTimer {
1615                         get {
1616                                 if (tooltip_timer == null) {
1617                                         tooltip_timer = new Timer ();
1618                                         tooltip_timer.Enabled = false;
1619                                         tooltip_timer.Interval = 500;
1620                                         tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick);
1621                                 }
1622                                 
1623                                 return tooltip_timer;
1624                         }
1625                 }
1626                 
1627                 private ToolTip ToolTipWindow {
1628                         get {
1629                                 if (tooltip_window == null)
1630                                         tooltip_window = new ToolTip ();
1631                                         
1632                                 return tooltip_window;
1633                         }
1634                 }
1635                 
1636                 private void ToolTipTimer_Tick (object o, EventArgs args)
1637                 {
1638                         string tooltip = tooltip_currently_showing.GetToolTip ();
1639                         
1640                         if (!string.IsNullOrEmpty (tooltip))
1641                                 ToolTipWindow.Present (this, tooltip);
1642
1643                         tooltip_currently_showing.FireEvent (EventArgs.Empty, ToolStripItemEventType.MouseHover);
1644
1645                         ToolTipTimer.Stop ();
1646                 }
1647                 #endregion
1648
1649                 #region Stuff for Merging
1650                 internal ToolStrip CurrentlyMergedWith {
1651                         get { return this.currently_merged_with; }
1652                         set { this.currently_merged_with = value; }
1653                 }
1654                 
1655                 internal List<ToolStripItem> HiddenMergedItems {
1656                         get {
1657                                 if (this.hidden_merged_items == null)
1658                                         this.hidden_merged_items = new List<ToolStripItem> ();
1659                                         
1660                                 return this.hidden_merged_items;
1661                         }
1662                 }
1663                 
1664                 internal bool IsCurrentlyMerged {
1665                         get { return this.is_currently_merged; }
1666                         set { 
1667                                 this.is_currently_merged = value; 
1668                                 
1669                                 if (!value && this is MenuStrip) 
1670                                         foreach (ToolStripMenuItem tsmi in this.Items)
1671                                                 tsmi.DropDown.IsCurrentlyMerged = value;
1672                          }
1673                 }
1674                 
1675                 internal void BeginMerge ()
1676                 {
1677                         if (!IsCurrentlyMerged) {
1678                                 IsCurrentlyMerged = true;
1679                                 
1680                                 if (this.pre_merge_items == null) {
1681                                         this.pre_merge_items = new List<ToolStripItem> ();
1682                         
1683                                 foreach (ToolStripItem tsi in this.Items)
1684                                         this.pre_merge_items.Add (tsi);
1685                                 }
1686                         }
1687                 }
1688                 
1689                 internal void RevertMergeItem (ToolStripItem item)
1690                 {
1691                         int index = 0;
1692
1693                         // Remove it from it's current Parent
1694                         if (item.Parent != null && item.Parent != this) {
1695                                 if (item.Parent is ToolStripOverflow)
1696                                         (item.Parent as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
1697                                 else
1698                                         item.Parent.Items.RemoveNoOwnerOrLayout (item);
1699
1700                                 item.Parent = item.Owner;       
1701                         }
1702                         
1703                         // Find where the item was before the merge
1704                         index = item.Owner.pre_merge_items.IndexOf (item);
1705
1706                         // Find the first pre-merge item that was after this item, that
1707                         // is currently in the Items collection.  Insert our item before
1708                         // that one.
1709                         for (int i = index; i < this.pre_merge_items.Count; i++) {
1710                                 if (this.Items.Contains (this.pre_merge_items[i])) {
1711                                         item.Owner.Items.InsertNoOwnerOrLayout (this.Items.IndexOf (this.pre_merge_items[i]), item);
1712                                         return;
1713                                 }
1714                         }
1715                         
1716                         // There aren't any items that are supposed to be after this item,
1717                         // so just append it to the end.
1718                         item.Owner.Items.AddNoOwnerOrLayout (item);
1719                 }
1720                 #endregion
1721                 #endregion
1722
1723                 #region ToolStripAccessibleObject
1724                 [ComVisible (true)]
1725                 public class ToolStripAccessibleObject : ControlAccessibleObject
1726                 {
1727                         #region Public Constructor
1728                         public ToolStripAccessibleObject (ToolStrip owner) : base (owner)
1729                         {
1730                         }
1731                         #endregion
1732                         
1733                         #region Public Properties
1734                         public override AccessibleRole Role {
1735                                 get { return AccessibleRole.ToolBar; }
1736                         }
1737                         #endregion
1738
1739                         #region Public Methods
1740                         public override AccessibleObject GetChild (int index)
1741                         {
1742                                 return base.GetChild (index);
1743                         }
1744
1745                         public override int GetChildCount ()
1746                         {
1747                                 return (owner as ToolStrip).Items.Count;
1748                         }
1749
1750                         public override AccessibleObject HitTest (int x, int y)
1751                         {
1752                                 return base.HitTest (x, y);
1753                         }
1754                         #endregion
1755                 }
1756                 #endregion
1757         }
1758 }
1759 #endif