📄 menu.c
字号:
{
ROSMENUINFO MenuInfo;
SendMessageW(Wnd, WM_INITMENU, (WPARAM)Menu, 0);
MenuGetRosMenuInfo(&MenuInfo, Menu);
if (0 == MenuInfo.Height)
{
/* app changed/recreated menu bar entries in WM_INITMENU
Recalculate menu sizes else clicks will not work */
SetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
}
/* This makes the menus of applications built with Delphi work.
* It also enables menus to be displayed in more than one window,
* but there are some bugs left that need to be fixed in this case.
*/
if(MenuInfo.Self == Menu)
{
MenuInfo.Wnd = Wnd;
MenuSetRosMenuInfo(&MenuInfo);
}
}
return TRUE;
}
/***********************************************************************
* MenuShowPopup
*
* Display a popup menu.
*/
static BOOL FASTCALL
MenuShowPopup(HWND WndOwner, HMENU Menu, UINT Id,
INT X, INT Y, INT XAnchor, INT YAnchor )
{
ROSMENUINFO MenuInfo;
ROSMENUITEMINFO ItemInfo;
UINT Width, Height;
DPRINT("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
WndOwner, Menu, Id, X, Y, XAnchor, YAnchor);
if (! MenuGetRosMenuInfo(&MenuInfo, Menu))
{
return FALSE;
}
if (NO_SELECTED_ITEM != MenuInfo.FocusedItem)
{
MenuInitRosMenuItemInfo(&ItemInfo);
if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo))
{
ItemInfo.fMask |= MIIM_STATE;
ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo);
}
MenuCleanupRosMenuItemInfo(&ItemInfo);
MenuInfo.FocusedItem = NO_SELECTED_ITEM;
}
/* store the owner for DrawItem */
MenuInfo.WndOwner = WndOwner;
MenuSetRosMenuInfo(&MenuInfo);
MenuPopupMenuCalcSize(&MenuInfo, WndOwner);
/* adjust popup menu pos so that it fits within the desktop */
Width = MenuInfo.Width + GetSystemMetrics(SM_CXBORDER);
Height = MenuInfo.Height + GetSystemMetrics(SM_CYBORDER);
if (GetSystemMetrics(SM_CXSCREEN ) < X + Width)
{
if (0 != XAnchor && X >= Width - XAnchor)
{
X -= Width - XAnchor;
}
if (GetSystemMetrics(SM_CXSCREEN) < X + Width)
{
X = GetSystemMetrics(SM_CXSCREEN) - Width;
}
}
if (X < 0 )
{
X = 0;
}
if (GetSystemMetrics(SM_CYSCREEN) < Y + Height)
{
if (0 != YAnchor && Y >= Height + YAnchor)
{
Y -= Height + YAnchor;
}
if (GetSystemMetrics(SM_CYSCREEN) < Y + Height)
{
Y = GetSystemMetrics(SM_CYSCREEN) - Height;
}
}
if (Y < 0 )
{
Y = 0;
}
/* NOTE: In Windows, top menu popup is not owned. */
MenuInfo.Wnd = CreateWindowExW(0, POPUPMENU_CLASS_ATOMW, NULL,
WS_POPUP, X, Y, Width, Height,
WndOwner, 0, (HINSTANCE) GetWindowLongPtrW(WndOwner, GWLP_HINSTANCE),
(LPVOID) MenuInfo.Self);
if (NULL == MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo))
{
return FALSE;
}
if (NULL == TopPopup)
{
TopPopup = MenuInfo.Wnd;
}
/* Display the window */
SetWindowPos(MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
UpdateWindow(MenuInfo.Wnd);
return TRUE;
}
/***********************************************************************
* MenuFindSubMenu
*
* Find a Sub menu. Return the position of the submenu, and modifies
* *hmenu in case it is found in another sub-menu.
* If the submenu cannot be found, NO_SELECTED_ITEM is returned.
*/
static UINT FASTCALL
MenuFindSubMenu(HMENU *Menu, HMENU SubTarget)
{
ROSMENUINFO MenuInfo;
ROSMENUITEMINFO ItemInfo;
UINT i;
HMENU SubMenu;
UINT Pos;
if ((HMENU) 0xffff == *Menu
|| ! MenuGetRosMenuInfo(&MenuInfo, *Menu))
{
return NO_SELECTED_ITEM;
}
MenuInitRosMenuItemInfo(&ItemInfo);
for (i = 0; i < MenuInfo.MenuItemCount; i++)
{
if (! MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
{
MenuCleanupRosMenuItemInfo(&ItemInfo);
return NO_SELECTED_ITEM;
}
if (0 == (ItemInfo.fType & MF_POPUP))
{
continue;
}
if (ItemInfo.hSubMenu == SubTarget)
{
MenuCleanupRosMenuItemInfo(&ItemInfo);
return i;
}
SubMenu = ItemInfo.hSubMenu;
Pos = MenuFindSubMenu(&SubMenu, SubTarget);
if (NO_SELECTED_ITEM != Pos)
{
*Menu = SubMenu;
return Pos;
}
}
MenuCleanupRosMenuItemInfo(&ItemInfo);
return NO_SELECTED_ITEM;
}
/***********************************************************************
* MenuSelectItem
*/
static void FASTCALL
MenuSelectItem(HWND WndOwner, PROSMENUINFO MenuInfo, UINT Index,
BOOL SendMenuSelect, HMENU TopMenu)
{
HDC Dc;
ROSMENUITEMINFO ItemInfo;
ROSMENUINFO TopMenuInfo;
int Pos;
DPRINT("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner, MenuInfo, Index, SendMenuSelect);
if (NULL == MenuInfo || 0 == MenuInfo->MenuItemCount || NULL == MenuInfo->Wnd)
{
return;
}
if (MenuInfo->FocusedItem == Index)
{
return;
}
if (0 != (MenuInfo->Flags & MF_POPUP))
{
Dc = GetDC(MenuInfo->Wnd);
}
else
{
Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
}
if (NULL == TopPopup)
{
TopPopup = MenuInfo->Wnd;
}
SelectObject(Dc, hMenuFont);
MenuInitRosMenuItemInfo(&ItemInfo);
/* Clear previous highlighted item */
if (NO_SELECTED_ITEM != MenuInfo->FocusedItem)
{
if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo))
{
ItemInfo.fMask |= MIIM_STATE;
ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
}
MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo,
MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP),
ODA_SELECT);
}
/* Highlight new item (if any) */
MenuInfo->FocusedItem = Index;
MenuSetRosMenuInfo(MenuInfo);
if (NO_SELECTED_ITEM != MenuInfo->FocusedItem)
{
if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo))
{
if (0 == (ItemInfo.fType & MF_SEPARATOR))
{
ItemInfo.fMask |= MIIM_STATE;
ItemInfo.fState |= MF_HILITE;
MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc,
&ItemInfo, MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP),
ODA_SELECT);
}
if (SendMenuSelect)
{
SendMessageW(WndOwner, WM_MENUSELECT,
MAKELONG(ItemInfo.fType & MF_POPUP ? Index : ItemInfo.wID,
ItemInfo.fType | ItemInfo.fState | MF_MOUSESELECT |
(MenuInfo->Flags & MF_SYSMENU)), (LPARAM) MenuInfo->Self);
}
}
}
else if (SendMenuSelect)
{
if (NULL != TopMenu)
{
Pos = MenuFindSubMenu(&TopMenu, MenuInfo->Self);
if (NO_SELECTED_ITEM != Pos)
{
if (MenuGetRosMenuInfo(&TopMenuInfo, TopMenu)
&& MenuGetRosMenuItemInfo(TopMenu, Pos, &ItemInfo))
{
SendMessageW(WndOwner, WM_MENUSELECT,
MAKELONG(Pos, ItemInfo.fType | ItemInfo.fState
| MF_MOUSESELECT
| (TopMenuInfo.Flags & MF_SYSMENU)),
(LPARAM) TopMenu);
}
}
}
}
MenuCleanupRosMenuItemInfo(&ItemInfo);
ReleaseDC(MenuInfo->Wnd, Dc);
}
/***********************************************************************
* MenuMoveSelection
*
* Moves currently selected item according to the Offset parameter.
* If there is no selection then it should select the last item if
* Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
*/
static void FASTCALL
MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
{
INT i;
ROSMENUITEMINFO ItemInfo;
INT OrigPos;
DPRINT("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
/* Prevent looping */
if (0 == MenuInfo->MenuItemCount || 0 == Offset)
return;
else if (Offset < -1)
Offset = -1;
else if (Offset > 1)
Offset = 1;
MenuInitRosMenuItemInfo(&ItemInfo);
OrigPos = MenuInfo->FocusedItem;
if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
{
OrigPos = 0;
i = -1;
}
else
{
i = MenuInfo->FocusedItem;
}
do
{
/* Step */
i += Offset;
/* Clip and wrap around */
if (i < 0)
{
i = MenuInfo->MenuItemCount - 1;
}
else if (i >= MenuInfo->MenuItemCount)
{
i = 0;
}
/* If this is a good candidate; */
if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
0 == (ItemInfo.fType & MF_SEPARATOR) &&
0 == (ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)) )
{
MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
MenuCleanupRosMenuItemInfo(&ItemInfo);
return;
}
} while (i != OrigPos);
/* Not found */
MenuCleanupRosMenuItemInfo(&ItemInfo);
}
/***********************************************************************
* MenuInitSysMenuPopup
*
* Grey the appropriate items in System menu.
*/
void FASTCALL
MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle, LONG HitTest )
{
BOOL Gray;
UINT DefItem;
#if 0
MENUITEMINFOW mii;
#endif
Gray = 0 == (Style & WS_THICKFRAME) || 0 != (Style & (WS_MAXIMIZE | WS_MINIMIZE));
EnableMenuItem(Menu, SC_SIZE, (Gray ? MF_GRAYED : MF_ENABLED));
Gray = 0 != (Style & WS_MAXIMIZE);
EnableMenuItem(Menu, SC_MOVE, (Gray ? MF_GRAYED : MF_ENABLED));
Gray = 0 == (Style & WS_MINIMIZEBOX) || 0 != (Style & WS_MINIMIZE);
EnableMenuItem(Menu, SC_MINIMIZE, (Gray ? MF_GRAYED : MF_ENABLED));
Gray = 0 == (Style & WS_MAXIMIZEBOX) || 0 != (Style & WS_MAXIMIZE);
EnableMenuItem(Menu, SC_MAXIMIZE, (Gray ? MF_GRAYED : MF_ENABLED));
Gray = 0 == (Style & (WS_MAXIMIZE | WS_MINIMIZE));
EnableMenuItem(Menu, SC_RESTORE, (Gray ? MF_GRAYED : MF_ENABLED));
Gray = 0 != (ClsStyle & CS_NOCLOSE);
/* The menu item must keep its state if it's disabled */
if (Gray)
{
EnableMenuItem(Menu, SC_CLOSE, MF_GRAYED);
}
/* Set default menu item */
if(Style & WS_MINIMIZE)
{
DefItem = SC_RESTORE;
}
else
{
if(HitTest == HTCAPTION)
{
DefItem = ((Style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
}
else
{
DefItem = SC_CLOSE;
}
}
#if 0
mii.cbSize = sizeof(MENUITEMINFOW);
mii.fMask |= MIIM_STATE;
if((DefItem != SC_CLOSE) && GetMenuItemInfoW(Menu, DefItem, FALSE, &mii) &&
(mii.fState & (MFS_GRAYED | MFS_DISABLED)))
{
DefItem = SC_CLOSE;
}
#endif
SetMenuDefaultItem(Menu, DefItem, MF_BYCOMMAND);
}
/***********************************************************************
* MenuShowSubPopup
*
* Display the sub-menu of the selected item of this menu.
* Return the handle of the submenu, or menu if no submenu to display.
*/
static HMENU FASTCALL
MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags)
{
extern void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect);
RECT Rect;
ROSMENUITEMINFO ItemInfo;
ROSMENUINFO SubMenuInfo;
HDC Dc;
HMENU Ret;
DPRINT("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst);
if (NO_SELECTED_ITEM == MenuInfo->FocusedItem)
{
return MenuInfo->Self;
}
MenuInitRosMenuItemInfo(&ItemInfo);
i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -