📄 menu.c
字号:
/* SCCSWHAT() */
/*
COW : Character Oriented Windows
menu.c : menu handler
*/
#define COW
#include <cow.h>
#include <umenu.h>
#include <uwindow.h>
#include <uisa.h>
#include <uevent.h>
#include <vkey.h>
#include <uscreen.h>
#include <uutil.h>
#include <kkeyboar.h>
#include "dialog.h"
#include "event.h"
#include "window.h"
#include "screen.h"
#include "util.h"
#include "case.h"
#include "overlap.h"
#include "shadow.h"
#ifdef DUAL
#include <os2.h>
extern WORD fProtectMode;
#else
#ifdef DOS5
#include <os2.h>
#endif
#endif
#include "menu.h"
#include "_menu.h"
#ifdef KANJI
PUBLIC BOOL fKanaAccel = FALSE; /* Kana accelerators ?? */
#endif /*KANJI*/
#define FShowMenuBar() (pmenubarCur != NULL)
STATIC PMENUBAR pmenubarCur; /* current menu bar being displayed */
STATIC ARC arcMenu;
STATIC PWND pwndMenu;
STATIC BYTE FAR *lpbMenu; /* where the screen image under menu is kept */
#ifdef ACCEL_MULTIPLE
BOOL fOneOfMultiple; /* => if one of multiple matching accelerators */
#endif /*ACCEL_MULTIPLE*/
#ifdef MULTIPLE_ACTION
WORD vkActionPrim = VK_MENU; /* Primary Action Key */
WORD vkActionSec = VK_F11; /* Secondary Action Key */
WORD vkCancelPrim = LOBYTE(VK_ESCAPE); /* Primary Cancel Key */
WORD vkCancelSec = VK_F12; /* Secondary Cancel Key */
#endif /* MULTIPLE_ACTION */
/* Menu Info : see note in MENU.H */
extern MNI mniCur;
/* PRIVATE MNI mniCur = { imenuNil, iitemNil, NULL, FALSE, FALSE, FALSE }; */
STATIC MENU *pmenuFound;
/* set by FindMenuItem to indicate which menu contains
the item that was found */
/* forward */
STATIC PMENUITEM PmenuitemOfPmenu(PMENU);
/* menus */
STATIC VOID SelectMenu(WORD);
STATIC VOID HiliteMenuTitle(BOOL);
STATIC VOID ReportMenuInactive(void);
STATIC VOID OpenMenuCur(void);
#ifdef DIALOG_NOSAVE
STATIC VOID DrawMenuCur(void);
#endif // DIALOG_NOSAVE
STATIC VOID CloseMenuCur(BOOL);
/* menu title selection */
STATIC VOID HiliteMenuMnem(BOOL);
STATIC BOOL FMakeSelection(void);
STATIC WORD ImenuPickVk(WORD);
STATIC WORD ImenuPickMsp(MSP);
/* menu items */
STATIC VOID DrawMenuItem(AX, AX, AY, PMENUITEM);
STATIC VOID HiliteItem(BOOL);
STATIC BOOL FSelectItem(WORD);
STATIC BOOL FMatchItemVk(WORD);
STATIC BOOL FSelectItemMsp(MSP);
STATIC BOOL FInsideMenuMsp(AX, AY);
/* filter */
STATIC VOID SetIdleState(void);
/* utilities */
STATIC BOOL FTranslateAccelerator(WORD, WORD);
STATIC BOOL FMatchVkCh(WORD, char);
STATIC char * SzItem(PMENUITEM);
STATIC VOID SendMenuHelp(WORD);
#ifdef MENU_NOSAVE
extern VOID FAR PASCAL ScreenRedraw(VOID);
#endif // MENU_NOSAVE
STATIC PMENUITEM
PmenuitemOfPmenu(pmenu)
/*
-- return address of first menu item in menu
*/
REGISTER PMENU pmenu;
{
return (pmenu->fHandle ? *(pmenu->u.prgmenuitem) : pmenu->u.rgmenuitem);
}
PUBLIC PMENUITEM FARPUBLIC
FindMenuItem(id)
WORD id;
/* FindMenuItem - Find specified menu item in tree */
{
StartPublic();
PMENU pmenu = pmenubarCur->rgmenu;
WORD cmenu = pmenubarCur->cmenu;
while (cmenu--)
{
REGISTER PMENUITEM pmenuitem = PmenuitemOfPmenu(pmenu);
REGISTER WORD citem = pmenu->citem;
while (citem--)
{
if (pmenuitem->idItem == id &&
!pmenuitem->fSeparator)
{
pmenuFound = pmenu;
ReturnPublic(pmenuitem, PMENUITEM);
}
pmenuitem++;
}
pmenu++;
}
ReturnPublic(NULL, PMENUITEM);
}
PUBLIC VOID FARPUBLIC
InitMenu(pwnd, pmenubar)
/*
-- initialize menu state
*/
REGISTER PWND pwnd;
PMENUBAR pmenubar;
{
StartPublic();
CloseMenuCur(TRUE);
ReportMenuInactive();
AssertSz(mniCur.imenu == imenuNil, "Init Menu while another menu still active");
mniCur.iitem = iitemNil;
mniCur.fMouse = FALSE;
pwndMenu = pwnd;
pmenubarCur = pmenubar;
FEnableMenuBar(pwnd != NULL);
DrawMenubar();
StopPublic();
}
PUBLIC VOID FARPUBLIC
DrawMenubar()
/*
-- Draw Menu Bar and optionally fill with MENU item strings
*/
{
StartPublic();
REGISTER PMENU pmenu;
REGISTER WORD imenu;
if (!FShowMenuBar())
return;
DrawThisWnd(NULL);
FillArc(axMenuMin, ayMenu, axMenuMac, ayMenu+1, ' ', isaMenu);
for (imenu = 0, pmenu = pmenubarCur->rgmenu;
imenu < pmenubarCur->cmenu;
imenu++, pmenu++)
{
WORD di = pmenu->fEnabled ? dmTextOnly :
DiNormal(isaDisabledMenuItem);
TextOutAbs(axMenuMin + pmenu->rxTitle, ayMenu,
pmenu->pchTitle, pmenu->cchTitle, di);
#ifdef KANJI
/* kana accelerator at start ? */
if (fKanaAccel)
CharOutAbs(axMenuMin + pmenu->rxTitle, ayMenu,
pmenu->chKanaAccel, di);
#endif
}
#ifdef DEBUG
/* special stuff if we want to redraw menubar while not idle,
i.e. for the HELLO application.
*/
if (FMenuActive())
HiliteMenuTitle(TRUE);
#endif /*DEBUG*/
StopPublic();
}
/*****************************************************************************/
STATIC VOID
SelectMenu(imenu)
/*
-- select the specified menu (may be imenuNil)
-- clears old menu title
-- modifies mniCur.imenu
*/
WORD imenu;
{
Assert(mniCur.pmenuOpen == NULL); /* no drop downs open */
/* if we don't have a menubar -- get one !! */
if (pmenubarCur == NULL)
{
SendMessageShort(pwndMenu, WM_MENUSTART);
AssertSz(pmenubarCur != NULL, "WM_MENUSTART error");
}
if (imenu != mniCur.imenu)
{
/* close old */
CloseMenuCur(TRUE); /* close current */
HiliteMenuTitle(FALSE); /* & clear title */
mniCur.imenu = imenu;
mniCur.iitem = iitemNil;
HiliteMenuTitle(TRUE); /* hilite new title */
}
}
STATIC VOID
HiliteMenuTitle(fHilite)
/*
-- hilite/unhilite the menu title "hilite" characters, for current menu
-- do nothing if no current menu
-- menu should not be open.
*/
BOOL fHilite; /* hilite ? */
{
REGISTER AX ax;
REGISTER PMENU pmenu;
AX axRight;
if (!FShowMenuBar() || mniCur.imenu == imenuNil)
return;
DrawThisWnd(NULL);
Assert(mniCur.imenu != imenuNil);
Assert(!FMenuOpen());
MoveHardwareCursor(0, 0, FALSE);
/* 1 character before & after */
pmenu = &pmenubarCur->rgmenu[mniCur.imenu];
ax = ((AX) pmenu->rxTitle) - daxBorder;
axRight = ax + pmenu->cchTitle + 2;
/* Pin hilite to edges of screen */
if (pmenu->rxTitle == 0)
ax = 0;
if (axRight > axMax)
axRight = axMax;
FillArc(ax, ayMenu, axRight, ayMenu + 1, '\0',
(fHilite) ? (dmAttrOnly | isaMenuSelected) :
((pmenu->fEnabled) ? (dmAttrOnly | isaMenu) :
(dmAttrOnly | isaDisabledMenuItem) ));
ax = ((AX) pmenu->rxTitle) + (BYTE) pmenu->ichHilite;
Assert(ax < axMax); /* Hilited character must be on screen */
/* only single width characters for accelerators */
if (mniCur.fMenuMnem)
FillArc(ax, ayMenu, ax + 1, ayMenu + 1, '\0',
(fHilite) ? (dmAttrOnly | isaMenuHiliteSel) :
(dmAttrOnly | isaMenuHilite));
if (fHilite)
SendMessage(pwndMenu, WM_MENUSELECT, pmenu->idMenu,
MAKELONG(pmenu, mmdMenu));
}
STATIC VOID
ReportMenuInactive()
/*
-- send a MENUSELECT message with NULL pmenuitem
-- normally application will clear the help line
*/
{
Assert(mmdItem == 0);
if (pwndMenu != NULL)
SendMessageShort(pwndMenu, WM_MENUSELECT);
}
STATIC VOID
OpenMenuCur()
/*
-- open current menu (mniCur.imenu)
-- all other menus must be closed
-- turn of mnemonics in menu titles
-- if imenuNil then do nothing
-- if items, select first one
*/
{
REGISTER PMENU pmenu;
AX axLeft, axRight;
#ifdef DIALOG_NOSAVE
AY ayBottom, ayTop;
#else
AY ay, ayBottom, ayTop;
WORD citem;
#endif
Assert(mniCur.pmenuOpen == NULL);
DrawThisWnd(NULL);
HiliteMenuMnem(FALSE);
if (mniCur.imenu == imenuNil)
return;
pmenu = mniCur.pmenuOpen = &pmenubarCur->rgmenu[mniCur.imenu];
SendMessage(pwndMenu, WM_INITMENUPOPUP, pmenu->idMenu,
MAKELONG(pmenu, 0)); /* Must not enter dialogs */
BeginDraw();
if (pmenu->citem)
{
#ifndef DIALOG_NOSAVE
REGISTER PMENUITEM pmenuitem;
#endif // DIALOG_NOSAVE
WORD cw;
arcMenu.axLeft = axLeft = (AX) pmenu->rxTitle + daxMenuBox;
/* to left side of box */
arcMenu.axRight = axRight = (AX) pmenu->rxTitle +
pmenu->cchitemMax + 2;
/* bord+gap+"text"+gap+bord */
/* adjust for too near screen borders */
if (axRight > axMac - daxShadow)
{
/* adjust for too large (too near right) */
arcMenu.axLeft = axLeft = axLeft - (axRight -
(axMac - daxShadow));
arcMenu.axRight = axRight = (axMac - daxShadow);
}
if (pmenu->rxTitle < -daxMenuBox)
{
/* adjust for too small (too near left) */
arcMenu.axRight = axRight - axLeft;
arcMenu.axLeft = 0;
}
arcMenu.ayTop = ayTop = ayMenu + 1;
/* 1 for menu title */
arcMenu.ayBottom = ayBottom = ayTop + pmenu->citem + 2;
/* 2 for top and bottom sides of menu box */
cw = (WORD) (ayBottom - ayTop + dayShadow) *
(WORD) (axRight - axLeft + daxShadow + daxDbcs * 2);
#ifdef SCREEN_FFONT
if (fFontAvailable)
cw *= 2;
#endif /*SCREEN_FFONT*/
#ifndef MENU_NOSAVE
SaveArc(axLeft - daxDbcs, ayTop, axRight + daxShadow + daxDbcs,
ayBottom + dayShadow,
lpbMenu = LpbAllocWorkFar(cw * 2));
#endif // MENU_NOSAVE
#ifdef DIALOG_NOSAVE
/* Hilite first item if not in mouse mode */
if (!mniCur.fMouse)
{
mniCur.iitem = 0;
}
DrawMenuCur();
#else // !DIALOG_NOSAVE
FillArc(axLeft, ayTop, axRight, ayBottom, ' ',
DiNormal(isaEnabledMenuItem));
DrawBoxArc(&boxSingle, &arcMenu, isaMenuBox,
TRUE, TRUE, NULL);
ShadowArc(&arcMenu);
pmenuitem = PmenuitemOfPmenu(pmenu);
citem = pmenu->citem;
ay = ayTop + 1;
while (citem--)
{
if (pmenuitem->fSeparator)
{
/* draw a separator */
FillArc(axLeft + daxBorder, ay,
axRight - daxBorder, ay + dayBorder,
(ACHAR) chTopSide1,
DiNormal(isaMenuBox));
CharOutAbs(axRight - daxBorder, ay,
(ACHAR) chMiddleRight1,
DiNormal(isaMenuBox));
CharOutAbs(axLeft, ay, (ACHAR) chMiddleLeft1,
DiNormal(isaMenuBox));
}
else
{
DrawMenuItem(axLeft, ay,
(AX) axRight - daxBorder, pmenuitem);
}
ay++;
pmenuitem++;
}
/* Hilite first item if not in mouse mode */
if (!mniCur.fMouse)
{
mniCur.iitem = 0;
HiliteItem(TRUE);
}
#endif // DIALOG_NOSAVE
}
else
{
/* no items => no mouse selection of items */
arcMenu.ayTop = 0;
arcMenu.ayBottom = 1;
mniCur.iitem = iitemNil;
}
EndDraw();
/* just to be sure */
Assert(pmenu == mniCur.pmenuOpen);
}
#ifdef DIALOG_NOSAVE
STATIC VOID
DrawMenuCur()
{
WORD citem;
REGISTER PMENUITEM pmenuitem;
AX axLeft = arcMenu.axLeft;
AX axRight = arcMenu.axRight;
AY ayTop = arcMenu.ayTop;
AY ayBottom = arcMenu.ayBottom;
AY ay;
if (mniCur.pmenuOpen == NULL)
{
HiliteMenuTitle(TRUE);
return;
}
FillArc(axLeft, ayTop, axRight, ayBottom, ' ',
DiNormal(isaEnabledMenuItem));
DrawBoxArc(&boxSingle, &arcMenu, isaMenuBox,
TRUE, TRUE, NULL);
ShadowArc(&arcMenu);
pmenuitem = PmenuitemOfPmenu(mniCur.pmenuOpen);
citem = mniCur.pmenuOpen->citem;
ay = ayTop + 1;
while (citem--)
{
if (pmenuitem->fSeparator)
{
/* draw a separator */
FillArc(axLeft + daxBorder, ay,
axRight - daxBorder, ay + dayBorder,
(ACHAR) chTopSide1,
DiNormal(isaMenuBox));
CharOutAbs(axRight - daxBorder, ay,
(ACHAR) chMiddleRight1,
DiNormal(isaMenuBox));
CharOutAbs(axLeft, ay, (ACHAR) chMiddleLeft1,
DiNormal(isaMenuBox));
}
else
{
DrawMenuItem(axLeft, ay,
(AX) axRight - daxBorder, pmenuitem);
}
ay++;
pmenuitem++;
}
HiliteItem(TRUE);
}
#endif // DIALOG_NOSAVE
STATIC VOID
CloseMenuCur(fMessage)
BOOL fMessage; /* send WM_COMMAND message? */
/*
-- close the body of current menu
-- can be called if menu not open (do nothing)
*/
{
if (mniCur.imenu == imenuNil || mniCur.pmenuOpen == NULL)
return; /* not open */
Assert(mniCur.pmenuOpen == &pmenubarCur->rgmenu[mniCur.imenu]);
#ifndef MENU_NOSAVE
DrawThisWnd(NULL);
if (mniCur.pmenuOpen->citem)
{
#ifdef KANJI
fRestoreDbcs = TRUE;
#endif /*KANJI*/
RestoreArc(arcMenu.axLeft - daxDbcs, arcMenu.ayTop,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -