// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows.Forms.Layout;
using static Interop;

namespace System.Windows.Forms
{
    [Designer("System.Windows.Forms.Design.ToolStripDropDownDesigner, " + AssemblyRef.SystemDesign)]
    public class ToolStripDropDown : ToolStrip
    {
        private ToolStripItem ownerItem;
        private bool isAutoGenerated;
        private bool dropShadowEnabled = true;
        private bool autoClose = true;
        private bool autoSize = true;
        private int countDropDownItemsAssignedTo; // the number of dropdown items using this as their dropdown..
        private BitVector32 state;
        private Point displayLocation = new Point(0, 0);
        private bool saveSourceControl;

        private ToolStripDropDownDirection childDropDownDirection = ToolStripDropDownDirection.Default;
        private ToolStripDropDownCloseReason closeReason = ToolStripDropDownCloseReason.AppFocusChange;

        private static readonly int PropOpacity = PropertyStore.CreateKey();
        private static readonly int PropSourceControl = PropertyStore.CreateKey();

        private static readonly object EventOpening = new object();
        private static readonly object EventOpened = new object();
        private static readonly object EventClosed = new object();
        private static readonly object EventClosing = new object();

        private static readonly Padding defaultPadding = new Padding(1, 2, 1, 2);
        private Padding scaledDefaultPadding = defaultPadding;

#if DEBUG
        internal static TraceSwitch DropDownActivateDebug = new TraceSwitch("DropDownActivateDebug", "Debug activation code for dropDown controls");
        internal static TraceSwitch DropDownDebugBounds = new TraceSwitch("DropDownDebugBounds", "Debug GetDropDownBounds");
#else
        internal static TraceSwitch DropDownActivateDebug;
        internal static TraceSwitch DropDownDebugBounds;
#endif

        private static readonly int stateLayered = BitVector32.CreateMask();
        private static readonly int stateAllowTransparency = BitVector32.CreateMask(stateLayered);
        private static readonly int stateNotWorkingAreaConstrained = BitVector32.CreateMask(stateAllowTransparency);
        private static readonly int stateInSetVisibleCore = BitVector32.CreateMask(stateNotWorkingAreaConstrained);

        public ToolStripDropDown()
        {
            if (DpiHelper.IsScalingRequirementMet)
            {
                scaledDefaultPadding = DpiHelper.LogicalToDeviceUnits(defaultPadding);
            }

            SuspendLayout();
            Initialize();
            ResumeLayout(false);
        }

        internal ToolStripDropDown(ToolStripItem ownerItem) : this()
        {
            this.ownerItem = ownerItem;
        }

