📄 menu.c
字号:
return r;
}
/*********************************************************************
*
* _GetItemPos
*/
static void _GetItemPos(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index, int* px, int* py) {
int i, EffectSize;
EffectSize = _GetEffectSize(hObj, pObj);
if (pObj->Flags & MENU_SF_VERTICAL) {
int yPos = 0;
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:
pObj->Sel = -1;
pObj->IsSubmenuActive = 0;
pObj->Flags |= MENU_SF_ACTIVE | MENU_SF_OPEN_ON_POINTEROVER;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -