?? popupmenu.cs
字號:
using System;
using System.IO;
using System.Drawing;
using System.Reflection;
using System.Drawing.Text;
using System.Collections;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using UtilityLibrary.Menus;
using UtilityLibrary.Win32;
using UtilityLibrary.Collections;
using UtilityLibrary.General;
namespace UtilityLibrary.Menus
{
internal class FocusCatcher : NativeWindow
{
public FocusCatcher(IntPtr hParent)
{
CreateParams cp = new CreateParams();
// Any old title will do as it will not be shown
cp.Caption = "NativeFocusCatcher";
// Set the position off the screen so it will not be seen
cp.X = -1;
cp.Y = -1;
cp.Height = 0;
cp.Width = 0;
// As a top-level window it has no parent
cp.Parent = hParent;
// Create as a child of the specified parent
cp.Style = unchecked((int)(uint)Win32.WindowStyles.WS_CHILD +
(int)(uint)Win32.WindowStyles.WS_VISIBLE);
// Create the actual window
this.CreateHandle(cp);
}
}
[ToolboxItem(false)]
[DefaultProperty("MenuCommands")]
public class PopupMenu : NativeWindow
{
// Enumeration of Indexes into positioning constants array
protected enum PI
{
BorderTop = 0,
BorderLeft = 1,
BorderBottom = 2,
BorderRight = 3,
ImageGapTop = 4,
ImageGapLeft = 5,
ImageGapBottom = 6,
ImageGapRight = 7,
TextGapLeft = 8,
TextGapRight = 9,
SubMenuGapLeft = 10,
SubMenuWidth = 11,
SubMenuGapRight = 12,
SeparatorHeight = 13,
SeparatorWidth = 14,
ShortcutGap = 15,
ShadowWidth = 16,
ShadowHeight = 17,
ExtraWidthGap = 18,
ExtraHeightGap = 19,
ExtraRightGap = 20,
ExtraReduce = 21
}
// Class constants for sizing/positioning each style
protected static readonly int[,] _position = {
{2, 1, 0, 1, 4, 3, 4, 5, 4, 4, 2, 6, 5, 3, 1, 10, 3, 3, 2, 2, 0, 0}, // IDE
{1, 0, 1, 2, 2, 1, 3, 4, 3, 3, 2, 8, 5, 4, 5, 10, 0, 0, 2, 2, 2, 5} // Plain
};
// Other class constants
protected static readonly int _selectionDelay = 400;
// Class fields
protected static ImageList _menuImages = null;
protected static bool _supportsLayered = false;
// Indexes into the menu images strip
protected enum ImageIndex
{
Check = 0,
Radio = 1,
SubMenu = 2,
CheckSelected = 3,
RadioSelected = 4,
SubMenuSelected = 5,
Expansion = 6,
ImageError = 7
}
// Class constants that are marked as 'readonly' are allowed computed initialization
protected readonly int WM_DISMISS = (int)Msg.WM_USER + 1;
protected readonly int _imageWidth = SystemInformation.SmallIconSize.Width;
protected readonly int _imageHeight = SystemInformation.SmallIconSize.Height;
// Instance fields
protected Timer _timer;
protected bool _layered;
protected Font _textFont;
protected int _popupItem;
protected int _trackItem;
protected int _borderGap;
protected int _returnDir;
protected int _extraSize;
protected bool _exitLoop;
protected bool _mouseOver;
protected bool _grabFocus;
protected bool _popupDown;
protected bool _popupRight;
protected bool _excludeTop;
protected Point _screenPos;
protected IntPtr _oldFocus;
protected VisualStyle _style;
protected Size _currentSize;
protected int _excludeOffset;
protected Point _lastMousePos;
protected Point _currentPoint;
protected bool _showInfrequent;
protected PopupMenu _childMenu;
protected Point _leftScreenPos;
protected Direction _direction;
protected Point _aboveScreenPos;
protected PopupMenu _parentMenu;
protected ArrayList _drawCommands;
internal FocusCatcher _focusCatcher;
protected MenuControl _parentControl;
protected MenuCommand _returnCommand;
protected MenuCommandCollection _menuCommands;
static PopupMenu()
{
// Create a strip of images by loading an embedded bitmap resource
_menuImages = ResourceUtil.LoadImageListResource(Type.GetType("UtilityLibrary.Menus.PopupMenu"),
"Resources.ImagesMenu",
"MenuControlImages",
new Size(16,16),
true,
new Point(0,0));
// We need to know if the OS supports layered windows
_supportsLayered = (OSFeature.Feature.GetVersionPresent(OSFeature.LayeredWindows) != null);
}
public PopupMenu()
{
// Create collection objects
_drawCommands = new ArrayList();
_menuCommands = new MenuCommandCollection();
// Default the properties
_returnDir = 0;
_extraSize = 0;
_popupItem = -1;
_trackItem = -1;
_childMenu = null;
_exitLoop = false;
_popupDown = true;
_mouseOver = false;
_grabFocus = false;
_excludeTop = true;
_popupRight = true;
_parentMenu = null;
_excludeOffset = 0;
_focusCatcher = null;
_parentControl = null;
_returnCommand = null;
_oldFocus = IntPtr.Zero;
_showInfrequent = false;
_style = VisualStyle.IDE;
_lastMousePos = new Point(-1,-1);
_direction = Direction.Horizontal;
_textFont = SystemInformation.MenuFont;
// Create and initialise the timer object (but do not start it running!)
_timer = new Timer();
_timer.Interval = _selectionDelay;
_timer.Tick += new EventHandler(OnTimerExpire);
}
[Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public MenuCommandCollection MenuCommands
{
get { return _menuCommands; }
set
{
_menuCommands.Clear();
_menuCommands = value;
}
}
[Category("Appearance")]
[DefaultValue(VisualStyle.IDE)]
public VisualStyle Style
{
get { return _style; }
set
{
if (_style != value)
_style = value;
}
}
[Category("Appearance")]
public Font Font
{
get { return _textFont; }
set
{
if (_textFont != value)
_textFont = value;
}
}
[Category("Behaviour")]
[DefaultValue(false)]
public bool ShowInfrequent
{
get { return _showInfrequent; }
set
{
if (_showInfrequent != value)
_showInfrequent = value;
}
}
public MenuCommand TrackPopup(Point screenPos)
{
return TrackPopup(screenPos, false);
}
public MenuCommand TrackPopup(Point screenPos, bool selectFirst)
{
// No point in showing PopupMenu if there are no entries
if (_menuCommands.VisibleItems())
{
// We are being called as a popup window and not from a MenuControl instance
// and so we need to the focus during the lifetime of the popup and then return
// focus back again when we are dismissed. Otherwise keyboard input will still go
// to the control that has it when the popup is created.
_grabFocus = true;
// Default the drawing direction
_direction = Direction.Horizontal;
// Remember screen positions
_screenPos = screenPos;
_aboveScreenPos = screenPos;
_leftScreenPos = screenPos;
return InternalTrackPopup(selectFirst);
}
else
return null;
}
internal MenuCommand TrackPopup(Point screenPos, Point aboveScreenPos,
Direction direction,
MenuCommandCollection menuCollection,
int borderGap,
bool selectFirst,
MenuControl parentControl,
ref int returnDir)
{
// Remember which direction the MenuControl is drawing in
_direction = direction;
// Remember the MenuControl that initiated us
_parentControl = parentControl;
// Remember the gap in drawing the top border
_borderGap = borderGap;
// Remember any currect menu item collection
MenuCommandCollection oldCollection = _menuCommands;
// Use the passed in collection of menu commands
_menuCommands = menuCollection;
// Remember screen positions
_screenPos = screenPos;
_aboveScreenPos = aboveScreenPos;
_leftScreenPos = screenPos;
MenuCommand ret = InternalTrackPopup(selectFirst);
// Restore to original collection
_menuCommands = oldCollection;
// Remove reference no longer required
_parentControl = null;
// Return the direction key that caused dismissal
returnDir = _returnDir;
return ret;
}
protected MenuCommand InternalTrackPopup(Point screenPosTR, Point screenPosTL,
MenuCommandCollection menuCollection,
PopupMenu parentMenu, bool selectFirst,
MenuControl parentControl, bool popupRight,
bool popupDown, ref int returnDir)
{
// Default the drawing direction
_direction = Direction.Horizontal;
// Remember the MenuControl that initiated us
_parentControl = parentControl;
// We have a parent popup menu that should be consulted about operation
_parentMenu = parentMenu;
// Remember any currect menu item collection
MenuCommandCollection oldCollection = _menuCommands;
// Use the passed in collection of menu commands
_menuCommands = menuCollection;
// Remember screen positions
_screenPos = screenPosTR;
_aboveScreenPos = screenPosTR;
_leftScreenPos = screenPosTL;
// Remember display directions
_popupRight = popupRight;
_popupDown = popupDown;
MenuCommand ret = InternalTrackPopup(selectFirst);
// Restore to original collection
_menuCommands = oldCollection;
// Remove references no longer required
_parentControl = null;
_parentMenu = null;
// Return the direction key that caused dismissal
returnDir = _returnDir;
return ret;
}
protected MenuCommand InternalTrackPopup(bool selectFirst)
{
// MenuCommand to return as method result
_returnCommand = null;
// No item is being tracked
_trackItem = -1;
// Flag to indicate when to exit the message loop
_exitLoop = false;
// Assume the mouse does not start over our window
_mouseOver = false;
// Direction of key press if this caused dismissal
_returnDir = 0;
// Flag to indicate if the message should be dispatched
bool leaveMsg = false;
// Create and show the popup window (without taking the focus)
CreateAndShowWindow();
// Create an object for storing windows message information
Win32.MSG msg = new Win32.MSG();
// Draw everything now...
//RefreshAllCommands();
// Pretend user pressed key down to get the first valid item selected
if (selectFirst)
ProcessKeyDown();
// Process messages until exit condition recognised
while(!_exitLoop)
{
// Suspend thread until a windows message has arrived
if (WindowsAPI.WaitMessage())
{
// Take a peek at the message details without removing from queue
while(!_exitLoop && WindowsAPI.PeekMessage(ref msg, 0, 0, 0, (int)Win32.PeekMessageFlags.PM_NOREMOVE))
{
//Console.WriteLine("Track {0} {1}", this.Handle, ((Msg)msg.message).ToString());
//Console.WriteLine("Message is for {0 }", msg.hwnd);
// Leave messages for children
IntPtr hParent = WindowsAPI.GetParent(msg.hwnd);
bool child = hParent == Handle;
bool combolist = IsComboBoxList(msg.hwnd);
// Mouse was pressed in a window of this application
if ((msg.message == (int)Msg.WM_LBUTTONDOWN) ||
(msg.message == (int)Msg.WM_MBUTTONDOWN) ||
(msg.message == (int)Msg.WM_RBUTTONDOWN) ||
(msg.message == (int)Msg.WM_NCLBUTTONDOWN) ||
(msg.message == (int)Msg.WM_NCMBUTTONDOWN) ||
(msg.message == (int)Msg.WM_NCRBUTTONDOWN))
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -