2 // ToolStripDropDown.cs
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 namespace System.Windows.Forms
36 [ClassInterface (ClassInterfaceType.AutoDispatch)]
38 [Designer ("System.Windows.Forms.Design.ToolStripDropDownDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
39 public class ToolStripDropDown : ToolStrip
41 private bool allow_transparency;
42 private bool auto_close;
43 private bool can_overflow;
44 private bool drop_shadow_enabled = true;
45 private double opacity = 1D;
46 private ToolStripItem owner_item;
48 #region Public Constructor
49 public ToolStripDropDown () : base ()
51 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
52 SetStyle (ControlStyles.ResizeRedraw, true);
54 this.auto_close = true;
56 this.DefaultDropDownDirection = ToolStripDropDownDirection.Right;
57 this.GripStyle = ToolStripGripStyle.Hidden;
58 this.is_toplevel = true;
62 #region Public Properties
64 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
65 public bool AllowTransparency {
66 get { return allow_transparency; }
68 if (value == allow_transparency)
71 if ((XplatUI.SupportsTransparency () & TransparencySupport.Set) != 0) {
72 allow_transparency = value;
74 if (this.IsHandleCreated) {
76 XplatUI.SetWindowTransparency (Handle, Opacity, Color.Empty);
78 UpdateStyles (); // Remove the WS_EX_LAYERED style
85 [EditorBrowsable (EditorBrowsableState.Never)]
86 public override AnchorStyles Anchor {
87 get { return base.Anchor; }
88 set { base.Anchor = value; }
94 get { return this.auto_close; }
95 set { this.auto_close = value; }
99 public override bool AutoSize {
100 get { return base.AutoSize; }
101 set { base.AutoSize = value; }
105 [DefaultValue (false)]
106 [EditorBrowsable (EditorBrowsableState.Never)]
107 public new bool CanOverflow {
108 get { return this.can_overflow; }
109 set { this.can_overflow = value; }
113 [EditorBrowsable (EditorBrowsableState.Never)]
114 public new ContextMenu ContextMenu {
120 [EditorBrowsable (EditorBrowsableState.Never)]
121 public new ContextMenuStrip ContextMenuStrip {
126 public override ToolStripDropDownDirection DefaultDropDownDirection {
127 get { return base.DefaultDropDownDirection; }
128 set { base.DefaultDropDownDirection = value; }
132 [EditorBrowsable (EditorBrowsableState.Always)]
133 [DefaultValue (DockStyle.None)]
134 public override DockStyle Dock {
135 get { return base.Dock; }
136 set { base.Dock = value; }
139 public bool DropShadowEnabled {
140 get { return this.drop_shadow_enabled; }
142 if (this.drop_shadow_enabled == value)
145 this.drop_shadow_enabled = value;
146 UpdateStyles (); // Re-CreateParams
150 public override Font Font {
151 get { return base.Font; }
152 set { base.Font = value; }
156 [EditorBrowsable (EditorBrowsableState.Never)]
157 public new ToolStripGripDisplayStyle GripDisplayStyle {
158 get { return ToolStripGripDisplayStyle.Vertical; }
162 [EditorBrowsable (EditorBrowsableState.Never)]
163 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
164 public new Padding GripMargin {
165 get { return Padding.Empty; }
170 [EditorBrowsable (EditorBrowsableState.Never)]
171 public new Rectangle GripRectangle {
172 get { return Rectangle.Empty; }
176 [EditorBrowsable (EditorBrowsableState.Never)]
177 [DefaultValue (ToolStripGripStyle.Hidden)]
178 public new ToolStripGripStyle GripStyle {
179 get { return base.GripStyle; }
180 set { base.GripStyle = value; }
184 public bool IsAutoGenerated {
185 get { return this is ToolStripOverflow; }
189 [EditorBrowsable (EditorBrowsableState.Never)]
190 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
191 public new Point Location {
192 get { return base.Location; }
193 set { base.Location = value; }
197 [TypeConverter (typeof (OpacityConverter))]
199 [EditorBrowsable (EditorBrowsableState.Advanced)]
200 public double Opacity {
201 get { return this.opacity; }
203 if (this.opacity == value)
206 this.opacity = value;
207 this.allow_transparency = true;
209 if (this.IsHandleCreated) {
211 XplatUI.SetWindowTransparency (Handle, opacity, Color.Empty);
217 [EditorBrowsable (EditorBrowsableState.Never)]
218 public new ToolStripOverflowButton OverflowButton {
219 get { return base.OverflowButton; }
223 [DefaultValue (null)]
224 public ToolStripItem OwnerItem {
225 get { return this.owner_item; }
226 set { this.owner_item = value;
228 if (this.owner_item != null)
229 if (this.owner_item.Owner != null && this.owner_item.Owner.RenderMode != ToolStripRenderMode.ManagerRenderMode)
230 this.Renderer = this.owner_item.Owner.Renderer;
235 [EditorBrowsable (EditorBrowsableState.Always)]
236 public new Region Region {
237 get { return base.Region; }
238 set { base.Region = value; }
242 [AmbientValue (RightToLeft.Inherit)]
243 public override RightToLeft RightToLeft {
244 get { return base.RightToLeft; }
245 set { base.RightToLeft = value; }
249 [EditorBrowsable (EditorBrowsableState.Never)]
250 public new bool Stretch {
251 get { return false; }
256 [EditorBrowsable (EditorBrowsableState.Never)]
257 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
258 public new int TabIndex {
264 [DefaultValue (ToolStripTextDirection.Horizontal)]
265 public override ToolStripTextDirection TextDirection {
266 get { return base.TextDirection; }
267 set { base.TextDirection = value; }
271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
272 [EditorBrowsable (EditorBrowsableState.Advanced)]
273 public bool TopLevel {
274 get { return GetTopLevel (); }
275 set { SetTopLevel (value); }
280 [DefaultValue (false)]
281 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
282 public new bool Visible {
283 get { return base.Visible; }
284 set { base.Visible = value; }
288 #region Protected Properties
289 protected override CreateParams CreateParams {
291 CreateParams cp = base.CreateParams;
293 cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_CLIPCHILDREN));
294 cp.ClassStyle |= (int)XplatUIWin32.ClassStyle.CS_DROPSHADOW;
295 cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST);
297 if (Opacity < 1.0 && allow_transparency)
298 cp.ExStyle |= (int)WindowExStyles.WS_EX_LAYERED;
300 cp.ExStyle |= (int) WindowExStyles.WS_EX_TOPMOST;
306 protected override DockStyle DefaultDock {
307 get { return DockStyle.None; }
310 protected override Padding DefaultPadding {
311 get { return new Padding (1, 2, 1, 2); }
314 protected override bool DefaultShowItemToolTips {
318 //protected internal override Size MaxItemSize {
319 // get { return new Size (Screen.PrimaryScreen.Bounds.Width - 2, Screen.PrimaryScreen.Bounds.Height - 34); }
322 protected virtual bool TopMost {
327 #region Public Methods
330 this.Close (ToolStripDropDownCloseReason.CloseCalled);
333 public void Close (ToolStripDropDownCloseReason reason)
338 // Give users a chance to cancel the close
339 ToolStripDropDownClosingEventArgs e = new ToolStripDropDownClosingEventArgs (reason);
345 // Don't actually close if AutoClose == true unless explicitly called
346 if (!this.auto_close && reason != ToolStripDropDownCloseReason.CloseCalled)
349 // Detach from the tracker
350 ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ;
351 ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange);
353 // Hide this dropdown
356 // Owner MenuItem needs to be told to redraw (it's no longer selected)
357 if (owner_item != null)
358 owner_item.Invalidate ();
360 // Recursive hide all child dropdowns
361 foreach (ToolStripItem tsi in this.Items)
362 tsi.Dismiss (reason);
364 this.OnClosed (new ToolStripDropDownClosedEventArgs (reason));
368 [EditorBrowsable (EditorBrowsableState.Never)]
369 public new void Show ()
371 CancelEventArgs e = new CancelEventArgs ();
377 // The tracker lets us know when the form is clicked or loses focus
378 ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked);
379 ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange);
383 ToolStripManager.SetActiveToolStrip (this);
385 this.OnOpened (EventArgs.Empty);
388 public void Show (Point screenLocation)
390 this.Location = screenLocation;
394 public void Show (Control control, Point position)
397 throw new ArgumentNullException ("control");
399 this.Location = control.PointToScreen (position);
403 public void Show (int x, int y)
405 this.Location = new Point (x, y);
409 public void Show (Point position, ToolStripDropDownDirection direction)
411 this.PerformLayout ();
413 Point show_point = position;
416 case ToolStripDropDownDirection.AboveLeft:
417 show_point.Y -= this.Height;
418 show_point.X -= this.Width;
420 case ToolStripDropDownDirection.AboveRight:
421 show_point.Y -= this.Height;
423 case ToolStripDropDownDirection.BelowLeft:
424 show_point.X -= this.Width;
426 case ToolStripDropDownDirection.Left:
427 show_point.X -= this.Width;
429 case ToolStripDropDownDirection.Right:
433 if (this.Location != show_point)
434 this.Location = show_point;
439 public void Show (Control control, int x, int y)
442 throw new ArgumentNullException ("control");
444 Show (control, new Point (x, y));
447 public void Show (Control control, Point position, ToolStripDropDownDirection direction)
450 throw new ArgumentNullException ("control");
452 Show (control.PointToScreen (position), direction);
456 #region Protected Methods
457 protected override AccessibleObject CreateAccessibilityInstance ()
459 return new ToolStripDropDownAccessibleObject ();
462 protected override void CreateHandle ()
464 base.CreateHandle ();
467 protected override LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle style)
469 return base.CreateLayoutSettings (style);
472 protected override void Dispose (bool disposing)
474 base.Dispose (disposing);
477 protected virtual void OnClosed (ToolStripDropDownClosedEventArgs e)
479 ToolStripDropDownClosedEventHandler eh = (ToolStripDropDownClosedEventHandler)(Events [ClosedEvent]);
484 protected virtual void OnClosing (ToolStripDropDownClosingEventArgs e)
486 ToolStripDropDownClosingEventHandler eh = (ToolStripDropDownClosingEventHandler)(Events [ClosingEvent]);
491 protected override void OnHandleCreated (EventArgs e)
493 base.OnHandleCreated (e);
495 XplatUI.SetOwner (this.Handle, Application.MWFThread.Current.Context.MainForm.Handle);
498 protected override void OnItemClicked (ToolStripItemClickedEventArgs e)
500 base.OnItemClicked (e);
503 protected override void OnLayout (LayoutEventArgs e)
505 // Find the widest menu item
508 foreach (ToolStripItem tsi in this.Items) {
512 tsi.SetPlacement (ToolStripItemPlacement.Main);
514 if (tsi.GetPreferredSize (Size.Empty).Width > widest)
515 widest = tsi.GetPreferredSize (Size.Empty).Width;
518 int x = this.Padding.Left;
519 widest += 68 - this.Padding.Horizontal;
520 int y = this.Padding.Top;
522 foreach (ToolStripItem tsi in this.Items) {
530 if (tsi is ToolStripSeparator)
535 tsi.SetBounds (new Rectangle (x, y, widest, height));
536 y += tsi.Height + tsi.Margin.Bottom;
539 this.Size = new Size (widest + this.Padding.Horizontal, y + this.Padding.Bottom);// + 2);
540 this.SetDisplayedItems ();
541 this.OnLayoutCompleted (EventArgs.Empty);
545 protected override void OnMouseUp (MouseEventArgs mea)
547 base.OnMouseUp (mea);
550 protected virtual void OnOpened (EventArgs e)
552 EventHandler eh = (EventHandler)(Events [OpenedEvent]);
557 protected virtual void OnOpening (CancelEventArgs e)
559 CancelEventHandler eh = (CancelEventHandler)(Events [OpeningEvent]);
564 protected override void OnParentChanged (EventArgs e)
566 base.OnParentChanged (e);
568 if (Parent is ToolStrip)
569 this.Renderer = (Parent as ToolStrip).Renderer;
572 protected override void OnVisibleChanged (EventArgs e)
574 base.OnVisibleChanged (e);
577 [EditorBrowsable (EditorBrowsableState.Advanced)]
578 protected override bool ProcessDialogChar (char charCode)
580 return base.ProcessDialogChar (charCode);
583 protected override bool ProcessDialogKey (Keys keyData)
585 // We don't want to let our base change the active ToolStrip
587 case Keys.Control | Keys.Tab:
588 case Keys.Control | Keys.Shift | Keys.Tab:
592 return base.ProcessDialogKey (keyData);
595 protected override bool ProcessMnemonic (char charCode)
597 return base.ProcessMnemonic (charCode);
600 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
602 base.ScaleControl (factor, specified);
605 [EditorBrowsable (EditorBrowsableState.Never)]
606 protected override void ScaleCore (float dx, float dy)
608 base.ScaleCore (dx, dy);
611 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
613 base.SetBoundsCore (x, y, width, height, specified);
616 protected override void SetVisibleCore (bool value)
618 base.SetVisibleCore (value);
621 protected override void WndProc (ref Message m)
623 const int MA_NOACTIVATE = 0x0003;
625 // Don't activate when the WM tells us to
626 if ((Msg)m.Msg == Msg.WM_MOUSEACTIVATE) {
627 m.Result = (IntPtr)MA_NOACTIVATE;
631 base.WndProc (ref m);
635 #region Public Events
636 static object ClosedEvent = new object ();
637 static object ClosingEvent = new object ();
638 static object OpenedEvent = new object ();
639 static object OpeningEvent = new object ();
640 static object ScrollEvent = new object ();
643 public new event EventHandler BackgroundImageChanged {
644 add { base.BackgroundImageChanged += value; }
645 remove { base.BackgroundImageChanged -= value; }
649 public new event EventHandler BackgroundImageLayoutChanged {
650 add { base.BackgroundImageLayoutChanged += value; }
651 remove { base.BackgroundImageLayoutChanged -= value; }
655 public new event EventHandler BindingContextChanged {
656 add { base.BindingContextChanged += value; }
657 remove { base.BindingContextChanged -= value; }
661 [EditorBrowsable (EditorBrowsableState.Always)]
662 public new event UICuesEventHandler ChangeUICues {
663 add { base.ChangeUICues += value; }
664 remove { base.ChangeUICues -= value; }
667 public event ToolStripDropDownClosedEventHandler Closed {
668 add { Events.AddHandler (ClosedEvent, value); }
669 remove { Events.RemoveHandler (ClosedEvent, value); }
672 public event ToolStripDropDownClosingEventHandler Closing {
673 add { Events.AddHandler (ClosingEvent, value); }
674 remove { Events.RemoveHandler (ClosingEvent, value); }
678 [EditorBrowsable (EditorBrowsableState.Never)]
679 public new event EventHandler ContextMenuChanged {
680 add { base.ContextMenuChanged += value; }
681 remove { base.ContextMenuChanged -= value; }
685 [EditorBrowsable (EditorBrowsableState.Always)]
686 public new event EventHandler ContextMenuStripChanged {
687 add { base.ContextMenuStripChanged += value; }
688 remove { base.ContextMenuStripChanged -= value; }
692 [EditorBrowsable (EditorBrowsableState.Always)]
693 public new event EventHandler DockChanged {
694 add { base.DockChanged += value; }
695 remove { base.DockChanged -= value; }
699 [EditorBrowsable (EditorBrowsableState.Always)]
700 public new event EventHandler Enter {
701 add { base.Enter += value; }
702 remove { base.Enter -= value; }
706 [EditorBrowsable (EditorBrowsableState.Always)]
707 public new event EventHandler FontChanged {
708 add { base.FontChanged += value; }
709 remove { base.FontChanged -= value; }
713 [EditorBrowsable (EditorBrowsableState.Never)]
714 public new event EventHandler ForeColorChanged {
715 add { base.ForeColorChanged += value; }
716 remove { base.ForeColorChanged -= value; }
720 [EditorBrowsable (EditorBrowsableState.Never)]
721 public new event GiveFeedbackEventHandler GiveFeedback {
722 add { base.GiveFeedback += value; }
723 remove { base.GiveFeedback -= value; }
727 [EditorBrowsable (EditorBrowsableState.Always)]
728 public new event HelpEventHandler HelpRequested {
729 add { base.HelpRequested += value; }
730 remove { base.HelpRequested -= value; }
734 [EditorBrowsable (EditorBrowsableState.Always)]
735 public new event EventHandler ImeModeChanged {
736 add { base.ImeModeChanged += value; }
737 remove { base.ImeModeChanged -= value; }
741 [EditorBrowsable (EditorBrowsableState.Always)]
742 public new event KeyEventHandler KeyDown {
743 add { base.KeyDown += value; }
744 remove { base.KeyDown -= value; }
748 [EditorBrowsable (EditorBrowsableState.Always)]
749 public new event KeyPressEventHandler KeyPress {
750 add { base.KeyPress += value; }
751 remove { base.KeyPress -= value; }
755 [EditorBrowsable (EditorBrowsableState.Always)]
756 public new event KeyEventHandler KeyUp {
757 add { base.KeyUp += value; }
758 remove { base.KeyUp -= value; }
762 [EditorBrowsable (EditorBrowsableState.Always)]
763 public new event EventHandler Leave {
764 add { base.Leave += value; }
765 remove { base.Leave -= value; }
768 public event EventHandler Opened {
769 add { Events.AddHandler (OpenedEvent, value); }
770 remove { Events.RemoveHandler (OpenedEvent, value); }
773 public event CancelEventHandler Opening {
774 add { Events.AddHandler (OpeningEvent, value); }
775 remove { Events.RemoveHandler (OpeningEvent, value); }
779 [EditorBrowsable (EditorBrowsableState.Always)]
780 public new event EventHandler RegionChanged {
781 add { base.RegionChanged += value; }
782 remove { base.RegionChanged -= value; }
786 [EditorBrowsable (EditorBrowsableState.Never)]
787 public new event ScrollEventHandler Scroll {
788 add { Events.AddHandler (ScrollEvent, value); }
789 remove { Events.RemoveHandler (ScrollEvent, value); }
793 [EditorBrowsable (EditorBrowsableState.Always)]
794 public new event EventHandler StyleChanged {
795 add { base.StyleChanged += value; }
796 remove { base.StyleChanged -= value; }
800 [EditorBrowsable (EditorBrowsableState.Never)]
801 public new event EventHandler TabIndexChanged {
802 add { base.TabIndexChanged += value; }
803 remove { base.TabIndexChanged -= value; }
807 [EditorBrowsable (EditorBrowsableState.Never)]
808 public new event EventHandler TabStopChanged {
809 add { base.TabStopChanged += value; }
810 remove { base.TabStopChanged -= value; }
814 [EditorBrowsable (EditorBrowsableState.Never)]
815 public new event EventHandler TextChanged {
816 add { base.TextChanged += value; }
817 remove { base.TextChanged -= value; }
821 [EditorBrowsable (EditorBrowsableState.Never)]
822 public new event EventHandler Validated {
823 add { base.Validated += value; }
824 remove { base.Validated -= value; }
828 [EditorBrowsable (EditorBrowsableState.Never)]
829 public new event CancelEventHandler Validating {
830 add { base.Validating += value; }
831 remove { base.Validating -= value; }
835 #region Private Methods
836 internal override void Dismiss (ToolStripDropDownCloseReason reason)
839 base.Dismiss (reason);
842 internal override ToolStrip GetTopLevelToolStrip ()
844 if (this.OwnerItem == null)
847 return this.OwnerItem.GetTopLevelToolStrip ();
850 internal override bool ProcessArrowKey (Keys keyData)
855 this.SelectNextToolStripItem (this.GetCurrentlySelectedItem (), true);
858 case Keys.Shift | Keys.Tab:
859 this.SelectNextToolStripItem (this.GetCurrentlySelectedItem (), false);
862 this.GetTopLevelToolStrip ().SelectNextToolStripItem (this.TopLevelOwnerItem, true);
866 this.Dismiss (ToolStripDropDownCloseReason.Keyboard);
868 ToolStrip parent_strip = this.OwnerItem.Parent;
869 ToolStripManager.SetActiveToolStrip (parent_strip);
871 if (parent_strip is MenuStrip && keyData == Keys.Left) {
872 parent_strip.SelectNextToolStripItem (this.TopLevelOwnerItem, false);
873 this.TopLevelOwnerItem.Invalidate ();
874 } else if (parent_strip is MenuStrip && keyData == Keys.Escape) {
875 (parent_strip as MenuStrip).MenuDroppedDown = false;
876 this.TopLevelOwnerItem.Select ();
884 internal override ToolStripItem SelectNextToolStripItem (ToolStripItem start, bool forward)
886 ToolStripItem next_item = this.GetNextItem (start, forward ? ArrowDirection.Down : ArrowDirection.Up);
888 if (next_item != null)
889 this.ChangeSelection (next_item);
894 private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e)
896 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
899 private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e)
901 this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked);
905 #region Internal Properties
906 internal override bool ActivateOnShow { get { return false; } }
908 internal ToolStripItem TopLevelOwnerItem {
910 ToolStripItem owner_item = this.OwnerItem;
913 while (owner_item != null) {
914 ts = owner_item.Owner;
916 if (ts != null && (ts is ToolStripDropDown))
917 owner_item = (ts as ToolStripDropDown).OwnerItem;
927 #region ToolStripDropDownAccessibleObject
928 private class ToolStripDropDownAccessibleObject : AccessibleObject