        internal ToolStripDropDown(ToolStripItem ownerItem, bool isAutoGenerated) : this(ownerItem)
        {
            this.isAutoGenerated = isAutoGenerated;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new bool AllowItemReorder
        {
            get => base.AllowItemReorder;
            set => base.AllowItemReorder = value;
        }

        /// <summary>
        ///
        ///  Gets or sets
        ///  a value indicating whether the opacity of the form can be
        ///  adjusted.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [SRDescription(nameof(SR.ControlAllowTransparencyDescr))]
        public bool AllowTransparency
        {
            get
            {
                return state[stateAllowTransparency];
            }
            set
            {
                if (value != (state[stateAllowTransparency]))
                {
                    state[stateAllowTransparency] = value;

                    state[stateLayered] = state[stateAllowTransparency];

                    UpdateStyles();

                    if (!value)
                    {
                        if (Properties.ContainsObject(PropOpacity))
                        {
                            Properties.SetObject(PropOpacity, (object)1.0f);
                        }
                        UpdateLayered();
                    }
                }
            }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override AnchorStyles Anchor
        {
            get => base.Anchor;
            set => base.Anchor = value;
        }

        [DefaultValue(true)]
        public override bool AutoSize
        {
            get
            {
                return autoSize;
            }
            set
            {
                if (autoSize != value)
                {
                    autoSize = value;
                    // we shadow CommonProperties
                    LayoutTransaction.DoLayout(this, this, PropertyNames.AutoSize);
                    OnAutoSizeChanged(EventArgs.Empty);
                }
            }
        }

        /// <summary>
        ///  specifies whether the dropdown should automatically close when the dropdown has lost
        ///  activation.  If you want a dropdown that always stays open, specify AutoClose = false;
        /// </summary>
        [DefaultValue(true)]
        [SRCategory(nameof(SR.CatBehavior))]
        [SRDescription(nameof(SR.ToolStripDropDownAutoCloseDescr))]
        public bool AutoClose
        {
            get
            {
                return autoClose;
            }
            set
            {
                //
                if (autoClose != value)
                {
                    autoClose = value;
                    ApplyTopMost(/*topMost=*/!autoClose);
                }
            }
        }

        [Browsable(false)]
        public new event EventHandler BackgroundImageChanged
        {
            add => base.BackgroundImageChanged += value;
            remove => base.BackgroundImageChanged -= value;
        }

        [Browsable(false)]
        public new event EventHandler BackgroundImageLayoutChanged
        {
            add => base.BackgroundImageLayoutChanged += value;
            remove => base.BackgroundImageLayoutChanged -= value;
        }

        [Browsable(false)]
        public new event EventHandler BindingContextChanged
        {
            add => base.BindingContextChanged += value;
            remove => base.BindingContextChanged -= value;
        }

        [DefaultValue(false)]
         [Browsable(false)]
         [EditorBrowsable(EditorBrowsableState.Never)]
        public new bool CanOverflow
        {
            get => base.CanOverflow;
            set => base.CanOverflow = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event UICuesEventHandler ChangeUICues
        {
            add => base.ChangeUICues += value;
            remove => base.ChangeUICues -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ContextMenuStrip ContextMenuStrip
        {
            get => base.ContextMenuStrip;
            set => base.ContextMenuStrip = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler ContextMenuStripChanged
        {
            add => base.ContextMenuStripChanged += value;
            remove => base.ContextMenuStripChanged -= value;
        }

        /// <summary>
        ///  This is called when creating a window. Inheriting classes can overide
        ///  this to add extra functionality, but should not forget to first call
        ///  base.CreateParams() to make sure the control continues to work
        ///  correctly.
        /// </summary>
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;

                // If we're using themes then go ahead
                if (DropShadowEnabled)
                {
                    cp.ClassStyle |= (int)User32.CS.DROPSHADOW;
                }
                // we're a borderless menuless control with no min/max boxes
                // we don't want to show in the taskbar either

                //HOWTO: Prevent a Window from Appearing on the Taskbar
                //Give the window the WS_EX_TOOLWINDOW extended style, and remove the WS_EX_APPWINDOW style. As a side effect, the window will have a smaller caption than a normal window.
                //Give the window the WS_POPUP style and make it owned by a hidden window. (Form)

                cp.Style &= ~(int)(User32.WS.CAPTION | User32.WS.CLIPSIBLINGS);         /* no caption, no siblings */
                cp.ExStyle &= ~(int)User32.WS_EX.APPWINDOW;  /* show in taskbar = false */
                // | NativeMethods.WS_EX_TOOLWINDOW
                cp.Style |= TopLevel ? unchecked((int)User32.WS.POPUP) : (int)User32.WS.CHILD;
                cp.ExStyle |= (int)User32.WS_EX.CONTROLPARENT;  /* show in taskbar = false */

                bool topLevel = TopLevel;

                // opacity
                if (topLevel && state[stateLayered])
                {
                    cp.ExStyle |= (int)User32.WS_EX.LAYERED;
                }
                else if (topLevel)
                {
                    //From MSDN: Menus, dialog boxes, and combo list boxes have the CS_SAVEBITS style. When you use this style for a window,
                    //Windows saves a bitmap copy of the screen image that the window obscures. First, Windows asks the display driver to save the bits.
                    //If the display driver has enough memory, it saves the bits for Windows. If the display driver does not have enough memory, Window
                    //saves the bits itself as a bitmap in global memory and also uses some of User's local heap for housekeeping structures for each window.
                    //When the application removes the window, Windows can restore the screen image quickly by using the stored bits.
                    cp.ClassStyle |= (int)User32.CS.SAVEBITS;
                }
                else if (!topLevel)
                {
                    cp.Style |= (int)User32.WS.CLIPSIBLINGS;
                }

                // We're turning off CLIPSIBLINGS because in the designer the elements of the form beneath
                // are actually sibling controls.  We want to paint right over them as if we were a toplevel window.

                return cp;
            }
        }

        protected override Padding DefaultPadding
        {
            get { return scaledDefaultPadding; }
        }

        /// <summary> We want this to default to true... This way tooltips on overflows and custom dropdowns will show.
        ///  Since menu items don't show tooltips by default we can safely leave it on </summary>
        protected override bool DefaultShowItemToolTips
        {
            get
            {
                return true;
            }
        }

        protected override DockStyle DefaultDock
        {
            get
            {
                return DockStyle.None;
            }
        }

        public override ToolStripDropDownDirection DefaultDropDownDirection
        {
            get
            {
                if (childDropDownDirection == ToolStripDropDownDirection.Default)
                {
                    return (RightToLeft == RightToLeft.Yes) ? ToolStripDropDownDirection.Left : ToolStripDropDownDirection.Right;
                }
                return childDropDownDirection;
            }
            set
            {
                childDropDownDirection = value;
                base.DefaultDropDownDirection = value;
            }
        }

        [DefaultValue(DockStyle.None)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public override DockStyle Dock
        {
            get => base.Dock;
            set => base.Dock = value;
        }

        ///  changed the browsable attribute
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler DockChanged
        {
            add => base.DockChanged += value;
            remove => base.DockChanged -= value;
        }

        /// <summary>
        ///  Returns an owner window that can be used to
        ///  own a drop down.
        /// </summary>
        internal override NativeWindow DropDownOwnerWindow
        {
            get
            {
                // Re-use the drop down owner from our parenting
                // tool strip if we can.
                if (ownerItem != null && ownerItem.Owner != null)
                {
                    return ownerItem.Owner.DropDownOwnerWindow;
                }

                return base.DropDownOwnerWindow;
            }
        }

        public bool DropShadowEnabled
        {
            get
            {
                // DropShadows are only supported on TopMost windows
                // due to the flakeyness of the way it's implemented in the OS. (Non toplevel
                // windows can have parts of the shadow disappear because another window can get
                // sandwiched between the SysShadow window and the dropdown.)
                return dropShadowEnabled && TopMost && DisplayInformation.IsDropShadowEnabled;
            }
            set
            {
                if (dropShadowEnabled != value)
                {
                    dropShadowEnabled = value;
                    if (IsHandleCreated && !DesignMode)
                    {
                        RecreateHandle();
                    }
                }
            }
        }

        [SRCategory(nameof(SR.CatAction))]
        [SRDescription(nameof(SR.ToolStripDropDownClosedDecr))]
        public event ToolStripDropDownClosedEventHandler Closed
        {
            add => Events.AddHandler(EventClosed, value);
            remove => Events.RemoveHandler(EventClosed, value);
        }

        [SRCategory(nameof(SR.CatAction))]
        [SRDescription(nameof(SR.ToolStripDropDownClosingDecr))]
        public event ToolStripDropDownClosingEventHandler Closing
        {
            add => Events.AddHandler(EventClosing, value);
            remove => Events.RemoveHandler(EventClosing, value);
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler Enter
        {
            add => base.Enter += value;
            remove => base.Enter -= value;
        }

        public override Font Font
        {
            get
            {
                if (IsFontSet())
                {
                    return base.Font;
                }
                // if the FONT isnt set, then return our owner item's font.
                if (IsAutoGenerated && OwnerItem != null)
                {
                    return OwnerItem.Font;
                }

                return base.Font;
            }
            set => base.Font = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler FontChanged
        {
            add => base.FontChanged += value;
            remove => base.FontChanged -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler ForeColorChanged
        {
            add => base.ForeColorChanged += value;
            remove => base.ForeColorChanged -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        new public event GiveFeedbackEventHandler GiveFeedback
        {
            add => base.GiveFeedback += value;
            remove => base.GiveFeedback -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ToolStripGripDisplayStyle GripDisplayStyle
        {
            get => base.GripDisplayStyle;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new Rectangle GripRectangle
        {
            get => base.GripRectangle;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Padding GripMargin
        {
            get => base.GripMargin;
            set => base.GripMargin = value;
        }

        [DefaultValue(ToolStripGripStyle.Hidden)]
         [Browsable(false)]
         [EditorBrowsable(EditorBrowsableState.Never)]
        public new ToolStripGripStyle GripStyle
        {
            get => base.GripStyle;
            set => base.GripStyle = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event HelpEventHandler HelpRequested
        {
            add => base.HelpRequested += value;
            remove => base.HelpRequested -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler ImeModeChanged
        {
            add => base.ImeModeChanged += value;
            remove => base.ImeModeChanged -= value;
        }

        /// <summary>
        ///  determines whether this dropdown was autogenerated.
        /// </summary>
        [Browsable(false)]
        public bool IsAutoGenerated
        {
            get
            {
                return isAutoGenerated;
            }
        }

        internal bool IsAssignedToDropDownItem
        {
            get
            {
                return IsAutoGenerated || (countDropDownItemsAssignedTo > 0);
            }
        }

        internal override Size ImageScalingSizeInternal
        {
            get
            {
                if (IsAutoGenerated && OwnerToolStrip != null)
                {
                    return OwnerToolStrip.ImageScalingSizeInternal;
                }
                return base.ImageScalingSizeInternal;
            }
            set => base.ImageScalingSizeInternal = value;
        }

        internal override bool KeyboardActive
        {
            get
            {
                // ripple up the chain until we get the topmost toolstrip (usually the main menu strip is the one we care about)
                ToolStrip ownerToolStrip = OwnerToolStrip;
                if (ownerToolStrip != null)
                {
                    return ownerToolStrip.KeyboardActive;
                }
                return base.KeyboardActive;
            }
            set
            {
                base.KeyboardActive = value;

                // ripple up the chain until we get the topmost toolstrip (usually the main menu strip is the one we care about)
                ToolStrip ownerToolStrip = OwnerToolStrip;
                if (ownerToolStrip != null)
                {
                    ownerToolStrip.KeyboardActive = value;
                }
            }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event KeyEventHandler KeyDown
        {
            add => base.KeyDown += value;
            remove => base.KeyDown -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event KeyPressEventHandler KeyPress
        {
            add => base.KeyPress += value;
            remove => base.KeyPress -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event KeyEventHandler KeyUp
        {
            add => base.KeyUp += value;
            remove => base.KeyUp -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public new event EventHandler Leave
        {
            add => base.Leave += value;
            remove => base.Leave -= value;
        }

        /// <summary>
        ///  Override Location to make it hidden from the user in the designer
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public new Point Location
        {
            get => base.Location;
            set => base.Location = value;
        }

        [SRCategory(nameof(SR.CatAction))]
        [SRDescription(nameof(SR.ToolStripDropDownOpeningDescr))]
        public event CancelEventHandler Opening
        {
            add => Events.AddHandler(EventOpening, value);
            remove => Events.RemoveHandler(EventOpening, value);
        }

        /// <summary>
        ///  Occurs when the control is clicked.
        /// </summary>
        [SRCategory(nameof(SR.CatAction))]
        [SRDescription(nameof(SR.ToolStripDropDownOpenedDescr))]
        public event EventHandler Opened
        {
            add => Events.AddHandler(EventOpened, value);
            remove => Events.RemoveHandler(EventOpened, value);
        }

        protected internal override Size MaxItemSize
        {
            get
            {
                return Screen.GetWorkingArea(Bounds).Size - Padding.Size;
            }
        }

        /// <summary>
        ///  Determines the opacity of the form. This can only be set on top level controls.
        ///  Opacity requires Windows 2000 or later, and is ignored on earlier operating systems.
        /// </summary>
        [SRCategory(nameof(SR.CatWindowStyle))]
        [TypeConverter(typeof(OpacityConverter))]
        [SRDescription(nameof(SR.FormOpacityDescr))]
        [DefaultValue(1.0)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public double Opacity
        {
            get
            {
                object opacity = Properties.GetObject(PropOpacity);
                if (opacity != null)
                {
                    return Convert.ToDouble(opacity, CultureInfo.InvariantCulture);
                }

                return 1.0f;
            }
            set
            {
                if (value > 1.0)
                {
                    value = 1.0f;
                }
                else if (value < 0.0)
                {
                    value = 0.0f;
                }

                Properties.SetObject(PropOpacity, value);

                bool oldLayered = (state[stateLayered]);
                if (OpacityAsByte < 255)
                {
                    AllowTransparency = true;
                    state[stateLayered] = true;
                }
                else
                {
                    state[stateLayered] = false;
                }

                if (oldLayered != (state[stateLayered]))
                {
                    UpdateStyles();
                }

                UpdateLayered();
            }
        }

        private byte OpacityAsByte
        {
            get
            {
                return (byte)(Opacity * 255.0f);
            }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ToolStripOverflowButton OverflowButton
        {
            get => base.OverflowButton;
        }

        [DefaultValue(null)]
        [Browsable(false)]
        public ToolStripItem OwnerItem
        {
            get { return ownerItem; }
            set
            {
                if (ownerItem != value)
                {
                    Font originalFont = Font;
                    RightToLeft startRightToLeft = RightToLeft;
                    ownerItem = value;
                    // RESET ambient properties
                    if (!originalFont.Equals(Font))
                    {
                        OnOwnerItemFontChanged(EventArgs.Empty);
                    }
                    if (ownerItem != null && RightToLeftInherited && startRightToLeft != RightToLeft)
                    {
                        using (new LayoutTransaction(this, this, PropertyNames.RightToLeft))
                        {
                            OnRightToLeftChanged(EventArgs.Empty);
                        }
                    }
                }
            }
        }

        internal ToolStripDropDownItem OwnerDropDownItem
        {
            get { return OwnerItem as ToolStripDropDownItem; }
        }

        internal ToolStrip OwnerToolStrip
        {
            get
            {
                if (ownerItem != null)
                {
                    ToolStrip owner = ownerItem.ParentInternal;
                    if (owner != null)
                    {
                        return owner;
                    }

                    // might not actually be placed on the overflow, just check for sure.
                    if (ownerItem.Placement == ToolStripItemPlacement.Overflow && ownerItem.Owner != null)
                    {
                        return ownerItem.Owner.OverflowButton.DropDown;
                    }
                    if (owner is null)
                    {
                        return ownerItem.Owner;
                    }
                }
                return null;
            }
        }

        /// <summary>
        ///  Hide the Region Property
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public Region Region
        {
            get => base.Region;
            set => base.Region = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler RegionChanged
        {
            add => base.RegionChanged += value;
            remove => base.RegionChanged -= value;
        }

        internal virtual bool RequiresScrollButtons
        {
            get
            {
                return false;
            }
            set
            {
                Debug.Fail("You can't set this except on ToolStripDropDownMenu");
            }
        }

        [SRCategory(nameof(SR.CatAppearance))]
        [Localizable(true)]
        [AmbientValue(RightToLeft.Inherit)]
        [SRDescription(nameof(SR.ControlRightToLeftDescr))]
        public override RightToLeft RightToLeft
        {
            get
            {
                // our inheritance is from our owner item.
                if (RightToLeftInherited)
                {
                    if (SourceControlInternal != null)
                    {
                        return SourceControlInternal.RightToLeft;
                    }
                    if (OwnerItem != null)
                    {
                        return OwnerItem.RightToLeft;
                    }
                }
                return base.RightToLeft;
            }
            set => base.RightToLeft = value;
        }

        private bool RightToLeftInherited
        {
            get
            {
                // fish out of control's property store whether or not RTL was set, if it's set to inherit.
                return !ShouldSerializeRightToLeft();
            }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        new public event ScrollEventHandler Scroll
        {
            add => base.Scroll += value;
            remove => base.Scroll -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new bool Stretch
        {
            get => base.Stretch;
            set => base.Stretch = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        new public event EventHandler StyleChanged
        {
            add => base.StyleChanged += value;
            remove => base.StyleChanged -= value;
        }

        internal Control SourceControlInternal
        {
            get
            {
                return Properties.GetObject(PropSourceControl) as Control;
            }
            set
            {
                Properties.SetObject(PropSourceControl, value);
            }
        }

        internal override User32.SW ShowParams => User32.SW.SHOWNOACTIVATE;

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler TabStopChanged
        {
            add => base.TabStopChanged += value;
            remove => base.TabStopChanged -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler TextChanged
        {
            add => base.TextChanged += value;
            remove => base.TextChanged -= value;
        }

        [Browsable(false)]
        [DefaultValue(ToolStripTextDirection.Horizontal)]
        [SRDescription(nameof(SR.ToolStripTextDirectionDescr))]
        [SRCategory(nameof(SR.CatAppearance))]
        public override ToolStripTextDirection TextDirection
        {
            get => base.TextDirection;
            set => base.TextDirection = value;
        }

        //Consistency: match casing of Form.TopMost, which shipped in Everett, even though it's wrong
        protected virtual bool TopMost
        {
            get { return true; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool TopLevel
        {
            get
            {
                return GetTopLevel();
            }
            set
            {
                //
                if (value != GetTopLevel())
                {
                    SetTopLevelInternal(value);
                    SetTopLevelStyle(value);
                }
            }
        }

        // public Color TransparencyKey {
        //    This property intentionally not available for ToolStripDropDown
        //    it's not robust enough for our needs
        // }

        ///  Override base TabIndex property in order to avoid serialization
        ///  (since a dropdown shouldn't participate in the taborder...)
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public new int TabIndex
        {
            get => base.TabIndex;
            set => base.TabIndex = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [SRCategory(nameof(SR.CatPropertyChanged))]
        [SRDescription(nameof(SR.ControlOnTabIndexChangedDescr))]
        public new event EventHandler TabIndexChanged
        {
            add => base.TabIndexChanged += value;
            remove => base.TabIndexChanged -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler Validated
        {
            add => base.Validated += value;
            remove => base.Validated -= value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        new public event CancelEventHandler Validating
        {
            add => base.Validating += value;
            remove => base.Validating -= value;
        }

        ///  Override base Visible property in order to control serialization by setting default value
        [SRCategory(nameof(SR.CatBehavior))]
        [Localizable(true)]
        [SRDescription(nameof(SR.ControlVisibleDescr))]
        [DefaultValue(false)]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool Visible
        {
            get => base.Visible;
            set => base.Visible = value;
        }

        // internally we store the negated value so we don't have to initialize it.
        internal bool WorkingAreaConstrained
        {
            get => !state[stateNotWorkingAreaConstrained];
            set => state[stateNotWorkingAreaConstrained] = !value;
        }

        internal void AssignToDropDownItem()
        {
            countDropDownItemsAssignedTo++;
        }

        internal void AdjustSize()
        {
            Size size = GetSuggestedSize();
            if (size != Size)
            {
                Size = size;
            }
        }

        private void ApplyTopMost(bool topMost)
        {
            if (TopMost)
            {
                User32.SetWindowPos(
                    new HandleRef(this, Handle),
                    topMost ? User32.HWND_TOPMOST : User32.HWND_NOTOPMOST,
                    flags: User32.SWP.NOMOVE | User32.SWP.NOSIZE | User32.SWP.NOACTIVATE);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                SourceControlInternal = null;
            }
            base.Dispose(disposing);
        }

        private void CancelAutoExpand()
        {
            ToolStrip toplevelOwnerToolStrip = GetToplevelOwnerToolStrip();
            if (toplevelOwnerToolStrip != null)
            {
                toplevelOwnerToolStrip.MenuAutoExpand = false;
            }
        }

        internal override bool CanProcessMnemonic()
        {
            // Don't let mnemonics act as keyboard input in IE in the internet.
            if (!Application.MessageLoop)
            {
                return false;
            }

            return base.CanProcessMnemonic();
        }

        protected override AccessibleObject CreateAccessibilityInstance()
        {
            return new ToolStripDropDownAccessibleObject(this);
        }

        protected override LayoutSettings CreateLayoutSettings(ToolStripLayoutStyle style)
        {
            LayoutSettings layoutSettings = base.CreateLayoutSettings(style);

            if (style == ToolStripLayoutStyle.Flow)
            {
                FlowLayoutSettings flowLayoutSettings = layoutSettings as FlowLayoutSettings;
                flowLayoutSettings.FlowDirection = FlowDirection.TopDown;
                flowLayoutSettings.WrapContents = false;
                return flowLayoutSettings;
            }
            return layoutSettings;
        }

        protected override void CreateHandle()
        {
            base.CreateHandle();

            if (TopLevel)
            {
                ReparentToDropDownOwnerWindow();

                if (!AutoClose || !WorkingAreaConstrained)
                {
                    ApplyTopMost(true);
                }
            }
            if (DesignMode)
            {
                SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, false);
            }
        }

        public void Close()
        {
            SetCloseReason(ToolStripDropDownCloseReason.CloseCalled);
            Visible = false;
            // we were the last one in the chain, roll out of menu mode.
            if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() is null)
            {
                ToolStripManager.ModalMenuFilter.ExitMenuMode();
            }
        }

        private void ResetCloseReason()
        {
            closeReason = ToolStripDropDownCloseReason.AppFocusChange;
        }
        internal void SetCloseReason(ToolStripDropDownCloseReason reason)
        {
            closeReason = reason;
        }

        public void Close(ToolStripDropDownCloseReason reason)
        {
            SetCloseReason(reason);
            Visible = false;
        }

        internal Rectangle GetDropDownBounds(Rectangle suggestedBounds)
        {
            Rectangle dropDownBounds;
            if (TopLevel)
            {
                Point screenPoint = Point.Empty;

                if ((ownerItem != null) && (ownerItem is ToolStripDropDownItem))
                {
                    screenPoint = ((ToolStripDropDownItem)ownerItem).DropDownLocation;
                }
                else
                {
                    screenPoint = suggestedBounds.Location;
                }

                Rectangle suggestedScreenBounds = new Rectangle(screenPoint, suggestedBounds.Size);
                if (WorkingAreaConstrained)
                {
                    dropDownBounds = WindowsFormsUtils.ConstrainToScreenWorkingAreaBounds(suggestedScreenBounds);
                }
                else
                {
                    dropDownBounds = WindowsFormsUtils.ConstrainToScreenBounds(suggestedScreenBounds);
                }
            }
            else
            {
                Point parentClientPoint = Point.Empty;
                if ((ownerItem != null) && (ownerItem is ToolStripDropDownItem) && (ParentInternal != null))
                {
                    parentClientPoint = ParentInternal.PointToClient(((ToolStripDropDownItem)ownerItem).DropDownLocation);
                }
                else
                {
                    parentClientPoint = suggestedBounds.Location;
                }
                dropDownBounds = new Rectangle(parentClientPoint, suggestedBounds.Size);
            }
            Debug.WriteLineIf(DropDownDebugBounds.TraceVerbose, "DropDownBounds for " + suggestedBounds + "is" + dropDownBounds);

            return dropDownBounds;
        }

        internal Rectangle CalculateDropDownLocation(Point start, ToolStripDropDownDirection dropDownDirection)
        {
            Point offset = Point.Empty;
            if (!IsHandleCreated)
            {
                // PERF:
                // if the handle isn't created yet, then we likely haven't performed layout
                // yet. force a layout here so that we get the correct size.
                LayoutTransaction.DoLayout(this, this, PropertyNames.PreferredSize);
            }
            Rectangle dropDownBounds = new Rectangle(Point.Empty, GetSuggestedSize());
            // calculate the offset from the upper left hand corner of the item.
            switch (dropDownDirection)
            {
                case ToolStripDropDownDirection.AboveLeft:
                    offset.X = -dropDownBounds.Width;
                    offset.Y = -dropDownBounds.Height;
                    break;
                case ToolStripDropDownDirection.AboveRight:
                    offset.Y = -dropDownBounds.Height;
                    break;
                case ToolStripDropDownDirection.BelowRight:
                case ToolStripDropDownDirection.Right:
                    break;
                case ToolStripDropDownDirection.BelowLeft:
                case ToolStripDropDownDirection.Left:
                    offset.X = -dropDownBounds.Width;
                    break;
            }
            dropDownBounds.Location = new Point(start.X + offset.X, start.Y + offset.Y);
            if (WorkingAreaConstrained)
            {
                dropDownBounds = WindowsFormsUtils.ConstrainToScreenWorkingAreaBounds(dropDownBounds);
            }
            return dropDownBounds;
        }

        internal Size GetSuggestedSize()
        {
            if (AutoSize)
            {
                return GetPreferredSize(Size.Empty);
            }
            return Size;
        }

        /// <summary>
        ///  Returns the ToolStrip from which all the dropdowns started from.  This can be null.
        /// </summary>
        internal override ToolStrip GetToplevelOwnerToolStrip()
        {
            ToolStripDropDown topmost = GetFirstDropDown();
            return (topmost.OwnerItem is null) ? null : topmost.OwnerToolStrip;
        }

        internal ToolStripItem GetToplevelOwnerItem()
        {
            ToolStripDropDown topmost = GetFirstDropDown();
            return topmost.OwnerItem;
        }

        internal override void HandleItemClicked(ToolStripItem dismissingItem)
        {
            // Only clear the SourceControl if this is the last click.
            if (ActiveDropDowns.Count == 0)
            {
                // post processing after the click has happened.
                SourceControlInternal = null;
            }
            base.HandleItemClicked(dismissingItem);
        }
        /// <summary>
        ///  Set some common properties
        /// </summary>
        internal virtual void Initialize()
        {
            SetState(States.Visible, false);
            SetTopLevelInternal(true);

            // Marking this as a modal form prevents it from being activated
            // by the IMsoComponentManager, which will break keyboard routing in VS.
            //
            SetState(States.Modal, true);

            SetStyle(ControlStyles.ResizeRedraw, true);
            UpdateStyles();
            GripStyle = ToolStripGripStyle.Hidden;
            CanOverflow = false;
            LayoutStyle = ToolStripLayoutStyle.Flow;
            MenuAutoExpand = true;
            AutoSize = true;
        }

        protected virtual void OnClosed(ToolStripDropDownClosedEventArgs e)
        {
            if (IsHandleCreated)
            {
                if (ownerItem is null || !ownerItem.IsInDesignMode)
                {
                    AccessibilityNotifyClients(AccessibleEvents.SystemMenuPopupEnd, -1);
                }
            }

            ((ToolStripDropDownClosedEventHandler)Events[EventClosed])?.Invoke(this, e);
        }

        protected virtual void OnClosing(ToolStripDropDownClosingEventArgs e)
        {
            ((ToolStripDropDownClosingEventHandler)Events[EventClosing])?.Invoke(this, e);
        }

        /// <summary>
        ///  When our handle is being created, suspend the deactivation
        ///  portion of the WndProc, as we'll never be shown.
        /// </summary>
        protected override void OnHandleCreated(EventArgs e)
        {
            UpdateStyles();  // get rid of WS_CAPTION style
            base.OnHandleCreated(e);
            UpdateLayered(); // update transparency
        }

        protected override void OnItemClicked(ToolStripItemClickedEventArgs e)
        {
            try
            {
                base.OnItemClicked(e);
            }
            finally
            {
                if (AutoClose)
                {
                    if ((!(e.ClickedItem is ToolStripDropDownItem dismissingItem))                   // it's not a dropdownitem
                       || (dismissingItem is ToolStripSplitButton && !dismissingItem.DropDown.Visible) // clicking on the split button button dismisses
                       || !(dismissingItem.HasDropDownItems))
                    {    // clicking on a item w/dropdown does not dismiss window
                        Close(ToolStripDropDownCloseReason.ItemClicked);
                    }
                }
            }
        }

        protected override void OnLayout(LayoutEventArgs e)
        {
            // It's important to size the dropdown first, then layout so that
            // the layout engine and SetDisplayedItems know how big the container is.
            AdjustSize();
            base.OnLayout(e);
        }

        protected virtual void OnOpening(CancelEventArgs e)
        {
            ((CancelEventHandler)Events[EventOpening])?.Invoke(this, e);
        }

        protected virtual void OnOpened(EventArgs e)
        {
            if (IsHandleCreated)
            {
                if (ownerItem is null || !ownerItem.IsInDesignMode)
                {
                    AccessibilityNotifyClients(AccessibleEvents.SystemMenuPopupStart, -1);
                }
            }

            ((EventHandler)Events[EventOpened])?.Invoke(this, e);
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            if (Location != displayLocation)
            {
                // If we adjusted the position from where the user wanted it,
                // see if we can put it in the right location now that they've changed
                // the items collection, and store where we actually have it.

                // Just because this is the case doesn't mean that we need to do another
                // another layout however.
                Location = displayLocation;
                displayLocation = Location;
            }
            if (AutoScroll || LayoutRequired)
            {
                // the base here forces a layout... we really only want to do this the first
                // time we pop the window... the subsequent times should be snappy.
                base.OnVisibleChanged(e);
            }
            else
            {
                SuspendLayout();
                try
                {
                    // scrollable control forces a layout here for scrollbar reasons only
                    // since we toggle visibility a lot this is expensive.  Let's be clever and
                    // not do it.
                    base.OnVisibleChanged(e);
                }
                finally
                {
                    ResumeLayout(false);
                }
            }
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            Rectangle bounds = Bounds;
            SetBoundsCore(bounds.X, bounds.Y, bounds.Width, bounds.Height, BoundsSpecified.Location);
        }
        protected override void OnMouseUp(MouseEventArgs mea)
        {
            base.OnMouseUp(mea);
            Debug.WriteLineIf(ToolStrip.s_snapFocusDebug.TraceVerbose, "[ToolStripDropDown.OnMouseUp] mouse up outside of the toolstrip - this should dismiss the entire chain");

            // Menus should dismiss when you drag off
            if (!ClientRectangle.Contains(mea.Location))
            {
                bool dismiss = true;
                if (OwnerToolStrip != null && OwnerItem != null)
                {
                    if (OwnerItem.Bounds.Contains(WindowsFormsUtils.TranslatePoint(mea.Location, this, OwnerToolStrip)))
                    {
                        dismiss = false;  // don't dismiss if we clicked on our owner item
                    }
                }
                if (dismiss)
                {
                    DismissAll();
                    CancelAutoExpand();
                }
            }
        }

        internal void OnOwnerItemFontChanged(EventArgs e)
        {
            if (IsAutoGenerated)
            {
                using (new LayoutTransaction(this, OwnerItem, PropertyNames.Font))
                {
                    OnFontChanged(e);
                }
            }
        }

        internal void SelectPreviousToolStrip()
        {
            // snap the owner item before calling hide as non-auto created dropdowns will
            // exit menu mode if there's no OwnerItem.
            ToolStripItem itemOnPreviousMenuToSelect = OwnerItem;
            Hide();

            if (itemOnPreviousMenuToSelect != null)
            {
                itemOnPreviousMenuToSelect.Select();

                KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(itemOnPreviousMenuToSelect);

                if (OwnerToolStrip != null)
                {
                    // make sure we send keyboard handling where we've just
                    // sent selection
                    if (!OwnerToolStrip.IsDropDown)
                    {
                        if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() != OwnerToolStrip)
                        {
                            ToolStripManager.ModalMenuFilter.SetActiveToolStrip(OwnerToolStrip);
                        }
                        // escape should cancel auto expansion
                        OwnerToolStrip.MenuAutoExpand = false;
                        // When the control cannot be select (TabStop), we can press "Tab" to
                        // navigate inside the owner toolstip. Otherwise, press "Tab" will leave
                        // the owner toolstrip so it should exit the menu mode.
                        if (OwnerToolStrip.CanSelect)
                        {
                            ToolStripManager.ModalMenuFilter.ExitMenuMode();
                        }
                    }
                }
            }
            else
            {
                Debug.WriteLineIf(ToolStrip.s_snapFocusDebug.TraceVerbose, "[ToolStripDropDown.SelectPreviousToolStrip] No previous toolstrip to select - exiting menu mode.");
                ToolStripManager.ModalMenuFilter.ExitMenuMode();
            }
        }

        /// <summary>
        ///  this is where we handle navigation between the File,Edit,View dropdowns
        ///  if you have one of these dropdowns showing and you hit the arrow key
        ///  and it's not processed by the menu item
        ///  </summary>
        internal override bool ProcessArrowKey(Keys keyCode)
        {
            Debug.WriteLineIf(ToolStrip.s_menuAutoExpandDebug.TraceVerbose, "[ToolStripDropDown.ProcessArrowKey] MenuTimer.Cancel called");

            ToolStripMenuItem.MenuTimer.Cancel();

            if (keyCode == Keys.Left || keyCode == Keys.Right)
            {
                bool forward = keyCode == Keys.Right;

                if (!IsFirstDropDown && !forward)
                {
                    // this is the case where you've casecaded out to a second level dropdown and you hit the back arrow
                    // key.  In this case we want to just hide the current dropdown
                    Visible = false;
                    return true;
                }
                else
                {
                    bool closeOnHorizontalKey = false;
                    if (LayoutStyle == ToolStripLayoutStyle.Flow)
                    {
                        closeOnHorizontalKey = FlowLayout.GetFlowDirection(this) == FlowDirection.TopDown && !FlowLayout.GetWrapContents(this);
                    }

                    if (closeOnHorizontalKey)
                    {
                        ToolStrip toplevelToolStrip = GetToplevelOwnerToolStrip();
                        ToolStripItem rootItem = GetToplevelOwnerItem();

                        // This is the case where you need to open up the adjacent DropDown (File->Edit) menus because:
                        //      - this is the toplevel ToolStripDropDown and you hit left or right
                        //      - this is a non-toplevel ToolStripDropDown and you hit an arrow key in a direction
                        //        of the cascade AND the current item has no cascading menu associated with it.

                        bool isOnOverflow = (OwnerItem != null && OwnerItem.IsOnOverflow);
                        if (forward || !isOnOverflow)
                        {
                            SetCloseReason(ToolStripDropDownCloseReason.Keyboard);
                            DismissAll();
                        }
                        else if (isOnOverflow)
                        {
                            // Going backwards should roll us up and our children but not the overflow.
                            Visible = false;
                        }

                        if (toplevelToolStrip != null && rootItem != null)
                        {
                            if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() != toplevelToolStrip)
                            {
                                ToolStripManager.ModalMenuFilter.SetActiveToolStrip(toplevelToolStrip);
                            }
                            toplevelToolStrip.SelectNextToolStripItem(rootItem, forward);
                        }
                        return true;
                    }
                }
            }
            // get base behavior like up/down navigation.
            return base.ProcessArrowKey(keyCode);
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            if (OwnerItem != null && OwnerItem.IsInDesignMode)
            {
                return false;
            }

            if (AutoClose && Visible & ToolStripManager.IsMenuKey(keyData))
            {
                SetCloseReason(ToolStripDropDownCloseReason.Keyboard);
                DismissAll();
                ToolStrip toplevel = GetToplevelOwnerToolStrip();
                if (toplevel != null)
                {
                    Debug.WriteLineIf(ToolStrip.s_snapFocusDebug.TraceVerbose, "[ToolStripDropDown ProcessDialogKey]: Got Menu Key, finding toplevel toolstrip, calling RestoreFocus.");
                    toplevel.RestoreFocusInternal();
                    ToolStripManager.ModalMenuFilter.MenuKeyToggle = true;
                }
                ToolStripManager.ModalMenuFilter.ExitMenuMode();

                return true;
            }

            if ((keyData & Keys.KeyCode) == Keys.Escape)
            {
                SetCloseReason(ToolStripDropDownCloseReason.Keyboard);
                SelectPreviousToolStrip();

                return true;
            }

            return base.ProcessDialogKey(keyData);
        }

        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected override bool ProcessDialogChar(char charCode)
        {
            Debug.WriteLineIf(s_controlKeyboardRouting.TraceVerbose, "ToolStripDropDown.ProcessDialogChar [" + charCode.ToString() + "]");

            // Since we're toplevel and arent a container control, we've got to do our own mnemonic handling.
            if ((OwnerItem is null || OwnerItem.Pressed) && charCode != ' ' && ProcessMnemonic(charCode))
            {
                return true;
            }

            return base.ProcessDialogChar(charCode);
        }

        protected internal override bool ProcessMnemonic(char charCode)
        {
            if (!CanProcessMnemonic())
            {
                return false;
            }

            return base.ProcessMnemonic(charCode);
        }

        internal override void ProcessDuplicateMnemonic(ToolStripItem item, char charCode)
        {
            if (!CanProcessMnemonic())
            {
                return;
            }

            if (item != null)
            {
                base.ProcessDuplicateMnemonic(item, charCode);
            }
        }

        internal override void RecreateHandleCore()
        {
            // If we're visible, then we'll have set our parent hwnd to the active control.
            // That means that re-create handle will set it as our parent, but that's not what
            // we want, since that means that from now on we'll be displayed in that controls
            // client co-ordinates.  To fix this, we first re-parent ourselves back to the
            // hidden window, do the re-create, then set the parent again.
            if (Visible)
            {
                ReparentToDropDownOwnerWindow();
            }
            base.RecreateHandleCore();
            if (Visible)
            {
                ReparentToActiveToolStripWindow();
            }
        }

        private void ResetDropShadowEnabled()
        {
            DropShadowEnabled = true;
        }

        private void ReparentToActiveToolStripWindow()
        {
            ToolStripManager.ModalMenuFilter.SetActiveToolStrip(this);
            User32.SetWindowLong(this, User32.GWL.HWNDPARENT, ToolStripManager.ModalMenuFilter.ActiveHwnd);
        }

        private void ReparentToDropDownOwnerWindow()
        {
            // when we're toplevel we need to parent ourselves to a hidden window
            // this prevents a taskbar entry.
            NativeWindow ownerWindow = DropDownOwnerWindow;
            HandleRef ownerHandle = new HandleRef(ownerWindow, ownerWindow.Handle);
            User32.SetWindowLong(this, User32.GWL.HWNDPARENT, ownerHandle);
        }

        internal override void ResetScaling(int newDpi)
        {
            base.ResetScaling(newDpi);
            CommonProperties.xClearPreferredSizeCache(this);
            scaledDefaultPadding = DpiHelper.LogicalToDeviceUnits(defaultPadding, newDpi);
        }

        /// <summary>
        ///     VERY similar to Form.ScaleCore
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override void ScaleCore(float dx, float dy)
        {
            Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, GetType().Name + "::ScaleCore(" + dx + ", " + dy + ")");
            SuspendLayout();
            try
            {
                //Get size values in advance to prevent one change from affecting another.
                Size clientSize = ClientSize;
                Size minSize = MinimumSize;
                Size maxSize = MaximumSize;
                ClientSize = ScaleSize(clientSize, dx, dy);
                if (!MinimumSize.IsEmpty)
                {
                    MinimumSize = ScaleSize(minSize, dx, dy);
                }
                if (!MaximumSize.IsEmpty)
                {
                    MaximumSize = ScaleSize(maxSize, dx, dy);
                }

                ScaleDockPadding(dx, dy);

                foreach (Control control in Controls)
                {
                    if (control != null)
                    {
                        control.Scale(dx, dy);
                    }
                }
            }
            finally
            {
                ResumeLayout();
            }
        }

        /// <summary>
        ///  Scale this form.  Form overrides this to enforce a maximum / minimum size.
        /// </summary>
        protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
        {
            base.ScaleControl(factor, specified);

            Size minSize = MinimumSize;
            Size maxSize = MaximumSize;
            if (!MinimumSize.IsEmpty)
            {
                MinimumSize = ScaleSize(minSize, factor.Width, factor.Height);
            }
            if (!MaximumSize.IsEmpty)
            {
                MaximumSize = ScaleSize(maxSize, factor.Width, factor.Height);
            }
        }

        /// <summary>
        ///  This is called when the ToolStripDropDownItem sets the DropDown property using CreateDefaultDropDown.
        ///  In this case, the IsAutoGenerated should return true.
        /// </summary>
        internal void SetAutoGeneratedInternal(bool autoGenerated)
        {
            isAutoGenerated = autoGenerated;
        }

        /// <summary>
        ///  Sync sizes with the ToolStripDropDown
        /// </summary>
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            Rectangle bounds = new Rectangle(x, y, width, height);
            bounds = GetDropDownBounds(bounds);

            base.SetBoundsCore(bounds.X, bounds.Y, bounds.Width, bounds.Height, specified);
        }

        private void SetTopLevelStyle(bool value)
        {
            if (IsHandleCreated)
            {
                // We need to swap they style bits on the window handle
                // we could recreate the handle, but that seems rather expensive.
                int styleFlags = WindowStyle;

                if (value)
                {
                    // setting toplevel = true
                    styleFlags &= ~(int)User32.WS.CHILD;
                    styleFlags |= unchecked((int)User32.WS.POPUP);
                }
                else
                {
                    // this is a child window
                    styleFlags &= ~unchecked((int)User32.WS.POPUP);
                    styleFlags |= (int)User32.WS.CHILD;
                }

                WindowStyle = styleFlags;
            }
        }

        protected override void SetVisibleCore(bool visible)
        {
            if (state[stateInSetVisibleCore])
            {
                return;
            }

            state[stateInSetVisibleCore] = true;
            try
            {
                if (visible)
                {
                    if (LayoutRequired)
                    {
                        LayoutTransaction.DoLayout(this, this, PropertyNames.Visible);
                    }

                    // Assume that it's been cancelled so that if we throw we do nothing.
                    bool openingEventCancelled = true;

                    try
                    {
                        // Add opening event.
                        // Snap the foreground window BEFORE calling any user events so they
                        // dont have a chance to activate something else. This covers the case
                        // where someone handles the opening event and throws up a messagebox.
                        IntPtr foregroundWindow = User32.GetForegroundWindow();

                        // Fire Opening event
                        // Cancellable event in which default value of e.Cancel depends on
                        // the number of displayed items >0.
                        CancelEventArgs openEventArgs = new CancelEventArgs(cancel: DisplayedItems.Count == 0);
                        OnOpening(openEventArgs);

                        openingEventCancelled = openEventArgs.Cancel;

                        if (!openingEventCancelled)
                        {
                            // Do the actual work to open the window.
                            if (TopLevel)
                            {
                                ReparentToActiveToolStripWindow();
                            }

                            if (OwnerToolStrip != null)
                            {
                                OwnerToolStrip.ActiveDropDowns.Add(this);
                                // the act of showing this window can cause a spurious mouse move
                                // in the parent, make sure it retains where the mouse really was.
                                OwnerToolStrip.SnapMouseLocation();

                                // Make sure that mouse capture transitions between the owner and dropdown.
                                if (OwnerToolStrip.Capture)
                                {
                                    Capture = true;
                                }
                            }

                            base.SetVisibleCore(visible);

                            if (TopLevel)
                            {
                                ApplyTopMost(true);
                            }
                            else if (IsHandleCreated && User32.IsWindowEnabled(this).IsTrue())
                            {
                                User32.SetWindowPos(
                                    new HandleRef(this, Handle),
                                    User32.HWND_TOP,
                                    flags: User32.SWP.NOMOVE | User32.SWP.NOSIZE | User32.SWP.NOACTIVATE);
                            }
                        }
                    }
                    finally
                    {
                        // Fire the opened event only if we actually opened the control.
                        if (!openingEventCancelled)
                        {
                            OnOpened(EventArgs.Empty);
                        }
                    }
                }
                else
                {
                    if (Visible)
                    {
                        ToolStripDropDownCloseReason reason = closeReason;
                        ResetCloseReason();

                        var e = new ToolStripDropDownClosingEventArgs(reason);

                        // Fire Closing Event
                        // Cancel is prepopulated based on AutoClose feature.
                        if (e.CloseReason != ToolStripDropDownCloseReason.CloseCalled)
                        {
                            e.Cancel = !AutoClose;
                        }
                        else
                        {
                            e.Cancel = false;
                        }

                        try
                        {
                            OnClosing(e);
                        }
                        finally
                        {
                            // delay evaluate only in the case we need it
                            if (!e.Cancel)
                            {
                                // setting to not visible.  Dismiss our child drop downs, reset, set ourselves visible false.
                                DismissActiveDropDowns();

                                // Make sure we cancel auto expansion on the root
                                ToolStrip topLevelToolStrip = GetToplevelOwnerToolStrip();
                                ToolStrip parentToolStrip = OwnerItem?.ParentInternal;

                                // We don't consider reason == ToolStripDropDownCloseReason.Keyboard here.
                                // DropDown needs to be closed when Alt or ESC is pressed,
                                // but these two keys are handled in ToolStrip.RestoreFocusInternal()
                                // and ToolStripDropDown.SelectPreviousToolStrip() respectively,
                                // and ToolStrip.MenuAutoExpand of top level tool strip will be set false there.
                                // Left and Right keys may also close dropdown, but we don't need to
                                // set ToolStrip.MenuAutoExpand of top level tool strip to be false in such cases.
                                if ((reason == ToolStripDropDownCloseReason.AppClicked) ||
                                    (reason == ToolStripDropDownCloseReason.ItemClicked) ||
                                    (reason == ToolStripDropDownCloseReason.CloseCalled && topLevelToolStrip == parentToolStrip) ||
                                    (reason == ToolStripDropDownCloseReason.AppFocusChange && topLevelToolStrip == parentToolStrip))
                                {
                                    CancelAutoExpand();
                                }

                                // if this came through via a click event we should actually
                                // dismiss everyone in the chain. Other windows will receive a
                                // close, closing event with reason AppFocusChange. This is by
                                // design since the item wasn't clicked on that window.
                                if (reason == ToolStripDropDownCloseReason.ItemClicked)
                                {
                                    // Preserve the SourceControl value up the chain.
                                    saveSourceControl = true;
                                    DismissAll();

                                    // make sure that when we roll up, our owner item's selection is cleared.
                                    ToolStripItem rootOwnerItem = GetToplevelOwnerItem();
                                    rootOwnerItem?.Unselect();

                                    ToolStripManager.ModalMenuFilter.RemoveActiveToolStrip(this);

                                    Debug.WriteLineIf(ToolStrip.s_snapFocusDebug.TraceVerbose, "[ToolStripDropDown.SetVisibleCore] Exiting menu mode because item clicked");

                                    ToolStripManager.ModalMenuFilter.ExitMenuMode();
                                }
                                else
                                {
                                    ToolStripManager.ModalMenuFilter.RemoveActiveToolStrip(this);
                                }

                                // snap our bounds, we'll need it for some invalidation later.
                                Rectangle bounds = Bounds;

                                try
                                {
                                    base.SetVisibleCore(visible);
                                }
                                finally
                                {
                                    // Remove ourselves from the active dropdown list.
                                    OwnerToolStrip?.ActiveDropDowns.Remove(this);
                                    ActiveDropDowns.Clear();

                                    // If the user traps the click event and starts pumping their
                                    // own messages by calling Application.DoEvents, we should
                                    // release mouse capture.
                                    if (Capture)
                                    {
                                        Capture = false;
                                    }
                                }

                                // Fire OnClosed.
                                // if you make VisibleChanged throw you dont get closed. Sorry.
                                var closedEventArgs = new ToolStripDropDownClosedEventArgs(reason);
                                OnClosed(closedEventArgs);

                                if (TopLevel && (!IsDisposed || !Disposing))
                                {
                                    // Parent back up to our DropDownOwnerWindow.
                                    ReparentToDropDownOwnerWindow();
                                }

                                if (!saveSourceControl)
                                {
                                    Debug.Assert(reason != ToolStripDropDownCloseReason.ItemClicked,
                                        "Why are we resetting SourceControl on a click event?");

                                    // If we're not about to fire a Click event, reset SourceControl.
                                    SourceControlInternal = null;
                                }

                                // Making ourselves look presentable:
                                // We may be about to invoke a click event here...
                                // if we're the topmost dropdown then invalidate our
                                // intersection with the toplevel toolstrip
                                if (!DesignMode && IsFirstDropDown && OwnerItem != null && TopLevel)
                                {
                                    ToolStrip toolStrip = GetToplevelOwnerToolStrip();
                                    if (toolStrip != null && !(toolStrip.IsDisposed || toolStrip.Disposing))
                                    {
                                        // translate the bounds (already in screen coords) to toolstrip.
                                        bounds.Location = toolStrip.PointToClient(bounds.Location);

                                        // find the intersection with the client and use that to invalidate
                                        bounds.Intersect(toolStrip.ClientRectangle);

                                        if (bounds.Width > 0 && bounds.Height > 0)
                                        {
                                            toolStrip.Invalidate(bounds);
                                            toolStrip.Update();
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        ToolStripManager.ModalMenuFilter.RemoveActiveToolStrip(this);
                    }
                }
            }
            finally
            {
                state[stateInSetVisibleCore] = false;
                saveSourceControl = false;
            }
        }

        private bool ShouldSerializeDefaultDropDownDirection()
        {
            return (childDropDownDirection != ToolStripDropDownDirection.Default);
        }

        /// <summary>
        ///  Updates the layered window attributes if the control
        ///  is in layered mode.
        /// </summary>
        private void UpdateLayered()
        {
            if (state[stateLayered] && IsHandleCreated && TopLevel)
            {
                BOOL result = User32.SetLayeredWindowAttributes(this, 0, OpacityAsByte, User32.LWA.ALPHA);

                if (result.IsFalse())
                {
                    throw new Win32Exception();
                }
            }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new void Show()
        {
            // don't set displayLocation here, since all the other Show methods call this.
            base.Show();
        }

        /// <summary> show relative to control coordinates </summary>
        public void Show(Control control, Point position)
        {
            SourceControlInternal = control ?? throw new ArgumentNullException(nameof(control));
            // When we have no owner item and we're set to RTL.Inherit, translate the coordinates
            // so that the menu looks like it's swooping from the other side
            if (OwnerItem is null && control.RightToLeft == RightToLeft.Yes)
            {
                AdjustSize();
                position.Offset(control.IsMirrored ? Width : -Width, 0);
            }

            displayLocation = control.PointToScreen(position);
            Location = displayLocation;
            ShowCore();
        }

        public void Show(Control control, Point position, ToolStripDropDownDirection direction)
        {
            SourceControlInternal = control ?? throw new ArgumentNullException(nameof(control));
            displayLocation = CalculateDropDownLocation(control.PointToScreen(position), direction).Location;
            Location = displayLocation;
            ShowCore();
        }

        /// <summary> show relative to control coordinates </summary>
        public void Show(Control control, int x, int y)
        {
            SourceControlInternal = control ?? throw new ArgumentNullException(nameof(control));
            Show(control, new Point(x, y));
        }

        /// <summary> show relative to screen coordinates </summary>
        public void Show(Point screenLocation)
        {
            displayLocation = screenLocation;
            Location = displayLocation;
            ShowCore();
        }
        public void Show(Point position, ToolStripDropDownDirection direction)
        {
            displayLocation = CalculateDropDownLocation(position, direction).Location;
            Location = displayLocation;
            ShowCore();
        }

        /// <summary> show relative to screen coordinates </summary>
        public void Show(int x, int y)
        {
            displayLocation = new Point(x, y);
            Location = displayLocation;
            ShowCore();
        }

        private void ShowCore()
        {
            Show();
        }

        private bool ShouldSerializeDropShadowEnabled()
        {
            return dropShadowEnabled == false;
        }
        internal override bool ShouldSerializeLayoutStyle()
        {
            return LayoutStyle != ToolStripLayoutStyle.VerticalStackWithOverflow;
        }
        internal void UnassignDropDownItem()
        {
            Debug.Assert(countDropDownItemsAssignedTo > 0, "dropdown assignment underflow");
            countDropDownItemsAssignedTo = Math.Max(--countDropDownItemsAssignedTo, 0);
        }

        protected override void WndProc(ref Message m)
        {
            switch ((User32.WM)m.Msg)
            {
                case User32.WM.NCACTIVATE:
                    // if someone clicks on a child control of the toolstrip dropdown, we want
                    // the title bar to continue appearing active.  Normally we just show without
                    // taking window activation (ShowWindow(SHOWNOACTIVATE)) but we cant stop
                    // child controls from taking focus.
                    WmNCActivate(ref m);
                    return;
                case User32.WM.ACTIVATE:
                    // This is the Chrome Panel collection editor scenario
                    // we had focus, then the Chrome panel was activated and we never went away
                    // when we get focus again, we should reactivate our message filter.
                    Debug.WriteLineIf(ToolStrip.s_snapFocusDebug.TraceVerbose, "[ToolStripDropDown.WndProc] got a WM_ACTIVATE " + (((int)m.WParam == (int)User32.WA.ACTIVE) ? "WA_ACTIVE" : "WA_INACTIVE") + " - checkin if we need to set the active toolstrip");

                    if ((int)m.WParam == (int)User32.WA.ACTIVE)
                    {
                        if (Visible)
                        {
                            if (ToolStripManager.ModalMenuFilter.GetActiveToolStrip() != this)
                            {
                                // if we were inactive and now we are, we should enter menu mode
                                ToolStripManager.ModalMenuFilter.SetActiveToolStrip(this);
                            }
                        }
                        else
                        {
                            Debug.Fail("Why are we being activated when we're not visible? Deactivating thingee is " + WindowsFormsUtils.GetControlInformation(m.LParam));
                        }
                    }
                    else
                    {
                        Debug.WriteLineIf(ToolStrip.s_snapFocusDebug.TraceVerbose, "[ToolStripDropDown.WndProc] activating thingee is " + WindowsFormsUtils.GetControlInformation(m.LParam));
                    }

                    base.WndProc(ref m);
                    return;
                default:
                    base.WndProc(ref m);
                    return;
            }
        }

        #region DropDownSpecific
        internal void DismissAll()
        {
            ToolStripDropDown toplevel = GetFirstDropDown();
            toplevel.closeReason = closeReason;
            toplevel.DismissActiveDropDowns();
            toplevel.saveSourceControl = saveSourceControl;
            toplevel.Visible = false;
        }

        private void DismissActiveDropDowns()
        {
            Debug.WriteLineIf((DropDownActivateDebug.TraceVerbose && ActiveDropDowns.Count > 0), "Dismiss children called - COUNT " + ActiveDropDowns.Count + " \r\n" + new StackTrace().ToString());
            int count = ActiveDropDowns.Count;
            if (count == 1)
            {
                // this is the most common case
                if (ActiveDropDowns[0] is ToolStripDropDown dropDown)
                {
                    dropDown.Visible = false;
                }
            }
            else
            {
                ArrayList dropDowns = ActiveDropDowns.Clone() as ArrayList;
                // We cant iterate through the active dropdown collection
                // here as changing visibility changes the collection.
                for (int i = 0; i < dropDowns.Count; i++)
                {
                    if (dropDowns[i] is ToolStripDropDown dropDown)
                    {
                        dropDown.Visible = false;
                    }
                }
            }
        }

        #region WMNCACTIVATE
        private bool sendingActivateMessage;

        /// <summary>
        ///  If someone clicks on a child control of the toolstrip dropdown, we want
        ///  the title bar to continue appearing active.  Normally we just show without
        ///  taking window activation (ShowWindow(SHOWNOACTIVATE)) but we cant stop
        ///  child controls from taking focus.
        /// </summary>
        private unsafe void WmNCActivate(ref Message m)
        {
            if (m.WParam != IntPtr.Zero /*activating*/)
            {
                if (!sendingActivateMessage)
                {
                    sendingActivateMessage = true;
                    try
                    {
                        Debug.WriteLineIf(DropDownActivateDebug.TraceVerbose, "Sending WM_NCACTIVATE to toplevel hwnd" + ToolStripManager.ModalMenuFilter.ActiveHwnd);
                        // we're activating - notify the previous guy that we're activating.
                        HandleRef activeHwndHandleRef = ToolStripManager.ModalMenuFilter.ActiveHwnd;

                        User32.SendMessageW(activeHwndHandleRef, User32.WM.NCACTIVATE, (IntPtr)1, (IntPtr)(-1));
                        User32.RedrawWindow(
                            activeHwndHandleRef,
                            null,
                            IntPtr.Zero,
                            User32.RDW.FRAME | User32.RDW.INVALIDATE);
                        m.WParam = (IntPtr)1;
                    }
                    finally
                    {
                        sendingActivateMessage = false;
                    }
                }
                DefWndProc(ref m);
                return;
            }
            else
            {
                base.WndProc(ref m);
            }
        }
        #endregion
        /// <summary>
        ///  Determines if this is the first dropDown in the dropDown chain
        /// </summary>
        internal bool IsFirstDropDown
        {
            get
            {
                return ((OwnerToolStrip as ToolStripDropDown) is null);
            }
        }

        /// <summary>
        ///  returns the root dropdown in the chain.
        /// </summary>
        internal ToolStripDropDown GetFirstDropDown()
        {
            ToolStripDropDown topmost = this;
            // walk back up the chain of windows to get the topmost
            ToolStripDropDown ownerDropDown = topmost.OwnerToolStrip as ToolStripDropDown;
            while (ownerDropDown != null)
            {
                topmost = ownerDropDown;
                ownerDropDown = topmost.OwnerToolStrip as ToolStripDropDown;
            }
            return topmost;
        }

        internal static ToolStripDropDown GetFirstDropDown(ToolStrip start)
        {
            Debug.Assert(start != null, "Who is passing null to GetFirstDropDown?");
            if ((start is null) || (!start.IsDropDown))
            {
                return null;
            }
            ToolStripDropDown startDropDown = (start as ToolStripDropDown);
            return startDropDown.GetFirstDropDown();
        }

        #endregion DropDownSpecific

        public class ToolStripDropDownAccessibleObject : ToolStripAccessibleObject
        {
            private readonly ToolStripDropDown owner;

            public ToolStripDropDownAccessibleObject(ToolStripDropDown owner) : base(owner)
            {
                this.owner = owner;
            }

            internal override object GetPropertyValue(UiaCore.UIA propertyID)
            {
                switch (propertyID)
                {
                    case UiaCore.UIA.ControlTypePropertyId:
                        return UiaCore.UIA.MenuControlTypeId;
                    case UiaCore.UIA.IsKeyboardFocusablePropertyId:
                        return (State & AccessibleStates.Focusable) == AccessibleStates.Focusable;
                    case UiaCore.UIA.NamePropertyId:
                        return Name;
                }

                return base.GetPropertyValue(propertyID);
            }

            public override string Name
            {
                get
                {
                    // Special case: If an explicit name has been set in the AccessibleName property, use that.
                    // Note: Any non-null value in AccessibleName overrides the default accessible name logic,
                    // even an empty string (this is the only way to *force* the accessible name to be blank).
                    string name = owner.AccessibleName;
                    if (name != null)
                    {
                        return name;
                    }

                    if (owner.OwnerItem != null && owner.OwnerItem.AccessibilityObject.Name != null)
                    {
                        name = owner.OwnerItem.AccessibilityObject.Name;
                    }

                    return name;
                }

                set
                {
                    // If anyone tries to set the accessible name, just cache the value in the control's
                    // AccessibleName property. This value will then end up overriding the normal accessible
                    // name logic, until such time as AccessibleName is set back to null.
                    owner.AccessibleName = value;
                }
            }
            public override AccessibleRole Role
            {
                get
                {
                    AccessibleRole role = Owner.AccessibleRole;
                    if (role != AccessibleRole.Default)
                    {
                        return role;
                    }
                    return AccessibleRole.MenuPopup;
                }
            }
        }
    }
}
