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(HWND hwnd
)
63 TRACE("(%p)\n", hwnd
);
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 OffsetViewportOrgEx(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 static 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 static 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
= (max(min(imagecount
, iStateId
), 1)-1) * height
;
217 bmpRect
->bottom
= bmpRect
->top
+ height
;
220 int width
= bmp
.bmWidth
/imagecount
;
221 bmpRect
->left
= (max(min(imagecount
, iStateId
), 1)-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 static 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, use magenta */
306 transparentcolor
= RGB(255, 0, 255);
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 static 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 static 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 static 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
-1;
595 ptCorners
[1].y
= pRect
->top
;
596 ptCorners
[2].x
= pRect
->right
-1;
597 ptCorners
[2].y
= pRect
->bottom
-1;
598 ptCorners
[3].x
= pRect
->left
;
599 ptCorners
[3].y
= pRect
->bottom
-1;
600 ptCorners
[4].x
= pRect
->left
;
601 ptCorners
[4].y
= pRect
->top
;
603 InflateRect(pRect
, -bordersize
, -bordersize
);
604 if(pOptions
->dwFlags
& DTBG_OMITBORDER
)
606 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_BORDERCOLOR
, &bordercolor
);
607 hPen
= CreatePen(PS_SOLID
, bordersize
, bordercolor
);
609 return HRESULT_FROM_WIN32(GetLastError());
610 oldPen
= SelectObject(hdc
, hPen
);
612 if(!Polyline(hdc
, ptCorners
, 5))
613 hr
= HRESULT_FROM_WIN32(GetLastError());
615 SelectObject(hdc
, oldPen
);
621 /***********************************************************************
622 * UXTHEME_DrawBackgroundFill
624 * Fill a borderfill background rectangle
626 static HRESULT
UXTHEME_DrawBackgroundFill(HTHEME hTheme
, HDC hdc
, int iPartId
,
627 int iStateId
, RECT
*pRect
,
628 const DTBGOPTS
*pOptions
)
631 int filltype
= FT_SOLID
;
633 TRACE("(%d,%d,%ld)\n", iPartId
, iStateId
, pOptions
->dwFlags
);
635 if(pOptions
->dwFlags
& DTBG_OMITCONTENT
)
638 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_FILLTYPE
, &filltype
);
640 if(filltype
== FT_SOLID
) {
642 COLORREF fillcolor
= RGB(255,255,255);
644 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_FILLCOLOR
, &fillcolor
);
645 hBrush
= CreateSolidBrush(fillcolor
);
646 if(!FillRect(hdc
, pRect
, hBrush
))
647 hr
= HRESULT_FROM_WIN32(GetLastError());
648 DeleteObject(hBrush
);
650 else if(filltype
== FT_VERTGRADIENT
|| filltype
== FT_HORZGRADIENT
) {
651 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
652 the gradient ratios (no idea how those work)
653 Few themes use this, and the ones I've seen only use 2 colors with
654 a gradient ratio of 0 and 255 respectivly
657 COLORREF gradient1
= RGB(0,0,0);
658 COLORREF gradient2
= RGB(255,255,255);
662 FIXME("Gradient implementation not complete\n");
664 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_GRADIENTCOLOR1
, &gradient1
);
665 GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_GRADIENTCOLOR2
, &gradient2
);
667 vert
[0].x
= pRect
->left
;
668 vert
[0].y
= pRect
->top
;
669 vert
[0].Red
= GetRValue(gradient1
) << 8;
670 vert
[0].Green
= GetGValue(gradient1
) << 8;
671 vert
[0].Blue
= GetBValue(gradient1
) << 8;
672 vert
[0].Alpha
= 0x0000;
674 vert
[1].x
= pRect
->right
;
675 vert
[1].y
= pRect
->bottom
;
676 vert
[1].Red
= GetRValue(gradient2
) << 8;
677 vert
[1].Green
= GetGValue(gradient2
) << 8;
678 vert
[1].Blue
= GetBValue(gradient2
) << 8;
679 vert
[1].Alpha
= 0x0000;
682 gRect
.LowerRight
= 1;
683 GradientFill(hdc
,vert
,2,&gRect
,1,filltype
==FT_HORZGRADIENT
?GRADIENT_FILL_RECT_H
:GRADIENT_FILL_RECT_V
);
685 else if(filltype
== FT_RADIALGRADIENT
) {
686 /* I've never seen this used in a theme */
687 FIXME("Radial gradient\n");
689 else if(filltype
== FT_TILEIMAGE
) {
690 /* I've never seen this used in a theme */
691 FIXME("Tile image\n");
696 /***********************************************************************
697 * UXTHEME_DrawBorderBackground
699 * Draw an imagefile background
701 static HRESULT
UXTHEME_DrawBorderBackground(HTHEME hTheme
, HDC hdc
, int iPartId
,
702 int iStateId
, const RECT
*pRect
,
703 const DTBGOPTS
*pOptions
)
708 CopyRect(&rt
, pRect
);
710 hr
= UXTHEME_DrawBorderRectangle(hTheme
, hdc
, iPartId
, iStateId
, &rt
, pOptions
);
713 return UXTHEME_DrawBackgroundFill(hTheme
, hdc
, iPartId
, iStateId
, &rt
, pOptions
);
716 /***********************************************************************
717 * DrawThemeBackgroundEx (UXTHEME.@)
719 HRESULT WINAPI
DrawThemeBackgroundEx(HTHEME hTheme
, HDC hdc
, int iPartId
,
720 int iStateId
, const RECT
*pRect
,
721 const DTBGOPTS
*pOptions
)
724 const DTBGOPTS defaultOpts
= {sizeof(DTBGOPTS
), 0, {0,0,0,0}};
725 const DTBGOPTS
*opts
;
728 int bgtype
= BT_BORDERFILL
;
731 TRACE("(%p,%p,%d,%d,%ld,%ld)\n", hTheme
, hdc
, iPartId
, iStateId
,pRect
->left
,pRect
->top
);
735 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
737 if(!opts
) opts
= &defaultOpts
;
739 if(opts
->dwFlags
& DTBG_CLIPRECT
) {
740 clip
= CreateRectRgn(0,0,1,1);
741 hasClip
= GetClipRgn(hdc
, clip
);
743 TRACE("Failed to get original clipping region\n");
745 IntersectClipRect(hdc
, opts
->rcClip
.left
, opts
->rcClip
.top
, opts
->rcClip
.right
, opts
->rcClip
.bottom
);
747 CopyRect(&rt
, pRect
);
749 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_BGTYPE
, &bgtype
);
750 if(bgtype
== BT_IMAGEFILE
)
751 hr
= UXTHEME_DrawImageBackground(hTheme
, hdc
, iPartId
, iStateId
, &rt
, opts
);
752 else if(bgtype
== BT_BORDERFILL
)
753 hr
= UXTHEME_DrawBorderBackground(hTheme
, hdc
, iPartId
, iStateId
, pRect
, opts
);
755 FIXME("Unknown background type\n");
756 /* This should never happen, and hence I don't know what to return */
760 hr
= UXTHEME_DrawGlyph(hTheme
, hdc
, iPartId
, iStateId
, &rt
, opts
);
761 if(opts
->dwFlags
& DTBG_CLIPRECT
) {
763 SelectClipRgn(hdc
, NULL
);
764 else if(hasClip
== 1)
765 SelectClipRgn(hdc
, clip
);
771 /***********************************************************************
772 * DrawThemeEdge (UXTHEME.@)
774 HRESULT WINAPI
DrawThemeEdge(HTHEME hTheme
, HDC hdc
, int iPartId
,
775 int iStateId
, const RECT
*pDestRect
, UINT uEdge
,
776 UINT uFlags
, RECT
*pContentRect
)
778 FIXME("%d %d 0x%08x 0x%08x: stub\n", iPartId
, iStateId
, uEdge
, uFlags
);
781 return ERROR_CALL_NOT_IMPLEMENTED
;
784 /***********************************************************************
785 * DrawThemeIcon (UXTHEME.@)
787 HRESULT WINAPI
DrawThemeIcon(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
,
788 const RECT
*pRect
, HIMAGELIST himl
, int iImageIndex
)
790 FIXME("%d %d: stub\n", iPartId
, iStateId
);
793 return ERROR_CALL_NOT_IMPLEMENTED
;
796 /***********************************************************************
797 * DrawThemeText (UXTHEME.@)
799 HRESULT WINAPI
DrawThemeText(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
,
800 LPCWSTR pszText
, int iCharCount
, DWORD dwTextFlags
,
801 DWORD dwTextFlags2
, const RECT
*pRect
)
805 HGDIOBJ oldFont
= NULL
;
808 COLORREF oldTextColor
;
812 TRACE("%d %d: stub\n", iPartId
, iStateId
);
816 hr
= GetThemeFont(hTheme
, hdc
, iPartId
, iStateId
, TMT_FONT
, &logfont
);
818 hFont
= CreateFontIndirectW(&logfont
);
820 TRACE("Failed to create font\n");
822 CopyRect(&rt
, pRect
);
824 oldFont
= SelectObject(hdc
, hFont
);
826 if(dwTextFlags2
& DTT_GRAYED
)
827 textColor
= GetSysColor(COLOR_GRAYTEXT
);
829 if(FAILED(GetThemeColor(hTheme
, iPartId
, iStateId
, TMT_TEXTCOLOR
, &textColor
)))
830 textColor
= GetTextColor(hdc
);
832 oldTextColor
= SetTextColor(hdc
, textColor
);
833 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
834 DrawTextW(hdc
, pszText
, iCharCount
, &rt
, dwTextFlags
);
835 SetBkMode(hdc
, oldBkMode
);
836 SetTextColor(hdc
, oldTextColor
);
839 SelectObject(hdc
, oldFont
);
845 /***********************************************************************
846 * GetThemeBackgroundContentRect (UXTHEME.@)
848 HRESULT WINAPI
GetThemeBackgroundContentRect(HTHEME hTheme
, HDC hdc
, int iPartId
,
850 const RECT
*pBoundingRect
,
856 TRACE("(%d,%d)\n", iPartId
, iStateId
);
860 hr
= GetThemeMargins(hTheme
, hdc
, iPartId
, iStateId
, TMT_CONTENTMARGINS
, NULL
, &margin
);
862 TRACE("Margins not found\n");
865 pContentRect
->left
= pBoundingRect
->left
+ margin
.cxLeftWidth
;
866 pContentRect
->top
= pBoundingRect
->top
+ margin
.cyTopHeight
;
867 pContentRect
->right
= pBoundingRect
->right
- margin
.cxRightWidth
;
868 pContentRect
->bottom
= pBoundingRect
->bottom
- margin
.cyBottomHeight
;
870 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect
->left
, pContentRect
->top
, pContentRect
->right
, pContentRect
->bottom
);
875 /***********************************************************************
876 * GetThemeBackgroundExtent (UXTHEME.@)
878 HRESULT WINAPI
GetThemeBackgroundExtent(HTHEME hTheme
, HDC hdc
, int iPartId
,
879 int iStateId
, const RECT
*pContentRect
,
885 TRACE("(%d,%d)\n", iPartId
, iStateId
);
889 hr
= GetThemeMargins(hTheme
, hdc
, iPartId
, iStateId
, TMT_CONTENTMARGINS
, NULL
, &margin
);
891 TRACE("Margins not found\n");
894 pExtentRect
->left
= pContentRect
->left
- margin
.cxLeftWidth
;
895 pExtentRect
->top
= pContentRect
->top
- margin
.cyTopHeight
;
896 pExtentRect
->right
= pContentRect
->right
+ margin
.cxRightWidth
;
897 pExtentRect
->bottom
= pContentRect
->bottom
+ margin
.cyBottomHeight
;
899 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pExtentRect
->left
, pExtentRect
->top
, pExtentRect
->right
, pExtentRect
->bottom
);
904 /***********************************************************************
905 * GetThemeBackgroundRegion (UXTHEME.@)
907 * Calculate the background region, taking into consideration transparent areas
908 * of the background image.
910 HRESULT WINAPI
GetThemeBackgroundRegion(HTHEME hTheme
, HDC hdc
, int iPartId
,
911 int iStateId
, const RECT
*pRect
,
915 int bgtype
= BT_BORDERFILL
;
917 TRACE("(%p,%p,%d,%d)\n", hTheme
, hdc
, iPartId
, iStateId
);
920 if(!pRect
|| !pRegion
)
923 GetThemeEnumValue(hTheme
, iPartId
, iStateId
, TMT_BGTYPE
, &bgtype
);
924 if(bgtype
== BT_IMAGEFILE
) {
925 FIXME("Images not handled yet\n");
926 hr
= ERROR_CALL_NOT_IMPLEMENTED
;
928 else if(bgtype
== BT_BORDERFILL
) {
929 *pRegion
= CreateRectRgn(pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
931 hr
= HRESULT_FROM_WIN32(GetLastError());
934 FIXME("Unknown background type\n");
935 /* This should never happen, and hence I don't know what to return */
941 /***********************************************************************
942 * GetThemePartSize (UXTHEME.@)
944 HRESULT WINAPI
GetThemePartSize(HTHEME hTheme
, HDC hdc
, int iPartId
,
945 int iStateId
, RECT
*prc
, THEMESIZE eSize
,
948 FIXME("%d %d %d: stub\n", iPartId
, iStateId
, eSize
);
951 return ERROR_CALL_NOT_IMPLEMENTED
;
955 /***********************************************************************
956 * GetThemeTextExtent (UXTHEME.@)
958 HRESULT WINAPI
GetThemeTextExtent(HTHEME hTheme
, HDC hdc
, int iPartId
,
959 int iStateId
, LPCWSTR pszText
, int iCharCount
,
960 DWORD dwTextFlags
, const RECT
*pBoundingRect
,
965 HGDIOBJ oldFont
= NULL
;
967 RECT rt
= {0,0,0xFFFF,0xFFFF};
969 TRACE("%d %d: stub\n", iPartId
, iStateId
);
974 CopyRect(&rt
, pBoundingRect
);
976 hr
= GetThemeFont(hTheme
, hdc
, iPartId
, iStateId
, TMT_FONT
, &logfont
);
978 hFont
= CreateFontIndirectW(&logfont
);
980 TRACE("Failed to create font\n");
983 oldFont
= SelectObject(hdc
, hFont
);
985 DrawTextW(hdc
, pszText
, iCharCount
, &rt
, dwTextFlags
|DT_CALCRECT
);
986 CopyRect(pExtentRect
, &rt
);
989 SelectObject(hdc
, oldFont
);
995 /***********************************************************************
996 * GetThemeTextMetrics (UXTHEME.@)
998 HRESULT WINAPI
GetThemeTextMetrics(HTHEME hTheme
, HDC hdc
, int iPartId
,
999 int iStateId
, TEXTMETRICW
*ptm
)
1003 HGDIOBJ oldFont
= NULL
;
1006 TRACE("(%p, %p, %d, %d)\n", hTheme
, hdc
, iPartId
, iStateId
);
1010 hr
= GetThemeFont(hTheme
, hdc
, iPartId
, iStateId
, TMT_FONT
, &logfont
);
1012 hFont
= CreateFontIndirectW(&logfont
);
1014 TRACE("Failed to create font\n");
1017 oldFont
= SelectObject(hdc
, hFont
);
1019 if(!GetTextMetricsW(hdc
, ptm
))
1020 hr
= HRESULT_FROM_WIN32(GetLastError());
1023 SelectObject(hdc
, oldFont
);
1024 DeleteObject(hFont
);
1029 /***********************************************************************
1030 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1032 BOOL WINAPI
IsThemeBackgroundPartiallyTransparent(HTHEME hTheme
, int iPartId
,
1035 BOOL transparent
= FALSE
;
1036 TRACE("(%d,%d)\n", iPartId
, iStateId
);
1037 GetThemeBool(hTheme
, iPartId
, iStateId
, TMT_TRANSPARENT
, &transparent
);