File: winforms\Managed\System\WinForms\ContextMenu.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ContextMenu.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Windows.Forms {
 
    using Microsoft.Win32;
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Security;
    using System.Security.Permissions;
 
    /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu"]/*' />
    /// <devdoc>
    ///     This class is used to put context menus on your form and show them for
    ///     controls at runtime.  It basically acts like a regular Menu control,
    ///     but can be set for the ContextMenu property that most controls have.
    /// </devdoc>
    [
    DefaultEvent("Popup"),
    ]
    public class ContextMenu : Menu {
 
        private EventHandler onPopup;
        private EventHandler onCollapse;
        internal Control sourceControl;
        
        private RightToLeft rightToLeft = System.Windows.Forms.RightToLeft.Inherit;
    
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.ContextMenu"]/*' />
        /// <devdoc>
        ///     Creates a new ContextMenu object with no items in it by default.
        /// </devdoc>
        public ContextMenu()
            : base(null) {
        }
 
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.ContextMenu1"]/*' />
        /// <devdoc>
        ///     Creates a ContextMenu object with the given MenuItems.
        /// </devdoc>
        public ContextMenu(MenuItem[] menuItems)
            : base(menuItems) {
        }
 
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.SourceControl"]/*' />
        /// <devdoc>
        ///     The last control that was acted upon that resulted in this context
        ///     menu being displayed.
        ///     VSWHIDBEY 426099 - add demand for AllWindows.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.ContextMenuSourceControlDescr)
        ]
        public Control SourceControl {
            [UIPermission(SecurityAction.Demand, Window=UIPermissionWindow.AllWindows)]
            get {
                return sourceControl;
            }
        }
 
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.Popup"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [SRDescription(SR.MenuItemOnInitDescr)]
        public event EventHandler Popup {
            add {
                onPopup += value;
            }
            remove {
                onPopup -= value;
            }
        }
        
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.Collapse"]/*' />
        /// <devdoc>
        ///    Fires when the context menu collapses.
        /// </devdoc>
        [SRDescription(SR.ContextMenuCollapseDescr)]
        public event EventHandler Collapse {
            add {
                onCollapse += value;
            }
            remove {
                onCollapse -= value;
            }
        }
        
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.RightToLeft"]/*' />
        /// <devdoc>
        ///     This is used for international applications where the language
        ///     is written from RightToLeft. When this property is true,
        ///     text alignment and reading order will be from right to left.
        /// </devdoc>
        // VSWhidbey 164244: Add a DefaultValue attribute so that the Reset context menu becomes
        // available in the Property Grid but the default value remains No.
        [
        Localizable(true),
        DefaultValue(RightToLeft.No),
        SRDescription(SR.MenuRightToLeftDescr)
        ]
        public virtual RightToLeft RightToLeft {
            get {
                if (System.Windows.Forms.RightToLeft.Inherit == rightToLeft) {
                    if (sourceControl != null) {
                        return ((Control)sourceControl).RightToLeft;
                    }
                    else {
                        return RightToLeft.No;
                    }
                }
                else {
                    return rightToLeft;
                }
            }
            set {
            
                //valid values are 0x0 to 0x2.
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)RightToLeft.No, (int)RightToLeft.Inherit)){
                    throw new InvalidEnumArgumentException("RightToLeft", (int)value, typeof(RightToLeft));
                }
                if (RightToLeft != value) {
                    rightToLeft = value;
                    UpdateRtl((value == System.Windows.Forms.RightToLeft.Yes));
                }
 
            }
        } 
 
        internal override bool RenderIsRightToLeft {
            get {
                return (rightToLeft == System.Windows.Forms.RightToLeft.Yes);
            }
        }
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.OnPopup"]/*' />
        /// <devdoc>
        ///     Fires the popup event
        /// </devdoc>
        protected internal virtual void OnPopup(EventArgs e) {
            if (onPopup != null) {
                onPopup(this, e);
            }
        }
 
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.OnCollapse"]/*' />
        /// <devdoc>
        ///     Fires the collapse event
        /// </devdoc>
        protected internal virtual void OnCollapse(EventArgs e) {
            if (onCollapse != null) {
                onCollapse(this, e);
            }
        }
 
        /// <include file='doc\Menu.uex' path='docs/doc[@for="ContextMenu.ProcessCmdKey"]/*' />
        /// <devdoc>
        /// </devdoc>
        /// <internalonly/>
        [
            System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode),
            System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)
        ]
        protected internal virtual bool ProcessCmdKey(ref Message msg, Keys keyData, Control control) {
            sourceControl = control;
            return ProcessCmdKey(ref msg, keyData);
        }
 
        private void ResetRightToLeft() {
        	RightToLeft = RightToLeft.No;	
        }
        
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.ShouldSerializeRightToLeft"]/*' />
        /// <devdoc>
        ///     Returns true if the RightToLeft should be persisted in code gen.
        /// </devdoc>
        internal virtual bool ShouldSerializeRightToLeft() {
            if (System.Windows.Forms.RightToLeft.Inherit == rightToLeft) {
                return false;
            }
            return true;
        }
 
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.Show"]/*' />
        /// <devdoc>
        ///     Displays the context menu at the specified position.  This method
        ///     doesn't return until the menu is dismissed.
        /// </devdoc>
        public void Show(Control control, Point pos) {
            Show(control, pos, NativeMethods.TPM_VERTICAL | NativeMethods.TPM_RIGHTBUTTON);
        }
 
        /// <include file='doc\ContextMenu.uex' path='docs/doc[@for="ContextMenu.Show2"]/*' />
        /// <devdoc>
        ///     Displays the context menu at the specified position.  This method
        ///     doesn't return until the menu is dismissed.
        /// </devdoc>
        public void Show(Control control, Point pos, LeftRightAlignment alignment)  {
 
            // This code below looks wrong but it's correct. 
            // Microsoft Left alignment means we want the menu to show up left of the point it is invoked from.
            // We specify TPM_RIGHTALIGN which tells win32 to align the right side of this 
            // menu with the point (which aligns it Left visually)
            if (alignment == LeftRightAlignment.Left) {
                Show(control, pos, NativeMethods.TPM_VERTICAL | NativeMethods.TPM_RIGHTBUTTON | NativeMethods.TPM_RIGHTALIGN);
            }
            else {
                Show(control, pos, NativeMethods.TPM_VERTICAL | NativeMethods.TPM_RIGHTBUTTON | NativeMethods.TPM_LEFTALIGN);
            }
        }
 
        private void Show(Control control, Point pos, int flags) {
            if (control == null)
                throw new ArgumentNullException("control");
 
            if (!control.IsHandleCreated || !control.Visible)
                throw new ArgumentException(SR.GetString(SR.ContextMenuInvalidParent), "control");
 
            sourceControl = control;
 
            OnPopup(EventArgs.Empty);
            pos = control.PointToScreen(pos);
            SafeNativeMethods.TrackPopupMenuEx(new HandleRef(this, Handle),
                flags,
                pos.X,
                pos.Y,
                new HandleRef(control, control.Handle),
                null);
        }
            
    }
}