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;
37 namespace System.Windows.Forms
40 [ClassInterface (ClassInterfaceType.AutoDispatch)]
41 [DefaultEvent ("ItemClicked")]
42 [DefaultProperty ("Items")]
43 public class ToolStrip : ScrollableControl, IComponent, IDisposable
45 #region Private Variables
46 private bool allow_merge;
47 private Color back_color;
48 private bool can_overflow;
49 private ToolStrip currently_merged_with;
50 private ToolStripDropDownDirection default_drop_down_direction;
51 internal ToolStripItemCollection displayed_items;
52 private Color fore_color;
53 private Padding grip_margin;
54 private ToolStripGripStyle grip_style;
55 private List<ToolStripItem> hidden_merged_items;
56 private ImageList image_list;
57 private Size image_scaling_size;
58 private bool is_currently_merged;
59 private ToolStripItemCollection items;
60 private LayoutEngine layout_engine;
61 private LayoutSettings layout_settings;
62 private ToolStripLayoutStyle layout_style;
63 private Orientation orientation;
64 private ToolStripOverflowButton overflow_button;
65 private List<ToolStripItem> pre_merge_items;
66 private ToolStripRenderer renderer;
67 private ToolStripRenderMode render_mode;
68 private Timer tooltip_timer;
69 private ToolTip.ToolTipWindow tooltip_window;
70 private bool show_item_tool_tips;
73 private ToolStripItem mouse_currently_over;
74 private bool menu_selected;
75 private ToolStripItem tooltip_currently_showing;
78 #region Public Constructors
79 public ToolStrip () : this (null)
83 public ToolStrip (params ToolStripItem[] items) : base ()
85 SetStyle (ControlStyles.AllPaintingInWmPaint, true);
86 SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
87 SetStyle (ControlStyles.Selectable, false);
88 SetStyle (ControlStyles.SupportsTransparentBackColor, true);
90 this.SuspendLayout ();
91 this.items = new ToolStripItemCollection (this, items);
92 this.allow_merge = true;
94 this.back_color = Control.DefaultBackColor;
95 this.can_overflow = true;
96 base.CausesValidation = false;
97 this.default_drop_down_direction = ToolStripDropDownDirection.BelowRight;
98 this.displayed_items = new ToolStripItemCollection (this, null);
99 this.Dock = this.DefaultDock;
100 base.Font = new Font ("Tahoma", 8.25f);
101 this.fore_color = Control.DefaultForeColor;
102 this.grip_margin = this.DefaultGripMargin;
103 this.grip_style = ToolStripGripStyle.Visible;
104 this.image_scaling_size = new Size (16, 16);
105 this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
106 this.orientation = Orientation.Horizontal;
107 if (!(this is ToolStripDropDown))
108 this.overflow_button = new ToolStripOverflowButton (this);
109 this.Padding = this.DefaultPadding;
110 this.renderer = null;
111 this.render_mode = ToolStripRenderMode.ManagerRenderMode;
112 this.show_item_tool_tips = this.DefaultShowItemToolTips;
113 base.TabStop = false;
114 this.ResumeLayout ();
117 // Register with the ToolStripManager
118 ToolStripManager.AddToolStrip (this);
122 #region Public Properties
123 public bool AllowMerge {
124 get { return this.allow_merge; }
125 set { this.allow_merge = false; }
128 public override AnchorStyles Anchor {
129 get { return base.Anchor; }
130 set { base.Anchor = value; }
134 [EditorBrowsable (EditorBrowsableState.Never)]
135 public override bool AutoScroll {
136 get { return base.AutoScroll; }
137 set { base.AutoScroll = value; }
141 [EditorBrowsable (EditorBrowsableState.Never)]
142 public new Size AutoScrollMargin {
143 get { return base.AutoScrollMargin; }
144 set { base.AutoScrollMargin = value; }
148 [EditorBrowsable (EditorBrowsableState.Never)]
149 public new Size AutoScrollMinSize {
150 get { return base.AutoScrollMinSize; }
151 set { base.AutoScrollMinSize = value; }
155 [EditorBrowsable (EditorBrowsableState.Never)]
156 public new Point AutoScrollPosition {
157 get { return base.AutoScrollPosition; }
158 set { base.AutoScrollPosition = value; }
161 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
163 [EditorBrowsable (EditorBrowsableState.Always)]
164 [DefaultValue (true)]
165 public override bool AutoSize {
166 get { return base.AutoSize; }
167 set { base.AutoSize = value; }
170 new public Color BackColor {
171 get { return this.back_color; }
172 set { this.back_color = value; }
175 [DefaultValue (true)]
176 public bool CanOverflow {
177 get { return this.can_overflow; }
178 set { this.can_overflow = value; }
182 [DefaultValue (false)]
183 public new bool CausesValidation {
184 get { return base.CausesValidation; }
185 set { base.CausesValidation = value; }
188 [EditorBrowsable (EditorBrowsableState.Never)]
189 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
190 public new ControlCollection Controls {
191 get { return base.Controls; }
195 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
196 public override Cursor Cursor {
197 get { return base.Cursor; }
198 set { base.Cursor = value; }
202 public virtual ToolStripDropDownDirection DefaultDropDownDirection {
203 get { return this.default_drop_down_direction; }
205 if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value))
206 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value));
208 this.default_drop_down_direction = value;
212 public override Rectangle DisplayRectangle {
214 if (this.orientation == Orientation.Horizontal)
215 if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
216 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
218 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);
220 if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
221 return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical);
223 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);
227 [DefaultValue (DockStyle.Top)]
228 public override DockStyle Dock {
229 get { return base.Dock; }
231 if (base.Dock != value) {
236 case DockStyle.Bottom:
238 this.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;
241 case DockStyle.Right:
242 this.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow;
249 public override Font Font {
250 get { return base.Font; }
252 if (base.Font != value) {
255 foreach (ToolStripItem tsi in this.Items)
256 tsi.OnOwnerFontChanged (EventArgs.Empty);
262 public new Color ForeColor {
263 get { return this.fore_color; }
265 if (this.fore_color != value) {
266 this.fore_color = value;
267 this.OnForeColorChanged (EventArgs.Empty);
273 public ToolStripGripDisplayStyle GripDisplayStyle {
274 get { return this.orientation == Orientation.Vertical ? ToolStripGripDisplayStyle.Horizontal : ToolStripGripDisplayStyle.Vertical; }
277 public Padding GripMargin {
278 get { return this.grip_margin; }
280 if (this.grip_margin != value) {
281 this.grip_margin = value;
282 this.PerformLayout ();
288 public Rectangle GripRectangle {
290 if (this.grip_style == ToolStripGripStyle.Hidden)
291 return Rectangle.Empty;
293 if (this.orientation == Orientation.Horizontal)
294 return new Rectangle (this.grip_margin.Left + this.Padding.Left, this.Padding.Top, 3, this.Height);
296 return new Rectangle (this.Padding.Left, this.grip_margin.Top + this.Padding.Top, this.Width, 3);
300 [DefaultValue (ToolStripGripStyle.Visible)]
301 public ToolStripGripStyle GripStyle {
302 get { return this.grip_style; }
304 if (this.grip_style != value) {
305 if (!Enum.IsDefined (typeof (ToolStripGripStyle), value))
306 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripGripStyle", value));
307 this.grip_style = value;
308 this.PerformLayout ();
314 [EditorBrowsable (EditorBrowsableState.Never)]
315 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
316 public new bool HasChildren {
317 get { return base.HasChildren; }
321 [EditorBrowsable (EditorBrowsableState.Never)]
322 public new HScrollProperties HorizontalScroll {
323 get { return base.HorizontalScroll; }
327 [DefaultValue (null)]
328 public ImageList ImageList {
329 get { return this.image_list; }
330 set { this.image_list = value; }
333 [DefaultValue ("{Width=16, Height=16}")]
334 public Size ImageScalingSize {
335 get { return this.image_scaling_size; }
336 set { this.image_scaling_size = value; }
339 [MonoTODO ("Always returns false, dragging not implemented yet.")]
341 [EditorBrowsable (EditorBrowsableState.Advanced)]
342 public bool IsCurrentlyDragging {
343 get { return false; }
347 public bool IsDropDown {
349 if (this is ToolStripDropDown)
356 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
357 public virtual ToolStripItemCollection Items {
358 get { return this.items; }
361 public override LayoutEngine LayoutEngine {
363 if (layout_engine == null)
364 this.layout_engine = new ToolStripSplitStackLayout ();
366 return this.layout_engine;
371 [DefaultValue (null)]
372 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
373 public LayoutSettings LayoutSettings {
374 get { return this.layout_settings; }
375 set { this.layout_settings = value; }
378 [AmbientValue (ToolStripLayoutStyle.StackWithOverflow)]
379 public ToolStripLayoutStyle LayoutStyle {
380 get { return layout_style; }
382 if (this.layout_style != value) {
383 if (!Enum.IsDefined (typeof (ToolStripLayoutStyle), value))
384 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripLayoutStyle", value));
386 this.layout_style = value;
388 if (this.layout_style == ToolStripLayoutStyle.Flow)
389 this.layout_engine = new FlowLayout ();
391 this.layout_engine = new ToolStripSplitStackLayout ();
393 if (this.layout_style == ToolStripLayoutStyle.StackWithOverflow) {
394 if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right)
395 this.layout_style = ToolStripLayoutStyle.VerticalStackWithOverflow;
397 this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow;
400 if (this.layout_style == ToolStripLayoutStyle.HorizontalStackWithOverflow)
401 this.orientation = Orientation.Horizontal;
402 else if (this.layout_style == ToolStripLayoutStyle.VerticalStackWithOverflow)
403 this.orientation = Orientation.Vertical;
405 this.layout_settings = this.CreateLayoutSettings (value);
407 this.PerformLayout ();
408 this.OnLayoutStyleChanged (EventArgs.Empty);
414 public Orientation Orientation {
415 get { return this.orientation; }
419 [EditorBrowsable (EditorBrowsableState.Advanced)]
420 public ToolStripOverflowButton OverflowButton {
421 get { return this.overflow_button; }
425 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
426 public ToolStripRenderer Renderer {
428 if (this.render_mode == ToolStripRenderMode.ManagerRenderMode)
429 return ToolStripManager.Renderer;
431 return this.renderer;
434 if (this.renderer != value) {
435 this.renderer = value;
436 this.render_mode = ToolStripRenderMode.Custom;
437 this.PerformLayout ();
438 this.OnRendererChanged (EventArgs.Empty);
443 public ToolStripRenderMode RenderMode {
444 get { return this.render_mode; }
446 if (!Enum.IsDefined (typeof (ToolStripRenderMode), value))
447 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripRenderMode", value));
449 if (value == ToolStripRenderMode.Custom && this.renderer == null)
450 throw new NotSupportedException ("Must set Renderer property before setting RenderMode to Custom");
451 if (value == ToolStripRenderMode.Professional || value == ToolStripRenderMode.System)
452 this.Renderer = new ToolStripProfessionalRenderer ();
454 this.render_mode = value;
458 [DefaultValue (true)]
459 public bool ShowItemToolTips {
460 get { return this.show_item_tool_tips; }
461 set { this.show_item_tool_tips = value; }
464 [DefaultValue (false)]
465 public bool Stretch {
466 get { return this.stretch; }
467 set { this.stretch = value; }
470 [DefaultValue (false)]
472 public new bool TabStop {
473 get { return base.TabStop; }
474 set { base.TabStop = value; }
478 [EditorBrowsable (EditorBrowsableState.Never)]
479 public new VScrollProperties VerticalScroll {
480 get { return base.VerticalScroll; }
484 #region Protected Properties
485 protected virtual DockStyle DefaultDock { get { return DockStyle.Top; } }
486 protected virtual Padding DefaultGripMargin { get { return new Padding (2); } }
487 protected override Padding DefaultMargin { get { return Padding.Empty; } }
488 protected override Padding DefaultPadding { get { return new Padding (0, 0, 1, 0); } }
489 protected virtual bool DefaultShowItemToolTips { get { return true; } }
490 protected override Size DefaultSize { get { return new Size (100, 25); } }
491 protected internal virtual ToolStripItemCollection DisplayedItems { get { return this.displayed_items; } }
494 #region Public Methods
495 public new Control GetChildAtPoint (Point point)
497 return base.GetChildAtPoint (point);
500 public ToolStripItem GetItemAt (Point point)
502 foreach (ToolStripItem tsi in this.displayed_items)
503 if (tsi.Visible && tsi.Bounds.Contains (point))
509 public ToolStripItem GetItemAt (int x, int y)
511 return GetItemAt (new Point (x, y));
514 public virtual ToolStripItem GetNextItem (ToolStripItem start, ArrowDirection direction)
516 if (!Enum.IsDefined (typeof (ArrowDirection), direction))
517 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ArrowDirection", direction));
519 int index = this.items.IndexOf (start);
522 case ArrowDirection.Left:
523 case ArrowDirection.Up:
525 return this.items[index - 1];
527 return this.items[this.items.Count - 1];
528 case ArrowDirection.Right:
529 case ArrowDirection.Down:
530 if (index + 1 >= this.items.Count)
531 return this.items[0];
533 return this.items[index + 1];
539 public void ResetMinimumSize ()
541 this.MinimumSize = new Size (-1, -1);
545 [EditorBrowsable (EditorBrowsableState.Never)]
546 public new void SetAutoScrollMargin (int x, int y)
548 base.SetAutoScrollMargin (x, y);
551 public override string ToString ()
553 return String.Format ("{0}, Name: {1}, Items: {2}", base.ToString(), this.Name, this.items.Count.ToString ());
557 #region Protected Methods
558 protected override AccessibleObject CreateAccessibilityInstance ()
560 AccessibleObject ao = new AccessibleObject (this);
562 ao.role = AccessibleRole.ToolBar;
567 protected override ControlCollection CreateControlsInstance ()
569 return base.CreateControlsInstance ();
572 protected internal virtual ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
575 return new ToolStripSeparator ();
577 if (this is ToolStripDropDown)
578 return new ToolStripMenuItem (text, image, onClick);
580 return new ToolStripButton (text, image, onClick);
583 protected virtual LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle layoutStyle)
585 switch (layoutStyle) {
586 case ToolStripLayoutStyle.Flow:
587 return new FlowLayoutSettings ();
588 case ToolStripLayoutStyle.Table:
589 //return new TableLayoutSettings ();
590 case ToolStripLayoutStyle.StackWithOverflow:
591 case ToolStripLayoutStyle.HorizontalStackWithOverflow:
592 case ToolStripLayoutStyle.VerticalStackWithOverflow:
598 protected override void Dispose (bool disposing)
601 ToolStripManager.RemoveToolStrip (this);
602 base.Dispose (disposing);
606 protected override void OnDockChanged (EventArgs e)
608 base.OnDockChanged (e);
611 protected override void OnEnabledChanged (EventArgs e)
613 base.OnEnabledChanged (e);
615 foreach (ToolStripItem tsi in this.Items)
616 tsi.OnParentEnabledChanged (EventArgs.Empty);
619 protected override void OnFontChanged (EventArgs e)
621 base.OnFontChanged (e);
624 protected override void OnHandleCreated (EventArgs e)
626 base.OnHandleCreated (e);
629 protected override void OnHandleDestroyed (EventArgs e)
631 base.OnHandleDestroyed (e);
634 protected override void OnInvalidated (InvalidateEventArgs e)
636 base.OnInvalidated (e);
639 protected internal virtual void OnItemAdded (ToolStripItemEventArgs e)
641 e.Item.Available = true;
642 e.Item.SetPlacement (ToolStripItemPlacement.Main);
644 this.PerformLayout ();
646 ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemAddedEvent]);
651 protected virtual void OnItemClicked (ToolStripItemClickedEventArgs e)
653 ToolStripItemClickedEventHandler eh = (ToolStripItemClickedEventHandler)(Events [ItemClickedEvent]);
658 protected internal virtual void OnItemRemoved (ToolStripItemEventArgs e)
660 ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemRemovedEvent]);
665 protected override void OnLayout (LayoutEventArgs e)
670 this.SetDisplayedItems ();
671 this.OnLayoutCompleted (EventArgs.Empty);
675 protected virtual void OnLayoutCompleted (EventArgs e)
677 EventHandler eh = (EventHandler)(Events [LayoutCompletedEvent]);
682 protected virtual void OnLayoutStyleChanged (EventArgs e)
684 EventHandler eh = (EventHandler)(Events[LayoutStyleChangedEvent]);
689 protected override void OnLeave (EventArgs e)
694 protected override void OnLostFocus (EventArgs e)
696 base.OnLostFocus (e);
699 protected override void OnMouseCaptureChanged (EventArgs e)
701 base.OnMouseCaptureChanged (e);
704 protected override void OnMouseDown (MouseEventArgs mea)
706 if (mouse_currently_over != null)
708 if (this is MenuStrip && !(mouse_currently_over as ToolStripMenuItem).HasDropDownItems) {
710 (this as MenuStrip).FireMenuActivate ();
715 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseDown);
717 if (this is MenuStrip && !menu_selected) {
718 (this as MenuStrip).FireMenuActivate ();
719 menu_selected = true;
722 if (this is MenuStrip)
723 this.HideMenus (true, ToolStripDropDownCloseReason.AppClicked);
726 if (this is MenuStrip)
727 this.Capture = false;
729 base.OnMouseDown (mea);
732 protected override void OnMouseLeave (EventArgs e)
734 if (mouse_currently_over != null) {
735 MouseLeftItem (mouse_currently_over);
736 mouse_currently_over.FireEvent (e, ToolStripItemEventType.MouseLeave);
737 mouse_currently_over = null;
740 base.OnMouseLeave (e);
743 protected override void OnMouseMove (MouseEventArgs mea)
746 // Find the item we are now
747 if (this.overflow_button != null && this.overflow_button.Visible && this.overflow_button.Bounds.Contains (mea.Location))
748 tsi = this.overflow_button;
750 tsi = this.GetItemAt (mea.X, mea.Y);
753 // If we were already hovering on this item, just send a mouse move
754 if (tsi == mouse_currently_over)
755 tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
757 // If we were over a different item, fire a mouse leave on it
758 if (mouse_currently_over != null) {
760 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
763 // Set the new item we are currently over
764 mouse_currently_over = tsi;
766 // Fire mouse enter and mouse move
767 tsi.FireEvent (mea, ToolStripItemEventType.MouseEnter);
768 MouseEnteredItem (tsi);
769 tsi.FireEvent (mea, ToolStripItemEventType.MouseMove);
771 // If we're over something with a drop down, show it
772 if (menu_selected && mouse_currently_over.Enabled && mouse_currently_over is ToolStripDropDownItem && (mouse_currently_over as ToolStripDropDownItem).HasDropDownItems)
773 (mouse_currently_over as ToolStripDropDownItem).ShowDropDown ();
776 // We're not over anything now, just fire the mouse leave on what we used to be over
777 if (mouse_currently_over != null) {
779 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave);
780 mouse_currently_over = null;
784 base.OnMouseMove (mea);
787 protected override void OnMouseUp (MouseEventArgs mea)
789 // If we're currently over an item (set in MouseMove)
790 if (mouse_currently_over != null) {
791 // Fire the item's MouseUp event
792 mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseUp);
794 // The event handler may have blocked until the mouse moved off of the ToolStripItem
795 if (mouse_currently_over == null)
798 // Fire our ItemClicked event
799 OnItemClicked (new ToolStripItemClickedEventArgs (mouse_currently_over));
802 base.OnMouseUp (mea);
805 protected override void OnPaint (PaintEventArgs e)
810 this.OnPaintGrip (e);
812 // Make each item draw itself
813 foreach (ToolStripItem tsi in this.displayed_items) {
814 e.Graphics.TranslateTransform (tsi.Bounds.Left, tsi.Bounds.Top);
815 tsi.FireEvent (e, ToolStripItemEventType.Paint);
816 e.Graphics.ResetTransform ();
819 // Paint the Overflow button if it's visible
820 if (this.overflow_button != null && this.overflow_button.Visible) {
821 e.Graphics.TranslateTransform (this.overflow_button.Bounds.Left, this.overflow_button.Bounds.Top);
822 this.overflow_button.FireEvent (e, ToolStripItemEventType.Paint);
823 e.Graphics.ResetTransform ();
826 Rectangle affected_bounds = new Rectangle (new Point (0, 0), this.Size);
827 Rectangle connected_area = Rectangle.Empty;
829 if (this is ToolStripDropDown && (this as ToolStripDropDown).OwnerItem != null && !(this as ToolStripDropDown).OwnerItem.IsOnDropDown)
830 connected_area = new Rectangle (1, 0, (this as ToolStripDropDown).OwnerItem.Width - 2, 2);
832 ToolStripRenderEventArgs pevent = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, Color.Empty);
833 pevent.InternalConnectedArea = connected_area;
835 this.Renderer.DrawToolStripBorder (pevent);
838 [EditorBrowsable (EditorBrowsableState.Advanced)]
839 protected override void OnPaintBackground (PaintEventArgs pevent)
841 base.OnPaintBackground (pevent);
843 Rectangle affected_bounds = new Rectangle (new Point (0, 0), this.Size);
844 Rectangle connected_area = Rectangle.Empty;
846 if (this is ToolStripDropDown && (this as ToolStripDropDown).OwnerItem != null && !(this as ToolStripDropDown).OwnerItem.IsOnDropDown)
847 connected_area = new Rectangle (1, 0, (this as ToolStripDropDown).OwnerItem.Width - 2, 2);
849 ToolStripRenderEventArgs e = new ToolStripRenderEventArgs (pevent.Graphics, this, affected_bounds, Color.Empty);
850 e.InternalConnectedArea = connected_area;
852 this.Renderer.DrawToolStripBackground (e);
855 protected internal virtual void OnPaintGrip (PaintEventArgs e)
857 // Never draw a grip with these two layouts
858 if (this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table)
861 PaintEventHandler eh = (PaintEventHandler)(Events [PaintGripEvent]);
865 if (!(this is MenuStrip)) {
866 if (this.orientation == Orientation.Horizontal)
867 e.Graphics.TranslateTransform (2, 0);
869 e.Graphics.TranslateTransform (0, 2);
872 this.Renderer.DrawGrip (new ToolStripGripRenderEventArgs (e.Graphics, this, this.GripRectangle, this.GripDisplayStyle, this.grip_style));
873 e.Graphics.ResetTransform ();
876 protected virtual void OnRendererChanged (EventArgs e)
878 EventHandler eh = (EventHandler)(Events [RendererChangedEvent]);
883 [EditorBrowsable (EditorBrowsableState.Advanced)]
884 protected override void OnRightToLeftChanged (EventArgs e)
886 base.OnRightToLeftChanged (e);
889 protected override void OnScroll (ScrollEventArgs se)
894 protected override void OnTabStopChanged (EventArgs e)
896 base.OnTabStopChanged (e);
899 protected override void OnVisibleChanged (EventArgs e)
901 base.OnVisibleChanged (e);
904 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
906 return base.ProcessCmdKey (ref msg, keyData);
909 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
911 base.SetBoundsCore (x, y, width, height, specified);
914 protected virtual void SetDisplayedItems ()
916 this.displayed_items.Clear ();
918 foreach (ToolStripItem tsi in this.items)
919 if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) {
920 this.displayed_items.AddNoOwnerOrLayout (tsi);
923 else if (tsi.Placement == ToolStripItemPlacement.Overflow)
924 tsi.Parent = this.OverflowButton.DropDown;
926 if (this.OverflowButton != null)
927 this.OverflowButton.DropDown.SetDisplayedItems ();
930 protected internal void SetItemLocation (ToolStripItem item, Point location)
933 throw new ArgumentNullException ("item");
935 if (item.Owner != this)
936 throw new NotSupportedException ("The item is not owned by this ToolStrip");
938 item.SetBounds (new Rectangle (location, item.Size));
941 protected internal static void SetItemParent (ToolStripItem item, ToolStrip parent)
943 if (item.Parent != null) {
944 item.Parent.Items.RemoveNoOwnerOrLayout (item);
946 if (item.Parent is ToolStripOverflow)
947 (item.Parent as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
950 parent.Items.AddNoOwnerOrLayout (item);
951 item.Parent = parent;
954 protected override void SetVisibleCore (bool value)
956 base.SetVisibleCore (value);
959 protected override void WndProc (ref Message m)
961 base.WndProc (ref m);
965 #region Public Events
966 static object ItemAddedEvent = new object ();
967 static object ItemClickedEvent = new object ();
968 static object ItemRemovedEvent = new object ();
969 static object LayoutCompletedEvent = new object ();
970 static object LayoutStyleChangedEvent = new object ();
971 static object PaintGripEvent = new object ();
972 static object RendererChangedEvent = new object ();
975 [EditorBrowsable (EditorBrowsableState.Always)]
976 public new event EventHandler AutoSizeChanged {
977 add { base.AutoSizeChanged += value; }
978 remove { base.AutoSizeChanged -= value; }
982 public new event EventHandler CausesValidationChanged {
983 add { base.CausesValidationChanged += value; }
984 remove { base.CausesValidationChanged -= value; }
988 public new event ControlEventHandler ControlAdded {
989 add { base.ControlAdded += value; }
990 remove { base.ControlAdded -= value; }
994 public new event ControlEventHandler ControlRemoved {
995 add { base.ControlRemoved += value; }
996 remove { base.ControlRemoved -= value; }
1000 public new event EventHandler CursorChanged {
1001 add { base.CursorChanged += value; }
1002 remove { base.CursorChanged -= value; }
1006 public new event EventHandler ForeColorChanged {
1007 add { base.ForeColorChanged += value; }
1008 remove { base.ForeColorChanged -= value; }
1011 public event ToolStripItemEventHandler ItemAdded {
1012 add { Events.AddHandler (ItemAddedEvent, value); }
1013 remove { Events.RemoveHandler (ItemAddedEvent, value); }
1016 public event ToolStripItemClickedEventHandler ItemClicked {
1017 add { Events.AddHandler (ItemClickedEvent, value); }
1018 remove { Events.RemoveHandler (ItemClickedEvent, value); }
1021 public event ToolStripItemEventHandler ItemRemoved {
1022 add { Events.AddHandler (ItemRemovedEvent, value); }
1023 remove { Events.RemoveHandler (ItemRemovedEvent, value); }
1026 public event EventHandler LayoutCompleted {
1027 add { Events.AddHandler (LayoutCompletedEvent, value); }
1028 remove { Events.RemoveHandler (LayoutCompletedEvent, value); }
1031 public event EventHandler LayoutStyleChanged {
1032 add { Events.AddHandler (LayoutStyleChangedEvent, value); }
1033 remove { Events.RemoveHandler (LayoutStyleChangedEvent, value); }
1036 public event PaintEventHandler PaintGrip {
1037 add { Events.AddHandler (PaintGripEvent, value); }
1038 remove { Events.RemoveHandler (PaintGripEvent, value); }
1041 public event EventHandler RendererChanged {
1042 add { Events.AddHandler (RendererChangedEvent, value); }
1043 remove { Events.RemoveHandler (RendererChangedEvent, value); }
1047 #region Private Methods
1048 private void DoAutoSize ()
1050 if (this.AutoSize == true && this.Dock == DockStyle.None)
1051 this.Size = GetPreferredSize (Size.Empty);
1053 if (this.AutoSize == true && this.Orientation == Orientation.Horizontal && (this.Dock == DockStyle.Top || this.Dock == DockStyle.Bottom))
1054 this.Height = GetPreferredSize (Size.Empty).Height;
1057 public override Size GetPreferredSize (Size proposedSize)
1059 Size new_size = new Size (0, this.Height);
1061 if (this.orientation == Orientation.Vertical) {
1062 foreach (ToolStripItem tsi in this.items)
1063 if (tsi.GetPreferredSize (Size.Empty).Height + tsi.Margin.Top + tsi.Margin.Bottom > new_size.Height)
1064 new_size.Height = tsi.GetPreferredSize (Size.Empty).Height + tsi.Margin.Top + tsi.Margin.Bottom;
1066 new_size.Height += this.Padding.Top + this.Padding.Bottom;
1067 new_size.Width = this.Width;
1069 foreach (ToolStripItem tsi in this.items)
1070 if (tsi.Available) {
1071 Size tsi_preferred = tsi.GetPreferredSize (Size.Empty);
1072 new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right;
1074 if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height))
1075 new_size.Height = (this.Padding.Vertical + tsi_preferred.Height);
1079 new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4);
1083 internal void HideMenus (bool release, ToolStripDropDownCloseReason reason)
1085 if (this is MenuStrip && release && menu_selected)
1086 (this as MenuStrip).FireMenuDeactivate ();
1089 menu_selected = false;
1091 NotifySelectedChanged (null);
1094 internal void NotifySelectedChanged (ToolStripItem tsi)
1096 foreach (ToolStripItem tsi2 in this.DisplayedItems)
1098 if (tsi2 is ToolStripDropDownItem)
1099 (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1101 if (this.OverflowButton != null) {
1102 ToolStripItemCollection tsic = this.OverflowButton.DropDown.DisplayedItems;
1104 foreach (ToolStripItem tsi2 in tsic)
1106 if (tsi2 is ToolStripDropDownItem)
1107 (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard);
1109 this.OverflowButton.HideDropDown ();
1113 private void MouseEnteredItem (ToolStripItem item)
1115 if (this.show_item_tool_tips) {
1116 tooltip_currently_showing = item;
1117 ToolTipTimer.Start ();
1121 private void MouseLeftItem (ToolStripItem item)
1123 ToolTipTimer.Stop ();
1124 ToolTipWindow.Hide ();
1125 tooltip_currently_showing = null;
1128 private Timer ToolTipTimer {
1130 if (tooltip_timer == null) {
1131 tooltip_timer = new Timer ();
1132 tooltip_timer.Enabled = false;
1133 tooltip_timer.Interval = 500;
1134 tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick);
1137 return tooltip_timer;
1141 private ToolTip.ToolTipWindow ToolTipWindow {
1143 if (tooltip_window == null)
1144 tooltip_window = new ToolTip.ToolTipWindow ();
1146 return tooltip_window;
1150 private void ToolTipTimer_Tick (object o, EventArgs args)
1152 string tooltip = tooltip_currently_showing.GetToolTip ();
1154 if (!string.IsNullOrEmpty (tooltip))
1155 ToolTipWindow.Present (this, tooltip);
1157 tooltip_currently_showing.FireEvent (EventArgs.Empty, ToolStripItemEventType.MouseHover);
1159 ToolTipTimer.Stop ();
1162 internal ToolStrip CurrentlyMergedWith {
1163 get { return this.currently_merged_with; }
1164 set { this.currently_merged_with = value; }
1167 internal List<ToolStripItem> HiddenMergedItems {
1169 if (this.hidden_merged_items == null)
1170 this.hidden_merged_items = new List<ToolStripItem> ();
1172 return this.hidden_merged_items;
1176 internal bool IsCurrentlyMerged {
1177 get { return this.is_currently_merged; }
1179 this.is_currently_merged = value;
1181 if (!value && this is MenuStrip)
1182 foreach (ToolStripMenuItem tsmi in this.Items)
1183 tsmi.DropDown.IsCurrentlyMerged = value;
1187 internal void BeginMerge ()
1189 if (!IsCurrentlyMerged) {
1190 IsCurrentlyMerged = true;
1192 if (this.pre_merge_items == null) {
1193 this.pre_merge_items = new List<ToolStripItem> ();
1195 foreach (ToolStripItem tsi in this.Items)
1196 this.pre_merge_items.Add (tsi);
1199 if (this is MenuStrip)
1200 foreach (ToolStripMenuItem tsmi in this.Items)
1201 tsmi.DropDown.BeginMerge ();
1205 internal void RevertMergeItem (ToolStripItem item)
1209 // Remove it from it's current Parent
1210 if (item.Parent != null && item.Parent != this) {
1211 if (item.Parent is ToolStripOverflow)
1212 (item.Parent as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item);
1214 item.Parent.Items.RemoveNoOwnerOrLayout (item);
1216 item.Parent = item.Owner;
1219 // Find where the item was before the merge
1220 index = item.Owner.pre_merge_items.IndexOf (item);
1222 // Find the first pre-merge item that was after this item, that
1223 // is currently in the Items collection. Insert our item before
1225 for (int i = index; i < this.pre_merge_items.Count; i++) {
1226 if (this.Items.Contains (this.pre_merge_items[i])) {
1227 item.Owner.Items.InsertNoOwnerOrLayout (this.Items.IndexOf (this.pre_merge_items[i]), item);
1232 // There aren't any items that are supposed to be after this item,
1233 // so just append it to the end.
1234 item.Owner.Items.AddNoOwnerOrLayout (item);