/****************************** Module Header ******************************\ * Module Name: draw.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains common drawing functions. * * History: * 12-Feb-1992 MikeKe Moved Drawtext to the client side \***************************************************************************/ CONST WCHAR szRadio[] = L"nmlkji"; CONST WCHAR szCheck[] = L"gfedcb"; /***************************************************************************\ * FlipUserTextOutW * * Flip the check mark if the hdc is mirrored otherwise it just calls UserTextOutW * \***************************************************************************/ BOOL FlipUserTextOutW(HDC hdc, int x, int y, LPCWSTR ch, int nCount) { BOOL bRet; int iOldTextAlign, iGraphicsModeOld; if ((UserGetLayout(hdc) & LAYOUT_RTL) && (nCount == 1) && ((ch[0] == TEXT('a')) ||(ch[0] == TEXT('b'))) ) { bRet = FALSE; //Check mark then set the hdc in GM_COMPATIBLE to unmirror it. if (iGraphicsModeOld = UserSetGraphicsMode(hdc, GM_COMPATIBLE)) { iOldTextAlign = UserGetTextAlign(hdc); if ((iOldTextAlign & TA_CENTER) != TA_CENTER) { UserSetTextAlign(hdc, iOldTextAlign^TA_RIGHT); } bRet = UserTextOutW(hdc, x, y, ch, nCount); UserSetGraphicsMode(hdc, iGraphicsModeOld); UserSetTextAlign(hdc, iOldTextAlign); } } else { bRet = UserTextOutW(hdc, x, y, ch, nCount); } return bRet; } /***************************************************************************\ * FillRect * * Callable from either client or server contexts * * History: * 29-Oct-1990 MikeHar Ported from Windows. \***************************************************************************/ int APIENTRY FillRect( HDC hdc, LPCRECT prc, HBRUSH hBrush) { ULONG_PTR iBrush; POLYPATBLT PolyData; iBrush = (ULONG_PTR)hBrush - 1; if (iBrush <= COLOR_ENDCOLORS) { hBrush = SYSHBRUSH(iBrush); } PolyData.x = prc->left; PolyData.y = prc->top; PolyData.cx = prc->right - prc->left; PolyData.cy = prc->bottom - prc->top; PolyData.BrClr.hbr = hBrush; /* * Win95 incompatibility: they return either hBrush or the brush that * was previosuly selected in hdc. Not documented this way though. */ return UserPolyPatBlt(hdc, PATCOPY, &PolyData, 1, PPB_BRUSH); } /***************************************************************************\ * InvertRect * * Can be called from either the client or server contexts. * * History: * 29-Oct-1990 MikeHar Ported from Windows. \***************************************************************************/ BOOL APIENTRY InvertRect( HDC hdc, LPCRECT prc) { return UserPatBlt(hdc, prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top, DSTINVERT); } /***************************************************************************\ * DrawDiagonalLine * * History: \***************************************************************************/ DWORD DrawDiagonalLine( HDC hdc, LPRECT lprc, int iDirection, int iThickness, UINT flags) { RECT rc; LPINT py; int cx; int cy; int dx; int dy; LPINT pc; POLYPATBLT ppbData[8]; int ppbCount = 0; if (IsRectEmpty(lprc)) return 0L; rc = *lprc; /* * We draw slopes < 1 by varying y instead of x. */ --iThickness; /* * See WinBug #139374 */ cy = rc.bottom - rc.top; cx = rc.right - rc.left; if (!flags && (cy != cx)) cy -= iThickness * SYSMETRTL(CYBORDER); if (cy >= cx) { /* * "slope" is >= 1, so vary x by 1 */ cy /= cx; pc = &cy; cx = SYSMETRTL(CXBORDER); } else { /* * "slope" is < 1, so vary y by 1 */ cx /= cy; pc = &cx; cy = SYSMETRTL(CYBORDER); } dx = cx; dy = iDirection * cy; *pc = (*pc + iThickness) * SYSMETRTL(CYBORDER); rc.right -= cx; rc.bottom -= cy; /* * For negative slopes, start from opposite side. */ py = ((iDirection < 0) ? &rc.top : &rc.bottom); while ((rc.left <= rc.right) && (rc.top <= rc.bottom)) { if (!(flags & BF_MIDDLE)) { /* * UserPatBlt(hdc, rc.left, *py, cx, cy, PATCOPY); */ ppbData[ppbCount].x = rc.left; ppbData[ppbCount].y = *py; ppbData[ppbCount].cx = cx; ppbData[ppbCount].cy = cy; ppbData[ppbCount].BrClr.hbr = NULL; ppbCount++; } else { /* * Fill interior. We can determine vertex in interior * by vector define. */ if (cy > SYSMETRTL(CYBORDER)) { if (flags & BF_LEFT) { /* * UserPatBlt(hdc, rc.left, lprc->top, cx, *py - lprc->top + cy, PATCOPY); */ ppbData[ppbCount].x = rc.left; ppbData[ppbCount].y = lprc->top; ppbData[ppbCount].cx = cx; ppbData[ppbCount].cy = *py - lprc->top + cy; ppbData[ppbCount].BrClr.hbr = NULL; ppbCount++; } else { /* * UserPatBlt(hdc, rc.left, *py, cx, lprc->bottom - *py, PATCOPY); */ ppbData[ppbCount].x = rc.left; ppbData[ppbCount].y = *py; ppbData[ppbCount].cx = cx; ppbData[ppbCount].cy = lprc->bottom - *py; ppbData[ppbCount].BrClr.hbr = NULL; ppbCount++; } } else { if (flags & BF_TOP) { /* * UserPatBlt(hdc, rc.left, *py, lprc->right - rc.left, cy, PATCOPY); */ ppbData[ppbCount].x = rc.left; ppbData[ppbCount].y = *py; ppbData[ppbCount].cx = lprc->right - rc.left; ppbData[ppbCount].cy = cy; ppbData[ppbCount].BrClr.hbr = NULL; ppbCount++; } else { /* * UserPatBlt(hdc, lprc->left, *py, rc.left - lprc->left + cx, cy, PATCOPY); */ ppbData[ppbCount].x = lprc->left; ppbData[ppbCount].y = *py; ppbData[ppbCount].cx = rc.left - lprc->left + cx; ppbData[ppbCount].cy = cy; ppbData[ppbCount].BrClr.hbr = NULL; ppbCount++; } } } rc.left += dx; *py -= dy; /* * do we need to flush PolyPatBlt ? */ if (ppbCount == 8) { UserPolyPatBlt(hdc, PATCOPY, &ppbData[0], 8, PPB_BRUSH); ppbCount = 0; } } /* * any left-over PolyPatblt buffered operations? */ if (ppbCount != 0) { UserPolyPatBlt(hdc, PATCOPY, &ppbData[0], ppbCount, PPB_BRUSH); } return MAKELONG(cx, cy); } /***************************************************************************\ * FillTriangle * * Fills in the triangle whose sides are two rectangle edges and a * diagonal. The vertex in the interior can be determined from the * vector type. * * History: \***************************************************************************/ BOOL FillTriangle( HDC hdc, LPRECT lprc, HBRUSH hbr, UINT flags) { HBRUSH hbrT; int nDirection; switch (flags & (BF_RECT | BF_DIAGONAL)) { case BF_DIAGONAL_ENDTOPLEFT: case BF_DIAGONAL_ENDBOTTOMRIGHT: nDirection = -1; break; default: nDirection = 1; break; } hbrT = UserSelectBrush(hdc, hbr); DrawDiagonalLine(hdc, lprc, nDirection, 1, flags); /* * Don't care if the above functions failed for a bad hdc */ return (UserSelectBrush(hdc, hbrT) != NULL); } /***************************************************************************\ * DrawDiagonal * * Called by DrawEdge() for BF_DIAGONAL edges. * * Draws line of slope 1, one of 4 different ones. The difference is * where the line starts and where the end point is. The BF_ flags for * BF_DIAGONAL specify where the end point is. For example, BF_DIAGONAL | * BF_TOP | BF_LEFT means to draw a line ending up at the top left corner. * So the origin must be bottom right, and the angle must be 3pi/4, or * 135 degrees. * * History: \***************************************************************************/ BOOL DrawDiagonal( HDC hdc, LPRECT lprc, HBRUSH hbrTL, HBRUSH hbrBR, UINT flags) { HBRUSH hbrT; int nDirection; DWORD dAdjust; /* * Away from light source */ hbrT = ((flags & BF_BOTTOM) ? hbrBR : hbrTL); switch (flags & (BF_RECT | BF_DIAGONAL)){ case BF_DIAGONAL_ENDTOPLEFT: case BF_DIAGONAL_ENDBOTTOMRIGHT: nDirection = -1; break; default: nDirection = 1; break; } hbrT = UserSelectBrush(hdc, hbrT); dAdjust = DrawDiagonalLine(hdc, lprc, nDirection, 1, (flags & ~BF_MIDDLE)); /* * Adjust rectangle for next border */ if (flags & BF_TOP) lprc->left += LOWORD(dAdjust); else lprc->right -= LOWORD(dAdjust); if (flags & BF_RIGHT) lprc->top += HIWORD(dAdjust); else lprc->bottom -= HIWORD(dAdjust); /* * Moved this to the end to save a check for return value */ return (UserSelectBrush(hdc, hbrT) != NULL); } /***************************************************************************\ * DrawGrip * * History: \***************************************************************************/ BOOL DrawGrip( HDC hdc, LPRECT lprc, UINT wState) { int x; int y; int c; HBRUSH hbrOld; DWORD rgbHilight; DWORD rgbShadow; DWORD rgbOld; POLYPATBLT PolyData; c = min((lprc->right - lprc->left), (lprc->bottom - lprc->top)); x = lprc->right - c; // right justify y = lprc->bottom - c; // bottom justify /* * Setup colors */ if (wState & (DFCS_FLAT | DFCS_MONO)) { hbrOld = SYSHBR(WINDOW); rgbHilight = SYSRGBRTL(WINDOWFRAME); rgbShadow = SYSRGBRTL(WINDOWFRAME); } else { hbrOld = SYSHBR(3DFACE); rgbHilight = SYSRGBRTL(3DHILIGHT); rgbShadow = SYSRGBRTL(3DSHADOW); } PolyData.x = lprc->left; PolyData.y = lprc->top; PolyData.cx = lprc->right-lprc->left; PolyData.cy = lprc->bottom-lprc->top; PolyData.BrClr.hbr = hbrOld; UserPolyPatBlt(hdc, PATCOPY, &PolyData, 1, PPB_BRUSH); rgbOld = UserSetTextColor(hdc, rgbHilight); if (wState & DFCS_SCROLLSIZEGRIPRIGHT) { UserTextOutW(hdc, x, y, L"x", 1); UserSetTextColor(hdc, rgbShadow); UserTextOutW(hdc, x, y, L"y", 1); } else { UserTextOutW(hdc, x, y, L"o", 1); UserSetTextColor(hdc, rgbShadow); UserTextOutW(hdc, x, y, L"p", 1); } UserSetTextColor(hdc, rgbOld); return TRUE; } /***************************************************************************\ * DrawBox * * History: \***************************************************************************/ BOOL DrawBox( HDC hdc, LPRECT lprc, UINT wControlState) { int cx; int cy; int c; int x; int y; LPCWSTR lp = szRadio; int i; BOOL fSkip0thItem; COLORREF clr[6]; COLORREF clrOld; fSkip0thItem = ((wControlState & (DFCS_BUTTON3STATE | DFCS_PUSHED | DFCS_INACTIVE | DFCS_CHECKED)) == (DFCS_BUTTON3STATE | DFCS_CHECKED)); /* * Don't need radio mask with marlett font! */ if (wControlState & DFCS_BUTTONRADIOMASK) { clr[0] = clr[1] = clr[2] = clr[3] = clr[4] = 0L; FillRect(hdc, lprc, ghbrWhite); } else { /* * DFCS_BUTTONRADIOIMAGE */ if (wControlState & (DFCS_MONO | DFCS_FLAT)) { clr[1] = clr[2] = clr[3] = clr[4] = SYSRGBRTL(WINDOWFRAME); } else { clr[1] = SYSRGBRTL(3DLIGHT); clr[2] = SYSRGBRTL(3DDKSHADOW); clr[3] = SYSRGBRTL(3DHILIGHT); clr[4] = SYSRGBRTL(3DSHADOW); } if (wControlState & (DFCS_PUSHED | DFCS_INACTIVE)) clr[0] = SYSRGBRTL(3DFACE); else if (fSkip0thItem) clr[0] = SYSRGBRTL(3DHILIGHT); else clr[0] = SYSRGBRTL(WINDOW); if (wControlState & DFCS_BUTTONRADIOIMAGE) FillRect(hdc, lprc, ghbrBlack); else if (!(wControlState & DFCS_BUTTONRADIO)) lp = szCheck; } cx = lprc->right - lprc->left; cy = lprc->bottom - lprc->top; c = min(cx,cy); x = lprc->left + ((cx - c) / 2); // - 1; y = lprc->top + ((cy - c) / 2); if (fSkip0thItem && ((gpsi->BitCount < 8) || (SYSRGB(3DHILIGHT) == RGB(255,255,255)))) { COLORREF clrBk; POLYPATBLT PolyData; /* * Make the interior of a 3State checkbox which is just checked a * dither, just like an indeterminate push button which is pressed. */ clrBk = UserSetBkColor(hdc, SYSRGB(3DHILIGHT)); clrOld = UserSetTextColor(hdc, SYSRGB(3DFACE)); PolyData.x = x; PolyData.y = y; PolyData.cx = cx; PolyData.cy = cy; PolyData.BrClr.hbr = gpsi->hbrGray; UserPolyPatBlt(hdc, PATCOPY, &PolyData, 1, PPB_BRUSH); UserSetBkColor(hdc, clrBk); } else { clrOld = UserSetTextColor(hdc, clr[0]); UserTextOutW(hdc, x, y, lp, 1); } lp++; for (i = 1; i < 5; i++) { UserSetTextColor(hdc, clr[i]); UserTextOutW(hdc, x, y, lp++, 1); } if (wControlState & DFCS_CHECKED) { COLORREF clrCheck; if (wControlState & (DFCS_BUTTON3STATE | DFCS_INACTIVE)) { clrCheck = SYSRGBRTL(3DSHADOW); } else if (wControlState & DFCS_HOT) { clrCheck = SYSRGBRTL(HOTLIGHT); } else { clrCheck = SYSRGBRTL(WINDOWTEXT); } UserSetTextColor(hdc, clrCheck); FlipUserTextOutW(hdc, x, y, lp, 1); } UserSetTextColor(hdc, clrOld); return TRUE; } /***************************************************************************\ * GetCaptionChar * * History: * 04/02/97 GerardoB Created \***************************************************************************/ WCHAR GetCaptionChar (UINT wState) { wState &= DFCS_CAPTIONALL; switch (wState) { case DFCS_CAPTIONCLOSE: return TEXT('r'); case DFCS_CAPTIONMIN: return TEXT('0'); case DFCS_CAPTIONMAX: return TEXT('1'); case DFCS_CAPTIONRESTORE: return TEXT('2'); /* case DFCS_CAPTIONHELP: */ default: return TEXT('s'); } } /***************************************************************************\ * DrawMenuMark * * History: \***************************************************************************/ BOOL DrawMenuMark( HDC hdc, LPRECT lprc, UINT wType, UINT wState) { COLORREF rgbOld; int x; int y; int c; int cx; int cy; WCHAR ch; cx = lprc->right - lprc->left; cy = lprc->bottom - lprc->top; c = min(cx,cy); x = lprc->left + ((cx - c) / 2) - ((cx > 0xb) ? 1 : 0); y = lprc->top + ((cy - c) / 2); FillRect(hdc, lprc, ghbrWhite); rgbOld = UserSetTextColor(hdc, 0L); if (wType == DFC_MENU) { if (wState & DFCS_MENUCHECK) { ch = TEXT('a'); } else if (wState & DFCS_MENUBULLET) { ch = TEXT('h'); } else if (wState & DFCS_MENUARROWRIGHT) { ch = TEXT('w'); } else { ch = TEXT('8'); } } else { UserAssert(wType == DFC_POPUPMENU); ch = GetCaptionChar(wState); } FlipUserTextOutW(hdc, x, y, &ch, 1); UserSetTextColor(hdc, rgbOld); return TRUE; } /***************************************************************************\ * DrawIt * * History: \***************************************************************************/ BOOL DrawIt( HDC hdc, LPRECT lprc, UINT wState, WCHAR ch) { COLORREF rgb; int x; int y; int c; int cx; int cy; BOOL fDrawDisabled = wState & DFCS_INACTIVE; cx = lprc->right - lprc->left; cy = lprc->bottom - lprc->top; c = min(cx,cy); x = lprc->left + ((cx - c) / 2); y = lprc->top + ((cy - c) / 2); if (fDrawDisabled) { rgb = SYSRGBRTL(3DHILIGHT); } else if (wState & DFCS_HOT) { rgb = SYSRGBRTL(HOTLIGHT); } else { rgb = SYSRGBRTL(BTNTEXT); } rgb = UserSetTextColor(hdc, rgb); if (wState & (DFCS_INACTIVE | DFCS_PUSHED)) { x++; y++; } UserTextOutW(hdc, x, y, &ch, 1); if (fDrawDisabled) { UserSetTextColor(hdc, SYSRGBRTL(3DSHADOW)); UserTextOutW(hdc, x - 1, y - 1, &ch, 1); } UserSetTextColor(hdc, rgb); return TRUE; } /***************************************************************************\ * DrawScrollArrow * * History: \***************************************************************************/ BOOL DrawScrollArrow( HDC hdc, LPRECT lprc, UINT wControlState) { WCHAR ch = (wControlState & DFCS_SCROLLHORZ) ? TEXT('3') : TEXT('5'); if (wControlState & DFCS_SCROLLMAX) ch++; return DrawIt(hdc, lprc, wControlState, ch); } /***************************************************************************\ * DrawFrameControl * * History: * 03-March-2001 Mohamed Hooked API and created this wrapper. \***************************************************************************/ FUNCLOG4( LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DrawFrameControl, HDC, hdc, LPRECT, lprc, UINT, wType, UINT, wState) BOOL DrawFrameControl( HDC hdc, LPRECT lprc, UINT wType, UINT wState) { /* * There is a note here about the use of _USERK_. DrawFrameControl is present * both in kernel and user mode. Kernel side is not aware of UAH and therefore * this directive protects the kernel side by eliminating all wrappers * and UAH-related code from the kernel version and only exposing it during * the build for user mode. */ #ifndef _USERK_ // Eliminate UAH code in kernel build. BOOL bRet; BEGIN_USERAPIHOOK() bRet = guah.pfnDrawFrameControl(hdc, lprc, wType, wState); END_USERAPIHOOK() return bRet; } /***************************************************************************\ * RealDrawFrameControl * * History: * 03-March-2001 Mohamed Hooked this API and changed to Real* \***************************************************************************/ BOOL RealDrawFrameControl( HDC hdc, LPRECT lprc, UINT wType, UINT wState) { #endif // _USERK_ RECT rc; HFONT hFont; HFONT hOldFont; BOOL fRet = TRUE; int iOldBk; int c; BOOL fButton = FALSE; LOGFONTW lfw; int iGraphicsModeOld = 0; int iOldTextAlign; rc = *lprc; /* * If the hdc is mirrored then set it in GM_ADVANCED mode * to enforce the text to be mirrored. */ if (UserGetLayout(hdc) & LAYOUT_RTL) { if (iGraphicsModeOld = UserSetGraphicsMode(hdc, GM_ADVANCED)) { iOldTextAlign = UserGetTextAlign(hdc); if ((iOldTextAlign & TA_CENTER) != TA_CENTER) { UserSetTextAlign(hdc, iOldTextAlign^TA_RIGHT); } } } /* * Enforce monochrome/flat */ if (gpsi->BitCount == 1) wState |= DFCS_MONO; if (wState & DFCS_MONO) wState |= DFCS_FLAT; if ((wType != DFC_MENU) && (wType != DFC_POPUPMENU) && ((wType != DFC_BUTTON) || (wState & DFCS_BUTTONPUSH)) && ((wType != DFC_SCROLL) || !(wState & (DFCS_SCROLLSIZEGRIP | DFCS_SCROLLSIZEGRIPRIGHT)))) { UINT wBorder = BF_ADJUST; if (wType != DFC_SCROLL) wBorder |= BF_SOFT; UserAssert(DFCS_FLAT == BF_FLAT); UserAssert(DFCS_MONO == BF_MONO); wBorder |= (wState & (DFCS_FLAT | DFCS_MONO)); DrawPushButton(hdc, &rc, wState, wBorder); if (wState & DFCS_ADJUSTRECT) *lprc = rc; fButton = TRUE; } iOldBk = UserSetBkMode(hdc, TRANSPARENT); if (!iOldBk) { /* * return FALSE if the hdc is bogus */ if (iGraphicsModeOld) { UserSetGraphicsMode(hdc, iGraphicsModeOld); UserSetTextAlign(hdc, iOldTextAlign); } return FALSE; } c = min(rc.right - rc.left, rc.bottom - rc.top); if (c <= 0) { if (iGraphicsModeOld){ UserSetGraphicsMode(hdc, iGraphicsModeOld); UserSetTextAlign(hdc, iOldTextAlign); } return FALSE; } RtlZeroMemory(&lfw, sizeof(lfw)); lfw.lfHeight = c; lfw.lfWeight = FW_NORMAL; lfw.lfCharSet = SYMBOL_CHARSET; RtlCopyMemory(lfw.lfFaceName, L"Marlett", sizeof(L"Marlett")); hFont = UserCreateFontIndirectW(&lfw); hOldFont = UserSelectFont(hdc, hFont); if (!fButton) { if ((wType == DFC_MENU) || (wType == DFC_POPUPMENU)) { if (wState & (DFCS_MENUARROWUP | DFCS_MENUARROWDOWN)) { if (!(wState & DFCS_TRANSPARENT)) { POLYPATBLT ppbData; ppbData.x = lprc->left; ppbData.y = lprc->top; ppbData.cx = lprc->right - lprc->left; ppbData.cy = lprc->bottom - lprc->top; ppbData.BrClr.hbr = SYSHBR(MENU); UserPolyPatBlt(hdc, PATCOPY, &ppbData, 1, PPB_BRUSH); } DrawScrollArrow(hdc, &rc, (wState & (DFCS_HOT | DFCS_INACTIVE)) | ((wState & DFCS_MENUARROWUP) ? DFCS_SCROLLUP : DFCS_SCROLLDOWN)); } else { DrawMenuMark(hdc, &rc, wType, wState); } } else if (wType == DFC_BUTTON) { DrawBox(hdc, &rc, wState); } else { // wType == DFC_SCROLL DrawGrip(hdc, lprc, wState); } } else if (wType == DFC_CAPTION) { DrawIt(hdc, &rc, wState, GetCaptionChar(wState)); } else if (wType == DFC_SCROLL) { DrawScrollArrow(hdc, &rc, wState); } else if (wType != DFC_BUTTON) { fRet = FALSE; } if (iGraphicsModeOld){ UserSetGraphicsMode(hdc, iGraphicsModeOld); UserSetTextAlign(hdc, iOldTextAlign); } UserSetBkMode(hdc, iOldBk); UserSelectFont(hdc, hOldFont); UserDeleteObject(hFont); return fRet; } /***************************************************************************\ * DrawEdge * * Draws a 3D edge using 2 3D borders. Adjusts interior rectangle if desired * And fills it if requested. * * Returns: * FALSE if error * * History: * 30-Jan-1991 Laurabu Created. \***************************************************************************/ BOOL DrawEdge( HDC hdc, LPRECT lprc, UINT edge, UINT flags) { HBRUSH hbrTL; HBRUSH hbrBR; RECT rc; UINT bdrType; POLYPATBLT ppbData[4]; UINT ppbCount; BOOL fResult = TRUE; /* * Enforce monochromicity and flatness */ if (gpsi->BitCount == 1) flags |= BF_MONO; if (flags & BF_MONO) flags |= BF_FLAT; rc = *lprc; /* * Draw the border segment(s), and calculate the remaining space as we * go. */ if (bdrType = (edge & BDR_OUTER)) { DrawBorder: /* * Get brushes. Note the symmetry between raised outer, * sunken inner and sunken outer, raised inner. */ if (flags & BF_FLAT) { if (flags & BF_MONO) hbrBR = (bdrType & BDR_OUTER) ? SYSHBR(WINDOWFRAME) : SYSHBR(WINDOW); else hbrBR = (bdrType & BDR_OUTER) ? SYSHBR(3DSHADOW) : SYSHBR(3DFACE); hbrTL = hbrBR; } else { /* * 5 == HILIGHT * 4 == LIGHT * 3 == FACE * 2 == SHADOW * 1 == DKSHADOW */ switch (bdrType) { /* * +2 above surface */ case BDR_RAISEDOUTER: hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DHILIGHT) : SYSHBR(3DLIGHT)); hbrBR = SYSHBR(3DDKSHADOW); // 1 break; /* * +1 above surface */ case BDR_RAISEDINNER: hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DLIGHT) : SYSHBR(3DHILIGHT)); hbrBR = SYSHBR(3DSHADOW); // 2 break; /* * -1 below surface */ case BDR_SUNKENOUTER: hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DDKSHADOW) : SYSHBR(3DSHADOW)); hbrBR = SYSHBR(3DHILIGHT); // 5 break; /* * -2 below surface */ case BDR_SUNKENINNER: hbrTL = ((flags & BF_SOFT) ? SYSHBR(3DSHADOW) : SYSHBR(3DDKSHADOW)); hbrBR = SYSHBR(3DLIGHT); // 4 break; default: return FALSE; } } /* * Draw the sides of the border. NOTE THAT THE ALGORITHM FAVORS THE * BOTTOM AND RIGHT SIDES, since the light source is assumed to be top * left. If we ever decide to let the user set the light source to a * particular corner, then change this algorithm. */ if (flags & BF_DIAGONAL) { fResult = DrawDiagonal(hdc, &rc, hbrTL, hbrBR, flags); } else { /* * reset ppbData index */ ppbCount = 0; /* * Bottom Right edges */ /* * Right */ if (flags & BF_RIGHT) { rc.right -= SYSMETRTL(CXBORDER); ppbData[ppbCount].x = rc.right; ppbData[ppbCount].y = rc.top; ppbData[ppbCount].cx = SYSMETRTL(CXBORDER); ppbData[ppbCount].cy = rc.bottom - rc.top; ppbData[ppbCount].BrClr.hbr = hbrBR; ppbCount++; } /* * Bottom */ if (flags & BF_BOTTOM) { rc.bottom -= SYSMETRTL(CYBORDER); ppbData[ppbCount].x = rc.left; ppbData[ppbCount].y = rc.bottom; ppbData[ppbCount].cx = rc.right - rc.left; ppbData[ppbCount].cy = SYSMETRTL(CYBORDER); ppbData[ppbCount].BrClr.hbr = hbrBR; ppbCount++; } /* * Top Left edges */ /* * Left */ if (flags & BF_LEFT) { ppbData[ppbCount].x = rc.left; ppbData[ppbCount].y = rc.top; ppbData[ppbCount].cx = SYSMETRTL(CXBORDER); ppbData[ppbCount].cy = rc.bottom - rc.top; ppbData[ppbCount].BrClr.hbr = hbrTL; ppbCount++; rc.left += SYSMETRTL(CXBORDER); } /* * Top */ if (flags & BF_TOP) { ppbData[ppbCount].x = rc.left; ppbData[ppbCount].y = rc.top; ppbData[ppbCount].cx = rc.right - rc.left; ppbData[ppbCount].cy = SYSMETRTL(CYBORDER); ppbData[ppbCount].BrClr.hbr = hbrTL; ppbCount++; rc.top += SYSMETRTL(CYBORDER); } /* * Send all queued PatBlts to GDI in one go */ fResult = UserPolyPatBlt(hdc,PATCOPY,&ppbData[0],ppbCount,PPB_BRUSH); } } if (bdrType = (edge & BDR_INNER)) { /* * Strip this so the next time through, bdrType will be 0. * Otherwise, we'll loop forever. */ edge &= ~BDR_INNER; goto DrawBorder; } /* * Select old brush back in, if we changed it. */ /* * Fill the middle & clean up if asked */ if (flags & BF_MIDDLE) { if (flags & BF_DIAGONAL) fResult = FillTriangle(hdc, &rc, ((flags & BF_MONO) ? (HBRUSH)SYSHBR(WINDOW) : (HBRUSH)SYSHBR(3DFACE)), flags); else fResult = FillRect(hdc, &rc, ((flags & BF_MONO) ? (HBRUSH)SYSHBR(WINDOW) : (HBRUSH)SYSHBR(3DFACE))); } if (flags & BF_ADJUST) *lprc = rc; return fResult; } /***************************************************************************\ * DrawPushButton * * Draws a push style button in the given state. Adjusts passed in rectangle * if desired. * * Algorithm: * Depending on the state we either draw * * raised edge (undepressed) * * sunken edge with extra shadow (depressed) * If it is an option push button (a push button that is * really a check button or a radio button like buttons * in tool bars), and it is checked, then we draw it * depressed with a different fill in the middle. * * History: * 05-Feb-19 Laurabu Created. \***************************************************************************/ VOID DrawPushButton( HDC hdc, LPRECT lprc, UINT state, UINT flags) { RECT rc; HBRUSH hbrMiddle; DWORD rgbBack; DWORD rgbFore; BOOL fDither; rc = *lprc; DrawEdge(hdc, &rc, (state & (DFCS_PUSHED | DFCS_CHECKED)) ? EDGE_SUNKEN : EDGE_RAISED, (UINT)(BF_ADJUST | BF_RECT | (flags & (BF_SOFT | BF_FLAT | BF_MONO)))); /* * BOGUS * On monochrome, need to do something to make pushed buttons look * better. */ /* * Fill in middle. If checked, use dither brush (gray brush) with * black becoming normal color. */ fDither = FALSE; if (state & DFCS_CHECKED) { if ((gpsi->BitCount < 8) || (SYSRGBRTL(3DHILIGHT) == RGB(255,255,255))) { hbrMiddle = KHBRUSH_TO_HBRUSH(gpsi->hbrGray); rgbBack = UserSetBkColor(hdc, SYSRGBRTL(3DHILIGHT)); rgbFore = UserSetTextColor(hdc, SYSRGBRTL(3DFACE)); fDither = TRUE; } else { hbrMiddle = SYSHBR(3DHILIGHT); } } else { hbrMiddle = SYSHBR(3DFACE); } FillRect(hdc, &rc, hbrMiddle); if (fDither) { UserSetBkColor(hdc, rgbBack); UserSetTextColor(hdc, rgbFore); } if (flags & BF_ADJUST) *lprc = rc; } /***************************************************************************\ * DrawFrame * * History: \***************************************************************************/ BOOL DrawFrame( HDC hdc, PRECT prc, int clFrame, int cmd) { int x; int y; int cx; int cy; int cxWidth; int cyWidth; HANDLE hbrSave; LONG rop; POLYPATBLT PolyData[4]; x = prc->left; y = prc->top; cxWidth = SYSMETRTL(CXBORDER) * clFrame; cyWidth = SYSMETRTL(CYBORDER) * clFrame; cx = prc->right - x - cxWidth; cy = prc->bottom - y - cyWidth; rop = ((cmd & DF_ROPMASK) ? PATINVERT : PATCOPY); if ((cmd & DF_HBRMASK) == DF_GRAY) { hbrSave = KHBRUSH_TO_HBRUSH(gpsi->hbrGray); } else { UserAssert(((cmd & DF_HBRMASK) >> 3) < COLOR_MAX); hbrSave = SYSHBRUSH((cmd & DF_HBRMASK) >> 3); } PolyData[0].x = x; PolyData[0].y = y; PolyData[0].cx = cxWidth; PolyData[0].cy = cy; PolyData[0].BrClr.hbr = hbrSave; PolyData[1].x = x + cxWidth; PolyData[1].y = y; PolyData[1].cx = cx; PolyData[1].cy = cyWidth; PolyData[1].BrClr.hbr = hbrSave; PolyData[2].x = x; PolyData[2].y = y + cy; PolyData[2].cx = cx; PolyData[2].cy = cyWidth; PolyData[2].BrClr.hbr = hbrSave; PolyData[3].x = x + cx; PolyData[3].y = y + cyWidth; PolyData[3].cx = cxWidth; PolyData[3].cy = cy; PolyData[3].BrClr.hbr = hbrSave; UserPolyPatBlt(hdc, rop, &PolyData[0], 4, PPB_BRUSH); return TRUE; } /***************************************************************************\ * GetSignFromMappingMode * * For the current mapping mode, find out the sign of x from left to right, * and the sign of y from top to bottom. * * History: \***************************************************************************/ BOOL GetSignFromMappingMode ( HDC hdc, PPOINT pptSign) { SIZE sizeViewPortExt; SIZE sizeWindowExt; if (!UserGetViewportExtEx(hdc, &sizeViewPortExt) || !UserGetWindowExtEx(hdc, &sizeWindowExt)) { return FALSE; } pptSign->x = ((sizeViewPortExt.cx ^ sizeWindowExt.cx) < 0) ? -1 : 1; pptSign->y = ((sizeViewPortExt.cy ^ sizeWindowExt.cy) < 0) ? -1 : 1; return TRUE; } /***************************************************************************\ * ClientFrame * * Draw a rectangle * * History: * 19-Jan-1993 MikeKe Created \***************************************************************************/ BOOL ClientFrame( HDC hDC, LPCRECT pRect, HBRUSH hBrush, DWORD patOp, int cxBorder, int cyBorder) { int x; int y; POINT point; POINT ptSign; POLYPATBLT PolyData[4]; if (!GetSignFromMappingMode (hDC, &ptSign)) return FALSE; y = pRect->bottom - (point.y = pRect->top); if (y < 0) { return FALSE; } x = pRect->right - (point.x = pRect->left); /* * Check width and height signs */ if (((x ^ ptSign.x) < 0) || ((y ^ ptSign.y) < 0)) return FALSE; /* * Factor in the thickness of the rectangle to be drawn. This will * automatically offset the edges so that the actual rectangle gets filled * "in" as it becomes thicker. */ ptSign.x *= cxBorder; ptSign.y *= cyBorder; // Top border PolyData[0].x = point.x; PolyData[0].y = point.y; PolyData[0].cx = x; PolyData[0].cy = ptSign.y; PolyData[0].BrClr.hbr = hBrush; // Bottom border point.y = pRect->bottom - ptSign.y; PolyData[1].x = point.x; PolyData[1].y = point.y; PolyData[1].cx = x; PolyData[1].cy = ptSign.y; PolyData[1].BrClr.hbr = hBrush; /* * Left Border * Don't xor the corners twice */ point.y = pRect->top + ptSign.y; y -= 2 * ptSign.y; PolyData[2].x = point.x; PolyData[2].y = point.y; PolyData[2].cx = ptSign.x; PolyData[2].cy = y; PolyData[2].BrClr.hbr = hBrush; // Right Border point.x = pRect->right - ptSign.x; PolyData[3].x = point.x; PolyData[3].y = point.y; PolyData[3].cx = ptSign.x; PolyData[3].cy = y; PolyData[3].BrClr.hbr = hBrush; return UserPolyPatBlt(hDC, patOp, PolyData, sizeof (PolyData) / sizeof (*PolyData), PPB_BRUSH); }