388 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			388 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Text;
 | |
| using System.ComponentModel;
 | |
| using System.Collections;
 | |
| using System.Windows.Forms;
 | |
| using System.Drawing;
 | |
| 
 | |
| namespace DevComponents.DotNetBar
 | |
| {
 | |
|     /// <summary>
 | |
|     /// Represents the context menu bar that provides the context menus for the System.Windows.Forms.Control inherited controls on the form.
 | |
|     /// </summary>
 | |
|     [ToolboxItem(true), Designer("DevComponents.DotNetBar.Design.ContextMenuBarDesigner, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=90f470f34c89ccaf"), ProvideProperty("ContextMenuEx", typeof(Control)), System.Runtime.InteropServices.ComVisible(false), DefaultEvent("ItemClick")]
 | |
|     public class ContextMenuBar : Bar, System.ComponentModel.IExtenderProvider
 | |
|     {
 | |
|         #region Private Variables
 | |
|         private Hashtable m_ContextExMenus = new Hashtable();
 | |
|         private Hashtable m_ContextExHandlers = new Hashtable();
 | |
|         private bool m_ContextMenuSubclass = true;
 | |
|         #endregion
 | |
| 
 | |
|         #region Internal Implementation
 | |
|         public ContextMenuBar() : base()
 | |
|         {
 | |
|             this.Visible = false;
 | |
|             this.WrapItemsDock = true;
 | |
|             this.WrapItemsFloat = true;
 | |
|         }
 | |
| 
 | |
|         protected override bool IsContextPopup(BaseItem popup)
 | |
|         {
 | |
|             if (this.Items.Contains(popup)) return true;
 | |
|             return base.IsContextPopup(popup);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Property Hiding
 | |
|         /// <summary>
 | |
|         /// Gets/Sets whether Bar is visible or not.
 | |
|         /// </summary>
 | |
|         [DevCoBrowsable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 | |
|         public new bool Visible
 | |
|         {
 | |
|             get { return base.Visible; }
 | |
|             set { base.Visible = value; }
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Extender Implementation
 | |
|         // *********************************************************************
 | |
|         //
 | |
|         // Extended Property ContextMenuEx implementation code
 | |
|         //
 | |
|         // *********************************************************************
 | |
|         bool IExtenderProvider.CanExtend(object target)
 | |
|         {
 | |
|             if (target is Control)
 | |
|                 return true;
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         private delegate void WmContextEventHandler(object sender, WmContextEventArgs e);
 | |
|         /// <summary>
 | |
|         /// Returns the instance of the BaseItem that is assigned as context menu to the control.
 | |
|         /// </summary>
 | |
|         /// <param name="control">Control to return context menu for.</param>
 | |
|         /// <returns>Instance of the BaseItem used as context menu for the control.</returns>
 | |
|         [DefaultValue(null), Editor(typeof(ContextExMenuTypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
 | |
|         public BaseItem GetContextMenuEx(Control control)
 | |
|         {
 | |
|             if (control is DevComponents.DotNetBar.Controls.RichTextBoxEx)
 | |
|                 control = ((DevComponents.DotNetBar.Controls.RichTextBoxEx)control).RichTextBox;
 | |
| 
 | |
|             BaseItem item = (BaseItem)m_ContextExMenus[control];
 | |
|             return item;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Assigns the context menu to a control.
 | |
|         /// </summary>
 | |
|         /// <param name="control">Control to assign the context menu to.</param>
 | |
|         /// <param name="value">Instance of PopupItem derived class usually ButtonItem to act as context menu for a control. The SubItems collection of the item specified here actually defines the visible context menu items.</param>
 | |
|         public void SetContextMenuEx(Control control, BaseItem value)
 | |
|         {
 | |
|             if (control is DevComponents.DotNetBar.Controls.RichTextBoxEx)
 | |
|                 control = ((DevComponents.DotNetBar.Controls.RichTextBoxEx)control).RichTextBox;
 | |
|             if (value == null)
 | |
|             {
 | |
|                 if (m_ContextExMenus.Contains(control))
 | |
|                 {
 | |
|                     if (m_ContextExHandlers.Contains(control))
 | |
|                     {
 | |
|                         ContextMessageHandler h = m_ContextExHandlers[control] as ContextMessageHandler;
 | |
|                         if (h != null)
 | |
|                         {
 | |
|                             h.ContextMenu -= new WmContextEventHandler(this.OnContextMenu);
 | |
|                             h.ReleaseHandle();
 | |
|                             h = null;
 | |
|                         }
 | |
|                         m_ContextExHandlers.Remove(control);
 | |
|                     }
 | |
| 
 | |
|                     m_ContextExMenus.Remove(control);
 | |
|                     control.MouseUp -= new MouseEventHandler(this.ContextExMouseUp);
 | |
|                     try
 | |
|                     {
 | |
|                         control.HandleDestroyed -= new EventHandler(this.ContextExHandleDestroy);
 | |
|                     }
 | |
|                     catch { }
 | |
|                     try
 | |
|                     {
 | |
|                         control.HandleCreated -= new EventHandler(this.ContextExHandleCreate);
 | |
|                     }
 | |
|                     catch { }
 | |
|                     try { control.MouseUp -= new MouseEventHandler(this.ContextExMouseUp); }
 | |
|                     catch { }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (m_ContextExMenus.Contains(control))
 | |
|                 {
 | |
|                     m_ContextExMenus[control] = value;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     m_ContextExMenus[control] = value;
 | |
|                     if (!m_ContextExHandlers.Contains(control) && !this.DesignMode)
 | |
|                     {
 | |
|                         if (!(control is System.Windows.Forms.TreeView) && !(control is System.Windows.Forms.Form) && 
 | |
|                             !(control is System.Windows.Forms.Panel
 | |
| #if FRAMEWORK20
 | |
|                             || control is System.Windows.Forms.DataGridView
 | |
| #endif
 | |
|                             ) && 
 | |
|                             m_ContextMenuSubclass)
 | |
|                         {
 | |
|                             if (control.IsHandleCreated)
 | |
|                             {
 | |
|                                 ContextMessageHandler h = new ContextMessageHandler();
 | |
|                                 h.ContextMenu += new WmContextEventHandler(this.OnContextMenu);
 | |
|                                 h.ParentControl = control;
 | |
|                                 h.AssignHandle(control.Handle);
 | |
|                                 m_ContextExHandlers[control] = h;
 | |
|                             }
 | |
|                             control.HandleDestroyed += new EventHandler(this.ContextExHandleDestroy);
 | |
|                             control.HandleCreated += new EventHandler(this.ContextExHandleCreate);
 | |
|                         }
 | |
|                         if (control is ComboBox)
 | |
|                         {
 | |
|                             ComboBox cbo = control as ComboBox;
 | |
|                             cbo.ContextMenu = new ContextMenu();
 | |
|                         }
 | |
|                     }
 | |
|                     try { control.MouseUp += new MouseEventHandler(this.ContextExMouseUp); }
 | |
|                     catch { }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal bool HasContextMenu(Control ctrl)
 | |
|         {
 | |
|             return m_ContextExMenus.Contains(ctrl);
 | |
|         }
 | |
| 
 | |
|         private void ContextExHandleDestroy(object sender, EventArgs e)
 | |
|         {
 | |
|             Control control = sender as Control;
 | |
|             if (control == null)
 | |
|                 return;
 | |
|             ContextMessageHandler h = m_ContextExHandlers[control] as ContextMessageHandler;
 | |
|             if (h != null)
 | |
|             {
 | |
|                 h.ContextMenu -= new WmContextEventHandler(this.OnContextMenu);
 | |
|                 h.ReleaseHandle();
 | |
|                 h = null;
 | |
|             }
 | |
|             m_ContextExHandlers.Remove(control);
 | |
|         }
 | |
| 
 | |
|         private void ContextExHandleCreate(object sender, EventArgs e)
 | |
|         {
 | |
|             Control control = sender as Control;
 | |
|             if (control == null)
 | |
|                 return;
 | |
|             if (m_ContextExHandlers.Contains(control))
 | |
|                 return;
 | |
| 
 | |
|             ContextMessageHandler h = new ContextMessageHandler();
 | |
|             h.ContextMenu += new WmContextEventHandler(this.OnContextMenu);
 | |
|             h.ParentControl = control;
 | |
|             h.AssignHandle(control.Handle);
 | |
|             m_ContextExHandlers[control] = h;
 | |
|         }
 | |
| 
 | |
|         private void ContextExMouseUp(object sender, MouseEventArgs e)
 | |
|         {
 | |
|             if (e.Button != MouseButtons.Right)
 | |
|                 return;
 | |
|             Control ctrl = sender as Control;
 | |
|             if (ctrl == null)
 | |
|                 return;
 | |
|             // Find it in pop-ups
 | |
|             PopupItem popup = GetContextExItem(ctrl) as PopupItem;
 | |
|             if (popup == null) return;
 | |
| 
 | |
|             if (!popup.Expanded)
 | |
|             {
 | |
|                 popup.Style = this.Style;
 | |
|                 popup.SetSourceControl(ctrl);
 | |
|                 popup.Popup(ctrl.PointToScreen(new Point(e.X, e.Y)));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private Control FindControl(Control parent, IntPtr handle)
 | |
|         {
 | |
|             foreach (Control ctrl in parent.Controls)
 | |
|             {
 | |
|                 if (ctrl.Handle == handle)
 | |
|                     return ctrl;
 | |
|                 if (ctrl.Controls.Count > 0)
 | |
|                 {
 | |
|                     Control ret = FindControl(ctrl, handle);
 | |
|                     if (ret != null)
 | |
|                         return ret;
 | |
|                 }
 | |
|             }
 | |
|             return parent;
 | |
|         }
 | |
| 
 | |
|         private BaseItem GetContextExItem(Control ctrl)
 | |
|         {
 | |
|             BaseItem item = (BaseItem)m_ContextExMenus[ctrl];
 | |
|             return item;
 | |
|         }
 | |
|         private void OnContextMenu(object sender, WmContextEventArgs e)
 | |
|         {
 | |
|             ContextMessageHandler h = sender as ContextMessageHandler;
 | |
|             if (h == null)
 | |
|                 return;
 | |
| 
 | |
|             BaseItem contextItem = GetContextExItem(h.ParentControl);
 | |
|             if (contextItem == null)
 | |
|                 return;
 | |
| 
 | |
|             // Check whether context menu originated elsewhere in particular a Panel which handles MouseUp
 | |
|             if (e.Handle != e.SourceHandle && e.SourceHandle != IntPtr.Zero)
 | |
|             {
 | |
|                 Control ctrl = Control.FromChildHandle(e.Handle);
 | |
|                 if (ctrl != null && ctrl is Panel && this.GetContextExItem(ctrl) != null) return; // WM_CONTEXT bubbles up and Panel handles MouseUp
 | |
|             }
 | |
| 
 | |
|             // Find it in pop-ups
 | |
|             PopupItem popup = contextItem as PopupItem;
 | |
|             popup.Style = this.Style;
 | |
| 
 | |
|             if (e.Button == MouseButtons.None)
 | |
|             {
 | |
|                 // Get the control with focus
 | |
|                 Control ctrl = Control.FromChildHandle(e.Handle);
 | |
|                 if (ctrl != null && ctrl.Handle != e.Handle)
 | |
|                 {
 | |
|                     ctrl = FindControl(ctrl, e.Handle);
 | |
|                 }
 | |
|                 popup.SetSourceControl(h.ParentControl);
 | |
|                 if (ctrl != null)
 | |
|                 {
 | |
|                     if (ctrl.ClientRectangle.Contains(ctrl.PointToClient(Control.MousePosition)))
 | |
|                         popup.Popup(Control.MousePosition);
 | |
|                     else
 | |
|                         popup.Popup(ctrl.PointToScreen(Point.Empty));
 | |
|                 }
 | |
|                 else
 | |
|                     popup.Popup(Control.MousePosition);
 | |
| 
 | |
|                 // We need to eat the message in OnSysKeyUp for Shift+F10 case
 | |
|                 if (this.IgnoreSysKeyUp)
 | |
|                 {
 | |
|                     this.IgnoreSysKeyUp = false;
 | |
|                     this.EatSysKeyUp = true;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // This is handled by the WM_RBUTTONUP just eat it
 | |
|                 if (!e.WmContext)
 | |
|                 {
 | |
|                     popup.SetSourceControl(h.ParentControl);
 | |
|                     popup.Popup(e.X, e.Y);
 | |
|                 }
 | |
|             }
 | |
|             e.Handled = true;
 | |
|         }
 | |
|         private class ContextMessageHandler : NativeWindow
 | |
|         {
 | |
|             public event WmContextEventHandler ContextMenu;
 | |
|             private const int WM_CONTEXTMENU = 0x007B;
 | |
|             private const int WM_RBUTTONUP = 0x0205;
 | |
|             private const int WM_NCRBUTTONUP = 0x00A5;
 | |
|             private const int WM_RBUTTONDOWN = 0x0204;
 | |
|             public Control ParentControl = null;
 | |
|             protected override void WndProc(ref Message m)
 | |
|             {
 | |
|                 if (m.Msg == WM_CONTEXTMENU)
 | |
|                 {
 | |
|                     if (ContextMenu != null)
 | |
|                     {
 | |
|                         int ilParam = WinApi.ToInt(m.LParam);
 | |
|                         int y = ilParam >> 16;
 | |
|                         int x = (short)(ilParam & 0xFFFF);
 | |
|                         IntPtr hWnd = m.WParam;
 | |
|                         if (hWnd == IntPtr.Zero)
 | |
|                             hWnd = m.HWnd;
 | |
|                         bool context = true;
 | |
|                         if (m.HWnd != m.WParam)
 | |
|                             context = false;
 | |
|                         WmContextEventArgs e = new WmContextEventArgs(hWnd, x, y, ((x == -1 && y == -1) ? MouseButtons.None : MouseButtons.Right), context, m.HWnd);
 | |
|                         ContextMenu(this, e);
 | |
|                         if (e.Handled)
 | |
|                             return;
 | |
|                     }
 | |
|                 }
 | |
|                 // This case was taken out becouse the message was not generated for the listview control and possibly for
 | |
|                 // treview control so this code was moved to the MouseUp event of the Control see ContextExMouseUp
 | |
|                 //				else if(m.Msg==WM_RBUTTONUP || m.Msg==WM_NCRBUTTONUP)
 | |
|                 //				{
 | |
|                 //					if(ContextMenu!=null)
 | |
|                 //					{
 | |
|                 //						int ilParam=m.LParam.ToInt32();
 | |
|                 //						int y=ilParam>>16;
 | |
|                 //						int x=ilParam & 0xFFFF;
 | |
|                 //						Point p=ParentControl.PointToScreen(new Point(x,y));
 | |
|                 //						WmContextEventArgs e=new WmContextEventArgs(m.HWnd,p.X,p.Y,MouseButtons.Right,false);
 | |
|                 //						ContextMenu(this,e);
 | |
|                 //					}
 | |
|                 //				}
 | |
|                 base.WndProc(ref m);
 | |
|             }
 | |
|         }
 | |
|         private class WmContextEventArgs : EventArgs
 | |
|         {
 | |
|             private readonly int x;
 | |
|             private readonly int y;
 | |
|             private readonly MouseButtons button = 0;
 | |
|             private readonly IntPtr hwnd;
 | |
|             private readonly bool wmcontext;
 | |
|             public bool Handled = false;
 | |
|             private IntPtr sourceHandle;
 | |
|             public WmContextEventArgs(IntPtr phwnd, int ix, int iy, MouseButtons eButton, bool WmContextMessage, IntPtr sourceHandle)
 | |
|             {
 | |
|                 this.x = ix;
 | |
|                 this.y = iy;
 | |
|                 this.button = eButton;
 | |
|                 this.hwnd = phwnd;
 | |
|                 this.wmcontext = WmContextMessage;
 | |
|                 this.sourceHandle = sourceHandle;
 | |
|             }
 | |
|             public int X
 | |
|             {
 | |
|                 get { return this.x; }
 | |
|             }
 | |
|             public int Y
 | |
|             {
 | |
|                 get { return this.y; }
 | |
|             }
 | |
|             public MouseButtons Button
 | |
|             {
 | |
|                 get { return this.button; }
 | |
|             }
 | |
|             public IntPtr Handle
 | |
|             {
 | |
|                 get { return this.hwnd; }
 | |
|             }
 | |
|             public bool WmContext
 | |
|             {
 | |
|                 get { return this.wmcontext; }
 | |
|             }
 | |
|             public IntPtr SourceHandle
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     return this.sourceHandle;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         #endregion
 | |
|     }
 | |
| }
 |