2 * Win32 5.1 Theme drawing
4 * Copyright (C) 2003 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "uxthemedll.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
41 /***********************************************************************
42 * Defines and global variables
45 extern ATOM atDialogThemeEnabled;
47 /***********************************************************************/
49 /***********************************************************************
50 * EnableThemeDialogTexture (UXTHEME.@)
52 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
54 static const WCHAR szTab[] = { 'T','a','b',0 };
57 TRACE("(%p,0x%08x\n", hwnd, dwFlags);
58 hr = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled),
59 (HANDLE)(dwFlags|0x80000000));
60 /* 0x80000000 serves as a "flags set" flag */
63 if (dwFlags & ETDT_USETABTEXTURE)
64 return SetWindowTheme (hwnd, NULL, szTab);
66 return SetWindowTheme (hwnd, NULL, NULL);
70 /***********************************************************************
71 * IsThemeDialogTextureEnabled (UXTHEME.@)
73 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
75 DWORD dwDialogTextureFlags;
76 TRACE("(%p)\n", hwnd);
78 dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
79 (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled));
80 if (dwDialogTextureFlags == 0)
81 /* Means EnableThemeDialogTexture wasn't called for this dialog */
84 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
87 /***********************************************************************
88 * DrawThemeParentBackground (UXTHEME.@)
90 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
98 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
99 hParent = GetParent(hwnd);
104 MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
106 clip = CreateRectRgn(0,0,1,1);
107 hasClip = GetClipRgn(hdc, clip);
109 TRACE("Failed to get original clipping region\n");
111 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
114 GetClientRect(hParent, &rt);
115 MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
118 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
120 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
121 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
123 SetViewportOrgEx(hdc, org.x, org.y, NULL);
126 SelectClipRgn(hdc, NULL);
127 else if(hasClip == 1)
128 SelectClipRgn(hdc, clip);
135 /***********************************************************************
136 * DrawThemeBackground (UXTHEME.@)
138 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
139 int iStateId, const RECT *pRect,
140 const RECT *pClipRect)
143 opts.dwSize = sizeof(DTBGOPTS);
146 opts.dwFlags |= DTBG_CLIPRECT;
147 CopyRect(&opts.rcClip, pClipRect);
149 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
152 /***********************************************************************
153 * UXTHEME_SelectImage
155 * Select the image to use
157 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
160 int imageselecttype = IST_NONE;
164 image = TMT_GLYPHIMAGEFILE;
166 image = TMT_IMAGEFILE;
168 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
170 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
172 if(imageselecttype == IST_DPI) {
174 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
175 for(i=4; i>=0; i--) {
177 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
178 if(reqdpi != 0 && screendpi >= reqdpi) {
179 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
180 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
184 /* If an image couldn't be selected, choose the first one */
185 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
187 else if(imageselecttype == IST_SIZE) {
188 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
190 for(i=4; i>=0; i--) {
191 PTHEME_PROPERTY fileProp =
192 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
193 if (!fileProp) continue;
194 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
195 /* fall back to size of Nth image */
196 WCHAR szPath[MAX_PATH];
197 int imagelayout = IL_HORIZONTAL;
204 lstrcpynW(szPath, fileProp->lpValue,
205 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
206 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
209 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
210 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
212 imagenum = max (min (imagecount, iStateId), 1) - 1;
213 GetObjectW(hBmp, sizeof(bmp), &bmp);
214 if(imagelayout == IL_VERTICAL) {
215 reqsize.x = bmp.bmWidth;
216 reqsize.y = bmp.bmHeight/imagecount;
219 reqsize.x = bmp.bmWidth/imagecount;
220 reqsize.y = bmp.bmHeight;
223 if(reqsize.x <= size.x && reqsize.y <= size.y) {
224 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
228 /* If an image couldn't be selected, choose the smallest one */
229 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
234 /***********************************************************************
237 * Load image for part/state
239 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
240 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
242 int imagelayout = IL_HORIZONTAL;
246 WCHAR szPath[MAX_PATH];
247 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
249 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
250 return E_PROP_ID_UNSUPPORTED;
252 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
253 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
255 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
256 return HRESULT_FROM_WIN32(GetLastError());
259 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
260 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
262 imagenum = max (min (imagecount, iStateId), 1) - 1;
263 GetObjectW(*hBmp, sizeof(bmp), &bmp);
264 if(imagelayout == IL_VERTICAL) {
265 int height = bmp.bmHeight/imagecount;
267 bmpRect->right = bmp.bmWidth;
268 bmpRect->top = imagenum * height;
269 bmpRect->bottom = bmpRect->top + height;
272 int width = bmp.bmWidth/imagecount;
273 bmpRect->left = imagenum * width;
274 bmpRect->right = bmpRect->left + width;
276 bmpRect->bottom = bmp.bmHeight;
281 /***********************************************************************
284 * Pseudo TransparentBlt/StretchBlt
286 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
287 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
288 INT transparent, COLORREF transcolor)
290 static const BLENDFUNCTION blendFunc =
292 AC_SRC_OVER, /* BlendOp */
294 255, /* SourceConstantAlpha */
295 AC_SRC_ALPHA /* AlphaFormat */
297 if (transparent == ALPHABLEND_BINARY) {
298 /* Ensure we don't pass any negative values to TransparentBlt */
299 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
300 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
303 if ((transparent == ALPHABLEND_NONE) ||
304 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
305 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
308 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
309 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
315 /***********************************************************************
318 * Simplify sending same width/height for both source and dest
320 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
321 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
322 INT transparent, COLORREF transcolor)
324 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
325 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
326 transparent, transcolor);
329 /***********************************************************************
332 * Stretches or tiles, depending on sizingtype.
334 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
335 int nWidthDst, int nHeightDst,
336 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
337 int nWidthSrc, int nHeightSrc,
339 INT transparent, COLORREF transcolor)
341 if (sizingtype == ST_TILE)
343 int yOfs = nYOriginDst;
344 int yRemaining = nHeightDst;
345 while (yRemaining > 0)
347 int bltHeight = min (yRemaining, nHeightSrc);
348 int xOfs = nXOriginDst;
349 int xRemaining = nWidthDst;
350 while (xRemaining > 0)
352 int bltWidth = min (xRemaining, nWidthSrc);
353 if (!UXTHEME_Blt (hdcDst, xOfs, yOfs, bltWidth, bltHeight,
354 hdcSrc, nXOriginSrc, nYOriginSrc,
355 transparent, transcolor))
358 xRemaining -= nWidthSrc;
361 yRemaining -= nHeightSrc;
367 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
368 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
369 transparent, transcolor);
373 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
374 * depend on whether the image has full alpha or whether it is
375 * color-transparent or just opaque. */
376 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
377 BOOL hasImageAlpha, INT* transparent,
378 COLORREF* transparentcolor, BOOL glyph)
382 *transparent = ALPHABLEND_FULL;
383 *transparentcolor = RGB (255, 0, 255);
388 GetThemeBool(hTheme, iPartId, iStateId,
389 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
391 *transparent = ALPHABLEND_BINARY;
392 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
393 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
394 transparentcolor))) {
395 /* If image is transparent, but no color was specified, use magenta */
396 *transparentcolor = RGB(255, 0, 255);
400 *transparent = ALPHABLEND_NONE;
404 /***********************************************************************
405 * UXTHEME_DrawImageGlyph
407 * Draw an imagefile glyph
409 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
410 int iStateId, RECT *pRect,
411 const DTBGOPTS *pOptions)
414 HBITMAP bmpSrc = NULL;
416 HGDIOBJ oldSrc = NULL;
418 INT transparent = FALSE;
419 COLORREF transparentcolor;
420 int valign = VA_CENTER;
421 int halign = HA_CENTER;
427 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
428 &bmpSrc, &rcSrc, &hasAlpha);
429 if(FAILED(hr)) return hr;
430 hdcSrc = CreateCompatibleDC(hdc);
432 hr = HRESULT_FROM_WIN32(GetLastError());
435 oldSrc = SelectObject(hdcSrc, bmpSrc);
437 dstSize.x = pRect->right-pRect->left;
438 dstSize.y = pRect->bottom-pRect->top;
439 srcSize.x = rcSrc.right-rcSrc.left;
440 srcSize.y = rcSrc.bottom-rcSrc.top;
442 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
443 &transparentcolor, TRUE);
444 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
445 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
447 topleft.x = pRect->left;
448 topleft.y = pRect->top;
449 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
450 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
451 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
452 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
454 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
455 hdcSrc, rcSrc.left, rcSrc.top,
456 transparent, transparentcolor)) {
457 hr = HRESULT_FROM_WIN32(GetLastError());
460 SelectObject(hdcSrc, oldSrc);
465 /***********************************************************************
466 * UXTHEME_DrawImageGlyph
468 * Draw glyph on top of background, if appropriate
470 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
471 int iStateId, RECT *pRect,
472 const DTBGOPTS *pOptions)
474 int glyphtype = GT_NONE;
476 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
478 if(glyphtype == GT_IMAGEGLYPH) {
479 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
481 else if(glyphtype == GT_FONTGLYPH) {
482 /* I don't know what a font glyph is, I've never seen it used in any themes */
483 FIXME("Font glyph\n");
488 /***********************************************************************
489 * get_image_part_size
491 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
493 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
494 int iStateId, RECT *prc, THEMESIZE eSize,
502 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
503 &bmpSrc, &rcSrc, &hasAlpha);
504 if (FAILED(hr)) return hr;
514 int sizingtype = ST_STRETCH;
515 BOOL uniformsizing = FALSE;
517 CopyRect(&rcDst, prc);
519 dstSize.x = rcDst.right-rcDst.left;
520 dstSize.y = rcDst.bottom-rcDst.top;
521 srcSize.x = rcSrc.right-rcSrc.left;
522 srcSize.y = rcSrc.bottom-rcSrc.top;
524 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
526 /* Scale height and width equally */
527 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
529 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
530 rcDst.bottom = rcDst.top + dstSize.y;
534 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
535 rcDst.right = rcDst.left + dstSize.x;
539 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
540 if(sizingtype == ST_TRUESIZE) {
541 int truesizestretchmark = 100;
543 if(dstSize.x < 0 || dstSize.y < 0) {
544 BOOL mirrorimage = TRUE;
545 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
548 rcDst.left += dstSize.x;
549 rcDst.right += dstSize.x;
552 rcDst.top += dstSize.y;
553 rcDst.bottom += dstSize.y;
557 /* Whatever TrueSizeStretchMark does - it does not seem to
558 * be what's outlined below. It appears as if native
559 * uxtheme always stretches if dest is smaller than source
560 * (ie as if TrueSizeStretchMark==100 with the code below) */
562 /* Only stretch when target exceeds source by truesizestretchmark percent */
563 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
565 if(dstSize.x < 0 || dstSize.y < 0 ||
566 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
567 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
568 memcpy (psz, &dstSize, sizeof (SIZE));
571 memcpy (psz, &srcSize, sizeof (SIZE));
576 psz->x = abs(dstSize.x);
577 psz->y = abs(dstSize.y);
581 /* else fall through */
583 /* FIXME: couldn't figure how native uxtheme computes min size */
585 psz->x = rcSrc.right - rcSrc.left;
586 psz->y = rcSrc.bottom - rcSrc.top;
592 /***********************************************************************
593 * UXTHEME_DrawImageBackground
595 * Draw an imagefile background
597 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
598 int iStateId, RECT *pRect,
599 const DTBGOPTS *pOptions)
610 int sizingtype = ST_STRETCH;
612 COLORREF transparentcolor = 0;
615 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
616 &bmpSrc, &rcSrc, &hasAlpha);
617 if(FAILED(hr)) return hr;
618 hdcSrc = CreateCompatibleDC(hdc);
620 hr = HRESULT_FROM_WIN32(GetLastError());
623 oldSrc = SelectObject(hdcSrc, bmpSrc);
625 CopyRect(&rcDst, pRect);
627 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
628 &transparentcolor, FALSE);
630 dstSize.x = rcDst.right-rcDst.left;
631 dstSize.y = rcDst.bottom-rcDst.top;
632 srcSize.x = rcSrc.right-rcSrc.left;
633 srcSize.y = rcSrc.bottom-rcSrc.top;
635 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
636 if(sizingtype == ST_TRUESIZE) {
637 int valign = VA_CENTER, halign = HA_CENTER;
639 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
640 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
641 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
643 if (halign == HA_CENTER)
644 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
645 else if (halign == HA_RIGHT)
646 rcDst.left = rcDst.right - drawSize.x;
647 if (valign == VA_CENTER)
648 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
649 else if (valign == VA_BOTTOM)
650 rcDst.top = rcDst.bottom - drawSize.y;
651 rcDst.right = rcDst.left + drawSize.x;
652 rcDst.bottom = rcDst.top + drawSize.y;
653 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
654 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
655 transparent, transparentcolor))
656 hr = HRESULT_FROM_WIN32(GetLastError());
663 dstSize.x = abs(dstSize.x);
664 dstSize.y = abs(dstSize.y);
666 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
669 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
671 /* Upper left corner */
672 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
673 hdcSrc, rcSrc.left, rcSrc.top,
674 transparent, transparentcolor)) {
675 hr = HRESULT_FROM_WIN32(GetLastError());
678 /* Upper right corner */
679 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
680 sm.cxRightWidth, sm.cyTopHeight,
681 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
682 transparent, transparentcolor)) {
683 hr = HRESULT_FROM_WIN32(GetLastError());
686 /* Lower left corner */
687 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
688 sm.cxLeftWidth, sm.cyBottomHeight,
689 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
690 transparent, transparentcolor)) {
691 hr = HRESULT_FROM_WIN32(GetLastError());
694 /* Lower right corner */
695 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
696 sm.cxRightWidth, sm.cyBottomHeight,
697 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
698 transparent, transparentcolor)) {
699 hr = HRESULT_FROM_WIN32(GetLastError());
703 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
704 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
705 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
706 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
707 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
709 if(destCenterWidth > 0) {
711 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
712 destCenterWidth, sm.cyTopHeight,
713 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
714 srcCenterWidth, sm.cyTopHeight,
715 sizingtype, transparent, transparentcolor)) {
716 hr = HRESULT_FROM_WIN32(GetLastError());
720 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
721 destCenterWidth, sm.cyBottomHeight,
722 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
723 srcCenterWidth, sm.cyBottomHeight,
724 sizingtype, transparent, transparentcolor)) {
725 hr = HRESULT_FROM_WIN32(GetLastError());
729 if(destCenterHeight > 0) {
731 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
732 sm.cxLeftWidth, destCenterHeight,
733 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
734 sm.cxLeftWidth, srcCenterHeight,
736 transparent, transparentcolor)) {
737 hr = HRESULT_FROM_WIN32(GetLastError());
741 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
742 sm.cxRightWidth, destCenterHeight,
743 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
744 sm.cxRightWidth, srcCenterHeight,
745 sizingtype, transparent, transparentcolor)) {
746 hr = HRESULT_FROM_WIN32(GetLastError());
750 if(destCenterHeight > 0 && destCenterWidth > 0) {
751 BOOL borderonly = FALSE;
752 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
755 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
756 destCenterWidth, destCenterHeight,
757 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
758 srcCenterWidth, srcCenterHeight,
759 sizingtype, transparent, transparentcolor)) {
760 hr = HRESULT_FROM_WIN32(GetLastError());
768 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
770 SelectObject(hdcSrc, oldSrc);
772 CopyRect(pRect, &rcDst);
776 /***********************************************************************
777 * UXTHEME_DrawBorderRectangle
779 * Draw the bounding rectangle for a borderfill background
781 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
782 int iStateId, RECT *pRect,
783 const DTBGOPTS *pOptions)
788 COLORREF bordercolor = RGB(0,0,0);
791 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
794 ptCorners[0].x = pRect->left;
795 ptCorners[0].y = pRect->top;
796 ptCorners[1].x = pRect->right-1;
797 ptCorners[1].y = pRect->top;
798 ptCorners[2].x = pRect->right-1;
799 ptCorners[2].y = pRect->bottom-1;
800 ptCorners[3].x = pRect->left;
801 ptCorners[3].y = pRect->bottom-1;
802 ptCorners[4].x = pRect->left;
803 ptCorners[4].y = pRect->top;
805 InflateRect(pRect, -bordersize, -bordersize);
806 if(pOptions->dwFlags & DTBG_OMITBORDER)
808 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
809 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
811 return HRESULT_FROM_WIN32(GetLastError());
812 oldPen = SelectObject(hdc, hPen);
814 if(!Polyline(hdc, ptCorners, 5))
815 hr = HRESULT_FROM_WIN32(GetLastError());
817 SelectObject(hdc, oldPen);
823 /***********************************************************************
824 * UXTHEME_DrawBackgroundFill
826 * Fill a borderfill background rectangle
828 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
829 int iStateId, RECT *pRect,
830 const DTBGOPTS *pOptions)
833 int filltype = FT_SOLID;
835 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
837 if(pOptions->dwFlags & DTBG_OMITCONTENT)
840 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
842 if(filltype == FT_SOLID) {
844 COLORREF fillcolor = RGB(255,255,255);
846 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
847 hBrush = CreateSolidBrush(fillcolor);
848 if(!FillRect(hdc, pRect, hBrush))
849 hr = HRESULT_FROM_WIN32(GetLastError());
850 DeleteObject(hBrush);
852 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
853 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
854 the gradient ratios (no idea how those work)
855 Few themes use this, and the ones I've seen only use 2 colors with
856 a gradient ratio of 0 and 255 respectivly
859 COLORREF gradient1 = RGB(0,0,0);
860 COLORREF gradient2 = RGB(255,255,255);
864 FIXME("Gradient implementation not complete\n");
866 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
867 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
869 vert[0].x = pRect->left;
870 vert[0].y = pRect->top;
871 vert[0].Red = GetRValue(gradient1) << 8;
872 vert[0].Green = GetGValue(gradient1) << 8;
873 vert[0].Blue = GetBValue(gradient1) << 8;
874 vert[0].Alpha = 0x0000;
876 vert[1].x = pRect->right;
877 vert[1].y = pRect->bottom;
878 vert[1].Red = GetRValue(gradient2) << 8;
879 vert[1].Green = GetGValue(gradient2) << 8;
880 vert[1].Blue = GetBValue(gradient2) << 8;
881 vert[1].Alpha = 0x0000;
884 gRect.LowerRight = 1;
885 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
887 else if(filltype == FT_RADIALGRADIENT) {
888 /* I've never seen this used in a theme */
889 FIXME("Radial gradient\n");
891 else if(filltype == FT_TILEIMAGE) {
892 /* I've never seen this used in a theme */
893 FIXME("Tile image\n");
898 /***********************************************************************
899 * UXTHEME_DrawBorderBackground
901 * Draw an imagefile background
903 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
904 int iStateId, const RECT *pRect,
905 const DTBGOPTS *pOptions)
910 CopyRect(&rt, pRect);
912 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
915 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
918 /***********************************************************************
919 * DrawThemeBackgroundEx (UXTHEME.@)
921 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
922 int iStateId, const RECT *pRect,
923 const DTBGOPTS *pOptions)
926 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
927 const DTBGOPTS *opts;
930 int bgtype = BT_BORDERFILL;
933 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
937 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
938 if (bgtype == BT_NONE) return S_OK;
940 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
942 if(!opts) opts = &defaultOpts;
944 if(opts->dwFlags & DTBG_CLIPRECT) {
945 clip = CreateRectRgn(0,0,1,1);
946 hasClip = GetClipRgn(hdc, clip);
948 TRACE("Failed to get original clipping region\n");
950 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
952 CopyRect(&rt, pRect);
954 if(bgtype == BT_IMAGEFILE)
955 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
956 else if(bgtype == BT_BORDERFILL)
957 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
959 FIXME("Unknown background type\n");
960 /* This should never happen, and hence I don't know what to return */
964 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
965 if(opts->dwFlags & DTBG_CLIPRECT) {
967 SelectClipRgn(hdc, NULL);
968 else if(hasClip == 1)
969 SelectClipRgn(hdc, clip);
976 * DrawThemeEdge() implementation
978 * Since it basically is DrawEdge() with different colors, I copied its code
979 * from user32's uitools.c.
1000 } EdgeColorMap[EDGE_NUMCOLORS] = {
1001 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1002 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1003 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1004 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1005 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1007 {-1, COLOR_WINDOWFRAME}
1010 static const signed char LTInnerNormal[] = {
1012 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1013 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1017 static const signed char LTOuterNormal[] = {
1018 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1019 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1020 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1021 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1024 static const signed char RBInnerNormal[] = {
1026 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1027 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1031 static const signed char RBOuterNormal[] = {
1032 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1033 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1034 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1035 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1038 static const signed char LTInnerSoft[] = {
1040 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1041 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1045 static const signed char LTOuterSoft[] = {
1046 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1047 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1048 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1049 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1052 #define RBInnerSoft RBInnerNormal /* These are the same */
1053 #define RBOuterSoft RBOuterNormal
1055 static const signed char LTRBOuterMono[] = {
1056 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1057 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1058 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1059 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1062 static const signed char LTRBInnerMono[] = {
1064 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1065 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1066 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1069 static const signed char LTRBOuterFlat[] = {
1070 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1071 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1072 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1073 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1076 static const signed char LTRBInnerFlat[] = {
1078 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1079 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1080 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1083 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1086 if ((EdgeColorMap[edgeType].themeProp == -1)
1087 || FAILED (GetThemeColor (theme, part, state,
1088 EdgeColorMap[edgeType].themeProp, &col)))
1089 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1093 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1095 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1098 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1100 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1103 /***********************************************************************
1106 * Same as DrawEdge invoked with BF_DIAGONAL
1108 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1109 const RECT* rc, UINT uType,
1110 UINT uFlags, LPRECT contentsRect)
1113 signed char InnerI, OuterI;
1114 HPEN InnerPen, OuterPen;
1119 int Width = rc->right - rc->left;
1120 int Height= rc->bottom - rc->top;
1121 int SmallDiam = Width > Height ? Height : Width;
1122 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1123 || (uType & BDR_OUTER) == BDR_OUTER)
1124 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1125 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1126 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1128 /* Init some vars */
1129 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1130 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1131 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1133 /* Determine the colors of the edges */
1134 if(uFlags & BF_MONO)
1136 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1137 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1139 else if(uFlags & BF_FLAT)
1141 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1142 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1144 else if(uFlags & BF_SOFT)
1146 if(uFlags & BF_BOTTOM)
1148 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1149 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1153 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1154 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1159 if(uFlags & BF_BOTTOM)
1161 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1162 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1166 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1167 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1171 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1172 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1174 MoveToEx(hdc, 0, 0, &SavePoint);
1176 /* Don't ask me why, but this is what is visible... */
1177 /* This must be possible to do much simpler, but I fail to */
1178 /* see the logic in the MS implementation (sigh...). */
1179 /* So, this might look a bit brute force here (and it is), but */
1180 /* it gets the job done;) */
1182 switch(uFlags & BF_RECT)
1188 /* Left bottom endpoint */
1190 spx = epx + SmallDiam;
1192 spy = epy - SmallDiam;
1196 case BF_BOTTOMRIGHT:
1197 /* Left top endpoint */
1199 spx = epx + SmallDiam;
1201 spy = epy + SmallDiam;
1207 case BF_RIGHT|BF_LEFT:
1208 case BF_RIGHT|BF_LEFT|BF_TOP:
1209 case BF_BOTTOM|BF_TOP:
1210 case BF_BOTTOM|BF_TOP|BF_LEFT:
1211 case BF_BOTTOMRIGHT|BF_LEFT:
1212 case BF_BOTTOMRIGHT|BF_TOP:
1214 /* Right top endpoint */
1216 epx = spx + SmallDiam;
1218 epy = spy - SmallDiam;
1222 MoveToEx(hdc, spx, spy, NULL);
1223 SelectObject(hdc, OuterPen);
1224 LineTo(hdc, epx, epy);
1226 SelectObject(hdc, InnerPen);
1228 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1230 case BF_DIAGONAL_ENDBOTTOMLEFT:
1231 case (BF_DIAGONAL|BF_BOTTOM):
1233 case (BF_DIAGONAL|BF_LEFT):
1234 MoveToEx(hdc, spx-1, spy, NULL);
1235 LineTo(hdc, epx, epy-1);
1236 Points[0].x = spx-add;
1238 Points[1].x = rc->left;
1239 Points[1].y = rc->top;
1240 Points[2].x = epx+1;
1241 Points[2].y = epy-1-add;
1242 Points[3] = Points[2];
1245 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1246 MoveToEx(hdc, spx-1, spy, NULL);
1247 LineTo(hdc, epx, epy+1);
1248 Points[0].x = spx-add;
1250 Points[1].x = rc->left;
1251 Points[1].y = rc->bottom-1;
1252 Points[2].x = epx+1;
1253 Points[2].y = epy+1+add;
1254 Points[3] = Points[2];
1257 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1258 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1259 case BF_DIAGONAL_ENDTOPRIGHT:
1260 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1261 MoveToEx(hdc, spx+1, spy, NULL);
1262 LineTo(hdc, epx, epy+1);
1263 Points[0].x = epx-1;
1264 Points[0].y = epy+1+add;
1265 Points[1].x = rc->right-1;
1266 Points[1].y = rc->top+add;
1267 Points[2].x = rc->right-1;
1268 Points[2].y = rc->bottom-1;
1269 Points[3].x = spx+add;
1273 case BF_DIAGONAL_ENDTOPLEFT:
1274 MoveToEx(hdc, spx, spy-1, NULL);
1275 LineTo(hdc, epx+1, epy);
1276 Points[0].x = epx+1+add;
1277 Points[0].y = epy+1;
1278 Points[1].x = rc->right-1;
1279 Points[1].y = rc->top;
1280 Points[2].x = rc->right-1;
1281 Points[2].y = rc->bottom-1-add;
1283 Points[3].y = spy-add;
1286 case (BF_DIAGONAL|BF_TOP):
1287 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1288 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1289 MoveToEx(hdc, spx+1, spy-1, NULL);
1290 LineTo(hdc, epx, epy);
1291 Points[0].x = epx-1;
1292 Points[0].y = epy+1;
1293 Points[1].x = rc->right-1;
1294 Points[1].y = rc->top;
1295 Points[2].x = rc->right-1;
1296 Points[2].y = rc->bottom-1-add;
1297 Points[3].x = spx+add;
1298 Points[3].y = spy-add;
1301 case (BF_DIAGONAL|BF_RIGHT):
1302 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1303 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1304 MoveToEx(hdc, spx, spy, NULL);
1305 LineTo(hdc, epx-1, epy+1);
1308 Points[1].x = rc->left;
1309 Points[1].y = rc->top+add;
1310 Points[2].x = epx-1-add;
1311 Points[2].y = epy+1+add;
1312 Points[3] = Points[2];
1316 /* Fill the interior if asked */
1317 if((uFlags & BF_MIDDLE) && retval)
1320 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1321 theme, part, state);
1323 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1324 theme, part, state);
1325 hbsave = (HBRUSH)SelectObject(hdc, hb);
1326 hpsave = (HPEN)SelectObject(hdc, hp);
1327 Polygon(hdc, Points, 4);
1328 SelectObject(hdc, hbsave);
1329 SelectObject(hdc, hpsave);
1334 /* Adjust rectangle if asked */
1335 if(uFlags & BF_ADJUST)
1337 *contentsRect = *rc;
1338 if(uFlags & BF_LEFT) contentsRect->left += add;
1339 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1340 if(uFlags & BF_TOP) contentsRect->top += add;
1341 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1345 SelectObject(hdc, SavePen);
1346 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1347 if(InnerI != -1) DeleteObject (InnerPen);
1348 if(OuterI != -1) DeleteObject (OuterPen);
1353 /***********************************************************************
1356 * Same as DrawEdge invoked without BF_DIAGONAL
1358 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1359 const RECT* rc, UINT uType,
1360 UINT uFlags, LPRECT contentsRect)
1362 signed char LTInnerI, LTOuterI;
1363 signed char RBInnerI, RBOuterI;
1364 HPEN LTInnerPen, LTOuterPen;
1365 HPEN RBInnerPen, RBOuterPen;
1366 RECT InnerRect = *rc;
1373 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1374 || (uType & BDR_OUTER) == BDR_OUTER)
1375 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1377 /* Init some vars */
1378 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1379 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1381 /* Determine the colors of the edges */
1382 if(uFlags & BF_MONO)
1384 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1385 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1387 else if(uFlags & BF_FLAT)
1389 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1390 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1392 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1394 else if(uFlags & BF_SOFT)
1396 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1397 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1398 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1399 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1403 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1404 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1405 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1406 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1409 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1410 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1411 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1412 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1414 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1415 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1416 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1417 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1419 MoveToEx(hdc, 0, 0, &SavePoint);
1421 /* Draw the outer edge */
1422 SelectObject(hdc, LTOuterPen);
1425 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1426 LineTo(hdc, InnerRect.right, InnerRect.top);
1428 if(uFlags & BF_LEFT)
1430 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1431 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1433 SelectObject(hdc, RBOuterPen);
1434 if(uFlags & BF_BOTTOM)
1436 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1437 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1439 if(uFlags & BF_RIGHT)
1441 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1442 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1445 /* Draw the inner edge */
1446 SelectObject(hdc, LTInnerPen);
1449 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1450 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1452 if(uFlags & BF_LEFT)
1454 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1455 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1457 SelectObject(hdc, RBInnerPen);
1458 if(uFlags & BF_BOTTOM)
1460 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1461 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1463 if(uFlags & BF_RIGHT)
1465 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1466 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1469 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1471 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1472 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1474 if(uFlags & BF_LEFT) InnerRect.left += add;
1475 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1476 if(uFlags & BF_TOP) InnerRect.top += add;
1477 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1479 if((uFlags & BF_MIDDLE) && retval)
1481 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1482 theme, part, state);
1483 FillRect(hdc, &InnerRect, br);
1487 if(uFlags & BF_ADJUST)
1488 *contentsRect = InnerRect;
1492 SelectObject(hdc, SavePen);
1493 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1494 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1495 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1496 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1497 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1502 /***********************************************************************
1503 * DrawThemeEdge (UXTHEME.@)
1505 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1506 * difference is that it does not rely on the system colors alone, but
1507 * also allows color specification in the theme.
1509 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1510 int iStateId, const RECT *pDestRect, UINT uEdge,
1511 UINT uFlags, RECT *pContentRect)
1513 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1517 if(uFlags & BF_DIAGONAL)
1518 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1519 uEdge, uFlags, pContentRect);
1521 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1522 uEdge, uFlags, pContentRect);
1526 /***********************************************************************
1527 * DrawThemeIcon (UXTHEME.@)
1529 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1530 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1532 FIXME("%d %d: stub\n", iPartId, iStateId);
1535 return ERROR_CALL_NOT_IMPLEMENTED;
1538 /***********************************************************************
1539 * DrawThemeText (UXTHEME.@)
1541 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1542 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1543 DWORD dwTextFlags2, const RECT *pRect)
1547 HGDIOBJ oldFont = NULL;
1550 COLORREF oldTextColor;
1554 TRACE("%d %d: stub\n", iPartId, iStateId);
1558 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1560 hFont = CreateFontIndirectW(&logfont);
1562 TRACE("Failed to create font\n");
1564 CopyRect(&rt, pRect);
1566 oldFont = SelectObject(hdc, hFont);
1568 if(dwTextFlags2 & DTT_GRAYED)
1569 textColor = GetSysColor(COLOR_GRAYTEXT);
1571 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1572 textColor = GetTextColor(hdc);
1574 oldTextColor = SetTextColor(hdc, textColor);
1575 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1576 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1577 SetBkMode(hdc, oldBkMode);
1578 SetTextColor(hdc, oldTextColor);
1581 SelectObject(hdc, oldFont);
1582 DeleteObject(hFont);
1587 /***********************************************************************
1588 * GetThemeBackgroundContentRect (UXTHEME.@)
1590 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1592 const RECT *pBoundingRect,
1598 TRACE("(%d,%d)\n", iPartId, iStateId);
1602 /* try content margins property... */
1603 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1605 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1606 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1607 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1608 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1610 /* otherwise, try to determine content rect from the background type and props */
1611 int bgtype = BT_BORDERFILL;
1612 memcpy(pContentRect, pBoundingRect, sizeof(RECT));
1614 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1615 if(bgtype == BT_BORDERFILL) {
1618 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1619 InflateRect(pContentRect, -bordersize, -bordersize);
1620 } else if ((bgtype == BT_IMAGEFILE)
1621 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1622 TMT_SIZINGMARGINS, NULL, &margin)))) {
1623 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1624 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1625 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1626 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1628 /* If nothing was found, leave unchanged */
1631 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1636 /***********************************************************************
1637 * GetThemeBackgroundExtent (UXTHEME.@)
1639 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1640 int iStateId, const RECT *pContentRect,
1646 TRACE("(%d,%d)\n", iPartId, iStateId);
1650 /* try content margins property... */
1651 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1653 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1654 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1655 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1656 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1658 /* otherwise, try to determine content rect from the background type and props */
1659 int bgtype = BT_BORDERFILL;
1660 memcpy(pExtentRect, pContentRect, sizeof(RECT));
1662 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1663 if(bgtype == BT_BORDERFILL) {
1666 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1667 InflateRect(pExtentRect, bordersize, bordersize);
1668 } else if ((bgtype == BT_IMAGEFILE)
1669 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1670 TMT_SIZINGMARGINS, NULL, &margin)))) {
1671 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1672 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1673 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1674 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1676 /* If nothing was found, leave unchanged */
1679 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1684 /***********************************************************************
1685 * GetThemeBackgroundRegion (UXTHEME.@)
1687 * Calculate the background region, taking into consideration transparent areas
1688 * of the background image.
1690 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1691 int iStateId, const RECT *pRect,
1695 int bgtype = BT_BORDERFILL;
1697 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1700 if(!pRect || !pRegion)
1703 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1704 if(bgtype == BT_IMAGEFILE) {
1705 FIXME("Images not handled yet\n");
1706 hr = ERROR_CALL_NOT_IMPLEMENTED;
1708 else if(bgtype == BT_BORDERFILL) {
1709 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1711 hr = HRESULT_FROM_WIN32(GetLastError());
1714 FIXME("Unknown background type\n");
1715 /* This should never happen, and hence I don't know what to return */
1721 /* compute part size for "borderfill" backgrounds */
1722 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1723 int iStateId, THEMESIZE eSize, POINT* psz)
1728 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1731 psz->x = psz->y = 2*bordersize;
1732 if (eSize != TS_MIN)
1741 /***********************************************************************
1742 * GetThemePartSize (UXTHEME.@)
1744 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1745 int iStateId, RECT *prc, THEMESIZE eSize,
1748 int bgtype = BT_BORDERFILL;
1750 POINT size = {1, 1};
1755 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1756 if (bgtype == BT_NONE)
1758 else if(bgtype == BT_IMAGEFILE)
1759 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1760 else if(bgtype == BT_BORDERFILL)
1761 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1763 FIXME("Unknown background type\n");
1764 /* This should never happen, and hence I don't know what to return */
1773 /***********************************************************************
1774 * GetThemeTextExtent (UXTHEME.@)
1776 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1777 int iStateId, LPCWSTR pszText, int iCharCount,
1778 DWORD dwTextFlags, const RECT *pBoundingRect,
1783 HGDIOBJ oldFont = NULL;
1785 RECT rt = {0,0,0xFFFF,0xFFFF};
1787 TRACE("%d %d: stub\n", iPartId, iStateId);
1792 CopyRect(&rt, pBoundingRect);
1794 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1796 hFont = CreateFontIndirectW(&logfont);
1798 TRACE("Failed to create font\n");
1801 oldFont = SelectObject(hdc, hFont);
1803 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1804 CopyRect(pExtentRect, &rt);
1807 SelectObject(hdc, oldFont);
1808 DeleteObject(hFont);
1813 /***********************************************************************
1814 * GetThemeTextMetrics (UXTHEME.@)
1816 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1817 int iStateId, TEXTMETRICW *ptm)
1821 HGDIOBJ oldFont = NULL;
1824 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1828 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1830 hFont = CreateFontIndirectW(&logfont);
1832 TRACE("Failed to create font\n");
1835 oldFont = SelectObject(hdc, hFont);
1837 if(!GetTextMetricsW(hdc, ptm))
1838 hr = HRESULT_FROM_WIN32(GetLastError());
1841 SelectObject(hdc, oldFont);
1842 DeleteObject(hFont);
1847 /***********************************************************************
1848 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1850 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1853 int bgtype = BT_BORDERFILL;
1854 RECT rect = {0, 0, 0, 0};
1859 COLORREF transparentcolor;
1861 TRACE("(%d,%d)\n", iPartId, iStateId);
1866 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1868 if (bgtype != BT_IMAGEFILE) return FALSE;
1870 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1871 &bmpSrc, &rcSrc, &hasAlpha)))
1874 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1875 &transparentcolor, FALSE);
1876 return (transparent != ALPHABLEND_NONE);