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

mndraw.c

Go to the documentation of this file.
00001 /**************************** Module Header ********************************\ 00002 * Module Name: mndraw.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Menu Painting 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 #define SRCSTENCIL 0x00B8074AL 00018 00019 #define MENU_STRLEN 255 00020 /***************************************************************************\ 00021 * MNIsCachedBmpOnly 00022 * 00023 * 04/02/97 GerardoB Created 00024 \***************************************************************************/ 00025 __inline BOOL MNIsCachedBmpOnly (PITEM pItem) 00026 { 00027 return TestMFS(pItem, MFS_CACHEDBMP) && (pItem->lpstr == NULL); 00028 } 00029 /***************************************************************************\ 00030 * MNDrawHilite 00031 * 00032 * Don't draw the hilite if: 00033 * The insertion bar is on (MFS_GAPDROP) 00034 * or this is a cached bitmap (close, min, max, etc) with no text 00035 * 00036 * 00037 * 08/12/96 GerardoB Ported From Memphis. 00038 \***************************************************************************/ 00039 BOOL mnDrawHilite (PITEM pItem) 00040 { 00041 return TestMFS(pItem, MFS_HILITE) 00042 && !TestMFS(pItem, MFS_GAPDROP) 00043 && !MNIsCachedBmpOnly(pItem); 00044 } 00045 00046 /***************************************************************************\ 00047 * MNDrawMenu3DHotTracking 00048 * 00049 * 03/10/97 yutakas created 00050 * 04/07/97 vadimg ported from Memphis 00051 \***************************************************************************/ 00052 void MNDrawMenu3DHotTracking(HDC hdc, PMENU pMenu, PITEM pItem) 00053 { 00054 HBRUSH hbrTopLeft, hbrBottomRight; 00055 BOOL fDrawEdge; 00056 00057 if (pItem->hbmp && TestMFS(pItem, MFS_CACHEDBMP)) 00058 return; 00059 00060 fDrawEdge = FALSE; 00061 00062 if (!TestMF(pMenu, MFISPOPUP)) { 00063 if (TestMFS(pItem, MFS_HILITE)) { 00064 hbrTopLeft = SYSHBR(3DSHADOW); 00065 hbrBottomRight = SYSHBR(3DHILIGHT); 00066 SetMFS(pItem, MFS_HOTTRACKDRAWN); 00067 fDrawEdge = TRUE; 00068 } else if (TestMFS(pItem, MFS_HOTTRACK)) { 00069 hbrTopLeft = SYSHBR(3DHILIGHT); 00070 hbrBottomRight = SYSHBR(3DSHADOW); 00071 SetMFS(pItem, MFS_HOTTRACKDRAWN); 00072 fDrawEdge = TRUE; 00073 } else if (TestMFS(pItem, MFS_HOTTRACKDRAWN)) { 00074 hbrTopLeft = SYSHBR(MENU); 00075 hbrBottomRight = SYSHBR(MENU); 00076 ClearMFS(pItem, MFS_HOTTRACKDRAWN); 00077 fDrawEdge = TRUE; 00078 } 00079 } 00080 00081 if (fDrawEdge) { 00082 int x = pItem->xItem, y = pItem->yItem; 00083 int cx = pItem->cxItem, cy = pItem->cyItem; 00084 HBRUSH hbrOld = GreSelectBrush(hdc, hbrTopLeft); 00085 GrePatBlt(hdc, x, y, cx - CXMENU3DEDGE, CYMENU3DEDGE, PATCOPY); 00086 GrePatBlt(hdc, x, y, CXMENU3DEDGE, cy - CYMENU3DEDGE, PATCOPY); 00087 GreSelectBrush(hdc, hbrBottomRight); 00088 GrePatBlt(hdc, x, y + cy - CYMENU3DEDGE, cx - CXMENU3DEDGE, CYMENU3DEDGE, PATCOPY); 00089 GrePatBlt(hdc, x + cx - CYMENU3DEDGE, y, CXMENU3DEDGE, cy, PATCOPY); 00090 GreSelectBrush(hdc, hbrOld); 00091 } 00092 } 00093 /***************************************************************************\ 00094 * MNDrawArrow 00095 * 00096 * redraws the specified arrow (uArrow) in a scrollable menu (ppopup) to reflect 00097 * it's current state of enabled or disabled, drawing it in HOTLIGHT if 00098 * fOn is TRUE 00099 * 00100 * 08/12/96 GerardoB Ported From Memphis. 00101 \***************************************************************************/ 00102 void MNDrawArrow(HDC hdcIn, PPOPUPMENU ppopup, UINT uArrow) 00103 { 00104 PWND pwnd = ppopup->spwndPopupMenu; 00105 HDC hdc; 00106 int x, y; 00107 DWORD dwBmp; 00108 DWORD dwAtCheck; 00109 DWORD dwState; 00110 00111 if (ppopup->spmenu->dwArrowsOn == MSA_OFF) { 00112 return; 00113 } 00114 00115 if (hdcIn == NULL) { 00116 hdc = _GetDCEx(pwnd, NULL, DCX_USESTYLE | DCX_WINDOW | DCX_LOCKWINDOWUPDATE); 00117 } else { 00118 hdc = hdcIn; 00119 } 00120 00121 x = SYSMET(CXFIXEDFRAME); 00122 if (!TestMF(ppopup->spmenu, MNS_NOCHECK)) { 00123 /* 00124 * Win9x: x += MNByteAlignItem(oemInfo.bm[OBI_MENUCHECK].cx); 00125 */ 00126 x += gpsi->oembmi[OBI_MENUCHECK].cx; 00127 } else { 00128 x += SYSMET(CXEDGE) * 2; 00129 } 00130 00131 if (uArrow == MFMWFP_UPARROW) { 00132 y = SYSMET(CXFIXEDFRAME); 00133 dwBmp = OBI_MENUARROWUP; 00134 dwAtCheck = MSA_ATTOP; 00135 dwState = DFCS_MENUARROWUP; 00136 } else { 00137 y = pwnd->rcWindow.bottom - pwnd->rcWindow.top - SYSMET(CYFIXEDFRAME) - gcyMenuScrollArrow; 00138 dwBmp = OBI_MENUARROWDOWN; 00139 dwAtCheck = MSA_ATBOTTOM; 00140 dwState = DFCS_MENUARROWDOWN; 00141 } 00142 00143 if (ppopup->spmenu->dwArrowsOn == dwAtCheck) { 00144 /* 00145 * go 2 ahead to inactive state bitmap 00146 */ 00147 dwBmp += 2; 00148 dwState |= DFCS_INACTIVE; 00149 } 00150 00151 if (ppopup->spmenu->hbrBack != NULL) { 00152 /* 00153 * for menus with background brushes, we can't do a straight blt 00154 * of the scroll arrows 'cause the background wouldn't be right; 00155 * need to call DrawFrameControl with DFCS_TRANSPARENT instead 00156 */ 00157 RECT rc; 00158 rc.top = y; 00159 rc.left = x; 00160 rc.right = x + gpsi->oembmi[OBI_MENUARROWUP].cx; 00161 rc.bottom = y + gpsi->oembmi[OBI_MENUARROWUP].cy; 00162 DrawFrameControl(hdc, &rc, DFC_MENU, dwState | DFCS_TRANSPARENT); 00163 } else { 00164 BitBltSysBmp(hdc, x, y, dwBmp); 00165 BitBltSysBmp(hdc, x, y, dwBmp); 00166 } 00167 00168 if (hdcIn == NULL) { 00169 _ReleaseDC(hdc); 00170 } 00171 } 00172 /***************************************************************************\ 00173 * MNDrawFullNC 00174 * 00175 * Performs the custom nonclient painting needed for scrollable menus. 00176 * Assumes that the given menu is a scrollable menu. 00177 * 00178 * History: 00179 * 08-14-96 GerardoB - Ported from Memphis 00180 \***************************************************************************/ 00181 void MNDrawFullNC(PWND pwnd, HDC hdcIn, PPOPUPMENU ppopup) 00182 { 00183 RECT rc; 00184 HDC hdc; 00185 HBRUSH hbrOld; 00186 int yTop, yBottom; 00187 POINT ptOrg; 00188 if (hdcIn == NULL) { 00189 hdc = _GetDCEx(pwnd, NULL, DCX_USESTYLE | DCX_WINDOW | DCX_LOCKWINDOWUPDATE); 00190 } else { 00191 hdc = hdcIn; 00192 } 00193 00194 rc.left = rc.top = 0; 00195 rc.right = pwnd->rcWindow.right - pwnd->rcWindow.left; 00196 rc.bottom = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 00197 DrawEdge(hdc, &rc, EDGE_RAISED, (BF_RECT | BF_ADJUST)); 00198 DrawFrame(hdc, &rc, 1, DF_3DFACE); 00199 InflateRect(&rc, -SYSMET(CXBORDER), -SYSMET(CYBORDER)); 00200 00201 yTop = rc.top; 00202 yBottom = rc.bottom - gcyMenuScrollArrow; 00203 00204 GreGetBrushOrg(hdc, &ptOrg); 00205 if (ppopup->spmenu->hbrBack != NULL) { 00206 GreSetBrushOrg(hdc, 0, 00207 -(int)MNGetToppItem(ppopup->spmenu)->yItem, NULL); 00208 hbrOld = GreSelectBrush(hdc, ppopup->spmenu->hbrBack); 00209 } else { 00210 hbrOld = GreSelectBrush(hdc, SYSHBR(MENU)); 00211 } 00212 00213 rc.right -= rc.left; 00214 GrePatBlt(hdc, rc.left, yTop, rc.right, gcyMenuScrollArrow, PATCOPY); 00215 MNDrawArrow(hdc, ppopup, MFMWFP_UPARROW); 00216 GrePatBlt(hdc, rc.left, yBottom, rc.right, gcyMenuScrollArrow, PATCOPY); 00217 MNDrawArrow(hdc, ppopup, MFMWFP_DOWNARROW); 00218 00219 GreSetBrushOrg(hdc, ptOrg.x, ptOrg.y, NULL); 00220 GreSelectBrush(hdc, hbrOld); 00221 00222 if (hdcIn == NULL) { 00223 _ReleaseDC(hdc); 00224 } 00225 } 00226 /***************************************************************************\ 00227 * MNEraseBackground 00228 * 00229 * Erases the background making sure that the background pattern (i.e, watermark) 00230 * aligns with the pattern in the nonclient area. 00231 * 00232 * History: 00233 * 08-23-96 GerardoB - Created 00234 \***************************************************************************/ 00235 void MNEraseBackground (HDC hdc, PMENU pmenu, int x, int y, int cx, int cy) 00236 { 00237 BOOL fSetOrg; 00238 HBRUSH hbrOld; 00239 POINT ptOrg; 00240 00241 UserAssert(pmenu->hbrBack != NULL); 00242 00243 fSetOrg = TRUE; 00244 GreGetBrushOrg(hdc, &ptOrg); 00245 /* 00246 * If we have scrollbars 00247 */ 00248 if (pmenu->dwArrowsOn != MSA_OFF) { 00249 /* 00250 * If not drawing on the client area only 00251 */ 00252 if (TestMF(pmenu, MFWINDOWDC)) { 00253 ptOrg.x = 0; 00254 ptOrg.y = -(int)MNGetToppItem(pmenu)->yItem; 00255 } else { 00256 ptOrg.x = -MNXBORDER; 00257 ptOrg.y = -MNYBORDER - gcyMenuScrollArrow - MNGetToppItem(pmenu)->yItem; 00258 } 00259 } else { 00260 if (TestMF(pmenu, MFWINDOWDC)) { 00261 ptOrg.x = MNXBORDER; 00262 ptOrg.y = MNYBORDER; 00263 } else { 00264 fSetOrg = FALSE; 00265 } 00266 } 00267 00268 if (fSetOrg) { 00269 GreSetBrushOrg(hdc, ptOrg.x, ptOrg.y, &ptOrg); 00270 } 00271 hbrOld = GreSelectBrush(hdc, pmenu->hbrBack); 00272 00273 GrePatBlt(hdc, x, y, cx, cy, PATCOPY); 00274 00275 if (fSetOrg) { 00276 GreSetBrushOrg(hdc, ptOrg.x, ptOrg.y, NULL); 00277 } 00278 GreSelectBrush(hdc, hbrOld); 00279 } 00280 00281 /***************************************************************************\ 00282 * MNAnimate 00283 * 00284 * If fIterate is TRUE, then perform the next iteration in the menu animation 00285 * sequence. If fIterate is FALSE, terminate the animation sequence. 00286 * 00287 * History: 00288 * 07-23-96 GerardoB - fixed up for 5.0 00289 \***************************************************************************/ 00290 void MNAnimate(PMENUSTATE pMenuState, BOOL fIterate) 00291 { 00292 DWORD dwTimeElapsed; 00293 int x, y, xOff, yOff, xLast, yLast; 00294 00295 if (TestFadeFlags(FADE_MENU)) { 00296 if (!fIterate) { 00297 StopFade(); 00298 } 00299 return; 00300 } 00301 00302 /* 00303 * If we're not animating, bail 00304 */ 00305 if (pMenuState->hdcWndAni == NULL) { 00306 return; 00307 } 00308 00309 /* 00310 * The active popup must be visible. It's supposed to be the 00311 * window we're animating 00312 */ 00313 UserAssert(TestWF(pMenuState->pGlobalPopupMenu->spwndActivePopup, WFVISIBLE)); 00314 00315 /* 00316 * End animation if asked to do so, if it's taking too long 00317 * or someone is waiting for the critical section 00318 */ 00319 dwTimeElapsed = NtGetTickCount() - pMenuState->dwAniStartTime; 00320 if (!fIterate 00321 || (dwTimeElapsed > CMS_QANIMATION) 00322 || (ExGetExclusiveWaiterCount(gpresUser) > 0) 00323 || (ExGetSharedWaiterCount(gpresUser) > 0)) { 00324 00325 GreBitBlt(pMenuState->hdcWndAni, 0, 0, pMenuState->cxAni, pMenuState->cyAni, pMenuState->hdcAni, 00326 0, 0, SRCCOPY | NOMIRRORBITMAP, 0xFFFFFF); 00327 00328 goto AnimationCompleted; 00329 } 00330 00331 /* 00332 * Remember current animation point and calculate new one 00333 */ 00334 xLast = pMenuState->ixAni; 00335 yLast = pMenuState->iyAni; 00336 if (pMenuState->iAniDropDir & PAS_HORZ) { 00337 pMenuState->ixAni = MultDiv(gcxMenuFontChar, dwTimeElapsed, CMS_QANIMATION / 20); 00338 if (pMenuState->ixAni > pMenuState->cxAni) { 00339 pMenuState->ixAni = pMenuState->cxAni; 00340 } 00341 } 00342 00343 if (pMenuState->iAniDropDir & PAS_VERT) { 00344 pMenuState->iyAni = MultDiv(gcyMenuFontChar, dwTimeElapsed, CMS_QANIMATION / 10); 00345 if (pMenuState->iyAni > pMenuState->cyAni) { 00346 pMenuState->iyAni = pMenuState->cyAni; 00347 } 00348 } 00349 00350 /* 00351 * if no change -- bail out 00352 */ 00353 if ((pMenuState->ixAni == xLast) && (pMenuState->iyAni == yLast)) { 00354 return; 00355 } 00356 00357 /* 00358 * Calculate source and dest coordinates 00359 */ 00360 if (pMenuState->iAniDropDir & PAS_LEFT) { 00361 x = pMenuState->cxAni - pMenuState->ixAni; 00362 xOff = 0; 00363 } else { 00364 xOff = pMenuState->cxAni - pMenuState->ixAni; 00365 x = 0; 00366 } 00367 00368 if (pMenuState->iAniDropDir & PAS_UP) { 00369 y = pMenuState->cyAni - pMenuState->iyAni; 00370 yOff = 0; 00371 } else { 00372 yOff = pMenuState->cyAni - pMenuState->iyAni; 00373 y = 0; 00374 } 00375 00376 /* 00377 * Do it 00378 */ 00379 GreBitBlt(pMenuState->hdcWndAni, x, y, pMenuState->ixAni, pMenuState->iyAni, 00380 pMenuState->hdcAni, xOff, yOff, SRCCOPY | NOMIRRORBITMAP, 0xFFFFFF); 00381 00382 /* 00383 * Check if we're done 00384 */ 00385 if ((pMenuState->cxAni == pMenuState->ixAni) 00386 && (pMenuState->cyAni == pMenuState->iyAni)) { 00387 00388 AnimationCompleted: 00389 00390 MNDestroyAnimationBitmap(pMenuState); 00391 _ReleaseDC(pMenuState->hdcWndAni); 00392 pMenuState->hdcWndAni = NULL; 00393 _KillTimer(pMenuState->pGlobalPopupMenu->spwndActivePopup, IDSYS_MNANIMATE); 00394 } 00395 00396 } 00397 00398 /***************************************************************************\ 00399 * DrawMenuItemCheckMark() - 00400 * 00401 * Draws the proper check mark for the given item. Note that ownerdraw 00402 * items should NOT be passed to this procedure, otherwise we'd draw a 00403 * checkmark for them when they are already going to take care of it. 00404 * 00405 * Returns TRUE is a bitmap was drawn (or at least we attempted to draw it). 00406 * 00407 * History: 00408 \***************************************************************************/ 00409 BOOL DrawMenuItemCheckMark(HDC hdc, PITEM pItem, int xPos) 00410 { 00411 int yCenter; 00412 HBITMAP hbm; 00413 DWORD textColorSave; 00414 DWORD bkColorSave; 00415 BOOL fChecked; 00416 POEMBITMAPINFO pOem; 00417 BOOL fRet = TRUE; 00418 DWORD dwFlags = BC_INVERT; 00419 00420 UserAssert(hdc != ghdcMem2); 00421 pOem = gpsi->oembmi + OBI_MENUCHECK; 00422 yCenter = pItem->cyItem - pOem->cy; 00423 if (yCenter < 0) 00424 yCenter = 0; 00425 yCenter /= 2; 00426 00427 fChecked = TestMFS(pItem, MFS_CHECKED); 00428 00429 if (hbm = (fChecked) ? pItem->hbmpChecked : pItem->hbmpUnchecked) { 00430 HBITMAP hbmSave; 00431 00432 // Use the app supplied bitmaps. 00433 if (hbmSave = GreSelectBitmap(ghdcMem2, hbm)) { 00434 00435 textColorSave = GreSetTextColor(hdc, 0x00000000L); 00436 bkColorSave = GreSetBkColor (hdc, 0x00FFFFFFL); 00437 00438 if (TestMFT(pItem, MFT_RIGHTORDER)) 00439 xPos = pItem->cxItem - pOem->cx; 00440 00441 GreBitBlt(hdc, 00442 xPos, 00443 yCenter, 00444 pOem->cx, 00445 pOem->cy, 00446 ghdcMem2, 00447 0, 00448 0, 00449 SRCSTENCIL, 00450 0x00FFFFFF); 00451 00452 GreSetTextColor(hdc, textColorSave); 00453 GreSetBkColor(hdc, bkColorSave); 00454 00455 GreSelectBitmap(ghdcMem2, hbmSave); 00456 } 00457 00458 } else if (fChecked) { 00459 00460 if (TestMFT(pItem, MFT_RADIOCHECK)) 00461 pOem = gpsi->oembmi + OBI_MENUBULLET; 00462 00463 if (TestMFT(pItem, MFT_RIGHTORDER)) 00464 xPos = pItem->cxItem - pOem->cx; 00465 00466 #ifdef USE_MIRRORING 00467 // 389917: Mirror active menu's check mark if hdc is mirroed. 00468 if ((GreGetLayout(hdc) & LAYOUT_RTL) && (hdc != gpDispInfo->hdcGray)) { 00469 dwFlags |= BC_NOMIRROR; 00470 } 00471 #endif 00472 BltColor(hdc, 00473 NULL, 00474 HDCBITS(), 00475 xPos, 00476 yCenter, 00477 pOem->cx, 00478 pOem->cy, 00479 pOem->x, 00480 pOem->y, 00481 dwFlags); 00482 } else { 00483 fRet = FALSE; 00484 } 00485 00486 return fRet; 00487 } 00488 00489 00490 /***************************************************************************\ 00491 * xxxDrawItemtUnderline 00492 * 00493 * Draws or hides an underline for a menu item 00494 * 00495 * 07/23/96 vadimg separated into a separate routine 00496 \***************************************************************************/ 00497 00498 void xxxDrawItemUnderline(PITEM pItem, HDC hdc, int xLeft, int yTop, 00499 LPWSTR pszMenu, LONG lResLo) 00500 { 00501 int cx; 00502 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00503 // 00504 // LOWORD of result is 0xFFFF if there is no underlined character. 00505 // Therefore ulX must be valid or be UNDERLINE_RECALC because the item 00506 // or menu mode changed. 00507 // 00508 // Bail out if there isn't one. 00509 // 00510 if (lResLo == 0xFFFF) 00511 return; 00512 00513 // 00514 // For proportional fonts, or if an LPK is installed, find starting 00515 // point of underline 00516 // 00517 if ((pItem->ulX == UNDERLINE_RECALC) || (PpiCurrent()->dwLpkEntryPoints & LPK_INSTALLED)) { 00518 if (lResLo != 0) { 00519 SIZE size; 00520 00521 if (CALL_LPK(ptiCurrent)) { 00522 xxxClientGetTextExtentPointW(hdc, pszMenu, lResLo, &size); 00523 } else { 00524 GreGetTextExtentW(hdc, pszMenu, lResLo, &size, GGTE_WIN3_EXTENT); 00525 } 00526 pItem->ulX = size.cx - gcxMenuFontOverhang; 00527 } else 00528 pItem->ulX = 0; 00529 } 00530 00531 xLeft += pItem->ulX; 00532 00533 // 00534 // Adjust for proportional font when setting the length of the underline 00535 // and height of text. 00536 // 00537 // Calculate underline width. 00538 if (!pItem->ulWidth) { 00539 SIZE size; 00540 00541 if (CALL_LPK(ptiCurrent)) { 00542 xxxClientGetTextExtentPointW(hdc, pszMenu + lResLo, 1, &size); 00543 } else { 00544 GreGetTextExtentW(hdc, pszMenu + lResLo, 1, &size, GGTE_WIN3_EXTENT); 00545 } 00546 pItem->ulWidth = size.cx - gcxMenuFontOverhang; 00547 } 00548 cx = pItem->ulWidth; 00549 00550 // Get ascent of text (units above baseline) so that underline can be drawn 00551 // below the text 00552 yTop += gcyMenuFontAscent; 00553 00554 // Proper brush should be selected into dc. 00555 GrePatBlt(hdc, xLeft, yTop, pItem->ulWidth, SYSMET(CYBORDER), PATCOPY); 00556 } 00557 00558 /***************************************************************************\ 00559 * 00560 * xxxDrawMenuItemText() 00561 * 00562 * Draws menu text with underline. 00563 * 00564 \***************************************************************************/ 00565 void xxxDrawMenuItemText(PITEM pItem, HDC hdc, int xLeft, int yTop, 00566 LPWSTR lpsz, int cch, BOOL fShowUnderlines) 00567 { 00568 LONG result; 00569 WCHAR szMenu[MENU_STRLEN], *pchOut; 00570 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00571 TL tl; 00572 00573 if (cch > MENU_STRLEN) { 00574 pchOut = (WCHAR*)UserAllocPool((cch+1) * sizeof(WCHAR), TAG_RTL); 00575 if (pchOut == NULL) 00576 return; 00577 ThreadLockPool(ptiCurrent, pchOut, &tl); 00578 } else { 00579 pchOut = szMenu; 00580 } 00581 result = GetPrefixCount(lpsz, cch, pchOut, cch); 00582 00583 if (CALL_LPK(ptiCurrent)) { 00584 xxxClientExtTextOutW(hdc, xLeft, yTop, 0, NULL, pchOut, cch - HIWORD(result), NULL); 00585 } else { 00586 GreExtTextOutW(hdc, xLeft, yTop, 0, NULL, pchOut, cch - HIWORD(result), NULL); 00587 } 00588 00589 if (fShowUnderlines || TEST_BOOL_ACCF(ACCF_KEYBOARDPREF) || TestEffectInvertUP(KEYBOARDCUES) 00590 || (GetAppCompatFlags2(VER40) & GACF2_KCOFF)) { 00591 if (CALL_LPK(ptiCurrent)) { 00592 xxxPSMTextOut(hdc, xLeft, yTop, lpsz, cch, DT_PREFIXONLY); 00593 } else{ 00594 xxxDrawItemUnderline(pItem, hdc, xLeft, yTop, pchOut, LOWORD(result)); 00595 } 00596 } 00597 if (pchOut != szMenu) { 00598 ThreadUnlockAndFreePool(ptiCurrent, &tl); 00599 } 00600 } 00601 00602 /***************************************************************************\ 00603 * xxxSendMenuDrawItemMessage 00604 * 00605 * Sends a WM_DRAWITEM message to the owner of the menu (pMenuState->hwndMenu). 00606 * All state is determined in this routine so HILITE state must be properly 00607 * set before entering this routine.. 00608 * 00609 * Revalidation notes: 00610 * This routine must be called with a valid and non-NULL pwnd. 00611 * Revalidation is not required in this routine: no windows are used after 00612 * potentially leaving the critsect. 00613 * 00614 * History: 00615 \***************************************************************************/ 00616 00617 void xxxSendMenuDrawItemMessage( 00618 HDC hdc, 00619 UINT itemAction, 00620 PMENU pmenu, 00621 PITEM pItem, 00622 BOOL fBitmap, 00623 int iOffset) 00624 { 00625 DRAWITEMSTRUCT dis; 00626 TL tlpwndNotify; 00627 int y; 00628 00629 CheckLock(pmenu); 00630 00631 dis.CtlType = ODT_MENU; 00632 dis.CtlID = 0; 00633 00634 dis.itemID = pItem->wID; 00635 00636 dis.itemAction = itemAction; 00637 dis.itemState = 00638 ((pItem->fState & MF_GRAYED) ? ODS_GRAYED : 0) | 00639 ((pItem->fState & MFS_DEFAULT) ? ODS_DEFAULT : 0) | 00640 ((pItem->fState & MFS_CHECKED) ? ODS_CHECKED : 0) | 00641 ((pItem->fState & MFS_DISABLED) ? ODS_DISABLED : 0) | 00642 (mnDrawHilite(pItem) ? ODS_SELECTED : 0) | 00643 ((pItem->fState & MFS_HOTTRACK) ? ODS_HOTLIGHT : 0) | 00644 (TestMF(pmenu, MFINACTIVE) ? ODS_INACTIVE : 0) | 00645 (!TestMF(pmenu, MFUNDERLINE) ? ODS_NOACCEL : 0); 00646 00647 dis.hwndItem = (HWND)PtoH(pmenu); 00648 dis.hDC = hdc; 00649 00650 y = pItem->yItem; 00651 if (fBitmap) { 00652 y = (pItem->cyItem - pItem->cyBmp) / 2; 00653 } 00654 00655 dis.rcItem.left = iOffset + pItem->xItem; 00656 dis.rcItem.top = y; 00657 dis.rcItem.right = iOffset + pItem->xItem + (fBitmap ? pItem->cxBmp : pItem->cxItem); 00658 dis.rcItem.bottom = y + (fBitmap ? pItem->cyBmp : pItem->cyItem); 00659 dis.itemData = pItem->dwItemData; 00660 00661 if (pmenu->spwndNotify != NULL) { 00662 ThreadLockAlways(pmenu->spwndNotify, &tlpwndNotify); 00663 xxxSendMessage(pmenu->spwndNotify, WM_DRAWITEM, 0, (LPARAM)&dis); 00664 ThreadUnlock(&tlpwndNotify); 00665 } 00666 00667 } 00668 00669 /***************************************************************************\ 00670 * CalcbfExtra 00671 * 00672 * History: 00673 * 08-09-96 GerardoB Made into an inline function (code from xxxMenuDraw) 00674 \***************************************************************************/ 00675 __inline UINT CalcbfExtra (void) 00676 { 00677 if ((SYSRGB(3DHILIGHT) == SYSRGB(MENU)) && (SYSRGB(3DSHADOW) == SYSRGB(MENU))) 00678 return BF_FLAT | BF_MONO; 00679 else 00680 return 0; 00681 } 00682 /***************************************************************************\ 00683 * MNDrawInsertionBar 00684 * 00685 * History: 00686 * 11/21/96 GerardoB Created 00687 \***************************************************************************/ 00688 void MNDrawInsertionBar (HDC hdc, PITEM pItem) 00689 { 00690 BOOL fTop; 00691 POLYPATBLT PolyData [3], *ppd; 00692 00693 /* 00694 * If no insertion bar for this item, bail 00695 */ 00696 fTop = TestMFS(pItem, MFS_TOPGAPDROP); 00697 if (!fTop && !TestMFS(pItem, (MFS_BOTTOMGAPDROP))) { 00698 return; 00699 } 00700 00701 /* 00702 * Vertical line on the left 00703 */ 00704 ppd = PolyData; 00705 ppd->x = pItem->xItem + SYSMET(CXDRAG); 00706 ppd->cx = SYSMET(CXDRAG); 00707 ppd->cy = SYSMET(CYDRAG); 00708 if (fTop) { 00709 ppd->y = pItem->yItem; 00710 } else { 00711 ppd->y = pItem->yItem + pItem->cyItem - ppd->cy; 00712 } 00713 ppd->BrClr.hbr = SYSHBR(HIGHLIGHT); 00714 00715 /* 00716 * Horizontal line in the middle 00717 */ 00718 ppd++; 00719 ppd->x = pItem->xItem + (2 * SYSMET(CXDRAG)); 00720 ppd->cx = pItem->cxItem - (4 * SYSMET(CXDRAG)); 00721 ppd->cy = SYSMET(CYDRAG) / 2; 00722 if (fTop) { 00723 ppd->y = pItem->yItem; 00724 } else { 00725 ppd->y = pItem->yItem + pItem->cyItem - ppd->cy; 00726 } 00727 ppd->BrClr.hbr = PolyData->BrClr.hbr; 00728 00729 /* 00730 * Vertical line on the right 00731 */ 00732 ppd++; 00733 ppd->x = pItem->xItem + pItem->cxItem - (2 * SYSMET(CXDRAG)); 00734 ppd->cx = PolyData->cx; 00735 ppd->cy = PolyData->cy; 00736 ppd->y = PolyData->y; 00737 ppd->BrClr.hbr = PolyData->BrClr.hbr; 00738 00739 GrePolyPatBlt(hdc, PATCOPY, PolyData, 3, PPB_BRUSH); 00740 00741 } 00742 /***************************************************************************\ 00743 * xxxDrawMenuItem 00744 * 00745 * ! 00746 * 00747 * History: 00748 \***************************************************************************/ 00749 00750 void xxxDrawMenuItem( 00751 HDC hdc, 00752 PMENU pMenu, 00753 PITEM pItem, 00754 DWORD dwFlags) 00755 { 00756 BOOL fHilite; 00757 HFONT hfnOld; 00758 int tcExtra; 00759 UINT uFlags; 00760 int iBkSave; 00761 hfnOld = NULL; 00762 uFlags = DST_COMPLEX; 00763 00764 00765 CheckLock(pMenu); 00766 00767 /* 00768 * If the insertion bar is on (MFS_GAPDROP), don't draw the item hilited 00769 */ 00770 fHilite = mnDrawHilite(pItem); 00771 00772 00773 if (TestMFS(pItem, MFS_DEFAULT)) 00774 { 00775 if (ghMenuFontDef != NULL) 00776 hfnOld = GreSelectFont(hdc, ghMenuFontDef); 00777 else 00778 { 00779 uFlags |= DSS_DEFAULT; 00780 tcExtra = GreGetTextCharacterExtra(hdc); 00781 GreSetTextCharacterExtra(hdc, tcExtra + 1 + (gcxMenuFontChar / gpsi->cxSysFontChar)); 00782 } 00783 } 00784 00785 if (TestMFT(pItem, MFT_OWNERDRAW)) { 00786 00787 /* 00788 * If ownerdraw, just set the default menu colors since the app is 00789 * responsible for handling the rest. 00790 */ 00791 GreSetTextColor(hdc, SYSRGB(MENUTEXT)); 00792 GreSetBkColor(hdc, SYSRGB(MENU)); 00793 00794 /* 00795 * Send drawitem message since this is an ownerdraw item. 00796 */ 00797 xxxSendMenuDrawItemMessage(hdc, 00798 (UINT)((dwFlags & DMI_INVERT) ? ODA_SELECT : ODA_DRAWENTIRE), 00799 pMenu, pItem,FALSE,0); 00800 00801 // Draw the hierarchical arrow for the cascade menu. 00802 if (TestMF(pMenu, MFISPOPUP) && (pItem->spSubMenu != NULL)) 00803 { 00804 POEMBITMAPINFO pOem; 00805 HBRUSH hbr = fHilite ? SYSHBR(HIGHLIGHTTEXT) : SYSHBR(MENUTEXT); 00806 00807 pOem = gpsi->oembmi + (TestMFT(pItem, MFT_RIGHTORDER) 00808 ? OBI_MENUARROW_L : OBI_MENUARROW); 00809 00810 // This item has a hierarchical popup associated with it. Draw the 00811 // bitmap dealy to signify its presence. Note we check if fPopup is set 00812 // so that this isn't drawn for toplevel menus that have popups. 00813 00814 BltColor(hdc, 00815 hbr, 00816 HDCBITS(), 00817 TestMFT(pItem, MFT_RIGHTORDER) 00818 ? pItem->xItem + pOem->cx : 00819 pItem->xItem + pItem->cxItem - pOem->cx, 00820 pItem->yItem + max((INT)(pItem->cyItem - 2 - pOem->cy) / 2, 00821 0), 00822 pOem->cx, 00823 pOem->cy, 00824 pOem->x, 00825 pOem->y, 00826 BC_INVERT); 00827 } 00828 } else { 00829 int icolBack; 00830 int icolFore; 00831 GRAYMENU gm; 00832 00833 // 00834 // Setup colors and state 00835 // 00836 if (fHilite && TestMF(pMenu, MFISPOPUP)) { 00837 icolBack = COLOR_HIGHLIGHT; 00838 icolFore = COLOR_HIGHLIGHTTEXT; 00839 } else { 00840 icolBack = COLOR_MENU; 00841 icolFore = COLOR_MENUTEXT; 00842 } 00843 00844 // B#4157 - Lotus doesn't like it if we draw 00845 // its disabled menu items in GRAY, t-arthb 00846 // MAKE SURE MF_GRAYED stays 0x0001 NOT 0x0003 for this to fix 00847 00848 /* 00849 * System bitmaps are already grayed so don't draw them disabled 00850 * if the menu is inactive 00851 */ 00852 if (!MNIsCachedBmpOnly(pItem) 00853 && (TestMFS(pItem, MF_GRAYED) || TestMF(pMenu, MFINACTIVE))) { 00854 // 00855 // Only do embossing if menu color is same as 3D color. The 00856 // emboss uses 3D hilight & 3D shadow, which doesn't look cool 00857 // on a different background. 00858 // 00859 if ((icolBack == COLOR_HIGHLIGHT) || 00860 (SYSRGB(MENU) != SYSRGB(3DFACE)) || SYSMET(SLOWMACHINE)) { 00861 // 00862 // If gray text won't show up on background, then dither. 00863 // 00864 if (SYSRGB(GRAYTEXT) == gpsi->argbSystem[icolBack]) 00865 uFlags |= DSS_UNION; 00866 else 00867 icolFore = COLOR_GRAYTEXT; 00868 } else 00869 { 00870 if ((SYSRGB(3DSHADOW) == SYSRGB(MENU)) && (SYSRGB(3DHILIGHT) == SYSRGB(MENU))) 00871 uFlags |= DSS_UNION; 00872 else 00873 uFlags |= TestMF(pMenu, MFINACTIVE) ? DSS_INACTIVE : DSS_DISABLED; 00874 } 00875 } 00876 00877 GreSetBkColor(hdc, gpsi->argbSystem[icolBack]); 00878 GreSetTextColor(hdc, gpsi->argbSystem[icolFore]); 00879 if (((dwFlags & DMI_INVERT) && (pMenu->hbrBack == NULL)) 00880 || fHilite) { 00881 00882 POLYPATBLT PolyData; 00883 00884 /* 00885 * Only fill the background if we're being called on behalf of 00886 * MNInvertItem. This is so that we don't waste time filling 00887 * the unselected rect when the menu is first pulled down. 00888 * If the menu has a background brush and we were called by 00889 * MNInvertItem, that function will have already taken care of 00890 * filling the background 00891 */ 00892 00893 PolyData.x = pItem->xItem; 00894 PolyData.y = pItem->yItem; 00895 PolyData.cx = pItem->cxItem; 00896 PolyData.cy = pItem->cyItem; 00897 PolyData.BrClr.hbr = SYSHBRUSH(icolBack); 00898 00899 GrePolyPatBlt(hdc, PATCOPY, &PolyData, 1, PPB_BRUSH); 00900 } 00901 00902 if (pMenu->hbrBack != NULL) { 00903 iBkSave = GreSetBkMode(hdc, TRANSPARENT); 00904 } 00905 GreSelectBrush(hdc, SYSHBRUSH(icolFore)); 00906 00907 // 00908 // Draw the image 00909 // 00910 gm.pItem = pItem; 00911 gm.pMenu = pMenu; 00912 00913 xxxDrawState(hdc, 00914 SYSHBRUSH(icolFore), 00915 (LPARAM)(PGRAYMENU)&gm, 00916 pItem->xItem, 00917 pItem->yItem, 00918 pItem->cxItem, 00919 pItem->cyItem, 00920 uFlags); 00921 00922 MNDrawMenu3DHotTracking(hdc, pMenu, pItem); 00923 } 00924 00925 /* 00926 * Draw the drop insertion bar, if any 00927 */ 00928 MNDrawInsertionBar (hdc, pItem); 00929 00930 00931 if (pMenu->hbrBack != NULL) 00932 GreSetBkMode(hdc, iBkSave); 00933 00934 if (TestMFS(pItem, MFS_DEFAULT)) 00935 { 00936 if (hfnOld) 00937 GreSelectFont(hdc, hfnOld); 00938 else 00939 GreSetTextCharacterExtra(hdc, tcExtra); 00940 } 00941 } 00942 00943 extern void SetupFakeMDIAppStuff(PMENU lpMenu, PITEM lpItem); 00944 00945 /***************************************************************************\ 00946 * 00947 * xxxRealDrawMenuItem() 00948 * 00949 * Callback from xxxDrawState() to draw the menu item, either normally or into 00950 * an offscreen bitmp. We don't know where we're drawing, and shouldn't 00951 * have to. 00952 * 00953 \***************************************************************************/ 00954 BOOL CALLBACK xxxRealDrawMenuItem( 00955 HDC hdc, 00956 PGRAYMENU pGray, 00957 int cx, 00958 int cy) 00959 { 00960 PMENU pMenu; 00961 PITEM pItem; 00962 BOOL fPopup; 00963 int cch; 00964 int xLeft; 00965 int yTop; 00966 int tp; 00967 int rp; 00968 LPWSTR lpsz; 00969 int cyTemp; 00970 int xHilite = 0; 00971 int yHilite = 0; 00972 TL tlpwndChild; 00973 PTHREADINFO ptiCurrent = PtiCurrent(); 00974 BOOL fCheckDrawn = FALSE; 00975 int xFarLeft; 00976 // 00977 // BOGUS 00978 // Use cx and cy instead of lpItem->cxItem, lpItem->cyItem to 00979 // speed stuff up. 00980 // 00981 pMenu = pGray->pMenu; 00982 CheckLock(pMenu); 00983 pItem = pGray->pItem; 00984 fPopup = TestMF(pMenu, MFISPOPUP); 00985 00986 if (fPopup) { 00987 xLeft = MNLEFTMARGIN; 00988 if (TestMF(pMenu, MNS_NOCHECK)) { 00989 xLeft += MNXSPACE; 00990 } else { 00991 fCheckDrawn = DrawMenuItemCheckMark(hdc, pItem, xLeft); 00992 if (!TestMF(pMenu, MNS_CHECKORBMP) 00993 || ((pItem->hbmp == NULL) || fCheckDrawn)) { 00994 00995 xLeft += TestMFT(pItem, MFT_RIGHTORDER) 00996 ? 0 : (gpsi->oembmi[OBI_MENUCHECK].cx + MNXSPACE); 00997 } 00998 } 00999 } else { 01000 xLeft = 0; 01001 01002 if (TestMFS(pItem, MFS_HILITE)) { 01003 xHilite = CXMENU3DEDGE; 01004 yHilite = CYMENU3DEDGE; 01005 } 01006 } 01007 01008 /* 01009 * If there is not bitmap or we don't to draw it, go draw the text 01010 */ 01011 if ((pItem->hbmp == NULL) 01012 || (fCheckDrawn 01013 && TestMF(pMenu, MNS_CHECKORBMP))) { 01014 goto RealDrawMenuItemText; 01015 } 01016 01017 /* 01018 * Draw the bitmap 01019 */ 01020 if (TestMFS(pItem, MFS_CACHEDBMP)) { 01021 if (pItem->hbmp == HBMMENU_SYSTEM) { 01022 /* 01023 * Drawing app icon (system menu) 01024 */ 01025 PWND pwndChild; 01026 PICON pIcon = NULL; 01027 UINT cyUse, cxUse; 01028 01029 AintNothingLikeTheRealMDIThing: 01030 if (!(pItem->dwItemData)) 01031 SetupFakeMDIAppStuff(pMenu, pItem); 01032 01033 pwndChild = HMValidateHandleNoRip((HWND)(pItem->dwItemData),TYPE_WINDOW); 01034 if (!pwndChild) 01035 { 01036 // 01037 // Oops, child window isn't valid anymore. Go find 01038 // the new one. 01039 // 01040 if (pItem->dwItemData) 01041 { 01042 pItem->dwItemData = 0; 01043 goto AintNothingLikeTheRealMDIThing; 01044 } 01045 01046 pIcon = NULL; 01047 } 01048 else { 01049 ThreadLock(pwndChild, &tlpwndChild); 01050 pIcon = xxxGetWindowSmIcon(pwndChild, FALSE); 01051 ThreadUnlock(&tlpwndChild); 01052 } 01053 01054 01055 if (!pIcon) 01056 pIcon = SYSICO(WINLOGO); 01057 01058 cyUse = cy - SYSMET(CYEDGE); 01059 cxUse = cx - (SYSMET(CXEDGE) * 2); 01060 /* 01061 * If this is a popup, make sure that no weird 01062 * width/height stretch takes place. 01063 */ 01064 if (fPopup && (cyUse < cxUse)) { 01065 cxUse = cyUse; 01066 } 01067 01068 _DrawIconEx(hdc, xLeft + (SYSMET(CXEDGE) * 2), 01069 SYSMET(CYBORDER), pIcon, cxUse, 01070 cyUse, 0, SYSHBR(MENU), DI_NORMAL); 01071 01072 } else { 01073 /* 01074 * This is a cached bitmap 01075 */ 01076 UINT wBmp; 01077 int xBmpLeft = xLeft; 01078 int y; 01079 POEMBITMAPINFO pOem; 01080 01081 switch ((ULONG_PTR)pItem->hbmp) { 01082 case (ULONG_PTR)HBMMENU_MBAR_RESTORE: 01083 wBmp = OBI_RESTORE_MBAR; 01084 goto DrawSysBmp; 01085 01086 case (ULONG_PTR)HBMMENU_MBAR_MINIMIZE: 01087 wBmp = OBI_REDUCE_MBAR; 01088 xBmpLeft += SYSMET(CXEDGE); 01089 goto DrawSysBmp; 01090 01091 case (ULONG_PTR)HBMMENU_MBAR_CLOSE: 01092 wBmp = OBI_CLOSE_MBAR; 01093 goto DrawSysBmp; 01094 01095 case (ULONG_PTR)HBMMENU_MBAR_CLOSE_D: 01096 wBmp = OBI_CLOSE_MBAR_I; 01097 goto DrawSysBmp2; 01098 01099 case (ULONG_PTR)HBMMENU_MBAR_MINIMIZE_D: 01100 wBmp = OBI_REDUCE_MBAR_I; 01101 xBmpLeft += SYSMET(CXEDGE); 01102 goto DrawSysBmp2; 01103 01104 DrawSysBmp: 01105 /* 01106 * Select proper bitmap based on the item state 01107 */ 01108 if (TestMFS(pItem, MFS_HILITE)) { 01109 wBmp += DOBI_PUSHED; 01110 } 01111 01112 DrawSysBmp2: 01113 BitBltSysBmp(hdc, xBmpLeft, SYSMET(CYEDGE), wBmp); 01114 break; 01115 01116 default: 01117 UserAssert((pItem->hbmp >= HBMMENU_POPUPFIRST) 01118 && (pItem->hbmp <= HBMMENU_POPUPLAST)); 01119 01120 wBmp = OBI_POPUPFIRST + HandleToUlong(pItem->hbmp) - HandleToUlong(HBMMENU_POPUPFIRST); 01121 UserAssert(wBmp < OBI_COUNT); 01122 01123 pOem = gpsi->oembmi + wBmp; 01124 y = (pItem->cyItem - pOem->cy) / 2; 01125 if (y < 0) { 01126 y = 0; 01127 } 01128 BltColor(hdc, NULL, HDCBITS(), xLeft, y, 01129 pOem->cx, pOem->cy, pOem->x, pOem->y, BC_INVERT); 01130 break; 01131 } 01132 01133 } /* if (pItem->hbmp == HBMMENU_SYSTEM) */ 01134 01135 01136 } else if (pItem->hbmp == HBMMENU_CALLBACK) { 01137 /* 01138 * Owner draw bitmap 01139 */ 01140 xxxSendMenuDrawItemMessage(hdc,ODA_DRAWENTIRE, pMenu, pItem, TRUE, xLeft); 01141 01142 } else { 01143 /* 01144 * Drawing a regular bitmap. 01145 */ 01146 01147 int dx, dy; 01148 HBITMAP hbmSave; 01149 01150 // 01151 // Is this the zero'th item in a menu bar that's not all 01152 // bitmaps? Hmm, sounds like it could be a fake MDI dude. 01153 // If it is, use the windows icon instead 01154 // 01155 /* 01156 * Let's fail this for > 4.0 apps so we can get rid of 01157 * this horrible hack someday. The HBMMENU_ constants 01158 * have been made public so people can use them freely. 01159 * 01160 * Note: even if the app is marked as 4.0, he could be 01161 * recompiled and may utilizes the new feature in NT5 menu. 01162 * So just in case, we have to check both dwItemData and lpstr 01163 * so that the menu could have bitmap, dwItemData and a menu string. 01164 * 01165 */ 01166 if (ptiCurrent->dwExpWinVer <= VER40) { 01167 if (pItem->dwItemData && pItem->lpstr == NULL) 01168 goto AintNothingLikeTheRealMDIThing; 01169 else if (!fPopup && 01170 (pItem == pMenu->rgItems) && 01171 (pMenu->cItems > 1) && 01172 !(pMenu->rgItems[1].hbmp) && 01173 (pItem->spSubMenu)) { 01174 RIPMSG0(RIP_WARNING, "Fake MDI detected, using window icon in place of bitmap"); 01175 goto AintNothingLikeTheRealMDIThing; 01176 } 01177 } 01178 01179 UserAssert(hdc != ghdcMem2); 01180 01181 dx = pItem->cxBmp; 01182 01183 if (fPopup) { 01184 dy = pItem->cyBmp; 01185 01186 // 01187 // Center bitmap in middle of item area 01188 // 01189 cyTemp = (pItem->cyItem - dy); 01190 if (cyTemp > 0) 01191 cyTemp = cyTemp / 2; 01192 else 01193 cyTemp = 0; 01194 } else { 01195 dy = max(pItem->cyBmp, SYSMET(CYMENUSIZE)); 01196 cyTemp = 0; 01197 if (pItem->lpstr != NULL) { 01198 xLeft += gcxMenuFontChar; 01199 } 01200 } 01201 01202 if (hbmSave = GreSelectBitmap(ghdcMem2, pItem->hbmp)) { 01203 BITMAP bmp; 01204 // 01205 // Draw the bitmap leaving some room on the left for the 01206 // optional check mark if we are in a popup menu. (as opposed 01207 // to a top level menu bar). 01208 // 01209 // We can do cool stuff with monochrome bitmap itmes 01210 // by merging with the current colors. 01211 // 01212 // If the item is selected and the bitmap isn't monochrome, 01213 // we just invert the thing when we draw it. We can't do 01214 // anything more clever unless we want to convert to 01215 // monochrome. 01216 // 01217 GreExtGetObjectW(pItem->hbmp, sizeof(bmp), (LPSTR)&bmp); 01218 GreBitBlt(hdc, xLeft + xHilite, cyTemp + xHilite, dx, dy, ghdcMem2, 0, 0, 01219 (bmp.bmPlanes * bmp.bmBitsPixel == 1) ? 01220 SRCSTENCIL : 01221 (mnDrawHilite(pItem) ? NOTSRCCOPY : SRCCOPY), 01222 0x00FFFFFF); 01223 GreSelectBitmap(ghdcMem2, hbmSave); 01224 } else { 01225 RIPMSG3(RIP_WARNING, "Menu 0x%08X, item 0x%08X: Tried to draw invalid bitmap 0x%08X", pMenu, pItem, pItem->hbmp) ; 01226 } 01227 } 01228 01229 01230 RealDrawMenuItemText: 01231 if (pItem->lpstr != NULL) { 01232 /* 01233 * We want the text in all popup menu items to be aligned 01234 * if an alignment offset is available. 01235 */ 01236 if (fPopup && (pMenu->cxTextAlign != 0)) { 01237 xLeft = pMenu->cxTextAlign; 01238 } else if (pItem->hbmp != NULL) { 01239 xLeft += pItem->cxBmp + SYSMET(CXEDGE); 01240 } 01241 01242 // This item is a text string item. Display it. 01243 yTop = gcyMenuFontExternLeading; 01244 01245 cyTemp = pItem->cyItem - (gcyMenuFontChar + gcyMenuFontExternLeading + SYSMET(CYBORDER)); 01246 if (cyTemp > 0) 01247 yTop += (cyTemp / 2); 01248 01249 if (!fPopup && (pItem->hbmp == NULL)) { 01250 xLeft += gcxMenuFontChar; 01251 } 01252 01253 lpsz = TextPointer(pItem->lpstr); 01254 if (lpsz!=NULL) { 01255 cch = pItem->cch; 01256 01257 // Even though we no longer support any funky handling of the 01258 // help prefix character, we still need to eat it up if we run 01259 // across it so that the menu item is drawn correctly 01260 if ((*lpsz == CH_HELPPREFIX) && !fPopup) { 01261 // Skip help prefix character. 01262 lpsz++; 01263 cch--; 01264 } 01265 01266 // tp will contain the character position of the \t indicator 01267 // in the menu string. This is where we add a tab to the string. 01268 // 01269 // rp will contain the character position of the \a indicator 01270 // in the string. All text following this is right aligned. 01271 tp = FindCharPosition(lpsz, TEXT('\t')); 01272 rp = FindCharPosition(lpsz, TEXT('\t') - 1); 01273 01274 xFarLeft = pItem->cxItem - (gpsi->oembmi[OBI_MENUCHECK].cx + MNXSPACE); 01275 01276 if (rp && (rp != cch)) { 01277 // Display all the text up to the \a 01278 if (TestMFT(pItem, MFT_RIGHTORDER) && fPopup) { 01279 SIZE extent; 01280 01281 xxxPSMGetTextExtent(hdc, lpsz, rp, &extent); 01282 xLeft = xFarLeft - extent.cx; 01283 } 01284 xxxDrawMenuItemText(pItem, hdc, xLeft + xHilite, yTop + xHilite, lpsz, rp, 01285 TestMF(pMenu, MFUNDERLINE)); 01286 01287 // Do we also have a tab beyond the \a ?? 01288 if (tp > rp + 1) { 01289 SIZE extent; 01290 01291 if (TestMFT(pItem, MFT_RIGHTORDER) && fPopup) { 01292 xLeft = xFarLeft - pItem->dxTab ; 01293 } else { 01294 xxxPSMGetTextExtent(hdc, lpsz + rp + 1, 01295 (UINT)(tp - rp - 1), &extent); 01296 xLeft = (int)(pItem->dxTab - extent.cx); 01297 } 01298 // 01299 // lotus in Hebrew make their menus by putting the 01300 // accelerator on the left and the text on the right 01301 // 01302 xxxPSMTextOut(hdc, xLeft, yTop, (LPWSTR)(lpsz + rp + 1), tp - rp - 1, 01303 TestMF(pMenu, MFUNDERLINE) ? 0 : DT_HIDEPREFIX); 01304 } 01305 } else if (tp && rp == cch) { 01306 // Display text up to the tab position 01307 if (TestMFT(pItem, MFT_RIGHTORDER)) { 01308 SIZE extent; 01309 01310 xxxPSMGetTextExtent(hdc, lpsz, tp, &extent); 01311 xLeft = xFarLeft - extent.cx; 01312 if (!fPopup && (pItem->hbmp == NULL)) { 01313 xLeft += gcxMenuFontChar; 01314 } 01315 } 01316 xxxDrawMenuItemText(pItem, hdc, xLeft + xHilite, yTop + xHilite, lpsz, tp, 01317 TestMF(pMenu, MFUNDERLINE)); 01318 } 01319 01320 // Any text left to display (like after the tab) ?? 01321 if (tp < cch - 1) { 01322 if (TestMFT(pItem, MFT_RIGHTORDER) && fPopup) { 01323 SIZE extent; 01324 01325 xxxPSMGetTextExtent(hdc, lpsz + tp + 1, (int)cch - tp - 1, &extent); 01326 xLeft = pItem->cxItem - pItem->dxTab - extent.cx; 01327 } else { 01328 xLeft = pItem->dxTab + gcxMenuFontChar; 01329 } 01330 xxxPSMTextOut(hdc, xLeft, yTop, lpsz + tp + 1, cch - tp - 1, 01331 TestMF(pMenu, MFUNDERLINE) ? 0 : DT_HIDEPREFIX); 01332 } 01333 } 01334 } 01335 01336 // 01337 // Draw the hierarchical arrow for the cascade menu. 01338 // 01339 if (fPopup && (pItem->spSubMenu != NULL)) { 01340 POEMBITMAPINFO pOem; 01341 01342 pOem = gpsi->oembmi + (TestMFT(pItem, MFT_RIGHTORDER) 01343 ? OBI_MENUARROW_L : OBI_MENUARROW); 01344 01345 // This item has a hierarchical popup associated with it. Draw the 01346 // bitmap dealy to signify its presence. Note we check if fPopup is set 01347 // so that this isn't drawn for toplevel menus that have popups. 01348 01349 BltColor(hdc, 01350 NULL, 01351 HDCBITS(), 01352 TestMFT(pItem, MFT_RIGHTORDER) 01353 ? pOem->cx : 01354 pItem->cxItem - pOem->cx, 01355 max((INT)(pItem->cyItem - 2 - pOem->cy) / 2, 0), 01356 pOem->cx, 01357 pOem->cy, 01358 pOem->x, 01359 pOem->y, 01360 BC_INVERT); 01361 } 01362 01363 return(TRUE); 01364 } 01365 01366 /***************************************************************************\ 01367 * xxxMenuBarDraw 01368 * 01369 * History: 01370 * 11-Mar-1992 mikeke From win31 01371 \***************************************************************************/ 01372 01373 int xxxMenuBarDraw( 01374 PWND pwnd, 01375 HDC hdc, 01376 int cxFrame, 01377 int cyFrame) 01378 { 01379 UINT cxMenuMax; 01380 int yTop; 01381 PMENU pMenu; 01382 BOOL fClipped = FALSE; 01383 TL tlpmenu; 01384 HRGN hrgnVisSave; 01385 HBRUSH hbrT; 01386 CheckLock(pwnd); 01387 01388 /* 01389 * Lock the menu so we can poke around 01390 */ 01391 pMenu = (PMENU)pwnd->spmenu; 01392 if (pMenu == NULL) 01393 return SYSMET(CYBORDER); 01394 01395 /* 01396 * NT5 menus are drawn inactive when the window is not active. 01397 */ 01398 if (TestwndFrameOn(pwnd) || (GetAppCompatFlags2(VER40) & GACF2_ACTIVEMENUS)) { 01399 ClearMF(pMenu, MFINACTIVE); 01400 } else { 01401 SetMF(pMenu, MFINACTIVE); 01402 } 01403 01404 ThreadLock(pMenu, &tlpmenu); 01405 01406 yTop = cyFrame; 01407 yTop += GetCaptionHeight(pwnd); 01408 01409 01410 /* 01411 * Calculate maximum available horizontal real estate 01412 */ 01413 cxMenuMax = (pwnd->rcWindow.right - pwnd->rcWindow.left) - cxFrame * 2; 01414 01415 /* 01416 * If the menu has switched windows, or if either count is 0, 01417 * then we need to recompute the menu width. 01418 */ 01419 if (pwnd != pMenu->spwndNotify || 01420 pMenu->cxMenu == 0 || 01421 pMenu->cyMenu == 0) { 01422 01423 xxxMenuBarCompute(pMenu, pwnd, yTop, cxFrame, cxMenuMax); 01424 } 01425 01426 /* 01427 * If the menu rectangle is wider than allowed, or the 01428 * bottom would overlap the size border, we need to clip. 01429 */ 01430 if (pMenu->cxMenu > cxMenuMax || 01431 (int)(yTop + pMenu->cyMenu) > (int)((pwnd->rcWindow.bottom - pwnd->rcWindow.top) 01432 - cyFrame)) { 01433 01434 /* 01435 * Lock the display while we're playing around with visrgns. Make 01436 * a local copy of the saved-visrgn so it can be restored in case 01437 * we make a callback (i.e. WM_DRAWITEM). 01438 */ 01439 GreLockDisplay(gpDispInfo->hDev); 01440 01441 fClipped = TRUE; 01442 01443 #ifdef LATER 01444 // mikeke don't use the visrgn here if possible 01445 hrgnVisSave = GreCreateRectRgn( 01446 pwnd->rcWindow.left + cxFrame, 01447 pwnd->rcWindow.top, 01448 pwnd->rcWindow.left + cxFrame + cxMenuMax, 01449 pwnd->rcWindow.bottom - cyFrame); 01450 GreExtSelectClipRgn(hdc, hrgnVisSave, RGN_COPY); 01451 GreSetMetaRgn(hdc); 01452 GreDeleteObject(hrgnVisSave); 01453 #else 01454 hrgnVisSave = CreateEmptyRgn(); 01455 GreCopyVisRgn(hdc,hrgnVisSave); 01456 GreIntersectVisRect(hdc, pwnd->rcWindow.left + cxFrame, 01457 pwnd->rcWindow.top, 01458 pwnd->rcWindow.left + cxFrame + cxMenuMax, 01459 pwnd->rcWindow.bottom - cyFrame); 01460 01461 #endif 01462 01463 GreUnlockDisplay(gpDispInfo->hDev); 01464 } 01465 01466 { 01467 POLYPATBLT PolyData[2]; 01468 01469 PolyData[0].x = cxFrame; 01470 PolyData[0].y = yTop; 01471 PolyData[0].cx = pMenu->cxMenu; 01472 PolyData[0].cy = pMenu->cyMenu; 01473 PolyData[0].BrClr.hbr = (pMenu->hbrBack) ? pMenu->hbrBack : SYSHBR(MENU); 01474 01475 PolyData[1].x = cxFrame; 01476 PolyData[1].y = yTop + pMenu->cyMenu; 01477 PolyData[1].cx = pMenu->cxMenu; 01478 PolyData[1].cy = SYSMET(CYBORDER); 01479 PolyData[1].BrClr.hbr = (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI))? SYSHBR(3DFACE) : SYSHBR(WINDOWFRAME); 01480 01481 GrePolyPatBlt(hdc,PATCOPY,&PolyData[0],2,PPB_BRUSH); 01482 01483 // 01484 // Draw menu background in MENU color 01485 // 01486 //hbrT = GreSelectBrush(hdc, SYSHBR(MENU)); 01487 //GrePatBlt(hdc, cxFrame, yTop, pMenu->cxMenu, pMenu->cyMenu, PATCOPY); 01488 01489 // 01490 // Draw border under menu in proper BORDER color 01491 // 01492 //GreSelectBrush(hdc, (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI))? SYSHBR(3DFACE) : SYSHBR(WINDOWFRAME)); 01493 //GrePatBlt(hdc, cxFrame, yTop + pMenu->cyMenu, pMenu->cxMenu, SYSMET(CYBORDER), PATCOPY); 01494 01495 01496 } 01497 01498 /* 01499 * Finally, draw the menu itself. 01500 */ 01501 01502 hbrT = GreSelectBrush(hdc, (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI))? SYSHBR(3DFACE) : SYSHBR(WINDOWFRAME)); 01503 xxxMenuDraw(hdc, pMenu); 01504 GreSelectBrush(hdc, hbrT); 01505 01506 if (fClipped) { 01507 #ifdef LATER 01508 // mikeke don't use the visrgn here if possible 01509 hrgnVisSave = CreateEmptyRgn(); 01510 GreExtSelectClipRgn(hdc, hrgnVisSave, RGN_COPY); 01511 GreSetMetaRgn(hdc); 01512 GreDeleteObject(hrgnVisSave); 01513 #else 01514 GreLockDisplay(gpDispInfo->hDev); 01515 GreSelectVisRgn(hdc, hrgnVisSave, SVR_DELETEOLD); 01516 GreUnlockDisplay(gpDispInfo->hDev); 01517 #endif 01518 } 01519 01520 ThreadUnlock(&tlpmenu); 01521 return(pMenu->cyMenu + SYSMET(CYBORDER)); 01522 } 01523 /***************************************************************************\ 01524 * xxxMenuDraw 01525 * 01526 * Draws the menu 01527 * 01528 * Revalidation notes: 01529 * This routine must be called with a valid and non-NULL pwnd. 01530 * 01531 * History: 01532 \***************************************************************************/ 01533 01534 void xxxMenuDraw( 01535 HDC hdc, 01536 PMENU pmenu) 01537 { 01538 PITEM pItem; 01539 UINT i, cy; 01540 RECT rcItem; 01541 HFONT hFontOld; 01542 UINT bfExtra; 01543 PTHREADINFO ptiCurrent = PtiCurrent(); 01544 UINT oldAlign; 01545 int iBkSave; 01546 POINT ptOrg; 01547 CheckLock(pmenu); 01548 01549 if (pmenu == NULL) { 01550 RIPERR0(ERROR_INVALID_HANDLE, 01551 RIP_WARNING, 01552 "Invalid menu handle \"pmenu\" (NULL) to xxxMenuDraw"); 01553 01554 return; 01555 } 01556 01557 GreGetViewportOrg(hdc, &ptOrg); 01558 hFontOld = GreSelectFont(hdc, ghMenuFont); 01559 01560 oldAlign = GreGetTextAlign(hdc); 01561 if (pmenu->rgItems && TestMFT(pmenu->rgItems, MFT_RIGHTORDER)) 01562 GreSetTextAlign(hdc, oldAlign | TA_RTLREADING); 01563 01564 bfExtra = CalcbfExtra(); 01565 01566 if (pmenu->hbrBack != NULL) { 01567 iBkSave = GreSetBkMode(hdc, TRANSPARENT); 01568 } 01569 01570 if (pmenu->dwArrowsOn != MSA_OFF) { 01571 pItem = MNGetToppItem(pmenu); 01572 GreSetViewportOrg(hdc, ptOrg.x, ptOrg.y - ((int)pItem->yItem), NULL); 01573 i = pmenu->iTop; 01574 } else { 01575 pItem = (PITEM)pmenu->rgItems; 01576 i = 0; 01577 } 01578 01579 cy = 0; 01580 for (; i < pmenu->cItems; i++, pItem++) { 01581 if (TestMFT(pItem, MFT_MENUBARBREAK) && 01582 TestMF(pmenu, MFISPOPUP)) { 01583 01584 // 01585 // Draw a vertical etch. This is done by calling DrawEdge(), 01586 // sunken, with BF_LEFT | BF_RIGHT. 01587 // 01588 if(TestMFT(pItem, MFT_RIGHTORDER) && i) { 01589 // 01590 // going backwards, so the correct place is just before the 01591 // _previous_ item. 01592 // 01593 PITEM pi; 01594 01595 pi = pItem - 1; 01596 rcItem.left = pi->xItem - SYSMET(CXFIXEDFRAME); 01597 rcItem.top = 0; 01598 rcItem.right = pi->xItem - SYSMET(CXBORDER); 01599 rcItem.bottom = pmenu->cyMenu; 01600 } else { 01601 rcItem.left = pItem->xItem - SYSMET(CXFIXEDFRAME); 01602 rcItem.top = 0; 01603 rcItem.right = pItem->xItem - SYSMET(CXBORDER); 01604 rcItem.bottom = pmenu->cyMenu; 01605 } 01606 01607 DrawEdge(hdc, &rcItem, BDR_SUNKENOUTER, BF_LEFT | BF_RIGHT | bfExtra); 01608 } 01609 /* 01610 * If this is a separator, draw it and return. 01611 * If version is less than 4.0 don't test the MFT_OWNERDRAW 01612 * flag. Bug 21922; App MaxEda has both separator and Ownerdraw 01613 * flags on. In 3.51 we didn't test the OwnerDraw flag 01614 */ 01615 if (TestMFT(pItem, MFT_SEPARATOR) 01616 && (!TestMFT(pItem, MFT_OWNERDRAW) 01617 || (LOWORD(ptiCurrent->dwExpWinVer) < VER40))) { 01618 01619 /* 01620 * Draw a horizontal etch. 01621 */ 01622 int yT = pItem->yItem + (pItem->cyItem / 2) - SYSMET(CYBORDER); 01623 RECT rcItem; 01624 01625 rcItem.left = pItem->xItem + 1; 01626 rcItem.top = yT; 01627 rcItem.right = pItem->xItem + pItem->cxItem - 1; 01628 rcItem.bottom = yT + SYSMET(CYEDGE); 01629 01630 DrawEdge(hdc, &rcItem, BDR_SUNKENOUTER, BF_TOP | BF_BOTTOM | bfExtra); 01631 /* 01632 * Draw drop insertion bar, if any. 01633 */ 01634 MNDrawInsertionBar (hdc, pItem); 01635 01636 } else { 01637 xxxDrawMenuItem(hdc, pmenu, pItem, 0); 01638 } 01639 01640 if (pmenu->dwArrowsOn != MSA_OFF) { 01641 cy += pItem->cyItem; 01642 if (cy > pmenu->cyMenu) { 01643 /* 01644 * this is a scrollable menu and the item just drawn falls below 01645 * the bottom of the visible menu -- no need to draw any further 01646 */ 01647 break; 01648 } 01649 } 01650 } /* for (; i < pmenu->cItems; i++, pItem++) */ 01651 01652 if (pmenu->hbrBack != NULL) { 01653 GreSetBkMode(hdc, iBkSave); 01654 } 01655 GreSetViewportOrg(hdc, ptOrg.x, ptOrg.y, NULL); 01656 GreSetTextAlign(hdc, oldAlign); 01657 GreSelectFont(hdc, hFontOld); 01658 01659 } 01660 01661 01662 /***************************************************************************\ 01663 * xxxDrawMenuBar 01664 * 01665 * Forces redraw of the menu bar 01666 * 01667 * History: 01668 \***************************************************************************/ 01669 01670 BOOL xxxDrawMenuBar( 01671 PWND pwnd) 01672 { 01673 CheckLock(pwnd); 01674 01675 if (!TestwndChild(pwnd)) { 01676 xxxRedrawFrame(pwnd); 01677 } 01678 01679 return TRUE; 01680 } 01681 01682 01683 /***************************************************************************\ 01684 * xxxMenuInvert 01685 * 01686 * Invert menu item 01687 * 01688 * Revalidation notes: 01689 * This routine must be called with a valid and non-NULL pwnd. 01690 * 01691 * fOn - TRUE if the item is selected thus it needs to be inverted 01692 * fNotify - TRUE if the parent should be notified (as appropriate), FALSE 01693 * if we are just redrawing the selected item. 01694 * 01695 * History: 01696 \***************************************************************************/ 01697 PITEM xxxMNInvertItem( 01698 PPOPUPMENU ppopupmenu, 01699 PMENU pmenu, 01700 int itemNumber, 01701 PWND pwndNotify, 01702 BOOL fOn) 01703 { 01704 PITEM pItem = NULL; 01705 HDC hdc; 01706 int y, iNewTop; 01707 RECT rcItem; 01708 BOOL fSysMenuIcon = FALSE; 01709 PMENU pmenusys; 01710 BOOL fClipped = FALSE; 01711 HFONT hOldFont; 01712 HRGN hrgnVisSave; 01713 PWND pwnd; 01714 POINT ptOrg; 01715 TL tlpwnd; 01716 UINT oldAlign; 01717 01718 CheckLock(pmenu); 01719 CheckLock(pwndNotify); 01720 01721 /* 01722 * If we are in the middle of trying to get out of menu mode, hMenu 01723 * and/or pwndNotify will be NULL, so just bail out now. 01724 */ 01725 if ((pmenu == NULL) || (pwndNotify == NULL)) { 01726 return NULL; 01727 } 01728 01729 01730 /* 01731 * If ppopupmenu is NULL, we're not in menu mode (i.e, call from 01732 * HiliteMenuItem). 01733 */ 01734 if (ppopupmenu == NULL) { 01735 pwnd = pwndNotify; 01736 } else { 01737 pwnd = ppopupmenu->spwndPopupMenu; 01738 } 01739 01740 if (pwnd != pwndNotify) { 01741 ThreadLock(pwnd, &tlpwnd); 01742 } 01743 01744 01745 if (itemNumber < 0) { 01746 01747 if (ppopupmenu != NULL) { 01748 if ((itemNumber == MFMWFP_UPARROW) || (itemNumber == MFMWFP_DOWNARROW)) { 01749 MNDrawArrow(NULL, ppopupmenu, itemNumber); 01750 } 01751 } 01752 01753 xxxSendMenuSelect(pwndNotify, pwnd, pmenu, itemNumber); 01754 goto SeeYa; 01755 } 01756 01757 if (!TestMF(pmenu, MFISPOPUP)) { 01758 pmenusys = xxxGetSysMenuHandle(pwndNotify); 01759 if (pmenu == pmenusys) { 01760 MNPositionSysMenu(pwndNotify, pmenusys); 01761 fSysMenuIcon = TRUE; 01762 } 01763 } 01764 01765 if ((UINT)itemNumber >= pmenu->cItems) 01766 goto SeeYa; 01767 01768 pItem = &pmenu->rgItems[itemNumber]; 01769 01770 if (!TestMF(pmenu, MFISPOPUP) && TestWF(pwndNotify, WFMINIMIZED)) { 01771 01772 /* 01773 * Skip inverting top level menus if the window is iconic. 01774 */ 01775 goto SeeYa; 01776 } 01777 01778 /* 01779 * Is this a separator? 01780 */ 01781 if (TestMFT(pItem, MFT_SEPARATOR)) { 01782 goto SendSelectMsg; 01783 } 01784 01785 if ((BOOL)TestMFS(pItem, MFS_HILITE) == (BOOL)fOn) { 01786 01787 /* 01788 * Item's state isn't really changing. Just return. 01789 */ 01790 goto SeeYa; 01791 } 01792 01793 if (fOn && (ppopupmenu != NULL) && (pmenu->dwArrowsOn != MSA_OFF)) { 01794 /* 01795 * when selecting an item, ensure that the item is fully visible 01796 * BUGBUG -- for mouse use, partially visible should be acceptable 01797 * -- can we get mouse info down this far ? 01798 */ 01799 01800 if (itemNumber < pmenu->iTop) { 01801 iNewTop = itemNumber; 01802 goto NewTop; 01803 } else { 01804 PITEM pWalk = MNGetToppItem(pmenu); 01805 int dy = pItem->yItem + pItem->cyItem - pWalk->yItem - pmenu->cyMenu; 01806 iNewTop = pmenu->iTop; 01807 while ((dy > 0) && (iNewTop < (int)pmenu->cItems)) { 01808 dy -= pWalk->cyItem; 01809 pWalk++; 01810 iNewTop++; 01811 } 01812 if (iNewTop >= (int)pmenu->cItems) { 01813 iNewTop = pmenu->cItems; 01814 } 01815 NewTop: 01816 if (xxxMNSetTop(ppopupmenu, iNewTop)) { 01817 xxxUpdateWindow(pwnd); 01818 } 01819 } 01820 } 01821 01822 rcItem.left = pItem->xItem; 01823 rcItem.top = pItem->yItem; 01824 rcItem.right = pItem->xItem + pItem->cxItem; 01825 rcItem.bottom = pItem->yItem + pItem->cyItem; 01826 01827 y = pItem->cyItem; 01828 01829 if (TestMF(pmenu, MFISPOPUP)) { 01830 hdc = _GetDC(pwnd); 01831 } else { 01832 hdc = _GetWindowDC(pwnd); 01833 if ( TestWF(pwnd, WFSIZEBOX) && !fSysMenuIcon) { 01834 01835 /* 01836 * If the window is small enough that some of the menu bar has been 01837 * obscured by the frame, we don't want to draw on the bottom of the 01838 * sizing frame. Note that we don't want to do this if we are 01839 * inverting the system menu icon since that will be clipped to the 01840 * window rect. (otherwise we end up with only half the sys menu 01841 * icon inverted) 01842 */ 01843 int xMenuMax = (pwnd->rcWindow.right - pwnd->rcWindow.left) - SYSMET(CXSIZEFRAME); 01844 01845 if (rcItem.right > xMenuMax || 01846 rcItem.bottom > ((pwnd->rcWindow.bottom - 01847 pwnd->rcWindow.top) - SYSMET(CYSIZEFRAME))) { 01848 01849 /* 01850 * Lock the display while we're playing around with visrgns. 01851 * Make a local copy of the visrgn, so that it can be 01852 * properly restored on potential callbacks (i.e. WM_DRAWITEM). 01853 */ 01854 GreLockDisplay(gpDispInfo->hDev); 01855 01856 fClipped = TRUE; 01857 01858 #ifdef LATER 01859 // mikeke - don't use the visrgn here if possible 01860 hrgnVisSave = GreCreateRectRgn( 01861 pwnd->rcWindow.left + rcItem.left, 01862 pwnd->rcWindow.top + rcItem.top, 01863 pwnd->rcWindow.left + xMenuMax, 01864 pwnd->rcWindow.bottom - SYSMET(CYSIZEFRAME)); 01865 GreExtSelectClipRgn(hdc, hrgnVisSave, RGN_COPY); 01866 GreSetMetaRgn(hdc); 01867 GreDeleteObject(hrgnVisSave); 01868 #else 01869 hrgnVisSave = CreateEmptyRgn(); 01870 GreCopyVisRgn(hdc,hrgnVisSave); 01871 GreIntersectVisRect(hdc, 01872 pwnd->rcWindow.left + rcItem.left, 01873 pwnd->rcWindow.top + rcItem.top, 01874 pwnd->rcWindow.left + xMenuMax, 01875 pwnd->rcWindow.bottom - SYSMET(CYSIZEFRAME)); 01876 #endif 01877 01878 GreUnlockDisplay(gpDispInfo->hDev); 01879 } 01880 } 01881 } 01882 01883 oldAlign = GreGetTextAlign(hdc); 01884 if (pItem && TestMFT(pItem, MFT_RIGHTORDER)) 01885 GreSetTextAlign(hdc, oldAlign | TA_RTLREADING); 01886 01887 hOldFont = GreSelectFont(hdc, ghMenuFont); 01888 GreGetViewportOrg(hdc, &ptOrg); 01889 01890 if (fOn) { 01891 SetMFS(pItem, MFS_HILITE); 01892 } else { 01893 ClearMFS(pItem, MFS_HILITE); 01894 } 01895 01896 if (!fSysMenuIcon 01897 && ((pItem->hbmp != HBMMENU_SYSTEM) 01898 || (TestMF(pmenu, MFISPOPUP)))) { 01899 01900 if (pmenu->dwArrowsOn != MSA_OFF) { 01901 GreSetViewportOrg(hdc, ptOrg.x, ptOrg.y - ((int)MNGetToppItem(pmenu)->yItem), NULL); 01902 } 01903 01904 if ((pmenu->hbrBack != NULL) 01905 && !mnDrawHilite(pItem) 01906 && !TestMFT(pItem, MFT_OWNERDRAW)) { 01907 01908 /* 01909 * fill the background here so xxxDrawMenuItem doesn't have to fool 01910 * around with hbrBack 01911 */ 01912 int iBkSave = GreSetBkMode(hdc, TRANSPARENT); 01913 MNEraseBackground (hdc, pmenu, 01914 pItem->xItem, pItem->yItem, 01915 pItem->cxItem, pItem->cyItem); 01916 GreSetBkMode(hdc, iBkSave); 01917 } 01918 01919 xxxDrawMenuItem(hdc, pmenu, pItem, DMI_INVERT); 01920 } 01921 01922 01923 if (fClipped) { 01924 GreLockDisplay(gpDispInfo->hDev); 01925 GreSelectVisRgn(hdc, hrgnVisSave, SVR_DELETEOLD); 01926 GreUnlockDisplay(gpDispInfo->hDev); 01927 } 01928 01929 GreSelectFont(hdc, hOldFont); 01930 GreSetViewportOrg(hdc, ptOrg.x, ptOrg.y, NULL); 01931 GreSetTextAlign(hdc, oldAlign); 01932 _ReleaseDC(hdc); 01933 01934 SendSelectMsg: 01935 /* 01936 * send select msg only if we are selecting an item. 01937 */ 01938 if (fOn) { 01939 xxxSendMenuSelect(pwndNotify, pwnd, pmenu, itemNumber); 01940 } 01941 01942 SeeYa: 01943 if (pwnd != pwndNotify) { 01944 ThreadUnlock(&tlpwnd); 01945 } 01946 01947 return(pItem); 01948 } 01949 01950 /***************************************************************************\ 01951 * 01952 * xxxDrawMenuBarTemp() 01953 * 01954 * This is so the control panel can let us do the work -- and make their 01955 * preview windows that much more accurate. The only reason I put the hwnd in 01956 * here is because, in the low level menu routines, we assume that an hwnd is 01957 * associated with the hmenu -- I didn't want to slow that code down by adding 01958 * NULL checks. 01959 * 01960 * The SYSMET(CYMENU) with regard to the given font is returned -- this 01961 * way control panel can say, "The user wants this menu font (hfont) with this 01962 * menu height (lprc)", and we can respond "this is the height we ended up 01963 * using." 01964 * 01965 * NOTE: It's OK to overrite lprc because this function receives a pointer 01966 * to the rectangle captured in NtUserDrawMenuBarTemp. 01967 * 01968 * History: 01969 * 20-Sep-95 BradG Ported from Win95 (inctlpan.c) 01970 \***************************************************************************/ 01971 01972 int xxxDrawMenuBarTemp( 01973 PWND pwnd, 01974 HDC hdc, 01975 LPRECT lprc, 01976 PMENU pMenu, 01977 HFONT hfont) 01978 { 01979 int cyMenu; 01980 HFONT hOldFont; 01981 HFONT hFontSave; 01982 int cxCharSave; 01983 int cxOverhangSave; 01984 int cyCharSave; 01985 int cyLeadingSave; 01986 int cyAscentSave; 01987 int cySizeSave; 01988 PWND pwndNotify; 01989 TL tlpwndNotify; 01990 01991 hFontSave = ghMenuFont; 01992 cxCharSave = gcxMenuFontChar; 01993 cxOverhangSave = gcxMenuFontOverhang; 01994 cyCharSave = gcyMenuFontChar; 01995 cyLeadingSave = gcyMenuFontExternLeading; 01996 cyAscentSave = gcyMenuFontAscent; 01997 cySizeSave = SYSMET(CYMENUSIZE); 01998 01999 CheckLock(pwnd); 02000 CheckLock(pMenu); 02001 02002 ThreadLock(pMenu->spwndNotify, &tlpwndNotify); 02003 pwndNotify = pMenu->spwndNotify; 02004 02005 cyMenu = lprc->bottom - lprc->top; 02006 02007 if (hfont) { 02008 TEXTMETRIC textMetrics; 02009 02010 /* 02011 * Compute the new menu font info if needed 02012 */ 02013 ghMenuFont = hfont; 02014 hOldFont = GreSelectFont(HDCBITS(), ghMenuFont); 02015 gcxMenuFontChar = GetCharDimensions( 02016 HDCBITS(), &textMetrics, &gcyMenuFontChar); 02017 02018 gcxMenuFontOverhang = textMetrics.tmOverhang; 02019 GreSelectFont(HDCBITS(), hOldFont); 02020 02021 #if 0 // FYI: #254237 removing KOR hack 02022 if (gSystemCPCharSet == HANGUL_CHARSET) { 02023 gcyMenuFontChar -= textMetrics.tmInternalLeading - 2; 02024 } 02025 #endif 02026 02027 gcyMenuFontExternLeading = textMetrics.tmExternalLeading; 02028 02029 gcyMenuFontAscent = textMetrics.tmAscent + SYSMET(CYBORDER); 02030 } 02031 02032 cyMenu -= SYSMET(CYBORDER); 02033 cyMenu = max(cyMenu, (gcyMenuFontChar + gcyMenuFontExternLeading + SYSMET(CYEDGE))); 02034 SYSMET(CYMENUSIZE) = cyMenu; 02035 SYSMET(CYMENU) = cyMenu + SYSMET(CYBORDER); 02036 02037 /* 02038 * Compute the dimensons of the menu (hope that we don't leave the 02039 * USER critical section) 02040 */ 02041 xxxMenuBarCompute(pMenu, pwnd, lprc->top, lprc->left, lprc->right); 02042 02043 /* 02044 * Draw menu border in menu color 02045 */ 02046 lprc->bottom = lprc->top + pMenu->cyMenu; 02047 FillRect(hdc, lprc, SYSHBR(MENU)); 02048 02049 /* 02050 * Finally, draw the menu itself. 02051 */ 02052 xxxMenuDraw(hdc, pMenu); 02053 02054 /* 02055 * Restore the old state 02056 */ 02057 ghMenuFont = hFontSave; 02058 gcxMenuFontChar = cxCharSave; 02059 gcxMenuFontOverhang = cxOverhangSave; 02060 gcyMenuFontChar = cyCharSave; 02061 gcyMenuFontExternLeading = cyLeadingSave; 02062 gcyMenuFontAscent = cyAscentSave; 02063 SYSMET(CYMENUSIZE) = cySizeSave; 02064 02065 cyMenu = SYSMET(CYMENU); 02066 SYSMET(CYMENU) = cySizeSave + SYSMET(CYBORDER); 02067 02068 Lock(&pMenu->spwndNotify, pwndNotify); 02069 ThreadUnlock(&tlpwndNotify); 02070 02071 return cyMenu; 02072 } 02073 02074 /***************************************************************************\ 02075 * DrawBarUnderlines 02076 * 02077 * Description: Shows or hides all underlines on a menu bar. 02078 * 02079 * History: 02080 * 07/23/96 vadimg created 02081 \***************************************************************************/ 02082 void xxxDrawMenuBarUnderlines(PWND pwnd, BOOL fShow) 02083 { 02084 HDC hdc; 02085 PMENU pmenu; 02086 PITEM pitem; 02087 ULONG i, yTop, cyTemp; 02088 LPWSTR psz; 02089 WCHAR szMenu[MENU_STRLEN], *pchOut; 02090 LONG result; 02091 HBRUSH hbr; 02092 TL tlmenu; 02093 PTHREADINFO ptiCurrent = PtiCurrentShared(); 02094 int xLeft; 02095 LPWSTR lpsz; 02096 SIZE extent; 02097 02098 CheckLock(pwnd); 02099 02100 /* 02101 * Bail if menu underlines are always on. 02102 */ 02103 if (TEST_BOOL_ACCF(ACCF_KEYBOARDPREF) || TestEffectInvertUP(KEYBOARDCUES) 02104 || (GetAppCompatFlags2(VER40) & GACF2_KCOFF)) { 02105 return; 02106 } 02107 02108 // if there is no menu, bail out right away 02109 02110 pwnd = GetTopLevelWindow(pwnd); 02111 if (pwnd == NULL || !TestWF(pwnd, WFMPRESENT)) 02112 return; 02113 /* 02114 * We don't clear WFMPRESENT when the menu is unlocked so make sure we have one 02115 */ 02116 pmenu = pwnd->spmenu; 02117 if (pmenu == NULL) { 02118 return; 02119 } 02120 02121 /* 02122 * set/clear the underline state. There are cases when the 02123 * menu loop doesn't remove the keys from the queue; so after 02124 * exiting we might get here but nothing needs to be drawn 02125 */ 02126 if (fShow) { 02127 if (TestMF(pmenu, MFUNDERLINE)) { 02128 return; 02129 } 02130 hbr = SYSHBR(MENUTEXT); 02131 SetMF(pmenu, MFUNDERLINE); 02132 } else { 02133 if (!TestMF(pmenu, MFUNDERLINE)) { 02134 return; 02135 } 02136 if (pmenu->hbrBack != NULL) { 02137 hbr = pmenu->hbrBack; 02138 } else { 02139 hbr = SYSHBR(MENU); 02140 } 02141 ClearMF(pmenu, MFUNDERLINE); 02142 } 02143 02144 pitem = (PITEM)pmenu->rgItems; 02145 02146 hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE); 02147 02148 // select in the correct brush and font 02149 02150 GreSelectFont(hdc, ghMenuFont); 02151 02152 ThreadLock(pmenu, &tlmenu); 02153 for (i = 0; i < pmenu->cItems; i++, pitem++) { 02154 if (((psz = TextPointer(pitem->lpstr)) == NULL) 02155 && !TestMFT(pitem, MFT_OWNERDRAW)) { 02156 continue; 02157 } 02158 02159 if (TestMFT(pitem, MFT_OWNERDRAW)) { 02160 GreSetViewportOrg(hdc, 0, 0, NULL); 02161 } else { 02162 GreSetViewportOrg(hdc, pitem->xItem, pitem->yItem, NULL); 02163 } 02164 02165 // this funky xLeft and yTop calculation stolen from RealDrawMenuItem 02166 02167 yTop = gcyMenuFontExternLeading; 02168 cyTemp = pitem->cyItem - (gcyMenuFontChar + gcyMenuFontExternLeading + 02169 SYSMET(CYBORDER)); 02170 if (cyTemp > 0) { 02171 yTop += (cyTemp / 2); 02172 } 02173 02174 if (fShow && TestMFS(pitem, MFS_HOTTRACK)) { 02175 GreSelectBrush(hdc, SYSHBR(HOTLIGHT)); 02176 } else { 02177 GreSelectBrush(hdc, hbr); 02178 } 02179 02180 if (TestMFT(pitem, MFT_OWNERDRAW)) { 02181 xxxSendMenuDrawItemMessage(hdc, ODA_DRAWENTIRE, pmenu, pitem, FALSE, 0); 02182 } else { 02183 TL tl; 02184 02185 if (pitem->cch > MENU_STRLEN) { 02186 pchOut = (WCHAR*)UserAllocPool((pitem->cch+1) * sizeof(WCHAR), TAG_RTL); 02187 if (pchOut == NULL) 02188 return; 02189 ThreadLockPool(ptiCurrent, pchOut, &tl); 02190 } else { 02191 pchOut = szMenu; 02192 } 02193 02194 xLeft = gcxMenuFontChar; 02195 02196 if ( TestMFT(pitem, MFT_RIGHTORDER) && 02197 ((lpsz = TextPointer(pitem->lpstr)) != NULL)) 02198 { 02199 xxxPSMGetTextExtent(hdc, lpsz, pitem->cch, &extent); 02200 xLeft += (pitem->cxItem - (gpsi->oembmi[OBI_MENUCHECK].cx + MNXSPACE) - extent.cx); 02201 } 02202 02203 if (CALL_LPK(ptiCurrent)) { 02204 if (!fShow) { 02205 //Becuase PSMTextOut does not use PatBlt it uses ExtTextOut. 02206 GreSetTextColor(hdc, SYSRGB(MENU)); 02207 } 02208 xxxPSMTextOut(hdc, xLeft, yTop, psz, pitem->cch, DT_PREFIXONLY); 02209 02210 } else { 02211 result = GetPrefixCount(psz, pitem->cch, pchOut, pitem->cch); 02212 xxxDrawItemUnderline(pitem, hdc, xLeft, yTop, pchOut, 02213 LOWORD(result)); 02214 } 02215 if (pchOut != szMenu) { 02216 ThreadUnlockAndFreePool(ptiCurrent, &tl); 02217 } 02218 } 02219 } 02220 ThreadUnlock(&tlmenu); 02221 02222 _ReleaseDC(hdc); 02223 }

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