ToolStripDropDownMenu.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / WinForms / Managed / System / WinForms / ToolStripDropDownMenu.cs / 1 / ToolStripDropDownMenu.cs

                            namespace System.Windows.Forms {

    using System;
    using System.Collections; 
    using System.ComponentModel;
    using System.ComponentModel.Design.Serialization; 
    using System.Diagnostics; 
    using System.Drawing;
    using System.Globalization; 
    using System.Windows.Forms.Layout;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Security; 
    using System.Security.Permissions;
    using System.Windows.Forms.Internal; 
    using System.Collections.Specialized; 
    using System.Diagnostics.CodeAnalysis;
 
    /// 
    [Designer("System.Windows.Forms.Design.ToolStripDropDownDesigner, " + AssemblyRef.SystemDesign)]
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDispatch)] 
    public class ToolStripDropDownMenu : ToolStripDropDown {
 
            private static Padding ImagePadding     = new Padding(2); 
            private static Padding TextPadding      = new Padding(8,1,9,1);
            private static Padding CheckPadding     = new Padding(5,2,2,2); 
            private static Padding ArrowPadding     = new Padding(0,0,8,0);

            // This is totally a UI Fudge - if we have an image or check margin with
            // no image or checks in it use this - which is consistent with office 
            // and an image margin with a 16x16 icon in it.
            private static int DefaultImageMarginWidth = 25; // 24+1px border 
            private static int DefaultImageAndCheckMarginWidth = 47;  // 46+1px border 

            private Size maxItemSize            = Size.Empty; 
            private Rectangle checkRectangle    = Rectangle.Empty;
            private Rectangle imageRectangle    = Rectangle.Empty;
            private Rectangle arrowRectangle    = Rectangle.Empty;
            private Rectangle textRectangle     = Rectangle.Empty; 
            private Rectangle imageMarginBounds = Rectangle.Empty;
            private int paddingToTrim = 0; 
            private int tabWidth = -1; 

            private ToolStripScrollButton upScrollButton = null; 
            private ToolStripScrollButton downScrollButton = null;
            private int scrollAmount = 0;
            private int indexOfFirstDisplayedItem = -1;
 
            private BitVector32                    state                               = new BitVector32();
 
            private static readonly int stateShowImageMargin          = BitVector32.CreateMask(); 
            private static readonly int stateShowCheckMargin          = BitVector32.CreateMask(stateShowImageMargin);
            private static readonly int stateMaxItemSizeValid         = BitVector32.CreateMask(stateShowCheckMargin); 

            private static readonly Size defaultImageSize = new Size(16,16);

            ///  
            /// 
            /// Summary of ToolStripDropDown. 
            ///  
            public ToolStripDropDownMenu(){
            } 

            /// 
            /// Constructor to autogenerate
            ///  
            internal ToolStripDropDownMenu(ToolStripItem ownerItem, bool isAutoGenerated) : base(ownerItem,isAutoGenerated) {
            } 
 
            internal override bool AllItemsVisible {
                get { 
                    return !RequiresScrollButtons;
                }
                set {
                    RequiresScrollButtons = !value; 
                }
            } 
 
            internal Rectangle ArrowRectangle {
                get { 
                    return arrowRectangle;
                }
            }
 
            internal Rectangle CheckRectangle {
                get { 
                    return checkRectangle; 
                }
            } 

            /// 
            protected override Padding DefaultPadding {
                get { 
                    RightToLeft rightToLeft = RightToLeft;
 
                    int textPadding = (rightToLeft == RightToLeft.Yes) ? TextPadding.Right : TextPadding.Left; 
                    int padding = (ShowCheckMargin || ShowImageMargin) ? textPadding + ImageMargin.Width : textPadding;
 
                    // scooch in all the items by the margin.
                    if (rightToLeft == RightToLeft.Yes) {
                         return new Padding(1,2,padding,2);
                    } 
                    return new Padding(padding,2,1,2);
                } 
            } 

            ///  
            public override Rectangle DisplayRectangle {
                get {
                    Rectangle rect = base.DisplayRectangle;
                    if (GetToolStripState(STATE_SCROLLBUTTONS)) { 

                        rect.Y += UpScrollButton.Height + UpScrollButton.Margin.Vertical; 
                        rect.Height -= UpScrollButton.Height + UpScrollButton.Margin.Vertical + DownScrollButton.Height + DownScrollButton.Margin.Vertical; 
                        // Because we're going to draw the scroll buttons on top of the padding, we need to add it back in here.
                        rect = LayoutUtils.InflateRect(rect, new Padding(0, this.Padding.Top, 0, this.Padding.Bottom)); 
                    }
                    return rect;
                }
            } 

            private ToolStripScrollButton DownScrollButton { 
                get { 
                    if (downScrollButton == null) {
                        downScrollButton = new ToolStripScrollButton(false); 
                        downScrollButton.ParentInternal = this;
                    }
                    return downScrollButton;
                } 
            }
            ///  
            ///  the rectangle representing 
            /// 
            internal Rectangle ImageRectangle { 
                get {
                    return imageRectangle;
                }
            } 

            internal int PaddingToTrim { 
                get { 
                    return paddingToTrim;
                } 
                set {
                    if (paddingToTrim != value) {
                        paddingToTrim = value;
                        AdjustSize(); 
                    }
 
                } 
            }
 
            /// 
            ///  the rectangle representing the color stripe in the menu - this will appear as AffectedBounds
            ///  in the ToolStripRenderEventArgs
            ///  
            internal Rectangle ImageMargin {
                get { 
                    imageMarginBounds.Height =this.Height; 
                    return imageMarginBounds;
                } 
            }

            /// 
            public override LayoutEngine LayoutEngine { 
                get {
                     return ToolStripDropDownLayoutEngine.LayoutInstance; 
                } 
            }
 
            [
            DefaultValue(ToolStripLayoutStyle.Flow)
            ]
            public new ToolStripLayoutStyle LayoutStyle { 
                get { return base.LayoutStyle; }
                set { base.LayoutStyle = value; } 
            } 

            ///  
            protected internal override Size MaxItemSize {
                get {
                    if (!state[stateMaxItemSizeValid]) {
                        CalculateInternalLayoutMetrics(); 
                    }
                    return maxItemSize; 
                } 
            }
 
            /// 
            [
            DefaultValue(true),
            SRDescription(SR.ToolStripDropDownMenuShowImageMarginDescr), 
            SRCategory(SR.CatAppearance)
            ] 
            public bool ShowImageMargin { 
                get {
                    return state[stateShowImageMargin]; 
                }
                set {
                    if (value != state[stateShowImageMargin]) {
                        state[stateShowImageMargin] = value; 
                        LayoutTransaction.DoLayout(this, this, PropertyNames.ShowImageMargin);
                    } 
                } 
            }
 
            /// 
            [
            DefaultValue(false),
            SRDescription(SR.ToolStripDropDownMenuShowCheckMarginDescr), 
            SRCategory(SR.CatAppearance)
            ] 
            public bool ShowCheckMargin { 
                get {
                    return state[stateShowCheckMargin]; 
                }
                set {
                    if (value != state[stateShowCheckMargin]) {
                        state[stateShowCheckMargin] = value; 
                        LayoutTransaction.DoLayout(this, this, PropertyNames.ShowCheckMargin);
                    } 
                } 
            }
 

            internal Rectangle TextRectangle {
                get {
                    return textRectangle; 
                }
            } 
 
            private ToolStripScrollButton UpScrollButton {
                get { 
                    if (upScrollButton == null) {
                        upScrollButton = new ToolStripScrollButton(true);
                        upScrollButton.ParentInternal = this;
                    } 
                    return upScrollButton;
                } 
            } 

            ///  this takes a native menu and builds up a managed toolstrip around it. 
            ///          Scenario: showing the items from the SystemMenu.
            ///          targetWindow is the window to send WM_COMMAND, WM_SYSCOMMAND to
            ///          hmenu is a handle to the native menu
            /// 
            ///
 
            internal static ToolStripDropDownMenu FromHMenu(IntPtr hmenu, IWin32Window targetWindow) { 
                ToolStripDropDownMenu managedDropDown = new ToolStripDropDownMenu();
                managedDropDown.SuspendLayout(); 


                HandleRef menuHandle = new HandleRef(null, hmenu);
                int count = UnsafeNativeMethods.GetMenuItemCount(menuHandle); 

                ToolStripItem itemToAdd; 
 
                // surf through the items in the collection, building up TSMenuItems and TSSeparators
                // corresponding to the native menu. 
                for (int i = 0; i < count; i++) {
                    // peek at the i'th item.
                    NativeMethods.MENUITEMINFO_T_RW info = new NativeMethods.MENUITEMINFO_T_RW();
                    info.cbSize = Marshal.SizeOf(typeof(NativeMethods.MENUITEMINFO_T_RW)); 
                    info.fMask = NativeMethods.MIIM_FTYPE;
                    info.fType = NativeMethods.MIIM_FTYPE; 
                    UnsafeNativeMethods.GetMenuItemInfo(menuHandle, i, /*fByPosition=*/ true, info); 

                    if (info.fType == NativeMethods.MFT_SEPARATOR){ 
                        // its a separator.
                    	itemToAdd = new ToolStripSeparator();
                    }
                    else { 
                        // its a menu item... lets fish out the command id
                     	info = new NativeMethods.MENUITEMINFO_T_RW(); 
                    	info.cbSize = Marshal.SizeOf(typeof(NativeMethods.MENUITEMINFO_T_RW)); 
                    	info.fMask = NativeMethods.MIIM_ID;
                    	info.fType = NativeMethods.MIIM_ID; 
                    	UnsafeNativeMethods.GetMenuItemInfo(menuHandle, i, /*fByPosition=*/ true, info);

                        // create the managed object - toolstripmenu item knows how to grok hmenu for information.
                    	itemToAdd = new ToolStripMenuItem(hmenu, info.wID, targetWindow); 

 
                    	// if there is a submenu fetch it. 
                    	info = new NativeMethods.MENUITEMINFO_T_RW();
                    	info.cbSize = Marshal.SizeOf(typeof(NativeMethods.MENUITEMINFO_T_RW)); 
                    	info.fMask = NativeMethods.MIIM_SUBMENU;
                    	info.fType = NativeMethods.MIIM_SUBMENU;
                    	UnsafeNativeMethods.GetMenuItemInfo(menuHandle, i, /*fByPosition=*/ true, info);
 
                    	if (info.hSubMenu != IntPtr.Zero) {
                    	    // set the dropdown to be the items from the submenu 
                    		((ToolStripMenuItem)itemToAdd).DropDown = FromHMenu(info.hSubMenu, targetWindow); 
                    	}
                    } 

                    managedDropDown.Items.Add(itemToAdd);
                }
                managedDropDown.ResumeLayout(); 
                return managedDropDown;
            } 
 
            [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")] // using "\t" to figure out the width of tab
            private void  CalculateInternalLayoutMetrics() { 


                Size maxTextSize    = Size.Empty;
                Size maxImageSize   = Size.Empty; 
                Size maxCheckSize   = defaultImageSize;
                Size maxArrowSize   = Size.Empty; 
                Size maxNonMenuItemSize = Size.Empty; 

                // determine Text Metrics 
                for (int i = 0; i < Items.Count; i++)  {
                    ToolStripItem item = Items[i];
                    ToolStripMenuItem menuItem = item as ToolStripMenuItem;
 
                    if (menuItem != null) {
 
                        Size menuItemTextSize = menuItem.GetTextSize(); 

                        if (menuItem.ShowShortcutKeys)  { 
                            Size shortcutTextSize = menuItem.GetShortcutTextSize();
                            if (tabWidth == -1) {
                                tabWidth = TextRenderer.MeasureText("\t", this.Font).Width;
                            } 
                            menuItemTextSize.Width += tabWidth + shortcutTextSize.Width;
                            menuItemTextSize.Height = Math.Max(menuItemTextSize.Height, shortcutTextSize.Height); 
                        } 

                        // we truly only care about the maximum size we find. 
                        maxTextSize.Width = Math.Max(maxTextSize.Width, menuItemTextSize.Width);
                        maxTextSize.Height = Math.Max(maxTextSize.Height, menuItemTextSize.Height);

                        // determine Image Metrics 
                        Size imageSize = Size.Empty;
                        if (menuItem.Image != null) { 
                            imageSize = (menuItem.ImageScaling == ToolStripItemImageScaling.SizeToFit) ? ImageScalingSize : menuItem.Image.Size; 
                        }
 
                        maxImageSize.Width = Math.Max(maxImageSize.Width, imageSize.Width);
                        maxImageSize.Height = Math.Max(maxImageSize.Height, imageSize.Height);

                        if (menuItem.CheckedImage != null) { 
                            Size checkedImageSize = menuItem.CheckedImage.Size;
                            maxCheckSize.Width = Math.Max(checkedImageSize.Width, maxCheckSize.Width); 
                            maxCheckSize.Height = Math.Max(checkedImageSize.Height, maxCheckSize.Height); 
                        }
                    } 
                    else if (!(item is ToolStripSeparator)) {
                        maxNonMenuItemSize.Height = Math.Max(item.Bounds.Height, maxNonMenuItemSize.Height);
                        maxNonMenuItemSize.Width = Math.Max(item.Bounds.Width, maxNonMenuItemSize.Width);
                    } 
                }
 
                this.maxItemSize.Height =  Math.Max(maxTextSize.Height + TextPadding.Vertical, Math.Max(maxCheckSize.Height + CheckPadding.Vertical, maxArrowSize.Height + ArrowPadding.Vertical)); 

                if (ShowImageMargin) { 
                    // only add in the image into the calculation if we're going to render it.
                    this.maxItemSize.Height = Math.Max(maxImageSize.Height + ImagePadding.Vertical, maxItemSize.Height);
                }
 
                bool  useDefaultCheckMarginWidth = (ShowCheckMargin && (maxCheckSize.Width == 0));
                bool  useDefaultImageMarginWidth = (ShowImageMargin && (maxImageSize.Width == 0)); 
                // Always save space for an arrow 
                maxArrowSize = new Size(10, maxItemSize.Height);
 
                maxTextSize.Height = maxItemSize.Height -  TextPadding.Vertical;
                maxImageSize.Height = maxItemSize.Height - ImagePadding.Vertical;
                maxCheckSize.Height = maxItemSize.Height - CheckPadding.Vertical;
 
               // fixup if there are non-menu items that are larger than our normal menu items
               maxTextSize.Width = Math.Max(maxTextSize.Width, maxNonMenuItemSize.Width); 
 
               Point nextPoint = Point.Empty;
               int checkAndImageMarginWidth = 0; 

               int extraImageWidth = Math.Max(0, maxImageSize.Width - defaultImageSize.Width);

 
               if (ShowCheckMargin && ShowImageMargin) {
                    // double column - check margin then image margin 
                    // default to 46px - grow if necessary. 
                    checkAndImageMarginWidth = DefaultImageAndCheckMarginWidth;
 
                    // add in the extra space for the image... since the check size is locked down to 16x16.
                    checkAndImageMarginWidth += extraImageWidth;

                    // align the checkmark 
                    nextPoint = new Point(CheckPadding.Left, CheckPadding.Top);
               		checkRectangle = LayoutUtils.Align(maxCheckSize, new Rectangle(nextPoint.X, nextPoint.Y, maxCheckSize.Width, maxItemSize.Height), ContentAlignment.MiddleCenter); 
 
                    // align the image rectangle
                    nextPoint.X = checkRectangle.Right + CheckPadding.Right + ImagePadding.Left; 
                    nextPoint.Y = ImagePadding.Top;
                    imageRectangle = LayoutUtils.Align(maxImageSize, new Rectangle(nextPoint.X, nextPoint.Y, maxImageSize.Width, maxItemSize.Height), ContentAlignment.MiddleCenter);

               } 
               else if (ShowCheckMargin) {
                   // no images should be shown in a ShowCheckMargin only scenario. 
                   // default to 24px - grow if necessary. 
                   checkAndImageMarginWidth = DefaultImageMarginWidth;
 
                   // align the checkmark
                    nextPoint = new Point(1,CheckPadding.Top);
               //    nextPoint = new Point(CheckPadding.Left, CheckPadding.Top);
                   checkRectangle = LayoutUtils.Align(maxCheckSize, new Rectangle(nextPoint.X, nextPoint.Y, checkAndImageMarginWidth, maxItemSize.Height), ContentAlignment.MiddleCenter); 

                   imageRectangle = Rectangle.Empty; 
 
               }
               else if (ShowImageMargin) { 
                   // checks and images render in the same area.

                   // default to 24px - grow if necessary.
                   checkAndImageMarginWidth = DefaultImageMarginWidth; 

                   // add in the extra space for the image... since the check size is locked down to 16x16. 
                   checkAndImageMarginWidth += extraImageWidth; 

                   // NOTE due to the Padding property, we're going to have to recalc the vertical alignment in ToolStripMenuItemInternalLayout. 
                   // Dont fuss here over the Y, X is what's critical.

                   // check and image rect are the same - take the max of the image size and the check size and align
                   nextPoint = new Point(1,CheckPadding.Top); 
                   checkRectangle = LayoutUtils.Align(LayoutUtils.UnionSizes(maxCheckSize,maxImageSize), new Rectangle(nextPoint.X, nextPoint.Y, checkAndImageMarginWidth-1, maxItemSize.Height), ContentAlignment.MiddleCenter);
 
                   // align the image 
                   imageRectangle = checkRectangle;
 
               }
               else {
                    checkAndImageMarginWidth = 0;
               } 
               nextPoint.X = checkAndImageMarginWidth+1;
 
 
                // calculate space for image
                // if we didnt have a check - make sure to ignore check padding 

                // consider: should we constrain to a reasonable width?
                //imageMarginBounds = new Rectangle(0, 0, Math.Max(imageMarginWidth,DefaultImageMarginWidth), this.Height);
                imageMarginBounds = new Rectangle(0,0,checkAndImageMarginWidth, this.Height); 

                // calculate space for shortcut and text 
                nextPoint.X = imageMarginBounds.Right+ TextPadding.Left; 
                nextPoint.Y = TextPadding.Top;
                textRectangle = new Rectangle(nextPoint, maxTextSize); 

                // calculate space for arrow
                nextPoint.X = textRectangle.Right+ TextPadding.Right +ArrowPadding.Left;
                nextPoint.Y = ArrowPadding.Top; 
                arrowRectangle = new Rectangle(nextPoint, maxArrowSize);
 
                // calculate space required for all of these pieces 
                this.maxItemSize.Width =  (arrowRectangle.Right + ArrowPadding.Right) - imageMarginBounds.Left;
 
                this.Padding = DefaultPadding;
                int trimPadding = imageMarginBounds.Width;

                if (RightToLeft == RightToLeft.Yes) { 
                    // reverse the rectangle alignment in RightToLeft.Yes
                    trimPadding += TextPadding.Right; 
                    int width = maxItemSize.Width; 
                    checkRectangle.X        = width - checkRectangle.Right;
                    imageRectangle.X        = width - imageRectangle.Right; 
                    textRectangle.X         = width - textRectangle.Right;
                    arrowRectangle.X        = width - arrowRectangle.Right;
                    imageMarginBounds.X     = width - imageMarginBounds.Right;
 
                }
                else { 
                    trimPadding += TextPadding.Left; 
                }
 


                // VSWhidbey 339274 - we need to make sure that the text really appears vertically centered - this can be a problem in
                // systems which force the text rectangle to be odd. 

                // force this to be an even height. 
                this.maxItemSize.Height += this.maxItemSize.Height%2; 

                textRectangle.Y = LayoutUtils.VAlign(textRectangle.Size, new Rectangle(Point.Empty, maxItemSize), ContentAlignment.MiddleCenter).Y; 
                textRectangle.Y += (textRectangle.Height %2); // if the height is odd, push down by one px, see 339274 for picture
                state[stateMaxItemSizeValid]=true;
                this.PaddingToTrim = trimPadding;
 
            }
 
            internal override void ChangeSelection(ToolStripItem nextItem) { 
                if (nextItem != null) {
                    Rectangle displayRect = DisplayRectangle; 
                    if (!displayRect.Contains(displayRect.X, nextItem.Bounds.Top)
                        || !displayRect.Contains(displayRect.X, nextItem.Bounds.Bottom)) {

                        int delta; 
                        if (displayRect.Y > nextItem.Bounds.Top) {
                            delta = nextItem.Bounds.Top - displayRect.Y; 
                        } 
                        else {
                            delta = nextItem.Bounds.Bottom - (displayRect.Y + displayRect.Height); 
                            // Now adjust so that the item at the top isn't truncated.
                            int index = this.Items.IndexOf(nextItem);
                            while (index >= 0) {
                                if (this.Items[index].Visible && displayRect.Contains(displayRect.X, this.Items[index].Bounds.Top - delta)) { 
                                    --index;
                                } 
                                else { 
                                    break;
                                } 
                            }
                            if (index >= 0) {
                                if (displayRect.Contains(displayRect.X, this.Items[index].Bounds.Bottom - delta)) {
                                    // We found an item which is truncated at the top. 
                                    delta += (this.Items[index].Bounds.Bottom - delta) - displayRect.Top;
                                } 
                            } 
                        }
                        this.ScrollInternal(delta); 
                        this.UpdateScrollButtonStatus();
                    }
                }
                base.ChangeSelection(nextItem); 
            }
 
            protected internal override ToolStripItem CreateDefaultItem(string text, Image image, EventHandler onClick) { 
                if (text == "-") {
                    return new ToolStripSeparator(); 
                }
                else {
                    return new ToolStripMenuItem(text,image,onClick);
                } 
            }
 
            internal override ToolStripItem GetNextItem(ToolStripItem start, ArrowDirection direction, bool rtlAware) { 
                  // for up/down we dont care about flipping left/right tab should still take you down.
                return GetNextItem(start, direction); 
            }

            internal override void Initialize() {
                base.Initialize(); 
                this.Padding = DefaultPadding;
                FlowLayoutSettings settings = FlowLayout.CreateSettings(this); 
                settings.FlowDirection = FlowDirection.TopDown; 
                state[stateShowImageMargin] = true;
            } 
            /// 
            protected override void OnLayout(LayoutEventArgs e) {
                if (!this.IsDisposed)
                { 
                    // We always layout as if we don't need scroll buttons.
                    // If we do, then we'll adjust the positions to match. 
                    this.RequiresScrollButtons = false; 
                    CalculateInternalLayoutMetrics();
                    base.OnLayout(e); 
                    if (!this.RequiresScrollButtons) {
                        this.ResetScrollPosition();
                    }
                } 
            }
 
            protected override void OnFontChanged(EventArgs e) { 
                tabWidth = -1;
                base.OnFontChanged(e); 

            }
            /// 
            protected override void OnPaintBackground(PaintEventArgs e) { 
                base.OnPaintBackground(e);
                if (ShowCheckMargin || ShowImageMargin) { 
                    Renderer.DrawImageMargin(new ToolStripRenderEventArgs(e.Graphics, this, this.ImageMargin, SystemColors.Control)); 
                }
            } 

            internal override bool RequiresScrollButtons {
                get {
                    return GetToolStripState(STATE_SCROLLBUTTONS); 
                }
                set { 
                    bool changed = (RequiresScrollButtons != value); 
                    SetToolStripState(STATE_SCROLLBUTTONS, value);
                    if (changed) { 
                        UpdateScrollButtonLocations();
                        if (this.Items.Count > 0) {
                            int delta = this.Items[0].Bounds.Top - this.DisplayRectangle.Top;
                            this.ScrollInternal(delta); 
                            this.scrollAmount -= delta;
                            if (value) { 
                                RestoreScrollPosition(); 
                            }
                        } 
                        else {
                            this.scrollAmount = 0;
                        }
                    } 
                }
            } 
 
            internal void ResetScrollPosition() {
                this.scrollAmount = 0; 
            }

            internal void RestoreScrollPosition() {
                if (!RequiresScrollButtons || this.Items.Count == 0) { 
                    return;
                } 
 
                // We don't just scroll by the amount, because that might
                // cause the bottom of the menu to be blank if some items have 
                // been removed/hidden since the last time we were displayed.
                // This also deals with items of different height, so that we don't truncate
                // and items under the top scrollbar.
 
                Rectangle displayRectangle = this.DisplayRectangle;
                int alreadyScrolled = displayRectangle.Top - this.Items[0].Bounds.Top; 
 
                int requiredScrollAmount = this.scrollAmount - alreadyScrolled;
 
                int deltaToScroll = 0;
                if (requiredScrollAmount > 0) {
                    for (int i = 0; i < this.Items.Count && deltaToScroll < requiredScrollAmount; ++i) {
                        if (this.Items[i].Available) { 
                            Rectangle adjustedLastItemBounds = this.Items[this.Items.Count - 1].Bounds;
                            adjustedLastItemBounds.Y -= deltaToScroll; 
                            if (displayRectangle.Contains(displayRectangle.X, adjustedLastItemBounds.Top) 
                                && displayRectangle.Contains(displayRectangle.X, adjustedLastItemBounds.Bottom)) {
                                // Scrolling this amount would make the last item visible, so don't scroll any more. 
                                break;
                            }

                            // We use a delta between the tops, since it takes margin's and padding into account. 
                            if (i < this.Items.Count - 1) {
                                deltaToScroll += this.Items[i + 1].Bounds.Top - this.Items[i].Bounds.Top; 
                            } 
                            else {
                                deltaToScroll += this.Items[i].Bounds.Height; 
                            }
                        }
                    }
                } 
                else {
                    for (int i = this.Items.Count - 1; i >= 0 && deltaToScroll > requiredScrollAmount; --i) { 
                        if (this.Items[i].Available) { 
                            Rectangle adjustedLastItemBounds = this.Items[0].Bounds;
                            adjustedLastItemBounds.Y -= deltaToScroll; 
                            if (displayRectangle.Contains(displayRectangle.X, adjustedLastItemBounds.Top)
                                && displayRectangle.Contains(displayRectangle.X, adjustedLastItemBounds.Bottom)) {
                                // Scrolling this amount would make the last item visible, so don't scroll any more.
                                break; 
                            }
 
                            // We use a delta between the tops, since it takes margin's and padding into account. 
                            if (i > 0) {
                                deltaToScroll -= this.Items[i].Bounds.Top - this.Items[i - 1].Bounds.Top; 
                            }
                            else {
                                deltaToScroll -= this.Items[i].Bounds.Height;
                            } 
                        }
                    } 
                } 
                this.ScrollInternal(deltaToScroll);
                this.scrollAmount = this.DisplayRectangle.Top - this.Items[0].Bounds.Top; 
                UpdateScrollButtonLocations();
            }

 
            internal override void ScrollInternal(int delta) {
                base.ScrollInternal(delta); 
                this.scrollAmount += delta; 
            }
 
            internal void ScrollInternal(bool up) {
                UpdateScrollButtonStatus();

                // calling this to get ScrollWindowEx.  In actuality it does nothing 
                // to change the display rect!
                int delta; 
                if (this.indexOfFirstDisplayedItem == -1 || this.indexOfFirstDisplayedItem >= this.Items.Count) { 
                    Debug.Fail("Why wasn't 'UpdateScrollButtonStatus called'? We don't have the item to scroll by");
                    int menuHeight = SystemInformation.MenuHeight; 

                    delta = up ? -menuHeight : menuHeight;
                }
                else { 
                    if (up) {
                        if (this.indexOfFirstDisplayedItem == 0) { 
                            Debug.Fail("We're trying to scroll up, but the top item is displayed!!!"); 
                            delta = 0;
                        } 
                        else {
                            ToolStripItem itemTop = this.Items[this.indexOfFirstDisplayedItem - 1];
                            ToolStripItem itemBottom = this.Items[this.indexOfFirstDisplayedItem];
                            // We use a delta between the tops, since it takes margin's and padding into account. 
                            delta = itemTop.Bounds.Top - itemBottom.Bounds.Top;
                        } 
                    } 
                    else {
                        if (this.indexOfFirstDisplayedItem == this.Items.Count - 1) { 
                            Debug.Fail("We're trying to scroll down, but the top item is displayed!!!");
                            delta = 0;
                        }
 
                        ToolStripItem itemTop = this.Items[this.indexOfFirstDisplayedItem];
                        ToolStripItem itemBottom = this.Items[this.indexOfFirstDisplayedItem + 1]; 
                        // We use a delta between the tops, since it takes margin's and padding into account. 
                        delta = itemBottom.Bounds.Top - itemTop.Bounds.Top;
                    } 
                }
                ScrollInternal(delta);
                UpdateScrollButtonLocations();
            } 

            ///  
            protected override void SetDisplayedItems() { 

                base.SetDisplayedItems(); 
                if (RequiresScrollButtons) {

                    this.DisplayedItems.Add(UpScrollButton);
                    this.DisplayedItems.Add(DownScrollButton); 
                    UpdateScrollButtonLocations();
                    UpScrollButton.Visible = true; 
                    DownScrollButton.Visible = true; 
                }
                else { 
                    UpScrollButton.Visible = false;
                    DownScrollButton.Visible = false;
                }
            } 

            private void UpdateScrollButtonLocations() { 
 
                if (GetToolStripState(STATE_SCROLLBUTTONS)) {
                    Size upSize = UpScrollButton.GetPreferredSize(Size.Empty); 
                    //
                    Point upLocation = new Point(1, 0);

                    UpScrollButton.SetBounds(new Rectangle(upLocation, upSize)); 

                    Size downSize = DownScrollButton.GetPreferredSize(Size.Empty); 
                    int height = GetDropDownBounds(this.Bounds).Height; 

                    Point downLocation = new Point(1, height - downSize.Height); 
                    DownScrollButton.SetBounds(new Rectangle(downLocation, downSize));
                    UpdateScrollButtonStatus();
                }
 
            }
 
            private void UpdateScrollButtonStatus() { 
                Rectangle displayRectangle = this.DisplayRectangle;
 
                this.indexOfFirstDisplayedItem = -1;
                int minY = int.MaxValue, maxY = 0;

                for (int i = 0; i < this.Items.Count; ++i) { 
                    ToolStripItem item = this.Items[i];
                    if (UpScrollButton == item) { 
                        continue; 
                    }
                    if (DownScrollButton == item) { 
                        continue;
                    }

                    if (!item.Available) { 
                        continue;
                    } 
 
                    if (this.indexOfFirstDisplayedItem == -1 && displayRectangle.Contains(displayRectangle.X, item.Bounds.Top)) {
                        this.indexOfFirstDisplayedItem = i; 
                    }

                    minY = Math.Min(minY, item.Bounds.Top);
                    maxY = Math.Max(maxY, item.Bounds.Bottom); 
                }
 
                UpScrollButton.Enabled = !displayRectangle.Contains(displayRectangle.X, minY); 
                DownScrollButton.Enabled = !displayRectangle.Contains(displayRectangle.X, maxY);
            } 

            internal sealed class ToolStripDropDownLayoutEngine : FlowLayout {

                public static ToolStripDropDownLayoutEngine LayoutInstance = new ToolStripDropDownLayoutEngine(); 

                internal override Size GetPreferredSize(IArrangedElement container, Size proposedConstraints) { 
                        Size preferredSize = base.GetPreferredSize(container, proposedConstraints); 
                        ToolStripDropDownMenu dropDownMenu = container as ToolStripDropDownMenu;
                        if (dropDownMenu != null) { 
                            preferredSize.Width = dropDownMenu.MaxItemSize.Width - dropDownMenu.PaddingToTrim;
                        }
                        return preferredSize;
                } 

           } 
       } 
    }

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK