Pass around what kind of transparency an image actually needs. Use
[wine.git] / dlls / uxtheme / draw.c
blobb760bef4b445dd6c095d0793b522af9d747c7c1d
1 /*
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "uxtheme.h"
31 #include "tmschema.h"
33 #include "msstyles.h"
34 #include "uxthemedll.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
40 /***********************************************************************
41 * Defines and global variables
44 extern ATOM atDialogThemeEnabled;
46 /***********************************************************************/
48 /***********************************************************************
49 * EnableThemeDialogTexture (UXTHEME.@)
51 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
53 static const WCHAR szTab[] = { 'T','a','b',0 };
54 HRESULT hr;
56 TRACE("(%p,0x%08lx\n", hwnd, dwFlags);
57 hr = SetPropW (hwnd, MAKEINTATOMW (atDialogThemeEnabled),
58 (HANDLE)(dwFlags|0x80000000));
59 /* 0x80000000 serves as a "flags set" flag */
60 if (FAILED(hr))
61 return hr;
62 if (dwFlags & ETDT_USETABTEXTURE)
63 return SetWindowTheme (hwnd, NULL, szTab);
64 else
65 return SetWindowTheme (hwnd, NULL, NULL);
66 return S_OK;
69 /***********************************************************************
70 * IsThemeDialogTextureEnabled (UXTHEME.@)
72 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
74 DWORD dwDialogTextureFlags;
75 TRACE("(%p)\n", hwnd);
77 dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
78 MAKEINTATOMW (atDialogThemeEnabled));
79 if (dwDialogTextureFlags == 0)
80 /* Means EnableThemeDialogTexture wasn't called for this dialog */
81 return TRUE;
83 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
86 /***********************************************************************
87 * DrawThemeParentBackground (UXTHEME.@)
89 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
91 RECT rt;
92 POINT org;
93 HWND hParent;
94 HRGN clip = NULL;
95 int hasClip = -1;
97 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
98 hParent = GetParent(hwnd);
99 if(!hParent)
100 hParent = hwnd;
101 if(prc) {
102 CopyRect(&rt, prc);
103 MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
105 clip = CreateRectRgn(0,0,1,1);
106 hasClip = GetClipRgn(hdc, clip);
107 if(hasClip == -1)
108 TRACE("Failed to get original clipping region\n");
109 else
110 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
112 else {
113 GetClientRect(hParent, &rt);
114 MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
117 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
119 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
120 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
122 SetViewportOrgEx(hdc, org.x, org.y, NULL);
123 if(prc) {
124 if(hasClip == 0)
125 SelectClipRgn(hdc, NULL);
126 else if(hasClip == 1)
127 SelectClipRgn(hdc, clip);
128 DeleteObject(clip);
130 return S_OK;
134 /***********************************************************************
135 * DrawThemeBackground (UXTHEME.@)
137 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
138 int iStateId, const RECT *pRect,
139 const RECT *pClipRect)
141 DTBGOPTS opts;
142 opts.dwSize = sizeof(DTBGOPTS);
143 opts.dwFlags = 0;
144 if(pClipRect) {
145 opts.dwFlags |= DTBG_CLIPRECT;
146 CopyRect(&opts.rcClip, pClipRect);
148 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
151 /***********************************************************************
152 * UXTHEME_SelectImage
154 * Select the image to use
156 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
158 PTHEME_PROPERTY tp;
159 int imageselecttype = IST_NONE;
160 int i;
161 int image;
162 if(glyph)
163 image = TMT_GLYPHIMAGEFILE;
164 else
165 image = TMT_IMAGEFILE;
167 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
168 return tp;
169 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
171 if(imageselecttype == IST_DPI) {
172 int reqdpi = 0;
173 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
174 for(i=4; i>=0; i--) {
175 reqdpi = 0;
176 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
177 if(reqdpi != 0 && screendpi >= reqdpi) {
178 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
179 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
183 /* If an image couldnt be selected, choose the first one */
184 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
186 else if(imageselecttype == IST_SIZE) {
187 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
188 POINT reqsize;
189 for(i=4; i>=0; i--) {
190 PTHEME_PROPERTY fileProp =
191 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
192 if (!fileProp) continue;
193 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
194 /* fall back to size of Nth image */
195 WCHAR szPath[MAX_PATH];
196 int imagelayout = IL_HORIZONTAL;
197 int imagecount = 1;
198 int imagenum;
199 BITMAP bmp;
200 HBITMAP hBmp;
201 BOOL hasAlpha;
203 lstrcpynW(szPath, fileProp->lpValue,
204 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
205 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
206 if(!hBmp) continue;
208 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
209 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
211 imagenum = max (min (imagecount, iStateId), 1) - 1;
212 GetObjectW(hBmp, sizeof(bmp), &bmp);
213 if(imagelayout == IL_VERTICAL) {
214 reqsize.x = bmp.bmWidth;
215 reqsize.y = bmp.bmHeight/imagecount;
217 else {
218 reqsize.x = bmp.bmWidth/imagecount;
219 reqsize.y = bmp.bmHeight;
222 if(reqsize.x <= size.x && reqsize.y <= size.y) {
223 TRACE("Using image size %ldx%ld, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
224 return fileProp;
227 /* If an image couldnt be selected, choose the smallest one */
228 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
230 return NULL;
233 /***********************************************************************
234 * UXTHEME_LoadImage
236 * Load image for part/state
238 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
239 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
241 int imagelayout = IL_HORIZONTAL;
242 int imagecount = 1;
243 int imagenum;
244 BITMAP bmp;
245 WCHAR szPath[MAX_PATH];
246 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
247 if(!tp) {
248 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
249 return E_PROP_ID_UNSUPPORTED;
251 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
252 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
253 if(!*hBmp) {
254 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
255 return HRESULT_FROM_WIN32(GetLastError());
258 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
259 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
261 imagenum = max (min (imagecount, iStateId), 1) - 1;
262 GetObjectW(*hBmp, sizeof(bmp), &bmp);
263 if(imagelayout == IL_VERTICAL) {
264 int height = bmp.bmHeight/imagecount;
265 bmpRect->left = 0;
266 bmpRect->right = bmp.bmWidth;
267 bmpRect->top = imagenum * height;
268 bmpRect->bottom = bmpRect->top + height;
270 else {
271 int width = bmp.bmWidth/imagecount;
272 bmpRect->left = imagenum * width;
273 bmpRect->right = bmpRect->left + width;
274 bmpRect->top = 0;
275 bmpRect->bottom = bmp.bmHeight;
277 return S_OK;
280 /***********************************************************************
281 * UXTHEME_StretchBlt
283 * Pseudo TransparentBlt/StretchBlt
285 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
286 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
287 INT transparent, COLORREF transcolor)
289 static const BLENDFUNCTION blendFunc =
291 AC_SRC_OVER, /* BlendOp */
292 0, /* BlendFlag */
293 255, /* SourceConstantAlpha */
294 AC_SRC_ALPHA /* AlphaFormat */
296 if (transparent == ALPHABLEND_BINARY) {
297 /* Ensure we don't pass any negative values to TransparentBlt */
298 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
299 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
300 transcolor);
302 if ((transparent == ALPHABLEND_NONE) ||
303 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
304 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
305 blendFunc))
307 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
308 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
309 SRCCOPY);
311 return TRUE;
314 /***********************************************************************
315 * UXTHEME_Blt
317 * Simplify sending same width/height for both source and dest
319 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
320 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
321 INT transparent, COLORREF transcolor)
323 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
324 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
325 transparent, transcolor);
328 /***********************************************************************
329 * UXTHEME_SizedBlt
331 * Stretches or tiles, depending on sizingtype.
333 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
334 int nWidthDst, int nHeightDst,
335 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
336 int nWidthSrc, int nHeightSrc,
337 int sizingtype,
338 INT transparent, COLORREF transcolor)
340 if (sizingtype == ST_TILE)
342 int yOfs = nYOriginDst;
343 int yRemaining = nHeightDst;
344 while (yRemaining > 0)
346 int bltHeight = min (yRemaining, nHeightSrc);
347 int xOfs = nXOriginDst;
348 int xRemaining = nWidthDst;
349 while (xRemaining > 0)
351 int bltWidth = min (xRemaining, nWidthSrc);
352 if (!UXTHEME_Blt (hdcDst, xOfs, yOfs, bltWidth, bltHeight,
353 hdcSrc, nXOriginSrc, nYOriginSrc,
354 transparent, transcolor))
355 return FALSE;
356 xOfs += nWidthSrc;
357 xRemaining -= nWidthSrc;
359 yOfs += nHeightSrc;
360 yRemaining -= nHeightSrc;
362 return TRUE;
364 else
366 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
367 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
368 transparent, transcolor);
372 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
373 * depend on whether the image has full alpha or whether it is
374 * color-transparent or just opaque. */
375 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
376 BOOL hasImageAlpha, INT* transparent,
377 COLORREF* transparentcolor, BOOL glyph)
379 if (hasImageAlpha)
381 *transparent = ALPHABLEND_FULL;
382 *transparentcolor = RGB (255, 0, 255);
384 else
386 BOOL trans = FALSE;
387 GetThemeBool(hTheme, iPartId, iStateId,
388 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
389 if(trans) {
390 *transparent = ALPHABLEND_BINARY;
391 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
392 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
393 transparentcolor))) {
394 /* If image is transparent, but no color was specified, use magenta */
395 *transparentcolor = RGB(255, 0, 255);
398 else
399 *transparent = ALPHABLEND_NONE;
403 /***********************************************************************
404 * UXTHEME_DrawImageGlyph
406 * Draw an imagefile glyph
408 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
409 int iStateId, RECT *pRect,
410 const DTBGOPTS *pOptions)
412 HRESULT hr;
413 HBITMAP bmpSrc = NULL;
414 HDC hdcSrc = NULL;
415 HGDIOBJ oldSrc = NULL;
416 RECT rcSrc;
417 INT transparent = FALSE;
418 COLORREF transparentcolor;
419 int valign = VA_CENTER;
420 int halign = HA_CENTER;
421 POINT dstSize;
422 POINT srcSize;
423 POINT topleft;
424 BOOL hasAlpha;
426 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
427 &bmpSrc, &rcSrc, &hasAlpha);
428 if(FAILED(hr)) return hr;
429 hdcSrc = CreateCompatibleDC(hdc);
430 if(!hdcSrc) {
431 hr = HRESULT_FROM_WIN32(GetLastError());
432 DeleteObject(bmpSrc);
433 return hr;
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);
461 DeleteDC(hdcSrc);
462 DeleteObject(bmpSrc);
463 return hr;
466 /***********************************************************************
467 * UXTHEME_DrawImageGlyph
469 * Draw glyph on top of background, if appropriate
471 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
472 int iStateId, RECT *pRect,
473 const DTBGOPTS *pOptions)
475 int glyphtype = GT_NONE;
477 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
479 if(glyphtype == GT_IMAGEGLYPH) {
480 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
482 else if(glyphtype == GT_FONTGLYPH) {
483 /* I don't know what a font glyph is, I've never seen it used in any themes */
484 FIXME("Font glyph\n");
486 return S_OK;
489 /***********************************************************************
490 * get_image_part_size
492 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
494 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
495 int iStateId, RECT *prc, THEMESIZE eSize,
496 POINT *psz)
498 HRESULT hr = S_OK;
499 HBITMAP bmpSrc;
500 RECT rcSrc;
501 BOOL hasAlpha;
503 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
504 &bmpSrc, &rcSrc, &hasAlpha);
505 if (FAILED(hr)) return hr;
507 switch (eSize)
509 case TS_DRAW:
510 if (prc != NULL)
512 RECT rcDst;
513 POINT dstSize;
514 POINT srcSize;
515 int sizingtype = ST_STRETCH;
516 BOOL uniformsizing = FALSE;
518 CopyRect(&rcDst, prc);
520 dstSize.x = rcDst.right-rcDst.left;
521 dstSize.y = rcDst.bottom-rcDst.top;
522 srcSize.x = rcSrc.right-rcSrc.left;
523 srcSize.y = rcSrc.bottom-rcSrc.top;
525 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
526 if(uniformsizing) {
527 /* Scale height and width equally */
528 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
530 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
531 rcDst.bottom = rcDst.top + dstSize.y;
533 else
535 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
536 rcDst.right = rcDst.left + dstSize.x;
540 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
541 if(sizingtype == ST_TRUESIZE) {
542 int truesizestretchmark = 100;
544 if(dstSize.x < 0 || dstSize.y < 0) {
545 BOOL mirrorimage = TRUE;
546 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
547 if(mirrorimage) {
548 if(dstSize.x < 0) {
549 rcDst.left += dstSize.x;
550 rcDst.right += dstSize.x;
552 if(dstSize.y < 0) {
553 rcDst.top += dstSize.y;
554 rcDst.bottom += dstSize.y;
558 /* Whatever TrueSizeStretchMark does - it does not seem to
559 * be what's outlined below. It appears as if native
560 * uxtheme always stretches if dest is smaller than source
561 * (ie as if TrueSizeStretchMark==100 with the code below) */
562 #if 0
563 /* Only stretch when target exceeds source by truesizestretchmark percent */
564 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
565 #endif
566 if(dstSize.x < 0 || dstSize.y < 0 ||
567 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
568 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
569 memcpy (psz, &dstSize, sizeof (SIZE));
571 else {
572 memcpy (psz, &srcSize, sizeof (SIZE));
575 else
577 psz->x = abs(dstSize.x);
578 psz->y = abs(dstSize.y);
580 break;
582 /* else fall through */
583 case TS_MIN:
584 /* FIXME: couldn't figure how native uxtheme computes min size */
585 case TS_TRUE:
586 psz->x = rcSrc.right - rcSrc.left;
587 psz->y = rcSrc.bottom - rcSrc.top;
588 break;
590 return hr;
593 /***********************************************************************
594 * UXTHEME_DrawImageBackground
596 * Draw an imagefile background
598 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
599 int iStateId, RECT *pRect,
600 const DTBGOPTS *pOptions)
602 HRESULT hr = S_OK;
603 HBITMAP bmpSrc;
604 HGDIOBJ oldSrc;
605 HDC hdcSrc;
606 RECT rcSrc;
607 RECT rcDst;
608 POINT dstSize;
609 POINT srcSize;
610 POINT drawSize;
611 int sizingtype = ST_STRETCH;
612 INT transparent;
613 COLORREF transparentcolor = 0;
614 BOOL hasAlpha;
616 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
617 &bmpSrc, &rcSrc, &hasAlpha);
618 if(FAILED(hr)) return hr;
619 hdcSrc = CreateCompatibleDC(hdc);
620 if(!hdcSrc) {
621 hr = HRESULT_FROM_WIN32(GetLastError());
622 DeleteObject(bmpSrc);
623 return hr;
625 oldSrc = SelectObject(hdcSrc, bmpSrc);
627 CopyRect(&rcDst, pRect);
629 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
630 &transparentcolor, FALSE);
632 dstSize.x = rcDst.right-rcDst.left;
633 dstSize.y = rcDst.bottom-rcDst.top;
634 srcSize.x = rcSrc.right-rcSrc.left;
635 srcSize.y = rcSrc.bottom-rcSrc.top;
637 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
638 if(sizingtype == ST_TRUESIZE) {
639 int valign = VA_CENTER, halign = HA_CENTER;
641 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
642 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
643 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
645 if (halign == HA_CENTER)
646 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
647 else if (halign == HA_RIGHT)
648 rcDst.left = rcDst.right - drawSize.x;
649 if (valign == VA_CENTER)
650 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
651 else if (valign == VA_BOTTOM)
652 rcDst.top = rcDst.bottom - drawSize.y;
653 rcDst.right = rcDst.left + drawSize.x;
654 rcDst.bottom = rcDst.top + drawSize.y;
655 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
656 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
657 transparent, transparentcolor))
658 hr = HRESULT_FROM_WIN32(GetLastError());
660 else {
661 HDC hdcDst = NULL;
662 MARGINS sm;
663 POINT org;
665 dstSize.x = abs(dstSize.x);
666 dstSize.y = abs(dstSize.y);
668 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
670 hdcDst = hdc;
671 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
673 /* Upper left corner */
674 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
675 hdcSrc, rcSrc.left, rcSrc.top,
676 transparent, transparentcolor)) {
677 hr = HRESULT_FROM_WIN32(GetLastError());
678 goto draw_error;
680 /* Upper right corner */
681 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
682 sm.cxRightWidth, sm.cyTopHeight,
683 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
684 transparent, transparentcolor)) {
685 hr = HRESULT_FROM_WIN32(GetLastError());
686 goto draw_error;
688 /* Lower left corner */
689 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
690 sm.cxLeftWidth, sm.cyBottomHeight,
691 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
692 transparent, transparentcolor)) {
693 hr = HRESULT_FROM_WIN32(GetLastError());
694 goto draw_error;
696 /* Lower right corner */
697 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
698 sm.cxRightWidth, sm.cyBottomHeight,
699 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
700 transparent, transparentcolor)) {
701 hr = HRESULT_FROM_WIN32(GetLastError());
702 goto draw_error;
705 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
706 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
707 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
708 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
709 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
711 if(destCenterWidth > 0) {
712 /* Center top */
713 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
714 destCenterWidth, sm.cyTopHeight,
715 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
716 srcCenterWidth, sm.cyTopHeight,
717 sizingtype, transparent, transparentcolor)) {
718 hr = HRESULT_FROM_WIN32(GetLastError());
719 goto draw_error;
721 /* Center bottom */
722 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
723 destCenterWidth, sm.cyBottomHeight,
724 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
725 srcCenterWidth, sm.cyBottomHeight,
726 sizingtype, transparent, transparentcolor)) {
727 hr = HRESULT_FROM_WIN32(GetLastError());
728 goto draw_error;
731 if(destCenterHeight > 0) {
732 /* Left center */
733 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
734 sm.cxLeftWidth, destCenterHeight,
735 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
736 sm.cxLeftWidth, srcCenterHeight,
737 sizingtype,
738 transparent, transparentcolor)) {
739 hr = HRESULT_FROM_WIN32(GetLastError());
740 goto draw_error;
742 /* Right center */
743 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
744 sm.cxRightWidth, destCenterHeight,
745 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
746 sm.cxRightWidth, srcCenterHeight,
747 sizingtype, transparent, transparentcolor)) {
748 hr = HRESULT_FROM_WIN32(GetLastError());
749 goto draw_error;
752 if(destCenterHeight > 0 && destCenterWidth > 0) {
753 BOOL borderonly = FALSE;
754 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
755 if(!borderonly) {
756 /* Center */
757 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
758 destCenterWidth, destCenterHeight,
759 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
760 srcCenterWidth, srcCenterHeight,
761 sizingtype, transparent, transparentcolor)) {
762 hr = HRESULT_FROM_WIN32(GetLastError());
763 goto draw_error;
769 draw_error:
770 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
772 SelectObject(hdcSrc, oldSrc);
773 DeleteObject(bmpSrc);
774 DeleteDC(hdcSrc);
775 CopyRect(pRect, &rcDst);
776 return hr;
779 /***********************************************************************
780 * UXTHEME_DrawBorderRectangle
782 * Draw the bounding rectangle for a borderfill background
784 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
785 int iStateId, RECT *pRect,
786 const DTBGOPTS *pOptions)
788 HRESULT hr = S_OK;
789 HPEN hPen;
790 HGDIOBJ oldPen;
791 COLORREF bordercolor = RGB(0,0,0);
792 int bordersize = 1;
794 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
795 if(bordersize > 0) {
796 POINT ptCorners[5];
797 ptCorners[0].x = pRect->left;
798 ptCorners[0].y = pRect->top;
799 ptCorners[1].x = pRect->right-1;
800 ptCorners[1].y = pRect->top;
801 ptCorners[2].x = pRect->right-1;
802 ptCorners[2].y = pRect->bottom-1;
803 ptCorners[3].x = pRect->left;
804 ptCorners[3].y = pRect->bottom-1;
805 ptCorners[4].x = pRect->left;
806 ptCorners[4].y = pRect->top;
808 InflateRect(pRect, -bordersize, -bordersize);
809 if(pOptions->dwFlags & DTBG_OMITBORDER)
810 return S_OK;
811 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
812 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
813 if(!hPen)
814 return HRESULT_FROM_WIN32(GetLastError());
815 oldPen = SelectObject(hdc, hPen);
817 if(!Polyline(hdc, ptCorners, 5))
818 hr = HRESULT_FROM_WIN32(GetLastError());
820 SelectObject(hdc, oldPen);
821 DeleteObject(hPen);
823 return hr;
826 /***********************************************************************
827 * UXTHEME_DrawBackgroundFill
829 * Fill a borderfill background rectangle
831 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
832 int iStateId, RECT *pRect,
833 const DTBGOPTS *pOptions)
835 HRESULT hr = S_OK;
836 int filltype = FT_SOLID;
838 TRACE("(%d,%d,%ld)\n", iPartId, iStateId, pOptions->dwFlags);
840 if(pOptions->dwFlags & DTBG_OMITCONTENT)
841 return S_OK;
843 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
845 if(filltype == FT_SOLID) {
846 HBRUSH hBrush;
847 COLORREF fillcolor = RGB(255,255,255);
849 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
850 hBrush = CreateSolidBrush(fillcolor);
851 if(!FillRect(hdc, pRect, hBrush))
852 hr = HRESULT_FROM_WIN32(GetLastError());
853 DeleteObject(hBrush);
855 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
856 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
857 the gradient ratios (no idea how those work)
858 Few themes use this, and the ones I've seen only use 2 colors with
859 a gradient ratio of 0 and 255 respectivly
862 COLORREF gradient1 = RGB(0,0,0);
863 COLORREF gradient2 = RGB(255,255,255);
864 TRIVERTEX vert[2];
865 GRADIENT_RECT gRect;
867 FIXME("Gradient implementation not complete\n");
869 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
870 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
872 vert[0].x = pRect->left;
873 vert[0].y = pRect->top;
874 vert[0].Red = GetRValue(gradient1) << 8;
875 vert[0].Green = GetGValue(gradient1) << 8;
876 vert[0].Blue = GetBValue(gradient1) << 8;
877 vert[0].Alpha = 0x0000;
879 vert[1].x = pRect->right;
880 vert[1].y = pRect->bottom;
881 vert[1].Red = GetRValue(gradient2) << 8;
882 vert[1].Green = GetGValue(gradient2) << 8;
883 vert[1].Blue = GetBValue(gradient2) << 8;
884 vert[1].Alpha = 0x0000;
886 gRect.UpperLeft = 0;
887 gRect.LowerRight = 1;
888 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
890 else if(filltype == FT_RADIALGRADIENT) {
891 /* I've never seen this used in a theme */
892 FIXME("Radial gradient\n");
894 else if(filltype == FT_TILEIMAGE) {
895 /* I've never seen this used in a theme */
896 FIXME("Tile image\n");
898 return hr;
901 /***********************************************************************
902 * UXTHEME_DrawBorderBackground
904 * Draw an imagefile background
906 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
907 int iStateId, const RECT *pRect,
908 const DTBGOPTS *pOptions)
910 HRESULT hr;
911 RECT rt;
913 CopyRect(&rt, pRect);
915 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
916 if(FAILED(hr))
917 return hr;
918 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
921 /***********************************************************************
922 * DrawThemeBackgroundEx (UXTHEME.@)
924 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
925 int iStateId, const RECT *pRect,
926 const DTBGOPTS *pOptions)
928 HRESULT hr;
929 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
930 const DTBGOPTS *opts;
931 HRGN clip = NULL;
932 int hasClip = -1;
933 int bgtype = BT_BORDERFILL;
934 RECT rt;
936 TRACE("(%p,%p,%d,%d,%ld,%ld)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
937 if(!hTheme)
938 return E_HANDLE;
940 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
941 if (bgtype == BT_NONE) return S_OK;
943 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
944 opts = pOptions;
945 if(!opts) opts = &defaultOpts;
947 if(opts->dwFlags & DTBG_CLIPRECT) {
948 clip = CreateRectRgn(0,0,1,1);
949 hasClip = GetClipRgn(hdc, clip);
950 if(hasClip == -1)
951 TRACE("Failed to get original clipping region\n");
952 else
953 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
955 CopyRect(&rt, pRect);
957 if(bgtype == BT_IMAGEFILE)
958 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
959 else if(bgtype == BT_BORDERFILL)
960 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
961 else {
962 FIXME("Unknown background type\n");
963 /* This should never happen, and hence I don't know what to return */
964 hr = E_FAIL;
966 if(SUCCEEDED(hr))
967 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
968 if(opts->dwFlags & DTBG_CLIPRECT) {
969 if(hasClip == 0)
970 SelectClipRgn(hdc, NULL);
971 else if(hasClip == 1)
972 SelectClipRgn(hdc, clip);
973 DeleteObject(clip);
975 return hr;
979 * DrawThemeEdge() implementation
981 * Since it basically is DrawEdge() with different colors, I copied its code
982 * from user32's uitools.c.
985 enum
987 EDGE_LIGHT,
988 EDGE_HIGHLIGHT,
989 EDGE_SHADOW,
990 EDGE_DARKSHADOW,
991 EDGE_FILL,
993 EDGE_WINDOW,
994 EDGE_WINDOWFRAME,
996 EDGE_NUMCOLORS
999 static const struct
1001 int themeProp;
1002 int sysColor;
1003 } EdgeColorMap[EDGE_NUMCOLORS] = {
1004 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1005 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1006 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1007 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1008 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1009 {-1, COLOR_WINDOW},
1010 {-1, COLOR_WINDOWFRAME}
1013 static const signed char LTInnerNormal[] = {
1014 -1, -1, -1, -1,
1015 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1016 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1017 -1, -1, -1, -1
1020 static const signed char LTOuterNormal[] = {
1021 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1022 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1023 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1024 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1027 static const signed char RBInnerNormal[] = {
1028 -1, -1, -1, -1,
1029 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1030 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1031 -1, -1, -1, -1
1034 static const signed char RBOuterNormal[] = {
1035 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1036 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1037 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1038 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1041 static const signed char LTInnerSoft[] = {
1042 -1, -1, -1, -1,
1043 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1044 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1045 -1, -1, -1, -1
1048 static const signed char LTOuterSoft[] = {
1049 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1050 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1051 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1052 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1055 #define RBInnerSoft RBInnerNormal /* These are the same */
1056 #define RBOuterSoft RBOuterNormal
1058 static const signed char LTRBOuterMono[] = {
1059 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1060 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1061 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1062 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1065 static const signed char LTRBInnerMono[] = {
1066 -1, -1, -1, -1,
1067 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1068 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1069 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1072 static const signed char LTRBOuterFlat[] = {
1073 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1074 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1075 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1076 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1079 static const signed char LTRBInnerFlat[] = {
1080 -1, -1, -1, -1,
1081 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1082 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1083 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1086 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1088 COLORREF col;
1089 if ((EdgeColorMap[edgeType].themeProp == -1)
1090 || FAILED (GetThemeColor (theme, part, state,
1091 EdgeColorMap[edgeType].themeProp, &col)))
1092 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1093 return col;
1096 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1098 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1101 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1103 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1106 /***********************************************************************
1107 * draw_diag_edge
1109 * Same as DrawEdge invoked with BF_DIAGONAL
1111 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1112 const RECT* rc, UINT uType,
1113 UINT uFlags, LPRECT contentsRect)
1115 POINT Points[4];
1116 signed char InnerI, OuterI;
1117 HPEN InnerPen, OuterPen;
1118 POINT SavePoint;
1119 HPEN SavePen;
1120 int spx, spy;
1121 int epx, epy;
1122 int Width = rc->right - rc->left;
1123 int Height= rc->bottom - rc->top;
1124 int SmallDiam = Width > Height ? Height : Width;
1125 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1126 || (uType & BDR_OUTER) == BDR_OUTER)
1127 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1128 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1129 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1131 /* Init some vars */
1132 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1133 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1134 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1136 /* Determine the colors of the edges */
1137 if(uFlags & BF_MONO)
1139 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1140 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1142 else if(uFlags & BF_FLAT)
1144 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1145 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1147 else if(uFlags & BF_SOFT)
1149 if(uFlags & BF_BOTTOM)
1151 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1152 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1154 else
1156 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1157 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1160 else
1162 if(uFlags & BF_BOTTOM)
1164 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1165 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1167 else
1169 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1170 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1174 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1175 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1177 MoveToEx(hdc, 0, 0, &SavePoint);
1179 /* Don't ask me why, but this is what is visible... */
1180 /* This must be possible to do much simpler, but I fail to */
1181 /* see the logic in the MS implementation (sigh...). */
1182 /* So, this might look a bit brute force here (and it is), but */
1183 /* it gets the job done;) */
1185 switch(uFlags & BF_RECT)
1187 case 0:
1188 case BF_LEFT:
1189 case BF_BOTTOM:
1190 case BF_BOTTOMLEFT:
1191 /* Left bottom endpoint */
1192 epx = rc->left-1;
1193 spx = epx + SmallDiam;
1194 epy = rc->bottom;
1195 spy = epy - SmallDiam;
1196 break;
1198 case BF_TOPLEFT:
1199 case BF_BOTTOMRIGHT:
1200 /* Left top endpoint */
1201 epx = rc->left-1;
1202 spx = epx + SmallDiam;
1203 epy = rc->top-1;
1204 spy = epy + SmallDiam;
1205 break;
1207 case BF_TOP:
1208 case BF_RIGHT:
1209 case BF_TOPRIGHT:
1210 case BF_RIGHT|BF_LEFT:
1211 case BF_RIGHT|BF_LEFT|BF_TOP:
1212 case BF_BOTTOM|BF_TOP:
1213 case BF_BOTTOM|BF_TOP|BF_LEFT:
1214 case BF_BOTTOMRIGHT|BF_LEFT:
1215 case BF_BOTTOMRIGHT|BF_TOP:
1216 case BF_RECT:
1217 /* Right top endpoint */
1218 spx = rc->left;
1219 epx = spx + SmallDiam;
1220 spy = rc->bottom-1;
1221 epy = spy - SmallDiam;
1222 break;
1225 MoveToEx(hdc, spx, spy, NULL);
1226 SelectObject(hdc, OuterPen);
1227 LineTo(hdc, epx, epy);
1229 SelectObject(hdc, InnerPen);
1231 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1233 case BF_DIAGONAL_ENDBOTTOMLEFT:
1234 case (BF_DIAGONAL|BF_BOTTOM):
1235 case BF_DIAGONAL:
1236 case (BF_DIAGONAL|BF_LEFT):
1237 MoveToEx(hdc, spx-1, spy, NULL);
1238 LineTo(hdc, epx, epy-1);
1239 Points[0].x = spx-add;
1240 Points[0].y = spy;
1241 Points[1].x = rc->left;
1242 Points[1].y = rc->top;
1243 Points[2].x = epx+1;
1244 Points[2].y = epy-1-add;
1245 Points[3] = Points[2];
1246 break;
1248 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1249 MoveToEx(hdc, spx-1, spy, NULL);
1250 LineTo(hdc, epx, epy+1);
1251 Points[0].x = spx-add;
1252 Points[0].y = spy;
1253 Points[1].x = rc->left;
1254 Points[1].y = rc->bottom-1;
1255 Points[2].x = epx+1;
1256 Points[2].y = epy+1+add;
1257 Points[3] = Points[2];
1258 break;
1260 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1261 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1262 case BF_DIAGONAL_ENDTOPRIGHT:
1263 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1264 MoveToEx(hdc, spx+1, spy, NULL);
1265 LineTo(hdc, epx, epy+1);
1266 Points[0].x = epx-1;
1267 Points[0].y = epy+1+add;
1268 Points[1].x = rc->right-1;
1269 Points[1].y = rc->top+add;
1270 Points[2].x = rc->right-1;
1271 Points[2].y = rc->bottom-1;
1272 Points[3].x = spx+add;
1273 Points[3].y = spy;
1274 break;
1276 case BF_DIAGONAL_ENDTOPLEFT:
1277 MoveToEx(hdc, spx, spy-1, NULL);
1278 LineTo(hdc, epx+1, epy);
1279 Points[0].x = epx+1+add;
1280 Points[0].y = epy+1;
1281 Points[1].x = rc->right-1;
1282 Points[1].y = rc->top;
1283 Points[2].x = rc->right-1;
1284 Points[2].y = rc->bottom-1-add;
1285 Points[3].x = spx;
1286 Points[3].y = spy-add;
1287 break;
1289 case (BF_DIAGONAL|BF_TOP):
1290 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1291 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1292 MoveToEx(hdc, spx+1, spy-1, NULL);
1293 LineTo(hdc, epx, epy);
1294 Points[0].x = epx-1;
1295 Points[0].y = epy+1;
1296 Points[1].x = rc->right-1;
1297 Points[1].y = rc->top;
1298 Points[2].x = rc->right-1;
1299 Points[2].y = rc->bottom-1-add;
1300 Points[3].x = spx+add;
1301 Points[3].y = spy-add;
1302 break;
1304 case (BF_DIAGONAL|BF_RIGHT):
1305 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1306 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1307 MoveToEx(hdc, spx, spy, NULL);
1308 LineTo(hdc, epx-1, epy+1);
1309 Points[0].x = spx;
1310 Points[0].y = spy;
1311 Points[1].x = rc->left;
1312 Points[1].y = rc->top+add;
1313 Points[2].x = epx-1-add;
1314 Points[2].y = epy+1+add;
1315 Points[3] = Points[2];
1316 break;
1319 /* Fill the interior if asked */
1320 if((uFlags & BF_MIDDLE) && retval)
1322 HBRUSH hbsave;
1323 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1324 theme, part, state);
1325 HPEN hpsave;
1326 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1327 theme, part, state);
1328 hbsave = (HBRUSH)SelectObject(hdc, hb);
1329 hpsave = (HPEN)SelectObject(hdc, hp);
1330 Polygon(hdc, Points, 4);
1331 SelectObject(hdc, hbsave);
1332 SelectObject(hdc, hpsave);
1333 DeleteObject (hp);
1334 DeleteObject (hb);
1337 /* Adjust rectangle if asked */
1338 if(uFlags & BF_ADJUST)
1340 *contentsRect = *rc;
1341 if(uFlags & BF_LEFT) contentsRect->left += add;
1342 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1343 if(uFlags & BF_TOP) contentsRect->top += add;
1344 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1347 /* Cleanup */
1348 SelectObject(hdc, SavePen);
1349 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1350 if(InnerI != -1) DeleteObject (InnerPen);
1351 if(OuterI != -1) DeleteObject (OuterPen);
1353 return retval;
1356 /***********************************************************************
1357 * draw_rect_edge
1359 * Same as DrawEdge invoked without BF_DIAGONAL
1361 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1362 const RECT* rc, UINT uType,
1363 UINT uFlags, LPRECT contentsRect)
1365 signed char LTInnerI, LTOuterI;
1366 signed char RBInnerI, RBOuterI;
1367 HPEN LTInnerPen, LTOuterPen;
1368 HPEN RBInnerPen, RBOuterPen;
1369 RECT InnerRect = *rc;
1370 POINT SavePoint;
1371 HPEN SavePen;
1372 int LBpenplus = 0;
1373 int LTpenplus = 0;
1374 int RTpenplus = 0;
1375 int RBpenplus = 0;
1376 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1377 || (uType & BDR_OUTER) == BDR_OUTER)
1378 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1380 /* Init some vars */
1381 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1382 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1384 /* Determine the colors of the edges */
1385 if(uFlags & BF_MONO)
1387 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1388 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1390 else if(uFlags & BF_FLAT)
1392 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1393 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1395 if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
1397 else if(uFlags & BF_SOFT)
1399 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1400 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1401 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1402 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1404 else
1406 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1407 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1408 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1409 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1412 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1413 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1414 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1415 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1417 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1418 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1419 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1420 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1422 MoveToEx(hdc, 0, 0, &SavePoint);
1424 /* Draw the outer edge */
1425 SelectObject(hdc, LTOuterPen);
1426 if(uFlags & BF_TOP)
1428 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1429 LineTo(hdc, InnerRect.right, InnerRect.top);
1431 if(uFlags & BF_LEFT)
1433 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1434 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1436 SelectObject(hdc, RBOuterPen);
1437 if(uFlags & BF_BOTTOM)
1439 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1440 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1442 if(uFlags & BF_RIGHT)
1444 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1445 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1448 /* Draw the inner edge */
1449 SelectObject(hdc, LTInnerPen);
1450 if(uFlags & BF_TOP)
1452 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1453 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1455 if(uFlags & BF_LEFT)
1457 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1458 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1460 SelectObject(hdc, RBInnerPen);
1461 if(uFlags & BF_BOTTOM)
1463 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1464 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1466 if(uFlags & BF_RIGHT)
1468 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1469 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1472 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1474 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1475 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1477 if(uFlags & BF_LEFT) InnerRect.left += add;
1478 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1479 if(uFlags & BF_TOP) InnerRect.top += add;
1480 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1482 if((uFlags & BF_MIDDLE) && retval)
1484 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1485 theme, part, state);
1486 FillRect(hdc, &InnerRect, br);
1487 DeleteObject (br);
1490 if(uFlags & BF_ADJUST)
1491 *contentsRect = InnerRect;
1494 /* Cleanup */
1495 SelectObject(hdc, SavePen);
1496 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1497 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1498 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1499 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1500 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1501 return retval;
1505 /***********************************************************************
1506 * DrawThemeEdge (UXTHEME.@)
1508 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1509 * difference is that it does not rely on the system colors alone, but
1510 * also allows color specification in the theme.
1512 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1513 int iStateId, const RECT *pDestRect, UINT uEdge,
1514 UINT uFlags, RECT *pContentRect)
1516 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1517 if(!hTheme)
1518 return E_HANDLE;
1520 if(uFlags & BF_DIAGONAL)
1521 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1522 uEdge, uFlags, pContentRect);
1523 else
1524 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1525 uEdge, uFlags, pContentRect);
1529 /***********************************************************************
1530 * DrawThemeIcon (UXTHEME.@)
1532 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1533 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1535 FIXME("%d %d: stub\n", iPartId, iStateId);
1536 if(!hTheme)
1537 return E_HANDLE;
1538 return ERROR_CALL_NOT_IMPLEMENTED;
1541 /***********************************************************************
1542 * DrawThemeText (UXTHEME.@)
1544 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1545 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1546 DWORD dwTextFlags2, const RECT *pRect)
1548 HRESULT hr;
1549 HFONT hFont = NULL;
1550 HGDIOBJ oldFont = NULL;
1551 LOGFONTW logfont;
1552 COLORREF textColor;
1553 COLORREF oldTextColor;
1554 int oldBkMode;
1555 RECT rt;
1557 TRACE("%d %d: stub\n", iPartId, iStateId);
1558 if(!hTheme)
1559 return E_HANDLE;
1561 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1562 if(SUCCEEDED(hr)) {
1563 hFont = CreateFontIndirectW(&logfont);
1564 if(!hFont)
1565 TRACE("Failed to create font\n");
1567 CopyRect(&rt, pRect);
1568 if(hFont)
1569 oldFont = SelectObject(hdc, hFont);
1571 if(dwTextFlags2 & DTT_GRAYED)
1572 textColor = GetSysColor(COLOR_GRAYTEXT);
1573 else {
1574 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1575 textColor = GetTextColor(hdc);
1577 oldTextColor = SetTextColor(hdc, textColor);
1578 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1579 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1580 SetBkMode(hdc, oldBkMode);
1581 SetTextColor(hdc, oldTextColor);
1583 if(hFont) {
1584 SelectObject(hdc, oldFont);
1585 DeleteObject(hFont);
1587 return S_OK;
1590 /***********************************************************************
1591 * GetThemeBackgroundContentRect (UXTHEME.@)
1593 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1594 int iStateId,
1595 const RECT *pBoundingRect,
1596 RECT *pContentRect)
1598 MARGINS margin;
1599 HRESULT hr;
1601 TRACE("(%d,%d)\n", iPartId, iStateId);
1602 if(!hTheme)
1603 return E_HANDLE;
1605 /* try content margins property... */
1606 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1607 if(SUCCEEDED(hr)) {
1608 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1609 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1610 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1611 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1612 } else {
1613 /* otherwise, try to determine content rect from the background type and props */
1614 int bgtype = BT_BORDERFILL;
1615 memcpy(pContentRect, pBoundingRect, sizeof(RECT));
1617 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1618 if(bgtype == BT_BORDERFILL) {
1619 int bordersize = 1;
1621 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1622 InflateRect(pContentRect, -bordersize, -bordersize);
1623 } else if ((bgtype == BT_IMAGEFILE)
1624 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1625 TMT_SIZINGMARGINS, NULL, &margin)))) {
1626 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1627 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1628 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1629 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1631 /* If nothing was found, leave unchanged */
1634 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1636 return S_OK;
1639 /***********************************************************************
1640 * GetThemeBackgroundExtent (UXTHEME.@)
1642 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1643 int iStateId, const RECT *pContentRect,
1644 RECT *pExtentRect)
1646 MARGINS margin;
1647 HRESULT hr;
1649 TRACE("(%d,%d)\n", iPartId, iStateId);
1650 if(!hTheme)
1651 return E_HANDLE;
1653 /* try content margins property... */
1654 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1655 if(SUCCEEDED(hr)) {
1656 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1657 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1658 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1659 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1660 } else {
1661 /* otherwise, try to determine content rect from the background type and props */
1662 int bgtype = BT_BORDERFILL;
1663 memcpy(pExtentRect, pContentRect, sizeof(RECT));
1665 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1666 if(bgtype == BT_BORDERFILL) {
1667 int bordersize = 1;
1669 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1670 InflateRect(pExtentRect, bordersize, bordersize);
1671 } else if ((bgtype == BT_IMAGEFILE)
1672 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1673 TMT_SIZINGMARGINS, NULL, &margin)))) {
1674 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1675 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1676 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1677 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1679 /* If nothing was found, leave unchanged */
1682 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1684 return S_OK;
1687 /***********************************************************************
1688 * GetThemeBackgroundRegion (UXTHEME.@)
1690 * Calculate the background region, taking into consideration transparent areas
1691 * of the background image.
1693 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1694 int iStateId, const RECT *pRect,
1695 HRGN *pRegion)
1697 HRESULT hr = S_OK;
1698 int bgtype = BT_BORDERFILL;
1700 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1701 if(!hTheme)
1702 return E_HANDLE;
1703 if(!pRect || !pRegion)
1704 return E_POINTER;
1706 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1707 if(bgtype == BT_IMAGEFILE) {
1708 FIXME("Images not handled yet\n");
1709 hr = ERROR_CALL_NOT_IMPLEMENTED;
1711 else if(bgtype == BT_BORDERFILL) {
1712 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1713 if(!*pRegion)
1714 hr = HRESULT_FROM_WIN32(GetLastError());
1716 else {
1717 FIXME("Unknown background type\n");
1718 /* This should never happen, and hence I don't know what to return */
1719 hr = E_FAIL;
1721 return hr;
1724 /* compute part size for "borderfill" backgrounds */
1725 HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1726 int iStateId, THEMESIZE eSize, POINT* psz)
1728 HRESULT hr = S_OK;
1729 int bordersize = 1;
1731 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1732 &bordersize)))
1734 psz->x = psz->y = 2*bordersize;
1735 if (eSize != TS_MIN)
1737 psz->x++;
1738 psz->y++;
1741 return hr;
1744 /***********************************************************************
1745 * GetThemePartSize (UXTHEME.@)
1747 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1748 int iStateId, RECT *prc, THEMESIZE eSize,
1749 SIZE *psz)
1751 int bgtype = BT_BORDERFILL;
1752 HRESULT hr = S_OK;
1753 POINT size = {1, 1};
1755 if(!hTheme)
1756 return E_HANDLE;
1758 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1759 if (bgtype == BT_NONE)
1760 /* do nothing */;
1761 else if(bgtype == BT_IMAGEFILE)
1762 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1763 else if(bgtype == BT_BORDERFILL)
1764 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1765 else {
1766 FIXME("Unknown background type\n");
1767 /* This should never happen, and hence I don't know what to return */
1768 hr = E_FAIL;
1770 psz->cx = size.x;
1771 psz->cy = size.y;
1772 return hr;
1776 /***********************************************************************
1777 * GetThemeTextExtent (UXTHEME.@)
1779 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1780 int iStateId, LPCWSTR pszText, int iCharCount,
1781 DWORD dwTextFlags, const RECT *pBoundingRect,
1782 RECT *pExtentRect)
1784 HRESULT hr;
1785 HFONT hFont = NULL;
1786 HGDIOBJ oldFont = NULL;
1787 LOGFONTW logfont;
1788 RECT rt = {0,0,0xFFFF,0xFFFF};
1790 TRACE("%d %d: stub\n", iPartId, iStateId);
1791 if(!hTheme)
1792 return E_HANDLE;
1794 if(pBoundingRect)
1795 CopyRect(&rt, pBoundingRect);
1797 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1798 if(SUCCEEDED(hr)) {
1799 hFont = CreateFontIndirectW(&logfont);
1800 if(!hFont)
1801 TRACE("Failed to create font\n");
1803 if(hFont)
1804 oldFont = SelectObject(hdc, hFont);
1806 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1807 CopyRect(pExtentRect, &rt);
1809 if(hFont) {
1810 SelectObject(hdc, oldFont);
1811 DeleteObject(hFont);
1813 return S_OK;
1816 /***********************************************************************
1817 * GetThemeTextMetrics (UXTHEME.@)
1819 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1820 int iStateId, TEXTMETRICW *ptm)
1822 HRESULT hr;
1823 HFONT hFont = NULL;
1824 HGDIOBJ oldFont = NULL;
1825 LOGFONTW logfont;
1827 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1828 if(!hTheme)
1829 return E_HANDLE;
1831 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1832 if(SUCCEEDED(hr)) {
1833 hFont = CreateFontIndirectW(&logfont);
1834 if(!hFont)
1835 TRACE("Failed to create font\n");
1837 if(hFont)
1838 oldFont = SelectObject(hdc, hFont);
1840 if(!GetTextMetricsW(hdc, ptm))
1841 hr = HRESULT_FROM_WIN32(GetLastError());
1843 if(hFont) {
1844 SelectObject(hdc, oldFont);
1845 DeleteObject(hFont);
1847 return hr;
1850 /***********************************************************************
1851 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1853 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1854 int iStateId)
1856 BOOL transparent = FALSE;
1857 TRACE("(%d,%d)\n", iPartId, iStateId);
1858 GetThemeBool(hTheme, iPartId, iStateId, TMT_TRANSPARENT, &transparent);
1859 return transparent;