?? toolbarex.cs
字號:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Text;
using System.Diagnostics;
using System.Security;
using UtilityLibrary.Collections;
using UtilityLibrary.Win32;
using UtilityLibrary.General;
using UtilityLibrary.WinControls;
using UtilityLibrary.Menus;
namespace UtilityLibrary.CommandBars
{
public enum BarType
{
ToolBar = 0,
MenuBar = 1
}
/// <summary>
/// Summary description for ToolBarEx.
/// </summary>
public class ToolBarEx : System.Windows.Forms.Control, IChevron
{
ToolBarItemCollection items = new ToolBarItemCollection();
ToolBarItem[] handledItems = new ToolBarItem[0];
bool[] handledItemsVisible = new bool[0];
ChevronMenu chevronMenu = new ChevronMenu();
BarType barType = BarType.ToolBar;
const int DROWPDOWN_ARROW_WIDTH = 14;
const int MARGIN = 3;
const int MENUTEXT_MARGIN = 8;
ImageList imageList = null;
bool bGotIsCommonCtrl6 = false;
bool isCommonCtrl6 = false;
// To be used only when we have a menubar type
enum State
{
None,
Hot,
HotTracking
}
State state = State.None;
State lastState = State.None;
Point lastMousePosition = new Point(0, 0);
int trackHotItem = -1;
int trackNextItem = -1;
bool trackEscapePressed = false;
IntPtr hookHandle = IntPtr.Zero;
bool doKeyboardSelect = false;
bool useNewRow = true;
public ToolBarEx()
{
InitializeToolBar();
}
public ToolBarEx(bool useNewRow)
{
InitializeToolBar();
this.useNewRow = useNewRow;
}
public ToolBarEx(BarType type)
{
barType = type;
InitializeToolBar();
}
public ToolBarEx(BarType type, bool useNewRow)
{
barType = type;
InitializeToolBar();
this.useNewRow = useNewRow;
}
private void InitializeToolBar()
{
// We'll let the toolbar to send us messages for drawing
SetStyle(ControlStyles.UserPaint, false);
TabStop = false;
// Always on top
Dock = DockStyle.Top;
Attach();
}
~ToolBarEx()
{
Detach();
}
void Attach()
{
items.Changed += new EventHandler(Items_Changed);
int count = Items.Count;
handledItems = new ToolBarItem[count];
handledItemsVisible = new bool[count];
for (int i = 0; i < count; i++)
{
ToolBarItem item = Items[i];
item.Changed += new EventHandler(Item_Changed);
handledItems[i] = item;
handledItemsVisible[i] = item.Visible;
}
}
void Detach()
{
foreach (ToolBarItem item in handledItems)
{
item.Changed -= new EventHandler(Item_Changed);
}
handledItems = null;
handledItemsVisible = null;
items.Changed -= new EventHandler(Items_Changed);
}
public bool UseNewRow
{
get { return useNewRow; }
}
public ToolBarItemCollection Items
{
get { return items; }
}
protected override Size DefaultSize
{
get { return new Size(1, 1); }
}
public BarType BarType
{
get { return barType; }
}
private bool IsCommonCtrl6()
{
// Cache this value for efficenty
if ( bGotIsCommonCtrl6 == false )
{
DLLVERSIONINFO dllVersion = new DLLVERSIONINFO();
// We are assummng here that anything greater or equal than 6
// will have the new XP theme drawing enable
dllVersion.cbSize = Marshal.SizeOf(typeof(DLLVERSIONINFO));
WindowsAPI.GetCommonControlDLLVersion(ref dllVersion);
bGotIsCommonCtrl6 = true;
isCommonCtrl6 = (dllVersion.dwMajorVersion >= 6);
}
return isCommonCtrl6;
}
protected override void CreateHandle()
{
// Make sure common control library initilizes toolbars and rebars
if ( !RecreatingHandle )
{
INITCOMMONCONTROLSEX icex = new INITCOMMONCONTROLSEX();
icex.dwSize = Marshal.SizeOf(typeof(INITCOMMONCONTROLSEX));
icex.dwICC = (int)(CommonControlInitFlags.ICC_BAR_CLASSES | CommonControlInitFlags.ICC_COOL_CLASSES);
WindowsAPI.InitCommonControlsEx(icex);
}
base.CreateHandle();
}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ClassName = WindowsAPI.TOOLBARCLASSNAME;
createParams.ExStyle = 0;
// Windows specific flags
createParams.Style = (int)(WindowStyles.WS_CHILD | WindowStyles.WS_VISIBLE |
WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_CLIPSIBLINGS);
// Common Control specific flags
createParams.Style |= (int)(CommonControlStyles.CCS_NODIVIDER | CommonControlStyles.CCS_NORESIZE |
CommonControlStyles.CCS_NOPARENTALIGN);
// ToolBar specific flags
createParams.Style |= (int)(ToolBarStyles.TBSTYLE_TOOLTIPS | ToolBarStyles.TBSTYLE_FLAT | ToolBarStyles.TBSTYLE_TRANSPARENT);
if (HasText()) createParams.Style |= (int)ToolBarStyles.TBSTYLE_LIST;
return createParams;
}
}
private bool HasText()
{
for (int i = 0; i < items.Count; i++)
{
// check if we need to make this toolbar TBSTYLE_LIST
if ( items[i].Text != null && items[i].Text != string.Empty )
return true;
}
return false;
}
protected override void OnHandleCreated(EventArgs e)
{
// Send message needed for the toolbar to work properly before any other messages are sent
WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONSTRUCTSIZE, Marshal.SizeOf(typeof(TBBUTTON)), 0);
// Setup extended styles
int extendedStyle = (int)(ToolBarExStyles.TBSTYLE_EX_HIDECLIPPEDBUTTONS |
ToolBarExStyles.TBSTYLE_EX_DOUBLEBUFFER );
if ( BarType == BarType.ToolBar ) extendedStyle |= (int)ToolBarExStyles.TBSTYLE_EX_DRAWDDARROWS;
WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_SETEXTENDEDSTYLE, 0, extendedStyle);
RealizeItems();
base.OnHandleCreated(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if ( barType == BarType.MenuBar)
{
Point point = new Point(e.X, e.Y);
if ( state == State.Hot )
{
int index = HitTest(point);
if ((IsValid(index)) && ( point != lastMousePosition))
SetHotItem(index);
return;
}
lastMousePosition = point;
}
base.OnMouseMove(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if ( barType == BarType.MenuBar)
{
if ((e.Button == MouseButtons.Left) && (e.Clicks == 1))
{
Point point = new Point(e.X, e.Y);
int index = HitTest(point);
if (IsValid(index))
{
TrackDropDown(index);
return;
}
}
}
base.OnMouseDown(e);
}
bool IsValid(int index)
{
int count = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONCOUNT, 0, 0);
return ((index >= 0) && (index < count));
}
int HitTest(Point point)
{
POINT pt = new POINT();
pt.x = point.X;
pt.y = point.Y;
int hit = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_HITTEST, 0, ref pt);
if (hit > 0)
{
point = PointToScreen(point);
Rectangle bounds = RectangleToScreen(new Rectangle(0, 0, Width, Height));
if ( !bounds.Contains(point) ) return -1;
}
return hit;
}
int GetNextItem(int index)
{
if (index == -1) throw new Exception();
int count = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONCOUNT, 0, 0);
index++;
if (index >= count) index = 0;
return index;
}
int GetPreviousItem(int index)
{
if (index == -1) throw new Exception();
int count = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONCOUNT, 0, 0);
index--;
if (index < 0) index = count - 1;
return index;
}
int GetHotItemIndex()
{
return WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_GETHOTITEM, 0, 0);
}
void SetHotItem(int index)
{
WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_SETHOTITEM, index, 0);
}
void TrackDropDown(int index)
{
while ( index >= 0 )
{
trackNextItem = -1;
BeginUpdate();
// Raise event
ToolBarItem item = (ToolBarItem)items[index];
item.RaiseDropDown();
// Item state
WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_PRESSBUTTON, index, -1);
// Trick to get the first menu item selected
if ( doKeyboardSelect )
{
WindowsAPI.PostMessage(Handle, (int)Msg.WM_KEYDOWN, (int) Keys.Down, 1);
WindowsAPI.PostMessage(Handle, (int)Msg.WM_KEYUP, (int) Keys.Down, 1);
}
doKeyboardSelect = false;
SetState(State.HotTracking, index);
// Hook
WindowsAPI.HookProc hookProc = new WindowsAPI.HookProc(DropDownHook);
GCHandle hookProcHandle = GCHandle.Alloc(hookProc);
hookHandle = WindowsAPI.SetWindowsHookEx((int)WindowsHookCodes.WH_MSGFILTER,
hookProc, IntPtr.Zero, WindowsAPI.GetCurrentThreadId());
if ( hookHandle == IntPtr.Zero ) throw new SecurityException();
// Ask for position
RECT rect = new RECT();
WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_GETRECT, index, ref rect);
Point position = new Point(rect.left, rect.bottom-1);
EndUpdate();
Update();
CommandBarMenu menu = item.ToolBarItemMenu;
if ( menu == null ) return;
menu.Show(this, position);
// Unhook
WindowsAPI.UnhookWindowsHookEx(hookHandle);
hookProcHandle.Free();
hookHandle = IntPtr.Zero;
// Item state
WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_PRESSBUTTON, index, 0);
SetState(trackEscapePressed ? State.Hot : State.None, index);
index = trackNextItem;
}
}
void TrackDropDownNext(int index)
{
if (index != trackHotItem)
{
WindowsAPI.PostMessage(Handle, (int)Msg.WM_CANCELMODE, 0, 0);
trackNextItem = index;
}
}
IntPtr DropDownHook(int code, IntPtr wparam, IntPtr lparam)
{
if (code == (int)MouseHookFilters.MSGF_MENU)
{
MSG msg = (MSG) Marshal.PtrToStructure(lparam, typeof(MSG));
Message message = Message.Create(msg.hwnd, msg.message, msg.wParam, msg.lParam);
if ( DropDownFilter(ref message) )
return (IntPtr) 1;
}
return WindowsAPI.CallNextHookEx(hookHandle, code, wparam, lparam);
}
bool DropDownFilter(ref Message message)
{
if (state != State.HotTracking) throw new Exception();
// comctl32 sometimes steals the hot item for unknown reasons.
SetHotItem(trackHotItem);
if (message.Msg == (int)Msg.WM_KEYDOWN)
{
Keys keyData = (Keys)(int) message.WParam | ModifierKeys;
if ( keyData == Keys.Left || keyData == Keys.Right )
doKeyboardSelect = true;
if (keyData == Keys.Left)
{
TrackDropDownNext(GetPreviousItem(trackHotItem));
return true;
}
// Only move right if there is no submenu on the current selected item.
ToolBarItem item = items[trackHotItem];
if ((keyData == Keys.Right) && ((item.ToolBarItemMenu.SelectedMenuItem == null)
|| (item.ToolBarItemMenu.SelectedMenuItem.MenuItems.Count == 0)))
{
TrackDropDownNext(GetNextItem(trackHotItem));
return true;
}
if (keyData == Keys.Escape)
{
trackEscapePressed = true;
}
}
else if ((message.Msg == (int)Msg.WM_MOUSEMOVE) || (message.Msg == (int)Msg.WM_LBUTTONDOWN))
{
Point point = new Point(((int) message.LParam) & 0xffff, ((int) message.LParam) >> 16);
point = this.PointToClient(point);
if (message.Msg == (int)Msg.WM_MOUSEMOVE)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -