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:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
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.
23 // Copyright (c) 2006 Jonathan Pobst
26 // Jonathan Pobst (monkey@jpobst.com)
31 using System.Runtime.InteropServices;
32 using System.ComponentModel;
34 using System.Windows.Forms.Layout;
35 using System.Collections.Generic;
36 using System.ComponentModel.Design.Serialization;
38 namespace System.Windows.Forms
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
48 #region Private Variables
49 private bool allow_merge;
50 private Color back_color;
51 private bool can_overflow;
52 private ToolStrip currently_merged_with;
53 private ToolStripDropDownDirection default_drop_down_direction;
54 internal ToolStripItemCollection displayed_items;
55 private Color fore_color;
56 private Padding grip_margin;
57 private ToolStripGripStyle grip_style;
58 private List<ToolStripItem> hidden_merged_items;
59 private ImageList image_list;
60 private Size image_scaling_size;
61 private bool is_currently_merged;
62 private ToolStripItemCollection items;
63 private bool keyboard_active;
64 private LayoutEngine layout_engine;
65 private LayoutSettings layout_settings;
66 private ToolStripLayoutStyle layout_style;
67 private Orientation orientation;
68 private ToolStripOverflowButton overflow_button;
69 private List<ToolStripItem> pre_merge_items;
70 private ToolStripRenderer renderer;
71 private ToolStripRenderMode render_mode;
72 private Timer tooltip_timer;
73 private ToolTip.ToolTipWindow tooltip_window;
74 private bool show_item_tool_tips;
77 private ToolStripItem mouse_currently_over;
78 internal bool menu_selected;
79 private ToolStripItem tooltip_currently_showing;
82 #region Public Constructors
83 public ToolStrip () : this (null)
87 public ToolStrip (params ToolStripItem[] items) : base ()
89 SetStyle (ControlStyles.AllPaintingInWmPaint, true);
90 SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
91 SetStyle (ControlStyles.Selectable, false);
92 SetStyle (ControlStyles.SupportsTransparentBackColor, true);
94 this.SuspendLayout ();
96 this.items = new ToolStripItemCollection (this, items, true);
97 this.allow_merge = true;
99 this.back_color = Control.DefaultBackColor;
100 this.can_overflow = true;
101 base.CausesValidation = false;
102 this.default_drop_down_direction = ToolStripDropDownDirection.BelowRight;
103 this.displayed_items = new ToolStripItemCollection (this, null, true);
104 this.Dock = this.DefaultDock;
105 base.Font = new Font ("Tahoma", 8.25f);
106 this.fore_color = Control.DefaultForeColor;
107 this.grip_margin = this.DefaultGripMargin;
108 this.grip_style = ToolStripGripStyle.Visible;
109 this.image_scaling_size = new Size (16, 16);
110 this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
111 this.orientation = Orientation.Horizontal;
112 if (!(this is ToolStripDropDown))
113 this.overflow_button = new ToolStripOverflowButton (this);
114 this.renderer = null;
115 this.render_mode = ToolStripRenderMode.ManagerRenderMode;
116 this.show_item_tool_tips = this.DefaultShowItemToolTips;
117 base.TabStop = false;
118 this.ResumeLayout ();
121 // Register with the ToolStripManager
122 ToolStripManager.AddToolStrip (this);
126 #region Public Properties
127 [DefaultValue (true)]
128 public bool AllowMerge {
129 get { return this.allow_merge; }
130 set { this.allow_merge = false; }
133 public override AnchorStyles Anchor {
134 get { return base.Anchor; }
135 set { base.Anchor = value; }
139 [EditorBrowsable (EditorBrowsableState.Never)]
140 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
141 public override bool AutoScroll {
142 get { return base.AutoScroll; }
143 set { base.AutoScroll = value; }
147 [EditorBrowsable (EditorBrowsableState.Never)]
148 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
149 public new Size AutoScrollMargin {
150 get { return base.AutoScrollMargin; }
151 set { base.AutoScrollMargin = value; }
155 [EditorBrowsable (EditorBrowsableState.Never)]
156 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
157 public new Size AutoScrollMinSize {
158 get { return base.AutoScrollMinSize; }
159 set { base.AutoScrollMinSize = value; }
163 [EditorBrowsable (EditorBrowsableState.Never)]
164 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
165 public new Point AutoScrollPosition {
166 get { return base.AutoScrollPosition; }
167 set { base.AutoScrollPosition = value; }
170 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
172 [EditorBrowsable (EditorBrowsableState.Always)]
173 [DefaultValue (true)]
174 public override bool AutoSize {
175 get { return base.AutoSize; }
176 set { base.AutoSize = value; }
179 new public Color BackColor {
180 get { return this.back_color; }
181 set { this.back_color = value; }
184 [DefaultValue (true)]
185 public bool CanOverflow {
186 get { return this.can_overflow; }
187 set { this.can_overflow = value; }
191 [DefaultValue (false)]
192 public new bool CausesValidation {
193 get { return base.CausesValidation; }
194 set { base.CausesValidation = value; }
197 [EditorBrowsable (EditorBrowsableState.Never)]
198 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
199 public new ControlCollection Controls {
200 get { return base.Controls; }
204 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
205 public override Cursor Cursor {
206 get { return base.Cursor; }
207 set { base.Cursor = value; }
211 public virtual ToolStripDropDownDirection DefaultDropDownDirection {
212 get { return this.default_drop_down_direction; }
214 if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value))
215 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value));
217 this.default_drop_down_direction = value;
221 public override Rectangle DisplayRectangle {
223 if (this.orientation == Orientation.Horizontal)
224 if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
225 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
227 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);
229 if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
230 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
232 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);
236 [DefaultValue (DockStyle.Top)]
237 public override DockStyle Dock {
238 get { return base.Dock; }
240 if (base.Dock != value) {
245 case DockStyle.Bottom:
247 this.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
250 case DockStyle.Right:
251 this.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow;
258 public override Font Font {
259 get { return base.Font; }
261 if (base.Font != value) {
264 foreach (ToolStripItem tsi in this.Items)
265 tsi.OnOwnerFontChanged (EventArgs.Empty);
271 public new Color ForeColor {
272 get { return this.fore_color; }
274 if (this.fore_color != value) {
275 this.fore_color = value;
276 this.OnForeColorChanged (EventArgs.Empty);
282 public ToolStripGripDisplayStyle GripDisplayStyle {
283 get { return this.orientation == Orientation.Vertical ? ToolStripGripDisplayStyle.Horizontal : ToolStripGripDisplayStyle.Vertical; }
286 public Padding GripMargin {
287 get { return this.grip_margin; }
289 if (this.grip_margin != value) {
290 this.grip_margin = value;
291 this.PerformLayout ();
297 public Rectangle GripRectangle {
299 if (this.grip_style == ToolStripGripStyle.Hidden)
300 return Rectangle.Empty;
302 if (this.orientation == Orientation.Horizontal)
303 return new Rectangle (this.grip_margin.Left + this.Padding.Left, this.Padding.Top, 3, this.Height);
305 return new Rectangle (this.Padding.Left, this.grip_margin.Top + this.Padding.Top, this.Width, 3);
309 [DefaultValue (ToolStripGripStyle.Visible)]
310 public ToolStripGripStyle GripStyle {
311 get { return this.grip_style; }
313 if (this.grip_style != value) {
314 if (!Enum.IsDefined (typeof (ToolStripGripStyle), value))
315 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripGripStyle", value));
316 this.grip_style = value;
317 this.PerformLayout ();
323 [EditorBrowsable (EditorBrowsableState.Never)]
324 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
325 public new bool HasChildren {
326 get { return base.HasChildren; }
330 [EditorBrowsable (EditorBrowsableState.Never)]
331 public new HScrollProperties HorizontalScroll {
332 get { return base.HorizontalScroll; }
336 [DefaultValue (null)]
337 public ImageList ImageList {
338 get { return this.image_list; }
339 set { this.image_list = value; }
342 [DefaultValue ("{Width=16, Height=16}")]
343 public Size ImageScalingSize {
344 get { return this.image_scaling_size; }
345 set { this.image_scaling_size = value; }
348 [MonoTODO ("Always returns false, dragging not implemented yet.")]
350 [EditorBrowsable (EditorBrowsableState.Advanced)]
351 public bool IsCurrentlyDragging {
352 get { return false; }
356 public bool IsDropDown {
358 if (this is ToolStripDropDown)
365 [MergableProperty (false)]
366 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
367 public virtual ToolStripItemCollection Items {
368 get { return this.items; }
371 public override LayoutEngine LayoutEngine {
373 if (layout_engine == null)
374 this.layout_engine = new ToolStripSplitStackLayout ();
376 return this.layout_engine;
381 [DefaultValue (null)]
382 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
383 public LayoutSettings LayoutSettings {
384 get { return this.layout_settings; }
385 set { this.layout_settings = value; }
388 [AmbientValue (ToolStripLayoutStyle.StackWithOverflow)]
389 public ToolStripLayoutStyle LayoutStyle {
390 get { return layout_style; }
392 if (this.layout_style != value) {
393 if (!Enum.IsDefined (typeof (ToolStripLayoutStyle), value))
394 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripLayoutStyle", value));
396 this.layout_style = value;
398 if (this.layout_style == ToolStripLayoutStyle.Flow)
399 this.layout_engine = new FlowLayout ();
401 this.layout_engine = new ToolStripSplitStackLayout ();
403 if (this.layout_style == ToolStripLayoutStyle.StackWithOverflow) {
404 if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right)
405 this.layout_style = ToolStripLayoutStyle.VerticalStackWithOverflow;
407 this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
410 if (this.layout_style == ToolStripLayoutStyle.HorizontalStackWithOverflow)
411 this.orientation = Orientation.Horizontal;
412 else if (this.layout_style == ToolStripLayoutStyle.VerticalStackWithOverflow)
413 this.orientation = Orientation.Vertical;
415 this.layout_settings = this.CreateLayoutSettings (value);
417 this.PerformLayout ();
418 this.OnLayoutStyleChanged (EventArgs.Empty);
424 public Orientation Orientation {
425 get { return this.orientation; }
429 [EditorBrowsable (EditorBrowsableState.Advanced)]
430 public ToolStripOverflowButton OverflowButton {
431 get { return this.overflow_button; }
435 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
436 public ToolStripRenderer Renderer {
438 if (this.render_mode == ToolStripRenderMode.ManagerRenderMode)
439 return ToolStripManager.Renderer;
441 return this.renderer;
444 if (this.renderer != value) {
445 this.renderer = value;
446 this.render_mode = ToolStripRenderMode.Custom;
447 this.PerformLayout ();
448 this.OnRendererChanged (EventArgs.Empty);
453 public ToolStripRenderMode RenderMode {
454 get { return this.render_mode; }
456 if (!Enum.IsDefined (typeof (ToolStripRenderMode), value))
457 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripRenderMode", value));
459 if (value == ToolStripRenderMode.Custom && this.renderer == null)
460 throw new NotSupportedException ("Must set Renderer property before setting RenderMode to Custom");
461 if (value == ToolStripRenderMode.Professional || value == ToolStripRenderMode.System)
462 this.Renderer = new ToolStripProfessionalRenderer ();
464 this.render_mode = value;
468 [DefaultValue (true)]
469 public bool ShowItemToolTips {
470 get { return this.show_item_tool_tips; }
471 set { this.show_item_tool_tips = value; }
474 [DefaultValue (false)]
475 public bool Stretch {
476 get { return this.stretch; }
477 set { this.stretch = value; }
480 [DefaultValue (false)]
482 public new bool TabStop {
483 get { return base.TabStop; }
484 set { base.TabStop = value; }
488 [EditorBrowsable (EditorBrowsableState.Never)]
489 public new VScrollProperties VerticalScroll {
490 get { return base.VerticalScroll; }
494 #region Protected Properties
495 protected virtual DockStyle DefaultDock { get { return DockStyle.Top; } }
496 protected virtual Padding DefaultGripMargin { get { return new Padding (2); } }
497 protected override Padding DefaultMargin { get { return Padding.Empty; } }
498 protected override Padding DefaultPadding { get { return new Padding (0, 0, 1, 0); } }
499 protected virtual bool DefaultShowItemToolTips { get { return true; } }
500 protected override Size DefaultSize { get { return new Size (100, 25); } }
501 protected internal virtual ToolStripItemCollection DisplayedItems { get { return this.displayed_items; } }
504 #region Public Methods
505 [EditorBrowsable (EditorBrowsableState.Never)]
506 public new Control GetChildAtPoint (Point point)
508 return base.GetChildAtPoint (point);
511 //[EditorBrowsable (EditorBrowsableState.Never)]
512 //public new Control GetChildAtPoint (Point pt, GetChildAtPointSkip skipValue)
514 // return base.GetChildAtPoint (pt, skipValue);
517 public ToolStripItem GetItemAt (Point point)
519 foreach (ToolStripItem tsi in this.displayed_items)
520 if (tsi.Visible && tsi.Bounds.Contains (point))
526 public ToolStripItem GetItemAt (int x, int y)
528 return GetItemAt (new Point (x, y));
531 public virtual ToolStripItem GetNextItem (ToolStripItem start, ArrowDirection direction)
533 if (!Enum.IsDefined (typeof (ArrowDirection), direction))
534 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ArrowDirection", direction));
536 ToolStripItem current_best = null;
537 int current_best_point;
540 case ArrowDirection.Right:
541 current_best_point = int.MaxValue;
544 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
545 if (loop_tsi.Left >= start.Right && loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
546 current_best = loop_tsi;
547 current_best_point = loop_tsi.Left;
550 if (current_best == null)
551 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
552 if (loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
553 current_best = loop_tsi;
554 current_best_point = loop_tsi.Left;
558 case ArrowDirection.Up:
559 current_best_point = int.MinValue;
562 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
563 if (loop_tsi.Bottom <= start.Top && loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
564 current_best = loop_tsi;
565 current_best_point = loop_tsi.Top;
568 if (current_best == null)
569 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
570 if (loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
571 current_best = loop_tsi;
572 current_best_point = loop_tsi.Top;
576 case ArrowDirection.Left:
577 current_best_point = int.MinValue;
580 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
581 if (loop_tsi.Right <= start.Left && loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
582 current_best = loop_tsi;
583 current_best_point = loop_tsi.Left;
586 if (current_best == null)
587 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
588 if (loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
589 current_best = loop_tsi;
590 current_best_point = loop_tsi.Left;
594 case ArrowDirection.Down:
595 current_best_point = int.MaxValue;
598 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
599 if (loop_tsi.Top >= start.Bottom && loop_tsi.Bottom < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
600 current_best = loop_tsi;
601 current_best_point = loop_tsi.Top;
604 if (current_best == null)
605 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
606 if (loop_tsi.Top < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
607 current_best = loop_tsi;
608 current_best_point = loop_tsi.Top;
617 [EditorBrowsable (EditorBrowsableState.Never)]
618 public void ResetMinimumSize ()
620 this.MinimumSize = new Size (-1, -1);
623 [EditorBrowsable (EditorBrowsableState.Never)]
624 public new void SetAutoScrollMargin (int x, int y)
626 base.SetAutoScrollMargin (x, y);
629 public override string ToString ()
631 return String.Format ("{0}, Name: {1}, Items: {2}", base.ToString(), this.Name, this.items.Count.ToString ());
635 #region Protected Methods
636 protected override AccessibleObject CreateAccessibilityInstance ()
638 AccessibleObject ao = new AccessibleObject (this);
640 ao.role = AccessibleRole.ToolBar;
645 protected override ControlCollection CreateControlsInstance ()
647 return base.CreateControlsInstance ();
650 protected internal virtual ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
653 return new ToolStripSeparator ();
655 if (this is ToolStripDropDown)
656 return new ToolStripMenuItem (text, image, onClick);
658 return new ToolStripButton (text, image, onClick);
661 protected virtual LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle layoutStyle)
663 switch (layoutStyle) {
664 case ToolStripLayoutStyle.Flow:
665 return new FlowLayoutSettings ();
666 case ToolStripLayoutStyle.Table:
667 //return new TableLayoutSettings ();
668 case ToolStripLayoutStyle.StackWithOverflow:
669 case ToolStripLayoutStyle.HorizontalStackWithOverflow:
670 case ToolStripLayoutStyle.VerticalStackWithOverflow:
676 protected override void Dispose (bool disposing)
679 ToolStripManager.RemoveToolStrip (this);
680 base.Dispose (disposing);
684 protected override void OnDockChanged (EventArgs e)
686 base.OnDockChanged (e);
689 protected override bool IsInputChar (char charCode)
691 return base.IsInputChar (charCode);
694 protected override bool IsInputKey (Keys keyData)
696 return base.IsInputKey (keyData);
699 protected override void OnEnabledChanged (EventArgs e)
701 base.OnEnabledChanged (e);
703 foreach (ToolStripItem tsi in this.Items)
704 tsi.OnParentEnabledChanged (EventArgs.Empty);
707 protected override void OnFontChanged (EventArgs e)
709 base.OnFontChanged (e);
712 protected override void OnHandleCreated (EventArgs e)
714 base.OnHandleCreated (e);
717 protected override void OnHandleDestroyed (EventArgs e)
719 base.OnHandleDestroyed (e);
722 protected override void OnInvalidated (InvalidateEventArgs e)
724 base.OnInvalidated (e);
727 protected internal virtual void OnItemAdded (ToolStripItemEventArgs e)
729 e.Item.Available = true;
730 e.Item.SetPlacement (ToolStripItemPlacement.Main);
734 this.PerformLayout ();
736 ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemAddedEvent]);
741 protected virtual void OnItemClicked (ToolStripItemClickedEventArgs e)
743 ToolStripManager.SetActiveToolStrip (null);
745 ToolStripItemClickedEventHandler eh = (ToolStripItemClickedEventHandler)(Events [ItemClickedEvent]);
750 protected internal virtual void OnItemRemoved (ToolStripItemEventArgs e)
752 ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemRemovedEvent]);
757 protected override void OnLayout (LayoutEventArgs e)
762 this.SetDisplayedItems ();
763 this.OnLayoutCompleted (EventArgs.Empty);
767 protected virtual void OnLayoutCompleted (EventArgs e)
769 EventHandler eh = (EventHandler)(Events [LayoutCompletedEvent]);
774 protected virtual void OnLayoutStyleChanged (EventArgs e)
776 EventHandler eh = (EventHandler)(Events[LayoutStyleChangedEvent]);
781 protected override void OnLeave (EventArgs e)
786 protected override void OnLostFocus (EventArgs e)
788 base.OnLostFocus (e);
791 protected override void OnMouseCaptureChanged (EventArgs e)
793 base.OnMouseCaptureChanged (e);
796 protected override void OnMouseDown (MouseEventArgs mea)
798 if (mouse_currently_over != null)
800 if (this is MenuStrip && !(mouse_currently_over as ToolStripMenuItem).HasDropDownItems) {
802 (this as MenuStrip).FireMenuActivate ();
807 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseDown);
809 if (this is MenuStrip && !menu_selected) {
810 (this as MenuStrip).FireMenuActivate ();
811 menu_selected = true;
814 if (this is MenuStrip)
815 this.HideMenus (true, ToolStripDropDownCloseReason.AppClicked);
818 if (this is MenuStrip)
819 this.Capture = false;
821 base.OnMouseDown (mea);
824 protected override void OnMouseLeave (EventArgs e)
826 if (mouse_currently_over != null) {
827 MouseLeftItem (mouse_currently_over);
828 mouse_currently_over.FireEvent (e, ToolStripItemEventType.MouseLeave);
829 mouse_currently_over = null;
832 base.OnMouseLeave (e);
835 protected override void OnMouseMove (MouseEventArgs mea)
838 // Find the item we are now
839 if (this.overflow_button != null && this.overflow_button.Visible && this.overflow_button.Bounds.Contains (mea.Location))
840 tsi = this.overflow_button;
842 tsi = this.GetItemAt (mea.X, mea.Y);
845 // If we were already hovering on this item, just send a mouse move
846 if (tsi == mouse_currently_over)
847 tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
849 // If we were over a different item, fire a mouse leave on it
850 if (mouse_currently_over != null) {
852 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
855 // Set the new item we are currently over
856 mouse_currently_over = tsi;
858 // Fire mouse enter and mouse move
859 tsi.FireEvent (mea, ToolStripItemEventType.MouseEnter);
860 MouseEnteredItem (tsi);
861 tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
863 // If we're over something with a drop down, show it
864 if (menu_selected && mouse_currently_over.Enabled && mouse_currently_over is ToolStripDropDownItem && (mouse_currently_over as ToolStripDropDownItem).HasDropDownItems)
865 (mouse_currently_over as ToolStripDropDownItem).ShowDropDown ();
868 // We're not over anything now, just fire the mouse leave on what we used to be over
869 if (mouse_currently_over != null) {
871 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
872 mouse_currently_over = null;
876 base.OnMouseMove (mea);
879 protected override void OnMouseUp (MouseEventArgs mea)
881 // If we're currently over an item (set in MouseMove)
882 if (mouse_currently_over != null) {
883 // Fire the item's MouseUp event
884 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseUp);
886 // The event handler may have blocked until the mouse moved off of the ToolStripItem
887 if (mouse_currently_over == null)
890 // Fire our ItemClicked event
891 OnItemClicked (new ToolStripItemClickedEventArgs (mouse_currently_over));
894 base.OnMouseUp (mea);
897 protected override void OnPaint (PaintEventArgs e)
902 this.OnPaintGrip (e);
904 // Make each item draw itself
905 foreach (ToolStripItem tsi in this.displayed_items) {
906 e.Graphics.TranslateTransform (tsi.Bounds.Left, tsi.Bounds.Top);
907 tsi.FireEvent (e, ToolStripItemEventType.Paint);
908 e.Graphics.ResetTransform ();
911 // Paint the Overflow button if it's visible
912 if (this.overflow_button != null && this.overflow_button.Visible) {
913 e.Graphics.TranslateTransform (this.overflow_button.Bounds.Left, this.overflow_button.Bounds.Top);
914 this.overflow_button.FireEvent (e, ToolStripItemEventType.Paint);
915 e.Graphics.ResetTransform ();
918 Rectangle affected_bounds = new Rectangle (new Point (0, 0), this.Size);
919 Rectangle connected_area = Rectangle.Empty;
921 if (this is ToolStripDropDown && (this as ToolStripDropDown).OwnerItem != null && !(this as ToolStripDropDown).OwnerItem.IsOnDropDown)
922 connected_area = new Rectangle (1, 0, (this as ToolStripDropDown).OwnerItem.Width - 2, 2);
924 ToolStripRenderEventArgs pevent = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, Color.Empty);
925 pevent.InternalConnectedArea = connected_area;
927 this.Renderer.DrawToolStripBorder (pevent);
930 [EditorBrowsable (EditorBrowsableState.Advanced)]
931 protected override void OnPaintBackground (PaintEventArgs pevent)
933 base.OnPaintBackground (pevent);
935 Rectangle affected_bounds = new Rectangle (new Point (0, 0), this.Size);
936 Rectangle connected_area = Rectangle.Empty;
938 if (this is ToolStripDropDown && (this as ToolStripDropDown).OwnerItem != null && !(this as ToolStripDropDown).OwnerItem.IsOnDropDown)
939 connected_area = new Rectangle (1, 0, (this as ToolStripDropDown).OwnerItem.Width - 2, 2);
941 ToolStripRenderEventArgs e = new ToolStripRenderEventArgs (pevent.Graphics, this, affected_bounds, Color.Empty);
942 e.InternalConnectedArea = connected_area;
944 this.Renderer.DrawToolStripBackground (e);
947 protected internal virtual void OnPaintGrip (PaintEventArgs e)
949 // Never draw a grip with these two layouts
950 if (this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
953 PaintEventHandler eh = (PaintEventHandler)(Events [PaintGripEvent]);
957 if (!(this is MenuStrip)) {
958 if (this.orientation == Orientation.Horizontal)
959 e.Graphics.TranslateTransform (2, 0);
961 e.Graphics.TranslateTransform (0, 2);
964 this.Renderer.DrawGrip (new ToolStripGripRenderEventArgs (e.Graphics, this, this.GripRectangle, this.GripDisplayStyle, this.grip_style));
965 e.Graphics.ResetTransform ();
968 protected virtual void OnRendererChanged (EventArgs e)
970 EventHandler eh = (EventHandler)(Events [RendererChangedEvent]);
975 [EditorBrowsable (EditorBrowsableState.Advanced)]
976 protected override void OnRightToLeftChanged (EventArgs e)
978 base.OnRightToLeftChanged (e);
980 foreach (ToolStripItem tsi in this.Items)
981 tsi.OnParentRightToLeftChanged (e);
984 protected override void OnScroll (ScrollEventArgs se)
989 protected override void OnTabStopChanged (EventArgs e)
991 base.OnTabStopChanged (e);
994 protected override void OnVisibleChanged (EventArgs e)
996 base.OnVisibleChanged (e);
999 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
1001 return base.ProcessCmdKey (ref msg, keyData);
1004 protected override bool ProcessDialogKey (Keys keyData)
1006 if (!this.KeyboardActive)
1009 // Give each item a chance to handle the key
1010 foreach (ToolStripItem tsi in this.Items)
1011 if (tsi.ProcessDialogKey (keyData))
1014 // See if I want to handle it
1015 if (this.ProcessArrowKey (keyData))
1018 ToolStrip ts = null;
1022 this.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1025 case Keys.Control | Keys.Tab:
1026 ts = ToolStripManager.GetNextToolStrip (this, true);
1029 foreach (ToolStripItem tsi in this.Items)
1030 tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1032 ToolStripManager.SetActiveToolStrip (ts);
1033 ts.SelectNextToolStripItem (null, true);
1037 case Keys.Control | Keys.Shift | Keys.Tab:
1038 ts = ToolStripManager.GetNextToolStrip (this, false);
1041 foreach (ToolStripItem tsi in this.Items)
1042 tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1044 ToolStripManager.SetActiveToolStrip (ts);
1045 ts.SelectNextToolStripItem (null, true);
1053 if (GetCurrentlySelectedItem () is ToolStripControlHost)
1058 return base.ProcessDialogKey (keyData);
1061 protected override bool ProcessMnemonic (char charCode)
1063 // If any item has an explicit mnemonic, it gets the message
1064 foreach (ToolStripItem tsi in this.Items)
1065 if (tsi.Enabled && tsi.Visible && Control.IsMnemonic (charCode, tsi.Text))
1066 return tsi.ProcessMnemonic (charCode);
1068 string code = Char.ToUpper (charCode).ToString ();
1070 // If any item's text starts with our letter, it gets the message
1071 foreach (ToolStripItem tsi in this.Items)
1072 if (tsi.Enabled && tsi.Visible && tsi.Text.Length > 0 && tsi.Text.ToUpper ().StartsWith (code))
1073 return tsi.ProcessMnemonic (charCode);
1075 return base.ProcessMnemonic (charCode);
1078 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1080 base.SetBoundsCore (x, y, width, height, specified);
1083 protected virtual void SetDisplayedItems ()
1085 this.displayed_items.Clear ();
1087 foreach (ToolStripItem tsi in this.items)
1088 if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) {
1089 this.displayed_items.AddNoOwnerOrLayout (tsi);
1092 else if (tsi.Placement == ToolStripItemPlacement.Overflow)
1093 tsi.Parent = this.OverflowButton.DropDown;
1095 if (this.OverflowButton != null)
1096 this.OverflowButton.DropDown.SetDisplayedItems ();
1099 protected internal void SetItemLocation (ToolStripItem item, Point location)
1102 throw new ArgumentNullException ("item");
1104 if (item.Owner != this)
1105 throw new NotSupportedException ("The item is not owned by this ToolStrip");
1107 item.SetBounds (new Rectangle (location, item.Size));
1110 protected internal static void SetItemParent (ToolStripItem item, ToolStrip parent)
1112 if (item.Parent != null) {
1113 item.Parent.Items.RemoveNoOwnerOrLayout (item);
1115 if (item.Parent is ToolStripOverflow)
1116 (item.Parent as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
1119 parent.Items.AddNoOwnerOrLayout (item);
1120 item.Parent = parent;
1123 protected override void SetVisibleCore (bool value)
1125 base.SetVisibleCore (value);
1128 protected override void WndProc (ref Message m)
1130 base.WndProc (ref m);
1134 #region Public Events
1135 static object ItemAddedEvent = new object ();
1136 static object ItemClickedEvent = new object ();
1137 static object ItemRemovedEvent = new object ();
1138 static object LayoutCompletedEvent = new object ();
1139 static object LayoutStyleChangedEvent = new object ();
1140 static object PaintGripEvent = new object ();
1141 static object RendererChangedEvent = new object ();
1144 [EditorBrowsable (EditorBrowsableState.Always)]
1145 public new event EventHandler AutoSizeChanged {
1146 add { base.AutoSizeChanged += value; }
1147 remove { base.AutoSizeChanged -= value; }
1151 public new event EventHandler CausesValidationChanged {
1152 add { base.CausesValidationChanged += value; }
1153 remove { base.CausesValidationChanged -= value; }
1157 [EditorBrowsable (EditorBrowsableState.Never)]
1158 public new event ControlEventHandler ControlAdded {
1159 add { base.ControlAdded += value; }
1160 remove { base.ControlAdded -= value; }
1164 [EditorBrowsable (EditorBrowsableState.Never)]
1165 public new event ControlEventHandler ControlRemoved {
1166 add { base.ControlRemoved += value; }
1167 remove { base.ControlRemoved -= value; }
1171 public new event EventHandler CursorChanged {
1172 add { base.CursorChanged += value; }
1173 remove { base.CursorChanged -= value; }
1177 public new event EventHandler ForeColorChanged {
1178 add { base.ForeColorChanged += value; }
1179 remove { base.ForeColorChanged -= value; }
1182 public event ToolStripItemEventHandler ItemAdded {
1183 add { Events.AddHandler (ItemAddedEvent, value); }
1184 remove { Events.RemoveHandler (ItemAddedEvent, value); }
1187 public event ToolStripItemClickedEventHandler ItemClicked {
1188 add { Events.AddHandler (ItemClickedEvent, value); }
1189 remove { Events.RemoveHandler (ItemClickedEvent, value); }
1192 public event ToolStripItemEventHandler ItemRemoved {
1193 add { Events.AddHandler (ItemRemovedEvent, value); }
1194 remove { Events.RemoveHandler (ItemRemovedEvent, value); }
1197 public event EventHandler LayoutCompleted {
1198 add { Events.AddHandler (LayoutCompletedEvent, value); }
1199 remove { Events.RemoveHandler (LayoutCompletedEvent, value); }
1202 public event EventHandler LayoutStyleChanged {
1203 add { Events.AddHandler (LayoutStyleChangedEvent, value); }
1204 remove { Events.RemoveHandler (LayoutStyleChangedEvent, value); }
1207 public event PaintEventHandler PaintGrip {
1208 add { Events.AddHandler (PaintGripEvent, value); }
1209 remove { Events.RemoveHandler (PaintGripEvent, value); }
1212 public event EventHandler RendererChanged {
1213 add { Events.AddHandler (RendererChangedEvent, value); }
1214 remove { Events.RemoveHandler (RendererChangedEvent, value); }
1218 #region Internal Properties
1219 internal virtual bool KeyboardActive
1221 get { return this.keyboard_active; }
1223 if (this.keyboard_active != value) {
1224 this.keyboard_active = value;
1227 Application.KeyboardCapture = this;
1228 else if (Application.KeyboardCapture == this)
1229 Application.KeyboardCapture = null;
1231 // Redraw for mnemonic underlines
1238 #region Private Methods
1239 internal void ChangeSelection (ToolStripItem nextItem)
1241 if (Application.KeyboardCapture != this)
1242 ToolStripManager.SetActiveToolStrip (this);
1244 foreach (ToolStripItem tsi in this.Items)
1245 if (tsi != nextItem)
1246 tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1250 if (nextItem.Parent is MenuStrip && (nextItem.Parent as MenuStrip).MenuDroppedDown)
1251 (nextItem as ToolStripMenuItem).HandleAutoExpansion ();
1254 internal virtual void Dismiss ()
1256 this.Dismiss (ToolStripDropDownCloseReason.AppClicked);
1259 internal virtual void Dismiss (ToolStripDropDownCloseReason reason)
1261 // Release our stranglehold on the keyboard
1262 this.KeyboardActive = false;
1264 // Set our drop down flag to false;
1265 this.menu_selected = false;
1267 // Make sure all of our items are deselected and repainted
1268 foreach (ToolStripItem tsi in this.Items)
1269 tsi.Dismiss (reason);
1272 private void DoAutoSize ()
1274 if (this.AutoSize == true && this.Dock == DockStyle.None)
1275 this.Size = GetPreferredSize (Size.Empty);
1277 if (this.AutoSize == true && this.Orientation == Orientation.Horizontal && (this.Dock == DockStyle.Top || this.Dock == DockStyle.Bottom))
1278 this.Height = GetPreferredSize (Size.Empty).Height;
1281 internal ToolStripItem GetCurrentlySelectedItem ()
1283 foreach (ToolStripItem tsi in this.DisplayedItems)
1290 public override Size GetPreferredSize (Size proposedSize)
1292 Size new_size = new Size (0, this.Height);
1294 if (this.orientation == Orientation.Vertical) {
1295 foreach (ToolStripItem tsi in this.items)
1296 if (tsi.GetPreferredSize (Size.Empty).Height + tsi.Margin.Top + tsi.Margin.Bottom > new_size.Height)
1297 new_size.Height = tsi.GetPreferredSize (Size.Empty).Height + tsi.Margin.Top + tsi.Margin.Bottom;
1299 new_size.Height += this.Padding.Top + this.Padding.Bottom;
1300 new_size.Width = this.Width;
1302 foreach (ToolStripItem tsi in this.items)
1303 if (tsi.Available) {
1304 Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
1305 new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right;
1307 if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height))
1308 new_size.Height = (this.Padding.Vertical + tsi_preferred.Height);
1312 new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4);
1316 internal virtual ToolStrip GetTopLevelToolStrip ()
1321 internal void HandleItemClick (ToolStripItem dismissingItem)
1323 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.ItemClicked);
1324 this.OnItemClicked (new ToolStripItemClickedEventArgs (dismissingItem));
1327 internal void HideMenus (bool release, ToolStripDropDownCloseReason reason)
1329 if (this is MenuStrip && release && menu_selected)
1330 (this as MenuStrip).FireMenuDeactivate ();
1333 menu_selected = false;
1335 NotifySelectedChanged (null);
1338 internal void NotifySelectedChanged (ToolStripItem tsi)
1340 foreach (ToolStripItem tsi2 in this.DisplayedItems)
1342 if (tsi2 is ToolStripDropDownItem)
1343 (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1345 if (this.OverflowButton != null) {
1346 ToolStripItemCollection tsic = this.OverflowButton.DropDown.DisplayedItems;
1348 foreach (ToolStripItem tsi2 in tsic)
1350 if (tsi2 is ToolStripDropDownItem)
1351 (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1353 this.OverflowButton.HideDropDown ();
1356 foreach (ToolStripItem tsi2 in this.Items)
1358 tsi2.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1361 internal virtual bool OnMenuKey ()
1366 internal virtual bool ProcessArrowKey (Keys keyData)
1372 tsi = this.GetCurrentlySelectedItem ();
1374 if (tsi is ToolStripControlHost)
1377 tsi = this.SelectNextToolStripItem (tsi, true);
1379 if (tsi is ToolStripControlHost)
1380 (tsi as ToolStripControlHost).Focus ();
1384 tsi = this.GetCurrentlySelectedItem ();
1386 tsi = this.SelectNextToolStripItem (tsi, true);
1388 if (tsi is ToolStripControlHost)
1389 (tsi as ToolStripControlHost).Focus ();
1393 tsi = this.GetCurrentlySelectedItem ();
1395 if (tsi is ToolStripControlHost)
1398 tsi = this.SelectNextToolStripItem (tsi, false);
1400 if (tsi is ToolStripControlHost)
1401 (tsi as ToolStripControlHost).Focus ();
1404 case Keys.Shift | Keys.Tab:
1405 tsi = this.GetCurrentlySelectedItem ();
1407 tsi = this.SelectNextToolStripItem (tsi, false);
1409 if (tsi is ToolStripControlHost)
1410 (tsi as ToolStripControlHost).Focus ();
1418 internal virtual ToolStripItem SelectNextToolStripItem (ToolStripItem start, bool forward)
1420 ToolStripItem next_item = this.GetNextItem (start, forward ? ArrowDirection.Right : ArrowDirection.Left);
1422 this.ChangeSelection (next_item);
1424 if (next_item is ToolStripControlHost)
1425 (next_item as ToolStripControlHost).Focus ();
1430 #region Stuff for ToolTips
1431 private void MouseEnteredItem (ToolStripItem item)
1433 if (this.show_item_tool_tips) {
1434 tooltip_currently_showing = item;
1435 ToolTipTimer.Start ();
1439 private void MouseLeftItem (ToolStripItem item)
1441 ToolTipTimer.Stop ();
1442 ToolTipWindow.Hide ();
1443 tooltip_currently_showing = null;
1446 private Timer ToolTipTimer {
1448 if (tooltip_timer == null) {
1449 tooltip_timer = new Timer ();
1450 tooltip_timer.Enabled = false;
1451 tooltip_timer.Interval = 500;
1452 tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick);
1455 return tooltip_timer;
1459 private ToolTip.ToolTipWindow ToolTipWindow {
1461 if (tooltip_window == null)
1462 tooltip_window = new ToolTip.ToolTipWindow ();
1464 return tooltip_window;
1468 private void ToolTipTimer_Tick (object o, EventArgs args)
1470 string tooltip = tooltip_currently_showing.GetToolTip ();
1472 if (!string.IsNullOrEmpty (tooltip))
1473 ToolTipWindow.Present (this, tooltip);
1475 tooltip_currently_showing.FireEvent (EventArgs.Empty, ToolStripItemEventType.MouseHover);
1477 ToolTipTimer.Stop ();
1481 #region Stuff for Merging
1482 internal ToolStrip CurrentlyMergedWith {
1483 get { return this.currently_merged_with; }
1484 set { this.currently_merged_with = value; }
1487 internal List<ToolStripItem> HiddenMergedItems {
1489 if (this.hidden_merged_items == null)
1490 this.hidden_merged_items = new List<ToolStripItem> ();
1492 return this.hidden_merged_items;
1496 internal bool IsCurrentlyMerged {
1497 get { return this.is_currently_merged; }
1499 this.is_currently_merged = value;
1501 if (!value && this is MenuStrip)
1502 foreach (ToolStripMenuItem tsmi in this.Items)
1503 tsmi.DropDown.IsCurrentlyMerged = value;
1507 internal void BeginMerge ()
1509 if (!IsCurrentlyMerged) {
1510 IsCurrentlyMerged = true;
1512 if (this.pre_merge_items == null) {
1513 this.pre_merge_items = new List<ToolStripItem> ();
1515 foreach (ToolStripItem tsi in this.Items)
1516 this.pre_merge_items.Add (tsi);
1521 internal void RevertMergeItem (ToolStripItem item)
1525 // Remove it from it's current Parent
1526 if (item.Parent != null && item.Parent != this) {
1527 if (item.Parent is ToolStripOverflow)
1528 (item.Parent as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
1530 item.Parent.Items.RemoveNoOwnerOrLayout (item);
1532 item.Parent = item.Owner;
1535 // Find where the item was before the merge
1536 index = item.Owner.pre_merge_items.IndexOf (item);
1538 // Find the first pre-merge item that was after this item, that
1539 // is currently in the Items collection. Insert our item before
1541 for (int i = index; i < this.pre_merge_items.Count; i++) {
1542 if (this.Items.Contains (this.pre_merge_items[i])) {
1543 item.Owner.Items.InsertNoOwnerOrLayout (this.Items.IndexOf (this.pre_merge_items[i]), item);
1548 // There aren't any items that are supposed to be after this item,
1549 // so just append it to the end.
1550 item.Owner.Items.AddNoOwnerOrLayout (item);