Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

948 lines
26 KiB

/**************************** Module Header ********************************\
* Module Name: mncomput.c
*
* Copyright 1985-96, Microsoft Corporation
*
* Menu Layout Calculation Routines
*
* History:
* 10-10-90 JimA Cleanup.
* 03-18-91 IanJa Window revalidation added
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
DWORD MNRecalcTabStrings(HDC, PMENU, UINT, UINT, DWORD, DWORD);
#ifdef MEMPHIS_MENUS
// returns TRUE if measureitem was sent and FALSE if not
BOOL xxxMNGetBitmapSize(LPITEM pItem, PWND pwndNotify)
{
MEASUREITEMSTRUCT mis;
if (pItem->cxBmp != -1)
return(FALSE);
// Send a measure item message to the owner
mis.CtlType = ODT_MENU;
mis.CtlID = 0;
mis.itemID = pItem->wID;
mis.itemWidth = 0;
// After scrollable menus
// mis32.itemHeight= cyMenuFontChar;
mis.itemHeight= (UINT)gpsi->cySysFontChar;
mis.itemData = pItem->dwItemData;
xxxSendMessage(pwndNotify, WM_MEASUREITEM, 0, (LONG)&mis);
pItem->cxBmp = mis.itemWidth;
pItem->cyBmp = mis.itemHeight;
}
#endif // MEMPHIS_MENUS
/***************************************************************************\
* xxxItemSize
*
* Calc the dimensions of bitmaps and strings. Loword of returned
* value contains width, high word contains height of item.
*
* History:
\***************************************************************************/
#ifdef MEMPHIS_MENUS
BOOL xxxMNItemSize(
PMENU pMenu,
PWND pwndNotify,
HDC hdc,
PITEM pItem,
BOOL fPopup,
LPPOINT lppt)
{
BITMAP bmp;
int width = 0;
int height = 0;
DWORD xRightJustify;
LPWSTR lpMenuString;
HFONT hfnOld;
int tcExtra;
CheckLock(pMenu);
CheckLock(pwndNotify);
if (!fPopup) {
/*
* Save off the height of the top menu bar since we will used this often
* if the pItem is not in a popup. (ie. it is in the top level menu bar)
*/
height = SYSMET(CYMENUSIZE);
}
hfnOld = NULL;
if (TestMFS(pItem, MFS_DEFAULT)) {
if (ghMenuFontDef)
hfnOld = GreSelectFont(hdc, ghMenuFontDef);
else {
tcExtra = GreGetTextCharacterExtra(hdc);
GreSetTextCharacterExtra(hdc, tcExtra + 1 + (cxMenuFontChar / gpsi->cxSysFontChar));
}
}
if (pItem->hbmp) {
/*
* Item is a bitmap so compute its dimensions.
*/
switch ((UINT)pItem->hbmp) {
case MENUHBM_SYSTEM:
width = SYSMET(CXMENUSIZE) + SYSMET(CXEDGE);
break;
case MENUHBM_MINIMIZE:
case MENUHBM_MINIMIZE_D:
case MENUHBM_RESTORE:
case MENUHBM_CLOSE:
case MENUHBM_CLOSE_D:
width = SYSMET(CXMENUSIZE);
break;
case MENUHBM_CALLBACK:
xxxMNGetBitmapSize(pItem, pwndNotify);
goto GotCxCy;
default:
//
// In menu bars, we force the item to be CYMNSIZE.
// Fixes many, many problems w/ apps that fake own MDI.
//
if (pItem->cxBmp == -1) {
GreExtGetObjectW(pItem->hbmp, sizeof(BITMAP), (LPSTR)&bmp);
pItem->cxBmp = bmp.bmWidth;
pItem->cyBmp = bmp.bmHeight;
}
GotCxCy:
width = pItem->cxBmp;
if (fPopup)
height = pItem->cyBmp;
else
height = max((int)pItem->cyBmp, height);
break;
}
} else if (TestMFT(pItem, MFT_OWNERDRAW)) {
// This is an ownerdraw item -- the width and height are stored in
// cxBmp and cyBmp
xxxMNGetBitmapSize(pItem, pwndNotify);
width = pItem->cxBmp;
//
// Ignore height with menu bar now--that's set by user.
//
if (fPopup) {
height = pItem->cyBmp;
// If this item has a popup (hierarchical) menu associated with it, then
// reserve room for the bitmap that tells the user that a hierarchical
// menu exists here.
// B#2966, t-arthb
UserAssert(fPopup == (TestMF(pMenu, MFISPOPUP) != 0));
width = width + (cxMenuFontChar << 1);
}
}
if ( pItem->lpstr && (!TestMFT(pItem, MFT_OWNERDRAW)) ) {
SIZE size;
/*
* This menu item contains a string
*/
/*
* We want to keep the menu bar height if this isn't a popup.
*/
if (fPopup)
/* The thickness of mnemonic underscore is CYBORDER and the gap
* between the characters and the underscore is another CYBORDER
*/
height = max(height, cyMenuFontChar + cyMenuFontExternLeading + SYSMET(CYEDGE));
lpMenuString = TextPointer(pItem->lpstr);
xRightJustify = FindCharPosition(lpMenuString, TEXT('\t'));
PSMGetTextExtent(hdc, lpMenuString, xRightJustify,
&size);
if (width) {
width += SYSMET(CXEDGE) + size.cx;
} else {
width = size.cx;
}
}
if (fPopup && !TestMFT(pItem, MFT_OWNERDRAW)) {
// Add on space for checkmark, then horz spacing for default & disabled
width += oemInfo.bm[OBI_MENUCHECK].cx + 2;
height += 2;
}
if (TestMFS(pItem, MFS_DEFAULT)) {
if (hfnOld)
GreSelectFont(hdc, hfnOld);
else
GreSetTextCharacterExtra(hdc, tcExtra);
}
/*
* Loword contains width, high word contains height of item.
*/
lppt->x = width;
lppt->y = height;
return(TestMFT(pItem, MFT_OWNERDRAW));
}
#else // MEMPHIS_MENUS
BOOL xxxMNItemSize(
PMENU pMenu,
PWND pwndNotify,
HDC hdc,
PITEM pItem,
BOOL fPopup,
LPPOINT lppt)
{
BITMAP bmp;
DWORD width = 0;
DWORD height = 0;
DWORD xRightJustify;
MEASUREITEMSTRUCT mis;
LPWSTR lpMenuString;
HFONT hfnOld;
int tcExtra;
CheckLock(pMenu);
CheckLock(pwndNotify);
if (!fPopup) {
/*
* Save off the height of the top menu bar since we will used this often
* if the pItem is not in a popup. (ie. it is in the top level menu bar)
*/
height = SYSMET(CYMENUSIZE);
}
hfnOld = NULL;
if (TestMFS(pItem, MFS_DEFAULT))
{
if (ghMenuFontDef)
hfnOld = GreSelectFont(hdc, ghMenuFontDef);
else
{
tcExtra = GreGetTextCharacterExtra(hdc);
GreSetTextCharacterExtra(hdc, tcExtra + 1 + (cxMenuFontChar / gpsi->cxSysFontChar));
}
}
if (TestMFT(pItem, MFT_BITMAP)) {
/*
* Item is a bitmap so compute its dimensions.
*/
switch ((UINT)pItem->hTypeData) {
case MENUHBM_SYSTEM:
width = SYSMET(CXMENUSIZE) + SYSMET(CXEDGE);
break;
case MENUHBM_MINIMIZE:
case MENUHBM_MINIMIZE_D:
case MENUHBM_RESTORE:
case MENUHBM_CLOSE:
case MENUHBM_CLOSE_D:
width = SYSMET(CXMENUSIZE);
break;
default:
//
// In menu bars, we force the item to be CYMNSIZE.
// Fixes many, many problems w/ apps that fake own MDI.
//
if (GreExtGetObjectW(pItem->hTypeData, sizeof(BITMAP), (LPSTR)&bmp)) {
width = bmp.bmWidth;
if (fPopup)
height = bmp.bmHeight;
else
height = max((DWORD)bmp.bmHeight, height);
} else {
width = SYSMET(CXMENUSIZE) + SYSMET(CXEDGE);
RIPMSG3(RIP_WARNING, "Menu 0x%08X, item 0x%08X: ItemSize referenced invalid bitmap 0x%08X", pMenu, pItem, pItem->hTypeData) ;
}
break;
}
} else if (TestMFT(pItem, MFT_OWNERDRAW)) {
/*
* This is an ownerdraw item.
*/
width = LOWORD(pItem->hTypeData);
if (width == 0) {
/*
* Send a measure item message to the owner
*/
mis.CtlType = ODT_MENU;
mis.CtlID = 0;
mis.itemID = pItem->wID;
mis.itemHeight = (UINT)gpsi->cySysFontChar;
mis.itemData = pItem->dwItemData;
xxxSendMessage(pwndNotify, WM_MEASUREITEM, 0, (LONG)&mis);
width = mis.itemWidth;
pItem->hTypeData = (HANDLE)MAKELONG(mis.itemWidth,mis.itemHeight);
}
//
// Ignore height with menu bar now--that's set by user.
//
if (fPopup) {
height = HIWORD(pItem->hTypeData);
// If this item has a popup (hierarchical) menu associated with it, then
// reserve room for the bitmap that tells the user that a hierarchical
// menu exists here.
// B#2966, t-arthb
UserAssert(fPopup == (TestMF(pMenu, MFISPOPUP) != 0));
width = width + (cxMenuFontChar << 1);
}
} else {
/*
* This menu item contains a string
*/
/*
* We want to keep the menu bar height if this isn't a popup.
*/
if (fPopup)
/* The thickness of mnemonic underscore is CYBORDER and the gap
* between the characters and the underscore is another CYBORDER
*/
height = cyMenuFontChar + cyMenuFontExternLeading + SYSMET(CYEDGE);
if (pItem->hTypeData != NULL) {
SIZE size;
lpMenuString = TextPointer(pItem->hTypeData);
xRightJustify = FindCharPosition(lpMenuString, TEXT('\t'));
PSMGetTextExtent(hdc, lpMenuString, xRightJustify,
&size);
width = size.cx;
} else {
width = 0;
}
}
if (fPopup && !TestMFT(pItem, MFT_OWNERDRAW)) {
// Add on space for checkmark, then horz spacing for default & disabled
width += oemInfo.bm[OBI_MENUCHECK].cx + 2;
// Add vert spacing for disabled, then 1 more for balance
height += 2;
}
if (TestMFS(pItem, MFS_DEFAULT))
{
if (hfnOld)
GreSelectFont(hdc, hfnOld);
else
GreSetTextCharacterExtra(hdc, tcExtra);
}
/*
* Loword contains width, high word contains height of item.
*/
lppt->x = width;
lppt->y = height;
return(TestMFT(pItem, MFT_OWNERDRAW));
}
#endif // MEMPHIS_MENUS
/***************************************************************************\
* xxxMenuCompute2
*
* !
*
* History:
\***************************************************************************/
int xxxMNCompute(
PMENU pMenu,
PWND pwndNotify,
DWORD yMenuTop,
DWORD xMenuLeft,
DWORD cxMax,
LPDWORD lpdwMenuHeight)
{
UINT cItem;
DWORD cxItem;
DWORD cyItem;
DWORD cyItemKeep;
DWORD yPopupTop;
INT cMaxWidth;
DWORD cMaxHeight;
UINT cItemBegCol;
DWORD temp;
int ret;
PITEM pCurItem;
POINT ptMNItemSize;
BOOL fOwnerDrawItems;
BOOL fMenuBreak;
LPWSTR lpsz;
BOOL fPopupMenu;
DWORD menuHeight = 0;
HDC hdc;
HFONT hOldFont;
PTHREADINFO ptiCurrent;
ptiCurrent = PtiCurrent();
CheckLock(pMenu);
CheckLock(pwndNotify);
if (lpdwMenuHeight != NULL)
menuHeight = *lpdwMenuHeight;
Lock(&pMenu->spwndNotify, pwndNotify);
/*
* Empty menus have a height of zero.
*/
ret = 0;
if (pMenu->cItems == 0)
return ret;
hdc = _GetScreenDC();
hOldFont = GreSelectFont(hdc, ghMenuFont);
/*
* Try to make a non-multirow menu first.
*/
pMenu->fFlags &= (~MFMULTIROW);
fPopupMenu = TestMF(pMenu, MFISPOPUP);
if (fPopupMenu) {
/*
* Reset the menu bar height to 0 if this is a popup since we are
* being called from menu.c MN_SIZEWINDOW.
*/
menuHeight = 0;
} else if (pwndNotify != NULL) {
pMenu->cxMenu = cxMax;
}
/*
* Initialize the computing variables.
*/
cMaxWidth = cyItemKeep = 0L;
cItemBegCol = 0;
cyItem = yPopupTop = yMenuTop;
cxItem = xMenuLeft;
pCurItem = (PITEM)&pMenu->rgItems[0];
/*
* Process each item in the menu.
*/
fOwnerDrawItems = FALSE;
for (cItem = 0; cItem < pMenu->cItems; cItem++) {
/*
* If it's not a separator, find the dimensions of the object.
*/
if (TestMFT(pCurItem, MFT_SEPARATOR) &&
( !TestMFT(pCurItem, 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
*/
//
// This is a separator. It's drawn as wide as the menu area,
// leaving some space above and below. Since the menu area is
// the max of the items' widths, we set our width to 0 so as not
// to affect the result.
//
pCurItem->cxItem = 0;
pCurItem->cyItem = SYSMET(CYMENUSIZE) / 2;
} else {
/*
* Get the item's X and Y dimensions.
*/
if (xxxMNItemSize(pMenu, pwndNotify, hdc, pCurItem, fPopupMenu, &ptMNItemSize))
fOwnerDrawItems = TRUE;
pCurItem->cxItem = ptMNItemSize.x;
pCurItem->cyItem = ptMNItemSize.y;
#ifdef MEMPHIS_MENUS
if (!fPopupMenu && !pCurItem->hbmp) {
#else
if (!fPopupMenu && !TestMFT(pCurItem,MFT_BITMAP)) {
#endif // MEMPHIS_MENUS
pCurItem->cxItem += cxMenuFontChar * 2;
}
}
if (menuHeight != 0)
pCurItem->cyItem = menuHeight;
/*
* If this is the first item, initialize cMaxHeight.
*/
if (cItem == 0)
cMaxHeight = pCurItem->cyItem;
/*
* Is this a Pull-Down menu?
*/
if (fPopupMenu) {
/*
* If this item has a break or is the last item...
*/
if ((fMenuBreak = TestMFT(pCurItem, MFT_BREAK)) ||
pMenu->cItems == cItem + (UINT)1) {
/*
* Keep cMaxWidth around if this is not the last item.
*/
temp = cMaxWidth;
if (pMenu->cItems == cItem + (UINT)1) {
if ((int)(pCurItem->cxItem) > cMaxWidth)
temp = pCurItem->cxItem;
}
/*
* Get new width of string from RecalcTabStrings.
*/
temp = MNRecalcTabStrings(hdc, pMenu, cItemBegCol,
(UINT)(cItem + (fMenuBreak ? 0 : 1)), temp, cxItem);
/*
* If this item has a break, account for it.
*/
if (fMenuBreak) {
//
// Add on space for the etch and a border on either side.
// NOTE: For old apps that do weird stuff with owner
// draw, keep 'em happy by adding on the same amount
// of space we did in 3.1.
//
if (fOwnerDrawItems && !TestWF(pwndNotify, WFWIN40COMPAT))
cxItem = temp + SYSMET(CXBORDER);
else
cxItem = temp + 2 * SYSMET(CXEDGE);
/*
* Reset the cMaxWidth to the current item.
*/
cMaxWidth = pCurItem->cxItem;
/*
* Start at the top.
*/
cyItem = yPopupTop;
/*
* Save the item where this column begins.
*/
cItemBegCol = cItem;
/*
* If this item is also the last item, recalc for this
* column.
*/
if (pMenu->cItems == (UINT)(cItem + 1)) {
temp = MNRecalcTabStrings(hdc, pMenu, cItem,
(UINT)(cItem + 1), cMaxWidth, cxItem);
}
}
/*
* If this is the last entry, supply the width.
*/
if (pMenu->cItems == cItem + (UINT)1)
pMenu->cxMenu = temp;
}
pCurItem->xItem = cxItem;
pCurItem->yItem = cyItem;
cyItem += pCurItem->cyItem;
if (cyItemKeep < cyItem)
cyItemKeep = cyItem;
} else {
/*
* This a Top Level menu, not a Pull-Down.
*/
/*
* Adjust right aligned items before testing for multirow
*/
#ifdef MEMPHIS_MENUS
if (pCurItem->lpstr ) {
lpsz = TextPointer(pCurItem->lpstr);
#else // MEMPHIS_MENUS
if (!TestMFT(pCurItem, MFT_NONSTRING)) {
lpsz = TextPointer(pCurItem->hTypeData);
#endif // MEMPHIS_MENUS
if (lpsz != NULL && *lpsz == CH_HELPPREFIX)
pCurItem->cxItem -= cxMenuFontChar;
}
/*
* If this is a new line or a menu break.
*/
if ((TestMFT(pCurItem, MFT_BREAK)) ||
(((cxItem + pCurItem->cxItem + cxMenuFontChar) >
pMenu->cxMenu) && (cItem != 0))) {
cyItem += cMaxHeight;
cxItem = xMenuLeft;
cMaxHeight = pCurItem->cyItem;
pMenu->fFlags |= MFMULTIROW;
}
pCurItem->yItem = cyItem;
pCurItem->xItem = cxItem;
cxItem += pCurItem->cxItem;
}
if (cMaxWidth < (int)(pCurItem->cxItem))
cMaxWidth = pCurItem->cxItem;
if (cMaxHeight != pCurItem->cyItem) {
if (cMaxHeight < pCurItem->cyItem)
cMaxHeight = pCurItem->cyItem;
if (!fPopupMenu)
menuHeight = cMaxHeight;
}
if (!fPopupMenu)
cyItemKeep = cyItem + cMaxHeight;
pCurItem++;
} /* of for loop */
GreSelectFont(hdc, hOldFont);
_ReleaseDC(hdc);
pMenu->cyMenu = cyItemKeep - yMenuTop;
ret = pMenu->cyMenu;
if (lpdwMenuHeight != NULL)
*lpdwMenuHeight = menuHeight;
return ret;
}
/***************************************************************************\
* MBC_RightJustifyMenu
*
* !
*
* History:
\***************************************************************************/
void MBC_RightJustifyMenu(
PMENU pMenu)
{
PITEM pItem;
int cItem;
int iFirstRJItem = MFMWFP_NOITEM;
DWORD xMenuPos;
// B#4055
// Use signed arithmetic so comparison cItem >= iFirstRJItem won't
// cause underflow.
for (cItem = 0; cItem < (int)pMenu->cItems; cItem++) {
// Find the first item which is right justified.
if (TestMFT((pMenu->rgItems + cItem), MFT_RIGHTJUSTIFY)) {
iFirstRJItem = cItem;
xMenuPos = pMenu->cxMenu + pMenu->rgItems[0].xItem;
for (cItem = (int)pMenu->cItems - 1; cItem >= iFirstRJItem; cItem--) {
pItem = pMenu->rgItems + cItem;
xMenuPos -= pItem->cxItem;
if (pItem->xItem < xMenuPos)
pItem->xItem = xMenuPos;
}
return;
}
}
}
/***************************************************************************\
* xxxMenuBarCompute
*
* returns the height of the menubar menu. yMenuTop, xMenuLeft, and
* cxMax are used when computing the height/width of top level menu bars in
* windows.
*
*
* History:
\***************************************************************************/
int xxxMenuBarCompute(
PMENU pMenu,
PWND pwndNotify,
DWORD yMenuTop,
DWORD xMenuLeft,
int cxMax)
{
int size;
/* menuHeight is set by MNCompute when dealing with a top level menu and
* not all items in the menu bar have the same height. Thus, by setting
* menuHeight, MNCompute is called a second time to set every item to the
* same height. The actual value stored in menuHeight is the maximum
* height of all the menu bar items
*/
DWORD menuHeight = 0;
CheckLock(pwndNotify);
CheckLock(pMenu);
Lock(&(pMenu->spwndNotify), pwndNotify);
size = xxxMNCompute(pMenu, pwndNotify, yMenuTop, xMenuLeft, cxMax, &menuHeight);
if (!TestMF(pMenu, MFISPOPUP)) {
if (menuHeight != 0) {
/*
* Add a border for the multi-row case.
*/
size = xxxMNCompute(pMenu, pwndNotify, yMenuTop, xMenuLeft,
cxMax, &menuHeight);
}
/*
* Right justification of HELP items is only needed on top level
* menus.
*/
MBC_RightJustifyMenu(pMenu);
}
/*
* There's an extra border underneath the menu bar, if it's not empty!
*/
return(size ? size + SYSMET(CYBORDER) : size);
}
/***************************************************************************\
* xxxRecomputeMenu
*
* !
*
* History:
\***************************************************************************/
void xxxMNRecomputeBarIfNeeded(
PWND pwndNotify,
PMENU pMenu)
{
int cxFrame;
int cyFrame;
UserAssert(!TestMF(pMenu, MFISPOPUP));
CheckLock(pwndNotify);
CheckLock(pMenu);
if ((pMenu != pwndNotify->head.rpdesk->spmenuSys) &&
(pMenu != pwndNotify->head.rpdesk->spmenuDialogSys) &&
((pMenu->spwndNotify != pwndNotify) || !pMenu->cxMenu || !pMenu->cyMenu)) {
int cBorders;
Lock(&pMenu->spwndNotify, pwndNotify);
cBorders = GetWindowBorders(pwndNotify->style, pwndNotify->ExStyle, TRUE, FALSE);
cxFrame = cBorders * SYSMET(CXBORDER);
cyFrame = cBorders * SYSMET(CYBORDER);
if (TestWF(pwndNotify, WFCPRESENT)) {
cyFrame += TestWF(pwndNotify, WEFTOOLWINDOW) ?
SYSMET(CYSMCAPTION) : SYSMET(CYCAPTION);
}
// The width passed in this call was larger by cxFrame;
// Fix for Bug #11466 - Fixed by SANKAR - 01/06/92 --
xxxMenuBarCompute(pMenu, pwndNotify, cyFrame, cxFrame,
(pwndNotify->rcWindow.right - pwndNotify->rcWindow.left) - cxFrame * 2);
}
}
/***************************************************************************\
* RecalcTabStrings
*
* !
*
* History:
* 10-11-90 JimA Translated from ASM
\***************************************************************************/
DWORD MNRecalcTabStrings(
HDC hdc,
PMENU pMenu,
UINT iBeg,
UINT iEnd,
DWORD xTab,
DWORD hCount)
{
UINT i;
UINT cOwnerDraw;
int adx;
int maxWidth = 0;
int cx;
PITEM pItem;
CheckLock(pMenu);
xTab += hCount;
if ((iBeg >= pMenu->cItems) || (iBeg > iEnd))
goto SeeYa;
cOwnerDraw = 0;
for (i = iBeg, pItem = pMenu->rgItems + iBeg; i < iEnd; pItem++, i++) {
adx = 0;
pItem->dxTab = xTab;
// Skip non-string or empty string items
#ifdef MEMPHIS_MENUS
if (pItem->lpstr) {
LPWSTR lpString = TextPointer(pItem->lpstr);
#else // MEMPHIS_MENUS
if (!TestMFT(pItem, MFT_NONSTRING) && (pItem->hTypeData != NULL)) {
LPWSTR lpString = TextPointer(pItem->hTypeData);
#endif // MEMPHIS_MENUS
int tp;
SIZE size;
// Are there any tabs?
tp = FindCharPosition(lpString, TEXT('\t'));
if (tp < (int) pItem->cch) {
GreGetTextExtentW(hdc, lpString + tp + 1,
pItem->cch - tp - 1, &size, GGTE_WIN3_EXTENT);
adx = cxMenuFontChar + size.cx;
}
} else if (TestMFT(pItem, MFT_OWNERDRAW))
cOwnerDraw++;
adx += xTab;
if (adx > maxWidth)
maxWidth = adx;
}
//
// Add on space for hierarchical arrow. So basically, popup menu items
// can have 4 columns:
// (1) Checkmark
// (2) Text
// (3) Tabbed text for accel
// (4) Hierarchical arrow
//
// But, we only do this if at least one item isn't ownerdraw
//
if (cOwnerDraw != (iEnd - iBeg))
maxWidth += cxMenuFontChar + oemInfo.bm[OBI_MENUCHECK].cx;
cx = maxWidth - hCount;
for (i = iBeg, pItem = pMenu->rgItems + iBeg; i < iEnd; pItem++, i++)
pItem->cxItem = cx;
SeeYa:
return(maxWidth);
}
// ============================================================================
//
// GetMenuItemRect()
//
// ============================================================================
BOOL xxxGetMenuItemRect(PWND pwnd, PMENU pMenu, UINT uIndex, LPRECT lprcScreen)
{
PITEM pItem;
int dx, dy;
CheckLock(pwnd);
CheckLock(pMenu);
SetRectEmpty(lprcScreen);
if (uIndex >= pMenu->cItems)
return(FALSE);
if (TestMF(pMenu, MFISPOPUP)) {
dx = pwnd->rcClient.left;
dy = pwnd->rcClient.top;
} else {
xxxMNRecomputeBarIfNeeded(pwnd, pMenu);
dx = pwnd->rcWindow.left;
dy = pwnd->rcWindow.top;
}
if (uIndex >= pMenu->cItems)
return(FALSE);
pItem = pMenu->rgItems + uIndex;
lprcScreen->right = pItem->cxItem;
lprcScreen->bottom = pItem->cyItem;
OffsetRect(lprcScreen, dx + pItem->xItem, dy + pItem->yItem);
return(TRUE);
}
/***************************************************************************\
*
* MenuItemFromPoint()
*
\***************************************************************************/
UINT MNItemHitTest(PMENU pMenu, PWND pwnd, POINT pt);
int xxxMenuItemFromPoint(PWND pwnd, PMENU pMenu, POINT ptScreen)
{
CheckLock(pwnd);
CheckLock(pMenu);
if (!TestMF(pMenu, MFISPOPUP)) {
xxxMNRecomputeBarIfNeeded(pwnd, pMenu);
}
return(MNItemHitTest(pMenu, pwnd, ptScreen));
}