Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

mncomput.c

Go to the documentation of this file.
00001 /**************************** Module Header ********************************\ 00002 * Module Name: mncomput.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Menu Layout Calculation Routines 00007 * 00008 * History: 00009 * 10-10-90 JimA Cleanup. 00010 * 03-18-91 IanJa Window revalidation added 00011 \***************************************************************************/ 00012 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 00016 00017 DWORD MNRecalcTabStrings(HDC, PMENU, UINT, UINT, DWORD, DWORD); 00018 00019 /***************************************************************************\ 00020 * xxxMNGetBitmapSize 00021 * 00022 * returns TRUE if measureitem was sent and FALSE if not 00023 * 00024 * History: 00025 * 07-23-96 GerardoB - Added header & fixed up for 5.0 00026 \***************************************************************************/ 00027 BOOL xxxMNGetBitmapSize(LPITEM pItem, PWND pwndNotify) 00028 { 00029 MEASUREITEMSTRUCT mis; 00030 00031 if (pItem->cxBmp != MNIS_MEASUREBMP) { 00032 return FALSE; 00033 } 00034 00035 // Send a measure item message to the owner 00036 mis.CtlType = ODT_MENU; 00037 mis.CtlID = 0; 00038 mis.itemID = pItem->wID; 00039 mis.itemWidth = 0; 00040 // After scrollable menus 00041 // mis32.itemHeight= gcyMenuFontChar; 00042 mis.itemHeight= (UINT)gpsi->cySysFontChar; 00043 mis.itemData = pItem->dwItemData; 00044 00045 xxxSendMessage(pwndNotify, WM_MEASUREITEM, 0, (LPARAM)&mis); 00046 00047 pItem->cxBmp = mis.itemWidth; 00048 pItem->cyBmp = mis.itemHeight; 00049 00050 return TRUE; 00051 } 00052 00053 /***************************************************************************\ 00054 * xxxItemSize 00055 * 00056 * Calc the dimensions of bitmaps and strings. Loword of returned 00057 * value contains width, high word contains height of item. 00058 * 00059 * History: 00060 * 07-23-96 GerardoB - fixed up for 5.0 00061 \***************************************************************************/ 00062 BOOL xxxMNItemSize( 00063 PMENU pMenu, 00064 PWND pwndNotify, 00065 HDC hdc, 00066 PITEM pItem, 00067 BOOL fPopup, 00068 LPPOINT lppt) 00069 { 00070 BITMAP bmp; 00071 int width = 0; 00072 int height = 0; 00073 DWORD xRightJustify; 00074 LPWSTR lpMenuString; 00075 HFONT hfnOld; 00076 int tcExtra; 00077 00078 UNREFERENCED_PARAMETER(pMenu); 00079 00080 CheckLock(pMenu); 00081 CheckLock(pwndNotify); 00082 00083 if (!fPopup) { 00084 00085 /* 00086 * Save off the height of the top menu bar since we will used this often 00087 * if the pItem is not in a popup. (ie. it is in the top level menu bar) 00088 */ 00089 height = SYSMET(CYMENUSIZE); 00090 } 00091 00092 hfnOld = NULL; 00093 if (TestMFS(pItem, MFS_DEFAULT)) { 00094 if (ghMenuFontDef) 00095 hfnOld = GreSelectFont(hdc, ghMenuFontDef); 00096 else { 00097 tcExtra = GreGetTextCharacterExtra(hdc); 00098 GreSetTextCharacterExtra(hdc, tcExtra + 1 + (gcxMenuFontChar / gpsi->cxSysFontChar)); 00099 } 00100 } 00101 00102 /* 00103 * Compute bitmap dimensions if needed 00104 */ 00105 if (pItem->hbmp != NULL) { 00106 if (pItem->hbmp == HBMMENU_CALLBACK) { 00107 xxxMNGetBitmapSize(pItem, pwndNotify); 00108 } else if (pItem->cxBmp == MNIS_MEASUREBMP) { 00109 if (TestMFS(pItem, MFS_CACHEDBMP)) { 00110 pItem->cxBmp = SYSMET(CXMENUSIZE); 00111 pItem->cyBmp = SYSMET(CYMENUSIZE); 00112 if (pItem->hbmp == HBMMENU_SYSTEM) { 00113 pItem->cxBmp += SYSMET(CXEDGE); 00114 /* 00115 * Chicago/Memphis only stretch the width, 00116 * not the height. NT Bug 124779. FritzS 00117 */ 00118 // pItem->cyBmp += SYSMET(CXEDGE); 00119 } 00120 } else { 00121 if (GreExtGetObjectW(pItem->hbmp, sizeof(BITMAP), (LPSTR)&bmp)) { 00122 pItem->cxBmp = bmp.bmWidth; 00123 pItem->cyBmp = bmp.bmHeight; 00124 } else { 00125 /* 00126 * If the bitmap is not useable, this is as good a default 00127 * as any. 00128 */ 00129 pItem->cxBmp = SYSMET(CXMENUSIZE); 00130 pItem->cyBmp = SYSMET(CYMENUSIZE); 00131 } 00132 } 00133 } 00134 width = pItem->cxBmp; 00135 /* 00136 * Remember the max bitmap width to align the text in all items. 00137 */ 00138 pMenu->cxTextAlign = max(pMenu->cxTextAlign, (DWORD)width); 00139 /* 00140 * In menu bars, we force the item to be at least CYMNSIZE. 00141 * Fixes many, many problems w/ apps that fake own MDI. 00142 */ 00143 if (fPopup) { 00144 height = pItem->cyBmp; 00145 } else { 00146 height = max((int)pItem->cyBmp, height); 00147 } 00148 } else if (TestMFT(pItem, MFT_OWNERDRAW)) { 00149 // This is an ownerdraw item -- the width and height are stored in 00150 // cxBmp and cyBmp 00151 xxxMNGetBitmapSize(pItem, pwndNotify); 00152 width = pItem->cxBmp; 00153 // 00154 // Ignore height with menu bar now--that's set by user. 00155 // 00156 if (fPopup) { 00157 height = pItem->cyBmp; 00158 // If this item has a popup (hierarchical) menu associated with it, then 00159 // reserve room for the bitmap that tells the user that a hierarchical 00160 // menu exists here. 00161 // B#2966, t-arthb 00162 00163 UserAssert(fPopup == (TestMF(pMenu, MFISPOPUP) != 0)); 00164 00165 width = width + (gcxMenuFontChar << 1); 00166 } 00167 } 00168 00169 if ((pItem->lpstr != NULL) && (!TestMFT(pItem, MFT_OWNERDRAW)) ) { 00170 SIZE size; 00171 00172 /* 00173 * This menu item contains a string 00174 */ 00175 00176 /* 00177 * We want to keep the menu bar height if this isn't a popup. 00178 */ 00179 if (fPopup) { 00180 /* The thickness of mnemonic underscore is CYBORDER and the gap 00181 * between the characters and the underscore is another CYBORDER 00182 */ 00183 height = max(height, gcyMenuFontChar + gcyMenuFontExternLeading + SYSMET(CYEDGE)); 00184 } 00185 00186 lpMenuString = TextPointer(pItem->lpstr); 00187 xRightJustify = FindCharPosition(lpMenuString, TEXT('\t')); 00188 00189 xxxPSMGetTextExtent(hdc, lpMenuString, xRightJustify, &size); 00190 00191 if (width) { 00192 width += MNXSPACE + size.cx; 00193 } else { 00194 width = size.cx; 00195 } 00196 } 00197 00198 if (fPopup && !TestMFT(pItem, MFT_OWNERDRAW)) { 00199 /* 00200 * Add on space for checkmark, then horz spacing for default & disabled 00201 * plus some left margin. 00202 */ 00203 if (TestMF(pMenu, MNS_CHECKORBMP) || !TestMF(pMenu, MNS_NOCHECK)) { 00204 width += gpsi->oembmi[OBI_MENUCHECK].cx; 00205 } 00206 width += MNXSPACE + MNLEFTMARGIN + 2; 00207 height += 2; 00208 } 00209 00210 if (TestMFS(pItem, MFS_DEFAULT)) { 00211 if (hfnOld) 00212 GreSelectFont(hdc, hfnOld); 00213 else 00214 GreSetTextCharacterExtra(hdc, tcExtra); 00215 } 00216 00217 /* 00218 * Loword contains width, high word contains height of item. 00219 */ 00220 lppt->x = width; 00221 lppt->y = height; 00222 00223 return(TestMFT(pItem, MFT_OWNERDRAW)); 00224 } 00225 /***************************************************************************\ 00226 * xxxMenuCompute2 00227 * 00228 * ! 00229 * 00230 * History: 00231 \***************************************************************************/ 00232 00233 int xxxMNCompute( 00234 PMENU pMenu, 00235 PWND pwndNotify, 00236 DWORD yMenuTop, 00237 DWORD xMenuLeft, 00238 DWORD cxMax, 00239 LPDWORD lpdwMenuHeight) 00240 { 00241 UINT cItem; 00242 DWORD cxItem; 00243 DWORD cyItem; 00244 DWORD cyItemKeep; 00245 DWORD yPopupTop; 00246 INT cMaxWidth; 00247 DWORD cMaxHeight; 00248 UINT cItemBegCol; 00249 DWORD temp; 00250 int ret; 00251 PITEM pCurItem; 00252 POINT ptMNItemSize; 00253 BOOL fOwnerDrawItems; 00254 BOOL fMenuBreak; 00255 LPWSTR lpsz; 00256 BOOL fPopupMenu; 00257 DWORD menuHeight = 0; 00258 HDC hdc; 00259 HFONT hOldFont; 00260 PTHREADINFO ptiCurrent = PtiCurrent(); 00261 BOOL fStringAndBitmapItems; 00262 00263 CheckLock(pMenu); 00264 CheckLock(pwndNotify); 00265 00266 /* 00267 * Whoever computes the menu, becomes the owner. 00268 */ 00269 if (pwndNotify != pMenu->spwndNotify) { 00270 Lock(&pMenu->spwndNotify, pwndNotify); 00271 } 00272 00273 00274 if (lpdwMenuHeight != NULL) 00275 menuHeight = *lpdwMenuHeight; 00276 00277 /* 00278 * Empty menus have a height of zero. 00279 */ 00280 ret = 0; 00281 if (pMenu->cItems == 0) 00282 return ret; 00283 00284 hdc = _GetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE); 00285 hOldFont = GreSelectFont(hdc, ghMenuFont); 00286 00287 /* 00288 * Try to make a non-multirow menu first. 00289 */ 00290 pMenu->fFlags &= (~MFMULTIROW); 00291 00292 fPopupMenu = TestMF(pMenu, MFISPOPUP); 00293 00294 if (fPopupMenu) { 00295 00296 /* 00297 * Reset the menu bar height to 0 if this is a popup since we are 00298 * being called from menu.c MN_SIZEWINDOW. 00299 */ 00300 menuHeight = 0; 00301 } else if (pwndNotify != NULL) { 00302 pMenu->cxMenu = cxMax; 00303 } 00304 00305 /* 00306 * Initialize the computing variables. 00307 */ 00308 cMaxWidth = cyItemKeep = 0L; 00309 cItemBegCol = 0; 00310 00311 cyItem = yPopupTop = yMenuTop; 00312 cxItem = xMenuLeft; 00313 00314 pCurItem = (PITEM)&pMenu->rgItems[0]; 00315 /* 00316 * cxTextAlign is used to align the text in all items; this is useful 00317 * in popup menus that mix text only items with bitmap-text items. It's 00318 * set to the max bitmap width plus some spacing. 00319 * Do this for new menus wich use string AND bitmaps on the same item 00320 */ 00321 fStringAndBitmapItems = FALSE; 00322 pMenu->cxTextAlign = 0; 00323 00324 /* 00325 * Process each item in the menu. 00326 */ 00327 fOwnerDrawItems = FALSE; 00328 for (cItem = 0; cItem < pMenu->cItems; cItem++) { 00329 00330 /* 00331 * If it's not a separator, find the dimensions of the object. 00332 */ 00333 if (TestMFT(pCurItem, MFT_SEPARATOR) && 00334 ( !TestMFT(pCurItem, MFT_OWNERDRAW) || 00335 (LOWORD(ptiCurrent->dwExpWinVer) < VER40)) ) { 00336 /* 00337 * If version is less than 4.0 don't test the MFT_OWNERDRAW 00338 * flag. Bug 21922; App MaxEda has both separator and Ownerdraw 00339 * flags on. In 3.51 we didn't test the OwnerDraw flag 00340 */ 00341 00342 // 00343 // This is a separator. It's drawn as wide as the menu area, 00344 // leaving some space above and below. Since the menu area is 00345 // the max of the items' widths, we set our width to 0 so as not 00346 // to affect the result. 00347 // 00348 pCurItem->cxItem = 0; 00349 pCurItem->cyItem = SYSMET(CYMENUSIZE) / 2; 00350 00351 00352 } else { 00353 /* 00354 * Are we using NT5 strings and bitmaps? 00355 */ 00356 fStringAndBitmapItems |= ((pCurItem->hbmp != NULL) && (pCurItem->lpstr != NULL)); 00357 /* 00358 * Get the item's X and Y dimensions. 00359 */ 00360 if (xxxMNItemSize(pMenu, pwndNotify, hdc, pCurItem, fPopupMenu, &ptMNItemSize)) 00361 fOwnerDrawItems = TRUE; 00362 00363 pCurItem->cxItem = ptMNItemSize.x; 00364 pCurItem->cyItem = ptMNItemSize.y; 00365 if (!fPopupMenu && ((pCurItem->hbmp == NULL) || (pCurItem->lpstr != NULL))) { 00366 pCurItem->cxItem += gcxMenuFontChar * 2; 00367 } 00368 } 00369 00370 if (menuHeight != 0) 00371 pCurItem->cyItem = menuHeight; 00372 00373 /* 00374 * If this is the first item, initialize cMaxHeight. 00375 */ 00376 if (cItem == 0) 00377 cMaxHeight = pCurItem->cyItem; 00378 00379 /* 00380 * Is this a Pull-Down menu? 00381 */ 00382 if (fPopupMenu) { 00383 00384 /* 00385 * If this item has a break or is the last item... 00386 */ 00387 if ((fMenuBreak = TestMFT(pCurItem, MFT_BREAK)) || 00388 pMenu->cItems == cItem + (UINT)1) { 00389 00390 /* 00391 * Keep cMaxWidth around if this is not the last item. 00392 */ 00393 temp = cMaxWidth; 00394 if (pMenu->cItems == cItem + (UINT)1) { 00395 if ((int)(pCurItem->cxItem) > cMaxWidth) 00396 temp = pCurItem->cxItem; 00397 } 00398 00399 /* 00400 * Get new width of string from RecalcTabStrings. 00401 */ 00402 temp = MNRecalcTabStrings(hdc, pMenu, cItemBegCol, 00403 (UINT)(cItem + (fMenuBreak ? 0 : 1)), temp, cxItem); 00404 00405 /* 00406 * If this item has a break, account for it. 00407 */ 00408 if (fMenuBreak) { 00409 // 00410 // Add on space for the etch and a border on either side. 00411 // NOTE: For old apps that do weird stuff with owner 00412 // draw, keep 'em happy by adding on the same amount 00413 // of space we did in 3.1. 00414 // 00415 if (fOwnerDrawItems && !TestWF(pwndNotify, WFWIN40COMPAT)) 00416 cxItem = temp + SYSMET(CXBORDER); 00417 else 00418 cxItem = temp + 2 * SYSMET(CXEDGE); 00419 00420 /* 00421 * Reset the cMaxWidth to the current item. 00422 */ 00423 cMaxWidth = pCurItem->cxItem; 00424 00425 /* 00426 * Start at the top. 00427 */ 00428 cyItem = yPopupTop; 00429 00430 /* 00431 * Save the item where this column begins. 00432 */ 00433 cItemBegCol = cItem; 00434 00435 /* 00436 * If this item is also the last item, recalc for this 00437 * column. 00438 */ 00439 if (pMenu->cItems == (UINT)(cItem + 1)) { 00440 temp = MNRecalcTabStrings(hdc, pMenu, cItem, 00441 (UINT)(cItem + 1), cMaxWidth, cxItem); 00442 } 00443 } 00444 00445 /* 00446 * If this is the last entry, supply the width. 00447 */ 00448 if (pMenu->cItems == cItem + (UINT)1) 00449 pMenu->cxMenu = temp; 00450 } 00451 00452 pCurItem->xItem = cxItem; 00453 pCurItem->yItem = cyItem; 00454 00455 cyItem += pCurItem->cyItem; 00456 00457 if (cyItemKeep < cyItem) 00458 cyItemKeep = cyItem; 00459 00460 } else { 00461 00462 /* 00463 * This a Top Level menu, not a Pull-Down. 00464 */ 00465 00466 /* 00467 * Adjust right aligned items before testing for multirow 00468 */ 00469 if (pCurItem->lpstr != NULL) { 00470 lpsz = TextPointer(pCurItem->lpstr); 00471 if ((lpsz != NULL) && (*lpsz == CH_HELPPREFIX)) { 00472 pCurItem->cxItem -= gcxMenuFontChar; 00473 } 00474 } 00475 00476 00477 /* 00478 * If this is a new line or a menu break. 00479 */ 00480 if ((TestMFT(pCurItem, MFT_BREAK)) || 00481 (((cxItem + pCurItem->cxItem + gcxMenuFontChar) > 00482 pMenu->cxMenu) && (cItem != 0))) { 00483 cyItem += cMaxHeight; 00484 00485 cxItem = xMenuLeft; 00486 cMaxHeight = pCurItem->cyItem; 00487 pMenu->fFlags |= MFMULTIROW; 00488 } 00489 00490 pCurItem->yItem = cyItem; 00491 00492 pCurItem->xItem = cxItem; 00493 cxItem += pCurItem->cxItem; 00494 } 00495 00496 if (cMaxWidth < (int)(pCurItem->cxItem)) 00497 cMaxWidth = pCurItem->cxItem; 00498 00499 if (cMaxHeight != pCurItem->cyItem) { 00500 if (cMaxHeight < pCurItem->cyItem) 00501 cMaxHeight = pCurItem->cyItem; 00502 00503 if (!fPopupMenu) 00504 menuHeight = cMaxHeight; 00505 } 00506 00507 if (!fPopupMenu) 00508 cyItemKeep = cyItem + cMaxHeight; 00509 00510 pCurItem++; 00511 00512 } /* of for loop */ 00513 /* 00514 * Determine where the strings should be drawn so they are aligned 00515 * The alignment is only for popup (vertical) menus (see xxxRealDrawMenuItem) 00516 * The actual space depends on the MNS_NOCHECK and MNS_CHECKORBMP styles 00517 * Multicolumn menus don't get aligment (now that we have scrollbars, multicolum is out) 00518 */ 00519 if (!fStringAndBitmapItems || (cItemBegCol != 0)) { 00520 pMenu->cxTextAlign = 0; 00521 } else if (TestMF(pMenu, MNS_NOCHECK)) { 00522 pMenu->cxTextAlign += MNXSPACE; 00523 } else if (TestMF(pMenu, MNS_CHECKORBMP)) { 00524 pMenu->cxTextAlign = max(pMenu->cxTextAlign, (UINT)gpsi->oembmi[OBI_MENUCHECK].cx); 00525 pMenu->cxTextAlign += MNXSPACE; 00526 } else { 00527 pMenu->cxTextAlign += gpsi->oembmi[OBI_MENUCHECK].cx + MNXSPACE; 00528 } 00529 /* 00530 * Add the left margin 00531 */ 00532 if (pMenu->cxTextAlign != 0) { 00533 pMenu->cxTextAlign += MNLEFTMARGIN; 00534 } 00535 00536 00537 if (cItemBegCol && pMenu->cItems && 00538 TestMFT(((PITEM)&pMenu->rgItems[0]), MFT_RIGHTJUSTIFY)) { 00539 // 00540 // multi-column, if we are in RtoL mode, reverse the columns 00541 // 00542 pCurItem = (PITEM)&pMenu->rgItems[0]; 00543 00544 for (cItem = 0; cItem < pMenu->cItems; cItem++) { 00545 pCurItem->xItem = pMenu->cxMenu - 00546 (pCurItem->xItem + pCurItem->cxItem); 00547 pCurItem++; 00548 } 00549 } 00550 00551 GreSelectFont(hdc, hOldFont); 00552 _ReleaseDC(hdc); 00553 00554 pMenu->cyMenu = cyItemKeep - yMenuTop; 00555 ret = pMenu->cyMenu; 00556 00557 if (lpdwMenuHeight != NULL) 00558 *lpdwMenuHeight = menuHeight; 00559 00560 return ret; 00561 } 00562 00563 /***************************************************************************\ 00564 * MBC_RightJustifyMenu 00565 * 00566 * ! 00567 * 00568 * History: 00569 \***************************************************************************/ 00570 00571 void MBC_RightJustifyMenu( 00572 PMENU pMenu) 00573 { 00574 PITEM pItem; 00575 int cItem; 00576 int iFirstRJItem = MFMWFP_NOITEM; 00577 DWORD xMenuPos; 00578 DWORD yPos; 00579 DWORD xPosStart; 00580 DWORD xPosEnd; 00581 int cItemEnd; 00582 int cItemStart; 00583 BOOL bIsWin95; 00584 00585 // 00586 // need to compensate for MDI menus. need to do all here as Win31/Hebrew did 00587 // this. also screwed up computation, anything non-text was not moved. 00588 // 00589 if (pMenu->cItems == 0) 00590 return; 00591 00592 pItem = (PITEM)&pMenu->rgItems[0]; 00593 cItemStart = 0; 00594 00595 if (TestMF(pMenu,MFRTL)) { 00596 bIsWin95 = TestWF(pMenu->spwndNotify, WFWIN40COMPAT); 00597 00598 while( cItemStart < (int)pMenu->cItems ) { 00599 if (bIsWin95) { //(not time critical) 00600 // 00601 // deal with fake MDI dude. 00602 // 00603 if (!cItemStart && IsMDIItem(pItem)) 00604 goto StillFindStart; 00605 else 00606 break; 00607 } 00608 00609 if( TestMFT(pItem, MFT_BITMAP) ) { 00610 if ( pItem->hbmp > (HBITMAP)HBMMENU_MAX ) 00611 break; 00612 else 00613 goto StillFindStart; 00614 } 00615 00616 if (!TestMFT(pItem, MFT_OWNERDRAW) ) 00617 break; 00618 00619 StillFindStart: 00620 cItemStart++; 00621 pItem = pMenu->rgItems + cItemStart; 00622 } 00623 // 00624 // anything before cItems should be left where it is! Now need to find 00625 // the last item to fool with. 00626 // 00627 cItemEnd = pMenu->cItems - 1; 00628 pItem = pMenu->rgItems + cItemEnd; 00629 00630 while( cItemEnd > cItemStart ) { 00631 if (bIsWin95) { 00632 // 00633 // fake mdi dudes 00634 // 00635 if (IsMDIItem(pItem)) 00636 goto StillFindEnd; 00637 else 00638 break; 00639 } 00640 if ( !TestMFT(pItem, MFT_BITMAP) && !TestMFT(pItem, MFT_OWNERDRAW) ) 00641 break; 00642 StillFindEnd: 00643 cItemEnd --; 00644 pItem = pMenu->rgItems + cItemEnd; 00645 } 00646 00647 yPos = pMenu->rgItems[0].yItem; 00648 xMenuPos = pMenu->cxMenu ; 00649 xPosStart = xMenuPos; // for 2nd row onward 00650 xPosEnd = pMenu->rgItems[cItemStart].xItem ; 00651 00652 for (cItem = pMenu->cItems-1; cItem > cItemEnd; cItem--) { 00653 // 00654 // force any MDI dudes back to the top line again. 00655 // 00656 pItem = pMenu->rgItems + cItem; 00657 xMenuPos = 00658 pItem->xItem = xMenuPos - pItem->cxItem; 00659 pItem->yItem = yPos; 00660 } 00661 00662 for( cItem = cItemStart; cItem <= cItemEnd; cItem++ ) { 00663 pItem = pMenu->rgItems + cItem; 00664 if (xMenuPos - pItem->cxItem > xPosEnd) { 00665 xMenuPos -= pItem->cxItem; 00666 } else { 00667 xMenuPos = xPosStart - pItem->cxItem; 00668 yPos += pItem->cyItem; 00669 xPosEnd = 0; 00670 } 00671 pItem->xItem = xMenuPos; 00672 pItem->yItem = yPos; 00673 } 00674 } else { 00675 // B#4055 00676 // Use signed arithmetic so comparison cItem >= iFirstRJItem won't 00677 // cause underflow. 00678 for (cItem = 0; cItem < (int)pMenu->cItems; cItem++) { 00679 // Find the first item which is right justified. 00680 if (TestMFT((pMenu->rgItems + cItem), MFT_RIGHTJUSTIFY)) { 00681 iFirstRJItem = cItem; 00682 xMenuPos = pMenu->cxMenu + pMenu->rgItems[0].xItem; 00683 for (cItem = (int)pMenu->cItems - 1; cItem >= iFirstRJItem; cItem--) { 00684 pItem = pMenu->rgItems + cItem; 00685 xMenuPos -= pItem->cxItem; 00686 if (pItem->xItem < xMenuPos) 00687 pItem->xItem = xMenuPos; 00688 } 00689 return; 00690 } 00691 } 00692 } 00693 } 00694 00695 /***************************************************************************\ 00696 * xxxMenuBarCompute 00697 * 00698 * returns the height of the menubar menu. yMenuTop, xMenuLeft, and 00699 * cxMax are used when computing the height/width of top level menu bars in 00700 * windows. 00701 * 00702 * 00703 * History: 00704 \***************************************************************************/ 00705 00706 int xxxMenuBarCompute( 00707 PMENU pMenu, 00708 PWND pwndNotify, 00709 DWORD yMenuTop, 00710 DWORD xMenuLeft, 00711 int cxMax) 00712 { 00713 int size; 00714 /* menuHeight is set by MNCompute when dealing with a top level menu and 00715 * not all items in the menu bar have the same height. Thus, by setting 00716 * menuHeight, MNCompute is called a second time to set every item to the 00717 * same height. The actual value stored in menuHeight is the maximum 00718 * height of all the menu bar items 00719 */ 00720 DWORD menuHeight = 0; 00721 00722 CheckLock(pwndNotify); 00723 CheckLock(pMenu); 00724 00725 size = xxxMNCompute(pMenu, pwndNotify, yMenuTop, xMenuLeft, cxMax, &menuHeight); 00726 00727 if (!TestMF(pMenu, MFISPOPUP)) { 00728 if (menuHeight != 0) { 00729 00730 /* 00731 * Add a border for the multi-row case. 00732 */ 00733 size = xxxMNCompute(pMenu, pwndNotify, yMenuTop, xMenuLeft, 00734 cxMax, &menuHeight); 00735 } 00736 00737 /* 00738 * Right justification of HELP items is only needed on top level 00739 * menus. 00740 */ 00741 MBC_RightJustifyMenu(pMenu); 00742 } 00743 00744 /* 00745 * There's an extra border underneath the menu bar, if it's not empty! 00746 */ 00747 return(size ? size + SYSMET(CYBORDER) : size); 00748 } 00749 00750 /***************************************************************************\ 00751 * xxxRecomputeMenu 00752 * 00753 * ! 00754 * 00755 * History: 00756 \***************************************************************************/ 00757 00758 void xxxMNRecomputeBarIfNeeded( 00759 PWND pwndNotify, 00760 PMENU pMenu) 00761 { 00762 int cxFrame; 00763 int cyFrame; 00764 00765 UserAssert(!TestMF(pMenu, MFISPOPUP)); 00766 00767 CheckLock(pwndNotify); 00768 CheckLock(pMenu); 00769 00770 if (!TestMF(pMenu, MFSYSMENU) 00771 && ((pMenu->spwndNotify != pwndNotify) || !pMenu->cxMenu || !pMenu->cyMenu)) { 00772 int cBorders; 00773 00774 cBorders = GetWindowBorders(pwndNotify->style, pwndNotify->ExStyle, TRUE, FALSE); 00775 cxFrame = cBorders * SYSMET(CXBORDER); 00776 cyFrame = cBorders * SYSMET(CYBORDER); 00777 00778 cyFrame += GetCaptionHeight(pwndNotify); 00779 00780 // The width passed in this call was larger by cxFrame; 00781 // Fix for Bug #11466 - Fixed by SANKAR - 01/06/92 -- 00782 xxxMenuBarCompute(pMenu, pwndNotify, cyFrame, cxFrame, 00783 (pwndNotify->rcWindow.right - pwndNotify->rcWindow.left) - cxFrame * 2); 00784 } 00785 } 00786 00787 /***************************************************************************\ 00788 * RecalcTabStrings 00789 * 00790 * ! 00791 * 00792 * History: 00793 * 10-11-90 JimA Translated from ASM 00794 \***************************************************************************/ 00795 00796 DWORD MNRecalcTabStrings( 00797 HDC hdc, 00798 PMENU pMenu, 00799 UINT iBeg, 00800 UINT iEnd, 00801 DWORD xTab, 00802 DWORD hCount) 00803 { 00804 UINT i; 00805 UINT cOwnerDraw; 00806 int adx; 00807 int maxWidth = 0; 00808 int cx; 00809 PITEM pItem; 00810 CheckLock(pMenu); 00811 00812 xTab += hCount; 00813 00814 if ((iBeg >= pMenu->cItems) || (iBeg > iEnd)) 00815 goto SeeYa; 00816 00817 cOwnerDraw = 0; 00818 00819 for (i = iBeg, pItem = pMenu->rgItems + iBeg; i < iEnd; pItem++, i++) { 00820 adx = 0; 00821 00822 /* 00823 * Subtract hCount to make dxTab relative to start of column for 00824 * multi-column menus. 00825 */ 00826 00827 pItem->dxTab = xTab - hCount; 00828 00829 // Skip non-string or empty string items 00830 if ((pItem->lpstr != NULL) && !TestMFT(pItem, MFT_OWNERDRAW)) { 00831 LPWSTR lpString = TextPointer(pItem->lpstr); 00832 int tp; 00833 SIZE size; 00834 00835 // Are there any tabs? 00836 tp = FindCharPosition(lpString, TEXT('\t')); 00837 if (tp < (int) pItem->cch) { 00838 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00839 00840 if (CALL_LPK(ptiCurrent)) { 00841 xxxClientGetTextExtentPointW(hdc, lpString + tp + 1, 00842 pItem->cch - tp - 1, &size); 00843 } else { 00844 GreGetTextExtentW(hdc, lpString + tp + 1, 00845 pItem->cch - tp - 1, &size, GGTE_WIN3_EXTENT); 00846 } 00847 adx = gcxMenuFontChar + size.cx; 00848 } 00849 } else if (TestMFT(pItem, MFT_OWNERDRAW)) 00850 cOwnerDraw++; 00851 00852 adx += xTab; 00853 00854 if (adx > maxWidth) 00855 maxWidth = adx; 00856 00857 } 00858 00859 /* 00860 * Add on space for hierarchical arrow. So basically, popup menu items 00861 * can have 4 columns: 00862 * (1) Checkmark 00863 * (2) Text 00864 * (3) Tabbed text for accel 00865 * (4) Hierarchical arrow 00866 * 00867 * But, we only do this if at least one item isn't ownerdraw 00868 * and if there's at least one submenu in the popup. 00869 */ 00870 if (cOwnerDraw != (iEnd - iBeg)) { 00871 maxWidth += gcxMenuFontChar + gpsi->oembmi[OBI_MENUCHECK].cx; 00872 } 00873 00874 cx = maxWidth - hCount; 00875 00876 for (i = iBeg, pItem = pMenu->rgItems + iBeg; i < iEnd; pItem++, i++) 00877 pItem->cxItem = cx; 00878 00879 SeeYa: 00880 return(maxWidth); 00881 } 00882 /***************************************************************************\ 00883 * GetMenuPwnd 00884 * 00885 * This function is used by xxxGetMenuItemRect and xxxMenuItemFromPoint 00886 * which expect a pointer to the menu window for popup menus. 00887 * In 4.0, apps had to go the extra mile to find the menu window; but this 00888 * is bogus since menu windows are an internally thing not directly exposed 00889 * to applications. 00890 * 00891 * 08/19/97 GerardoB Created 00892 \***************************************************************************/ 00893 PWND GetMenuPwnd (PWND pwnd, PMENU pmenu) 00894 { 00895 if (TestMF(pmenu, MFISPOPUP)) { 00896 if ((pwnd == NULL) || (GETFNID(pwnd) != FNID_MENU)) { 00897 PPOPUPMENU ppopup = MNGetPopupFromMenu(pmenu, NULL); 00898 if (ppopup != NULL) { 00899 UserAssert(ppopup->spmenu == pmenu); 00900 pwnd = ppopup->spwndPopupMenu; 00901 } 00902 } 00903 } 00904 return pwnd; 00905 } 00906 // ============================================================================ 00907 // 00908 // GetMenuItemRect() 00909 // 00910 // ============================================================================ 00911 BOOL xxxGetMenuItemRect(PWND pwnd, PMENU pMenu, UINT uIndex, LPRECT lprcScreen) 00912 { 00913 PITEM pItem; 00914 int dx, dy; 00915 00916 CheckLock(pwnd); 00917 CheckLock(pMenu); 00918 00919 SetRectEmpty(lprcScreen); 00920 00921 if (uIndex >= pMenu->cItems) 00922 return(FALSE); 00923 00924 /* 00925 * Raid #315084: Compatiblity with NT4/Win95/98 00926 * 00927 * WordPerfect does a long complex way to calc the menu rect 00928 * by calling this API. It calls GetMenuItemRect() with the app's 00929 * window. 00930 */ 00931 if (pwnd == NULL || TestWF(pwnd, WFWIN50COMPAT)) { 00932 pwnd = GetMenuPwnd(pwnd, pMenu); 00933 } 00934 00935 /* 00936 * If no pwnd, no go. 00937 * IMPORTANT: for MFISPOPUP we might get a different pwnd but we don't lock 00938 * it because we won't call back 00939 */ 00940 if (pwnd == NULL) { 00941 return FALSE; 00942 } 00943 00944 if (TestMF(pMenu, MFISPOPUP)) { 00945 dx = pwnd->rcClient.left; 00946 dy = pwnd->rcClient.top; 00947 } else { 00948 xxxMNRecomputeBarIfNeeded(pwnd, pMenu); 00949 00950 dx = pwnd->rcWindow.left; 00951 dy = pwnd->rcWindow.top; 00952 } 00953 00954 if (uIndex >= pMenu->cItems) 00955 return(FALSE); 00956 00957 pItem = pMenu->rgItems + uIndex; 00958 00959 lprcScreen->right = pItem->cxItem; 00960 lprcScreen->bottom = pItem->cyItem; 00961 00962 OffsetRect(lprcScreen, dx + pItem->xItem, dy + pItem->yItem); 00963 return(TRUE); 00964 } 00965 00966 /***************************************************************************\ 00967 * 00968 * MenuItemFromPoint() 00969 * 00970 \***************************************************************************/ 00971 UINT MNItemHitTest(PMENU pMenu, PWND pwnd, POINT pt); 00972 int xxxMenuItemFromPoint(PWND pwnd, PMENU pMenu, POINT ptScreen) 00973 { 00974 CheckLock(pwnd); 00975 CheckLock(pMenu); 00976 00977 /* 00978 * If no pwnd, no go. 00979 * IMPORTANT: for MFISPOPUP we might get a different pwnd but we don't lock 00980 * it because we won't call back 00981 */ 00982 pwnd = GetMenuPwnd(pwnd, pMenu); 00983 if (pwnd == NULL) { 00984 return MFMWFP_NOITEM; 00985 } 00986 00987 if (!TestMF(pMenu, MFISPOPUP)) { 00988 xxxMNRecomputeBarIfNeeded(pwnd, pMenu); 00989 } 00990 00991 return(MNItemHitTest(pMenu, pwnd, ptScreen)); 00992 } 00993 00994 00995 PMENU MakeMenuRtoL(PMENU pMenu, BOOL bRtoL) 00996 { 00997 PITEM pItem; 00998 int cItem; 00999 01000 if (bRtoL) 01001 SetMF(pMenu,MFRTL); 01002 else 01003 ClearMF(pMenu,MFRTL); 01004 01005 for (cItem = 0; cItem < (int)pMenu->cItems; cItem++) { 01006 pItem = pMenu->rgItems + cItem; 01007 if (bRtoL) { 01008 SetMFT(pItem, MFT_RIGHTJUSTIFY); 01009 SetMFT(pItem, MFT_RIGHTORDER); 01010 } else { 01011 ClearMFT(pItem, MFT_RIGHTJUSTIFY); 01012 ClearMFT(pItem, MFT_RIGHTORDER); 01013 } 01014 if (pItem->spSubMenu) 01015 MakeMenuRtoL(pItem->spSubMenu, bRtoL); 01016 } 01017 return pMenu; 01018 }

Generated on Sat May 15 19:40:51 2004 for test by doxygen 1.3.7