mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1760 lines
55 KiB
1760 lines
55 KiB
/**************************** Module Header ********************************\
|
|
* Module Name: mndraw.c
|
|
*
|
|
* Copyright 1985-96, Microsoft Corporation
|
|
*
|
|
* Menu Painting Routines
|
|
*
|
|
* History:
|
|
* 10-10-90 JimA Cleanup.
|
|
* 03-18-91 IanJa Window revalidation added
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
#define CMS_QANIMATION 175
|
|
|
|
typedef struct tagMENUSINMOTION
|
|
{
|
|
PWND pwnd; // window being animated
|
|
DWORD dwTimeStart;// starting time of animation
|
|
int ix; // current x-step in animation
|
|
int iy; // current y-step in animation
|
|
int cx; // total x in animation
|
|
int cy; // total y in animation
|
|
int iDropDir; // direction of animation
|
|
} MENUSINMOTION;
|
|
|
|
MENUSINMOTION gmim; // global for menu animation
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
|
|
#define SRCSTENCIL 0x00B8074AL
|
|
|
|
typedef struct {
|
|
PMENU pMenu;
|
|
PITEM pItem;
|
|
} GRAYMENU;
|
|
typedef GRAYMENU *PGRAYMENU;
|
|
|
|
BOOL CALLBACK RealDrawMenuItem(
|
|
HDC hdc,
|
|
PGRAYMENU lpGray,
|
|
BOOL fUnused,
|
|
int cx,
|
|
int cy);
|
|
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// MNAnimate(fIterate)
|
|
//
|
|
// If fIterate is TRUE, then perform the next iteration in the menu animation
|
|
// sequence. If fIterate is FALSE, terminate the animation sequence.
|
|
//
|
|
// Returns TRUE if the animation was iterated or terminated; FALSE if there
|
|
// currently no animation.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
BOOL MNAnimate(BOOL fIterate)
|
|
{
|
|
HDC hdc;
|
|
HBITMAP hbmpOld;
|
|
DWORD dwTimeElapsed = NtGetTickCount() - gmim.dwTimeStart;
|
|
int x;
|
|
int y;
|
|
int xOff;
|
|
int yOff;
|
|
int xLast = gmim.ix;
|
|
int yLast = gmim.iy;
|
|
|
|
if (!gmim.pwnd)
|
|
return(FALSE);
|
|
|
|
if (!TestWF(gmim.pwnd, WFVISIBLE))
|
|
return(FALSE);
|
|
|
|
if (!fIterate || (dwTimeElapsed > CMS_QANIMATION))
|
|
{
|
|
if ((gmim.ix != gmim.cx) || (gmim.iy != gmim.cy))
|
|
{
|
|
hdc = _GetDCEx(gmim.pwnd, (HRGN)1, DCX_WINDOW | DCX_USESTYLE | DCX_INTERSECTRGN);
|
|
hbmpOld = GreSelectBitmap(ghdcBits2, ghbmSlide);
|
|
GreBitBlt(hdc, 0, 0, gmim.cx, gmim.cy, ghdcBits2, 0, 0, SRCCOPY, 0x00FFFFFF);
|
|
GreSelectBitmap(ghdcBits2, hbmpOld);
|
|
_ReleaseDC(hdc);
|
|
}
|
|
gmim.pwnd = NULL;
|
|
return(TRUE);
|
|
}
|
|
|
|
if (gmim.iDropDir & PAS_HORZ)
|
|
gmim.ix = MultDiv(gmim.cx, dwTimeElapsed, CMS_QANIMATION);
|
|
|
|
if (gmim.iDropDir & PAS_VERT)
|
|
gmim.iy = MultDiv(gmim.cy, dwTimeElapsed, CMS_QANIMATION);
|
|
|
|
if ((gmim.ix == xLast) && (gmim.iy == yLast))
|
|
// no change -- bail out
|
|
return(TRUE);
|
|
|
|
if (gmim.iDropDir & PAS_LEFT) {
|
|
x = gmim.cx - gmim.ix;
|
|
xOff = 0;
|
|
} else {
|
|
xOff = gmim.cx - gmim.ix;
|
|
x = 0;
|
|
}
|
|
|
|
if (gmim.iDropDir & PAS_UP) {
|
|
y = gmim.cy - gmim.iy;
|
|
yOff = 0;
|
|
} else {
|
|
yOff = gmim.cy - gmim.iy;
|
|
y = 0;
|
|
}
|
|
|
|
hdc = _GetDCEx(gmim.pwnd, (HRGN)1, DCX_WINDOW | DCX_USESTYLE | DCX_INTERSECTRGN);
|
|
hbmpOld = GreSelectBitmap(ghdcBits2, ghbmSlide);
|
|
GreBitBlt(hdc, x, y, gmim.ix, gmim.iy, ghdcBits2, xOff, yOff, SRCCOPY, 0x00FFFFFF);
|
|
GreSelectBitmap(ghdcBits2, hbmpOld);
|
|
_ReleaseDC(hdc);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// xxxMNInitAnimation(hwnd, ppopup)
|
|
//
|
|
// Initialize the animation sequence for the given window and menu. If
|
|
// another animation sequence is already in progress, it is terminated so that
|
|
// this animation can proceed.
|
|
//
|
|
// Returns TRUE if the animation sequence has been successfully initiated;
|
|
// FALSE if not (i.e. menu is too wide for animation bitmap).
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
BOOL xxxMNInitAnimation(PWND pwnd, PPOPUPMENU ppopup)
|
|
{
|
|
HBITMAP hbmpOld;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
if ((pwnd->rcWindow.right - pwnd->rcWindow.left) > MAX_ANIMATE_WIDTH)
|
|
// too large for off-screen bitmap -- bail
|
|
return(FALSE);
|
|
|
|
MNAnimate(FALSE); // terminate any animation
|
|
|
|
gmim.pwnd = pwnd;
|
|
gmim.iDropDir = ppopup->iDropDir;
|
|
|
|
gmim.dwTimeStart = NtGetTickCount();
|
|
|
|
gmim.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
|
|
gmim.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
|
|
|
|
gmim.ix = (gmim.iDropDir & PAS_HORZ) ? 0 : gmim.cx;
|
|
gmim.iy = (gmim.iDropDir & PAS_VERT) ? 0 : gmim.cy;
|
|
|
|
// BUGBUG -- we will need to use a different hdc here since DrawState does
|
|
// a blt from hdcBits2 into the supplied hdc (which would also be hdcBits2)
|
|
hbmpOld = GreSelectBitmap(ghdcBits2, ghbmSlide);
|
|
xxxSendMessage(pwnd, WM_PRINT, (WPARAM) ghdcBits2, PRF_CLIENT | PRF_NONCLIENT | PRF_ERASEBKGND);
|
|
GreSelectBitmap(ghdcBits2, hbmpOld);
|
|
}
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
|
|
|
|
/***************************************************************************\
|
|
* DrawMenuItemCheckMark() -
|
|
*
|
|
* Draws the proper check mark for the given item. Note that ownerdraw
|
|
* items should NOT be passed to this procedure, otherwise we'd draw a
|
|
* checkmark for them when they are already going to take care of it.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
void DrawMenuItemCheckMark(HDC hdc, PITEM pItem)
|
|
{
|
|
int yCenter;
|
|
HBITMAP hbm;
|
|
DWORD textColorSave;
|
|
DWORD bkColorSave;
|
|
BOOL fChecked;
|
|
POEMBITMAPINFO pOem;
|
|
|
|
UserAssert(hdc != ghdcMem2);
|
|
|
|
pOem = oemInfo.bm + OBI_MENUCHECK;
|
|
yCenter = pItem->cyItem - pOem->cy;
|
|
if (yCenter < 0)
|
|
yCenter = 0;
|
|
yCenter /= 2;
|
|
|
|
fChecked = TestMFS(pItem, MFS_CHECKED);
|
|
|
|
if (hbm = (fChecked) ? pItem->hbmpChecked : pItem->hbmpUnchecked) {
|
|
HBITMAP hbmSave;
|
|
|
|
// Use the app supplied bitmaps.
|
|
if (hbmSave = GreSelectBitmap(ghdcMem2, hbm)) {
|
|
textColorSave = GreSetTextColor(hdc, 0x00000000L);
|
|
bkColorSave = GreSetBkColor (hdc, 0x00FFFFFFL);
|
|
|
|
GreBitBlt(hdc,
|
|
0,
|
|
yCenter,
|
|
pOem->cx,
|
|
pOem->cy,
|
|
ghdcMem2,
|
|
0,
|
|
0,
|
|
SRCSTENCIL,
|
|
0x00FFFFFF);
|
|
|
|
GreSetTextColor(hdc, textColorSave);
|
|
GreSetBkColor(hdc, bkColorSave);
|
|
|
|
GreSelectBitmap(ghdcMem2, hbmSave);
|
|
}
|
|
|
|
} else if (fChecked) {
|
|
|
|
if (TestMFT(pItem, MFT_RADIOCHECK))
|
|
pOem = oemInfo.bm + OBI_MENUBULLET;
|
|
|
|
BltColor(hdc,
|
|
NULL,
|
|
gpDispInfo->hdcBits,
|
|
0,
|
|
yCenter,
|
|
pOem->cx,
|
|
pOem->cy,
|
|
pOem->x,
|
|
pOem->y,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* DrawMenuItemText()
|
|
*
|
|
* Draws menu text with underline.
|
|
*
|
|
\***************************************************************************/
|
|
void DrawMenuItemText(PITEM pItem, HDC hdc, int xLeft, int yTop,
|
|
LPWSTR lpsz, int cch)
|
|
{
|
|
int cx;
|
|
LONG result;
|
|
WCHAR szMenu[255];
|
|
|
|
//
|
|
// Put the string on the stack and find where the underline starts.
|
|
//
|
|
result = GetPrefixCount(lpsz, cch, szMenu, 255);
|
|
GreExtTextOutW(hdc, xLeft, yTop, 0, NULL, szMenu, cch - HIWORD(result), NULL);
|
|
|
|
//
|
|
// LOWORD of result is 0xFFFF if there is no underlined character.
|
|
// Therefore ulX must be valid or be UNDERLINE_RECALC because the item
|
|
// or menu mode changed.
|
|
//
|
|
// Bail out if there isn't one.
|
|
//
|
|
if (LOWORD(result) == 0xFFFF)
|
|
return;
|
|
|
|
// For proportional fonts, find starting point of underline.
|
|
if (pItem->ulX == UNDERLINE_RECALC) {
|
|
if (LOWORD(result) != 0) {
|
|
SIZE size;
|
|
|
|
GreGetTextExtentW(hdc, szMenu, (DWORD)LOWORD(result), &size, GGTE_WIN3_EXTENT);
|
|
pItem->ulX = size.cx - cxMenuFontOverhang;
|
|
} else
|
|
pItem->ulX = 0;
|
|
}
|
|
|
|
xLeft += pItem->ulX;
|
|
|
|
//
|
|
// Adjust for proportional font when setting the length of the underline
|
|
// and height of text.
|
|
//
|
|
// Calculate underline width.
|
|
if (!pItem->ulWidth) {
|
|
SIZE size;
|
|
|
|
GreGetTextExtentW(hdc, (LPWSTR)&(szMenu[LOWORD(result)]), 1, &size, GGTE_WIN3_EXTENT);
|
|
pItem->ulWidth = size.cx - cxMenuFontOverhang;
|
|
}
|
|
cx = pItem->ulWidth;
|
|
|
|
// Get ascent of text (units above baseline) so that underline can be drawn
|
|
// below the text
|
|
yTop += cyMenuFontAscent;
|
|
|
|
// Proper brush should be selected into dc.
|
|
// if (fShowUnderlines)
|
|
GrePatBlt(hdc, xLeft, yTop, cx, SYSMET(CYBORDER), PATCOPY);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSendMenuDrawItemMessage
|
|
*
|
|
* Sends a WM_DRAWITEM message to the owner of the menu (pMenuState->hwndMenu).
|
|
* All state is determined in this routine so HILITE state must be properly
|
|
* set before entering this routine..
|
|
*
|
|
* Revalidation notes:
|
|
* This routine must be called with a valid and non-NULL pwnd.
|
|
* Revalidation is not required in this routine: no windows are used after
|
|
* potentially leaving the critsect.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void xxxSendMenuDrawItemMessage(
|
|
HDC hdc,
|
|
UINT itemAction,
|
|
PMENU pmenu,
|
|
#ifndef MEMPHIS_MENUS
|
|
PITEM pItem)
|
|
#else // MEMPHIS_MENUS
|
|
PITEM pItem,
|
|
BOOL fBitmap,
|
|
int iOffset)
|
|
#endif // MEMPHIS_MENUS
|
|
{
|
|
DRAWITEMSTRUCT dis;
|
|
TL tlpwndNotify;
|
|
#ifdef MEMPHIS_MENUS
|
|
int y;
|
|
#endif // MEMPHIS_MENUS
|
|
|
|
CheckLock(pmenu);
|
|
|
|
dis.CtlType = ODT_MENU;
|
|
dis.CtlID = 0;
|
|
|
|
dis.itemID = pItem->wID;
|
|
|
|
dis.itemAction = itemAction;
|
|
dis.itemState =
|
|
((pItem->fState & MF_GRAYED) ? ODS_GRAYED : 0) |
|
|
((pItem->fState & MFS_DEFAULT) ? ODS_DEFAULT : 0) |
|
|
((pItem->fState & MFS_CHECKED) ? ODS_CHECKED : 0) |
|
|
((pItem->fState & MFS_DISABLED) ? ODS_DISABLED : 0) |
|
|
((pItem->fState & MFS_HILITE) ? ODS_SELECTED : 0);
|
|
dis.hwndItem = (HWND)PtoH(pmenu);
|
|
dis.hDC = hdc;
|
|
|
|
#ifdef MEMPHIS_MENUS
|
|
y = pItem->yItem;
|
|
if (fBitmap)
|
|
y = (pItem->cyItem - pItem->cyBmp) / 2;
|
|
|
|
dis.rcItem.left = iOffset + pItem->xItem;
|
|
dis.rcItem.top = y;
|
|
dis.rcItem.right = iOffset + pItem->xItem + (fBitmap ? pItem->cxBmp : pItem->cxItem);
|
|
dis.rcItem.bottom = y + (fBitmap ? pItem->cyBmp : pItem->cyItem);
|
|
#else // MEMPHIS_MENUS
|
|
dis.rcItem.left = pItem->xItem;
|
|
dis.rcItem.top = pItem->yItem;
|
|
dis.rcItem.right = pItem->xItem + pItem->cxItem;
|
|
dis.rcItem.bottom = pItem->yItem + pItem->cyItem;
|
|
#endif // MEMPHIS_MENUS
|
|
dis.itemData = pItem->dwItemData;
|
|
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
if (hdc == ghdcBits2) {
|
|
if (!GreSetDCOwner(hdc, OBJECT_OWNER_CURRENT)) {
|
|
RIPMSG1(RIP_WARNING, "SendMenuDrawItemMesssage: SetDCOwner Failed %lX", hdc);
|
|
return;
|
|
}
|
|
}
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
if (pmenu->spwndNotify != NULL) {
|
|
ThreadLockAlways(pmenu->spwndNotify, &tlpwndNotify);
|
|
xxxSendMessage(pmenu->spwndNotify, WM_DRAWITEM, 0, (LONG)&dis);
|
|
ThreadUnlock(&tlpwndNotify);
|
|
}
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
if (hdc == ghdcBits2) {
|
|
if (!GreSetDCOwner(hdc, OBJECT_OWNER_PUBLIC)) {
|
|
RIPMSG1(RIP_WARNING, "SendMenuDrawItemMesssage: SetDCOwner Failed %lX", hdc);
|
|
return;
|
|
}
|
|
}
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxDrawMenuItem
|
|
*
|
|
* !
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void xxxDrawMenuItem(
|
|
HDC hdc,
|
|
PMENU pMenu,
|
|
PITEM pItem,
|
|
BOOL fInvert) /* True if we are being called by xxxMenuInvert */
|
|
{
|
|
HFONT hfnOld;
|
|
int tcExtra;
|
|
UINT uFlags;
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
int iBkSave;
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
|
|
hfnOld = NULL;
|
|
uFlags = DST_COMPLEX;
|
|
|
|
|
|
CheckLock(pMenu);
|
|
|
|
if (TestMFS(pItem, MFS_DEFAULT))
|
|
{
|
|
if (ghMenuFontDef != NULL)
|
|
hfnOld = GreSelectFont(hdc, ghMenuFontDef);
|
|
else
|
|
{
|
|
uFlags |= DSS_DEFAULT;
|
|
tcExtra = GreGetTextCharacterExtra(hdc);
|
|
GreSetTextCharacterExtra(hdc, tcExtra + 1 + (cxMenuFontChar / gpsi->cxSysFontChar));
|
|
}
|
|
}
|
|
|
|
if (TestMFT(pItem, MFT_OWNERDRAW)) {
|
|
|
|
/*
|
|
* If ownerdraw, just set the default menu colors since the app is
|
|
* responsible for handling the rest.
|
|
*/
|
|
GreSetTextColor(hdc, SYSRGB(MENUTEXT));
|
|
GreSetBkColor(hdc, SYSRGB(MENU));
|
|
|
|
/*
|
|
* Send drawitem message since this is an ownerdraw item.
|
|
*/
|
|
#ifdef MEMPHIS_MENUS
|
|
xxxSendMenuDrawItemMessage(hdc,
|
|
(UINT)(fInvert ? ODA_SELECT : ODA_DRAWENTIRE),
|
|
pMenu, pItem,FALSE,0);
|
|
#else // MEMPHIS_MENUS
|
|
xxxSendMenuDrawItemMessage(hdc,
|
|
(UINT)(fInvert ? ODA_SELECT : ODA_DRAWENTIRE),
|
|
pMenu, pItem);
|
|
#endif // MEMPHIS_MENUS
|
|
// Draw the hierarchical arrow for the cascade menu.
|
|
if (TestMF(pMenu, MFISPOPUP) && (pItem->spSubMenu != NULL))
|
|
{
|
|
POEMBITMAPINFO pOem = oemInfo.bm + OBI_MENUARROW;
|
|
HBRUSH hbr = (TestMFS(pItem, MFS_HILITE)) ? SYSHBR(HIGHLIGHTTEXT) : SYSHBR(MENUTEXT);
|
|
|
|
// This item has a hierarchical popup associated with it. Draw the
|
|
// bitmap dealy to signify its presence. Note we check if fPopup is set
|
|
// so that this isn't drawn for toplevel menus that have popups.
|
|
BltColor(hdc,
|
|
hbr,
|
|
gpDispInfo->hdcBits,
|
|
pItem->xItem + pItem->cxItem - pOem->cx,
|
|
pItem->yItem + max((pItem->cyItem - 2 - pOem->cy) / 2,
|
|
0),
|
|
pOem->cx,
|
|
pOem->cy,
|
|
pOem->x,
|
|
pOem->y,
|
|
TRUE);
|
|
}
|
|
} else {
|
|
int icolBack;
|
|
int icolFore;
|
|
GRAYMENU gm;
|
|
|
|
//
|
|
// Setup colors and state
|
|
//
|
|
if (TestMFS(pItem, MFS_HILITE)) {
|
|
icolBack = COLOR_HIGHLIGHT;
|
|
icolFore = COLOR_HIGHLIGHTTEXT;
|
|
} else {
|
|
icolBack = COLOR_MENU;
|
|
icolFore = COLOR_MENUTEXT;
|
|
}
|
|
|
|
// B#4157 - Lotus doesn't like it if we draw
|
|
// its disabled menu items in GRAY, t-arthb
|
|
// MAKE SURE MF_GRAYED stays 0x0001 NOT 0x0003 for this to fix
|
|
|
|
if (TestMFS(pItem, MF_GRAYED)) {
|
|
//
|
|
// Only do embossing if menu color is same as 3D color. The
|
|
// emboss uses 3D hilight & 3D shadow, which doesn't look cool
|
|
// on a different background.
|
|
//
|
|
if ((icolBack == COLOR_HIGHLIGHT) ||
|
|
(SYSRGB(MENU) != SYSRGB(3DFACE)) || SYSMET(SLOWMACHINE)) {
|
|
//
|
|
// If gray text won't show up on background, then dither.
|
|
//
|
|
if (SYSRGB(GRAYTEXT) == gpsi->argbSystem[icolBack])
|
|
uFlags |= DSS_UNION;
|
|
else
|
|
icolFore = COLOR_GRAYTEXT;
|
|
} else
|
|
{
|
|
if ((SYSRGB(3DSHADOW) == SYSRGB(MENU)) && (SYSRGB(3DHILIGHT) == SYSRGB(MENU)))
|
|
uFlags |= DSS_UNION;
|
|
else
|
|
uFlags |= DSS_DISABLED;
|
|
}
|
|
}
|
|
|
|
GreSetBkColor(hdc, gpsi->argbSystem[icolBack]);
|
|
GreSetTextColor(hdc, gpsi->argbSystem[icolFore]);
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
if ((fInvert && !pMenu->hbrBack) || TestMFS(pItem, MFS_HILITE)) {
|
|
#else // MEMPHIS_MENU_WATERMARKS
|
|
if (!TestMFT(pItem, MFT_BITMAP) && (fInvert || TestMFS(pItem, MFS_HILITE))) {
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
|
|
POLYPATBLT PolyData;
|
|
|
|
//
|
|
// Only fill the background if we're being called on behalf of
|
|
// MNInvertItem. This is so that we don't waste time filling
|
|
// the unselected rect when the menu is first pulled down.
|
|
//
|
|
|
|
PolyData.x = pItem->xItem;
|
|
PolyData.y = pItem->yItem;
|
|
PolyData.cx = pItem->cxItem;
|
|
PolyData.cy = pItem->cyItem;
|
|
PolyData.BrClr.hbr = ahbrSystem[icolBack];
|
|
|
|
GrePolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
|
|
|
|
//GreSelectBrush(hdc, ahbrSystem[icolBack]);
|
|
//GrePatBlt(hdc, pItem->xItem, pItem->yItem, pItem->cxItem,
|
|
// pItem->cyItem, PATCOPY);
|
|
|
|
|
|
|
|
}
|
|
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
if (pMenu->hbrBack)
|
|
iBkSave = GreSetBkMode(hdc, TRANSPARENT);
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
GreSelectBrush(hdc, ahbrSystem[icolFore]);
|
|
|
|
//
|
|
// Draw the image
|
|
//
|
|
gm.pItem = pItem;
|
|
gm.pMenu = pMenu;
|
|
|
|
_DrawState(hdc,
|
|
ahbrSystem[icolFore],
|
|
(DRAWSTATEPROC)RealDrawMenuItem,
|
|
(LPARAM)(PGRAYMENU)&gm,
|
|
TRUE,
|
|
pItem->xItem,
|
|
pItem->yItem,
|
|
pItem->cxItem,
|
|
pItem->cyItem,
|
|
uFlags);
|
|
}
|
|
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
if (pMenu->hbrBack)
|
|
GreSetBkMode(hdc, iBkSave);
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
|
|
if (TestMFS(pItem, MFS_DEFAULT))
|
|
{
|
|
if (hfnOld)
|
|
GreSelectFont(hdc, hfnOld);
|
|
else
|
|
GreSetTextCharacterExtra(hdc, tcExtra);
|
|
}
|
|
}
|
|
|
|
extern void SetupFakeMDIAppStuff(PMENU lpMenu, PITEM lpItem);
|
|
|
|
#ifndef MEMPHIS_MENUS
|
|
/***************************************************************************\
|
|
*
|
|
* RealDrawMenuItem()
|
|
*
|
|
* Callback from DrawState() to draw the menu item, either normally or into
|
|
* an offscreen bitmp. We don't know where we're drawing, and shouldn't
|
|
* have to.
|
|
*
|
|
\***************************************************************************/
|
|
BOOL CALLBACK RealDrawMenuItem(
|
|
HDC hdc,
|
|
PGRAYMENU pGray,
|
|
BOOL fUnused,
|
|
int cx,
|
|
int cy)
|
|
{
|
|
PMENU pMenu;
|
|
PITEM pItem;
|
|
BOOL fPopup;
|
|
int cch;
|
|
int xLeft;
|
|
int yTop;
|
|
int tp;
|
|
int rp;
|
|
LPWSTR lpsz;
|
|
int cyTemp;
|
|
TL tlpwndChild;
|
|
|
|
//
|
|
// BOGUS
|
|
// Use cx and cy instead of lpItem->cxItem, lpItem->cyItem to
|
|
// speed stuff up.
|
|
//
|
|
pMenu = pGray->pMenu;
|
|
pItem = pGray->pItem;
|
|
fPopup = TestMF(pMenu, MFISPOPUP);
|
|
|
|
if (fPopup) {
|
|
// Draw the checkmark
|
|
DrawMenuItemCheckMark(hdc, pItem);
|
|
xLeft = oemInfo.bm[OBI_MENUCHECK].cx;
|
|
} else
|
|
xLeft = 0;
|
|
|
|
if (TestMFT(pItem, MFT_BITMAP)) {
|
|
// The item is a bitmap so just blt it on the screen.
|
|
UINT wBmp = (UINT)(pItem->hTypeData);
|
|
|
|
switch (wBmp) {
|
|
case MENUHBM_SYSTEM:
|
|
{
|
|
PWND pwndChild;
|
|
PICON pIcon = NULL;
|
|
|
|
AintNothingLikeTheRealMDIThing:
|
|
if (!(pItem->dwItemData))
|
|
SetupFakeMDIAppStuff(pMenu, pItem);
|
|
|
|
pwndChild = HMValidateHandleNoRip((HWND)(pItem->dwItemData),TYPE_WINDOW);
|
|
if (!pwndChild)
|
|
{
|
|
//
|
|
// Oops, child window isn't valid anymore. Go find
|
|
// the new one.
|
|
//
|
|
if (pItem->dwItemData)
|
|
{
|
|
pItem->dwItemData = 0;
|
|
goto AintNothingLikeTheRealMDIThing;
|
|
}
|
|
|
|
pIcon = NULL;
|
|
}
|
|
else {
|
|
ThreadLock(pwndChild, &tlpwndChild);
|
|
pIcon = xxxGetWindowSmIcon(pwndChild, FALSE);
|
|
ThreadUnlock(&tlpwndChild);
|
|
}
|
|
|
|
|
|
if (!pIcon)
|
|
pIcon = SYSICO(WINLOGO);
|
|
|
|
_DrawIconEx(hdc, xLeft + (SYSMET(CXEDGE) * 2),
|
|
SYSMET(CYBORDER), pIcon, cx - (SYSMET(CXEDGE) * 2),
|
|
cy - SYSMET(CYEDGE), 0, SYSHBR(MENU), DI_NORMAL);
|
|
break;
|
|
}
|
|
|
|
|
|
case MENUHBM_RESTORE:
|
|
wBmp = OBI_RESTORE_MBAR;
|
|
goto DrawSysBmp;
|
|
|
|
case MENUHBM_CLOSE:
|
|
wBmp = OBI_CLOSE_MBAR;
|
|
goto DrawSysBmp;
|
|
|
|
case MENUHBM_CLOSE_D:
|
|
wBmp = OBI_CLOSE_MBAR_I;
|
|
goto DrawSysBmp2;
|
|
|
|
case MENUHBM_MINIMIZE_D:
|
|
wBmp = OBI_REDUCE_MBAR_I;
|
|
xLeft += SYSMET(CXEDGE);
|
|
goto DrawSysBmp2;
|
|
|
|
case MENUHBM_MINIMIZE:
|
|
wBmp = OBI_REDUCE_MBAR;
|
|
xLeft += SYSMET(CXEDGE);
|
|
DrawSysBmp:
|
|
// This is an internal bitmap; use depressed image
|
|
|
|
if (TestMFS(pItem, MFS_HILITE))
|
|
wBmp += DOBI_PUSHED;
|
|
DrawSysBmp2:
|
|
BitBltSysBmp(hdc, xLeft, SYSMET(CYEDGE), wBmp);
|
|
break;
|
|
|
|
default:
|
|
{
|
|
int dx, dy;
|
|
HBITMAP hbmSave;
|
|
BITMAP bmp;
|
|
|
|
//
|
|
// Is this the zero'th item in a menu bar that's not all
|
|
// bitmaps? Hmm, sounds like it could be a fake MDI dude.
|
|
// If it is, use the windows icon instead
|
|
//
|
|
if (pItem->dwItemData)
|
|
goto AintNothingLikeTheRealMDIThing;
|
|
else if (!fPopup &&
|
|
(pItem == pMenu->rgItems) &&
|
|
(pMenu->cItems > 1) &&
|
|
!(pMenu->rgItems[1].fType & MFT_BITMAP) &&
|
|
(pItem->spSubMenu)) {
|
|
RIPMSG0(RIP_WARNING, "Fake MDI detected, using window icon in place of bitmap");
|
|
goto AintNothingLikeTheRealMDIThing;
|
|
}
|
|
|
|
UserAssert(hdc != ghdcMem2);
|
|
|
|
if (GreExtGetObjectW(pItem->hTypeData, sizeof(bmp), (LPSTR)&bmp)) {
|
|
dx = bmp.bmWidth;
|
|
|
|
if (fPopup) {
|
|
dy = bmp.bmHeight;
|
|
|
|
//
|
|
// Center bitmap in middle of item area
|
|
//
|
|
cyTemp = (pItem->cyItem - dy);
|
|
if (cyTemp > 0)
|
|
cyTemp = cyTemp / 2;
|
|
else
|
|
cyTemp = 0;
|
|
} else {
|
|
dy = max(bmp.bmHeight, SYSMET(CYMENUSIZE));
|
|
cyTemp = 0;
|
|
}
|
|
|
|
if (hbmSave = GreSelectBitmap(ghdcMem2, (HBITMAP)wBmp)) {
|
|
//
|
|
// Draw the bitmap leaving some room on the left for the
|
|
// optional check mark if we are in a popup menu. (as opposed
|
|
// to a top level menu bar).
|
|
//
|
|
// We can do cool stuff with monochrome bitmap itmes
|
|
// by merging with the current colors.
|
|
//
|
|
// If the item is selected and the bitmap isn't monochrome,
|
|
// we just invert the thing when we draw it. We can't do
|
|
// anything more clever unless we want to convert to
|
|
// monochrome.
|
|
//
|
|
|
|
GreBitBlt(hdc, xLeft, cyTemp, dx, dy, ghdcMem2, 0, 0,
|
|
(bmp.bmPlanes * bmp.bmBitsPixel == 1) ?
|
|
SRCSTENCIL :
|
|
(TestMFS(pItem, MFS_HILITE) ? NOTSRCCOPY : SRCCOPY),
|
|
0x00FFFFFF);
|
|
|
|
GreSelectBitmap(ghdcMem2, hbmSave);
|
|
}
|
|
} else {
|
|
RIPMSG3(RIP_WARNING, "Menu 0x%08X, item 0x%08X: Tried to draw invalid bitmap 0x%08X", pMenu, pItem, pItem->hTypeData) ;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
// This item is a text string item. Display it.
|
|
yTop = cyMenuFontExternLeading;
|
|
|
|
cyTemp = pItem->cyItem - (cyMenuFontChar + cyMenuFontExternLeading + SYSMET(CYBORDER));
|
|
if (cyTemp > 0)
|
|
yTop += (cyTemp / 2);
|
|
|
|
if (!fPopup)
|
|
xLeft += cxMenuFontChar;
|
|
|
|
lpsz = TextPointer(pItem->hTypeData);
|
|
if (lpsz!=NULL) {
|
|
cch = pItem->cch;
|
|
|
|
// Even though we no longer support any funky handling of the
|
|
// help prefix character, we still need to eat it up if we run
|
|
// across it so that the menu item is drawn correctly
|
|
if ((*lpsz == CH_HELPPREFIX) && !fPopup) {
|
|
// Skip help prefix character.
|
|
lpsz++;
|
|
cch--;
|
|
}
|
|
|
|
// tp will contain the character position of the \t indicator
|
|
// in the menu string. This is where we add a tab to the string.
|
|
//
|
|
// rp will contain the character position of the \a indicator
|
|
// in the string. All text following this is right aligned.
|
|
tp = FindCharPosition(lpsz, TEXT('\t'));
|
|
rp = FindCharPosition(lpsz, TEXT('\t') - 1);
|
|
|
|
if (rp && (rp != cch)) {
|
|
// Display all the text up to the \a
|
|
DrawMenuItemText(pItem, hdc, xLeft, yTop, lpsz, rp);
|
|
|
|
// Do we also have a tab beyond the \a ??
|
|
if (tp > rp + 1) {
|
|
SIZE extent;
|
|
|
|
PSMGetTextExtent(hdc, lpsz + rp + 1,
|
|
(UINT)(tp - rp - 1), &extent);
|
|
GreExtTextOutW(hdc, (int)(pItem->dxTab - extent.cx), (int)yTop, 0,
|
|
NULL, lpsz + rp + 1, (UINT)(tp - rp - 1), NULL);
|
|
}
|
|
} else if (tp && rp == cch)
|
|
// Display text up to the tab position
|
|
DrawMenuItemText(pItem, hdc, xLeft, yTop, lpsz, tp);
|
|
|
|
// Any text left to display (like after the tab) ??
|
|
if (tp < cch - 1)
|
|
GreExtTextOutW(hdc, (int)(pItem->dxTab + cxMenuFontChar), (int)yTop, 0,
|
|
NULL, lpsz + tp + 1, (INT)(cch - tp - 1), NULL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw the hierarchical arrow for the cascade menu.
|
|
//
|
|
if (fPopup && (pItem->spSubMenu != NULL)) {
|
|
POEMBITMAPINFO pOem = oemInfo.bm + OBI_MENUARROW;
|
|
|
|
// This item has a hierarchical popup associated with it. Draw the
|
|
// bitmap dealy to signify its presence. Note we check if fPopup is set
|
|
// so that this isn't drawn for toplevel menus that have popups.
|
|
|
|
BltColor(hdc,
|
|
NULL,
|
|
gpDispInfo->hdcBits,
|
|
pItem->cxItem - pOem->cx,
|
|
max((pItem->cyItem - 2 - pOem->cy) / 2, 0),
|
|
pOem->cx,
|
|
pOem->cy,
|
|
pOem->x,
|
|
pOem->y,
|
|
TRUE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
#else // MEMPHIS_MENUS
|
|
BOOL CALLBACK RealDrawMenuItem(
|
|
HDC hdc,
|
|
PGRAYMENU pGray,
|
|
BOOL fUnused,
|
|
int cx,
|
|
int cy)
|
|
{
|
|
PMENU pMenu;
|
|
PITEM pItem;
|
|
BOOL fPopup;
|
|
int cch;
|
|
int xLeft;
|
|
int yTop;
|
|
int tp;
|
|
int rp;
|
|
LPWSTR lpsz;
|
|
int cyTemp;
|
|
TL tlpwndChild;
|
|
|
|
//
|
|
// BOGUS
|
|
// Use cx and cy instead of lpItem->cxItem, lpItem->cyItem to
|
|
// speed stuff up.
|
|
//
|
|
pMenu = pGray->pMenu;
|
|
pItem = pGray->pItem;
|
|
fPopup = TestMF(pMenu, MFISPOPUP);
|
|
|
|
if (fPopup) {
|
|
// Draw the checkmark
|
|
DrawMenuItemCheckMark(hdc, pItem);
|
|
xLeft = oemInfo.bm[OBI_MENUCHECK].cx;
|
|
} else
|
|
xLeft = 0;
|
|
|
|
if (pItem->hbmp) {
|
|
// The item is a bitmap so just blt it on the screen.
|
|
UINT wBmp = (UINT)(pItem->hbmp);
|
|
|
|
switch (wBmp) {
|
|
case MENUHBM_SYSTEM:
|
|
{
|
|
PWND pwndChild;
|
|
PICON pIcon = NULL;
|
|
|
|
AintNothingLikeTheRealMDIThing:
|
|
if (!(pItem->dwItemData))
|
|
SetupFakeMDIAppStuff(pMenu, pItem);
|
|
|
|
pwndChild = HMValidateHandleNoRip((HWND)(pItem->dwItemData),TYPE_WINDOW);
|
|
if (!pwndChild)
|
|
{
|
|
//
|
|
// Oops, child window isn't valid anymore. Go find
|
|
// the new one.
|
|
//
|
|
if (pItem->dwItemData)
|
|
{
|
|
pItem->dwItemData = 0;
|
|
goto AintNothingLikeTheRealMDIThing;
|
|
}
|
|
|
|
pIcon = NULL;
|
|
}
|
|
else {
|
|
ThreadLock(pwndChild, &tlpwndChild);
|
|
pIcon = xxxGetWindowSmIcon(pwndChild, FALSE);
|
|
ThreadUnlock(&tlpwndChild);
|
|
}
|
|
|
|
|
|
if (!pIcon)
|
|
pIcon = SYSICO(WINLOGO);
|
|
|
|
_DrawIconEx(hdc, xLeft + (SYSMET(CXEDGE) * 2),
|
|
SYSMET(CYBORDER), pIcon, cx - (SYSMET(CXEDGE) * 2),
|
|
cy - SYSMET(CYEDGE), 0, SYSHBR(MENU), DI_NORMAL);
|
|
break;
|
|
}
|
|
|
|
|
|
case MENUHBM_RESTORE:
|
|
wBmp = OBI_RESTORE_MBAR;
|
|
goto DrawSysBmp;
|
|
|
|
case MENUHBM_CLOSE:
|
|
wBmp = OBI_CLOSE_MBAR;
|
|
goto DrawSysBmp;
|
|
|
|
case MENUHBM_CLOSE_D:
|
|
wBmp = OBI_CLOSE_MBAR_I;
|
|
goto DrawSysBmp2;
|
|
|
|
case MENUHBM_MINIMIZE_D:
|
|
wBmp = OBI_REDUCE_MBAR_I;
|
|
xLeft += SYSMET(CXEDGE);
|
|
goto DrawSysBmp2;
|
|
|
|
case MENUHBM_MINIMIZE:
|
|
wBmp = OBI_REDUCE_MBAR;
|
|
xLeft += SYSMET(CXEDGE);
|
|
DrawSysBmp:
|
|
// This is an internal bitmap; use depressed image
|
|
|
|
if (TestMFS(pItem, MFS_HILITE))
|
|
wBmp += DOBI_PUSHED;
|
|
DrawSysBmp2:
|
|
BitBltSysBmp(hdc, xLeft, SYSMET(CYEDGE), wBmp);
|
|
break;
|
|
|
|
case MENUHBM_CALLBACK: {
|
|
TL tlpmenu;
|
|
|
|
ThreadLock(pMenu, &tlpmenu);
|
|
xxxSendMenuDrawItemMessage(hdc,ODA_DRAWENTIRE,
|
|
pMenu, pItem, TRUE, xLeft);
|
|
ThreadUnlock(&tlpmenu);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
int dx, dy;
|
|
HBITMAP hbmSave;
|
|
|
|
//
|
|
// Is this the zero'th item in a menu bar that's not all
|
|
// bitmaps? Hmm, sounds like it could be a fake MDI dude.
|
|
// If it is, use the windows icon instead
|
|
//
|
|
if (pItem->dwItemData)
|
|
goto AintNothingLikeTheRealMDIThing;
|
|
else if (!fPopup &&
|
|
(pItem == pMenu->rgItems) &&
|
|
(pMenu->cItems > 1) &&
|
|
!(pMenu->rgItems[1].hbmp) &&
|
|
(pItem->spSubMenu)) {
|
|
RIPMSG0(RIP_WARNING, "Fake MDI detected, using window icon in place of bitmap");
|
|
goto AintNothingLikeTheRealMDIThing;
|
|
}
|
|
|
|
UserAssert(hdc != ghdcMem2);
|
|
|
|
//if (GreExtGetObjectW(pItem->hTypeData, sizeof(bmp), (LPSTR)&bmp)) {
|
|
|
|
dx = pItem->cxBmp;
|
|
|
|
if (fPopup) {
|
|
dy = pItem->cyBmp;
|
|
|
|
//
|
|
// Center bitmap in middle of item area
|
|
//
|
|
cyTemp = (pItem->cyItem - dy);
|
|
if (cyTemp > 0)
|
|
cyTemp = cyTemp / 2;
|
|
else
|
|
cyTemp = 0;
|
|
} else {
|
|
dy = max(pItem->cyBmp, SYSMET(CYMENUSIZE));
|
|
cyTemp = 0;
|
|
}
|
|
|
|
if (hbmSave = GreSelectBitmap(ghdcMem2, pItem->hbmp)) {
|
|
BITMAP bmp;
|
|
//
|
|
// Draw the bitmap leaving some room on the left for the
|
|
// optional check mark if we are in a popup menu. (as opposed
|
|
// to a top level menu bar).
|
|
//
|
|
// We can do cool stuff with monochrome bitmap itmes
|
|
// by merging with the current colors.
|
|
//
|
|
// If the item is selected and the bitmap isn't monochrome,
|
|
// we just invert the thing when we draw it. We can't do
|
|
// anything more clever unless we want to convert to
|
|
// monochrome.
|
|
//
|
|
GreExtGetObjectW(pItem->hbmp, sizeof(bmp), (LPSTR)&bmp);
|
|
GreBitBlt(hdc, xLeft, cyTemp, dx, dy, ghdcMem2, 0, 0,
|
|
(bmp.bmPlanes * bmp.bmBitsPixel == 1) ?
|
|
SRCSTENCIL :
|
|
(TestMFS(pItem, MFS_HILITE) ? NOTSRCCOPY : SRCCOPY),
|
|
0x00FFFFFF);
|
|
GreSelectBitmap(ghdcMem2, hbmSave);
|
|
} else {
|
|
RIPMSG3(RIP_WARNING, "Menu 0x%08X, item 0x%08X: Tried to draw invalid bitmap 0x%08X", pMenu, pItem, pItem->hbmp) ;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pItem->lpstr ) {
|
|
|
|
if ( pItem->hbmp )
|
|
xLeft += pItem->cxBmp + SYSMET(CXEDGE); // NT equivalient of CXEDGE2 ?
|
|
// This item is a text string item. Display it.
|
|
yTop = cyMenuFontExternLeading;
|
|
|
|
cyTemp = pItem->cyItem - (cyMenuFontChar + cyMenuFontExternLeading + SYSMET(CYBORDER));
|
|
if (cyTemp > 0)
|
|
yTop += (cyTemp / 2);
|
|
|
|
if (!fPopup)
|
|
xLeft += cxMenuFontChar;
|
|
|
|
lpsz = TextPointer(pItem->lpstr);
|
|
if (lpsz!=NULL) {
|
|
cch = pItem->cch;
|
|
|
|
// Even though we no longer support any funky handling of the
|
|
// help prefix character, we still need to eat it up if we run
|
|
// across it so that the menu item is drawn correctly
|
|
if ((*lpsz == CH_HELPPREFIX) && !fPopup) {
|
|
// Skip help prefix character.
|
|
lpsz++;
|
|
cch--;
|
|
}
|
|
|
|
// tp will contain the character position of the \t indicator
|
|
// in the menu string. This is where we add a tab to the string.
|
|
//
|
|
// rp will contain the character position of the \a indicator
|
|
// in the string. All text following this is right aligned.
|
|
tp = FindCharPosition(lpsz, TEXT('\t'));
|
|
rp = FindCharPosition(lpsz, TEXT('\t') - 1);
|
|
|
|
if (rp && (rp != cch)) {
|
|
// Display all the text up to the \a
|
|
DrawMenuItemText(pItem, hdc, xLeft, yTop, lpsz, rp);
|
|
|
|
// Do we also have a tab beyond the \a ??
|
|
if (tp > rp + 1) {
|
|
SIZE extent;
|
|
|
|
PSMGetTextExtent(hdc, lpsz + rp + 1,
|
|
(UINT)(tp - rp - 1), &extent);
|
|
GreExtTextOutW(hdc, (int)(pItem->dxTab - extent.cx), (int)yTop, 0,
|
|
NULL, lpsz + rp + 1, (UINT)(tp - rp - 1), NULL);
|
|
}
|
|
} else if (tp && rp == cch)
|
|
// Display text up to the tab position
|
|
DrawMenuItemText(pItem, hdc, xLeft, yTop, lpsz, tp);
|
|
|
|
// Any text left to display (like after the tab) ??
|
|
if (tp < cch - 1)
|
|
GreExtTextOutW(hdc, (int)(pItem->dxTab + cxMenuFontChar), (int)yTop, 0,
|
|
NULL, lpsz + tp + 1, (INT)(cch - tp - 1), NULL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw the hierarchical arrow for the cascade menu.
|
|
//
|
|
if (fPopup && (pItem->spSubMenu != NULL)) {
|
|
POEMBITMAPINFO pOem = oemInfo.bm + OBI_MENUARROW;
|
|
|
|
// This item has a hierarchical popup associated with it. Draw the
|
|
// bitmap dealy to signify its presence. Note we check if fPopup is set
|
|
// so that this isn't drawn for toplevel menus that have popups.
|
|
|
|
BltColor(hdc,
|
|
NULL,
|
|
gpDispInfo->hdcBits,
|
|
pItem->cxItem - pOem->cx,
|
|
max((pItem->cyItem - 2 - pOem->cy) / 2, 0),
|
|
pOem->cx,
|
|
pOem->cy,
|
|
pOem->x,
|
|
pOem->y,
|
|
TRUE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
#endif //MEMPHIS_MENUS
|
|
|
|
/***************************************************************************\
|
|
* xxxMenuBarDraw
|
|
*
|
|
* History:
|
|
* 11-Mar-1992 mikeke From win31
|
|
\***************************************************************************/
|
|
|
|
int xxxMenuBarDraw(
|
|
PWND pwnd,
|
|
HDC hdc,
|
|
int cxFrame,
|
|
int cyFrame)
|
|
{
|
|
UINT cxMenuMax;
|
|
int yTop;
|
|
PMENU pMenu;
|
|
BOOL fClipped = FALSE;
|
|
TL tlpmenu;
|
|
HRGN hrgnVisSave;
|
|
HBRUSH hbrT;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
/*
|
|
* Lock the menu so we can poke around
|
|
*/
|
|
pMenu = (PMENU)pwnd->spmenu;
|
|
if (pMenu == NULL) return SYSMET(CYBORDER);
|
|
|
|
ThreadLock(pMenu, &tlpmenu);
|
|
|
|
yTop = cyFrame;
|
|
if (TestWF(pwnd, WFCPRESENT)) {
|
|
yTop += (TestWF(pwnd, WEFTOOLWINDOW)) ? SYSMET(CYSMCAPTION) : SYSMET(CYCAPTION);
|
|
}
|
|
|
|
|
|
/*
|
|
* Calculate maximum available horizontal real estate
|
|
*/
|
|
cxMenuMax = (pwnd->rcWindow.right - pwnd->rcWindow.left) - cxFrame * 2;
|
|
|
|
/*
|
|
* If the menu has switched windows, or if either count is 0,
|
|
* then we need to recompute the menu width.
|
|
*/
|
|
if (pwnd != pMenu->spwndNotify ||
|
|
pMenu->cxMenu == 0 ||
|
|
pMenu->cyMenu == 0) {
|
|
Lock(&pMenu->spwndNotify, pwnd);
|
|
|
|
xxxMenuBarCompute(pMenu, pwnd, yTop, cxFrame, cxMenuMax);
|
|
}
|
|
|
|
/*
|
|
* If the menu rectangle is wider than allowed, or the
|
|
* bottom would overlap the size border, we need to clip.
|
|
*/
|
|
if (pMenu->cxMenu > cxMenuMax ||
|
|
(int)(yTop + pMenu->cyMenu) > (int)((pwnd->rcWindow.bottom - pwnd->rcWindow.top)
|
|
- cyFrame)) {
|
|
|
|
/*
|
|
* Lock the display while we're playing around with visrgns. Make
|
|
* a local copy of the saved-visrgn so it can be restored in case
|
|
* we make a callback (i.e. WM_DRAWITEM).
|
|
*/
|
|
GreLockDisplay(gpDispInfo->pDevLock);
|
|
|
|
fClipped = TRUE;
|
|
|
|
#ifdef LATER
|
|
// mikeke don't use the visrgn here if possible
|
|
hrgnVisSave = GreCreateRectRgn(
|
|
pwnd->rcWindow.left + cxFrame,
|
|
pwnd->rcWindow.top,
|
|
pwnd->rcWindow.left + cxFrame + cxMenuMax,
|
|
pwnd->rcWindow.bottom - cyFrame);
|
|
GreExtSelectClipRgn(hdc, hrgnVisSave, RGN_COPY);
|
|
GreSetMetaRgn(hdc);
|
|
GreDeleteObject(hrgnVisSave);
|
|
#else
|
|
hrgnVisSave = GreCreateRectRgn(0, 0, 0, 0);
|
|
GreCopyVisRgn(hdc,hrgnVisSave);
|
|
GreIntersectVisRect(hdc, pwnd->rcWindow.left + cxFrame,
|
|
pwnd->rcWindow.top,
|
|
pwnd->rcWindow.left + cxFrame + cxMenuMax,
|
|
pwnd->rcWindow.bottom - cyFrame);
|
|
|
|
#endif
|
|
|
|
GreUnlockDisplay(gpDispInfo->pDevLock);
|
|
}
|
|
|
|
{
|
|
POLYPATBLT PolyData[2];
|
|
|
|
PolyData[0].x = cxFrame;
|
|
PolyData[0].y = yTop;
|
|
PolyData[0].cx = pMenu->cxMenu;
|
|
PolyData[0].cy = pMenu->cyMenu;
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
PolyData[0].BrClr.hbr = (pMenu->hbrBack) ? pMenu->hbrBack : SYSHBR(MENU);
|
|
#else // MEMPHIS_MENU_WATERMARKS
|
|
PolyData[0].BrClr.hbr = SYSHBR(MENU);
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
|
|
PolyData[1].x = cxFrame;
|
|
PolyData[1].y = yTop + pMenu->cyMenu;
|
|
PolyData[1].cx = pMenu->cxMenu;
|
|
PolyData[1].cy = SYSMET(CYBORDER);
|
|
PolyData[1].BrClr.hbr = (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI))? SYSHBR(3DFACE) : SYSHBR(WINDOWFRAME);
|
|
|
|
GrePolyPatBlt(hdc,PATCOPY,&PolyData[0],2,PPB_BRUSH);
|
|
|
|
//
|
|
// Draw menu background in MENU color
|
|
//
|
|
//hbrT = GreSelectBrush(hdc, SYSHBR(MENU));
|
|
//GrePatBlt(hdc, cxFrame, yTop, pMenu->cxMenu, pMenu->cyMenu, PATCOPY);
|
|
|
|
//
|
|
// Draw border under menu in proper BORDER color
|
|
//
|
|
//GreSelectBrush(hdc, (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI))? SYSHBR(3DFACE) : SYSHBR(WINDOWFRAME));
|
|
//GrePatBlt(hdc, cxFrame, yTop + pMenu->cyMenu, pMenu->cxMenu, SYSMET(CYBORDER), PATCOPY);
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
* Finally, draw the menu itself.
|
|
*/
|
|
|
|
hbrT = GreSelectBrush(hdc, (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI))? SYSHBR(3DFACE) : SYSHBR(WINDOWFRAME));
|
|
xxxMenuDraw(hdc, pMenu);
|
|
GreSelectBrush(hdc, hbrT);
|
|
|
|
if (fClipped) {
|
|
#ifdef LATER
|
|
// mikeke don't use the visrgn here if possible
|
|
hrgnVisSave = GreCreateRectRgn(0, 0, 0, 0);
|
|
GreExtSelectClipRgn(hdc, hrgnVisSave, RGN_COPY);
|
|
GreSetMetaRgn(hdc);
|
|
GreDeleteObject(hrgnVisSave);
|
|
#else
|
|
GreLockDisplay(gpDispInfo->pDevLock);
|
|
GreSelectVisRgn(hdc, hrgnVisSave, NULL, SVR_DELETEOLD);
|
|
GreUnlockDisplay(gpDispInfo->pDevLock);
|
|
#endif
|
|
}
|
|
|
|
ThreadUnlock(&tlpmenu);
|
|
return(pMenu->cyMenu + SYSMET(CYBORDER));
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxMenuDraw
|
|
*
|
|
* Draws the menu
|
|
*
|
|
* Revalidation notes:
|
|
* This routine must be called with a valid and non-NULL pwnd.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
void xxxMenuDraw(
|
|
HDC hdc,
|
|
PMENU pmenu)
|
|
{
|
|
PITEM pItem;
|
|
UINT i=0;
|
|
RECT rcItem;
|
|
HFONT hFontOld;
|
|
UINT bfExtra;
|
|
PTHREADINFO ptiCurrent;
|
|
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
int iBkSave;
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
POINT ptOrg;
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
|
|
ptiCurrent = PtiCurrent();
|
|
|
|
CheckLock(pmenu);
|
|
|
|
if (pmenu == NULL) {
|
|
RIPERR0(ERROR_INVALID_HANDLE,
|
|
RIP_WARNING,
|
|
"Invalid menu handle \"pmenu\" (NULL) to xxxMenuDraw");
|
|
|
|
return;
|
|
}
|
|
|
|
hFontOld = GreSelectFont(hdc, ghMenuFont);
|
|
|
|
if ((SYSRGB(3DHILIGHT) == SYSRGB(MENU)) && (SYSRGB(3DSHADOW) == SYSRGB(MENU)))
|
|
bfExtra = BF_FLAT | BF_MONO;
|
|
else
|
|
bfExtra = 0;
|
|
|
|
pItem = (PITEM)pmenu->rgItems;
|
|
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
if (pmenu->hbrBack)
|
|
iBkSave = GreSetBkMode(hdc, TRANSPARENT);
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
for (i = 0, pItem = (PITEM)pmenu->rgItems; i < pmenu->cItems; i++, pItem++) {
|
|
if (TestMFT(pItem, MFT_MENUBARBREAK) &&
|
|
TestMF(pmenu, MFISPOPUP)) {
|
|
|
|
//
|
|
// Draw a vertical etch. This is done by calling DrawEdge(),
|
|
// sunken, with BF_LEFT | BF_RIGHT.
|
|
//
|
|
rcItem.left = pItem->xItem - SYSMET(CXFIXEDFRAME);
|
|
rcItem.top = 0;
|
|
rcItem.right = pItem->xItem - SYSMET(CXBORDER);
|
|
rcItem.bottom = pmenu->cyMenu;
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
if (hdc == ghdcBits2) {
|
|
GreGetViewportOrg(hdc, &ptOrg);
|
|
if (ptOrg.x == 0 && ptOrg.y == 0) {
|
|
GreSetViewportOrg(hdc, VIEWPORT_X_OFFSET_GDIBUG,
|
|
VIEWPORT_Y_OFFSET_GDIBUG, NULL);
|
|
}
|
|
}
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
DrawEdge(hdc, &rcItem, BDR_SUNKENOUTER, BF_LEFT | BF_RIGHT |
|
|
bfExtra);
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
if (hdc == ghdcBits2) {
|
|
GreSetViewportOrg(hdc, ptOrg.x, ptOrg.y, NULL);
|
|
}
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
}
|
|
|
|
if (TestMFT(pItem, MFT_SEPARATOR) &&
|
|
( !TestMFT(pItem, MFT_OWNERDRAW) ||
|
|
(LOWORD(ptiCurrent->dwExpWinVer) < VER40)) ) {
|
|
/*
|
|
* If version is less than 4.0 don't test the MFT_OWNERDRAW
|
|
* flag. Bug 21922; App MaxEda has both separator and Ownerdraw
|
|
* flags on. In 3.51 we didn't test the OwnerDraw flag
|
|
*/
|
|
|
|
//
|
|
// Draw a horizontal etch.
|
|
//
|
|
int yT = pItem->yItem + (pItem->cyItem / 2) - SYSMET(CYBORDER);
|
|
|
|
rcItem.left = pItem->xItem;
|
|
rcItem.top = yT;
|
|
rcItem.right = pItem->xItem + pItem->cxItem;
|
|
rcItem.bottom = yT + SYSMET(CYEDGE);
|
|
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
if (hdc == ghdcBits2) {
|
|
GreGetViewportOrg(hdc, &ptOrg);
|
|
if (ptOrg.x == 0 && ptOrg.y == 0) {
|
|
GreSetViewportOrg(hdc, VIEWPORT_X_OFFSET_GDIBUG,
|
|
VIEWPORT_Y_OFFSET_GDIBUG, NULL);
|
|
}
|
|
}
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
DrawEdge(hdc, &rcItem, BDR_SUNKENOUTER, BF_TOP | BF_BOTTOM |
|
|
bfExtra);
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
if (hdc == ghdcBits2) {
|
|
GreSetViewportOrg(hdc, ptOrg.x, ptOrg.y, NULL);
|
|
}
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
|
|
} else {
|
|
xxxDrawMenuItem(hdc, pmenu, pItem, FALSE);
|
|
}
|
|
}
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
if (pmenu->hbrBack)
|
|
GreSetBkMode(hdc, iBkSave);
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
GreSelectFont(hdc, hFontOld);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxDrawMenuBar
|
|
*
|
|
* Forces redraw of the menu bar
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
BOOL xxxDrawMenuBar(
|
|
PWND pwnd)
|
|
{
|
|
CheckLock(pwnd);
|
|
|
|
if (!TestwndChild(pwnd))
|
|
xxxRedrawFrame(pwnd);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxMenuInvert
|
|
*
|
|
* Invert menu item
|
|
*
|
|
* Revalidation notes:
|
|
* This routine must be called with a valid and non-NULL pwnd.
|
|
*
|
|
* fOn - TRUE if the item is selected thus it needs to be inverted
|
|
* fNotify - TRUE if the parent should be notified (as appropriate), FALSE
|
|
* if we are just redrawing the selected item.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
PITEM xxxMNInvertItem(
|
|
PWND pwnd,
|
|
PMENU pmenu,
|
|
int itemNumber,
|
|
PWND pwndNotify,
|
|
BOOL fOn)
|
|
{
|
|
PITEM pItem;
|
|
HDC hdc;
|
|
int y;
|
|
RECT rcItem;
|
|
BOOL fSysMenuIcon = FALSE;
|
|
PMENU pmenusys;
|
|
BOOL fClipped = FALSE;
|
|
HFONT hOldFont;
|
|
HRGN hrgnVisSave;
|
|
|
|
CheckLock(pwnd);
|
|
CheckLock(pmenu);
|
|
CheckLock(pwndNotify);
|
|
|
|
/*
|
|
* If we are in the middle of trying to get out of menu mode, hMenu
|
|
* and/or pwndNotify will be NULL, so just bail out now.
|
|
*/
|
|
|
|
if ((pmenu == NULL) || (pwndNotify == NULL))
|
|
return(NULL);
|
|
|
|
#ifdef MEMPHIS_MENU_ANIMATION
|
|
MNAnimate(FALSE); // terminate any animation
|
|
#endif // MEMPHIS_MENU_ANIMATION
|
|
|
|
if (itemNumber < 0) {
|
|
xxxSendMenuSelect(pwndNotify, pmenu, itemNumber);
|
|
return NULL;
|
|
}
|
|
|
|
if (!TestMF(pmenu, MFISPOPUP)) {
|
|
pmenusys = GetSysMenuHandle(pwndNotify);
|
|
if (pmenu == pmenusys) {
|
|
MNPositionSysMenu(pwndNotify, pmenusys);
|
|
fSysMenuIcon = TRUE;
|
|
}
|
|
}
|
|
|
|
if ((UINT)itemNumber >= pmenu->cItems) return NULL;
|
|
|
|
pItem = &pmenu->rgItems[itemNumber];
|
|
|
|
if (!TestMF(pmenu, MFISPOPUP) && TestWF(pwndNotify, WFMINIMIZED)) {
|
|
|
|
/*
|
|
* Skip inverting top level menus if the window is iconic.
|
|
*/
|
|
goto SeeYa;
|
|
}
|
|
|
|
/*
|
|
* Is this a separator?
|
|
*/
|
|
if (TestMFT(pItem, MFT_SEPARATOR))
|
|
goto SendSelectMsg;
|
|
|
|
if ((BOOL)TestMFS(pItem, MFS_HILITE) == (BOOL)fOn) {
|
|
|
|
/*
|
|
* Item's state isn't really changing. Just return.
|
|
*/
|
|
goto SeeYa;
|
|
}
|
|
|
|
rcItem.left = pItem->xItem;
|
|
rcItem.top = pItem->yItem;
|
|
rcItem.right = pItem->xItem + pItem->cxItem;
|
|
rcItem.bottom = pItem->yItem + pItem->cyItem;
|
|
|
|
y = pItem->cyItem;
|
|
|
|
if (TestMF(pmenu, MFISPOPUP)) {
|
|
hdc = _GetDC(pwnd);
|
|
} else {
|
|
hdc = _GetWindowDC(pwnd);
|
|
if ( TestWF(pwnd, WFSIZEBOX) && !fSysMenuIcon) {
|
|
|
|
/*
|
|
* If the window is small enough that some of the menu bar has been
|
|
* obscured by the frame, we don't want to draw on the bottom of the
|
|
* sizing frame. Note that we don't want to do this if we are
|
|
* inverting the system menu icon since that will be clipped to the
|
|
* window rect. (otherwise we end up with only half the sys menu
|
|
* icon inverted)
|
|
*/
|
|
int xMenuMax = (pwnd->rcWindow.right - pwnd->rcWindow.left) - SYSMET(CXSIZEFRAME);
|
|
|
|
if (rcItem.right > xMenuMax ||
|
|
rcItem.bottom > ((pwnd->rcWindow.bottom -
|
|
pwnd->rcWindow.top) - SYSMET(CYSIZEFRAME))) {
|
|
|
|
/*
|
|
* Lock the display while we're playing around with visrgns.
|
|
* Make a local copy of the visrgn, so that it can be
|
|
* properly restored on potential callbacks (i.e. WM_DRAWITEM).
|
|
*/
|
|
GreLockDisplay(gpDispInfo->pDevLock);
|
|
|
|
fClipped = TRUE;
|
|
|
|
#ifdef LATER
|
|
// mikeke - don't use the visrgn here if possible
|
|
hrgnVisSave = GreCreateRectRgn(
|
|
pwnd->rcWindow.left + rcItem.left,
|
|
pwnd->rcWindow.top + rcItem.top,
|
|
pwnd->rcWindow.left + xMenuMax,
|
|
pwnd->rcWindow.bottom - SYSMET(CYSIZEFRAME));
|
|
GreExtSelectClipRgn(hdc, hrgnVisSave, RGN_COPY);
|
|
GreSetMetaRgn(hdc);
|
|
GreDeleteObject(hrgnVisSave);
|
|
#else
|
|
hrgnVisSave = GreCreateRectRgn(0, 0, 0, 0);
|
|
GreCopyVisRgn(hdc,hrgnVisSave);
|
|
GreIntersectVisRect(hdc,
|
|
pwnd->rcWindow.left + rcItem.left,
|
|
pwnd->rcWindow.top + rcItem.top,
|
|
pwnd->rcWindow.left + xMenuMax,
|
|
pwnd->rcWindow.bottom - SYSMET(CYSIZEFRAME));
|
|
#endif
|
|
|
|
GreUnlockDisplay(gpDispInfo->pDevLock);
|
|
}
|
|
}
|
|
}
|
|
|
|
hOldFont = GreSelectFont(hdc, ghMenuFont);
|
|
|
|
if (fOn)
|
|
SetMFS(pItem, MFS_HILITE);
|
|
else
|
|
ClearMFS(pItem, MFS_HILITE);
|
|
|
|
#ifdef MEMPHIS_MENUS
|
|
if (!fSysMenuIcon && (pItem->hbmp != (HANDLE)MENUHBM_SYSTEM)) {
|
|
#else // MEMPHIS_MENUS
|
|
if (!fSysMenuIcon && (!TestMFT(pItem, MFT_BITMAP) || (pItem->hTypeData != (HANDLE)MENUHBM_SYSTEM))) {
|
|
#endif //MEMPHIS_MENUS
|
|
#ifdef MEMPHIS_MENU_WATERMARKS
|
|
if (pmenu->hbrBack && !TestMFS(pItem, MFS_HILITE) && !TestMFT(pItem, MFT_OWNERDRAW)) {
|
|
// fill the background here so xxxDrawMenuItem doesn't have to fool
|
|
// around with hbrBack
|
|
HBRUSH hbrOld = GreSelectBrush(hdc, pmenu->hbrBack);
|
|
int iBkSave = GreSetBkMode(hdc, TRANSPARENT);
|
|
GrePatBlt(hdc, pItem->xItem, pItem->yItem, pItem->cxItem,
|
|
pItem->cyItem, PATCOPY);
|
|
GreSelectBrush(hdc, hbrOld);
|
|
GreSetBkMode(hdc, iBkSave);
|
|
}
|
|
#endif // MEMPHIS_MENU_WATERMARKS
|
|
xxxDrawMenuItem(hdc, pmenu, pItem, TRUE);
|
|
}
|
|
|
|
|
|
if (fClipped) {
|
|
GreLockDisplay(gpDispInfo->pDevLock);
|
|
GreSelectVisRgn(hdc, hrgnVisSave, NULL, SVR_DELETEOLD);
|
|
GreUnlockDisplay(gpDispInfo->pDevLock);
|
|
}
|
|
|
|
GreSelectFont(hdc, hOldFont);
|
|
_ReleaseDC(hdc);
|
|
|
|
SendSelectMsg:
|
|
|
|
/*
|
|
* send select msg only if we are selecting an item.
|
|
*/
|
|
if (fOn) {
|
|
xxxSendMenuSelect(pwndNotify, pmenu, itemNumber);
|
|
}
|
|
|
|
SeeYa:
|
|
return(pItem);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* xxxDrawMenuBarTemp()
|
|
*
|
|
* This is so the control panel can let us do the work -- and make their
|
|
* preview windows that much more accurate. The only reason I put the hwnd in
|
|
* here is because, in the low level menu routines, we assume that an hwnd is
|
|
* associated with the hmenu -- I didn't want to slow that code down by adding
|
|
* NULL checks.
|
|
*
|
|
* The SYSMET(CYMENU) with regard to the given font is returned -- this
|
|
* way control panel can say, "The user wants this menu font (hfont) with this
|
|
* menu height (lprc)", and we can respond "this is the height we ended up
|
|
* using."
|
|
*
|
|
* NOTE: It's OK to overrite lprc because this function receives a pointer
|
|
* to the rectangle captured in NtUserDrawMenuBarTemp.
|
|
*
|
|
* History:
|
|
* 20-Sep-95 BradG Ported from Win95 (inctlpan.c)
|
|
\***************************************************************************/
|
|
|
|
int xxxDrawMenuBarTemp(
|
|
PWND pwnd,
|
|
HDC hdc,
|
|
LPRECT lprc,
|
|
PMENU pMenu,
|
|
HFONT hfont)
|
|
{
|
|
int cyMenu;
|
|
HFONT hOldFont;
|
|
HFONT hFontSave = ghMenuFont;
|
|
int cxCharSave = cxMenuFontChar;
|
|
int cxOverhangSave = cxMenuFontOverhang;
|
|
int cyCharSave = cyMenuFontChar;
|
|
int cyLeadingSave = cyMenuFontExternLeading;
|
|
int cyAscentSave = cyMenuFontAscent;
|
|
int cySizeSave = SYSMET(CYMENUSIZE);
|
|
PWND pwndSave = pMenu->spwndNotify;
|
|
|
|
CheckLock(pwnd);
|
|
CheckLock(pMenu);
|
|
|
|
cyMenu = lprc->bottom - lprc->top;
|
|
|
|
if (hfont) {
|
|
TEXTMETRIC textMetrics;
|
|
|
|
/*
|
|
* Compute the new menu font info if needed
|
|
*/
|
|
ghMenuFont = hfont;
|
|
hOldFont = GreSelectFont(gpDispInfo->hdcBits, ghMenuFont);
|
|
cxMenuFontChar = GetCharDimensions(gpDispInfo->hdcBits, &textMetrics, &cyMenuFontChar);
|
|
cxMenuFontOverhang = textMetrics.tmOverhang;
|
|
GreSelectFont(gpDispInfo->hdcBits, hOldFont);
|
|
|
|
#ifdef KOREA
|
|
cyMenuFontChar -= textMetrics.tmInternalLeading - 2;
|
|
#endif
|
|
cyMenuFontExternLeading = textMetrics.tmExternalLeading;
|
|
|
|
cyMenuFontAscent = textMetrics.tmAscent;
|
|
#ifndef KOREA
|
|
cyMenuFontAscent += SYSMET(CYBORDER);
|
|
#endif
|
|
}
|
|
|
|
cyMenu -= SYSMET(CYBORDER);
|
|
cyMenu = max(cyMenu, (cyMenuFontChar + cyMenuFontExternLeading + SYSMET(CYEDGE)));
|
|
SYSMET(CYMENUSIZE) = cyMenu;
|
|
SYSMET(CYMENU) = cyMenu + SYSMET(CYBORDER);
|
|
|
|
/*
|
|
* Compute the dimensons of the menu (hope that we don't leave the
|
|
* USER critical section)
|
|
*/
|
|
xxxMenuBarCompute(pMenu, pwnd, lprc->top, lprc->left, lprc->right);
|
|
|
|
/*
|
|
* Draw menu border in menu color
|
|
*/
|
|
lprc->bottom = lprc->top + pMenu->cyMenu;
|
|
FillRect(hdc, lprc, SYSHBR(MENU));
|
|
|
|
/*
|
|
* Finally, draw the menu itself.
|
|
*/
|
|
xxxMenuDraw(hdc, pMenu);
|
|
|
|
/*
|
|
* Restore the old state
|
|
*/
|
|
pMenu->spwndNotify = pwndSave;
|
|
ghMenuFont = hFontSave;
|
|
cxMenuFontChar = cxCharSave;
|
|
cxMenuFontOverhang = cxOverhangSave;
|
|
cyMenuFontChar = cyCharSave;
|
|
cyMenuFontExternLeading = cyLeadingSave;
|
|
cyMenuFontAscent = cyAscentSave;
|
|
SYSMET(CYMENUSIZE) = cySizeSave;
|
|
|
|
cyMenu = SYSMET(CYMENU);
|
|
SYSMET(CYMENU) = cySizeSave + SYSMET(CYBORDER);
|
|
|
|
return cyMenu;
|
|
}
|