📄 menu.c
字号:
arcMenu.axRight + daxShadow + daxDbcs,
arcMenu.ayBottom + dayShadow,
lpbMenu);
FreeWorkFar(lpbMenu);
#ifdef KANJI
fRestoreDbcs = FALSE;
#endif /*KANJI*/
}
mniCur.pmenuOpen = NULL;
mniCur.iitem = iitemNil;
#else // MENU_NOSAVE
mniCur.pmenuOpen = NULL;
mniCur.iitem = iitemNil;
ScreenRedraw();
#endif // MENU_NOSAVE
if (fMessage)
SendMessage(pwndMenu, WM_COMMAND, mniCur.pmenuOpen->idMenu,
MAKELONG(mniCur.pmenuOpen,mmdMenu));
ReportMenuInactive();
}
/********** MENU selection **********/
STATIC VOID
HiliteMenuMnem(fOn)
/*
-- hilite or unhilite the menu mnemonics
-- do nothing if menu is open
-- update global state (mniCur.fMenuMnem)
*/
BOOL fOn;
{
REGISTER PMENU pmenu;
REGISTER WORD imenu;
WORD di;
if (FMenuOpen())
{
/* menu is open, this should be a no op */
Assert(mniCur.fMenuMnem == fOn);
return;
}
if (!FShowMenuBar())
return;
DrawThisWnd(NULL);
for (imenu = 0, pmenu = pmenubarCur->rgmenu;
imenu < pmenubarCur->cmenu;
imenu++, pmenu++)
{
AX ax = axMenuMin + pmenu->rxTitle + (BYTE) pmenu->ichHilite;
if (imenu != mniCur.imenu)
di = (fOn) ? (dmAttrOnly | isaMenuHilite) :
( (pmenu->fEnabled) ? (dmAttrOnly | isaMenu) :
(dmAttrOnly | isaDisabledMenuItem));
else
{
di = (fOn) ? (dmAttrOnly | isaMenuHiliteSel) :
(dmAttrOnly | isaMenuSelected);
}
FillArc(ax, ayMenu, ax + 1, ayMenu + 1, '\0', di);
}
mniCur.fMenuMnem = fOn;
}
STATIC BOOL
FMakeSelection()
/*
-- attempt to make a selection
-- if applicable send messages for menu selection
-- valid selection closes menu and returns TRUE
-- invalid selection (i.e. disabled item) optionally beeps,
keeps menu open, and returns FALSE
-- note : will set menu state to idle before returning TRUE
*/
{
WORD id;
DWORD lParam;
REGISTER PMENU pmenu = mniCur.pmenuOpen;
Assert(mniCur.imenu != imenuNil);
if (mniCur.iitem != iitemNil)
{
PMENUITEM pmenuitem = &(PmenuitemOfPmenu(pmenu)[mniCur.iitem]);
if (!pmenuitem->fEnabled)
{
/* selection of disabled item */
Beep();
return FALSE;
}
id = pmenuitem->idItem;
lParam = MAKELONG(pmenuitem, mmdItem);
}
else
{
id = pmenu->idMenu; /* menu but no selection */
lParam = MAKELONG(pmenu, mmdMenu);
}
/* valid selection : close menu - keep menu name hilited */
CloseMenuCur(FALSE);
/* send message while menu name hilited - the menu may change */
mniCur.imenu = imenuNil;
SendMessage(pwndMenu, WM_COMMAND, id, lParam);
ReportMenuInactive();
/* do both : unhilite menu title and redraw optionally changed bar */
DrawMenubar();
UpdateCursor();
return TRUE;
}
STATIC WORD
ImenuPickVk(vk)
/*
-- Search for menu based on "hilite" character in menu title
-- if found return imenu
-- if not found, return imenuNil
*/
WORD vk; /* virtual key of first character */
{
WORD imenu;
REGISTER PMENU pmenu = pmenubarCur->rgmenu;
for (imenu = 0; imenu < pmenubarCur->cmenu; imenu++, pmenu++)
{
#ifndef KANJI
if (FMatchVkCh(vk, *(pmenu->pchTitle + pmenu->ichHilite)))
#else
if (FMatchVkCh(vk, fKanaAccel ? (char) pmenu->chKanaAccel :
*(pmenu->pchTitle + pmenu->ichHilite)))
#endif /*KANJI*/
{
/* go one */
return imenu;
}
}
return imenuNil;
}
STATIC WORD
ImenuPickMsp(msp)
/*
-- mouse is on menu title line
-- return index of selected menu or imenuNil
*/
MSP msp;
{
REGISTER MENU *pmenu;
REGISTER AX ax = msp.s.ax;
WORD imenu;
Assert(msp.s.ay == ayMenu);
pmenu = pmenubarCur->rgmenu;
for (imenu = 0; imenu < pmenubarCur->cmenu; imenu++, pmenu++)
{
if (ax + 1 >= (AX) pmenu->rxTitle &&
ax <= ((AX) pmenu->rxTitle + pmenu->cchTitle))
{
return imenu;
}
}
return imenuNil;
}
/********** MENUITEMS **********/
STATIC VOID
DrawMenuItem(axLeft, ay, axRight, pmenuitem)
/*
-- output a menu item
-- left justify the portion to the left of a tab
-- right justify the portion after the tab
-- output checkmark if on
-- only called by OpenMenuCur().
*/
AX axLeft, axRight;
AY ay;
REGISTER PMENUITEM pmenuitem;
{
char * sz = SzItem(pmenuitem);
WORD di = pmenuitem->fEnabled ?
DiNormal(isaEnabledMenuItem) :
DiNormal(isaDisabledMenuItem);
AX ax = axLeft + rxMenuText;
#ifdef MENU_RIGHT_JUSTIFY
REGISTER char * szT = sz;
WORD cch;
for (cch = 0; *szT != '\t' && *szT != '\0'; cch++)
szT++;
Assert(pmenuitem->ichHilite < cch);
TextOutAbs(ax, ay, sz, cch, di);
#else
TextOutAbs(ax, ay, sz, strlen(sz), di);
Unreferenced(axRight); /* right coordinate not used */
#endif
#ifdef KANJI
/* kana accelerator at start ? */
if (fKanaAccel)
CharOutAbs(ax, ay, pmenuitem->chKanaAccel, di);
#endif /*KANJI*/
/* select hilited character (if enabled) */
if (pmenuitem->fEnabled)
{
ax += (BYTE) pmenuitem->ichHilite;
FillArc(ax, ay, ax + 1, ay + 1, '\0',
(dmAttrOnly | isaMenuHilite));
}
if (pmenuitem->fChecked)
CharOutAbs(axLeft + rxMenuMark, ay, chMenuMark, di);
#ifdef MENU_RIGHT_JUSTIFY
/* output right aligned stuff if any */
if (*szT != '\0')
{
cch = strlen(++szT);
TextOutAbs(axRight - cch - 1, ay, szT, cch, di);
}
#endif
}
STATIC VOID
HiliteItem(fSelected)
/*
-- highlight current menu item within current menu list
*/
BOOL fSelected;
{
if (mniCur.iitem != iitemNil)
{
REGISTER PMENUITEM pmenuitem;
REGISTER ISA isa;
AX ax;
AY ay;
Assert(mniCur.pmenuOpen != NULL && mniCur.pmenuOpen->citem != 0);
Assert(mniCur.pmenuOpen == &pmenubarCur->rgmenu[mniCur.imenu]);
DrawThisWnd(NULL);
pmenuitem = &PmenuitemOfPmenu(mniCur.pmenuOpen)[mniCur.iitem];
if (fSelected)
isa = isaSelectedMenuItem;
else
isa = (ISA) (pmenuitem->fEnabled ?
isaEnabledMenuItem :
isaDisabledMenuItem);
ay = arcMenu.ayTop + mniCur.iitem + 1;
FillArc(arcMenu.axLeft + daxBorder, ay,
arcMenu.axRight - daxBorder,
ay + dayBorder, '\0', dmAttrOnly | isa);
/* restore hilite character */
if (pmenuitem->fEnabled)
{
ax = arcMenu.axLeft + rxMenuText + pmenuitem->ichHilite;
FillArc(ax, ay, ax + 1, ay + 1,
'\0', fSelected ? (dmAttrOnly | isaItemHiliteSel) :
(dmAttrOnly | isaMenuHilite));
}
/* If Selected then update help line */
if (fSelected)
SendMessage(pwndMenu, WM_MENUSELECT, pmenuitem->idItem,
MAKELONG(pmenuitem, mmdItem));
}
}
STATIC BOOL
FSelectItem(iitem)
/*
-- set specified item to be current selected item
-- if item is valid, change current selection and return TRUE
-- if item is invalid (separator), change to no selection, return FALSE
-- return TRUE if selection made
-- item may be beyond valid range, do wrapping here
*/
WORD iitem;
{
Assert(FMenuOpen());
Assert(mniCur.pmenuOpen == &pmenubarCur->rgmenu[mniCur.imenu]);
/* check for empty drop downs */
if (mniCur.pmenuOpen->citem == 0)
return TRUE;
/* check for menu wrapping */
if (iitem != imenuNil && iitem >= mniCur.pmenuOpen->citem)
{
/* perform wrap */
if (iitem == (WORD) -1) /* wrapped to -1 */
iitem = mniCur.pmenuOpen->citem - 1;
else
{
Assert(iitem == mniCur.pmenuOpen->citem);
iitem = 0;
}
}
Assert(iitem == iitemNil || iitem < mniCur.pmenuOpen->citem);
if (iitem != mniCur.iitem)
{
HiliteItem(FALSE);
if (PmenuitemOfPmenu(mniCur.pmenuOpen)[iitem].fSeparator)
{
mniCur.iitem = iitemNil;
ReportMenuInactive();
return FALSE;
}
else
{
/* real item : hilite even if disabled */
mniCur.iitem = iitem;
HiliteItem(TRUE);
}
}
return TRUE;
}
STATIC BOOL
FMatchItemVk(vk)
/*
-- Search for menu item based on first character (using ichHilite)
-- if found changed current selection
-- if found and enabled : select item and return TRUE
-- otherwise return FALSE
*/
WORD vk;
{
REGISTER PMENU pmenu = mniCur.pmenuOpen;
WORD citem;
WORD iitem;
REGISTER PMENUITEM pmenuitem;
#ifdef ACCEL_MULTIPLE
WORD citemMatch;
citemMatch = 0;
pmenuitem = &(PmenuitemOfPmenu(pmenu)[0]);
citem = pmenu->citem;
while (citem--)
{
#ifdef KANJI
/* Kanji Accelerator matching */
if (!pmenuitem->fSeparator &&
FMatchVkCh(vk, fKanaAccel ? (char) pmenuitem->chKanaAccel :
*(SzItem(pmenuitem) + pmenuitem->ichHilite)))
#else
if (!pmenuitem->fSeparator &&
FMatchVkCh(vk, *(SzItem(pmenuitem) + pmenuitem->ichHilite)))
#endif
citemMatch++;
pmenuitem++;
}
if (citemMatch == 0)
return FALSE; /* no match */
fOneOfMultiple = (citemMatch > 1);
#endif /*ACCEL_MULTIPLE*/
citem = pmenu->citem;
iitem = mniCur.iitem;
pmenuitem = &(PmenuitemOfPmenu(pmenu)[++iitem]);
while (citem--)
{
if (iitem >= pmenu->citem)
{
/* wrap to top */
iitem = 0;
pmenuitem = PmenuitemOfPmenu(pmenu);
}
#ifdef KANJI
/* Kanji Accelerator matching */
if (!pmenuitem->fSeparator &&
FMatchVkCh(vk, fKanaAccel ? (char) pmenuitem->chKanaAccel :
*(SzItem(pmenuitem) + pmenuitem->ichHilite)))
#else
if (!pmenuitem->fSeparator &&
FMatchVkCh(vk, *(SzItem(pmenuitem) + pmenuitem->ichHilite)))
#endif
{
/* found ! */
return (FSelectItem(iitem) && pmenuitem->fEnabled);
}
pmenuitem++;
iitem++;
}
return FALSE; /* not found */
}
STATIC BOOL
FSelectItemMsp(msp)
/*
-- Mouse form to pick an item
-- returns TRUE if picking an item (and changes item selection)
*/
MSP msp;
{
Assert(msp.s.ay != ayMenu);
if (FInsideMenuMsp(msp.s.ax, msp.s.ay))
{
Assert(mniCur.pmenuOpen->citem != 0);
FSelectItem(msp.s.ay - arcMenu.ayTop - 1);
mniCur.fMouseOnTitle = FALSE; /* selected something */
return TRUE;
}
/* not selecting anything */
HiliteItem(FALSE);
mniCur.iitem = iitemNil;
return FALSE;
}
STATIC BOOL
FInsideMenuMsp(ax, ay)
/*
-- return TRUE if inside Menu dropdown, or on menu title bar
*/
REGISTER AX ax;
REGISTER AY ay;
{
if (ay == ayMenu)
{
mniCur.fMouseOnTitle = TRUE;
return TRUE;
}
if (!FMenuOpen())
return FALSE;
return (ay > arcMenu.ayTop &&
ay < arcMenu.ayBottom - 1 &&
ax >= arcMenu.axLeft &&
ax < arcMenu.axRight);
}
/********** The Filter **********/
PRIVATE BOOL FARPRIVATE
MenuFilterProc(pmsg)
/*
-- menu manager filter procedure
-- returns true if message is to be filtered out
*/
REGISTER PMSG pmsg; /* access pmsg-> with same speed as local auto vars */
{
REGISTER WORD kk; /* Key bits + vk */
MSP msp;
BOOL fMenuAction;
if (pwndCapture != NULL)
return(FALSE);
kk = HIWORD(pmsg->lParam);
fMenuAction = FALSE;
msp.lParam = pmsg->lParam;
/* is it a valid (LEFT) menu mouse message ?? */
if (pmsg->message >= WM_MOUSEFIRST && pmsg->message <= WM_LMOUSELAST &&
FShowMenuBar())
{
if ((pmsg->message == WM_LBUTTONDBLCLK ||
pmsg->message == WM_LBUTTONDOWN) && !mniCur.fMouse)
{
/* Menu Button */
BOOL fInside = FInsideMenuMsp(msp.s.ax, msp.s.ay);
if (!mniCur.fMouse && !fInside &&
(FMenuActive() || mniCur.fMenuMnem))
{
/* click not in drop down */
SetIdleState();
return FALSE; /* pass message through */
}
mniCur.fMouse |= fInside;
}
/* now see if we should do any mouse work */
if (!mniCur.fMouse)
return FMenuActive(); /* eat if menu active */
if (msp.s.ay == ayMenu)
{
WORD imenuT;
imenuT = ImenuPickMsp(msp);
if (imenuT != imenuNil && !FMenuOpen())
goto open_new_menu;
else if (imenuT != mniCur.imenu)
{
CloseMenuCur(TRUE);
open_new_menu:
mniCur.fMouseOnTitle = FALSE; /* selection */
SelectMenu(imenuT);
OpenMenuCur();
}
else if (FMenuActive())
{
/* clear any selection */
Assert(FMenuOpen());
FSelectItem(iitemNil);
}
/* re-send menu title message (for help) */
if (mniCur.pmenuOpen->citem != 0)
if (mniCur.pmenuOpen != NULL)
SendMessage(pwndMenu, WM_MENUSELECT,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -