File: winforms\Managed\System\WinForms\ToolStripGrip.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ToolStripGrip.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Windows.Forms {
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Windows.Forms.VisualStyles;
    using System.Windows.Forms.Layout;
    using System.Diagnostics;
    
    /// <summary>
    /// 
 
    internal class ToolStripGrip : ToolStripButton {
 
        private Cursor oldCursor;
        private int gripThickness = 0;
        Point startLocation = Point.Empty;
        private bool movingToolStrip = false;
        private Point lastEndLocation = ToolStrip.InvalidMouseEnter;
        private static Size DragSize = LayoutUtils.MaxSize;
 
        private static readonly Padding defaultPadding = new Padding(2);
        private static readonly int gripThicknessDefault = 3;
        private static readonly int gripThicknessVisualStylesEnabled = 5;
        private Padding scaledDefaultPadding = defaultPadding;
        private int scaledGripThickness = gripThicknessDefault;
        private int scaledGripThicknessVisualStylesEnabled = gripThicknessVisualStylesEnabled;
 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        internal ToolStripGrip()	{
            if (DpiHelper.EnableToolStripHighDpiImprovements) {
                scaledDefaultPadding = DpiHelper.LogicalToDeviceUnits(defaultPadding);
                scaledGripThickness = DpiHelper.LogicalToDeviceUnitsX(gripThicknessDefault);
                scaledGripThicknessVisualStylesEnabled = DpiHelper.LogicalToDeviceUnitsX(gripThicknessVisualStylesEnabled);
            }
 
            // if we're using XP themes we've got to be a bit thicker.
            gripThickness = ToolStripManager.VisualStylesEnabled ? scaledGripThicknessVisualStylesEnabled : scaledGripThickness;     
            SupportsItemClick = false;
        }
 
	    /// <devdoc>
        /// Deriving classes can override this to configure a default size for their control.
        /// This is more efficient than setting the size in the control's constructor.
        /// </devdoc>
        protected internal override Padding DefaultMargin {
            get {
                return scaledDefaultPadding;
            }
        }
 
        public override bool CanSelect {  
            get  {
                return false; 
            } 
        }
 
        internal int GripThickness {
            get {
                return gripThickness;
            }
        }
 
        internal bool MovingToolStrip {
            get {
                return ((ToolStripPanelRow != null) && movingToolStrip);  
            }
            set {
                if ((movingToolStrip != value) && ParentInternal != null) {
                    if (value) {
                        // dont let grips move the toolstrip
                        if (ParentInternal.ToolStripPanelRow == null) {
                            return;
                        }
                    }
                    movingToolStrip = value;
                    lastEndLocation = ToolStrip.InvalidMouseEnter;
                    if (movingToolStrip) {
                       ((ISupportToolStripPanel)this.ParentInternal).BeginDrag();
                    }
                    else {
                       ((ISupportToolStripPanel)this.ParentInternal).EndDrag();
                    }
                }
            }
        }
 
        private ToolStripPanelRow ToolStripPanelRow {
            get {
                return (ParentInternal == null) ? null : ((ISupportToolStripPanel)ParentInternal).ToolStripPanelRow;
            }
        }
 
        
        protected override AccessibleObject CreateAccessibilityInstance() {
            return new ToolStripGripAccessibleObject(this);
        }
 
        public override Size GetPreferredSize(Size constrainingSize) {
            Size preferredSize = Size.Empty;
            if (this.ParentInternal != null) {
                if (this.ParentInternal.LayoutStyle == ToolStripLayoutStyle.VerticalStackWithOverflow) {
                    preferredSize = new Size(this.ParentInternal.Width, gripThickness);
                }
                else {
                    preferredSize = new Size(gripThickness, this.ParentInternal.Height);
                    
                }
                    
            }
            // Constrain ourselves
            if (preferredSize.Width > constrainingSize.Width) {
                preferredSize.Width = constrainingSize.Width;
            }
 
            if (preferredSize.Height > constrainingSize.Height) {
                preferredSize.Height = constrainingSize.Height;
            }
            
            return preferredSize;
        }
 
        private bool LeftMouseButtonIsDown() {
          return (Control.MouseButtons == MouseButtons.Left) && (Control.ModifierKeys == Keys.None);
        }
         
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
            // all the grip painting should be on the ToolStrip itself. 
            if (ParentInternal != null) {
                ParentInternal.OnPaintGrip(e);
            }
        }
            
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mea"></param>
        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs mea) {            
            startLocation =  TranslatePoint(new Point(mea.X, mea.Y), ToolStripPointType.ToolStripItemCoords, ToolStripPointType.ScreenCoords);
            base.OnMouseDown(mea);
        }
 
        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs mea) {  
            bool leftMouseButtonDown = LeftMouseButtonIsDown();
            if (!MovingToolStrip && leftMouseButtonDown) {
 
                // determine if we've moved far enough such that the toolstrip
                // can be considered as moving.
                Point currentLocation =  TranslatePoint(mea.Location, ToolStripPointType.ToolStripItemCoords, ToolStripPointType.ScreenCoords);
                int deltaX = currentLocation.X - startLocation.X;
                deltaX = (deltaX < 0) ? deltaX *-1 : deltaX;
 
                if (DragSize == LayoutUtils.MaxSize) {
                    DragSize = SystemInformation.DragSize;
                }
               
                if (deltaX >= DragSize.Width) {
                    MovingToolStrip = true;
                }
                else {
                     int deltaY = currentLocation.Y - startLocation.Y;
                     deltaY = (deltaY < 0) ? deltaY *-1 : deltaY;
 
                    if (deltaY >= DragSize.Height) {
                        MovingToolStrip = true;
                    }
                }
                
            }
            if (MovingToolStrip) {
                if (leftMouseButtonDown) {
                    Point endLocation = TranslatePoint(new Point(mea.X, mea.Y), ToolStripPointType.ToolStripItemCoords, ToolStripPointType.ScreenCoords);
                    // protect against calling when the mouse hasnt really moved.  moving the toolstrip/creating the feedback rect
                    // can cause extra mousemove events, we want to make sure we're not doing all this work
                    // for nothing.
                    if (endLocation != lastEndLocation) {
                        ToolStripPanelRow.ToolStripPanel.MoveControl(ParentInternal, /*startLocation,*/endLocation );
                        lastEndLocation = endLocation;
                    }                        
                    startLocation = endLocation;
                }
                else {
                    // sometimes we dont get mouseup in DT.   Release now.
                    MovingToolStrip = false;
                }
            }
    
            base.OnMouseMove(mea);
        }
 
        protected override void OnMouseEnter(System.EventArgs e) { 
 
            // only switch the cursor if we've got a rafting row.
            if ((ParentInternal != null) && (ToolStripPanelRow != null) && (!ParentInternal.IsInDesignMode)) {
                oldCursor = ParentInternal.Cursor;
                SetCursor(ParentInternal, Cursors.SizeAll);
            }
            else {
                oldCursor = null;
            }
            base.OnMouseEnter(e);
 
        }
 
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(System.EventArgs e) { 
            if (oldCursor != null && !ParentInternal.IsInDesignMode) {
                SetCursor(ParentInternal,oldCursor);
            }
            if (!MovingToolStrip && LeftMouseButtonIsDown()) {
                MovingToolStrip = true;
            }
            base.OnMouseLeave(e);
        }
 
       
        
        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs mea) {    
            if (MovingToolStrip) {
                Point endLocation = TranslatePoint(new Point(mea.X, mea.Y), ToolStripPointType.ToolStripItemCoords, ToolStripPointType.ScreenCoords);
                ToolStripPanelRow.ToolStripPanel.MoveControl(ParentInternal, /*startLocation,*/endLocation );
            }
 
            if (!ParentInternal.IsInDesignMode) {
                SetCursor(ParentInternal, oldCursor);
            }
            ToolStripPanel.ClearDragFeedback();
            MovingToolStrip = false;
            base.OnMouseUp(mea);
        }
 
        internal override void ToolStrip_RescaleConstants(int oldDpi, int newDpi) {
            base.RescaleConstantsInternal(newDpi);
            scaledDefaultPadding = DpiHelper.LogicalToDeviceUnits(defaultPadding, newDpi);
            scaledGripThickness = DpiHelper.LogicalToDeviceUnits(gripThicknessDefault, newDpi);
            scaledGripThicknessVisualStylesEnabled = DpiHelper.LogicalToDeviceUnits(gripThicknessVisualStylesEnabled, newDpi);
            this.Margin = DefaultMargin;
 
            gripThickness = ToolStripManager.VisualStylesEnabled ? scaledGripThicknessVisualStylesEnabled : scaledGripThickness;
 
            OnFontChanged(EventArgs.Empty);
        }
 
        private static void SetCursor(Control control, Cursor cursor) {
            IntSecurity.ModifyCursor.Assert();
            control.Cursor = cursor;
            // CodeAccessPermission.RevertAssert automatically called 
        }
 
        internal class ToolStripGripAccessibleObject : ToolStripButtonAccessibleObject {
            private string stockName;
 
            public ToolStripGripAccessibleObject(ToolStripGrip owner) : base(owner){
            }
 
            public override string Name {
                get {
                    string name = Owner.AccessibleName;
                    if (name != null) {
                        return name;
                    }
                    if (string.IsNullOrEmpty(stockName)) {
                        stockName = SR.GetString(SR.ToolStripGripAccessibleName);
                    }
                    return stockName;
                }
                set {
                    base.Name  = value;
                }
            }
 
            
            public override AccessibleRole Role {
               get {
                   AccessibleRole role = Owner.AccessibleRole;
                   if (role != AccessibleRole.Default) {
                       return role;
                   }
                   return AccessibleRole.Grip;
               }
            }
 
            internal override object GetPropertyValue(int propertyID) {
                if (AccessibilityImprovements.Level3) {
                    switch (propertyID) {
                        case NativeMethods.UIA_IsOffscreenPropertyId:
                            return false;
                        case NativeMethods.UIA_ControlTypePropertyId:
                            return NativeMethods.UIA_ThumbControlTypeId;
                    }
                }
 
                return base.GetPropertyValue(propertyID);
            }
        }
    }
}