📄 menu.c
字号:
for (i = 0; i < (int) Index; i++)
{
yPos += _GetItemHeight(hObj, pObj, i);
}
*px = EffectSize;
*py = EffectSize + yPos;
}
else
{
int xPos = 0;
for (i = 0; i < (int) Index; i++)
{
xPos += _GetItemWidth(hObj, pObj, i);
}
*px = EffectSize + xPos;
*py = EffectSize;
}
}
/*********************************************************************
*
* _SetCapture
*/
static void _SetCapture(MENU_Handle hObj, const MENU_Obj *pObj)
{
if (pObj->IsSubmenuActive == 0)
{
if (WM_HasCaptured(hObj) == 0)
{
WM_SetCapture(hObj, 0);
}
}
}
/*********************************************************************
*
* _ReleaseCapture
*/
static void _ReleaseCapture(MENU_Handle hObj, const MENU_Obj *pObj)
{
if (WM_HasCaptured(hObj))
{
if (_IsTopLevelMenu(hObj, pObj) && !(pObj->Flags & MENU_SF_POPUP))
{
WM_ReleaseCapture();
}
}
}
/*********************************************************************
*
* _CloseSubmenu
*/
static void _CloseSubmenu(MENU_Handle hObj, MENU_Obj *pObj)
{
if (pObj->Flags & MENU_SF_ACTIVE)
{
if (pObj->IsSubmenuActive)
{
MENU_ITEM* pItem = (MENU_ITEM *) GUI_ARRAY_GetpItem(&pObj->ItemArray, pObj->Sel);
/* Inform submenu about its deactivation and detach it */
MENU__SendMenuMessage(hObj, pItem->hSubmenu, MENU_ON_CLOSE, 0);
WM_DetachWindow(pItem->hSubmenu);
pObj->IsSubmenuActive = 0;
/*
* Keep capture in menu widget. The capture may only released
* by clicking outside the menu or when mouse moved out.
* And it may only released from a top level menu.
*/
_SetCapture(hObj, pObj);
/* Invalidate menu item. This is needed because the appearance may have changed */
MENU__InvalidateItem(hObj, pObj, pObj->Sel);
}
}
}
/*********************************************************************
*
* _OpenSubmenu
*/
static void _OpenSubmenu(MENU_Handle hObj, MENU_Obj *pObj, unsigned Index)
{
if (pObj->Flags & MENU_SF_ACTIVE)
{
MENU_ITEM* pItem;
char PrevActiveSubmenu;
PrevActiveSubmenu = pObj->IsSubmenuActive;
/* Close previous submenu (if needed) */
_CloseSubmenu(hObj, pObj);
pItem = (MENU_ITEM *) GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);
if (pItem->hSubmenu)
{
if ((pItem->Flags & MENU_IF_DISABLED) == 0)
{
int x, y, EffectSize;
/* Calculate position of submenu */
EffectSize = _GetEffectSize(hObj, pObj);
_GetItemPos(hObj, pObj, Index, &x, &y);
if (pObj->Flags & MENU_SF_VERTICAL)
{
x += _CalcMenuSizeX(hObj, pObj) - (_GetEffectSize(hObj, pObj) << 1);
y -= EffectSize;
}
else
{
y += _CalcMenuSizeY(hObj, pObj) - (_GetEffectSize(hObj, pObj) << 1);
x -= EffectSize;
}
x += WM_GetWindowOrgX(hObj);
y += WM_GetWindowOrgY(hObj);
/*
* Notify owner window when for the first time open a menu (when no
* other submenu was open), so it can initialize the menu items.
*/
if (PrevActiveSubmenu == 0)
{
if (_IsTopLevelMenu(hObj, pObj))
{
MENU__SendMenuMessage(hObj, pObj->hOwner, MENU_ON_INITMENU, 0);
}
}
/* Notify owner window when a submenu opens, so it can initialize the menu items. */
MENU__SendMenuMessage(hObj, pObj->hOwner, MENU_ON_INITSUBMENU, pItem->Id);
/* Set active menu as owner of submenu. */
MENU_SetOwner(pItem->hSubmenu, hObj);
/* Attach submenu and inform it about its activation. */
WM_AttachWindowAt(pItem->hSubmenu, WM_HBKWIN, x, y);
MENU__SendMenuMessage(hObj, pItem->hSubmenu, MENU_ON_OPEN, 0);
pObj->IsSubmenuActive = 1;
/* Invalidate menu item. This is needed because the appearance may have changed. */
MENU__InvalidateItem(hObj, pObj, Index);
}
}
}
}
/*********************************************************************
*
* _ClosePopup
*/
static void _ClosePopup(MENU_Handle hObj, MENU_Obj *pObj)
{
if (pObj->Flags & MENU_SF_POPUP)
{
pObj->Flags &= ~(MENU_SF_POPUP);
WM_DetachWindow(hObj);
WM_ReleaseCapture();
}
}
/*********************************************************************
*
* _SetSelection
*/
static void _SetSelection(MENU_Handle hObj, MENU_Obj *pObj, int Index)
{
if (Index != pObj->Sel)
{
MENU__InvalidateItem(hObj, pObj, pObj->Sel); /* Invalidate previous selection */
MENU__InvalidateItem(hObj, pObj, Index); /* Invalidate new selection */
pObj->Sel = Index;
}
}
/*********************************************************************
*
* _SelectItem
*/
static void _SelectItem(MENU_Handle hObj, MENU_Obj *pObj, unsigned Index)
{
if (pObj->Sel != (int) Index)
{
_SetCapture(hObj, pObj);
_OpenSubmenu(hObj, pObj, Index);
_SetSelection(hObj, pObj, Index);
}
}
/*********************************************************************
*
* _DeselectItem
*/
static void _DeselectItem(MENU_Handle hObj, MENU_Obj *pObj)
{
if (pObj->IsSubmenuActive == 0)
{
_SetSelection(hObj, pObj, -1);
_ReleaseCapture(hObj, pObj);
}
}
/*********************************************************************
*
* _ActivateItem
*/
static void _ActivateItem(MENU_Handle hObj, MENU_Obj *pObj, unsigned Index)
{
MENU_ITEM* pItem;
pItem = (MENU_ITEM *) GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);
if (pItem->hSubmenu == 0)
{
if ((pItem->Flags & (MENU_IF_DISABLED | MENU_IF_SEPARATOR)) == 0)
{
_ClosePopup(hObj, pObj);
/* Send item select message to owner. */
MENU__SendMenuMessage(hObj, pObj->hOwner, MENU_ON_ITEMSELECT, pItem->Id);
}
}
}
/*********************************************************************
*
* _ActivateMenu
*/
static void _ActivateMenu(MENU_Handle hObj, MENU_Obj *pObj, unsigned Index)
{
if ((pObj->Flags & MENU_SF_OPEN_ON_POINTEROVER) == 0)
{
MENU_ITEM* pItem;
pItem = (MENU_ITEM *) GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);
if (pItem->hSubmenu)
{
if ((pItem->Flags & MENU_IF_DISABLED) == 0)
{
if ((pObj->Flags & MENU_SF_ACTIVE) == 0)
{
pObj->Flags |= MENU_SF_ACTIVE;
_OpenSubmenu(hObj, pObj, Index);
_SetSelection(hObj, pObj, Index);
}
else if (pObj->Flags & MENU_SF_CLOSE_ON_SECOND_CLICK)
{
if ((int) Index == pObj->Sel)
{
_CloseSubmenu(hObj, pObj);
pObj->Flags &= ~MENU_SF_ACTIVE;
}
}
}
}
}
}
/*********************************************************************
*
* _DeactivateMenu
*/
static void _DeactivateMenu(MENU_Handle hObj, MENU_Obj *pObj)
{
_CloseSubmenu(hObj, pObj);
if ((pObj->Flags & MENU_SF_OPEN_ON_POINTEROVER) == 0)
{
pObj->Flags &= ~MENU_SF_ACTIVE;
}
}
/*******************************************************************
*
* _ForwardMouseOverMsg
*/
static int _ForwardMouseOverMsg(MENU_Handle hObj, MENU_Obj *pObj, int x, int y)
{
#if (GUI_SUPPORT_MOUSE)
if ((pObj->IsSubmenuActive == 0) && !(pObj->Flags & MENU_SF_POPUP))
{
if (_IsTopLevelMenu(hObj, pObj))
{
WM_HWIN hBelow;
x += WM_GetWindowOrgX(hObj);
y += WM_GetWindowOrgY(hObj);
hBelow = WM_Screen2hWin(x, y);
if (hBelow && (hBelow != hObj))
{
WM_MESSAGE Msg;
GUI_PID_STATE State;
x -= WM_GetWindowOrgX(hBelow);
y -= WM_GetWindowOrgY(hBelow);
State.Pressed = 0;
State.x = x;
State.y = y;
Msg.Data.p = &State;
Msg.MsgId = WM_MOUSEOVER;
WM__SendMessage(hBelow, &Msg);
return 1;
}
}
}
#endif
return 0;
}
/*********************************************************************
*
* _HandlePID
*
* Return values:
* 1 = We need to forward PID message to owner.
* 0 = We do not need to inform owner.
*/
static char _HandlePID(MENU_Handle hObj, MENU_Obj *pObj, int x, int y, int Pressed)
{
GUI_PID_STATE PrevState;
char XYInWidget = 0;
WM_PID__GetPrevState(&PrevState);
/*
* Check if coordinates are inside the widget.
*/
if ((x >= 0) && (y >= 0))
{
GUI_RECT r;
WM__GetClientRectWin(&pObj->Widget.Win, &r);
if ((x <= r.x1) && (y <= r.y1))
{
XYInWidget = 1;
}
}
if (XYInWidget)
{
int ItemIndex;
ItemIndex = _GetItemFromPos(hObj, pObj, x, y);
/*
* Handle PID when coordinates are inside the widget.
*/
if (ItemIndex >= 0)
{
/*
* Coordinates are inside the menu.
*/
if (Pressed == 1)
{
if (PrevState.Pressed == 0)
{
/* Clicked */
_ActivateMenu(hObj, pObj, ItemIndex);
}
_SelectItem(hObj, pObj, ItemIndex);
}
else if ((Pressed == 0) && (PrevState.Pressed == 1))
{
/* Released */
_ActivateItem(hObj, pObj, ItemIndex);
}
else if (Pressed < 0)
{
/* Mouse moved */
if (_ForwardMouseOverMsg(hObj, pObj, x, y) == 0)
{
_SelectItem(hObj, pObj, ItemIndex);
}
else
{
_DeselectItem(hObj, pObj);
}
}
}
else
{
/*
* Coordinates are outside the menu but inside the widget.
*/
if (Pressed == 1)
{
if (PrevState.Pressed == 0)
{
/* Clicked */
/*
* User has clicked outside the menu. Close the active submenu.
* The widget itself must be closed (if needed) by the owner.
*/
_DeactivateMenu(hObj, pObj);
}
_DeselectItem(hObj, pObj);
}
else if (Pressed < 0)
{
/* Moved out or mouse moved */
_DeselectItem(hObj, pObj);
}
}
return 0;
}
else
{
/*
* Handle PID when coordinates are outside the widget.
*/
if ((Pressed == 1) && (PrevState.Pressed == 0))
{
/*
* User has clicked outside the menu. Close the active submenu.
* The widget itself must be closed (if needed) by the owner.
*/
_DeactivateMenu(hObj, pObj);
_ClosePopup(hObj, pObj);
}
_DeselectItem(hObj, pObj);
_ForwardMouseOverMsg(hObj, pObj, x, y);
}
return 1; /* Coordinates are not in widget, we need to forward PID message to owner */
}
/*********************************************************************
*
* _ForwardPIDMsgToOwner
*/
static void _ForwardPIDMsgToOwner(MENU_Handle hObj, MENU_Obj *pObj, WM_MESSAGE *pMsg)
{
if (_IsTopLevelMenu(hObj, pObj) == 0)
{
WM_HWIN hOwner;
hOwner = pObj->hOwner ? pObj->hOwner : WM_GetParent(hObj);
if (hOwner)
{
if (pMsg->Data.p)
{
GUI_PID_STATE* pState;
pState = (GUI_PID_STATE *) pMsg->Data.p;
pState->x += WM_GetWindowOrgX(hObj) - WM_GetWindowOrgX(hOwner);
pState->y += WM_GetWindowOrgY(hObj) - WM_GetWindowOrgY(hOwner);
}
WM__SendMessage(hOwner, pMsg);
}
}
}
/*********************************************************************
*
* Static routines, callback
*
**********************************************************************
*/
/*********************************************************************
*
* _OnMenu
*/
static void _OnMenu(MENU_Handle hObj, MENU_Obj *pObj, WM_MESSAGE *pMsg)
{
const MENU_MSG_DATA* pData = (const MENU_MSG_DATA *) pMsg->Data.p;
if (pData)
{
switch (pData->MsgType)
{
case MENU_ON_ITEMSELECT:
_DeactivateMenu(hObj, pObj);
_DeselectItem(hObj, pObj);
_ClosePopup(hObj, pObj);
/* No break here. We need to forward message to owner. */
case MENU_ON_INITMENU:
case MENU_ON_INITSUBMENU:
/* Forward message to owner. */
{
WM_HWIN hOwner;
hOwner = pObj->hOwner ? pObj->hOwner : WM_GetParent(hObj);
if (hOwner)
{
pMsg->hWinSrc = hObj;
WM__SendMessage(hOwner, pMsg);
}
}
break;
case MENU_ON_OPEN:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -