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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "uxthemedll.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme
);
40 /***********************************************************************
41 * Defines and global variables
44 DWORD dwDialogTextureFlags
;
46 /***********************************************************************/
48 /***********************************************************************
49 * EnableThemeDialogTexture (UXTHEME.@)
51 HRESULT WINAPI
EnableThemeDialogTexture(HWND hwnd
, DWORD dwFlags
)
53 TRACE("(%p,0x%08lx\n", hwnd
, dwFlags
);
54 dwDialogTextureFlags
= dwFlags
;
58 /***********************************************************************
59 * IsThemeDialogTextureEnabled (UXTHEME.@)
61 BOOL WINAPI
IsThemeDialogTextureEnabled(void)
64 return (dwDialogTextureFlags
& ETDT_ENABLE
) && !(dwDialogTextureFlags
& ETDT_DISABLE
);
67 /***********************************************************************
68 * DrawThemeParentBackground (UXTHEME.@)
70 HRESULT WINAPI
DrawThemeParentBackground(HWND hwnd
, HDC hdc
, RECT
*prc
)
78 TRACE("(%p,%p,%p)\n", hwnd
, hdc
, prc
);
79 hParent
= GetParent(hwnd
);
84 MapWindowPoints(hwnd
, NULL
, (LPPOINT
)&rt
, 2);
86 clip
= CreateRectRgn(0,0,1,1);
87 hasClip
= GetClipRgn(hdc
, clip
);
89 TRACE("Failed to get original clipping region\n");
91 IntersectClipRect(hdc
, prc
->left
, prc
->top
, prc
->right
, prc
->bottom
);
94 GetClientRect(hParent
, &rt
);
95 MapWindowPoints(hParent
, NULL
, (LPPOINT
)&rt
, 2);
98 SetViewportOrgEx(hdc
, rt
.left
, rt
.top
, &org
);
100 SendMessageW(hParent
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
101 SendMessageW(hParent
, WM_PRINTCLIENT
, (WPARAM
)hdc
, PRF_CLIENT
);
103 SetViewportOrgEx(hdc
, org
.x
, org
.y
, NULL
);
106 SelectClipRgn(hdc
, NULL
);
107 else if(hasClip
== 1)
108 SelectClipRgn(hdc
, clip
);
115 /***********************************************************************
116 * DrawThemeBackground (UXTHEME.@)
118 HRESULT WINAPI
DrawThemeBackground(HTHEME hTheme
, HDC hdc
, int iPartId
,
119 int iStateId
, const RECT
*pRect
,
120 const RECT
*pClipRect
)
123 opts
.dwSize
= sizeof(DTBGOPTS
);
126 opts
.dwFlags
|= DTBG_CLIPRECT
;
127 CopyRect(&opts
.rcClip
, pClipRect
);
129 return DrawThemeBackgroundEx(hTheme
, hdc
, iPartId
, iStateId
, pRect
, &opts
);
132 /***********************************************************************
133 * UXTHEME_SelectImage
135 * Select the image to use
137 PTHEME_PROPERTY
UXTHEME_SelectImage(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
, const RECT
*pRect
, BOOL glyph
)
140 int imageselecttype
= IST_NONE
;
144 image
= TMT_GLYPHIMAGEFILE
;
146 image
= TMT_IMAGEFILE
;
148 if((tp
=MSSTYLES_FindProperty(hTheme
, iPartId
, iStateId
, TMT_FILENAME
, image
)))
150 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_IMAGESELECTTYPE
, &imageselecttype
);
152 if(imageselecttype
== IST_DPI
) {
154 int screendpi
= GetDeviceCaps(hdc
, LOGPIXELSX
);
155 for(i
=4; i
>=0; i
--) {
157 if(SUCCEEDED(GetThemeInt(hTheme
, iPartId
, iStateId
, i
+ TMT_MINDPI1
, &reqdpi
))) {
158 if(reqdpi
!= 0 && screendpi
>= reqdpi
) {
159 TRACE("Using %d DPI, image %d\n", reqdpi
, i
+ TMT_IMAGEFILE1
);
160 return MSSTYLES_FindProperty(hTheme
, iPartId
, iStateId
, TMT_FILENAME
, i
+ TMT_IMAGEFILE1
);
164 /* If an image couldnt be selected, choose the first one */
165 return MSSTYLES_FindProperty(hTheme
, iPartId
, iStateId
, TMT_FILENAME
, TMT_IMAGEFILE1
);
167 else if(imageselecttype
== IST_SIZE
) {
168 POINT size
= {pRect
->right
-pRect
->left
, pRect
->bottom
-pRect
->top
};
170 for(i
=4; i
>=0; i
--) {
171 if(SUCCEEDED(GetThemePosition(hTheme
, iPartId
, iStateId
, i
+ TMT_MINSIZE1
, &reqsize
))) {
172 if(reqsize
.x
>= size
.x
&& reqsize
.y
>= size
.y
) {
173 TRACE("Using image size %ldx%ld, image %d\n", reqsize
.x
, reqsize
.y
, i
+ TMT_IMAGEFILE1
);
174 return MSSTYLES_FindProperty(hTheme
, iPartId
, iStateId
, TMT_FILENAME
, i
+ TMT_IMAGEFILE1
);
178 /* If an image couldnt be selected, choose the smallest one */
179 return MSSTYLES_FindProperty(hTheme
, iPartId
, iStateId
, TMT_FILENAME
, TMT_IMAGEFILE1
);
184 /***********************************************************************
187 * Load image for part/state
189 HRESULT
UXTHEME_LoadImage(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
, const RECT
*pRect
, BOOL glyph
,
190 HBITMAP
*hBmp
, RECT
*bmpRect
)
192 int imagelayout
= IL_VERTICAL
;
195 WCHAR szPath
[MAX_PATH
];
196 PTHEME_PROPERTY tp
= UXTHEME_SelectImage(hTheme
, hdc
, iPartId
, iStateId
, pRect
, glyph
);
198 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId
, iStateId
);
199 return E_PROP_ID_UNSUPPORTED
;
201 lstrcpynW(szPath
, tp
->lpValue
, min(tp
->dwValueLen
+1, sizeof(szPath
)/sizeof(szPath
[0])));
202 *hBmp
= MSSTYLES_LoadBitmap(hdc
, hTheme
, szPath
);
204 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath
));
205 return HRESULT_FROM_WIN32(GetLastError());
208 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_IMAGELAYOUT
, &imagelayout
);
209 GetThemeInt(hTheme
, iPartId
, iStateId
, TMT_IMAGECOUNT
, &imagecount
);
211 GetObjectW(*hBmp
, sizeof(bmp
), &bmp
);
212 if(imagelayout
== IL_VERTICAL
) {
213 int height
= bmp
.bmHeight
/imagecount
;
215 bmpRect
->right
= bmp
.bmWidth
;
216 bmpRect
->top
= (min(imagecount
, iStateId
)-1) * height
;
217 bmpRect
->bottom
= bmpRect
->top
+ height
;
220 int width
= bmp
.bmWidth
/imagecount
;
221 bmpRect
->left
= (min(imagecount
, iStateId
)-1) * width
;
222 bmpRect
->right
= bmpRect
->left
+ width
;
224 bmpRect
->bottom
= bmp
.bmHeight
;
229 /***********************************************************************
232 * Psudo TransparentBlt/StretchBlt
234 static inline BOOL
UXTHEME_StretchBlt(HDC hdcDst
, int nXOriginDst
, int nYOriginDst
, int nWidthDst
, int nHeightDst
,
235 HDC hdcSrc
, int nXOriginSrc
, int nYOriginSrc
, int nWidthSrc
, int nHeightSrc
,
236 BOOL transparent
, COLORREF transcolor
)
239 /* Ensure we don't pass any negative values to TransparentBlt */
240 return TransparentBlt(hdcDst
, nXOriginDst
, nYOriginDst
, abs(nWidthDst
), abs(nHeightDst
),
241 hdcSrc
, nXOriginSrc
, nYOriginSrc
, abs(nWidthSrc
), abs(nHeightSrc
),
244 /* This should be using AlphaBlend */
245 return StretchBlt(hdcDst
, nXOriginDst
, nYOriginDst
, nWidthDst
, nHeightDst
,
246 hdcSrc
, nXOriginSrc
, nYOriginSrc
, nWidthSrc
, nHeightSrc
,
250 /***********************************************************************
253 * Simplify sending same width/height for both source and dest
255 static inline BOOL
UXTHEME_Blt(HDC hdcDest
, int nXOriginDest
, int nYOriginDest
, int nWidthDest
, int nHeightDest
,
256 HDC hdcSrc
, int nXOriginSrc
, int nYOriginSrc
,
257 BOOL transparent
, COLORREF transcolor
)
259 return UXTHEME_StretchBlt(hdcDest
, nXOriginDest
, nYOriginDest
, nWidthDest
, nHeightDest
,
260 hdcSrc
, nXOriginSrc
, nYOriginSrc
, nWidthDest
, nHeightDest
,
261 transparent
, transcolor
);
265 /***********************************************************************
266 * UXTHEME_DrawImageGlyph
268 * Draw an imagefile glyph
270 HRESULT
UXTHEME_DrawImageGlyph(HTHEME hTheme
, HDC hdc
, int iPartId
,
271 int iStateId
, RECT
*pRect
,
272 const DTBGOPTS
*pOptions
)
275 HBITMAP bmpSrc
= NULL
;
277 HGDIOBJ oldSrc
= NULL
;
279 BOOL transparent
= FALSE
;
280 COLORREF transparentcolor
= 0;
281 int valign
= VA_CENTER
;
282 int halign
= HA_CENTER
;
287 hr
= UXTHEME_LoadImage(hTheme
, hdc
, iPartId
, iStateId
, pRect
, TRUE
, &bmpSrc
, &rcSrc
);
288 if(FAILED(hr
)) return hr
;
289 hdcSrc
= CreateCompatibleDC(hdc
);
291 hr
= HRESULT_FROM_WIN32(GetLastError());
292 DeleteObject(bmpSrc
);
295 oldSrc
= SelectObject(hdcSrc
, bmpSrc
);
297 dstSize
.x
= pRect
->right
-pRect
->left
;
298 dstSize
.y
= pRect
->bottom
-pRect
->top
;
299 srcSize
.x
= rcSrc
.right
-rcSrc
.left
;
300 srcSize
.y
= rcSrc
.bottom
-rcSrc
.top
;
302 GetThemeBool(hTheme
, iPartId
, iStateId
, TMT_GLYPHTRANSPARENT
, &transparent
);
304 if(FAILED(GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_GLYPHTRANSPARENTCOLOR
, &transparentcolor
))) {
305 /* If image is transparent, but no color was specified, get the color of the upper left corner */
306 transparentcolor
= GetPixel(hdcSrc
, 0, 0);
309 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_VALIGN
, &valign
);
310 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_HALIGN
, &halign
);
312 topleft
.x
= pRect
->left
;
313 topleft
.y
= pRect
->top
;
314 if(halign
== HA_CENTER
) topleft
.x
+= (dstSize
.x
/2)-(srcSize
.x
/2);
315 else if(halign
== HA_RIGHT
) topleft
.x
+= dstSize
.x
-srcSize
.x
;
316 if(valign
== VA_CENTER
) topleft
.y
+= (dstSize
.y
/2)-(srcSize
.y
/2);
317 else if(valign
== VA_BOTTOM
) topleft
.y
+= dstSize
.y
-srcSize
.y
;
319 if(!UXTHEME_Blt(hdc
, topleft
.x
, topleft
.y
, srcSize
.x
, srcSize
.y
,
320 hdcSrc
, rcSrc
.left
, rcSrc
.top
,
321 transparent
, transparentcolor
)) {
322 hr
= HRESULT_FROM_WIN32(GetLastError());
325 SelectObject(hdcSrc
, oldSrc
);
327 DeleteObject(bmpSrc
);
331 /***********************************************************************
332 * UXTHEME_DrawImageGlyph
334 * Draw glyph on top of background, if appropriate
336 HRESULT
UXTHEME_DrawGlyph(HTHEME hTheme
, HDC hdc
, int iPartId
,
337 int iStateId
, RECT
*pRect
,
338 const DTBGOPTS
*pOptions
)
340 int glyphtype
= GT_NONE
;
342 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_GLYPHTYPE
, &glyphtype
);
344 if(glyphtype
== GT_IMAGEGLYPH
) {
345 return UXTHEME_DrawImageGlyph(hTheme
, hdc
, iPartId
, iStateId
, pRect
, pOptions
);
347 else if(glyphtype
== GT_FONTGLYPH
) {
348 /* I don't know what a font glyph is, I've never seen it used in any themes */
349 FIXME("Font glyph\n");
354 /***********************************************************************
355 * UXTHEME_DrawImageBackground
357 * Draw an imagefile background
359 HRESULT
UXTHEME_DrawImageBackground(HTHEME hTheme
, HDC hdc
, int iPartId
,
360 int iStateId
, RECT
*pRect
,
361 const DTBGOPTS
*pOptions
)
371 int sizingtype
= ST_TRUESIZE
;
372 BOOL uniformsizing
= FALSE
;
373 BOOL transparent
= FALSE
;
374 COLORREF transparentcolor
= 0;
376 hr
= UXTHEME_LoadImage(hTheme
, hdc
, iPartId
, iStateId
, pRect
, FALSE
, &bmpSrc
, &rcSrc
);
377 if(FAILED(hr
)) return hr
;
378 hdcSrc
= CreateCompatibleDC(hdc
);
380 hr
= HRESULT_FROM_WIN32(GetLastError());
381 DeleteObject(bmpSrc
);
384 oldSrc
= SelectObject(hdcSrc
, bmpSrc
);
386 CopyRect(&rcDst
, pRect
);
388 GetThemeBool(hTheme
, iPartId
, iStateId
, TMT_TRANSPARENT
, &transparent
);
390 if(FAILED(GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_TRANSPARENTCOLOR
, &transparentcolor
))) {
391 /* If image is transparent, but no color was specified, get the color of the upper left corner */
392 transparentcolor
= GetPixel(hdcSrc
, 0, 0);
396 dstSize
.x
= rcDst
.right
-rcDst
.left
;
397 dstSize
.y
= rcDst
.bottom
-rcDst
.top
;
398 srcSize
.x
= rcSrc
.right
-rcSrc
.left
;
399 srcSize
.y
= rcSrc
.bottom
-rcSrc
.top
;
401 GetThemeBool(hTheme
, iPartId
, iStateId
, TMT_UNIFORMSIZING
, &uniformsizing
);
403 /* Scale height and width equally */
404 int widthDiff
= abs(srcSize
.x
-dstSize
.x
);
405 int heightDiff
= abs(srcSize
.y
-dstSize
.x
);
406 if(widthDiff
> heightDiff
) {
407 dstSize
.y
-= widthDiff
-heightDiff
;
408 rcDst
.bottom
= rcDst
.top
+ dstSize
.y
;
410 else if(heightDiff
> widthDiff
) {
411 dstSize
.x
-= heightDiff
-widthDiff
;
412 rcDst
.right
= rcDst
.left
+ dstSize
.x
;
416 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_SIZINGTYPE
, &sizingtype
);
417 if(sizingtype
== ST_TRUESIZE
) {
418 int truesizestretchmark
= 0;
420 if(dstSize
.x
< 0 || dstSize
.y
< 0) {
421 BOOL mirrorimage
= TRUE
;
422 GetThemeBool(hTheme
, iPartId
, iStateId
, TMT_MIRRORIMAGE
, &mirrorimage
);
425 rcDst
.left
+= dstSize
.x
;
426 rcDst
.right
+= dstSize
.x
;
429 rcDst
.top
+= dstSize
.y
;
430 rcDst
.bottom
+= dstSize
.y
;
434 /* Only stretch when target exceeds source by truesizestretchmark percent */
435 GetThemeInt(hTheme
, iPartId
, iStateId
, TMT_TRUESIZESTRETCHMARK
, &truesizestretchmark
);
436 if(dstSize
.x
< 0 || dstSize
.y
< 0 ||
437 MulDiv(srcSize
.x
, 100, dstSize
.x
) > truesizestretchmark
||
438 MulDiv(srcSize
.y
, 100, dstSize
.y
) > truesizestretchmark
) {
439 if(!UXTHEME_StretchBlt(hdc
, rcDst
.left
, rcDst
.top
, dstSize
.x
, dstSize
.y
,
440 hdcSrc
, rcSrc
.left
, rcSrc
.top
, srcSize
.x
, srcSize
.y
,
441 transparent
, transparentcolor
))
442 hr
= HRESULT_FROM_WIN32(GetLastError());
445 rcDst
.left
+= (dstSize
.x
/2)-(srcSize
.x
/2);
446 rcDst
.top
+= (dstSize
.y
/2)-(srcSize
.y
/2);
447 rcDst
.right
= rcDst
.left
+ srcSize
.x
;
448 rcDst
.bottom
= rcDst
.top
+ srcSize
.y
;
449 if(!UXTHEME_Blt(hdc
, rcDst
.left
, rcDst
.top
, srcSize
.x
, srcSize
.y
,
450 hdcSrc
, rcSrc
.left
, rcSrc
.top
,
451 transparent
, transparentcolor
))
452 hr
= HRESULT_FROM_WIN32(GetLastError());
457 HBITMAP bmpDst
= NULL
;
458 HGDIOBJ oldDst
= NULL
;
461 dstSize
.x
= abs(dstSize
.x
);
462 dstSize
.y
= abs(dstSize
.y
);
464 GetThemeMargins(hTheme
, hdc
, iPartId
, iStateId
, TMT_SIZINGMARGINS
, NULL
, &sm
);
466 hdcDst
= CreateCompatibleDC(hdc
);
468 hr
= HRESULT_FROM_WIN32(GetLastError());
471 bmpDst
= CreateCompatibleBitmap(hdc
, dstSize
.x
, dstSize
.y
);
473 hr
= HRESULT_FROM_WIN32(GetLastError());
476 oldDst
= SelectObject(hdcDst
, bmpDst
);
478 /* Upper left corner */
479 if(!BitBlt(hdcDst
, 0, 0, sm
.cxLeftWidth
, sm
.cyTopHeight
,
480 hdcSrc
, rcSrc
.left
, rcSrc
.top
, SRCCOPY
)) {
481 hr
= HRESULT_FROM_WIN32(GetLastError());
484 /* Upper right corner */
485 if(!BitBlt(hdcDst
, dstSize
.x
-sm
.cxRightWidth
, 0, sm
.cxRightWidth
, sm
.cyTopHeight
,
486 hdcSrc
, rcSrc
.right
-sm
.cxRightWidth
, rcSrc
.top
, SRCCOPY
)) {
487 hr
= HRESULT_FROM_WIN32(GetLastError());
490 /* Lower left corner */
491 if(!BitBlt(hdcDst
, 0, dstSize
.y
-sm
.cyBottomHeight
, sm
.cxLeftWidth
, sm
.cyBottomHeight
,
492 hdcSrc
, rcSrc
.left
, rcSrc
.bottom
-sm
.cyBottomHeight
, SRCCOPY
)) {
493 hr
= HRESULT_FROM_WIN32(GetLastError());
496 /* Lower right corner */
497 if(!BitBlt(hdcDst
, dstSize
.x
-sm
.cxRightWidth
, dstSize
.y
-sm
.cyBottomHeight
, sm
.cxRightWidth
, sm
.cyBottomHeight
,
498 hdcSrc
, rcSrc
.right
-sm
.cxRightWidth
, rcSrc
.bottom
-sm
.cyBottomHeight
, SRCCOPY
)) {
499 hr
= HRESULT_FROM_WIN32(GetLastError());
503 if(sizingtype
== ST_TILE
) {
505 sizingtype
= ST_STRETCH
; /* Just use stretch for now */
507 if(sizingtype
== ST_STRETCH
) {
508 int destCenterWidth
= dstSize
.x
- (sm
.cxLeftWidth
+ sm
.cxRightWidth
);
509 int srcCenterWidth
= srcSize
.x
- (sm
.cxLeftWidth
+ sm
.cxRightWidth
);
510 int destCenterHeight
= dstSize
.y
- (sm
.cyTopHeight
+ sm
.cyBottomHeight
);
511 int srcCenterHeight
= srcSize
.y
- (sm
.cyTopHeight
+ sm
.cyBottomHeight
);
513 if(destCenterWidth
> 0) {
515 if(!StretchBlt(hdcDst
, sm
.cxLeftWidth
, 0, destCenterWidth
, sm
.cyTopHeight
,
516 hdcSrc
, rcSrc
.left
+sm
.cxLeftWidth
, rcSrc
.top
, srcCenterWidth
, sm
.cyTopHeight
, SRCCOPY
)) {
517 hr
= HRESULT_FROM_WIN32(GetLastError());
521 if(!StretchBlt(hdcDst
, sm
.cxLeftWidth
, dstSize
.y
-sm
.cyBottomHeight
, destCenterWidth
, sm
.cyBottomHeight
,
522 hdcSrc
, rcSrc
.left
+sm
.cxLeftWidth
, rcSrc
.bottom
-sm
.cyBottomHeight
, srcCenterWidth
, sm
.cyTopHeight
, SRCCOPY
)) {
523 hr
= HRESULT_FROM_WIN32(GetLastError());
527 if(destCenterHeight
> 0) {
529 if(!StretchBlt(hdcDst
, 0, sm
.cyTopHeight
, sm
.cxLeftWidth
, destCenterHeight
,
530 hdcSrc
, rcSrc
.left
, rcSrc
.top
+sm
.cyTopHeight
, sm
.cxLeftWidth
, srcCenterHeight
, SRCCOPY
)) {
531 hr
= HRESULT_FROM_WIN32(GetLastError());
535 if(!StretchBlt(hdcDst
, dstSize
.x
-sm
.cxRightWidth
, sm
.cyTopHeight
, sm
.cxRightWidth
, destCenterHeight
,
536 hdcSrc
, rcSrc
.right
-sm
.cxRightWidth
, rcSrc
.top
+sm
.cyTopHeight
, sm
.cxRightWidth
, srcCenterHeight
, SRCCOPY
)) {
537 hr
= HRESULT_FROM_WIN32(GetLastError());
541 if(destCenterHeight
> 0 && destCenterWidth
> 0) {
542 BOOL borderonly
= FALSE
;
543 GetThemeBool(hTheme
, iPartId
, iStateId
, TMT_BORDERONLY
, &borderonly
);
546 if(!StretchBlt(hdcDst
, sm
.cxLeftWidth
, sm
.cyTopHeight
, destCenterWidth
, destCenterHeight
,
547 hdcSrc
, rcSrc
.left
+sm
.cxLeftWidth
, rcSrc
.top
+sm
.cyTopHeight
, srcCenterWidth
, srcCenterHeight
, SRCCOPY
)) {
548 hr
= HRESULT_FROM_WIN32(GetLastError());
555 if(!UXTHEME_Blt(hdc
, rcDst
.left
, rcDst
.top
, dstSize
.x
, dstSize
.y
,
557 transparent
, transparentcolor
))
558 hr
= HRESULT_FROM_WIN32(GetLastError());
562 SelectObject(hdcDst
, oldDst
);
565 if(bmpDst
) DeleteObject(bmpDst
);
567 SelectObject(hdcSrc
, oldSrc
);
568 DeleteObject(bmpSrc
);
570 CopyRect(pRect
, &rcDst
);
574 /***********************************************************************
575 * UXTHEME_DrawBorderRectangle
577 * Draw the bounding rectangle for a borderfill background
579 HRESULT
UXTHEME_DrawBorderRectangle(HTHEME hTheme
, HDC hdc
, int iPartId
,
580 int iStateId
, RECT
*pRect
,
581 const DTBGOPTS
*pOptions
)
586 COLORREF bordercolor
= RGB(0,0,0);
589 GetThemeInt(hTheme
, iPartId
, iStateId
, TMT_BORDERSIZE
, &bordersize
);
592 ptCorners
[0].x
= pRect
->left
;
593 ptCorners
[0].y
= pRect
->top
;
594 ptCorners
[1].x
= pRect
->right
;
595 ptCorners
[1].y
= pRect
->top
;
596 ptCorners
[2].x
= pRect
->right
;
597 ptCorners
[2].y
= pRect
->bottom
;
598 ptCorners
[3].x
= pRect
->left
;
599 ptCorners
[3].y
= pRect
->bottom
;
601 InflateRect(pRect
, -bordersize
, -bordersize
);
602 if(pOptions
->dwFlags
& DTBG_OMITBORDER
)
604 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_BORDERCOLOR
, &bordercolor
);
605 hPen
= CreatePen(PS_SOLID
, bordersize
, bordercolor
);
607 return HRESULT_FROM_WIN32(GetLastError());
608 oldPen
= SelectObject(hdc
, hPen
);
610 if(!Polyline(hdc
, ptCorners
, 4))
611 hr
= HRESULT_FROM_WIN32(GetLastError());
613 SelectObject(hdc
, oldPen
);
619 /***********************************************************************
620 * UXTHEME_DrawBackgroundFill
622 * Fill a borderfill background rectangle
624 HRESULT
UXTHEME_DrawBackgroundFill(HTHEME hTheme
, HDC hdc
, int iPartId
,
625 int iStateId
, RECT
*pRect
,
626 const DTBGOPTS
*pOptions
)
629 int filltype
= FT_SOLID
;
631 TRACE("(%d,%d,%ld)\n", iPartId
, iStateId
, pOptions
->dwFlags
);
633 if(pOptions
->dwFlags
& DTBG_OMITCONTENT
)
636 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_FILLTYPE
, &filltype
);
638 if(filltype
== FT_SOLID
) {
640 COLORREF fillcolor
= RGB(255,255,255);
642 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_FILLCOLOR
, &fillcolor
);
643 hBrush
= CreateSolidBrush(fillcolor
);
644 if(!FillRect(hdc
, pRect
, hBrush
))
645 hr
= HRESULT_FROM_WIN32(GetLastError());
646 DeleteObject(hBrush
);
648 else if(filltype
== FT_VERTGRADIENT
|| filltype
== FT_HORZGRADIENT
) {
649 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
650 the gradient ratios (no idea how those work)
651 Few themes use this, and the ones I've seen only use 2 colors with
652 a gradient ratio of 0 and 255 respectivly
655 COLORREF gradient1
= RGB(0,0,0);
656 COLORREF gradient2
= RGB(255,255,255);
660 FIXME("Gradient implementation not complete\n");
662 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_GRADIENTCOLOR1
, &gradient1
);
663 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_GRADIENTCOLOR2
, &gradient2
);
665 vert
[0].x
= pRect
->left
;
666 vert
[0].y
= pRect
->top
;
667 vert
[0].Red
= GetRValue(gradient1
) << 8;
668 vert
[0].Green
= GetGValue(gradient1
) << 8;
669 vert
[0].Blue
= GetBValue(gradient1
) << 8;
670 vert
[0].Alpha
= 0x0000;
672 vert
[1].x
= pRect
->right
;
673 vert
[1].y
= pRect
->bottom
;
674 vert
[1].Red
= GetRValue(gradient2
) << 8;
675 vert
[1].Green
= GetGValue(gradient2
) << 8;
676 vert
[1].Blue
= GetBValue(gradient2
) << 8;
677 vert
[1].Alpha
= 0x0000;
680 gRect
.LowerRight
= 1;
681 GradientFill(hdc
,vert
,2,&gRect
,1,filltype
==FT_HORZGRADIENT
?GRADIENT_FILL_RECT_H
:GRADIENT_FILL_RECT_V
);
683 else if(filltype
== FT_RADIALGRADIENT
) {
684 /* I've never seen this used in a theme */
685 FIXME("Radial gradient\n");
687 else if(filltype
== FT_TILEIMAGE
) {
688 /* I've never seen this used in a theme */
689 FIXME("Tile image\n");
694 /***********************************************************************
695 * UXTHEME_DrawBorderBackground
697 * Draw an imagefile background
699 HRESULT
UXTHEME_DrawBorderBackground(HTHEME hTheme
, HDC hdc
, int iPartId
,
700 int iStateId
, const RECT
*pRect
,
701 const DTBGOPTS
*pOptions
)
706 CopyRect(&rt
, pRect
);
708 hr
= UXTHEME_DrawBorderRectangle(hTheme
, hdc
, iPartId
, iStateId
, &rt
, pOptions
);
711 return UXTHEME_DrawBackgroundFill(hTheme
, hdc
, iPartId
, iStateId
, &rt
, pOptions
);
714 /***********************************************************************
715 * DrawThemeBackgroundEx (UXTHEME.@)
717 HRESULT WINAPI
DrawThemeBackgroundEx(HTHEME hTheme
, HDC hdc
, int iPartId
,
718 int iStateId
, const RECT
*pRect
,
719 const DTBGOPTS
*pOptions
)
722 const DTBGOPTS defaultOpts
= {sizeof(DTBGOPTS
), 0, {0,0,0,0}};
723 const DTBGOPTS
*opts
;
726 int bgtype
= BT_BORDERFILL
;
729 TRACE("(%p,%p,%d,%d,%ld,%ld)\n", hTheme
, hdc
, iPartId
, iStateId
,pRect
->left
,pRect
->top
);
733 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
735 if(!opts
) opts
= &defaultOpts
;
737 if(opts
->dwFlags
& DTBG_CLIPRECT
) {
738 clip
= CreateRectRgn(0,0,1,1);
739 hasClip
= GetClipRgn(hdc
, clip
);
741 TRACE("Failed to get original clipping region\n");
743 IntersectClipRect(hdc
, opts
->rcClip
.left
, opts
->rcClip
.top
, opts
->rcClip
.right
, opts
->rcClip
.bottom
);
745 CopyRect(&rt
, pRect
);
747 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_BGTYPE
, &bgtype
);
748 if(bgtype
== BT_IMAGEFILE
)
749 hr
= UXTHEME_DrawImageBackground(hTheme
, hdc
, iPartId
, iStateId
, &rt
, opts
);
750 else if(bgtype
== BT_BORDERFILL
)
751 hr
= UXTHEME_DrawBorderBackground(hTheme
, hdc
, iPartId
, iStateId
, pRect
, opts
);
753 FIXME("Unknown background type\n");
754 /* This should never happen, and hence I don't know what to return */
758 hr
= UXTHEME_DrawGlyph(hTheme
, hdc
, iPartId
, iStateId
, &rt
, opts
);
759 if(opts
->dwFlags
& DTBG_CLIPRECT
) {
761 SelectClipRgn(hdc
, NULL
);
762 else if(hasClip
== 1)
763 SelectClipRgn(hdc
, clip
);
769 /***********************************************************************
770 * DrawThemeEdge (UXTHEME.@)
772 HRESULT WINAPI
DrawThemeEdge(HTHEME hTheme
, HDC hdc
, int iPartId
,
773 int iStateId
, const RECT
*pDestRect
, UINT uEdge
,
774 UINT uFlags
, RECT
*pContentRect
)
776 FIXME("%d %d 0x%08x 0x%08x: stub\n", iPartId
, iStateId
, uEdge
, uFlags
);
779 return ERROR_CALL_NOT_IMPLEMENTED
;
782 /***********************************************************************
783 * DrawThemeIcon (UXTHEME.@)
785 HRESULT WINAPI
DrawThemeIcon(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
,
786 const RECT
*pRect
, HIMAGELIST himl
, int iImageIndex
)
788 FIXME("%d %d: stub\n", iPartId
, iStateId
);
791 return ERROR_CALL_NOT_IMPLEMENTED
;
794 /***********************************************************************
795 * DrawThemeText (UXTHEME.@)
797 HRESULT WINAPI
DrawThemeText(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
,
798 LPCWSTR pszText
, int iCharCount
, DWORD dwTextFlags
,
799 DWORD dwTextFlags2
, const RECT
*pRect
)
803 HGDIOBJ oldFont
= NULL
;
806 COLORREF oldTextColor
;
810 TRACE("%d %d: stub\n", iPartId
, iStateId
);
814 hr
= GetThemeFont(hTheme
, hdc
, iPartId
, iStateId
, TMT_FONT
, &logfont
);
816 hFont
= CreateFontIndirectW(&logfont
);
818 TRACE("Failed to create font\n");
820 CopyRect(&rt
, pRect
);
822 oldFont
= SelectObject(hdc
, hFont
);
824 if(dwTextFlags2
& DTT_GRAYED
)
825 textColor
= GetSysColor(COLOR_GRAYTEXT
);
827 if(FAILED(GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_TEXTCOLOR
, &textColor
)))
828 textColor
= GetTextColor(hdc
);
830 oldTextColor
= SetTextColor(hdc
, textColor
);
831 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
832 DrawTextW(hdc
, pszText
, iCharCount
, &rt
, dwTextFlags
);
833 SetBkMode(hdc
, oldBkMode
);
834 SetTextColor(hdc
, oldTextColor
);
837 SelectObject(hdc
, oldFont
);
843 /***********************************************************************
844 * GetThemeBackgroundContentRect (UXTHEME.@)
846 HRESULT WINAPI
GetThemeBackgroundContentRect(HTHEME hTheme
, HDC hdc
, int iPartId
,
848 const RECT
*pBoundingRect
,
854 TRACE("(%d,%d)\n", iPartId
, iStateId
);
858 hr
= GetThemeMargins(hTheme
, hdc
, iPartId
, iStateId
, TMT_CONTENTMARGINS
, NULL
, &margin
);
860 TRACE("Margins not found\n");
863 pContentRect
->left
= pBoundingRect
->left
+ margin
.cxLeftWidth
;
864 pContentRect
->top
= pBoundingRect
->top
+ margin
.cyTopHeight
;
865 pContentRect
->right
= pBoundingRect
->right
- margin
.cxRightWidth
;
866 pContentRect
->bottom
= pBoundingRect
->bottom
- margin
.cyBottomHeight
;
868 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect
->left
, pContentRect
->top
, pContentRect
->right
, pContentRect
->bottom
);
873 /***********************************************************************
874 * GetThemeBackgroundExtent (UXTHEME.@)
876 HRESULT WINAPI
GetThemeBackgroundExtent(HTHEME hTheme
, HDC hdc
, int iPartId
,
877 int iStateId
, const RECT
*pContentRect
,
883 TRACE("(%d,%d)\n", iPartId
, iStateId
);
887 hr
= GetThemeMargins(hTheme
, hdc
, iPartId
, iStateId
, TMT_CONTENTMARGINS
, NULL
, &margin
);
889 TRACE("Margins not found\n");
892 pExtentRect
->left
= pContentRect
->left
- margin
.cxLeftWidth
;
893 pExtentRect
->top
= pContentRect
->top
- margin
.cyTopHeight
;
894 pExtentRect
->right
= pContentRect
->right
+ margin
.cxRightWidth
;
895 pExtentRect
->bottom
= pContentRect
->bottom
+ margin
.cyBottomHeight
;
897 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pExtentRect
->left
, pExtentRect
->top
, pExtentRect
->right
, pExtentRect
->bottom
);
902 /***********************************************************************
903 * GetThemeBackgroundRegion (UXTHEME.@)
905 * Calculate the background region, taking into consideration transparent areas
906 * of the background image.
908 HRESULT WINAPI
GetThemeBackgroundRegion(HTHEME hTheme
, HDC hdc
, int iPartId
,
909 int iStateId
, const RECT
*pRect
,
913 int bgtype
= BT_BORDERFILL
;
915 TRACE("(%p,%p,%d,%d)\n", hTheme
, hdc
, iPartId
, iStateId
);
918 if(!pRect
|| !pRegion
)
921 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_BGTYPE
, &bgtype
);
922 if(bgtype
== BT_IMAGEFILE
) {
923 FIXME("Images not handled yet\n");
924 hr
= ERROR_CALL_NOT_IMPLEMENTED
;
926 else if(bgtype
== BT_BORDERFILL
) {
927 *pRegion
= CreateRectRgn(pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
929 hr
= HRESULT_FROM_WIN32(GetLastError());
932 FIXME("Unknown background type\n");
933 /* This should never happen, and hence I don't know what to return */
939 /***********************************************************************
940 * GetThemePartSize (UXTHEME.@)
942 HRESULT WINAPI
GetThemePartSize(HTHEME hTheme
, HDC hdc
, int iPartId
,
943 int iStateId
, RECT
*prc
, THEMESIZE eSize
,
946 FIXME("%d %d %d: stub\n", iPartId
, iStateId
, eSize
);
949 return ERROR_CALL_NOT_IMPLEMENTED
;
953 /***********************************************************************
954 * GetThemeTextExtent (UXTHEME.@)
956 HRESULT WINAPI
GetThemeTextExtent(HTHEME hTheme
, HDC hdc
, int iPartId
,
957 int iStateId
, LPCWSTR pszText
, int iCharCount
,
958 DWORD dwTextFlags
, const RECT
*pBoundingRect
,
963 HGDIOBJ oldFont
= NULL
;
965 RECT rt
= {0,0,0xFFFF,0xFFFF};
967 TRACE("%d %d: stub\n", iPartId
, iStateId
);
972 CopyRect(&rt
, pBoundingRect
);
974 hr
= GetThemeFont(hTheme
, hdc
, iPartId
, iStateId
, TMT_FONT
, &logfont
);
976 hFont
= CreateFontIndirectW(&logfont
);
978 TRACE("Failed to create font\n");
981 oldFont
= SelectObject(hdc
, hFont
);
983 DrawTextW(hdc
, pszText
, iCharCount
, &rt
, dwTextFlags
|DT_CALCRECT
);
984 CopyRect(pExtentRect
, &rt
);
987 SelectObject(hdc
, oldFont
);
993 /***********************************************************************
994 * GetThemeTextMetrics (UXTHEME.@)
996 HRESULT WINAPI
GetThemeTextMetrics(HTHEME hTheme
, HDC hdc
, int iPartId
,
997 int iStateId
, TEXTMETRICW
*ptm
)
1001 HGDIOBJ oldFont
= NULL
;
1004 TRACE("(%p, %p, %d, %d)\n", hTheme
, hdc
, iPartId
, iStateId
);
1008 hr
= GetThemeFont(hTheme
, hdc
, iPartId
, iStateId
, TMT_FONT
, &logfont
);
1010 hFont
= CreateFontIndirectW(&logfont
);
1012 TRACE("Failed to create font\n");
1015 oldFont
= SelectObject(hdc
, hFont
);
1017 if(!GetTextMetricsW(hdc
, ptm
))
1018 hr
= HRESULT_FROM_WIN32(GetLastError());
1021 SelectObject(hdc
, oldFont
);
1022 DeleteObject(hFont
);
1027 /***********************************************************************
1028 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1030 BOOL WINAPI
IsThemeBackgroundPartiallyTransparent(HTHEME hTheme
, int iPartId
,
1033 BOOL transparent
= FALSE
;
1034 TRACE("(%d,%d)\n", iPartId
, iStateId
);
1035 GetThemeBool(hTheme
, iPartId
, iStateId
, TMT_TRANSPARENT
, &transparent
);