readme.de: Git is not an acronym.
[wine/hramrach.git] / dlls / uxtheme / draw.c
blob9e220254db3c8a720e98f168e896ff9940f6c8b9
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "vfwmsgs.h"
31 #include "uxtheme.h"
32 #include "tmschema.h"
34 #include "msstyles.h"
35 #include "uxthemedll.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
41 /***********************************************************************
42 * Defines and global variables
45 extern ATOM atDialogThemeEnabled;
47 /***********************************************************************/
49 /***********************************************************************
50 * EnableThemeDialogTexture (UXTHEME.@)
52 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
54 static const WCHAR szTab[] = { 'T','a','b',0 };
55 BOOL res;
57 TRACE("(%p,0x%08x\n", hwnd, dwFlags);
58 res = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled),
59 (HANDLE)(dwFlags|0x80000000));
60 /* 0x80000000 serves as a "flags set" flag */
61 if (!res)
62 return HRESULT_FROM_WIN32(GetLastError());
63 if (dwFlags & ETDT_USETABTEXTURE)
64 return SetWindowTheme (hwnd, NULL, szTab);
65 else
66 return SetWindowTheme (hwnd, NULL, NULL);
69 /***********************************************************************
70 * IsThemeDialogTextureEnabled (UXTHEME.@)
72 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
74 DWORD dwDialogTextureFlags;
75 TRACE("(%p)\n", hwnd);
77 dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
78 (LPCWSTR)MAKEINTATOM(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, hParent, (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(hwnd, &rt);
114 MapWindowPoints(hwnd, hParent, (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 couldn't 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 BITMAP bmp;
199 HBITMAP hBmp;
200 BOOL hasAlpha;
202 lstrcpynW(szPath, fileProp->lpValue,
203 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
204 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
205 if(!hBmp) continue;
207 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
208 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
210 GetObjectW(hBmp, sizeof(bmp), &bmp);
211 if(imagelayout == IL_VERTICAL) {
212 reqsize.x = bmp.bmWidth;
213 reqsize.y = bmp.bmHeight/imagecount;
215 else {
216 reqsize.x = bmp.bmWidth/imagecount;
217 reqsize.y = bmp.bmHeight;
220 if(reqsize.x <= size.x && reqsize.y <= size.y) {
221 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
222 return fileProp;
225 /* If an image couldn't be selected, choose the smallest one */
226 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
228 return NULL;
231 /***********************************************************************
232 * UXTHEME_LoadImage
234 * Load image for part/state
236 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
237 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
239 int imagelayout = IL_HORIZONTAL;
240 int imagecount = 1;
241 int imagenum;
242 BITMAP bmp;
243 WCHAR szPath[MAX_PATH];
244 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
245 if(!tp) {
246 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
247 return E_PROP_ID_UNSUPPORTED;
249 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
250 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
251 if(!*hBmp) {
252 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
253 return HRESULT_FROM_WIN32(GetLastError());
256 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
257 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
259 imagenum = max (min (imagecount, iStateId), 1) - 1;
260 GetObjectW(*hBmp, sizeof(bmp), &bmp);
261 if(imagelayout == IL_VERTICAL) {
262 int height = bmp.bmHeight/imagecount;
263 bmpRect->left = 0;
264 bmpRect->right = bmp.bmWidth;
265 bmpRect->top = imagenum * height;
266 bmpRect->bottom = bmpRect->top + height;
268 else {
269 int width = bmp.bmWidth/imagecount;
270 bmpRect->left = imagenum * width;
271 bmpRect->right = bmpRect->left + width;
272 bmpRect->top = 0;
273 bmpRect->bottom = bmp.bmHeight;
275 return S_OK;
278 /***********************************************************************
279 * UXTHEME_StretchBlt
281 * Pseudo TransparentBlt/StretchBlt
283 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
284 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
285 INT transparent, COLORREF transcolor)
287 static const BLENDFUNCTION blendFunc =
289 AC_SRC_OVER, /* BlendOp */
290 0, /* BlendFlag */
291 255, /* SourceConstantAlpha */
292 AC_SRC_ALPHA /* AlphaFormat */
294 if (transparent == ALPHABLEND_BINARY) {
295 /* Ensure we don't pass any negative values to TransparentBlt */
296 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
297 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
298 transcolor);
300 if ((transparent == ALPHABLEND_NONE) ||
301 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
302 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
303 blendFunc))
305 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
306 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
307 SRCCOPY);
309 return TRUE;
312 /***********************************************************************
313 * UXTHEME_Blt
315 * Simplify sending same width/height for both source and dest
317 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
318 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
319 INT transparent, COLORREF transcolor)
321 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
322 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
323 transparent, transcolor);
326 /***********************************************************************
327 * UXTHEME_SizedBlt
329 * Stretches or tiles, depending on sizingtype.
331 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
332 int nWidthDst, int nHeightDst,
333 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
334 int nWidthSrc, int nHeightSrc,
335 int sizingtype,
336 INT transparent, COLORREF transcolor)
338 if (sizingtype == ST_TILE)
340 HDC hdcTemp;
341 BOOL result = FALSE;
343 if (!nWidthSrc || !nHeightSrc) return TRUE;
345 /* For destination width/height less than or equal to source
346 width/height, do not bother with memory bitmap optimization */
347 if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
349 int bltWidth = min (nWidthDst, nWidthSrc);
350 int bltHeight = min (nHeightDst, nHeightSrc);
352 return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
353 hdcSrc, nXOriginSrc, nYOriginSrc,
354 transparent, transcolor);
357 /* Create a DC with a bitmap consisting of a tiling of the source
358 bitmap, with standard GDI functions. This is faster than an
359 iteration with UXTHEME_Blt(). */
360 hdcTemp = CreateCompatibleDC(hdcSrc);
361 if (hdcTemp != 0)
363 HBITMAP bitmapTemp;
364 HBITMAP bitmapOrig;
365 int nWidthTemp, nHeightTemp;
366 int xOfs, xRemaining;
367 int yOfs, yRemaining;
368 int growSize;
370 /* Calculate temp dimensions of integer multiples of source dimensions */
371 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
372 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
373 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
374 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
376 /* Initial copy of bitmap */
377 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
379 /* Extend bitmap in the X direction. Growth of width is exponential */
380 xOfs = nWidthSrc;
381 xRemaining = nWidthTemp - nWidthSrc;
382 growSize = nWidthSrc;
383 while (xRemaining > 0)
385 growSize = min(growSize, xRemaining);
386 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
387 xOfs += growSize;
388 xRemaining -= growSize;
389 growSize *= 2;
392 /* Extend bitmap in the Y direction. Growth of height is exponential */
393 yOfs = nHeightSrc;
394 yRemaining = nHeightTemp - nHeightSrc;
395 growSize = nHeightSrc;
396 while (yRemaining > 0)
398 growSize = min(growSize, yRemaining);
399 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
400 yOfs += growSize;
401 yRemaining -= growSize;
402 growSize *= 2;
405 /* Use temporary hdc for source */
406 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
407 hdcTemp, 0, 0,
408 transparent, transcolor);
410 SelectObject(hdcTemp, bitmapOrig);
411 DeleteObject(bitmapTemp);
413 DeleteDC(hdcTemp);
414 return result;
416 else
418 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
419 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
420 transparent, transcolor);
424 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
425 * depend on whether the image has full alpha or whether it is
426 * color-transparent or just opaque. */
427 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
428 BOOL hasImageAlpha, INT* transparent,
429 COLORREF* transparentcolor, BOOL glyph)
431 if (hasImageAlpha)
433 *transparent = ALPHABLEND_FULL;
434 *transparentcolor = RGB (255, 0, 255);
436 else
438 BOOL trans = FALSE;
439 GetThemeBool(hTheme, iPartId, iStateId,
440 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
441 if(trans) {
442 *transparent = ALPHABLEND_BINARY;
443 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
444 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
445 transparentcolor))) {
446 /* If image is transparent, but no color was specified, use magenta */
447 *transparentcolor = RGB(255, 0, 255);
450 else
451 *transparent = ALPHABLEND_NONE;
455 /***********************************************************************
456 * UXTHEME_DrawImageGlyph
458 * Draw an imagefile glyph
460 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
461 int iStateId, RECT *pRect,
462 const DTBGOPTS *pOptions)
464 HRESULT hr;
465 HBITMAP bmpSrc = NULL;
466 HDC hdcSrc = NULL;
467 HGDIOBJ oldSrc = NULL;
468 RECT rcSrc;
469 INT transparent = FALSE;
470 COLORREF transparentcolor;
471 int valign = VA_CENTER;
472 int halign = HA_CENTER;
473 POINT dstSize;
474 POINT srcSize;
475 POINT topleft;
476 BOOL hasAlpha;
478 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
479 &bmpSrc, &rcSrc, &hasAlpha);
480 if(FAILED(hr)) return hr;
481 hdcSrc = CreateCompatibleDC(hdc);
482 if(!hdcSrc) {
483 hr = HRESULT_FROM_WIN32(GetLastError());
484 return hr;
486 oldSrc = SelectObject(hdcSrc, bmpSrc);
488 dstSize.x = pRect->right-pRect->left;
489 dstSize.y = pRect->bottom-pRect->top;
490 srcSize.x = rcSrc.right-rcSrc.left;
491 srcSize.y = rcSrc.bottom-rcSrc.top;
493 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
494 &transparentcolor, TRUE);
495 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
496 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
498 topleft.x = pRect->left;
499 topleft.y = pRect->top;
500 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
501 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
502 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
503 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
505 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
506 hdcSrc, rcSrc.left, rcSrc.top,
507 transparent, transparentcolor)) {
508 hr = HRESULT_FROM_WIN32(GetLastError());
511 SelectObject(hdcSrc, oldSrc);
512 DeleteDC(hdcSrc);
513 return hr;
516 /***********************************************************************
517 * UXTHEME_DrawImageGlyph
519 * Draw glyph on top of background, if appropriate
521 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
522 int iStateId, RECT *pRect,
523 const DTBGOPTS *pOptions)
525 int glyphtype = GT_NONE;
527 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
529 if(glyphtype == GT_IMAGEGLYPH) {
530 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
532 else if(glyphtype == GT_FONTGLYPH) {
533 /* I don't know what a font glyph is, I've never seen it used in any themes */
534 FIXME("Font glyph\n");
536 return S_OK;
539 /***********************************************************************
540 * get_image_part_size
542 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
544 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
545 int iStateId, RECT *prc, THEMESIZE eSize,
546 POINT *psz)
548 HRESULT hr = S_OK;
549 HBITMAP bmpSrc;
550 RECT rcSrc;
551 BOOL hasAlpha;
553 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
554 &bmpSrc, &rcSrc, &hasAlpha);
555 if (FAILED(hr)) return hr;
557 switch (eSize)
559 case TS_DRAW:
560 if (prc != NULL)
562 RECT rcDst;
563 POINT dstSize;
564 POINT srcSize;
565 int sizingtype = ST_STRETCH;
566 BOOL uniformsizing = FALSE;
568 CopyRect(&rcDst, prc);
570 dstSize.x = rcDst.right-rcDst.left;
571 dstSize.y = rcDst.bottom-rcDst.top;
572 srcSize.x = rcSrc.right-rcSrc.left;
573 srcSize.y = rcSrc.bottom-rcSrc.top;
575 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
576 if(uniformsizing) {
577 /* Scale height and width equally */
578 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
580 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
581 rcDst.bottom = rcDst.top + dstSize.y;
583 else
585 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
586 rcDst.right = rcDst.left + dstSize.x;
590 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
591 if(sizingtype == ST_TRUESIZE) {
592 int truesizestretchmark = 100;
594 if(dstSize.x < 0 || dstSize.y < 0) {
595 BOOL mirrorimage = TRUE;
596 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
597 if(mirrorimage) {
598 if(dstSize.x < 0) {
599 rcDst.left += dstSize.x;
600 rcDst.right += dstSize.x;
602 if(dstSize.y < 0) {
603 rcDst.top += dstSize.y;
604 rcDst.bottom += dstSize.y;
608 /* Whatever TrueSizeStretchMark does - it does not seem to
609 * be what's outlined below. It appears as if native
610 * uxtheme always stretches if dest is smaller than source
611 * (ie as if TrueSizeStretchMark==100 with the code below) */
612 #if 0
613 /* Only stretch when target exceeds source by truesizestretchmark percent */
614 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
615 #endif
616 if(dstSize.x < 0 || dstSize.y < 0 ||
617 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
618 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
619 memcpy (psz, &dstSize, sizeof (SIZE));
621 else {
622 memcpy (psz, &srcSize, sizeof (SIZE));
625 else
627 psz->x = abs(dstSize.x);
628 psz->y = abs(dstSize.y);
630 break;
632 /* else fall through */
633 case TS_MIN:
634 /* FIXME: couldn't figure how native uxtheme computes min size */
635 case TS_TRUE:
636 psz->x = rcSrc.right - rcSrc.left;
637 psz->y = rcSrc.bottom - rcSrc.top;
638 break;
640 return hr;
643 /***********************************************************************
644 * UXTHEME_DrawImageBackground
646 * Draw an imagefile background
648 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
649 int iStateId, RECT *pRect,
650 const DTBGOPTS *pOptions)
652 HRESULT hr = S_OK;
653 HBITMAP bmpSrc;
654 HGDIOBJ oldSrc;
655 HDC hdcSrc;
656 RECT rcSrc;
657 RECT rcDst;
658 POINT dstSize;
659 POINT srcSize;
660 POINT drawSize;
661 int sizingtype = ST_STRETCH;
662 INT transparent;
663 COLORREF transparentcolor = 0;
664 BOOL hasAlpha;
666 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
667 &bmpSrc, &rcSrc, &hasAlpha);
668 if(FAILED(hr)) return hr;
669 hdcSrc = CreateCompatibleDC(hdc);
670 if(!hdcSrc) {
671 hr = HRESULT_FROM_WIN32(GetLastError());
672 return hr;
674 oldSrc = SelectObject(hdcSrc, bmpSrc);
676 CopyRect(&rcDst, pRect);
678 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
679 &transparentcolor, FALSE);
681 dstSize.x = rcDst.right-rcDst.left;
682 dstSize.y = rcDst.bottom-rcDst.top;
683 srcSize.x = rcSrc.right-rcSrc.left;
684 srcSize.y = rcSrc.bottom-rcSrc.top;
686 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
687 if(sizingtype == ST_TRUESIZE) {
688 int valign = VA_CENTER, halign = HA_CENTER;
690 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
691 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
692 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
694 if (halign == HA_CENTER)
695 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
696 else if (halign == HA_RIGHT)
697 rcDst.left = rcDst.right - drawSize.x;
698 if (valign == VA_CENTER)
699 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
700 else if (valign == VA_BOTTOM)
701 rcDst.top = rcDst.bottom - drawSize.y;
702 rcDst.right = rcDst.left + drawSize.x;
703 rcDst.bottom = rcDst.top + drawSize.y;
704 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
705 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
706 transparent, transparentcolor))
707 hr = HRESULT_FROM_WIN32(GetLastError());
709 else {
710 HDC hdcDst = NULL;
711 MARGINS sm;
712 POINT org;
714 dstSize.x = abs(dstSize.x);
715 dstSize.y = abs(dstSize.y);
717 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
719 hdcDst = hdc;
720 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
722 /* Upper left corner */
723 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
724 hdcSrc, rcSrc.left, rcSrc.top,
725 transparent, transparentcolor)) {
726 hr = HRESULT_FROM_WIN32(GetLastError());
727 goto draw_error;
729 /* Upper right corner */
730 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
731 sm.cxRightWidth, sm.cyTopHeight,
732 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
733 transparent, transparentcolor)) {
734 hr = HRESULT_FROM_WIN32(GetLastError());
735 goto draw_error;
737 /* Lower left corner */
738 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
739 sm.cxLeftWidth, sm.cyBottomHeight,
740 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
741 transparent, transparentcolor)) {
742 hr = HRESULT_FROM_WIN32(GetLastError());
743 goto draw_error;
745 /* Lower right corner */
746 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
747 sm.cxRightWidth, sm.cyBottomHeight,
748 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
749 transparent, transparentcolor)) {
750 hr = HRESULT_FROM_WIN32(GetLastError());
751 goto draw_error;
754 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
755 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
756 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
757 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
758 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
760 if(destCenterWidth > 0) {
761 /* Center top */
762 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
763 destCenterWidth, sm.cyTopHeight,
764 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
765 srcCenterWidth, sm.cyTopHeight,
766 sizingtype, transparent, transparentcolor)) {
767 hr = HRESULT_FROM_WIN32(GetLastError());
768 goto draw_error;
770 /* Center bottom */
771 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
772 destCenterWidth, sm.cyBottomHeight,
773 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
774 srcCenterWidth, sm.cyBottomHeight,
775 sizingtype, transparent, transparentcolor)) {
776 hr = HRESULT_FROM_WIN32(GetLastError());
777 goto draw_error;
780 if(destCenterHeight > 0) {
781 /* Left center */
782 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
783 sm.cxLeftWidth, destCenterHeight,
784 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
785 sm.cxLeftWidth, srcCenterHeight,
786 sizingtype,
787 transparent, transparentcolor)) {
788 hr = HRESULT_FROM_WIN32(GetLastError());
789 goto draw_error;
791 /* Right center */
792 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
793 sm.cxRightWidth, destCenterHeight,
794 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
795 sm.cxRightWidth, srcCenterHeight,
796 sizingtype, transparent, transparentcolor)) {
797 hr = HRESULT_FROM_WIN32(GetLastError());
798 goto draw_error;
801 if(destCenterHeight > 0 && destCenterWidth > 0) {
802 BOOL borderonly = FALSE;
803 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
804 if(!borderonly) {
805 /* Center */
806 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
807 destCenterWidth, destCenterHeight,
808 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
809 srcCenterWidth, srcCenterHeight,
810 sizingtype, transparent, transparentcolor)) {
811 hr = HRESULT_FROM_WIN32(GetLastError());
812 goto draw_error;
818 draw_error:
819 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
821 SelectObject(hdcSrc, oldSrc);
822 DeleteDC(hdcSrc);
823 CopyRect(pRect, &rcDst);
824 return hr;
827 /***********************************************************************
828 * UXTHEME_DrawBorderRectangle
830 * Draw the bounding rectangle for a borderfill background
832 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
833 int iStateId, RECT *pRect,
834 const DTBGOPTS *pOptions)
836 HRESULT hr = S_OK;
837 HPEN hPen;
838 HGDIOBJ oldPen;
839 COLORREF bordercolor = RGB(0,0,0);
840 int bordersize = 1;
842 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
843 if(bordersize > 0) {
844 POINT ptCorners[5];
845 ptCorners[0].x = pRect->left;
846 ptCorners[0].y = pRect->top;
847 ptCorners[1].x = pRect->right-1;
848 ptCorners[1].y = pRect->top;
849 ptCorners[2].x = pRect->right-1;
850 ptCorners[2].y = pRect->bottom-1;
851 ptCorners[3].x = pRect->left;
852 ptCorners[3].y = pRect->bottom-1;
853 ptCorners[4].x = pRect->left;
854 ptCorners[4].y = pRect->top;
856 InflateRect(pRect, -bordersize, -bordersize);
857 if(pOptions->dwFlags & DTBG_OMITBORDER)
858 return S_OK;
859 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
860 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
861 if(!hPen)
862 return HRESULT_FROM_WIN32(GetLastError());
863 oldPen = SelectObject(hdc, hPen);
865 if(!Polyline(hdc, ptCorners, 5))
866 hr = HRESULT_FROM_WIN32(GetLastError());
868 SelectObject(hdc, oldPen);
869 DeleteObject(hPen);
871 return hr;
874 /***********************************************************************
875 * UXTHEME_DrawBackgroundFill
877 * Fill a borderfill background rectangle
879 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
880 int iStateId, RECT *pRect,
881 const DTBGOPTS *pOptions)
883 HRESULT hr = S_OK;
884 int filltype = FT_SOLID;
886 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
888 if(pOptions->dwFlags & DTBG_OMITCONTENT)
889 return S_OK;
891 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
893 if(filltype == FT_SOLID) {
894 HBRUSH hBrush;
895 COLORREF fillcolor = RGB(255,255,255);
897 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
898 hBrush = CreateSolidBrush(fillcolor);
899 if(!FillRect(hdc, pRect, hBrush))
900 hr = HRESULT_FROM_WIN32(GetLastError());
901 DeleteObject(hBrush);
903 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
904 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
905 the gradient ratios (no idea how those work)
906 Few themes use this, and the ones I've seen only use 2 colors with
907 a gradient ratio of 0 and 255 respectively
910 COLORREF gradient1 = RGB(0,0,0);
911 COLORREF gradient2 = RGB(255,255,255);
912 TRIVERTEX vert[2];
913 GRADIENT_RECT gRect;
915 FIXME("Gradient implementation not complete\n");
917 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
918 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
920 vert[0].x = pRect->left;
921 vert[0].y = pRect->top;
922 vert[0].Red = GetRValue(gradient1) << 8;
923 vert[0].Green = GetGValue(gradient1) << 8;
924 vert[0].Blue = GetBValue(gradient1) << 8;
925 vert[0].Alpha = 0x0000;
927 vert[1].x = pRect->right;
928 vert[1].y = pRect->bottom;
929 vert[1].Red = GetRValue(gradient2) << 8;
930 vert[1].Green = GetGValue(gradient2) << 8;
931 vert[1].Blue = GetBValue(gradient2) << 8;
932 vert[1].Alpha = 0x0000;
934 gRect.UpperLeft = 0;
935 gRect.LowerRight = 1;
936 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
938 else if(filltype == FT_RADIALGRADIENT) {
939 /* I've never seen this used in a theme */
940 FIXME("Radial gradient\n");
942 else if(filltype == FT_TILEIMAGE) {
943 /* I've never seen this used in a theme */
944 FIXME("Tile image\n");
946 return hr;
949 /***********************************************************************
950 * UXTHEME_DrawBorderBackground
952 * Draw an imagefile background
954 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
955 int iStateId, const RECT *pRect,
956 const DTBGOPTS *pOptions)
958 HRESULT hr;
959 RECT rt;
961 CopyRect(&rt, pRect);
963 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
964 if(FAILED(hr))
965 return hr;
966 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
969 /***********************************************************************
970 * DrawThemeBackgroundEx (UXTHEME.@)
972 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
973 int iStateId, const RECT *pRect,
974 const DTBGOPTS *pOptions)
976 HRESULT hr;
977 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
978 const DTBGOPTS *opts;
979 HRGN clip = NULL;
980 int hasClip = -1;
981 int bgtype = BT_BORDERFILL;
982 RECT rt;
984 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
985 if(!hTheme)
986 return E_HANDLE;
988 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
989 if (bgtype == BT_NONE) return S_OK;
991 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
992 opts = pOptions;
993 if(!opts) opts = &defaultOpts;
995 if(opts->dwFlags & DTBG_CLIPRECT) {
996 clip = CreateRectRgn(0,0,1,1);
997 hasClip = GetClipRgn(hdc, clip);
998 if(hasClip == -1)
999 TRACE("Failed to get original clipping region\n");
1000 else
1001 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
1003 CopyRect(&rt, pRect);
1005 if(bgtype == BT_IMAGEFILE)
1006 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
1007 else if(bgtype == BT_BORDERFILL)
1008 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
1009 else {
1010 FIXME("Unknown background type\n");
1011 /* This should never happen, and hence I don't know what to return */
1012 hr = E_FAIL;
1014 if(SUCCEEDED(hr))
1015 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1016 if(opts->dwFlags & DTBG_CLIPRECT) {
1017 if(hasClip == 0)
1018 SelectClipRgn(hdc, NULL);
1019 else if(hasClip == 1)
1020 SelectClipRgn(hdc, clip);
1021 DeleteObject(clip);
1023 return hr;
1027 * DrawThemeEdge() implementation
1029 * Since it basically is DrawEdge() with different colors, I copied its code
1030 * from user32's uitools.c.
1033 enum
1035 EDGE_LIGHT,
1036 EDGE_HIGHLIGHT,
1037 EDGE_SHADOW,
1038 EDGE_DARKSHADOW,
1039 EDGE_FILL,
1041 EDGE_WINDOW,
1042 EDGE_WINDOWFRAME,
1044 EDGE_NUMCOLORS
1047 static const struct
1049 int themeProp;
1050 int sysColor;
1051 } EdgeColorMap[EDGE_NUMCOLORS] = {
1052 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1053 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1054 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1055 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1056 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1057 {-1, COLOR_WINDOW},
1058 {-1, COLOR_WINDOWFRAME}
1061 static const signed char LTInnerNormal[] = {
1062 -1, -1, -1, -1,
1063 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1064 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1065 -1, -1, -1, -1
1068 static const signed char LTOuterNormal[] = {
1069 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1070 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1071 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1072 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1075 static const signed char RBInnerNormal[] = {
1076 -1, -1, -1, -1,
1077 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1078 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1079 -1, -1, -1, -1
1082 static const signed char RBOuterNormal[] = {
1083 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1084 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1085 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1086 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1089 static const signed char LTInnerSoft[] = {
1090 -1, -1, -1, -1,
1091 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1092 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1093 -1, -1, -1, -1
1096 static const signed char LTOuterSoft[] = {
1097 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1098 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1099 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1100 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1103 #define RBInnerSoft RBInnerNormal /* These are the same */
1104 #define RBOuterSoft RBOuterNormal
1106 static const signed char LTRBOuterMono[] = {
1107 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1108 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1109 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1110 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1113 static const signed char LTRBInnerMono[] = {
1114 -1, -1, -1, -1,
1115 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1116 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1117 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1120 static const signed char LTRBOuterFlat[] = {
1121 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1122 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1123 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1124 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1127 static const signed char LTRBInnerFlat[] = {
1128 -1, -1, -1, -1,
1129 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1130 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1131 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1134 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1136 COLORREF col;
1137 if ((EdgeColorMap[edgeType].themeProp == -1)
1138 || FAILED (GetThemeColor (theme, part, state,
1139 EdgeColorMap[edgeType].themeProp, &col)))
1140 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1141 return col;
1144 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1146 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1149 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1151 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1154 /***********************************************************************
1155 * draw_diag_edge
1157 * Same as DrawEdge invoked with BF_DIAGONAL
1159 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1160 const RECT* rc, UINT uType,
1161 UINT uFlags, LPRECT contentsRect)
1163 POINT Points[4];
1164 signed char InnerI, OuterI;
1165 HPEN InnerPen, OuterPen;
1166 POINT SavePoint;
1167 HPEN SavePen;
1168 int spx, spy;
1169 int epx, epy;
1170 int Width = rc->right - rc->left;
1171 int Height= rc->bottom - rc->top;
1172 int SmallDiam = Width > Height ? Height : Width;
1173 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1174 || (uType & BDR_OUTER) == BDR_OUTER)
1175 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1176 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1177 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1179 /* Init some vars */
1180 OuterPen = InnerPen = GetStockObject(NULL_PEN);
1181 SavePen = SelectObject(hdc, InnerPen);
1182 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1184 /* Determine the colors of the edges */
1185 if(uFlags & BF_MONO)
1187 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1188 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1190 else if(uFlags & BF_FLAT)
1192 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1193 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1195 else if(uFlags & BF_SOFT)
1197 if(uFlags & BF_BOTTOM)
1199 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1200 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1202 else
1204 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1205 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1208 else
1210 if(uFlags & BF_BOTTOM)
1212 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1213 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1215 else
1217 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1218 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1222 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1223 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1225 MoveToEx(hdc, 0, 0, &SavePoint);
1227 /* Don't ask me why, but this is what is visible... */
1228 /* This must be possible to do much simpler, but I fail to */
1229 /* see the logic in the MS implementation (sigh...). */
1230 /* So, this might look a bit brute force here (and it is), but */
1231 /* it gets the job done;) */
1233 switch(uFlags & BF_RECT)
1235 case 0:
1236 case BF_LEFT:
1237 case BF_BOTTOM:
1238 case BF_BOTTOMLEFT:
1239 /* Left bottom endpoint */
1240 epx = rc->left-1;
1241 spx = epx + SmallDiam;
1242 epy = rc->bottom;
1243 spy = epy - SmallDiam;
1244 break;
1246 case BF_TOPLEFT:
1247 case BF_BOTTOMRIGHT:
1248 /* Left top endpoint */
1249 epx = rc->left-1;
1250 spx = epx + SmallDiam;
1251 epy = rc->top-1;
1252 spy = epy + SmallDiam;
1253 break;
1255 case BF_TOP:
1256 case BF_RIGHT:
1257 case BF_TOPRIGHT:
1258 case BF_RIGHT|BF_LEFT:
1259 case BF_RIGHT|BF_LEFT|BF_TOP:
1260 case BF_BOTTOM|BF_TOP:
1261 case BF_BOTTOM|BF_TOP|BF_LEFT:
1262 case BF_BOTTOMRIGHT|BF_LEFT:
1263 case BF_BOTTOMRIGHT|BF_TOP:
1264 case BF_RECT:
1265 /* Right top endpoint */
1266 spx = rc->left;
1267 epx = spx + SmallDiam;
1268 spy = rc->bottom-1;
1269 epy = spy - SmallDiam;
1270 break;
1273 MoveToEx(hdc, spx, spy, NULL);
1274 SelectObject(hdc, OuterPen);
1275 LineTo(hdc, epx, epy);
1277 SelectObject(hdc, InnerPen);
1279 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1281 case BF_DIAGONAL_ENDBOTTOMLEFT:
1282 case (BF_DIAGONAL|BF_BOTTOM):
1283 case BF_DIAGONAL:
1284 case (BF_DIAGONAL|BF_LEFT):
1285 MoveToEx(hdc, spx-1, spy, NULL);
1286 LineTo(hdc, epx, epy-1);
1287 Points[0].x = spx-add;
1288 Points[0].y = spy;
1289 Points[1].x = rc->left;
1290 Points[1].y = rc->top;
1291 Points[2].x = epx+1;
1292 Points[2].y = epy-1-add;
1293 Points[3] = Points[2];
1294 break;
1296 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1297 MoveToEx(hdc, spx-1, spy, NULL);
1298 LineTo(hdc, epx, epy+1);
1299 Points[0].x = spx-add;
1300 Points[0].y = spy;
1301 Points[1].x = rc->left;
1302 Points[1].y = rc->bottom-1;
1303 Points[2].x = epx+1;
1304 Points[2].y = epy+1+add;
1305 Points[3] = Points[2];
1306 break;
1308 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1309 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1310 case BF_DIAGONAL_ENDTOPRIGHT:
1311 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1312 MoveToEx(hdc, spx+1, spy, NULL);
1313 LineTo(hdc, epx, epy+1);
1314 Points[0].x = epx-1;
1315 Points[0].y = epy+1+add;
1316 Points[1].x = rc->right-1;
1317 Points[1].y = rc->top+add;
1318 Points[2].x = rc->right-1;
1319 Points[2].y = rc->bottom-1;
1320 Points[3].x = spx+add;
1321 Points[3].y = spy;
1322 break;
1324 case BF_DIAGONAL_ENDTOPLEFT:
1325 MoveToEx(hdc, spx, spy-1, NULL);
1326 LineTo(hdc, epx+1, epy);
1327 Points[0].x = epx+1+add;
1328 Points[0].y = epy+1;
1329 Points[1].x = rc->right-1;
1330 Points[1].y = rc->top;
1331 Points[2].x = rc->right-1;
1332 Points[2].y = rc->bottom-1-add;
1333 Points[3].x = spx;
1334 Points[3].y = spy-add;
1335 break;
1337 case (BF_DIAGONAL|BF_TOP):
1338 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1339 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1340 MoveToEx(hdc, spx+1, spy-1, NULL);
1341 LineTo(hdc, epx, epy);
1342 Points[0].x = epx-1;
1343 Points[0].y = epy+1;
1344 Points[1].x = rc->right-1;
1345 Points[1].y = rc->top;
1346 Points[2].x = rc->right-1;
1347 Points[2].y = rc->bottom-1-add;
1348 Points[3].x = spx+add;
1349 Points[3].y = spy-add;
1350 break;
1352 case (BF_DIAGONAL|BF_RIGHT):
1353 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1354 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1355 MoveToEx(hdc, spx, spy, NULL);
1356 LineTo(hdc, epx-1, epy+1);
1357 Points[0].x = spx;
1358 Points[0].y = spy;
1359 Points[1].x = rc->left;
1360 Points[1].y = rc->top+add;
1361 Points[2].x = epx-1-add;
1362 Points[2].y = epy+1+add;
1363 Points[3] = Points[2];
1364 break;
1367 /* Fill the interior if asked */
1368 if((uFlags & BF_MIDDLE) && retval)
1370 HBRUSH hbsave;
1371 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1372 theme, part, state);
1373 HPEN hpsave;
1374 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1375 theme, part, state);
1376 hbsave = SelectObject(hdc, hb);
1377 hpsave = SelectObject(hdc, hp);
1378 Polygon(hdc, Points, 4);
1379 SelectObject(hdc, hbsave);
1380 SelectObject(hdc, hpsave);
1381 DeleteObject (hp);
1382 DeleteObject (hb);
1385 /* Adjust rectangle if asked */
1386 if(uFlags & BF_ADJUST)
1388 *contentsRect = *rc;
1389 if(uFlags & BF_LEFT) contentsRect->left += add;
1390 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1391 if(uFlags & BF_TOP) contentsRect->top += add;
1392 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1395 /* Cleanup */
1396 SelectObject(hdc, SavePen);
1397 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1398 if(InnerI != -1) DeleteObject (InnerPen);
1399 if(OuterI != -1) DeleteObject (OuterPen);
1401 return retval;
1404 /***********************************************************************
1405 * draw_rect_edge
1407 * Same as DrawEdge invoked without BF_DIAGONAL
1409 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1410 const RECT* rc, UINT uType,
1411 UINT uFlags, LPRECT contentsRect)
1413 signed char LTInnerI, LTOuterI;
1414 signed char RBInnerI, RBOuterI;
1415 HPEN LTInnerPen, LTOuterPen;
1416 HPEN RBInnerPen, RBOuterPen;
1417 RECT InnerRect = *rc;
1418 POINT SavePoint;
1419 HPEN SavePen;
1420 int LBpenplus = 0;
1421 int LTpenplus = 0;
1422 int RTpenplus = 0;
1423 int RBpenplus = 0;
1424 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1425 || (uType & BDR_OUTER) == BDR_OUTER)
1426 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1428 /* Init some vars */
1429 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = GetStockObject(NULL_PEN);
1430 SavePen = SelectObject(hdc, LTInnerPen);
1432 /* Determine the colors of the edges */
1433 if(uFlags & BF_MONO)
1435 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1436 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1438 else if(uFlags & BF_FLAT)
1440 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1441 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1443 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1445 else if(uFlags & BF_SOFT)
1447 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1448 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1449 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1450 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1452 else
1454 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1455 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1456 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1457 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1460 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1461 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1462 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1463 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1465 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1466 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1467 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1468 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1470 MoveToEx(hdc, 0, 0, &SavePoint);
1472 /* Draw the outer edge */
1473 SelectObject(hdc, LTOuterPen);
1474 if(uFlags & BF_TOP)
1476 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1477 LineTo(hdc, InnerRect.right, InnerRect.top);
1479 if(uFlags & BF_LEFT)
1481 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1482 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1484 SelectObject(hdc, RBOuterPen);
1485 if(uFlags & BF_BOTTOM)
1487 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1488 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1490 if(uFlags & BF_RIGHT)
1492 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1493 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1496 /* Draw the inner edge */
1497 SelectObject(hdc, LTInnerPen);
1498 if(uFlags & BF_TOP)
1500 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1501 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1503 if(uFlags & BF_LEFT)
1505 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1506 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1508 SelectObject(hdc, RBInnerPen);
1509 if(uFlags & BF_BOTTOM)
1511 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1512 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1514 if(uFlags & BF_RIGHT)
1516 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1517 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1520 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1522 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1523 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1525 if(uFlags & BF_LEFT) InnerRect.left += add;
1526 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1527 if(uFlags & BF_TOP) InnerRect.top += add;
1528 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1530 if((uFlags & BF_MIDDLE) && retval)
1532 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1533 theme, part, state);
1534 FillRect(hdc, &InnerRect, br);
1535 DeleteObject (br);
1538 if(uFlags & BF_ADJUST)
1539 *contentsRect = InnerRect;
1542 /* Cleanup */
1543 SelectObject(hdc, SavePen);
1544 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1545 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1546 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1547 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1548 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1549 return retval;
1553 /***********************************************************************
1554 * DrawThemeEdge (UXTHEME.@)
1556 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1557 * difference is that it does not rely on the system colors alone, but
1558 * also allows color specification in the theme.
1560 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1561 int iStateId, const RECT *pDestRect, UINT uEdge,
1562 UINT uFlags, RECT *pContentRect)
1564 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1565 if(!hTheme)
1566 return E_HANDLE;
1568 if(uFlags & BF_DIAGONAL)
1569 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1570 uEdge, uFlags, pContentRect);
1571 else
1572 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1573 uEdge, uFlags, pContentRect);
1577 /***********************************************************************
1578 * DrawThemeIcon (UXTHEME.@)
1580 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1581 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1583 FIXME("%d %d: stub\n", iPartId, iStateId);
1584 if(!hTheme)
1585 return E_HANDLE;
1586 return ERROR_CALL_NOT_IMPLEMENTED;
1589 /***********************************************************************
1590 * DrawThemeText (UXTHEME.@)
1592 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1593 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1594 DWORD dwTextFlags2, const RECT *pRect)
1596 HRESULT hr;
1597 HFONT hFont = NULL;
1598 HGDIOBJ oldFont = NULL;
1599 LOGFONTW logfont;
1600 COLORREF textColor;
1601 COLORREF oldTextColor;
1602 int oldBkMode;
1603 RECT rt;
1605 TRACE("%d %d: stub\n", iPartId, iStateId);
1606 if(!hTheme)
1607 return E_HANDLE;
1609 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1610 if(SUCCEEDED(hr)) {
1611 hFont = CreateFontIndirectW(&logfont);
1612 if(!hFont)
1613 TRACE("Failed to create font\n");
1615 CopyRect(&rt, pRect);
1616 if(hFont)
1617 oldFont = SelectObject(hdc, hFont);
1619 if(dwTextFlags2 & DTT_GRAYED)
1620 textColor = GetSysColor(COLOR_GRAYTEXT);
1621 else {
1622 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1623 textColor = GetTextColor(hdc);
1625 oldTextColor = SetTextColor(hdc, textColor);
1626 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1627 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1628 SetBkMode(hdc, oldBkMode);
1629 SetTextColor(hdc, oldTextColor);
1631 if(hFont) {
1632 SelectObject(hdc, oldFont);
1633 DeleteObject(hFont);
1635 return S_OK;
1638 /***********************************************************************
1639 * GetThemeBackgroundContentRect (UXTHEME.@)
1641 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1642 int iStateId,
1643 const RECT *pBoundingRect,
1644 RECT *pContentRect)
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 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1657 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1658 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1659 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1660 } else {
1661 /* otherwise, try to determine content rect from the background type and props */
1662 int bgtype = BT_BORDERFILL;
1663 *pContentRect = *pBoundingRect;
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(pContentRect, -bordersize, -bordersize);
1671 } else if ((bgtype == BT_IMAGEFILE)
1672 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1673 TMT_SIZINGMARGINS, NULL, &margin)))) {
1674 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1675 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1676 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1677 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1679 /* If nothing was found, leave unchanged */
1682 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1684 return S_OK;
1687 /***********************************************************************
1688 * GetThemeBackgroundExtent (UXTHEME.@)
1690 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1691 int iStateId, const RECT *pContentRect,
1692 RECT *pExtentRect)
1694 MARGINS margin;
1695 HRESULT hr;
1697 TRACE("(%d,%d)\n", iPartId, iStateId);
1698 if(!hTheme)
1699 return E_HANDLE;
1701 /* try content margins property... */
1702 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1703 if(SUCCEEDED(hr)) {
1704 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1705 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1706 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1707 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1708 } else {
1709 /* otherwise, try to determine content rect from the background type and props */
1710 int bgtype = BT_BORDERFILL;
1711 *pExtentRect = *pContentRect;
1713 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1714 if(bgtype == BT_BORDERFILL) {
1715 int bordersize = 1;
1717 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1718 InflateRect(pExtentRect, bordersize, bordersize);
1719 } else if ((bgtype == BT_IMAGEFILE)
1720 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1721 TMT_SIZINGMARGINS, NULL, &margin)))) {
1722 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1723 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1724 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1725 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1727 /* If nothing was found, leave unchanged */
1730 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1732 return S_OK;
1735 /***********************************************************************
1736 * GetThemeBackgroundRegion (UXTHEME.@)
1738 * Calculate the background region, taking into consideration transparent areas
1739 * of the background image.
1741 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1742 int iStateId, const RECT *pRect,
1743 HRGN *pRegion)
1745 HRESULT hr = S_OK;
1746 int bgtype = BT_BORDERFILL;
1748 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1749 if(!hTheme)
1750 return E_HANDLE;
1751 if(!pRect || !pRegion)
1752 return E_POINTER;
1754 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1755 if(bgtype == BT_IMAGEFILE) {
1756 FIXME("Images not handled yet\n");
1757 hr = ERROR_CALL_NOT_IMPLEMENTED;
1759 else if(bgtype == BT_BORDERFILL) {
1760 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1761 if(!*pRegion)
1762 hr = HRESULT_FROM_WIN32(GetLastError());
1764 else {
1765 FIXME("Unknown background type\n");
1766 /* This should never happen, and hence I don't know what to return */
1767 hr = E_FAIL;
1769 return hr;
1772 /* compute part size for "borderfill" backgrounds */
1773 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1774 int iStateId, THEMESIZE eSize, POINT* psz)
1776 HRESULT hr = S_OK;
1777 int bordersize = 1;
1779 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1780 &bordersize)))
1782 psz->x = psz->y = 2*bordersize;
1783 if (eSize != TS_MIN)
1785 psz->x++;
1786 psz->y++;
1789 return hr;
1792 /***********************************************************************
1793 * GetThemePartSize (UXTHEME.@)
1795 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1796 int iStateId, RECT *prc, THEMESIZE eSize,
1797 SIZE *psz)
1799 int bgtype = BT_BORDERFILL;
1800 HRESULT hr = S_OK;
1801 POINT size = {1, 1};
1803 if(!hTheme)
1804 return E_HANDLE;
1806 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1807 if (bgtype == BT_NONE)
1808 /* do nothing */;
1809 else if(bgtype == BT_IMAGEFILE)
1810 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1811 else if(bgtype == BT_BORDERFILL)
1812 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1813 else {
1814 FIXME("Unknown background type\n");
1815 /* This should never happen, and hence I don't know what to return */
1816 hr = E_FAIL;
1818 psz->cx = size.x;
1819 psz->cy = size.y;
1820 return hr;
1824 /***********************************************************************
1825 * GetThemeTextExtent (UXTHEME.@)
1827 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1828 int iStateId, LPCWSTR pszText, int iCharCount,
1829 DWORD dwTextFlags, const RECT *pBoundingRect,
1830 RECT *pExtentRect)
1832 HRESULT hr;
1833 HFONT hFont = NULL;
1834 HGDIOBJ oldFont = NULL;
1835 LOGFONTW logfont;
1836 RECT rt = {0,0,0xFFFF,0xFFFF};
1838 TRACE("%d %d: stub\n", iPartId, iStateId);
1839 if(!hTheme)
1840 return E_HANDLE;
1842 if(pBoundingRect)
1843 CopyRect(&rt, pBoundingRect);
1845 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1846 if(SUCCEEDED(hr)) {
1847 hFont = CreateFontIndirectW(&logfont);
1848 if(!hFont)
1849 TRACE("Failed to create font\n");
1851 if(hFont)
1852 oldFont = SelectObject(hdc, hFont);
1854 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1855 CopyRect(pExtentRect, &rt);
1857 if(hFont) {
1858 SelectObject(hdc, oldFont);
1859 DeleteObject(hFont);
1861 return S_OK;
1864 /***********************************************************************
1865 * GetThemeTextMetrics (UXTHEME.@)
1867 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1868 int iStateId, TEXTMETRICW *ptm)
1870 HRESULT hr;
1871 HFONT hFont = NULL;
1872 HGDIOBJ oldFont = NULL;
1873 LOGFONTW logfont;
1875 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1876 if(!hTheme)
1877 return E_HANDLE;
1879 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1880 if(SUCCEEDED(hr)) {
1881 hFont = CreateFontIndirectW(&logfont);
1882 if(!hFont)
1883 TRACE("Failed to create font\n");
1885 if(hFont)
1886 oldFont = SelectObject(hdc, hFont);
1888 if(!GetTextMetricsW(hdc, ptm))
1889 hr = HRESULT_FROM_WIN32(GetLastError());
1891 if(hFont) {
1892 SelectObject(hdc, oldFont);
1893 DeleteObject(hFont);
1895 return hr;
1898 /***********************************************************************
1899 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1901 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1902 int iStateId)
1904 int bgtype = BT_BORDERFILL;
1905 RECT rect = {0, 0, 0, 0};
1906 HBITMAP bmpSrc;
1907 RECT rcSrc;
1908 BOOL hasAlpha;
1909 INT transparent;
1910 COLORREF transparentcolor;
1912 TRACE("(%d,%d)\n", iPartId, iStateId);
1914 if(!hTheme)
1915 return FALSE;
1917 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1919 if (bgtype != BT_IMAGEFILE) return FALSE;
1921 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1922 &bmpSrc, &rcSrc, &hasAlpha)))
1923 return FALSE;
1925 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1926 &transparentcolor, FALSE);
1927 return (transparent != ALPHABLEND_NONE);