push 5b1efc32b5a8acb1d5b5e60584746392dd0c436e
[wine/hacks.git] / dlls / uxtheme / draw.c
blob17900f8352b224e6dd94c88a81d6878e86a7f0d7
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 UlongToHandle(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 = HandleToUlong( GetPropW( hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled) ));
78 if (dwDialogTextureFlags == 0)
79 /* Means EnableThemeDialogTexture wasn't called for this dialog */
80 return TRUE;
82 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
85 /***********************************************************************
86 * DrawThemeParentBackground (UXTHEME.@)
88 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
90 RECT rt;
91 POINT org;
92 HWND hParent;
93 HRGN clip = NULL;
94 int hasClip = -1;
96 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
97 hParent = GetParent(hwnd);
98 if(!hParent)
99 hParent = hwnd;
100 if(prc) {
101 CopyRect(&rt, prc);
102 MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2);
104 clip = CreateRectRgn(0,0,1,1);
105 hasClip = GetClipRgn(hdc, clip);
106 if(hasClip == -1)
107 TRACE("Failed to get original clipping region\n");
108 else
109 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
111 else {
112 GetClientRect(hwnd, &rt);
113 MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2);
116 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
118 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
119 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
121 SetViewportOrgEx(hdc, org.x, org.y, NULL);
122 if(prc) {
123 if(hasClip == 0)
124 SelectClipRgn(hdc, NULL);
125 else if(hasClip == 1)
126 SelectClipRgn(hdc, clip);
127 DeleteObject(clip);
129 return S_OK;
133 /***********************************************************************
134 * DrawThemeBackground (UXTHEME.@)
136 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
137 int iStateId, const RECT *pRect,
138 const RECT *pClipRect)
140 DTBGOPTS opts;
141 opts.dwSize = sizeof(DTBGOPTS);
142 opts.dwFlags = 0;
143 if(pClipRect) {
144 opts.dwFlags |= DTBG_CLIPRECT;
145 CopyRect(&opts.rcClip, pClipRect);
147 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
150 /***********************************************************************
151 * UXTHEME_SelectImage
153 * Select the image to use
155 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
157 PTHEME_PROPERTY tp;
158 int imageselecttype = IST_NONE;
159 int i;
160 int image;
161 if(glyph)
162 image = TMT_GLYPHIMAGEFILE;
163 else
164 image = TMT_IMAGEFILE;
166 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
167 return tp;
168 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
170 if(imageselecttype == IST_DPI) {
171 int reqdpi = 0;
172 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
173 for(i=4; i>=0; i--) {
174 reqdpi = 0;
175 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
176 if(reqdpi != 0 && screendpi >= reqdpi) {
177 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
178 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
182 /* If an image couldn't be selected, choose the first one */
183 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
185 else if(imageselecttype == IST_SIZE) {
186 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
187 POINT reqsize;
188 for(i=4; i>=0; i--) {
189 PTHEME_PROPERTY fileProp =
190 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
191 if (!fileProp) continue;
192 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
193 /* fall back to size of Nth image */
194 WCHAR szPath[MAX_PATH];
195 int imagelayout = IL_HORIZONTAL;
196 int imagecount = 1;
197 BITMAP bmp;
198 HBITMAP hBmp;
199 BOOL hasAlpha;
201 lstrcpynW(szPath, fileProp->lpValue,
202 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
203 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
204 if(!hBmp) continue;
206 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
207 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
209 GetObjectW(hBmp, sizeof(bmp), &bmp);
210 if(imagelayout == IL_VERTICAL) {
211 reqsize.x = bmp.bmWidth;
212 reqsize.y = bmp.bmHeight/imagecount;
214 else {
215 reqsize.x = bmp.bmWidth/imagecount;
216 reqsize.y = bmp.bmHeight;
219 if(reqsize.x <= size.x && reqsize.y <= size.y) {
220 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
221 return fileProp;
224 /* If an image couldn't be selected, choose the smallest one */
225 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
227 return NULL;
230 /***********************************************************************
231 * UXTHEME_LoadImage
233 * Load image for part/state
235 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
236 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
238 int imagelayout = IL_HORIZONTAL;
239 int imagecount = 1;
240 int imagenum;
241 BITMAP bmp;
242 WCHAR szPath[MAX_PATH];
243 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
244 if(!tp) {
245 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
246 return E_PROP_ID_UNSUPPORTED;
248 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
249 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
250 if(!*hBmp) {
251 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
252 return HRESULT_FROM_WIN32(GetLastError());
255 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
256 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
258 imagenum = max (min (imagecount, iStateId), 1) - 1;
259 GetObjectW(*hBmp, sizeof(bmp), &bmp);
260 if(imagelayout == IL_VERTICAL) {
261 int height = bmp.bmHeight/imagecount;
262 bmpRect->left = 0;
263 bmpRect->right = bmp.bmWidth;
264 bmpRect->top = imagenum * height;
265 bmpRect->bottom = bmpRect->top + height;
267 else {
268 int width = bmp.bmWidth/imagecount;
269 bmpRect->left = imagenum * width;
270 bmpRect->right = bmpRect->left + width;
271 bmpRect->top = 0;
272 bmpRect->bottom = bmp.bmHeight;
274 return S_OK;
277 /***********************************************************************
278 * UXTHEME_StretchBlt
280 * Pseudo TransparentBlt/StretchBlt
282 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
283 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
284 INT transparent, COLORREF transcolor)
286 static const BLENDFUNCTION blendFunc =
288 AC_SRC_OVER, /* BlendOp */
289 0, /* BlendFlag */
290 255, /* SourceConstantAlpha */
291 AC_SRC_ALPHA /* AlphaFormat */
293 if (transparent == ALPHABLEND_BINARY) {
294 /* Ensure we don't pass any negative values to TransparentBlt */
295 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
296 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
297 transcolor);
299 if ((transparent == ALPHABLEND_NONE) ||
300 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
301 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
302 blendFunc))
304 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
305 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
306 SRCCOPY);
308 return TRUE;
311 /***********************************************************************
312 * UXTHEME_Blt
314 * Simplify sending same width/height for both source and dest
316 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
317 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
318 INT transparent, COLORREF transcolor)
320 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
321 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
322 transparent, transcolor);
325 /***********************************************************************
326 * UXTHEME_SizedBlt
328 * Stretches or tiles, depending on sizingtype.
330 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
331 int nWidthDst, int nHeightDst,
332 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
333 int nWidthSrc, int nHeightSrc,
334 int sizingtype,
335 INT transparent, COLORREF transcolor)
337 if (sizingtype == ST_TILE)
339 HDC hdcTemp;
340 BOOL result = FALSE;
342 if (!nWidthSrc || !nHeightSrc) return TRUE;
344 /* For destination width/height less than or equal to source
345 width/height, do not bother with memory bitmap optimization */
346 if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
348 int bltWidth = min (nWidthDst, nWidthSrc);
349 int bltHeight = min (nHeightDst, nHeightSrc);
351 return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
352 hdcSrc, nXOriginSrc, nYOriginSrc,
353 transparent, transcolor);
356 /* Create a DC with a bitmap consisting of a tiling of the source
357 bitmap, with standard GDI functions. This is faster than an
358 iteration with UXTHEME_Blt(). */
359 hdcTemp = CreateCompatibleDC(hdcSrc);
360 if (hdcTemp != 0)
362 HBITMAP bitmapTemp;
363 HBITMAP bitmapOrig;
364 int nWidthTemp, nHeightTemp;
365 int xOfs, xRemaining;
366 int yOfs, yRemaining;
367 int growSize;
369 /* Calculate temp dimensions of integer multiples of source dimensions */
370 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
371 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
372 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
373 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
375 /* Initial copy of bitmap */
376 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
378 /* Extend bitmap in the X direction. Growth of width is exponential */
379 xOfs = nWidthSrc;
380 xRemaining = nWidthTemp - nWidthSrc;
381 growSize = nWidthSrc;
382 while (xRemaining > 0)
384 growSize = min(growSize, xRemaining);
385 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
386 xOfs += growSize;
387 xRemaining -= growSize;
388 growSize *= 2;
391 /* Extend bitmap in the Y direction. Growth of height is exponential */
392 yOfs = nHeightSrc;
393 yRemaining = nHeightTemp - nHeightSrc;
394 growSize = nHeightSrc;
395 while (yRemaining > 0)
397 growSize = min(growSize, yRemaining);
398 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
399 yOfs += growSize;
400 yRemaining -= growSize;
401 growSize *= 2;
404 /* Use temporary hdc for source */
405 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
406 hdcTemp, 0, 0,
407 transparent, transcolor);
409 SelectObject(hdcTemp, bitmapOrig);
410 DeleteObject(bitmapTemp);
412 DeleteDC(hdcTemp);
413 return result;
415 else
417 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
418 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
419 transparent, transcolor);
423 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
424 * depend on whether the image has full alpha or whether it is
425 * color-transparent or just opaque. */
426 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
427 BOOL hasImageAlpha, INT* transparent,
428 COLORREF* transparentcolor, BOOL glyph)
430 if (hasImageAlpha)
432 *transparent = ALPHABLEND_FULL;
433 *transparentcolor = RGB (255, 0, 255);
435 else
437 BOOL trans = FALSE;
438 GetThemeBool(hTheme, iPartId, iStateId,
439 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
440 if(trans) {
441 *transparent = ALPHABLEND_BINARY;
442 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
443 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
444 transparentcolor))) {
445 /* If image is transparent, but no color was specified, use magenta */
446 *transparentcolor = RGB(255, 0, 255);
449 else
450 *transparent = ALPHABLEND_NONE;
454 /***********************************************************************
455 * UXTHEME_DrawImageGlyph
457 * Draw an imagefile glyph
459 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
460 int iStateId, RECT *pRect,
461 const DTBGOPTS *pOptions)
463 HRESULT hr;
464 HBITMAP bmpSrc = NULL;
465 HDC hdcSrc = NULL;
466 HGDIOBJ oldSrc = NULL;
467 RECT rcSrc;
468 INT transparent = FALSE;
469 COLORREF transparentcolor;
470 int valign = VA_CENTER;
471 int halign = HA_CENTER;
472 POINT dstSize;
473 POINT srcSize;
474 POINT topleft;
475 BOOL hasAlpha;
477 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
478 &bmpSrc, &rcSrc, &hasAlpha);
479 if(FAILED(hr)) return hr;
480 hdcSrc = CreateCompatibleDC(hdc);
481 if(!hdcSrc) {
482 hr = HRESULT_FROM_WIN32(GetLastError());
483 return hr;
485 oldSrc = SelectObject(hdcSrc, bmpSrc);
487 dstSize.x = pRect->right-pRect->left;
488 dstSize.y = pRect->bottom-pRect->top;
489 srcSize.x = rcSrc.right-rcSrc.left;
490 srcSize.y = rcSrc.bottom-rcSrc.top;
492 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
493 &transparentcolor, TRUE);
494 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
495 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
497 topleft.x = pRect->left;
498 topleft.y = pRect->top;
499 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
500 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
501 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
502 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
504 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
505 hdcSrc, rcSrc.left, rcSrc.top,
506 transparent, transparentcolor)) {
507 hr = HRESULT_FROM_WIN32(GetLastError());
510 SelectObject(hdcSrc, oldSrc);
511 DeleteDC(hdcSrc);
512 return hr;
515 /***********************************************************************
516 * UXTHEME_DrawImageGlyph
518 * Draw glyph on top of background, if appropriate
520 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
521 int iStateId, RECT *pRect,
522 const DTBGOPTS *pOptions)
524 int glyphtype = GT_NONE;
526 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
528 if(glyphtype == GT_IMAGEGLYPH) {
529 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
531 else if(glyphtype == GT_FONTGLYPH) {
532 /* I don't know what a font glyph is, I've never seen it used in any themes */
533 FIXME("Font glyph\n");
535 return S_OK;
538 /***********************************************************************
539 * get_image_part_size
541 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
543 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
544 int iStateId, RECT *prc, THEMESIZE eSize,
545 POINT *psz)
547 HRESULT hr = S_OK;
548 HBITMAP bmpSrc;
549 RECT rcSrc;
550 BOOL hasAlpha;
552 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
553 &bmpSrc, &rcSrc, &hasAlpha);
554 if (FAILED(hr)) return hr;
556 switch (eSize)
558 case TS_DRAW:
559 if (prc != NULL)
561 RECT rcDst;
562 POINT dstSize;
563 POINT srcSize;
564 int sizingtype = ST_STRETCH;
565 BOOL uniformsizing = FALSE;
567 CopyRect(&rcDst, prc);
569 dstSize.x = rcDst.right-rcDst.left;
570 dstSize.y = rcDst.bottom-rcDst.top;
571 srcSize.x = rcSrc.right-rcSrc.left;
572 srcSize.y = rcSrc.bottom-rcSrc.top;
574 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
575 if(uniformsizing) {
576 /* Scale height and width equally */
577 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
579 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
580 rcDst.bottom = rcDst.top + dstSize.y;
582 else
584 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
585 rcDst.right = rcDst.left + dstSize.x;
589 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
590 if(sizingtype == ST_TRUESIZE) {
591 int truesizestretchmark = 100;
593 if(dstSize.x < 0 || dstSize.y < 0) {
594 BOOL mirrorimage = TRUE;
595 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
596 if(mirrorimage) {
597 if(dstSize.x < 0) {
598 rcDst.left += dstSize.x;
599 rcDst.right += dstSize.x;
601 if(dstSize.y < 0) {
602 rcDst.top += dstSize.y;
603 rcDst.bottom += dstSize.y;
607 /* Whatever TrueSizeStretchMark does - it does not seem to
608 * be what's outlined below. It appears as if native
609 * uxtheme always stretches if dest is smaller than source
610 * (ie as if TrueSizeStretchMark==100 with the code below) */
611 #if 0
612 /* Only stretch when target exceeds source by truesizestretchmark percent */
613 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
614 #endif
615 if(dstSize.x < 0 || dstSize.y < 0 ||
616 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
617 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
618 memcpy (psz, &dstSize, sizeof (SIZE));
620 else {
621 memcpy (psz, &srcSize, sizeof (SIZE));
624 else
626 psz->x = abs(dstSize.x);
627 psz->y = abs(dstSize.y);
629 break;
631 /* else fall through */
632 case TS_MIN:
633 /* FIXME: couldn't figure how native uxtheme computes min size */
634 case TS_TRUE:
635 psz->x = rcSrc.right - rcSrc.left;
636 psz->y = rcSrc.bottom - rcSrc.top;
637 break;
639 return hr;
642 /***********************************************************************
643 * UXTHEME_DrawImageBackground
645 * Draw an imagefile background
647 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
648 int iStateId, RECT *pRect,
649 const DTBGOPTS *pOptions)
651 HRESULT hr = S_OK;
652 HBITMAP bmpSrc;
653 HGDIOBJ oldSrc;
654 HDC hdcSrc;
655 RECT rcSrc;
656 RECT rcDst;
657 POINT dstSize;
658 POINT srcSize;
659 POINT drawSize;
660 int sizingtype = ST_STRETCH;
661 INT transparent;
662 COLORREF transparentcolor = 0;
663 BOOL hasAlpha;
665 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
666 &bmpSrc, &rcSrc, &hasAlpha);
667 if(FAILED(hr)) return hr;
668 hdcSrc = CreateCompatibleDC(hdc);
669 if(!hdcSrc) {
670 hr = HRESULT_FROM_WIN32(GetLastError());
671 return hr;
673 oldSrc = SelectObject(hdcSrc, bmpSrc);
675 CopyRect(&rcDst, pRect);
677 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
678 &transparentcolor, FALSE);
680 dstSize.x = rcDst.right-rcDst.left;
681 dstSize.y = rcDst.bottom-rcDst.top;
682 srcSize.x = rcSrc.right-rcSrc.left;
683 srcSize.y = rcSrc.bottom-rcSrc.top;
685 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
686 if(sizingtype == ST_TRUESIZE) {
687 int valign = VA_CENTER, halign = HA_CENTER;
689 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
690 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
691 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
693 if (halign == HA_CENTER)
694 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
695 else if (halign == HA_RIGHT)
696 rcDst.left = rcDst.right - drawSize.x;
697 if (valign == VA_CENTER)
698 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
699 else if (valign == VA_BOTTOM)
700 rcDst.top = rcDst.bottom - drawSize.y;
701 rcDst.right = rcDst.left + drawSize.x;
702 rcDst.bottom = rcDst.top + drawSize.y;
703 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
704 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
705 transparent, transparentcolor))
706 hr = HRESULT_FROM_WIN32(GetLastError());
708 else {
709 HDC hdcDst = NULL;
710 MARGINS sm;
711 POINT org;
713 dstSize.x = abs(dstSize.x);
714 dstSize.y = abs(dstSize.y);
716 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
718 hdcDst = hdc;
719 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
721 /* Upper left corner */
722 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
723 hdcSrc, rcSrc.left, rcSrc.top,
724 transparent, transparentcolor)) {
725 hr = HRESULT_FROM_WIN32(GetLastError());
726 goto draw_error;
728 /* Upper right corner */
729 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
730 sm.cxRightWidth, sm.cyTopHeight,
731 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
732 transparent, transparentcolor)) {
733 hr = HRESULT_FROM_WIN32(GetLastError());
734 goto draw_error;
736 /* Lower left corner */
737 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
738 sm.cxLeftWidth, sm.cyBottomHeight,
739 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
740 transparent, transparentcolor)) {
741 hr = HRESULT_FROM_WIN32(GetLastError());
742 goto draw_error;
744 /* Lower right corner */
745 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
746 sm.cxRightWidth, sm.cyBottomHeight,
747 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
748 transparent, transparentcolor)) {
749 hr = HRESULT_FROM_WIN32(GetLastError());
750 goto draw_error;
753 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
754 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
755 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
756 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
757 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
759 if(destCenterWidth > 0) {
760 /* Center top */
761 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
762 destCenterWidth, sm.cyTopHeight,
763 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
764 srcCenterWidth, sm.cyTopHeight,
765 sizingtype, transparent, transparentcolor)) {
766 hr = HRESULT_FROM_WIN32(GetLastError());
767 goto draw_error;
769 /* Center bottom */
770 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
771 destCenterWidth, sm.cyBottomHeight,
772 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
773 srcCenterWidth, sm.cyBottomHeight,
774 sizingtype, transparent, transparentcolor)) {
775 hr = HRESULT_FROM_WIN32(GetLastError());
776 goto draw_error;
779 if(destCenterHeight > 0) {
780 /* Left center */
781 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
782 sm.cxLeftWidth, destCenterHeight,
783 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
784 sm.cxLeftWidth, srcCenterHeight,
785 sizingtype,
786 transparent, transparentcolor)) {
787 hr = HRESULT_FROM_WIN32(GetLastError());
788 goto draw_error;
790 /* Right center */
791 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
792 sm.cxRightWidth, destCenterHeight,
793 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
794 sm.cxRightWidth, srcCenterHeight,
795 sizingtype, transparent, transparentcolor)) {
796 hr = HRESULT_FROM_WIN32(GetLastError());
797 goto draw_error;
800 if(destCenterHeight > 0 && destCenterWidth > 0) {
801 BOOL borderonly = FALSE;
802 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
803 if(!borderonly) {
804 /* Center */
805 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
806 destCenterWidth, destCenterHeight,
807 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
808 srcCenterWidth, srcCenterHeight,
809 sizingtype, transparent, transparentcolor)) {
810 hr = HRESULT_FROM_WIN32(GetLastError());
811 goto draw_error;
817 draw_error:
818 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
820 SelectObject(hdcSrc, oldSrc);
821 DeleteDC(hdcSrc);
822 CopyRect(pRect, &rcDst);
823 return hr;
826 /***********************************************************************
827 * UXTHEME_DrawBorderRectangle
829 * Draw the bounding rectangle for a borderfill background
831 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
832 int iStateId, RECT *pRect,
833 const DTBGOPTS *pOptions)
835 HRESULT hr = S_OK;
836 HPEN hPen;
837 HGDIOBJ oldPen;
838 COLORREF bordercolor = RGB(0,0,0);
839 int bordersize = 1;
841 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
842 if(bordersize > 0) {
843 POINT ptCorners[5];
844 ptCorners[0].x = pRect->left;
845 ptCorners[0].y = pRect->top;
846 ptCorners[1].x = pRect->right-1;
847 ptCorners[1].y = pRect->top;
848 ptCorners[2].x = pRect->right-1;
849 ptCorners[2].y = pRect->bottom-1;
850 ptCorners[3].x = pRect->left;
851 ptCorners[3].y = pRect->bottom-1;
852 ptCorners[4].x = pRect->left;
853 ptCorners[4].y = pRect->top;
855 InflateRect(pRect, -bordersize, -bordersize);
856 if(pOptions->dwFlags & DTBG_OMITBORDER)
857 return S_OK;
858 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
859 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
860 if(!hPen)
861 return HRESULT_FROM_WIN32(GetLastError());
862 oldPen = SelectObject(hdc, hPen);
864 if(!Polyline(hdc, ptCorners, 5))
865 hr = HRESULT_FROM_WIN32(GetLastError());
867 SelectObject(hdc, oldPen);
868 DeleteObject(hPen);
870 return hr;
873 /***********************************************************************
874 * UXTHEME_DrawBackgroundFill
876 * Fill a borderfill background rectangle
878 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
879 int iStateId, RECT *pRect,
880 const DTBGOPTS *pOptions)
882 HRESULT hr = S_OK;
883 int filltype = FT_SOLID;
885 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
887 if(pOptions->dwFlags & DTBG_OMITCONTENT)
888 return S_OK;
890 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
892 if(filltype == FT_SOLID) {
893 HBRUSH hBrush;
894 COLORREF fillcolor = RGB(255,255,255);
896 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
897 hBrush = CreateSolidBrush(fillcolor);
898 if(!FillRect(hdc, pRect, hBrush))
899 hr = HRESULT_FROM_WIN32(GetLastError());
900 DeleteObject(hBrush);
902 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
903 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
904 the gradient ratios (no idea how those work)
905 Few themes use this, and the ones I've seen only use 2 colors with
906 a gradient ratio of 0 and 255 respectively
909 COLORREF gradient1 = RGB(0,0,0);
910 COLORREF gradient2 = RGB(255,255,255);
911 TRIVERTEX vert[2];
912 GRADIENT_RECT gRect;
914 FIXME("Gradient implementation not complete\n");
916 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
917 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
919 vert[0].x = pRect->left;
920 vert[0].y = pRect->top;
921 vert[0].Red = GetRValue(gradient1) << 8;
922 vert[0].Green = GetGValue(gradient1) << 8;
923 vert[0].Blue = GetBValue(gradient1) << 8;
924 vert[0].Alpha = 0x0000;
926 vert[1].x = pRect->right;
927 vert[1].y = pRect->bottom;
928 vert[1].Red = GetRValue(gradient2) << 8;
929 vert[1].Green = GetGValue(gradient2) << 8;
930 vert[1].Blue = GetBValue(gradient2) << 8;
931 vert[1].Alpha = 0x0000;
933 gRect.UpperLeft = 0;
934 gRect.LowerRight = 1;
935 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
937 else if(filltype == FT_RADIALGRADIENT) {
938 /* I've never seen this used in a theme */
939 FIXME("Radial gradient\n");
941 else if(filltype == FT_TILEIMAGE) {
942 /* I've never seen this used in a theme */
943 FIXME("Tile image\n");
945 return hr;
948 /***********************************************************************
949 * UXTHEME_DrawBorderBackground
951 * Draw an imagefile background
953 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
954 int iStateId, const RECT *pRect,
955 const DTBGOPTS *pOptions)
957 HRESULT hr;
958 RECT rt;
960 CopyRect(&rt, pRect);
962 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
963 if(FAILED(hr))
964 return hr;
965 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
968 /***********************************************************************
969 * DrawThemeBackgroundEx (UXTHEME.@)
971 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
972 int iStateId, const RECT *pRect,
973 const DTBGOPTS *pOptions)
975 HRESULT hr;
976 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
977 const DTBGOPTS *opts;
978 HRGN clip = NULL;
979 int hasClip = -1;
980 int bgtype = BT_BORDERFILL;
981 RECT rt;
983 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
984 if(!hTheme)
985 return E_HANDLE;
987 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
988 if (bgtype == BT_NONE) return S_OK;
990 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
991 opts = pOptions;
992 if(!opts) opts = &defaultOpts;
994 if(opts->dwFlags & DTBG_CLIPRECT) {
995 clip = CreateRectRgn(0,0,1,1);
996 hasClip = GetClipRgn(hdc, clip);
997 if(hasClip == -1)
998 TRACE("Failed to get original clipping region\n");
999 else
1000 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
1002 CopyRect(&rt, pRect);
1004 if(bgtype == BT_IMAGEFILE)
1005 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
1006 else if(bgtype == BT_BORDERFILL)
1007 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
1008 else {
1009 FIXME("Unknown background type\n");
1010 /* This should never happen, and hence I don't know what to return */
1011 hr = E_FAIL;
1013 if(SUCCEEDED(hr))
1014 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1015 if(opts->dwFlags & DTBG_CLIPRECT) {
1016 if(hasClip == 0)
1017 SelectClipRgn(hdc, NULL);
1018 else if(hasClip == 1)
1019 SelectClipRgn(hdc, clip);
1020 DeleteObject(clip);
1022 return hr;
1026 * DrawThemeEdge() implementation
1028 * Since it basically is DrawEdge() with different colors, I copied its code
1029 * from user32's uitools.c.
1032 enum
1034 EDGE_LIGHT,
1035 EDGE_HIGHLIGHT,
1036 EDGE_SHADOW,
1037 EDGE_DARKSHADOW,
1038 EDGE_FILL,
1040 EDGE_WINDOW,
1041 EDGE_WINDOWFRAME,
1043 EDGE_NUMCOLORS
1046 static const struct
1048 int themeProp;
1049 int sysColor;
1050 } EdgeColorMap[EDGE_NUMCOLORS] = {
1051 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1052 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1053 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1054 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1055 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1056 {-1, COLOR_WINDOW},
1057 {-1, COLOR_WINDOWFRAME}
1060 static const signed char LTInnerNormal[] = {
1061 -1, -1, -1, -1,
1062 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1063 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1064 -1, -1, -1, -1
1067 static const signed char LTOuterNormal[] = {
1068 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1069 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1070 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1071 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1074 static const signed char RBInnerNormal[] = {
1075 -1, -1, -1, -1,
1076 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1077 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1078 -1, -1, -1, -1
1081 static const signed char RBOuterNormal[] = {
1082 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1083 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1084 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1085 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1088 static const signed char LTInnerSoft[] = {
1089 -1, -1, -1, -1,
1090 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1091 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1092 -1, -1, -1, -1
1095 static const signed char LTOuterSoft[] = {
1096 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1097 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1098 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1099 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1102 #define RBInnerSoft RBInnerNormal /* These are the same */
1103 #define RBOuterSoft RBOuterNormal
1105 static const signed char LTRBOuterMono[] = {
1106 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1107 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1108 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1109 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1112 static const signed char LTRBInnerMono[] = {
1113 -1, -1, -1, -1,
1114 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1115 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1116 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1119 static const signed char LTRBOuterFlat[] = {
1120 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1121 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1122 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1123 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1126 static const signed char LTRBInnerFlat[] = {
1127 -1, -1, -1, -1,
1128 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1129 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1130 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1133 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1135 COLORREF col;
1136 if ((EdgeColorMap[edgeType].themeProp == -1)
1137 || FAILED (GetThemeColor (theme, part, state,
1138 EdgeColorMap[edgeType].themeProp, &col)))
1139 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1140 return col;
1143 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1145 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1148 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1150 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1153 /***********************************************************************
1154 * draw_diag_edge
1156 * Same as DrawEdge invoked with BF_DIAGONAL
1158 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1159 const RECT* rc, UINT uType,
1160 UINT uFlags, LPRECT contentsRect)
1162 POINT Points[4];
1163 signed char InnerI, OuterI;
1164 HPEN InnerPen, OuterPen;
1165 POINT SavePoint;
1166 HPEN SavePen;
1167 int spx, spy;
1168 int epx, epy;
1169 int Width = rc->right - rc->left;
1170 int Height= rc->bottom - rc->top;
1171 int SmallDiam = Width > Height ? Height : Width;
1172 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1173 || (uType & BDR_OUTER) == BDR_OUTER)
1174 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1175 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1176 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1178 /* Init some vars */
1179 OuterPen = InnerPen = GetStockObject(NULL_PEN);
1180 SavePen = SelectObject(hdc, InnerPen);
1181 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1183 /* Determine the colors of the edges */
1184 if(uFlags & BF_MONO)
1186 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1187 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1189 else if(uFlags & BF_FLAT)
1191 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1192 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1194 else if(uFlags & BF_SOFT)
1196 if(uFlags & BF_BOTTOM)
1198 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1199 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1201 else
1203 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1204 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1207 else
1209 if(uFlags & BF_BOTTOM)
1211 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1212 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1214 else
1216 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1217 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1221 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1222 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1224 MoveToEx(hdc, 0, 0, &SavePoint);
1226 /* Don't ask me why, but this is what is visible... */
1227 /* This must be possible to do much simpler, but I fail to */
1228 /* see the logic in the MS implementation (sigh...). */
1229 /* So, this might look a bit brute force here (and it is), but */
1230 /* it gets the job done;) */
1232 switch(uFlags & BF_RECT)
1234 case 0:
1235 case BF_LEFT:
1236 case BF_BOTTOM:
1237 case BF_BOTTOMLEFT:
1238 /* Left bottom endpoint */
1239 epx = rc->left-1;
1240 spx = epx + SmallDiam;
1241 epy = rc->bottom;
1242 spy = epy - SmallDiam;
1243 break;
1245 case BF_TOPLEFT:
1246 case BF_BOTTOMRIGHT:
1247 /* Left top endpoint */
1248 epx = rc->left-1;
1249 spx = epx + SmallDiam;
1250 epy = rc->top-1;
1251 spy = epy + SmallDiam;
1252 break;
1254 case BF_TOP:
1255 case BF_RIGHT:
1256 case BF_TOPRIGHT:
1257 case BF_RIGHT|BF_LEFT:
1258 case BF_RIGHT|BF_LEFT|BF_TOP:
1259 case BF_BOTTOM|BF_TOP:
1260 case BF_BOTTOM|BF_TOP|BF_LEFT:
1261 case BF_BOTTOMRIGHT|BF_LEFT:
1262 case BF_BOTTOMRIGHT|BF_TOP:
1263 case BF_RECT:
1264 /* Right top endpoint */
1265 spx = rc->left;
1266 epx = spx + SmallDiam;
1267 spy = rc->bottom-1;
1268 epy = spy - SmallDiam;
1269 break;
1272 MoveToEx(hdc, spx, spy, NULL);
1273 SelectObject(hdc, OuterPen);
1274 LineTo(hdc, epx, epy);
1276 SelectObject(hdc, InnerPen);
1278 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1280 case BF_DIAGONAL_ENDBOTTOMLEFT:
1281 case (BF_DIAGONAL|BF_BOTTOM):
1282 case BF_DIAGONAL:
1283 case (BF_DIAGONAL|BF_LEFT):
1284 MoveToEx(hdc, spx-1, spy, NULL);
1285 LineTo(hdc, epx, epy-1);
1286 Points[0].x = spx-add;
1287 Points[0].y = spy;
1288 Points[1].x = rc->left;
1289 Points[1].y = rc->top;
1290 Points[2].x = epx+1;
1291 Points[2].y = epy-1-add;
1292 Points[3] = Points[2];
1293 break;
1295 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1296 MoveToEx(hdc, spx-1, spy, NULL);
1297 LineTo(hdc, epx, epy+1);
1298 Points[0].x = spx-add;
1299 Points[0].y = spy;
1300 Points[1].x = rc->left;
1301 Points[1].y = rc->bottom-1;
1302 Points[2].x = epx+1;
1303 Points[2].y = epy+1+add;
1304 Points[3] = Points[2];
1305 break;
1307 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1308 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1309 case BF_DIAGONAL_ENDTOPRIGHT:
1310 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1311 MoveToEx(hdc, spx+1, spy, NULL);
1312 LineTo(hdc, epx, epy+1);
1313 Points[0].x = epx-1;
1314 Points[0].y = epy+1+add;
1315 Points[1].x = rc->right-1;
1316 Points[1].y = rc->top+add;
1317 Points[2].x = rc->right-1;
1318 Points[2].y = rc->bottom-1;
1319 Points[3].x = spx+add;
1320 Points[3].y = spy;
1321 break;
1323 case BF_DIAGONAL_ENDTOPLEFT:
1324 MoveToEx(hdc, spx, spy-1, NULL);
1325 LineTo(hdc, epx+1, epy);
1326 Points[0].x = epx+1+add;
1327 Points[0].y = epy+1;
1328 Points[1].x = rc->right-1;
1329 Points[1].y = rc->top;
1330 Points[2].x = rc->right-1;
1331 Points[2].y = rc->bottom-1-add;
1332 Points[3].x = spx;
1333 Points[3].y = spy-add;
1334 break;
1336 case (BF_DIAGONAL|BF_TOP):
1337 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1338 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1339 MoveToEx(hdc, spx+1, spy-1, NULL);
1340 LineTo(hdc, epx, epy);
1341 Points[0].x = epx-1;
1342 Points[0].y = epy+1;
1343 Points[1].x = rc->right-1;
1344 Points[1].y = rc->top;
1345 Points[2].x = rc->right-1;
1346 Points[2].y = rc->bottom-1-add;
1347 Points[3].x = spx+add;
1348 Points[3].y = spy-add;
1349 break;
1351 case (BF_DIAGONAL|BF_RIGHT):
1352 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1353 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1354 MoveToEx(hdc, spx, spy, NULL);
1355 LineTo(hdc, epx-1, epy+1);
1356 Points[0].x = spx;
1357 Points[0].y = spy;
1358 Points[1].x = rc->left;
1359 Points[1].y = rc->top+add;
1360 Points[2].x = epx-1-add;
1361 Points[2].y = epy+1+add;
1362 Points[3] = Points[2];
1363 break;
1366 /* Fill the interior if asked */
1367 if((uFlags & BF_MIDDLE) && retval)
1369 HBRUSH hbsave;
1370 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1371 theme, part, state);
1372 HPEN hpsave;
1373 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1374 theme, part, state);
1375 hbsave = SelectObject(hdc, hb);
1376 hpsave = SelectObject(hdc, hp);
1377 Polygon(hdc, Points, 4);
1378 SelectObject(hdc, hbsave);
1379 SelectObject(hdc, hpsave);
1380 DeleteObject (hp);
1381 DeleteObject (hb);
1384 /* Adjust rectangle if asked */
1385 if(uFlags & BF_ADJUST)
1387 *contentsRect = *rc;
1388 if(uFlags & BF_LEFT) contentsRect->left += add;
1389 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1390 if(uFlags & BF_TOP) contentsRect->top += add;
1391 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1394 /* Cleanup */
1395 SelectObject(hdc, SavePen);
1396 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1397 if(InnerI != -1) DeleteObject (InnerPen);
1398 if(OuterI != -1) DeleteObject (OuterPen);
1400 return retval;
1403 /***********************************************************************
1404 * draw_rect_edge
1406 * Same as DrawEdge invoked without BF_DIAGONAL
1408 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1409 const RECT* rc, UINT uType,
1410 UINT uFlags, LPRECT contentsRect)
1412 signed char LTInnerI, LTOuterI;
1413 signed char RBInnerI, RBOuterI;
1414 HPEN LTInnerPen, LTOuterPen;
1415 HPEN RBInnerPen, RBOuterPen;
1416 RECT InnerRect = *rc;
1417 POINT SavePoint;
1418 HPEN SavePen;
1419 int LBpenplus = 0;
1420 int LTpenplus = 0;
1421 int RTpenplus = 0;
1422 int RBpenplus = 0;
1423 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1424 || (uType & BDR_OUTER) == BDR_OUTER)
1425 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1427 /* Init some vars */
1428 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = GetStockObject(NULL_PEN);
1429 SavePen = SelectObject(hdc, LTInnerPen);
1431 /* Determine the colors of the edges */
1432 if(uFlags & BF_MONO)
1434 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1435 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1437 else if(uFlags & BF_FLAT)
1439 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1440 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1442 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1444 else if(uFlags & BF_SOFT)
1446 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1447 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1448 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1449 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1451 else
1453 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1454 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1455 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1456 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1459 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1460 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1461 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1462 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1464 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1465 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1466 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1467 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1469 MoveToEx(hdc, 0, 0, &SavePoint);
1471 /* Draw the outer edge */
1472 SelectObject(hdc, LTOuterPen);
1473 if(uFlags & BF_TOP)
1475 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1476 LineTo(hdc, InnerRect.right, InnerRect.top);
1478 if(uFlags & BF_LEFT)
1480 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1481 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1483 SelectObject(hdc, RBOuterPen);
1484 if(uFlags & BF_BOTTOM)
1486 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1487 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1489 if(uFlags & BF_RIGHT)
1491 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1492 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1495 /* Draw the inner edge */
1496 SelectObject(hdc, LTInnerPen);
1497 if(uFlags & BF_TOP)
1499 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1500 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1502 if(uFlags & BF_LEFT)
1504 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1505 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1507 SelectObject(hdc, RBInnerPen);
1508 if(uFlags & BF_BOTTOM)
1510 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1511 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1513 if(uFlags & BF_RIGHT)
1515 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1516 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1519 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1521 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1522 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1524 if(uFlags & BF_LEFT) InnerRect.left += add;
1525 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1526 if(uFlags & BF_TOP) InnerRect.top += add;
1527 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1529 if((uFlags & BF_MIDDLE) && retval)
1531 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1532 theme, part, state);
1533 FillRect(hdc, &InnerRect, br);
1534 DeleteObject (br);
1537 if(uFlags & BF_ADJUST)
1538 *contentsRect = InnerRect;
1541 /* Cleanup */
1542 SelectObject(hdc, SavePen);
1543 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1544 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1545 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1546 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1547 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1548 return retval;
1552 /***********************************************************************
1553 * DrawThemeEdge (UXTHEME.@)
1555 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1556 * difference is that it does not rely on the system colors alone, but
1557 * also allows color specification in the theme.
1559 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1560 int iStateId, const RECT *pDestRect, UINT uEdge,
1561 UINT uFlags, RECT *pContentRect)
1563 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1564 if(!hTheme)
1565 return E_HANDLE;
1567 if(uFlags & BF_DIAGONAL)
1568 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1569 uEdge, uFlags, pContentRect);
1570 else
1571 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1572 uEdge, uFlags, pContentRect);
1576 /***********************************************************************
1577 * DrawThemeIcon (UXTHEME.@)
1579 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1580 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1582 FIXME("%d %d: stub\n", iPartId, iStateId);
1583 if(!hTheme)
1584 return E_HANDLE;
1585 return ERROR_CALL_NOT_IMPLEMENTED;
1588 /***********************************************************************
1589 * DrawThemeText (UXTHEME.@)
1591 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1592 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1593 DWORD dwTextFlags2, const RECT *pRect)
1595 HRESULT hr;
1596 HFONT hFont = NULL;
1597 HGDIOBJ oldFont = NULL;
1598 LOGFONTW logfont;
1599 COLORREF textColor;
1600 COLORREF oldTextColor;
1601 int oldBkMode;
1602 RECT rt;
1604 TRACE("%d %d: stub\n", iPartId, iStateId);
1605 if(!hTheme)
1606 return E_HANDLE;
1608 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1609 if(SUCCEEDED(hr)) {
1610 hFont = CreateFontIndirectW(&logfont);
1611 if(!hFont)
1612 TRACE("Failed to create font\n");
1614 CopyRect(&rt, pRect);
1615 if(hFont)
1616 oldFont = SelectObject(hdc, hFont);
1618 if(dwTextFlags2 & DTT_GRAYED)
1619 textColor = GetSysColor(COLOR_GRAYTEXT);
1620 else {
1621 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1622 textColor = GetTextColor(hdc);
1624 oldTextColor = SetTextColor(hdc, textColor);
1625 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1626 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1627 SetBkMode(hdc, oldBkMode);
1628 SetTextColor(hdc, oldTextColor);
1630 if(hFont) {
1631 SelectObject(hdc, oldFont);
1632 DeleteObject(hFont);
1634 return S_OK;
1637 /***********************************************************************
1638 * GetThemeBackgroundContentRect (UXTHEME.@)
1640 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1641 int iStateId,
1642 const RECT *pBoundingRect,
1643 RECT *pContentRect)
1645 MARGINS margin;
1646 HRESULT hr;
1648 TRACE("(%d,%d)\n", iPartId, iStateId);
1649 if(!hTheme)
1650 return E_HANDLE;
1652 /* try content margins property... */
1653 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1654 if(SUCCEEDED(hr)) {
1655 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1656 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1657 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1658 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1659 } else {
1660 /* otherwise, try to determine content rect from the background type and props */
1661 int bgtype = BT_BORDERFILL;
1662 *pContentRect = *pBoundingRect;
1664 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1665 if(bgtype == BT_BORDERFILL) {
1666 int bordersize = 1;
1668 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1669 InflateRect(pContentRect, -bordersize, -bordersize);
1670 } else if ((bgtype == BT_IMAGEFILE)
1671 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1672 TMT_SIZINGMARGINS, NULL, &margin)))) {
1673 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1674 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1675 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1676 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1678 /* If nothing was found, leave unchanged */
1681 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1683 return S_OK;
1686 /***********************************************************************
1687 * GetThemeBackgroundExtent (UXTHEME.@)
1689 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1690 int iStateId, const RECT *pContentRect,
1691 RECT *pExtentRect)
1693 MARGINS margin;
1694 HRESULT hr;
1696 TRACE("(%d,%d)\n", iPartId, iStateId);
1697 if(!hTheme)
1698 return E_HANDLE;
1700 /* try content margins property... */
1701 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1702 if(SUCCEEDED(hr)) {
1703 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1704 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1705 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1706 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1707 } else {
1708 /* otherwise, try to determine content rect from the background type and props */
1709 int bgtype = BT_BORDERFILL;
1710 *pExtentRect = *pContentRect;
1712 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1713 if(bgtype == BT_BORDERFILL) {
1714 int bordersize = 1;
1716 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1717 InflateRect(pExtentRect, bordersize, bordersize);
1718 } else if ((bgtype == BT_IMAGEFILE)
1719 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1720 TMT_SIZINGMARGINS, NULL, &margin)))) {
1721 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1722 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1723 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1724 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1726 /* If nothing was found, leave unchanged */
1729 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1731 return S_OK;
1734 /***********************************************************************
1735 * GetThemeBackgroundRegion (UXTHEME.@)
1737 * Calculate the background region, taking into consideration transparent areas
1738 * of the background image.
1740 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1741 int iStateId, const RECT *pRect,
1742 HRGN *pRegion)
1744 HRESULT hr = S_OK;
1745 int bgtype = BT_BORDERFILL;
1747 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1748 if(!hTheme)
1749 return E_HANDLE;
1750 if(!pRect || !pRegion)
1751 return E_POINTER;
1753 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1754 if(bgtype == BT_IMAGEFILE) {
1755 FIXME("Images not handled yet\n");
1756 hr = ERROR_CALL_NOT_IMPLEMENTED;
1758 else if(bgtype == BT_BORDERFILL) {
1759 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1760 if(!*pRegion)
1761 hr = HRESULT_FROM_WIN32(GetLastError());
1763 else {
1764 FIXME("Unknown background type\n");
1765 /* This should never happen, and hence I don't know what to return */
1766 hr = E_FAIL;
1768 return hr;
1771 /* compute part size for "borderfill" backgrounds */
1772 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1773 int iStateId, THEMESIZE eSize, POINT* psz)
1775 HRESULT hr = S_OK;
1776 int bordersize = 1;
1778 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1779 &bordersize)))
1781 psz->x = psz->y = 2*bordersize;
1782 if (eSize != TS_MIN)
1784 psz->x++;
1785 psz->y++;
1788 return hr;
1791 /***********************************************************************
1792 * GetThemePartSize (UXTHEME.@)
1794 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1795 int iStateId, RECT *prc, THEMESIZE eSize,
1796 SIZE *psz)
1798 int bgtype = BT_BORDERFILL;
1799 HRESULT hr = S_OK;
1800 POINT size = {1, 1};
1802 if(!hTheme)
1803 return E_HANDLE;
1805 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1806 if (bgtype == BT_NONE)
1807 /* do nothing */;
1808 else if(bgtype == BT_IMAGEFILE)
1809 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1810 else if(bgtype == BT_BORDERFILL)
1811 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1812 else {
1813 FIXME("Unknown background type\n");
1814 /* This should never happen, and hence I don't know what to return */
1815 hr = E_FAIL;
1817 psz->cx = size.x;
1818 psz->cy = size.y;
1819 return hr;
1823 /***********************************************************************
1824 * GetThemeTextExtent (UXTHEME.@)
1826 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1827 int iStateId, LPCWSTR pszText, int iCharCount,
1828 DWORD dwTextFlags, const RECT *pBoundingRect,
1829 RECT *pExtentRect)
1831 HRESULT hr;
1832 HFONT hFont = NULL;
1833 HGDIOBJ oldFont = NULL;
1834 LOGFONTW logfont;
1835 RECT rt = {0,0,0xFFFF,0xFFFF};
1837 TRACE("%d %d: stub\n", iPartId, iStateId);
1838 if(!hTheme)
1839 return E_HANDLE;
1841 if(pBoundingRect)
1842 CopyRect(&rt, pBoundingRect);
1844 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1845 if(SUCCEEDED(hr)) {
1846 hFont = CreateFontIndirectW(&logfont);
1847 if(!hFont)
1848 TRACE("Failed to create font\n");
1850 if(hFont)
1851 oldFont = SelectObject(hdc, hFont);
1853 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1854 CopyRect(pExtentRect, &rt);
1856 if(hFont) {
1857 SelectObject(hdc, oldFont);
1858 DeleteObject(hFont);
1860 return S_OK;
1863 /***********************************************************************
1864 * GetThemeTextMetrics (UXTHEME.@)
1866 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1867 int iStateId, TEXTMETRICW *ptm)
1869 HRESULT hr;
1870 HFONT hFont = NULL;
1871 HGDIOBJ oldFont = NULL;
1872 LOGFONTW logfont;
1874 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1875 if(!hTheme)
1876 return E_HANDLE;
1878 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1879 if(SUCCEEDED(hr)) {
1880 hFont = CreateFontIndirectW(&logfont);
1881 if(!hFont)
1882 TRACE("Failed to create font\n");
1884 if(hFont)
1885 oldFont = SelectObject(hdc, hFont);
1887 if(!GetTextMetricsW(hdc, ptm))
1888 hr = HRESULT_FROM_WIN32(GetLastError());
1890 if(hFont) {
1891 SelectObject(hdc, oldFont);
1892 DeleteObject(hFont);
1894 return hr;
1897 /***********************************************************************
1898 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1900 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1901 int iStateId)
1903 int bgtype = BT_BORDERFILL;
1904 RECT rect = {0, 0, 0, 0};
1905 HBITMAP bmpSrc;
1906 RECT rcSrc;
1907 BOOL hasAlpha;
1908 INT transparent;
1909 COLORREF transparentcolor;
1911 TRACE("(%d,%d)\n", iPartId, iStateId);
1913 if(!hTheme)
1914 return FALSE;
1916 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1918 if (bgtype != BT_IMAGEFILE) return FALSE;
1920 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1921 &bmpSrc, &rcSrc, &hasAlpha)))
1922 return FALSE;
1924 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1925 &transparentcolor, FALSE);
1926 return (transparent != ALPHABLEND_NONE);