|
|
/****************************** Module Header ******************************\
* Module Name: caption.c (aka wmcap.c) * * Copyright (c) 1985 - 1999, Microsoft Corporation * * History: * 28-Oct-1990 MikeHar Ported functions from Win 3.0 sources. * 01-Feb-1991 MikeKe Added Revalidation code (None) * 03-Jan-1992 IanJa Neutralized (ANSI/wide-character) \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#define MIN 0x01
#define MAX 0x02
#define NOMIN 0x04
#define NOMAX 0x08
#define NOCLOSE 0x10
#define SMCAP 0x20
#define NOSIZE (NOMIN | NOMAX)
/***************************************************************************\
* xxxCalcCaptionButton * * This calculates the location of the caption button. \***************************************************************************/ DWORD xxxCalcCaptionButton( PWND pwnd, int iButton, LPWORD pcmd, LPRECT prcBtn, LPWORD pbm) { int x, y, cBorders, cxS, cyS;
CheckLock(pwnd);
*pcmd = 0;
if (TestWF(pwnd, WFMINIMIZED)) { x = -SYSMET(CXFIXEDFRAME); y = -SYSMET(CYFIXEDFRAME); } else { cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); x = -cBorders * SYSMET(CXBORDER); y = -cBorders * SYSMET(CYBORDER); }
CopyInflateRect(prcBtn, &pwnd->rcWindow, x, y);
x = -pwnd->rcWindow.left; y = -pwnd->rcWindow.top;
/*
* Get real caption area: Subtract final border underneath caption that * separates it from everything else. */ if (TestWF(pwnd, WEFTOOLWINDOW)) { cxS = SYSMET(CXSMSIZE); cyS = SYSMET(CYSMSIZE); } else { cxS = SYSMET(CXSIZE); cyS = SYSMET(CYSIZE); }
if (iButton == INDEX_TITLEBAR_CLOSEBUTTON) { if (xxxMNCanClose(pwnd)) { *pbm = TestWF(pwnd, WEFTOOLWINDOW) ? OBI_CLOSE_PAL : OBI_CLOSE; *pcmd = SC_CLOSE; } } else if (iButton == INDEX_TITLEBAR_MINBUTTON) { /*
* Reduce button isn't last button, so shift left by one button */ if (TestWF(pwnd, WFMINBOX)) { prcBtn->right -= cxS * 2; x += SYSMET(CXEDGE);
if (TestWF(pwnd, WFMINIMIZED)) { *pbm = OBI_RESTORE; *pcmd = SC_RESTORE; } else { *pbm = OBI_REDUCE; *pcmd = SC_MINIMIZE; } } } else if (iButton == INDEX_TITLEBAR_MAXBUTTON) { if (TestWF(pwnd, WFMAXBOX)) { prcBtn->right -= cxS;
if (TestWF(pwnd, WFMAXIMIZED)) { *pbm = OBI_RESTORE; *pcmd = SC_RESTORE; } else { *pbm = OBI_ZOOM; *pcmd = SC_MAXIMIZE; } } } else { if (TestWF(pwnd, WEFCONTEXTHELP)) { prcBtn->right -= cxS;
*pbm = OBI_HELP; *pcmd = SC_CONTEXTHELP; } }
if (*pcmd) { prcBtn->bottom = prcBtn->top + cyS; prcBtn->left = prcBtn->right - cxS;
/*
* Adjust 'x' and 'y' to window coordinates */ x += prcBtn->left; y += prcBtn->top + SYSMET(CYEDGE);
/*
* rcBtn (screen coords hit rect) has a one-border tolerance all * around */ InflateRect(prcBtn, SYSMET(CXBORDER), SYSMET(CYBORDER));
if (TestWF(pwnd, WEFLAYOUTRTL)) { cxS = prcBtn->right - prcBtn->left; prcBtn->right = pwnd->rcWindow.right - (prcBtn->left - pwnd->rcWindow.left); prcBtn->left = prcBtn->right - cxS; } }
return (DWORD)MAKELONG(x, y); }
/***************************************************************************\
* xxxTrackCaptionButton * * Handles clicking and dragging on caption buttons. We draw the button * depressed then track the mouse. If the user moves outside of the button, * undepress it. When the mouse button is finally released, we return whether * the mouse was inside the button or not. I.E., whether the button was * clicked. \***************************************************************************/ WORD xxxTrackCaptionButton( PWND pwnd, UINT hit) { WORD cmd; MSG msg; HDC hdc; WORD bm; int x; int y; WORD wState; WORD wNewState; BOOL fMouseUp = FALSE; RECT rcBtn; DWORD dwWhere; int iButton; WORD wf; UserAssert(IsWinEventNotifyDeferredOK());
CheckLock(pwnd);
/*
* Set up iButton for this and future STATECHANGE events */ switch (hit) { case HTCLOSE: iButton = INDEX_TITLEBAR_CLOSEBUTTON; wf = WFCLOSEBUTTONDOWN; break;
case HTREDUCE: iButton = INDEX_TITLEBAR_MINBUTTON; wf = WFREDUCEBUTTONDOWN; break;
case HTZOOM: iButton = INDEX_TITLEBAR_MAXBUTTON; wf = WFZOOMBUTTONDOWN; break;
case HTHELP: iButton = INDEX_TITLEBAR_HELPBUTTON; wf = WFHELPBUTTONDOWN; break;
default: UserAssert(FALSE); } dwWhere = xxxCalcCaptionButton(pwnd, iButton, &cmd, &rcBtn, &bm); x = GET_X_LPARAM(dwWhere); y = GET_Y_LPARAM(dwWhere);
if (cmd) { /*
* Draw the image in its depressed state. */ hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE); BitBltSysBmp(hdc, x, y, bm + DOBI_PUSHED); _ReleaseDC(hdc);
wState = DOBI_PUSHED;
/*
* Notification of button press. */
SetWF(pwnd, wf);
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0); } else { iButton = 0; }
xxxSetCapture(pwnd);
while (!fMouseUp) { if (xxxPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) { if (msg.message == WM_LBUTTONUP) { xxxReleaseCapture(); fMouseUp = TRUE; } else if ((msg.message == WM_MOUSEMOVE) && cmd) { wNewState = PtInRect(&rcBtn, msg.pt) ? DOBI_PUSHED : DOBI_NORMAL;
if (wState != wNewState) { wState = wNewState;
hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE); BitBltSysBmp(hdc, x, y, bm + wState); _ReleaseDC(hdc);
if (wState == DOBI_PUSHED) { SetWF(pwnd, wf); } else { ClrWF(pwnd, wf); }
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0); } } } else if (!xxxSleepThread(QS_MOUSE, 0, TRUE)) { break; }
if (pwnd != PtiCurrent()->pq->spwndCapture) { /*
* We lost capture. This could have happened during * the WM_CAPTURECHANGED callback or later if we * are/were not in the foreground queue. */ break; } }
if (!cmd) { return 0; }
if (wState && (cmd != SC_CONTEXTHELP)) { hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE); BitBltSysBmp(hdc, x, y, bm); _ReleaseDC(hdc);
ClrWF(pwnd, wf);
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0); }
return (fMouseUp && PtInRect(&rcBtn, msg.pt)) ? cmd : 0; }
/***************************************************************************\
* xxxGetWindowSmIcon * * Gets icon to draw in caption of window. \***************************************************************************/ PCURSOR xxxGetWindowSmIcon( PWND pwnd, BOOL fDontSendMsg) { PCURSOR pcursor = NULL; HICON hico = NULL; PCLS pcls = pwnd->pcls;
CheckLock(pwnd);
/*
* We check per-window stuff first then per-class stuff, preferring a * real small icon over a stretched big one. * * Per-window small icon * Per-window big icon stretched small * Per-class small icon * Per-class big icon stretched small * WM_QUERYDRAGICON big icon stretched small (for 3.x dudes) * * Try window small icon first * NOTE: The WM_SETICON and WM_GETICON messags are for ISVs only. */ if ((hico = (HICON)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), PROPF_INTERNAL)) != NULL) {
if (pcursor = (PCURSOR)HMValidateHandleNoSecure(hico, TYPE_CURSOR)) { return pcursor; } else { RIPMSG1(RIP_WARNING,"GetWindowSmIcon: Invalid small icon handle (0x%p)", hico); } }
/*
* Try class small icon next. */ pcursor = pcls->spicnSm; { if (pcursor != NULL) return pcursor; }
if (!TestWF(pwnd, WFWIN40COMPAT) && (!TestWF(pwnd, WFOLDUI) || !TestWF(pwnd, WEFMDICHILD)) && !fDontSendMsg) { ULONG_PTR dwResult;
/*
* A few old apps like Corel don't set their class icon and other * data until long after we need it. If we send them WM_QUERYDRAGICON, * they will fault because they don't check the return from GWL to * get their data. WFOLDUI apps won't ever get a WM_QUERYDRAGICON, * sorry. Currently the apps with this hack (not for this reason * necessarily) * Corel Photo-Paint 5.0 * Myst 2.0 * Visual Baler 3.0 * Quicken */ if (xxxSendMessageTimeout(pwnd, WM_QUERYDRAGICON, 0, 0, SMTO_NORMAL, 100, &dwResult)) { hico = (HICON)dwResult; }
if (hico) { hico = xxxCreateWindowSmIcon(pwnd, hico, FALSE); pcursor = (PCURSOR)HMValidateHandleNoSecure(hico, TYPE_CURSOR);
if (pcursor == NULL) { hico = NULL; } } }
if (pcursor == NULL) { pcursor = SYSICO(WINLOGO); }
return pcursor; }
/***************************************************************************\
* BltMe4Times * * This routine blts out two copies of the specified caption icon. One for an * active window and one for an inactive window. \***************************************************************************/ VOID BltMe4Times( POEMBITMAPINFO pOem, int cxySlot, int cxyIcon, HDC hdcSrc, PCURSOR pcursor, UINT flags) { RECT rc; int i; int j; BOOL fMask = TRUE; LONG rop; HBRUSH hBrush;
hBrush = (flags & DC_INBUTTON) ? SYSHBR(3DHILIGHT) : SYSHBR(ACTIVECAPTION);
for (i = 0; i < 2; i++) { rop = SRCAND;
rc.left = pOem->x; rc.top = pOem->y; rc.right = rc.left + pOem->cx; rc.bottom = rc.top + pOem->cy; FillRect(HDCBITS(), &rc, hBrush);
rc.top += (cxySlot - cxyIcon) / 2; rc.left += SYSMET(CXBORDER) + (cxySlot - cxyIcon) / 2;
for (j = 0; j < 2; j++) { BltIcon( HDCBITS(), rc.left, rc.top, cxyIcon, cxyIcon, hdcSrc, pcursor, fMask ? DI_MASK : DI_IMAGE, rop);
fMask = !fMask; rop = SRCINVERT; }
pOem += DOBI_CAPOFF; hBrush = (flags & DC_INBUTTON) ? SYSHBR(3DFACE) : SYSHBR(INACTIVECAPTION); } }
/***************************************************************************\
* DrawCaptionIcon * * In order to speed up the drawing of caption icons a cache is maintained. * Within the cache, the first entry, 0, is for the tray's depressed caption * look. Items 1..CCACHEDCAPTIONS are for the actual caption's icons. \***************************************************************************/ VOID DrawCaptionIcon( HDC hdc, LPRECT lprc, PCURSOR pcursor, HBRUSH hbrFill, UINT flags) { int i; int xStart = 0; int cxySlot; POEMBITMAPINFO pOem; RECT rc; CAPTIONCACHE ccTemp;
/*
* Check the size of the icon to see if it matches the size of the * cache we created. Most of the time this will match. Also, if * we are drawing with DC_INBUTTON in 16 colors, don't cache. Also, * if the icon has an active alpha channel, just blit it directly * and don't cache! */ cxySlot = lprc->bottom - lprc->top;
if ((cxySlot != gpsi->oembmi[OBI_CAPCACHE1].cy) || (hbrFill == gpsi->hbrGray) || (pcursor->hbmUserAlpha != NULL)) {
rc.left = lprc->left; rc.top = lprc->top; rc.right = lprc->left + cxySlot; rc.bottom = lprc->top + cxySlot;
FillRect(hdc, &rc, hbrFill);
rc.left += SYSMET(CXBORDER) + (cxySlot - SYSMET(CXSMICON)) / 2; rc.top += (cxySlot - SYSMET(CYSMICON)) / 2;
_DrawIconEx(hdc, rc.left, rc.top, pcursor, SYSMET(CXSMICON), SYSMET(CYSMICON), 0, NULL, DI_NORMAL);
goto Done; }
if (flags & DC_INBUTTON) { /*
* The DC_INBUTTON icons is always slot 0. */ i = ((gcachedCaptions[0].spcursor == pcursor) ? 0 : CCACHEDCAPTIONS); } else { /*
* Search the cache to see if this cursor is currently cached. */ for (i = 1; i < CCACHEDCAPTIONS; i++) { if (gcachedCaptions[i].spcursor == pcursor) { break; } } }
if (i >= CCACHEDCAPTIONS) { /*
* Icon wasn't cached, so try and add it to the cache. */ if (flags & DC_INBUTTON) { /*
* The tray's special DC_INBUTTON style always goes in slot 0. */ i = 0; } else { /*
* Look for an empty slot in the cache. If we can't find one, * stuff the new icon at the end of the cache. The result will * be that the last item will be deleted. */ for (i = 1; i < CCACHEDCAPTIONS - 1; i++) { if (gcachedCaptions[i].spcursor == NULL) break; } }
/*
* Add an item to the cache by blting an active and inactive copy of * the icon. */ BltMe4Times(gcachedCaptions[i].pOem, cxySlot, SYSMET(CXSMICON), ghdcMem, pcursor, flags);
Lock(&(gcachedCaptions[i].spcursor), pcursor); #if DBG
gcachedCaptions[i].hico = (HICON)PtoH(pcursor); #endif
}
/*
* We have a hit, so move that cached icon to the front of the cache. * This means that the least recently used icon will be the last icon in * the cache. Remember, we never update index 0 because it is reserved * for the DC_INBUTTON icon. */ for ( ; i > 1; i-- ) { /*
* Move the entry toward the front. */ ccTemp = gcachedCaptions[i]; gcachedCaptions[i] = gcachedCaptions[i - 1]; gcachedCaptions[i - 1] = ccTemp;
#if DBG
/*
* In checked builds we need to adjust the lock records for the * cursor so it has the correct address. */ if (IsDbgTagEnabled(DBGTAG_TrackLocks)) { if (gcachedCaptions[i].spcursor) { HMRelocateLockRecord(&(gcachedCaptions[i].spcursor), (int)sizeof(CAPTIONCACHE)); }
if (gcachedCaptions[i - 1].spcursor) { HMRelocateLockRecord(&(gcachedCaptions[i - 1].spcursor), -(int)sizeof(CAPTIONCACHE)); } } #endif
}
/*
* Make sure the icon we want to draw is the one that we hit in the * cache. */ UserAssert(gcachedCaptions[i].hico == PtoH(pcursor));
/*
* Determine what cached bitmap to blt. */ pOem = gcachedCaptions[i].pOem; if (!(flags & DC_ACTIVE)) { pOem += DOBI_CAPOFF; }
GreBitBlt(hdc, lprc->left, lprc->top, cxySlot, cxySlot, HDCBITS(), pOem->x, pOem->y, SRCCOPY, 0);
Done: /*
* Adjust the given rectangle for the icon we just drew */ lprc->left += cxySlot; }
/***************************************************************************\
* FillGradient * * The rectangle is broken into two triangles: {0, 1, 2} and {0, 2, 3}. * Color on {0, 3} is black, and on {1, 2) is the active caption color. * * 0 1 * 3 2 * * 12/06/96 vadimg created \***************************************************************************/ VOID FillGradient( HDC hdc, LPCRECT prc, COLORREF rgbLeft, COLORREF rgbRight) { TRIVERTEX avert[4]; static GRADIENT_RECT auRect[1] = {0,1}; #define GetCOLOR16(RGB, clr) ((COLOR16)(Get ## RGB ## Value(clr) << 8))
avert[0].Red = GetCOLOR16(R, rgbLeft); avert[0].Green = GetCOLOR16(G, rgbLeft); avert[0].Blue = GetCOLOR16(B, rgbLeft);
avert[1].Red = GetCOLOR16(R, rgbRight); avert[1].Green = GetCOLOR16(G, rgbRight); avert[1].Blue = GetCOLOR16(B, rgbRight);
avert[0].x = prc->left; avert[0].y = prc->top; avert[1].x = prc->right; avert[1].y = prc->bottom;
GreGradientFill(hdc, avert, 2,(PVOID)auRect, 1, GRADIENT_FILL_RECT_H); }
VOID FillCaptionGradient( HDC hdc, LPCRECT prc, BOOL fActive) { COLORREF rgbLeft, rgbRight;
if (fActive) { rgbLeft = gpsi->argbSystem[COLOR_ACTIVECAPTION]; rgbRight = gpsi->argbSystem[COLOR_GRADIENTACTIVECAPTION]; } else { rgbLeft = gpsi->argbSystem[COLOR_INACTIVECAPTION]; rgbRight = gpsi->argbSystem[COLOR_GRADIENTINACTIVECAPTION]; }
if (rgbLeft != rgbRight) { FillGradient(hdc, prc, rgbLeft, rgbRight); } else { FillRect(hdc, prc, fActive ? SYSHBR(ACTIVECAPTION) : SYSHBR(INACTIVECAPTION)); } }
/***************************************************************************\
* xxxDrawCaptionTemp \***************************************************************************/ BOOL xxxDrawCaptionTemp( PWND pwnd, HDC hdc, LPRECT lprc, HFONT hFont, PCURSOR pcursor, PUNICODE_STRING pstrText, UINT flags) { int iOldMode; HBRUSH hbrFill; LONG clrOldText; LONG clrOldBk; BOOL fItFit = TRUE; BOOL fGradient = FALSE; SIZE size; UINT oldAlign;
CheckLock(pwnd);
if (lprc->right <= lprc->left) { return FALSE; }
if (pwnd != NULL) { if (!pcursor && _HasCaptionIcon(pwnd) && !(flags & DC_SMALLCAP) && TestWF(pwnd, WFSYSMENU)) {
/*
* Only get the icon if we can send messages AND the window has * a system menu. */ pcursor = xxxGetWindowSmIcon(pwnd, (flags & DC_NOSENDMSG)); } }
/*
* Set up the colors. */ if (flags & DC_ACTIVE) { if (flags & DC_INBUTTON) { if (gpsi->BitCount < 8 || SYSRGB(3DHILIGHT) != SYSRGB(SCROLLBAR) || SYSRGB(3DHILIGHT) == SYSRGB(WINDOW)) { clrOldText = SYSRGB(3DFACE); clrOldBk = SYSRGB(3DHILIGHT); hbrFill = gpsi->hbrGray; iOldMode = GreSetBkMode(hdc, TRANSPARENT); } else { clrOldText = SYSRGB(BTNTEXT); clrOldBk = SYSRGB(3DHILIGHT); hbrFill = SYSHBR(3DHILIGHT); } } else { clrOldText = SYSRGB(CAPTIONTEXT); clrOldBk = SYSRGB(ACTIVECAPTION); hbrFill = SYSHBR(ACTIVECAPTION);
if (flags & DC_GRADIENT) { fGradient = TRUE; iOldMode = GreSetBkMode(hdc, TRANSPARENT); } } } else { if (flags & DC_INBUTTON) { clrOldText = SYSRGB(BTNTEXT); clrOldBk = SYSRGB(3DFACE); hbrFill = SYSHBR(3DFACE); } else { clrOldText = SYSRGB(INACTIVECAPTIONTEXT); clrOldBk = SYSRGB(INACTIVECAPTION); hbrFill = SYSHBR(INACTIVECAPTION);
if (flags & DC_GRADIENT) { fGradient = TRUE; iOldMode = GreSetBkMode(hdc, TRANSPARENT); } } }
/*
* Set up drawing colors. */ clrOldText = GreSetTextColor(hdc, clrOldText); clrOldBk = GreSetBkColor(hdc, clrOldBk);
if (pcursor && !(flags & DC_SMALLCAP)) {
if (flags & DC_ICON) { /*
* Preserve icon shape when BitBlitting it to a * mirrored DC. This way we don't violate copyright * issues on icons. [samera] */ DWORD dwLayout=0L; if ((dwLayout=GreGetLayout(hdc)) & LAYOUT_RTL) { GreSetLayout(hdc, -1, dwLayout|LAYOUT_BITMAPORIENTATIONPRESERVED); }
DrawCaptionIcon(hdc, lprc, pcursor, hbrFill, flags);
/*
* Restore the DC to its previous layout state. */ if (dwLayout & LAYOUT_RTL) { GreSetLayout(hdc, -1, dwLayout); } } else { lprc->left += lprc->bottom - lprc->top; } }
if (flags & DC_TEXT) { int cch; HFONT hfnOld; int yCentered; WCHAR szText[CCHTITLEMAX]; UNICODE_STRING strTmp; PTHREADINFO ptiCurrent = PtiCurrentShared();
/*
* Get the text for the caption. */ if (pstrText == NULL) { if (pwnd == NULL || (flags & DC_NOSENDMSG)) { if (pwnd && pwnd->strName.Length) { cch = TextCopy(&pwnd->strName, szText, CCHTITLEMAX - 1); strTmp.Length = (USHORT)(cch * sizeof(WCHAR)); } else { szText[0] = TEXT('\0'); cch = strTmp.Length = 0; } } else { cch = xxxGetWindowText(pwnd, szText, CCHTITLEMAX - 1); strTmp.Length = (USHORT)(cch * sizeof(WCHAR)); }
/*
* We don't use RtlInitUnicodeString() to initialize the string * because it does a wstrlen() on the string, which is a waste * since we already know its length. */ strTmp.Buffer = szText; strTmp.MaximumLength = strTmp.Length + sizeof(UNICODE_NULL); pstrText = &strTmp;
} else { cch = pstrText->Length / sizeof(WCHAR); UserAssert(pstrText->Length < pstrText->MaximumLength); UserAssert(pstrText->Buffer[cch] == 0); }
/*
* We need to set up the font first, in case we're centering * the caption. Fortunately, no text at all is uncommon. */ if (hFont == NULL) { if (flags & DC_SMALLCAP) { hFont = ghSmCaptionFont; yCentered = gcySmCaptionFontChar; } else { hFont = gpsi->hCaptionFont; yCentered = gcyCaptionFontChar; }
yCentered = (lprc->top + lprc->bottom - yCentered) / 2;
hfnOld = GreSelectFont(hdc, hFont); } else { TEXTMETRICW tm;
/*
* UNCOMMON case: only for control panel */ hfnOld = GreSelectFont(hdc, hFont);
if (!_GetTextMetricsW(hdc, &tm)) { RIPMSG0(RIP_WARNING, "xxxDrawCaptionTemp: _GetTextMetricsW Failed"); tm.tmHeight = gpsi->tmSysFont.tmHeight; } yCentered = (lprc->top + lprc->bottom - tm.tmHeight) / 2; }
/*
* Draw text */ if (fGradient) { FillCaptionGradient(hdc, lprc, flags & DC_ACTIVE); } else { FillRect(hdc, lprc, hbrFill); }
if (hbrFill == gpsi->hbrGray) { GreSetTextColor(hdc, SYSRGB(BTNTEXT)); GreSetBkColor(hdc, SYSRGB(GRAYTEXT)); }
/*
* GDI doesn't do callbacks to the LPK. If an LPK is installed * and we're not in thread cleanup mode, call the appropriate * client side GDI routines. */ if (CALL_LPK(ptiCurrent)) { xxxClientGetTextExtentPointW(hdc, pstrText->Buffer, cch, &size); } else { GreGetTextExtentW(hdc, pstrText->Buffer, cch, &size, GGTE_WIN3_EXTENT); }
if (pwnd && TestWF(pwnd, WEFRTLREADING)) { oldAlign = GreSetTextAlign(hdc, TA_RTLREADING | GreGetTextAlign(hdc)); } if (!(flags & DC_CENTER) && (!cch || (size.cx <= (lprc->right - lprc->left - SYSMET(CXEDGE))))) { if (pwnd && TestWF(pwnd, WEFRIGHT)) { if (CALL_LPK(ptiCurrent)) { xxxClientExtTextOutW(hdc, lprc->right - (size.cx + SYSMET(CXEDGE)), yCentered, ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL); } else { GreExtTextOutW(hdc, lprc->right - (size.cx + SYSMET(CXEDGE)), yCentered, ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL); } } else { if (CALL_LPK(ptiCurrent)) { xxxClientExtTextOutW(hdc, lprc->left + SYSMET(CXEDGE), yCentered, ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL); } else { GreExtTextOutW(hdc, lprc->left + SYSMET(CXEDGE), yCentered, ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL); } }
#ifdef LAME_BUTTON
if ((flags & DC_LAMEBUTTON) && pwnd != NULL && TestWF(pwnd, WEFLAMEBUTTON)) { GreSelectFont(hdc, ghLameFont);
/*
* Make sure the Lame! text fits in the caption */ if (size.cx + gpsi->ncxLame + 2 * SYSMET(CXEDGE) <= (lprc->right - lprc->left - SYSMET(CXEDGE))) { int x;
if (pwnd && TestWF(pwnd, WEFRIGHT)) { x = lprc->left + SYSMET(CXEDGE); } else { x = lprc->right - SYSMET(CXEDGE) - gpsi->ncxLame; }
if (CALL_LPK(ptiCurrent)) { xxxClientExtTextOutW(hdc, x, yCentered, ETO_CLIPPED, lprc, gpsi->gwszLame, wcslen(gpsi->gwszLame), NULL); } else { GreExtTextOutW(hdc, x, yCentered, ETO_CLIPPED, lprc, gpsi->gwszLame, wcslen(gpsi->gwszLame), NULL); } } } #endif
} else { DRAWTEXTPARAMS dtp; UINT wSide;
dtp.cbSize = sizeof(DRAWTEXTPARAMS); dtp.iLeftMargin = SYSMET(CXEDGE); dtp.iRightMargin = 0;
wSide = (flags & DC_CENTER) ? DT_CENTER : ((pwnd && TestWF(pwnd, WEFRIGHT)) ? DT_RIGHT : 0);
DrawTextEx(hdc, pstrText->Buffer, cch, lprc, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | wSide, &dtp);
fItFit = FALSE; }
if (pwnd && TestWF(pwnd, WEFRTLREADING)) { GreSetTextAlign(hdc, oldAlign); }
if (hfnOld) { GreSelectFont(hdc, hfnOld); } }
/*
* Restore colors. */ GreSetTextColor(hdc, clrOldText); GreSetBkColor(hdc, clrOldBk);
if (hbrFill == gpsi->hbrGray) { GreSetBkMode(hdc, iOldMode); }
return fItFit; }
/***************************************************************************\
* xxxDrawCaptionBar * * \***************************************************************************/
VOID xxxDrawCaptionBar( PWND pwnd, HDC hdc, UINT wFlags) { UINT bm = OBI_CLOSE; RECT rcWindow; HBRUSH hBrush = NULL; HBRUSH hCapBrush; int colorBorder; UINT wBtns; UINT wCode; BOOL fGradient = FALSE;
CheckLock(pwnd);
/*
* If we're not currently showing on the screen, return. * NOTE * If you remove the IsVisible() check from DrawWindowFrame(), then * be careful to remove the NC_NOVISIBLE flag too. This is a smallish * speed thing, so that we don't have to call IsVisible() twice on a * window. DrawWindowFrame() already checks. */ if (!(wFlags & DC_NOVISIBLE) && !IsVisible(pwnd)) { return; }
/*
* Clear this flag so we know the frame has been drawn. */ ClearHungFlag(pwnd, WFREDRAWFRAMEIFHUNG);
GetRect(pwnd, &rcWindow, GRECT_WINDOW | GRECT_WINDOWCOORDS); /*
* The TestALPHA() will return false in ts connections because the * gbDisableAlpha flag will be set to true. So, we need to special case * for TS connections. If this is a remote connection and the gradient * captions flag is set, ideally, we should force it to draw gradients. * However, for 8-bit color, enabling gradients looks ugly. We will fix * this for Blackcomb. * * The code should be something like this: * fGradient = IsRemoteConnection() && !8-bit color ? TestEffectUP(GRADIENTCAPTIONS) : TestALPHA(GRADIENTCAPTIONS); */
fGradient = TestALPHA(GRADIENTCAPTIONS); if (fGradient) { hCapBrush = (wFlags & DC_ACTIVE) ? SYSHBR(GRADIENTACTIVECAPTION) : SYSHBR(GRADIENTINACTIVECAPTION); } else { hCapBrush = (wFlags & DC_ACTIVE) ? SYSHBR(ACTIVECAPTION) : SYSHBR(INACTIVECAPTION); }
wCode = 0;
if (!xxxMNCanClose(pwnd)) { wCode |= NOCLOSE; }
if (!TestWF(pwnd, WFMAXBOX)) { wCode |= NOMAX; } else if (TestWF(pwnd, WFMAXIMIZED)) { wCode |= MAX; }
if (!TestWF(pwnd, WFMINBOX)) { wCode |= NOMIN; } else if (TestWF(pwnd, WFMINIMIZED)) { wCode |= MIN; }
if (TestWF(pwnd, WFMINIMIZED)) { if (wFlags & DC_FRAME) {
/*
* Raised outer edge + border */ DrawEdge(hdc, &rcWindow, EDGE_RAISED, (BF_RECT | BF_ADJUST)); DrawFrame(hdc, &rcWindow, 1, DF_3DFACE); InflateRect(&rcWindow, -SYSMET(CXBORDER), -SYSMET(CYBORDER));
} else { InflateRect(&rcWindow, -SYSMET(CXFIXEDFRAME), -SYSMET(CYFIXEDFRAME)); }
rcWindow.bottom = rcWindow.top + SYSMET(CYSIZE);
hBrush = GreSelectBrush(hdc, hCapBrush);
} else { /*
* BOGUS * What color should we draw borders in? The check is NOT simple. * At create time, we set the 3D bits. NCCREATE will also * set them for listboxes, edit fields,e tc. */ colorBorder = (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI)) ? COLOR_3DFACE : COLOR_WINDOWFRAME;
/*
* Draw the window frame. */ if (wFlags & DC_FRAME) { /*
* Window edge */ if (TestWF(pwnd, WEFWINDOWEDGE)) { DrawEdge(hdc, &rcWindow, EDGE_RAISED, BF_RECT | BF_ADJUST); } else if (TestWF(pwnd, WEFSTATICEDGE)) { DrawEdge(hdc, &rcWindow, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST); }
/*
* Size border */ if (TestWF(pwnd, WFSIZEBOX)) { DrawFrame(hdc, &rcWindow, gpsi->gclBorder, ((wFlags & DC_ACTIVE) ? DF_ACTIVEBORDER : DF_INACTIVEBORDER));
InflateRect(&rcWindow, -gpsi->gclBorder * SYSMET(CXBORDER), -gpsi->gclBorder * SYSMET(CYBORDER)); }
/*
* Normal border */ if (TestWF(pwnd, WFBORDERMASK) || TestWF(pwnd, WEFDLGMODALFRAME)) { DrawFrame(hdc, &rcWindow, 1, (colorBorder << 3)); InflateRect(&rcWindow, -SYSMET(CXBORDER), -SYSMET(CYBORDER)); } } else { int cBorders;
cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE);
InflateRect(&rcWindow, -cBorders * SYSMET(CXBORDER), -cBorders * SYSMET(CYBORDER)); }
/*
* Punt if the window doesn't have a caption currently showing on * screen. */ if (!TestWF(pwnd, WFCPRESENT)) { return; }
if (TestWF(pwnd, WEFTOOLWINDOW)) { wCode |= SMCAP; rcWindow.bottom = rcWindow.top + SYSMET(CYSMSIZE); bm = OBI_CLOSE_PAL; } else { rcWindow.bottom = rcWindow.top + SYSMET(CYSIZE); }
{ POLYPATBLT PolyData;
PolyData.x = rcWindow.left; PolyData.y = rcWindow.bottom; PolyData.cx = rcWindow.right - rcWindow.left; PolyData.cy = SYSMET(CYBORDER); PolyData.BrClr.hbr = SYSHBRUSH(colorBorder);
GrePolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH); }
GreSelectBrush(hdc, hCapBrush); }
if (!TestWF(pwnd, WFSYSMENU) && TestWF(pwnd, WFWIN40COMPAT)) { goto JustDrawIt; }
/*
* New Rules: * (1) The caption has a horz border beneath it separating it from the * menu or client. * (2) The caption text area has an edge of space on the left and right * before the characters. * (3) We account for the descent below the baseline of the caption char */ wBtns = 1;
if (!(wFlags & DC_BUTTONS)) { if ((!wCode) || (!(wCode & SMCAP) && ((wCode & NOSIZE) != NOSIZE))) { wBtns += 2; } else { rcWindow.right -= SYSMET(CXEDGE);
if ((wCode == NOSIZE) && (wCode && TestWF(pwnd, WEFCONTEXTHELP))) { wBtns++; } }
rcWindow.right -= wBtns * ((wCode & SMCAP) ? SYSMET(CXSMSIZE) : SYSMET(CXSIZE));
goto JustDrawIt; }
if (!wCode || (wCode == NOSIZE)) { POEMBITMAPINFO pOem = gpsi->oembmi + OBI_CAPBTNS; int cx;
cx = (wCode ? SYSMET(CXSIZE) + SYSMET(CXEDGE) : SYSMET(CXSIZE) * 3);
if (!(wFlags & DC_ACTIVE)) pOem += DOBI_CAPOFF;
rcWindow.right -= cx;
GreBitBlt(hdc, rcWindow.right, rcWindow.top, cx, pOem->cy, HDCBITS(), pOem->x + pOem->cx - SYSMET(CXSIZE) - cx, pOem->y, SRCCOPY, 0);
if (wCode && TestWF(pwnd, WEFCONTEXTHELP)) {
rcWindow.right -= SYSMET(CXSIZE) - SYSMET(CXEDGE);
GreBitBlt(hdc, rcWindow.right, rcWindow.top, SYSMET(CXSIZE), pOem->cy, HDCBITS(), pOem->x + pOem->cx - SYSMET(CXSIZE), pOem->y, SRCCOPY, 0); /*
* If the UI language is Hebrew we do not want to mirror the ? mark only * Then redraw ? with out the button frame. */ if (HEBREW_UI_LANGID() && TestWF(pwnd, WEFLAYOUTRTL)) { GreBitBlt(hdc, rcWindow.right-SYSMET(CXEDGE), rcWindow.top+2, SYSMET(CXSIZE)-SYSMET(CXEDGE)*2, pOem->cy-4, HDCBITS(), pOem->x + pOem->cx - SYSMET(CXSIZE) + SYSMET(CXEDGE), pOem->y + SYSMET(CXEDGE), SRCCOPY|NOMIRRORBITMAP, 0); } }
goto JustDrawIt; }
/*
* Draw the caption buttons */ rcWindow.top += SYSMET(CYEDGE); rcWindow.bottom -= SYSMET(CYEDGE);
rcWindow.right -= SYSMET(CXEDGE);
GrePatBlt(hdc, rcWindow.right, rcWindow.top, SYSMET(CXEDGE), rcWindow.bottom - rcWindow.top, PATCOPY);
if (wCode & NOCLOSE) { bm += DOBI_INACTIVE; }
rcWindow.right -= gpsi->oembmi[bm].cx; BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm);
if (!(wCode & SMCAP) && ((wCode & NOSIZE) != NOSIZE)) { rcWindow.right -= SYSMET(CXEDGE);
GrePatBlt(hdc, rcWindow.right, rcWindow.top, SYSMET(CXEDGE), rcWindow.bottom - rcWindow.top, PATCOPY);
/*
* Max Box. * * If window is maximized use the restore bitmap; otherwise use the * regular zoom bitmap. */ bm = (wCode & MAX) ? OBI_RESTORE : ((wCode & NOMAX) ? OBI_ZOOM_I : OBI_ZOOM); rcWindow.right -= gpsi->oembmi[bm].cx; BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm);
/*
* Min Box. */ bm = (wCode & MIN) ? OBI_RESTORE : ((wCode & NOMIN) ? OBI_REDUCE_I : OBI_REDUCE); rcWindow.right -= gpsi->oembmi[bm].cx; BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm); rcWindow.right -= SYSMET(CXEDGE); GrePatBlt(hdc, rcWindow.right, rcWindow.top, SYSMET(CXEDGE), rcWindow.bottom - rcWindow.top, PATCOPY);
wBtns += 2; }
if ((wCode & (NOCLOSE | NOSIZE)) && (!(wCode & SMCAP)) && TestWF(pwnd, WEFCONTEXTHELP)) {
rcWindow.right -= SYSMET(CXEDGE);
GrePatBlt(hdc, rcWindow.right, rcWindow.top, SYSMET(CXEDGE), rcWindow.bottom - rcWindow.top, PATCOPY);
bm = OBI_HELP; rcWindow.right -= gpsi->oembmi[bm].cx; BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm);
wBtns++; }
rcWindow.top -= SYSMET(CYEDGE); rcWindow.bottom += SYSMET(CYEDGE);
wBtns *= (wCode & SMCAP) ? SYSMET(CXSMSIZE) : SYSMET(CXSIZE);
{ POLYPATBLT PolyData[2];
PolyData[0].x = rcWindow.right; PolyData[0].y = rcWindow.top; PolyData[0].cx = wBtns; PolyData[0].cy = SYSMET(CYEDGE); PolyData[0].BrClr.hbr = NULL;
PolyData[1].x = rcWindow.right; PolyData[1].y = rcWindow.bottom - SYSMET(CYEDGE); PolyData[1].cx = wBtns; PolyData[1].cy = SYSMET(CYEDGE); PolyData[1].BrClr.hbr = NULL;
GrePolyPatBlt(hdc,PATCOPY,&PolyData[0],2,PPB_BRUSH); }
/*
* We're going to release this DC -- we don't need to bother reselecting * in the old brush. */ if (hBrush) { GreSelectBrush(hdc, hBrush); }
JustDrawIt:
/*
* Call DrawCaption only if we need to draw the icon or the text. * * If the text gets truncated, set the window flag for the caption * tooltip. */ if (wFlags & (DC_TEXT | DC_ICON)) {
#ifdef LAME_BUTTON
wFlags |= DC_LAMEBUTTON; #endif // LAME_BUTTON
/*
* The TestALPHA() will return false in ts connections because the * gbDisableAlpha flag will be set to true. So, we need to special * case for TS connections. If this is a remote connection and the * gradient captions flag is set, ideally, we should force it to * draw gradients. However, for 8-bit color, enabling gradients * looks ugly. We will fix this for Blackcomb. */ if (!xxxDrawCaptionTemp(pwnd, hdc, &rcWindow, NULL, NULL, NULL, wFlags | ((wCode & SMCAP) ? DC_SMALLCAP : 0) | (fGradient? DC_GRADIENT : 0))) { SetWF(pwnd, WEFTRUNCATEDCAPTION); } else { ClrWF(pwnd, WEFTRUNCATEDCAPTION); } } }
|