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 ToolStripTextDirection text_direction;
73 private Timer tooltip_timer;
74 private ToolTip.ToolTipWindow tooltip_window;
75 private bool show_item_tool_tips;
78 private ToolStripItem mouse_currently_over;
79 internal bool menu_selected;
80 private ToolStripItem tooltip_currently_showing;
83 #region Public Constructors
84 public ToolStrip () : this (null)
88 public ToolStrip (params ToolStripItem[] items) : base ()
90 SetStyle (ControlStyles.AllPaintingInWmPaint, true);
91 SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
92 SetStyle (ControlStyles.Selectable, false);
93 SetStyle (ControlStyles.SupportsTransparentBackColor, true);
95 this.SuspendLayout ();
97 this.items = new ToolStripItemCollection (this, items, true);
98 this.allow_merge = true;
100 this.back_color = Control.DefaultBackColor;
101 this.can_overflow = true;
102 base.CausesValidation = false;
103 this.default_drop_down_direction = ToolStripDropDownDirection.BelowRight;
104 this.displayed_items = new ToolStripItemCollection (this, null, true);
105 this.Dock = this.DefaultDock;
106 base.Font = new Font ("Tahoma", 8.25f);
107 this.fore_color = Control.DefaultForeColor;
108 this.grip_margin = this.DefaultGripMargin;
109 this.grip_style = ToolStripGripStyle.Visible;
110 this.image_scaling_size = new Size (16, 16);
111 this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
112 this.orientation = Orientation.Horizontal;
113 if (!(this is ToolStripDropDown))
114 this.overflow_button = new ToolStripOverflowButton (this);
115 this.renderer = null;
116 this.render_mode = ToolStripRenderMode.ManagerRenderMode;
117 this.show_item_tool_tips = this.DefaultShowItemToolTips;
118 base.TabStop = false;
119 this.text_direction = ToolStripTextDirection.Horizontal;
120 this.ResumeLayout ();
123 // Register with the ToolStripManager
124 ToolStripManager.AddToolStrip (this);
128 #region Public Properties
129 [DefaultValue (true)]
130 public bool AllowMerge {
131 get { return this.allow_merge; }
132 set { this.allow_merge = false; }
135 public override AnchorStyles Anchor {
136 get { return base.Anchor; }
137 set { base.Anchor = value; }
141 [EditorBrowsable (EditorBrowsableState.Never)]
142 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
143 public override bool AutoScroll {
144 get { return base.AutoScroll; }
145 set { base.AutoScroll = value; }
149 [EditorBrowsable (EditorBrowsableState.Never)]
150 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
151 public new Size AutoScrollMargin {
152 get { return base.AutoScrollMargin; }
153 set { base.AutoScrollMargin = value; }
157 [EditorBrowsable (EditorBrowsableState.Never)]
158 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
159 public new Size AutoScrollMinSize {
160 get { return base.AutoScrollMinSize; }
161 set { base.AutoScrollMinSize = value; }
165 [EditorBrowsable (EditorBrowsableState.Never)]
166 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
167 public new Point AutoScrollPosition {
168 get { return base.AutoScrollPosition; }
169 set { base.AutoScrollPosition = value; }
172 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
174 [EditorBrowsable (EditorBrowsableState.Always)]
175 [DefaultValue (true)]
176 public override bool AutoSize {
177 get { return base.AutoSize; }
178 set { base.AutoSize = value; }
181 new public Color BackColor {
182 get { return this.back_color; }
183 set { this.back_color = value; }
186 [DefaultValue (true)]
187 public bool CanOverflow {
188 get { return this.can_overflow; }
189 set { this.can_overflow = value; }
193 [DefaultValue (false)]
194 public new bool CausesValidation {
195 get { return base.CausesValidation; }
196 set { base.CausesValidation = value; }
199 [EditorBrowsable (EditorBrowsableState.Never)]
200 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
201 public new ControlCollection Controls {
202 get { return base.Controls; }
206 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
207 public override Cursor Cursor {
208 get { return base.Cursor; }
209 set { base.Cursor = value; }
213 public virtual ToolStripDropDownDirection DefaultDropDownDirection {
214 get { return this.default_drop_down_direction; }
216 if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value))
217 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value));
219 this.default_drop_down_direction = value;
223 public override Rectangle DisplayRectangle {
225 if (this.orientation == Orientation.Horizontal)
226 if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
227 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
229 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);
231 if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
232 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
234 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);
238 [DefaultValue (DockStyle.Top)]
239 public override DockStyle Dock {
240 get { return base.Dock; }
242 if (base.Dock != value) {
247 case DockStyle.Bottom:
249 this.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
252 case DockStyle.Right:
253 this.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow;
260 public override Font Font {
261 get { return base.Font; }
263 if (base.Font != value) {
266 foreach (ToolStripItem tsi in this.Items)
267 tsi.OnOwnerFontChanged (EventArgs.Empty);
273 public new Color ForeColor {
274 get { return this.fore_color; }
276 if (this.fore_color != value) {
277 this.fore_color = value;
278 this.OnForeColorChanged (EventArgs.Empty);
284 public ToolStripGripDisplayStyle GripDisplayStyle {
285 get { return this.orientation == Orientation.Vertical ? ToolStripGripDisplayStyle.Horizontal : ToolStripGripDisplayStyle.Vertical; }
288 public Padding GripMargin {
289 get { return this.grip_margin; }
291 if (this.grip_margin != value) {
292 this.grip_margin = value;
293 this.PerformLayout ();
299 public Rectangle GripRectangle {
301 if (this.grip_style == ToolStripGripStyle.Hidden)
302 return Rectangle.Empty;
304 if (this.orientation == Orientation.Horizontal)
305 return new Rectangle (this.grip_margin.Left + this.Padding.Left, this.Padding.Top, 3, this.Height);
307 return new Rectangle (this.Padding.Left, this.grip_margin.Top + this.Padding.Top, this.Width, 3);
311 [DefaultValue (ToolStripGripStyle.Visible)]
312 public ToolStripGripStyle GripStyle {
313 get { return this.grip_style; }
315 if (this.grip_style != value) {
316 if (!Enum.IsDefined (typeof (ToolStripGripStyle), value))
317 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripGripStyle", value));
318 this.grip_style = value;
319 this.PerformLayout ();
325 [EditorBrowsable (EditorBrowsableState.Never)]
326 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
327 public new bool HasChildren {
328 get { return base.HasChildren; }
332 [EditorBrowsable (EditorBrowsableState.Never)]
333 public new HScrollProperties HorizontalScroll {
334 get { return base.HorizontalScroll; }
338 [DefaultValue (null)]
339 public ImageList ImageList {
340 get { return this.image_list; }
341 set { this.image_list = value; }
344 [DefaultValue ("{Width=16, Height=16}")]
345 public Size ImageScalingSize {
346 get { return this.image_scaling_size; }
347 set { this.image_scaling_size = value; }
350 [MonoTODO ("Always returns false, dragging not implemented yet.")]
352 [EditorBrowsable (EditorBrowsableState.Advanced)]
353 public bool IsCurrentlyDragging {
354 get { return false; }
358 public bool IsDropDown {
360 if (this is ToolStripDropDown)
367 [MergableProperty (false)]
368 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
369 public virtual ToolStripItemCollection Items {
370 get { return this.items; }
373 public override LayoutEngine LayoutEngine {
375 if (layout_engine == null)
376 this.layout_engine = new ToolStripSplitStackLayout ();
378 return this.layout_engine;
383 [DefaultValue (null)]
384 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
385 public LayoutSettings LayoutSettings {
386 get { return this.layout_settings; }
387 set { this.layout_settings = value; }
390 [AmbientValue (ToolStripLayoutStyle.StackWithOverflow)]
391 public ToolStripLayoutStyle LayoutStyle {
392 get { return layout_style; }
394 if (this.layout_style != value) {
395 if (!Enum.IsDefined (typeof (ToolStripLayoutStyle), value))
396 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripLayoutStyle", value));
398 this.layout_style = value;
400 if (this.layout_style == ToolStripLayoutStyle.Flow)
401 this.layout_engine = new FlowLayout ();
403 this.layout_engine = new ToolStripSplitStackLayout ();
405 if (this.layout_style == ToolStripLayoutStyle.StackWithOverflow) {
406 if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right)
407 this.layout_style = ToolStripLayoutStyle.VerticalStackWithOverflow;
409 this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
412 if (this.layout_style == ToolStripLayoutStyle.HorizontalStackWithOverflow)
413 this.orientation = Orientation.Horizontal;
414 else if (this.layout_style == ToolStripLayoutStyle.VerticalStackWithOverflow)
415 this.orientation = Orientation.Vertical;
417 this.layout_settings = this.CreateLayoutSettings (value);
419 this.PerformLayout ();
420 this.OnLayoutStyleChanged (EventArgs.Empty);
426 public Orientation Orientation {
427 get { return this.orientation; }
431 [EditorBrowsable (EditorBrowsableState.Advanced)]
432 public ToolStripOverflowButton OverflowButton {
433 get { return this.overflow_button; }
437 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
438 public ToolStripRenderer Renderer {
440 if (this.render_mode == ToolStripRenderMode.ManagerRenderMode)
441 return ToolStripManager.Renderer;
443 return this.renderer;
446 if (this.renderer != value) {
447 this.renderer = value;
448 this.render_mode = ToolStripRenderMode.Custom;
449 this.PerformLayout ();
450 this.OnRendererChanged (EventArgs.Empty);
455 public ToolStripRenderMode RenderMode {
456 get { return this.render_mode; }
458 if (!Enum.IsDefined (typeof (ToolStripRenderMode), value))
459 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripRenderMode", value));
461 if (value == ToolStripRenderMode.Custom && this.renderer == null)
462 throw new NotSupportedException ("Must set Renderer property before setting RenderMode to Custom");
463 else if (value == ToolStripRenderMode.Professional)
464 this.Renderer = new ToolStripProfessionalRenderer ();
465 else if (value == ToolStripRenderMode.System)
466 this.Renderer = new ToolStripSystemRenderer ();
468 this.render_mode = value;
472 [DefaultValue (true)]
473 public bool ShowItemToolTips {
474 get { return this.show_item_tool_tips; }
475 set { this.show_item_tool_tips = value; }
478 [DefaultValue (false)]
479 public bool Stretch {
480 get { return this.stretch; }
481 set { this.stretch = value; }
484 [DefaultValue (false)]
486 public new bool TabStop {
487 get { return base.TabStop; }
488 set { base.TabStop = value; }
491 [DefaultValue (ToolStripTextDirection.Horizontal)]
492 public virtual ToolStripTextDirection TextDirection {
493 get { return this.text_direction; }
495 if (!Enum.IsDefined (typeof (ToolStripTextDirection), value))
496 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripTextDirection", value));
498 if (this.text_direction != value) {
499 this.text_direction = value;
501 this.PerformLayout (this, "TextDirection");
509 [EditorBrowsable (EditorBrowsableState.Never)]
510 public new VScrollProperties VerticalScroll {
511 get { return base.VerticalScroll; }
515 #region Protected Properties
516 protected virtual DockStyle DefaultDock { get { return DockStyle.Top; } }
517 protected virtual Padding DefaultGripMargin { get { return new Padding (2); } }
518 protected override Padding DefaultMargin { get { return Padding.Empty; } }
519 protected override Padding DefaultPadding { get { return new Padding (0, 0, 1, 0); } }
520 protected virtual bool DefaultShowItemToolTips { get { return true; } }
521 protected override Size DefaultSize { get { return new Size (100, 25); } }
522 protected internal virtual ToolStripItemCollection DisplayedItems { get { return this.displayed_items; } }
525 #region Public Methods
526 [EditorBrowsable (EditorBrowsableState.Never)]
527 public new Control GetChildAtPoint (Point point)
529 return base.GetChildAtPoint (point);
532 [EditorBrowsable (EditorBrowsableState.Never)]
533 public new Control GetChildAtPoint (Point pt, GetChildAtPointSkip skipValue)
535 return base.GetChildAtPoint (pt, skipValue);
538 public ToolStripItem GetItemAt (Point point)
540 foreach (ToolStripItem tsi in this.displayed_items)
541 if (tsi.Visible && tsi.Bounds.Contains (point))
547 public ToolStripItem GetItemAt (int x, int y)
549 return GetItemAt (new Point (x, y));
552 public virtual ToolStripItem GetNextItem (ToolStripItem start, ArrowDirection direction)
554 if (!Enum.IsDefined (typeof (ArrowDirection), direction))
555 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ArrowDirection", direction));
557 ToolStripItem current_best = null;
558 int current_best_point;
561 case ArrowDirection.Right:
562 current_best_point = int.MaxValue;
565 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
566 if (loop_tsi.Left >= start.Right && loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
567 current_best = loop_tsi;
568 current_best_point = loop_tsi.Left;
571 if (current_best == null)
572 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
573 if (loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
574 current_best = loop_tsi;
575 current_best_point = loop_tsi.Left;
579 case ArrowDirection.Up:
580 current_best_point = int.MinValue;
583 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
584 if (loop_tsi.Bottom <= start.Top && loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
585 current_best = loop_tsi;
586 current_best_point = loop_tsi.Top;
589 if (current_best == null)
590 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
591 if (loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
592 current_best = loop_tsi;
593 current_best_point = loop_tsi.Top;
597 case ArrowDirection.Left:
598 current_best_point = int.MinValue;
601 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
602 if (loop_tsi.Right <= start.Left && loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
603 current_best = loop_tsi;
604 current_best_point = loop_tsi.Left;
607 if (current_best == null)
608 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
609 if (loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
610 current_best = loop_tsi;
611 current_best_point = loop_tsi.Left;
615 case ArrowDirection.Down:
616 current_best_point = int.MaxValue;
619 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
620 if (loop_tsi.Top >= start.Bottom && loop_tsi.Bottom < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
621 current_best = loop_tsi;
622 current_best_point = loop_tsi.Top;
625 if (current_best == null)
626 foreach (ToolStripItem loop_tsi in this.DisplayedItems)
627 if (loop_tsi.Top < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) {
628 current_best = loop_tsi;
629 current_best_point = loop_tsi.Top;
638 [EditorBrowsable (EditorBrowsableState.Never)]
639 public void ResetMinimumSize ()
641 this.MinimumSize = new Size (-1, -1);
644 [EditorBrowsable (EditorBrowsableState.Never)]
645 public new void SetAutoScrollMargin (int x, int y)
647 base.SetAutoScrollMargin (x, y);
650 public override string ToString ()
652 return String.Format ("{0}, Name: {1}, Items: {2}", base.ToString(), this.Name, this.items.Count.ToString ());
656 #region Protected Methods
657 protected override AccessibleObject CreateAccessibilityInstance ()
659 AccessibleObject ao = new AccessibleObject (this);
661 ao.role = AccessibleRole.ToolBar;
666 protected override ControlCollection CreateControlsInstance ()
668 return base.CreateControlsInstance ();
671 protected internal virtual ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
674 return new ToolStripSeparator ();
676 if (this is ToolStripDropDown)
677 return new ToolStripMenuItem (text, image, onClick);
679 return new ToolStripButton (text, image, onClick);
682 protected virtual LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle layoutStyle)
684 switch (layoutStyle) {
685 case ToolStripLayoutStyle.Flow:
686 return new FlowLayoutSettings ();
687 case ToolStripLayoutStyle.Table:
688 //return new TableLayoutSettings ();
689 case ToolStripLayoutStyle.StackWithOverflow:
690 case ToolStripLayoutStyle.HorizontalStackWithOverflow:
691 case ToolStripLayoutStyle.VerticalStackWithOverflow:
697 protected override void Dispose (bool disposing)
700 ToolStripManager.RemoveToolStrip (this);
701 base.Dispose (disposing);
705 protected override void OnDockChanged (EventArgs e)
707 base.OnDockChanged (e);
710 protected override bool IsInputChar (char charCode)
712 return base.IsInputChar (charCode);
715 protected override bool IsInputKey (Keys keyData)
717 return base.IsInputKey (keyData);
720 protected override void OnEnabledChanged (EventArgs e)
722 base.OnEnabledChanged (e);
724 foreach (ToolStripItem tsi in this.Items)
725 tsi.OnParentEnabledChanged (EventArgs.Empty);
728 protected override void OnFontChanged (EventArgs e)
730 base.OnFontChanged (e);
733 protected override void OnHandleCreated (EventArgs e)
735 base.OnHandleCreated (e);
738 protected override void OnHandleDestroyed (EventArgs e)
740 base.OnHandleDestroyed (e);
743 protected override void OnInvalidated (InvalidateEventArgs e)
745 base.OnInvalidated (e);
748 protected internal virtual void OnItemAdded (ToolStripItemEventArgs e)
750 e.Item.Available = true;
751 e.Item.SetPlacement (ToolStripItemPlacement.Main);
755 this.PerformLayout ();
757 ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemAddedEvent]);
762 protected virtual void OnItemClicked (ToolStripItemClickedEventArgs e)
764 if (this.KeyboardActive)
765 ToolStripManager.SetActiveToolStrip (null);
767 ToolStripItemClickedEventHandler eh = (ToolStripItemClickedEventHandler)(Events [ItemClickedEvent]);
772 protected internal virtual void OnItemRemoved (ToolStripItemEventArgs e)
774 ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemRemovedEvent]);
779 protected override void OnLayout (LayoutEventArgs e)
784 this.SetDisplayedItems ();
785 this.OnLayoutCompleted (EventArgs.Empty);
789 protected virtual void OnLayoutCompleted (EventArgs e)
791 EventHandler eh = (EventHandler)(Events [LayoutCompletedEvent]);
796 protected virtual void OnLayoutStyleChanged (EventArgs e)
798 EventHandler eh = (EventHandler)(Events[LayoutStyleChangedEvent]);
803 protected override void OnLeave (EventArgs e)
808 protected override void OnLostFocus (EventArgs e)
810 base.OnLostFocus (e);
813 protected override void OnMouseCaptureChanged (EventArgs e)
815 base.OnMouseCaptureChanged (e);
818 protected override void OnMouseDown (MouseEventArgs mea)
820 if (mouse_currently_over != null)
822 if (this is MenuStrip && !(mouse_currently_over as ToolStripMenuItem).HasDropDownItems) {
824 (this as MenuStrip).FireMenuActivate ();
829 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseDown);
831 if (this is MenuStrip && !menu_selected) {
832 (this as MenuStrip).FireMenuActivate ();
833 menu_selected = true;
836 if (this is MenuStrip)
837 this.HideMenus (true, ToolStripDropDownCloseReason.AppClicked);
840 if (this is MenuStrip)
841 this.Capture = false;
843 base.OnMouseDown (mea);
846 protected override void OnMouseLeave (EventArgs e)
848 if (mouse_currently_over != null) {
849 MouseLeftItem (mouse_currently_over);
850 mouse_currently_over.FireEvent (e, ToolStripItemEventType.MouseLeave);
851 mouse_currently_over = null;
854 base.OnMouseLeave (e);
857 protected override void OnMouseMove (MouseEventArgs mea)
860 // Find the item we are now
861 if (this.overflow_button != null && this.overflow_button.Visible && this.overflow_button.Bounds.Contains (mea.Location))
862 tsi = this.overflow_button;
864 tsi = this.GetItemAt (mea.X, mea.Y);
867 // If we were already hovering on this item, just send a mouse move
868 if (tsi == mouse_currently_over)
869 tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
871 // If we were over a different item, fire a mouse leave on it
872 if (mouse_currently_over != null) {
874 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
877 // Set the new item we are currently over
878 mouse_currently_over = tsi;
880 // Fire mouse enter and mouse move
881 tsi.FireEvent (mea, ToolStripItemEventType.MouseEnter);
882 MouseEnteredItem (tsi);
883 tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
885 // If we're over something with a drop down, show it
886 if (menu_selected && mouse_currently_over.Enabled && mouse_currently_over is ToolStripDropDownItem && (mouse_currently_over as ToolStripDropDownItem).HasDropDownItems)
887 (mouse_currently_over as ToolStripDropDownItem).ShowDropDown ();
890 // We're not over anything now, just fire the mouse leave on what we used to be over
891 if (mouse_currently_over != null) {
893 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
894 mouse_currently_over = null;
898 base.OnMouseMove (mea);
901 protected override void OnMouseUp (MouseEventArgs mea)
903 // If we're currently over an item (set in MouseMove)
904 if (mouse_currently_over != null) {
905 // Fire the item's MouseUp event
906 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseUp);
908 // The event handler may have blocked until the mouse moved off of the ToolStripItem
909 if (mouse_currently_over == null)
912 // Fire our ItemClicked event
913 OnItemClicked (new ToolStripItemClickedEventArgs (mouse_currently_over));
916 base.OnMouseUp (mea);
919 protected override void OnPaint (PaintEventArgs e)
924 this.OnPaintGrip (e);
926 // Make each item draw itself
927 foreach (ToolStripItem tsi in this.displayed_items) {
928 e.Graphics.TranslateTransform (tsi.Bounds.Left, tsi.Bounds.Top);
929 tsi.FireEvent (e, ToolStripItemEventType.Paint);
930 e.Graphics.ResetTransform ();
933 // Paint the Overflow button if it's visible
934 if (this.overflow_button != null && this.overflow_button.Visible) {
935 e.Graphics.TranslateTransform (this.overflow_button.Bounds.Left, this.overflow_button.Bounds.Top);
936 this.overflow_button.FireEvent (e, ToolStripItemEventType.Paint);
937 e.Graphics.ResetTransform ();
940 Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size);
942 ToolStripRenderEventArgs pevent = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, Color.Empty);
943 pevent.InternalConnectedArea = CalculateConnectedArea ();
945 this.Renderer.DrawToolStripBorder (pevent);
948 [EditorBrowsable (EditorBrowsableState.Advanced)]
949 protected override void OnPaintBackground (PaintEventArgs pevent)
951 base.OnPaintBackground (pevent);
953 Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size);
954 ToolStripRenderEventArgs e = new ToolStripRenderEventArgs (pevent.Graphics, this, affected_bounds, SystemColors.Control);
956 this.Renderer.DrawToolStripBackground (e);
959 protected internal virtual void OnPaintGrip (PaintEventArgs e)
961 // Never draw a grip with these two layouts
962 if (this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
965 PaintEventHandler eh = (PaintEventHandler)(Events [PaintGripEvent]);
969 if (!(this is MenuStrip)) {
970 if (this.orientation == Orientation.Horizontal)
971 e.Graphics.TranslateTransform (2, 0);
973 e.Graphics.TranslateTransform (0, 2);
976 this.Renderer.DrawGrip (new ToolStripGripRenderEventArgs (e.Graphics, this, this.GripRectangle, this.GripDisplayStyle, this.grip_style));
977 e.Graphics.ResetTransform ();
980 protected virtual void OnRendererChanged (EventArgs e)
982 EventHandler eh = (EventHandler)(Events [RendererChangedEvent]);
987 [EditorBrowsable (EditorBrowsableState.Advanced)]
988 protected override void OnRightToLeftChanged (EventArgs e)
990 base.OnRightToLeftChanged (e);
992 foreach (ToolStripItem tsi in this.Items)
993 tsi.OnParentRightToLeftChanged (e);
996 protected override void OnScroll (ScrollEventArgs se)
1001 protected override void OnTabStopChanged (EventArgs e)
1003 base.OnTabStopChanged (e);
1006 protected override void OnVisibleChanged (EventArgs e)
1008 base.OnVisibleChanged (e);
1011 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
1013 return base.ProcessCmdKey (ref msg, keyData);
1016 protected override bool ProcessDialogKey (Keys keyData)
1018 if (!this.KeyboardActive)
1021 // Give each item a chance to handle the key
1022 foreach (ToolStripItem tsi in this.Items)
1023 if (tsi.ProcessDialogKey (keyData))
1026 // See if I want to handle it
1027 if (this.ProcessArrowKey (keyData))
1030 ToolStrip ts = null;
1034 this.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1037 case Keys.Control | Keys.Tab:
1038 ts = ToolStripManager.GetNextToolStrip (this, true);
1041 foreach (ToolStripItem tsi in this.Items)
1042 tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1044 ToolStripManager.SetActiveToolStrip (ts);
1045 ts.SelectNextToolStripItem (null, true);
1049 case Keys.Control | Keys.Shift | Keys.Tab:
1050 ts = ToolStripManager.GetNextToolStrip (this, false);
1053 foreach (ToolStripItem tsi in this.Items)
1054 tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1056 ToolStripManager.SetActiveToolStrip (ts);
1057 ts.SelectNextToolStripItem (null, true);
1065 if (GetCurrentlySelectedItem () is ToolStripControlHost)
1070 return base.ProcessDialogKey (keyData);
1073 protected override bool ProcessMnemonic (char charCode)
1075 // If any item has an explicit mnemonic, it gets the message
1076 foreach (ToolStripItem tsi in this.Items)
1077 if (tsi.Enabled && tsi.Visible && Control.IsMnemonic (charCode, tsi.Text))
1078 return tsi.ProcessMnemonic (charCode);
1080 string code = Char.ToUpper (charCode).ToString ();
1082 // If any item's text starts with our letter, it gets the message
1083 if (this is MenuStrip)
1084 foreach (ToolStripItem tsi in this.Items)
1085 if (tsi.Enabled && tsi.Visible && tsi.Text.Length > 0 && tsi.Text.ToUpper ().StartsWith (code))
1086 return tsi.ProcessMnemonic (charCode);
1088 return base.ProcessMnemonic (charCode);
1091 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1093 base.SetBoundsCore (x, y, width, height, specified);
1096 protected virtual void SetDisplayedItems ()
1098 this.displayed_items.Clear ();
1100 foreach (ToolStripItem tsi in this.items)
1101 if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) {
1102 this.displayed_items.AddNoOwnerOrLayout (tsi);
1105 else if (tsi.Placement == ToolStripItemPlacement.Overflow)
1106 tsi.Parent = this.OverflowButton.DropDown;
1108 if (this.OverflowButton != null)
1109 this.OverflowButton.DropDown.SetDisplayedItems ();
1112 protected internal void SetItemLocation (ToolStripItem item, Point location)
1115 throw new ArgumentNullException ("item");
1117 if (item.Owner != this)
1118 throw new NotSupportedException ("The item is not owned by this ToolStrip");
1120 item.SetBounds (new Rectangle (location, item.Size));
1123 protected internal static void SetItemParent (ToolStripItem item, ToolStrip parent)
1125 if (item.Owner != null) {
1126 item.Owner.Items.RemoveNoOwnerOrLayout (item);
1128 if (item.Owner is ToolStripOverflow)
1129 (item.Owner as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
1132 parent.Items.AddNoOwnerOrLayout (item);
1133 item.Parent = parent;
1136 protected override void SetVisibleCore (bool value)
1138 base.SetVisibleCore (value);
1141 protected override void WndProc (ref Message m)
1143 base.WndProc (ref m);
1147 #region Public Events
1148 static object ItemAddedEvent = new object ();
1149 static object ItemClickedEvent = new object ();
1150 static object ItemRemovedEvent = new object ();
1151 static object LayoutCompletedEvent = new object ();
1152 static object LayoutStyleChangedEvent = new object ();
1153 static object PaintGripEvent = new object ();
1154 static object RendererChangedEvent = new object ();
1157 [EditorBrowsable (EditorBrowsableState.Always)]
1158 public new event EventHandler AutoSizeChanged {
1159 add { base.AutoSizeChanged += value; }
1160 remove { base.AutoSizeChanged -= value; }
1164 public new event EventHandler CausesValidationChanged {
1165 add { base.CausesValidationChanged += value; }
1166 remove { base.CausesValidationChanged -= value; }
1170 [EditorBrowsable (EditorBrowsableState.Never)]
1171 public new event ControlEventHandler ControlAdded {
1172 add { base.ControlAdded += value; }
1173 remove { base.ControlAdded -= value; }
1177 [EditorBrowsable (EditorBrowsableState.Never)]
1178 public new event ControlEventHandler ControlRemoved {
1179 add { base.ControlRemoved += value; }
1180 remove { base.ControlRemoved -= value; }
1184 public new event EventHandler CursorChanged {
1185 add { base.CursorChanged += value; }
1186 remove { base.CursorChanged -= value; }
1190 public new event EventHandler ForeColorChanged {
1191 add { base.ForeColorChanged += value; }
1192 remove { base.ForeColorChanged -= value; }
1195 public event ToolStripItemEventHandler ItemAdded {
1196 add { Events.AddHandler (ItemAddedEvent, value); }
1197 remove { Events.RemoveHandler (ItemAddedEvent, value); }
1200 public event ToolStripItemClickedEventHandler ItemClicked {
1201 add { Events.AddHandler (ItemClickedEvent, value); }
1202 remove { Events.RemoveHandler (ItemClickedEvent, value); }
1205 public event ToolStripItemEventHandler ItemRemoved {
1206 add { Events.AddHandler (ItemRemovedEvent, value); }
1207 remove { Events.RemoveHandler (ItemRemovedEvent, value); }
1210 public event EventHandler LayoutCompleted {
1211 add { Events.AddHandler (LayoutCompletedEvent, value); }
1212 remove { Events.RemoveHandler (LayoutCompletedEvent, value); }
1215 public event EventHandler LayoutStyleChanged {
1216 add { Events.AddHandler (LayoutStyleChangedEvent, value); }
1217 remove { Events.RemoveHandler (LayoutStyleChangedEvent, value); }
1220 public event PaintEventHandler PaintGrip {
1221 add { Events.AddHandler (PaintGripEvent, value); }
1222 remove { Events.RemoveHandler (PaintGripEvent, value); }
1225 public event EventHandler RendererChanged {
1226 add { Events.AddHandler (RendererChangedEvent, value); }
1227 remove { Events.RemoveHandler (RendererChangedEvent, value); }
1231 #region Internal Properties
1232 internal virtual bool KeyboardActive
1234 get { return this.keyboard_active; }
1236 if (this.keyboard_active != value) {
1237 this.keyboard_active = value;
1240 Application.KeyboardCapture = this;
1241 else if (Application.KeyboardCapture == this)
1242 Application.KeyboardCapture = null;
1244 // Redraw for mnemonic underlines
1251 #region Private Methods
1252 internal virtual Rectangle CalculateConnectedArea ()
1254 return Rectangle.Empty;
1257 internal void ChangeSelection (ToolStripItem nextItem)
1259 if (Application.KeyboardCapture != this)
1260 ToolStripManager.SetActiveToolStrip (this);
1262 foreach (ToolStripItem tsi in this.Items)
1263 if (tsi != nextItem)
1264 tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1268 if (nextItem.Parent is MenuStrip && (nextItem.Parent as MenuStrip).MenuDroppedDown)
1269 (nextItem as ToolStripMenuItem).HandleAutoExpansion ();
1272 internal virtual void Dismiss ()
1274 this.Dismiss (ToolStripDropDownCloseReason.AppClicked);
1277 internal virtual void Dismiss (ToolStripDropDownCloseReason reason)
1279 // Release our stranglehold on the keyboard
1280 this.KeyboardActive = false;
1282 // Set our drop down flag to false;
1283 this.menu_selected = false;
1285 // Make sure all of our items are deselected and repainted
1286 foreach (ToolStripItem tsi in this.Items)
1287 tsi.Dismiss (reason);
1290 private void DoAutoSize ()
1292 if (this.AutoSize == true && this.Dock == DockStyle.None)
1293 this.Size = GetPreferredSize (Size.Empty);
1295 if (this.AutoSize == true && this.Orientation == Orientation.Horizontal && (this.Dock == DockStyle.Top || this.Dock == DockStyle.Bottom))
1296 this.Height = GetPreferredSize (Size.Empty).Height;
1299 internal ToolStripItem GetCurrentlySelectedItem ()
1301 foreach (ToolStripItem tsi in this.DisplayedItems)
1308 public override Size GetPreferredSize (Size proposedSize)
1310 Size new_size = new Size (0, this.Height);
1312 if (this.orientation == Orientation.Vertical) {
1313 foreach (ToolStripItem tsi in this.items)
1314 if (tsi.GetPreferredSize (Size.Empty).Height + tsi.Margin.Top + tsi.Margin.Bottom > new_size.Height)
1315 new_size.Height = tsi.GetPreferredSize (Size.Empty).Height + tsi.Margin.Top + tsi.Margin.Bottom;
1317 new_size.Height += this.Padding.Top + this.Padding.Bottom;
1318 new_size.Width = this.Width;
1320 foreach (ToolStripItem tsi in this.items)
1321 if (tsi.Available) {
1322 Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
1323 new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right;
1325 if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height))
1326 new_size.Height = (this.Padding.Vertical + tsi_preferred.Height);
1330 new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4);
1334 internal virtual ToolStrip GetTopLevelToolStrip ()
1339 internal virtual void HandleItemClick (ToolStripItem dismissingItem)
1341 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.ItemClicked);
1342 this.OnItemClicked (new ToolStripItemClickedEventArgs (dismissingItem));
1345 internal void HideMenus (bool release, ToolStripDropDownCloseReason reason)
1347 if (this is MenuStrip && release && menu_selected)
1348 (this as MenuStrip).FireMenuDeactivate ();
1351 menu_selected = false;
1353 NotifySelectedChanged (null);
1356 internal void NotifySelectedChanged (ToolStripItem tsi)
1358 foreach (ToolStripItem tsi2 in this.DisplayedItems)
1360 if (tsi2 is ToolStripDropDownItem)
1361 (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1363 if (this.OverflowButton != null) {
1364 ToolStripItemCollection tsic = this.OverflowButton.DropDown.DisplayedItems;
1366 foreach (ToolStripItem tsi2 in tsic)
1368 if (tsi2 is ToolStripDropDownItem)
1369 (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1371 this.OverflowButton.HideDropDown ();
1374 foreach (ToolStripItem tsi2 in this.Items)
1376 tsi2.Dismiss (ToolStripDropDownCloseReason.Keyboard);
1379 internal virtual bool OnMenuKey ()
1384 internal virtual bool ProcessArrowKey (Keys keyData)
1390 tsi = this.GetCurrentlySelectedItem ();
1392 if (tsi is ToolStripControlHost)
1395 tsi = this.SelectNextToolStripItem (tsi, true);
1397 if (tsi is ToolStripControlHost)
1398 (tsi as ToolStripControlHost).Focus ();
1402 tsi = this.GetCurrentlySelectedItem ();
1404 tsi = this.SelectNextToolStripItem (tsi, true);
1406 if (tsi is ToolStripControlHost)
1407 (tsi as ToolStripControlHost).Focus ();
1411 tsi = this.GetCurrentlySelectedItem ();
1413 if (tsi is ToolStripControlHost)
1416 tsi = this.SelectNextToolStripItem (tsi, false);
1418 if (tsi is ToolStripControlHost)
1419 (tsi as ToolStripControlHost).Focus ();
1422 case Keys.Shift | Keys.Tab:
1423 tsi = this.GetCurrentlySelectedItem ();
1425 tsi = this.SelectNextToolStripItem (tsi, false);
1427 if (tsi is ToolStripControlHost)
1428 (tsi as ToolStripControlHost).Focus ();
1436 internal virtual ToolStripItem SelectNextToolStripItem (ToolStripItem start, bool forward)
1438 ToolStripItem next_item = this.GetNextItem (start, forward ? ArrowDirection.Right : ArrowDirection.Left);
1440 this.ChangeSelection (next_item);
1442 if (next_item is ToolStripControlHost)
1443 (next_item as ToolStripControlHost).Focus ();
1448 #region Stuff for ToolTips
1449 private void MouseEnteredItem (ToolStripItem item)
1451 if (this.show_item_tool_tips) {
1452 tooltip_currently_showing = item;
1453 ToolTipTimer.Start ();
1457 private void MouseLeftItem (ToolStripItem item)
1459 ToolTipTimer.Stop ();
1460 ToolTipWindow.Hide ();
1461 tooltip_currently_showing = null;
1464 private Timer ToolTipTimer {
1466 if (tooltip_timer == null) {
1467 tooltip_timer = new Timer ();
1468 tooltip_timer.Enabled = false;
1469 tooltip_timer.Interval = 500;
1470 tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick);
1473 return tooltip_timer;
1477 private ToolTip.ToolTipWindow ToolTipWindow {
1479 if (tooltip_window == null)
1480 tooltip_window = new ToolTip.ToolTipWindow ();
1482 return tooltip_window;
1486 private void ToolTipTimer_Tick (object o, EventArgs args)
1488 string tooltip = tooltip_currently_showing.GetToolTip ();
1490 if (!string.IsNullOrEmpty (tooltip))
1491 ToolTipWindow.Present (this, tooltip);
1493 tooltip_currently_showing.FireEvent (EventArgs.Empty, ToolStripItemEventType.MouseHover);
1495 ToolTipTimer.Stop ();
1499 #region Stuff for Merging
1500 internal ToolStrip CurrentlyMergedWith {
1501 get { return this.currently_merged_with; }
1502 set { this.currently_merged_with = value; }
1505 internal List<ToolStripItem> HiddenMergedItems {
1507 if (this.hidden_merged_items == null)
1508 this.hidden_merged_items = new List<ToolStripItem> ();
1510 return this.hidden_merged_items;
1514 internal bool IsCurrentlyMerged {
1515 get { return this.is_currently_merged; }
1517 this.is_currently_merged = value;
1519 if (!value && this is MenuStrip)
1520 foreach (ToolStripMenuItem tsmi in this.Items)
1521 tsmi.DropDown.IsCurrentlyMerged = value;
1525 internal void BeginMerge ()
1527 if (!IsCurrentlyMerged) {
1528 IsCurrentlyMerged = true;
1530 if (this.pre_merge_items == null) {
1531 this.pre_merge_items = new List<ToolStripItem> ();
1533 foreach (ToolStripItem tsi in this.Items)
1534 this.pre_merge_items.Add (tsi);
1539 internal void RevertMergeItem (ToolStripItem item)
1543 // Remove it from it's current Parent
1544 if (item.Parent != null && item.Parent != this) {
1545 if (item.Parent is ToolStripOverflow)
1546 (item.Parent as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
1548 item.Parent.Items.RemoveNoOwnerOrLayout (item);
1550 item.Parent = item.Owner;
1553 // Find where the item was before the merge
1554 index = item.Owner.pre_merge_items.IndexOf (item);
1556 // Find the first pre-merge item that was after this item, that
1557 // is currently in the Items collection. Insert our item before
1559 for (int i = index; i < this.pre_merge_items.Count; i++) {
1560 if (this.Items.Contains (this.pre_merge_items[i])) {
1561 item.Owner.Items.InsertNoOwnerOrLayout (this.Items.IndexOf (this.pre_merge_items[i]), item);
1566 // There aren't any items that are supposed to be after this item,
1567 // so just append it to the end.
1568 item.Owner.Items.AddNoOwnerOrLayout (item);