📄 popupmenu.cs
字号:
{
// Is the mouse event for this popup window?
if (msg.hwnd != this.Handle)
{
// Let the parent chain of PopupMenu's decide if they want it
if (!ParentWantsMouseMessage(ref msg)&& !child && !combolist)
{
// No, then we need to exit the popup menu tracking
_exitLoop = true;
// DO NOT process the message, leave it on the queue
// and let the real destination window handle it.
leaveMsg = true;
// Is a parent control specified?
if (_parentControl != null)
{
// Is the mouse event destination the parent control?
if (msg.hwnd == _parentControl.Handle)
{
// Then we want to consume the message so it does not get processed
// by the parent control. Otherwise, pressing down will cause this
// popup to disappear but the message will then get processed by
// the parent and cause a popup to reappear again. When we actually
// want the popup to disappear and nothing more.
leaveMsg = false;
}
}
}
}
}
else
{
// Mouse move occured
if (msg.message == (int)Msg.WM_MOUSEMOVE)
{
// Is the mouse event for this popup window?
if (msg.hwnd != this.Handle)
{
// Do we still think the mouse is over our window?
if (_mouseOver)
{
// Process mouse leaving situation
OnWM_MOUSELEAVE();
}
// Let the parent chain of PopupMenu's decide if they want it
if (!ParentWantsMouseMessage(ref msg) && !child && !combolist)
{
// Eat the message to prevent the destination getting it
Win32.MSG eat = new Win32.MSG();
WindowsAPI.GetMessage(ref eat, 0, 0, 0);
// Do not attempt to pull a message off the queue as it has already
// been eaten by us in the above code
leaveMsg = true;
}
}
}
else
{
// Was the alt key pressed?
if (msg.message == (int)Msg.WM_SYSKEYDOWN)
{
// Alt key pressed on its own
if((int)msg.wParam == (int)Win32.VirtualKeys.VK_MENU) // ALT key
{
// Then we should dimiss ourself
_exitLoop = true;
}
}
// Was a key pressed?
if (msg.message == (int)Msg.WM_KEYDOWN)
{
switch((int)msg.wParam)
{
case (int)Win32.VirtualKeys.VK_UP:
ProcessKeyUp();
break;
case (int)Win32.VirtualKeys.VK_DOWN:
ProcessKeyDown();
break;
case (int)Win32.VirtualKeys.VK_LEFT:
ProcessKeyLeft();
break;
case (int)Win32.VirtualKeys.VK_RIGHT:
if(ProcessKeyRight())
{
// Do not attempt to pull a message off the queue as the
// ProcessKeyRight has eaten the message for us
leaveMsg = true;
}
break;
case (int)Win32.VirtualKeys.VK_RETURN:
// Is an item currently selected
if (_trackItem != -1)
{
DrawCommand dc = _drawCommands[_trackItem] as DrawCommand;
// Does this item have a submenu?
if (dc.SubMenu)
{
// Consume the keyboard message to prevent the submenu immediately
// processing the same message again. Remember this routine is called
// after PeekMessage but the message is still on the queue at this point
Win32.MSG eat = new Win32.MSG();
WindowsAPI.GetMessage(ref eat, 0, 0, 0);
// Handle the submenu
OperateSubMenu(_trackItem, false);
// Do not attempt to pull a message off the queue as it has already
// been eaten by us in the above code
leaveMsg = true;
}
else
{
// Is this item the expansion command?
if (dc.Expansion)
{
RegenerateExpansion();
}
else
{
// Define the selection to return to caller
_returnCommand = dc.MenuCommand;
// Finish processing messages
_exitLoop = true;
}
}
}
break;
case (int)Win32.VirtualKeys.VK_ESCAPE:
// User wants to exit the menu, so set the flag to exit the message loop but
// let the message get processed. This way the key press is thrown away.
_exitLoop = true;
break;
default:
// Any other key is treated as a possible mnemonic
int selectItem = ProcessMnemonicKey((char)msg.wParam);
if (selectItem != -1)
{
DrawCommand dc = _drawCommands[selectItem] as DrawCommand;
// Define the selection to return to caller
_returnCommand = dc.MenuCommand;
// Finish processing messages
_exitLoop = true;
}
break;
}
}
}
}
// Should the message we pulled from the queue?
if (!leaveMsg)
{
if (WindowsAPI.GetMessage(ref msg, 0, 0, 0))
{
WindowsAPI.TranslateMessage(ref msg);
WindowsAPI.DispatchMessage(ref msg);
}
}
else
leaveMsg = false;
}
}
}
// Do we have a focus we need to restore?
if (_oldFocus != IntPtr.Zero)
ReturnTheFocus();
// Need to unset this window as the parent of the comboboxes
// -- if any -- otherwise the combobox use in an toolbar would get "sick"
UnsetComboBoxesParent();
// Hide the window from view before killing it, as sometimes there is a
// short delay between killing it and it disappearing because of the time
// it takes for the destroy messages to get processed
WindowsAPI.ShowWindow(this.Handle, (short)Win32.ShowWindowStyles.SW_HIDE);
// Commit suicide
DestroyHandle();
// Was a command actually selected?
if ((_parentMenu == null) && (_returnCommand != null))
{
// Pulse the selected event for the command
_returnCommand.OnClick(EventArgs.Empty);
}
return _returnCommand;
}
public void Dismiss()
{
if (this.Handle != IntPtr.Zero)
{
// Prevent the timer from expiring
_timer.Stop();
// Kill any child menu
if (_childMenu != null)
_childMenu.Dismiss();
// Finish processing messages
_exitLoop = true;
// Hide ourself
WindowsAPI.ShowWindow(this.Handle, (short)Win32.ShowWindowStyles.SW_HIDE);
// Cause our own message loop to exit
WindowsAPI.PostMessage(this.Handle, WM_DISMISS, 0, 0);
}
}
protected void CreateAndShowWindow()
{
// Decide if we need layered windows
_layered = (_supportsLayered && (_style == VisualStyle.IDE));
// Don't use layered windows because we would need to do more work
// to paint the comboboxes
_layered = false;
// Process the menu commands to determine where each one needs to be
// drawn and return the size of the window needed to display it.
Size winSize = GenerateDrawPositions();
Point screenPos = CorrectPositionForScreen(winSize);
CreateParams cp = new CreateParams();
// Any old title will do as it will not be shown
cp.Caption = "NativePopupMenu";
// Define the screen position/size
cp.X = screenPos.X;
cp.Y = screenPos.Y;
cp.Height = winSize.Height;
cp.Width = winSize.Width;
// As a top-level window it has no parent
cp.Parent = IntPtr.Zero;
// Appear as a top-level window
cp.Style = unchecked((int)(uint)Win32.WindowStyles.WS_POPUP |
(int)(uint)Win32.WindowStyles.WS_CLIPCHILDREN);
// Set styles so that it does not have a caption bar and is above all other
// windows in the ZOrder, i.e. TOPMOST
cp.ExStyle = (int)Win32.WindowExStyles.WS_EX_TOPMOST + (int)Win32.WindowExStyles.WS_EX_TOOLWINDOW;
// OS specific style
if (_layered)
{
// If not on NT then we are going to use alpha blending on the shadow border
// and so we need to specify the layered window style so the OS can handle it
cp.ExStyle += (int)Win32.WindowExStyles.WS_EX_LAYERED;
}
// Is this the plain style of appearance?
if (_style == VisualStyle.Plain)
{
// We want the tradiditonal 3D border
cp.Style += unchecked((int)(uint)Win32.WindowStyles.WS_DLGFRAME);
}
// Create the actual window
this.CreateHandle(cp);
// Update the window clipping region
if (!_layered)
SetWindowRegion(winSize);
// Make sure comboboxes are the children of this window
SetComboBoxesParent();
// Show the window without activating it (i.e. do not take focus)
WindowsAPI.ShowWindow(this.Handle, (short)Win32.ShowWindowStyles.SW_SHOWNOACTIVATE);
if (_layered)
{
// Remember the correct screen drawing details
_currentPoint = screenPos;
_currentSize = winSize;
// Update the image for display
UpdateLayeredWindow();
// Must grab the focus immediately
if (_grabFocus)
GrabTheFocus();
}
}
void SetComboBoxesParent()
{
foreach(MenuCommand command in _menuCommands)
{
// no need for recursion, comboboxes are only
// on the first level
if ( command.ComboBox != null)
{
WindowsAPI.SetParent(command.ComboBox.Handle, Handle);
}
}
}
void UnsetComboBoxesParent()
{
foreach(MenuCommand command in _menuCommands)
{
// no need for recursion, comboboxes are only
// on the first level
if ( command.ComboBox != null)
{
command.ComboBox.Visible = false;
WindowsAPI.SetParent(command.ComboBox.Handle, IntPtr.Zero);
}
}
}
bool IsComboBoxList(IntPtr hWnd)
{
STRINGBUFFER className;
WindowsAPI.GetClassName(hWnd, out className, 80);
if ( className.szText == "ComboLBox" )
return true;
return false;
}
protected void UpdateLayeredWindow()
{
UpdateLayeredWindow(_currentPoint, _currentSize);
}
protected void UpdateLayeredWindow(Point point, Size size)
{
// Create bitmap for drawing onto
Bitmap memoryBitmap = new Bitmap(size.Width, size.Height, PixelFormat.Format32bppArgb);
using(Graphics g = Graphics.FromImage(memoryBitmap))
{
Rectangle area = new Rectangle(0, 0, size.Width, size.Height);
// Draw the background area
DrawBackground(g, area);
// Draw the actual menu items
DrawAllCommands(g);
// Get hold of the screen DC
IntPtr hDC = WindowsAPI.GetDC(IntPtr.Zero); // Create a memory based DC compatible with the screen DC IntPtr memoryDC = WindowsAPI.CreateCompatibleDC(hDC); // Get access to the bitmap handle contained in the Bitmap object IntPtr hBitmap = memoryBitmap.GetHbitmap(Color.FromArgb(0)); // Select this bitmap for updating the window presentation IntPtr oldBitmap = WindowsAPI.SelectObject(memoryDC, hBitmap); // New window size Win32.SIZE ulwsize; ulwsize.cx = size.Width; ulwsize.cy = size.Height; // New window position Win32.POINT topPos; topPos.x = point.X; topPos.y = point.Y; // Offset into memory bitmap is always zero Win32.POINT pointSource; pointSource.x = 0; pointSource.y = 0; // We want to make the entire bitmap opaque Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION(); blend.BlendOp = (byte)Win32.AlphaFlags.AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = 255; blend.AlphaFormat = (byte)Win32.AlphaFlags.AC_SRC_ALPHA; // Tell operating system to use our bitmap for painting WindowsAPI.UpdateLayeredWindow(Handle, hDC, ref topPos, ref ulwsize, memoryDC, ref pointSource, 0, ref blend, (int)Win32.UpdateLayeredWindowsFlags.ULW_ALPHA);
// Put back the old bitmap handle
WindowsAPI.SelectObject(memoryDC, oldBitmap); // Cleanup resources WindowsAPI.ReleaseDC(IntPtr.Zero, hDC); WindowsAPI.DeleteObject(hBitmap); WindowsAPI.DeleteDC(memoryDC); } }
protected void SetWindowRegion(Size winSize)
{
// Style specific handling
if (_style == VisualStyle.IDE)
{
int shadowHeight = _position[(int)_style, (int)PI.ShadowHeight];
int shadowWidth = _position[(int)_style, (int)PI.ShadowWidth];
// Create a new region object
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -