test: mndraw.c Source File

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 }