?? menucontrol.cs
字號:
using System;
using System.IO;
using System.Drawing;
using System.Reflection;
using System.Collections;
using System.Drawing.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Imaging;
using UtilityLibrary.Win32;
using UtilityLibrary.Menus;
using UtilityLibrary.General;
using UtilityLibrary.Collections;
namespace UtilityLibrary.Menus
{
[ToolboxBitmap(typeof(MenuControl))]
[DefaultProperty("MenuCommands")]
[DefaultEvent("PopupStart")]
[Designer(typeof(UtilityLibrary.Menus.MenuControlDesigner))]
public class MenuControl : ContainerControl, IMessageFilter
{
// Class constants
protected const int _breadthGap = 5;
protected const int _lengthGap = 3;
protected const int _boxExpandUpper = 1;
protected const int _boxExpandSides = 2;
protected const int _shadowGap = 3;
protected const int _shadowYOffset = 3;
protected const int _separatorWidth = 15;
protected const int _subMenuBorderAdjust = 2;
protected const int _chevronIndex = 0;
protected const int _chevronLength = 10;
protected const int _chevronBreadth = 10;
// Class constant is marked as 'readonly' to allow non constant initialization
protected readonly int WM_OPERATEMENU = (int)Win32.Msg.WM_USER + 1;
// Class fields
protected static ImageList _menuImages = null;
protected static bool _supportsLayered = false;
// Declare the popup change event signature
public delegate void PopupHandler(MenuCommand item);
// Instance fields
protected int _rowWidth;
protected int _rowHeight;
protected bool _selected;
protected int _trackItem;
protected bool _multiLine;
protected bool _mouseOver;
protected IntPtr _oldFocus;
protected bool _manualFocus;
protected bool _drawUpwards;
protected VisualStyle _style;
protected bool _plainAsBlock;
protected Direction _direction;
protected bool _ignoreEscapeUp;
protected PopupMenu _popupMenu;
protected bool _dismissTransfer;
protected bool _ignoreMouseMove;
protected ArrayList _drawCommands;
protected MenuCommand _chevronStartCommand;
protected MenuCommandCollection _menuCommands;
// Instance fields - events
public event PopupHandler PopupStart;
public event PopupHandler PopupEnd;
static MenuControl()
{
// Create a strip of images by loading an embedded bitmap resource
_menuImages = ResourceUtil.LoadImageListResource(Type.GetType("UtilityLibrary.Menus.MenuControl"),
"Resources.ImagesMenu",
"MenuControlImages",
new Size(_chevronLength, _chevronBreadth),
true,
new Point(0,0));
// We need to know if the OS supports layered windows
_supportsLayered = (OSFeature.Feature.GetVersionPresent(OSFeature.LayeredWindows) != null);
}
public MenuControl()
{
// Set default values
this.Dock = DockStyle.Top;
_trackItem = -1;
_selected = false;
_multiLine = false;
_popupMenu = null;
_mouseOver = false;
_manualFocus = false;
_drawUpwards = false;
_plainAsBlock = false;
_oldFocus = IntPtr.Zero;
_ignoreEscapeUp = false;
_ignoreMouseMove = false;
_dismissTransfer = false;
_style = VisualStyle.IDE;
_chevronStartCommand = null;
_direction = Direction.Horizontal;
_menuCommands = new MenuCommandCollection();
// Prevent flicker with double buffering and all painting inside WM_PAINT
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
// Should not be allowed to select this control
SetStyle(ControlStyles.Selectable, false);
// Hookup to collection events
_menuCommands.Cleared += new CollectionWithEvents.CollectionClear(OnCollectionCleared);
_menuCommands.Inserted += new CollectionWithEvents.CollectionChange(OnCollectionInserted);
_menuCommands.Removed += new CollectionWithEvents.CollectionChange(OnCollectionRemoved);
// Set the default menu color as background
this.BackColor = SystemColors.Control;
// Do not allow tab key to select this control
this.TabStop = false;
// Default the Font we use
this.Font = SystemInformation.MenuFont;
// Calculate the initial height/width of the control
_rowWidth = _rowHeight = this.Font.Height + _breadthGap * 2 + 1;
// Default to one line of items
this.Height = _rowHeight;
// Add ourself to the application filtering list
Application.AddMessageFilter(this);
}
[Category("Behaviour")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public MenuCommandCollection MenuCommands
{
get { return _menuCommands; }
set
{
_menuCommands.Clear();
_menuCommands = value;
Recalculate();
Invalidate();
}
}
[Category("Appearance")]
public VisualStyle Style
{
get { return _style; }
set
{
if (_style != value)
{
_style = value;
Recalculate();
Invalidate();
}
}
}
[Category("Appearance")]
public override Font Font
{
get { return base.Font; }
set
{
base.Font = value;
// Resize to take into accout the new height
_rowHeight = this.Font.Height + _lengthGap * 2;
Recalculate();
Invalidate();
}
}
[Category("Appearance")]
[DefaultValue(false)]
public bool PlainAsBlock
{
get { return _plainAsBlock; }
set
{
if (_plainAsBlock != value)
{
_plainAsBlock = value;
Recalculate();
Invalidate();
}
}
}
[Category("Appearance")]
[DefaultValue(false)]
public bool MultiLine
{
get { return _multiLine; }
set
{
if (_multiLine != value)
{
_multiLine = value;
Recalculate();
Invalidate();
}
}
}
[Category("Appearance")]
public Direction Direction
{
get { return _direction; }
set
{
if (_direction != value)
{
_direction = value;
Recalculate();
Invalidate();
}
}
}
public override DockStyle Dock
{
get { return base.Dock; }
set
{
base.Dock = value;
switch(value)
{
case DockStyle.None:
_direction = Direction.Horizontal;
break;
case DockStyle.Top:
case DockStyle.Bottom:
this.Height = 0;
_direction = Direction.Horizontal;
break;
case DockStyle.Left:
case DockStyle.Right:
this.Width = 0;
_direction = Direction.Vertical;
break;
}
Recalculate();
Invalidate();
}
}
protected void OnPopupStart(MenuCommand mc)
{
if (PopupStart != null)
PopupStart(mc);
}
protected void OnPopupEnd(MenuCommand mc)
{
if (PopupEnd != null)
PopupEnd(mc);
}
protected void OnCollectionCleared()
{
// Reset state ready for a recalculation
_selected = false;
_trackItem = -1;
Recalculate();
Invalidate();
}
protected void OnCollectionInserted(int index, object value)
{
MenuCommand mc = value as MenuCommand;
// We need notification whenever the properties of this command change
mc.PropertyChanged += new MenuCommand.PropChangeHandler(OnCommandChanged);
// Reset state ready for a recalculation
_selected = false;
_trackItem = -1;
Recalculate();
Invalidate();
}
protected void OnCollectionRemoved(int index, object value)
{
// Reset state ready for a recalculation
_selected = false;
_trackItem = -1;
Recalculate();
Invalidate();
}
protected void OnCommandChanged(MenuCommand item, MenuCommand.Property prop)
{
Recalculate();
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
Point pos = new Point(e.X, e.Y);
for(int i=0; i<_drawCommands.Count; i++)
{
DrawCommand dc = _drawCommands[i] as DrawCommand;
// Find the DrawCommand this is over
if (dc.DrawRect.Contains(pos))
{
// Is an item already selected?
if (_selected)
{
// Is it this item that is already selected?
if (_trackItem == i)
{
// Is a popupMenu showing
if (_popupMenu != null)
{
// Dismiss the submenu
_popupMenu.Dismiss();
// No reference needed
_popupMenu = null;
}
}
}
else
{
// Select the tracked item
_selected = true;
_drawUpwards = false;
GrabTheFocus();
// Is there a change in tracking?
if (_trackItem != i)
{
// Modify the display of the two items
_trackItem = SwitchTrackingItem(_trackItem, i);
}
else
{
// Update display to show as selected
DrawCommand(_trackItem, true);
}
// Is there a submenu to show?
if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))
WindowsAPI.PostMessage(this.Handle, WM_OPERATEMENU, 1, 0);
}
break;
}
}
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
// Is an item currently being tracked?
if (_trackItem != -1)
{
// Is it also selected?
if (_selected == true)
{
// Is it also showing a submenu
if (_popupMenu == null)
{
// Deselect the item
_selected = false;
_drawUpwards = false;
DrawCommand(_trackItem, true);
ReturnTheFocus();
}
}
}
base.OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
// Sometimes we need to ignore this message
if (_ignoreMouseMove)
_ignoreMouseMove = false;
else
{
// Is the first time we have noticed a mouse movement over our window
if (!_mouseOver)
{
// Crea the structure needed for WindowsAPI call
Win32.TRACKMOUSEEVENTS tme = new Win32.TRACKMOUSEEVENTS();
// Fill in the structure
tme.cbSize = 16;
tme.dwFlags = (uint)Win32.TrackerEventFlags.TME_LEAVE;
tme.hWnd = this.Handle;
tme.dwHoverTime = 0;
// Request that a message gets sent when mouse leaves this window
WindowsAPI.TrackMouseEvent(ref tme);
// Yes, we know the mouse is over window
_mouseOver = true;
}
Form parentForm = this.FindForm();
// Only hot track if this Form is active
if ((parentForm != null) && parentForm.ContainsFocus)
{
Point pos = new Point(e.X, e.Y);
int i = 0;
for(i=0; i<_drawCommands.Count; i++)
{
DrawCommand dc = _drawCommands[i] as DrawCommand;
// Find the DrawCommand this is over
if (dc.DrawRect.Contains(pos))
{
// Is there a change in selected item?
if (_trackItem != i)
{
// We we currently selecting an item
if (_selected)
{
if (_popupMenu != null)
{
// Note that we are dismissing the submenu but not removing
// the selection of items, this flag is tested by the routine
// that will return because the submenu has been finished
_dismissTransfer = true;
// Dismiss the submenu
_popupMenu.Dismiss();
// Default to downward drawing
_drawUpwards = false;
}
// Modify the display of the two items
_trackItem = SwitchTrackingItem(_trackItem, i);
// Does the newly selected item have a submenu?
if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))
WindowsAPI.PostMessage(this.Handle, WM_OPERATEMENU, 1, 0);
}
else
{
// Modify the display of the two items
_trackItem = SwitchTrackingItem(_trackItem, i);
}
}
break;
}
}
// If not in selected mode
if (!_selected)
{
// None of the commands match?
if (i == _drawCommands.Count)
{
// Modify the display of the two items
_trackItem = SwitchTrackingItem(_trackItem, -1);
}
}
}
}
base.OnMouseMove(e);
}
protected override void OnMouseLeave(EventArgs e)
{
_mouseOver = false;
// If we manually grabbed focus then do not switch
// selection when the mouse leaves the control area
if (!_manualFocus)
{
if (_trackItem != -1)
{
// If an item is selected then do not change tracking item when the
// mouse leaves the control area, as a popup menu might be showing and
// so keep the tracking and selection indication visible
if (_selected == false)
_trackItem = SwitchTrackingItem(_trackItem, -1);
}
}
base.OnMouseLeave(e);
}
protected override void OnResize(EventArgs e)
{
Recalculate();
// Any resize of control should redraw all of it otherwise when you
// stretch to the right it will not paint correctly as we have a one
// pixel gao between text and min button which is not honoured otherwise
this.Invalidate();
base.OnResize(e);
}
internal void DrawSelectionUpwards()
{
// Double check the state is correct for this method to be called
if ((_trackItem != -1) && (_selected))
{
// This flag is tested in the DrawCommand method
_drawUpwards = true;
// Force immediate redraw of the item
DrawCommand(_trackItem, true);
}
}
protected void Recalculate()
{
int length;
if (_direction == Direction.Horizontal)
length = this.Width;
else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -