📄 menu.c
字号:
}
}
/*********************************************************************
*
* _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) {
pObj->Sel = Index;
MENU__InvalidateItem(hObj, pObj, pObj->Sel); /* Invalidate previous selection */
MENU__InvalidateItem(hObj, pObj, Index); /* Invalidate new selection */
}
}
/*********************************************************************
*
* _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
*/
#if (GUI_SUPPORT_MOUSE)
static int _ForwardMouseOverMsg(MENU_Handle hObj, MENU_Obj* pObj, int x, int y) {
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__IsInModalArea(hBelow)) {
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;
}
}
}
return 0;
}
#endif
/*********************************************************************
*
* _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 > 0) {
if ((PrevState.Pressed == 0) && (Pressed == 1)) { /* 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 (GUI_SUPPORT_MOUSE)
if (_ForwardMouseOverMsg(hObj, pObj, x, y) != 0) {
_DeselectItem(hObj, pObj);
} else
#endif
{
_SelectItem(hObj, pObj, ItemIndex);
}
}
} else {
/*
* Coordinates are outside the menu but inside the widget.
*/
if (Pressed > 0) {
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 */
if (!(pObj->Widget.State & WIDGET_STATE_FOCUS)) {
_DeselectItem(hObj, pObj);
}
}
}
return 0;
} else {
/*
* Handle PID when coordinates are outside the widget.
*/
if ((Pressed > 0) && (PrevState.Pressed == 0)) {
/*
* User has clicked outside the menu. Close the active submenu.
* The widget itself must be closed (if needed) by the owner.
*/
_DeselectItem(hObj, pObj);
_DeactivateMenu(hObj, pObj);
_ClosePopup(hObj, pObj);
_SetSelection(hObj, pObj, -1);
if (pObj->Widget.State & WIDGET_STATE_FOCUS) {
MENU_Handle hObjTopLevel;
MENU_Obj * pObjTopLevel;
_GetTopLevelMenu(hObj, pObj, &hObjTopLevel, &pObjTopLevel, 0);
WM_SetFocus(hObjTopLevel);
_SetSelection(hObjTopLevel, pObjTopLevel, -1);
_ReleaseCapture(hObjTopLevel, pObjTopLevel);
}
}
if (!(pObj->Widget.State & WIDGET_STATE_FOCUS)) {
_DeselectItem(hObj, pObj);
}
#if (GUI_SUPPORT_MOUSE)
_ForwardMouseOverMsg(hObj, pObj, x, y);
#endif
}
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;
_SetCapture(hObj, pObj);
MENU__ResizeMenu(hObj, pObj);
break;
case MENU_ON_CLOSE:
_CloseSubmenu(hObj, pObj);
break;
case MENU_IS_MENU:
pMsg->Data.v = 1;
break;
}
}
}
/*********************************************************************
*
* _OnTouch
*/
static char _OnTouch(MENU_Handle hObj, MENU_Obj* pObj, WM_MESSAGE* pMsg) {
const GUI_PID_STATE* pState = (const GUI_PID_STATE*)pMsg->Data.p;
if (pState) { /* Something happened in our area (pressed or released) */
return _HandlePID(hObj, pObj, pState->x, pState->y, pState->Pressed);
}
return _HandlePID(hObj, pObj, -1, -1, -1); /* Moved out */
}
/*********************************************************************
*
* _OnMouseOver
*/
#if (GUI_SUPPORT_MOUSE)
static char _OnMouseOver(MENU_Handle hObj, MENU_Obj* pObj, WM_MESSAGE* pMsg) {
const GUI_PID_STATE* pState = (const GUI_PID_STATE *)pMsg->Data.p;
if (pState) {
return _HandlePID(hObj, pObj, pState->x, pState->y, -1);
}
return 0;
}
#endif
/*********************************************************************
*
* _SetPaintColors
*/
static void _SetPaintColors(const MENU_Obj* pObj, const MENU_ITEM* pItem, int ItemIndex) {
char Selected;
unsigned ColorIndex;
Selected = (ItemIndex == pObj->Sel) ? 1 : 0;
if (pObj->IsSubmenuActive && Selected) {
ColorIndex = MENU_CI_ACTIVE_SUBMENU;
} else if (pItem->Flags & MENU_IF_SEPARATOR) {
ColorIndex = MENU_CI_ENABLED;
} else {
ColorIndex = (Selected) ? MENU_CI_SELECTED : MENU_CI_ENABLED;
if (pItem->Flags & MENU_IF_DISABLED) {
if (pObj->Flags & MENU_CF_HIDE_DISABLED_SEL) {
ColorIndex = MENU_CI_DISABLED;
} else {
ColorIndex += MENU_CI_DISABLED;
}
}
}
GUI_SetBkColor(pObj->Props.aBkColor[ColorIndex]);
GUI_SetColor(pObj->Props.aTextColor[ColorIndex]);
}
/*********************************************************************
*
* _OnPaint
*/
static void _OnPaint(MENU_Handle hObj, MENU_Obj* pObj) {
GUI_RECT FillRect, TextRect;
MENU_ITEM* pItem;
unsigned TextWidth, NumItems, i;
U8 BorderLeft = pObj->Props.aBorder[MENU_BI_LEFT];
U8 BorderTop = pObj->Props.aBorder[MENU_BI_TOP];
int FontHeight = GUI_GetYDistOfFont(pObj->Props.pFont);
int EffectSize = _GetEffectSize(hObj, pObj);
NumItems = MENU__GetNumItems(pObj);
WM__GetClientRectWin(&pObj->Widget.Win, &FillRect);
GUI__ReduceRect(&FillRect, &FillRect, EffectSize);
GUI_SetFont(pObj->Props.pFont);
if (pObj->Flags & MENU_SF_VERTICAL) {
int ItemHeight, xSize;
xSize = _CalcMenuSizeX(hObj, pObj);
FillRect.x1 = xSize - EffectSize - 1;
TextRect.x0 = FillRect.x0 + BorderLeft;
for (i = 0; i < NumItems; i++) {
pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, i);
ItemHeight = _GetItemHeight(hObj, pObj, i);
_SetPaintColors(pObj, pItem, i);
FillRect.y1 = FillRect.y0 + ItemHeight - 1;
if (pItem->Flags & MENU_IF_SEPARATOR) {
GUI_ClearRectEx(&FillRect);
GUI_SetColor(0x7C7C7C);
GUI_DrawHLine(FillRect.y0 + BorderTop + 1, FillRect.x0 + 2, FillRect.x1 - 2);
} else {
TextWidth = pItem->TextWidth;
TextRect.x1 = TextRect.x0 + TextWidth - 1;
TextRect.y0 = FillRect.y0 + BorderTop;
TextRect.y1 = TextRect.y0 + FontHeight - 1;
WIDGET__FillStringInRect(pItem->acText, &FillRect, &TextRect, &TextRect);
}
FillRect.y0 += ItemHeight;
}
} else {
int ItemWidth, ySize;
ySize = _CalcMenuSizeY(hObj, pObj);
FillRect.y1 = ySize - EffectSize - 1;
TextRect.y0 = FillRect.y0 + BorderTop;
TextRect.y1 = TextRect.y0 + FontHeight - 1;
for (i = 0; i < NumItems; i++) {
pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, i);
ItemWidth = _GetItemWidth(hObj, pObj, i);
_SetPaintColors(pObj, pItem, i);
FillRect.x1 = FillRect.x0 + ItemWidth - 1;
if (pItem->Flags & MENU_IF_SEPARATOR) {
GUI_ClearRectEx(&FillRect);
GUI_SetColor(0x7C7C7C);
GUI_DrawVLine(FillRect.x0 + BorderLeft + 1, FillRect.y0 + 2, FillRect.y1 - 2);
} else {
TextWidth = pItem->TextWidth;
TextRect.x0 = FillRect.x0 + BorderLeft;
TextRect.x1 = TextRect.x0 + TextWidth - 1;
WIDGET__FillStringInRect(pItem->acText, &FillRect, &TextRect, &TextRect);
}
FillRect.x0 += ItemWidth;
}
}
if (pObj->Width || pObj->Height) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -