iphlpapi: Correct copy/paste error in GetTcpTable.
[wine/wine-kai.git] / dlls / uxtheme / draw.c
blob003cf20ff10a65b0761488a2811f0b7edbd655d9
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 HRESULT hr;
57 TRACE("(%p,0x%08x\n", hwnd, dwFlags);
58 hr = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled),
59 (HANDLE)(dwFlags|0x80000000));
60 /* 0x80000000 serves as a "flags set" flag */
61 if (FAILED(hr))
62 return hr;
63 if (dwFlags & ETDT_USETABTEXTURE)
64 return SetWindowTheme (hwnd, NULL, szTab);
65 else
66 return SetWindowTheme (hwnd, NULL, NULL);
67 return S_OK;
70 /***********************************************************************
71 * IsThemeDialogTextureEnabled (UXTHEME.@)
73 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
75 DWORD dwDialogTextureFlags;
76 TRACE("(%p)\n", hwnd);
78 dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
79 (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled));
80 if (dwDialogTextureFlags == 0)
81 /* Means EnableThemeDialogTexture wasn't called for this dialog */
82 return TRUE;
84 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
87 /***********************************************************************
88 * DrawThemeParentBackground (UXTHEME.@)
90 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
92 RECT rt;
93 POINT org;
94 HWND hParent;
95 HRGN clip = NULL;
96 int hasClip = -1;
98 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
99 hParent = GetParent(hwnd);
100 if(!hParent)
101 hParent = hwnd;
102 if(prc) {
103 CopyRect(&rt, prc);
104 MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
106 clip = CreateRectRgn(0,0,1,1);
107 hasClip = GetClipRgn(hdc, clip);
108 if(hasClip == -1)
109 TRACE("Failed to get original clipping region\n");
110 else
111 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
113 else {
114 GetClientRect(hParent, &rt);
115 MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
118 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
120 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
121 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
123 SetViewportOrgEx(hdc, org.x, org.y, NULL);
124 if(prc) {
125 if(hasClip == 0)
126 SelectClipRgn(hdc, NULL);
127 else if(hasClip == 1)
128 SelectClipRgn(hdc, clip);
129 DeleteObject(clip);
131 return S_OK;
135 /***********************************************************************
136 * DrawThemeBackground (UXTHEME.@)
138 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
139 int iStateId, const RECT *pRect,
140 const RECT *pClipRect)
142 DTBGOPTS opts;
143 opts.dwSize = sizeof(DTBGOPTS);
144 opts.dwFlags = 0;
145 if(pClipRect) {
146 opts.dwFlags |= DTBG_CLIPRECT;
147 CopyRect(&opts.rcClip, pClipRect);
149 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
152 /***********************************************************************
153 * UXTHEME_SelectImage
155 * Select the image to use
157 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
159 PTHEME_PROPERTY tp;
160 int imageselecttype = IST_NONE;
161 int i;
162 int image;
163 if(glyph)
164 image = TMT_GLYPHIMAGEFILE;
165 else
166 image = TMT_IMAGEFILE;
168 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
169 return tp;
170 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
172 if(imageselecttype == IST_DPI) {
173 int reqdpi = 0;
174 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
175 for(i=4; i>=0; i--) {
176 reqdpi = 0;
177 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
178 if(reqdpi != 0 && screendpi >= reqdpi) {
179 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
180 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
184 /* If an image couldn't be selected, choose the first one */
185 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
187 else if(imageselecttype == IST_SIZE) {
188 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
189 POINT reqsize;
190 for(i=4; i>=0; i--) {
191 PTHEME_PROPERTY fileProp =
192 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
193 if (!fileProp) continue;
194 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
195 /* fall back to size of Nth image */
196 WCHAR szPath[MAX_PATH];
197 int imagelayout = IL_HORIZONTAL;
198 int imagecount = 1;
199 int imagenum;
200 BITMAP bmp;
201 HBITMAP hBmp;
202 BOOL hasAlpha;
204 lstrcpynW(szPath, fileProp->lpValue,
205 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
206 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
207 if(!hBmp) continue;
209 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
210 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
212 imagenum = max (min (imagecount, iStateId), 1) - 1;
213 GetObjectW(hBmp, sizeof(bmp), &bmp);
214 if(imagelayout == IL_VERTICAL) {
215 reqsize.x = bmp.bmWidth;
216 reqsize.y = bmp.bmHeight/imagecount;
218 else {
219 reqsize.x = bmp.bmWidth/imagecount;
220 reqsize.y = bmp.bmHeight;
223 if(reqsize.x <= size.x && reqsize.y <= size.y) {
224 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
225 return fileProp;
228 /* If an image couldn't be selected, choose the smallest one */
229 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
231 return NULL;
234 /***********************************************************************
235 * UXTHEME_LoadImage
237 * Load image for part/state
239 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
240 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
242 int imagelayout = IL_HORIZONTAL;
243 int imagecount = 1;
244 int imagenum;
245 BITMAP bmp;
246 WCHAR szPath[MAX_PATH];
247 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
248 if(!tp) {
249 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
250 return E_PROP_ID_UNSUPPORTED;
252 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
253 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
254 if(!*hBmp) {
255 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
256 return HRESULT_FROM_WIN32(GetLastError());
259 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
260 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
262 imagenum = max (min (imagecount, iStateId), 1) - 1;
263 GetObjectW(*hBmp, sizeof(bmp), &bmp);
264 if(imagelayout == IL_VERTICAL) {
265 int height = bmp.bmHeight/imagecount;
266 bmpRect->left = 0;
267 bmpRect->right = bmp.bmWidth;
268 bmpRect->top = imagenum * height;
269 bmpRect->bottom = bmpRect->top + height;
271 else {
272 int width = bmp.bmWidth/imagecount;
273 bmpRect->left = imagenum * width;
274 bmpRect->right = bmpRect->left + width;
275 bmpRect->top = 0;
276 bmpRect->bottom = bmp.bmHeight;
278 return S_OK;
281 /***********************************************************************
282 * UXTHEME_StretchBlt
284 * Pseudo TransparentBlt/StretchBlt
286 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
287 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
288 INT transparent, COLORREF transcolor)
290 static const BLENDFUNCTION blendFunc =
292 AC_SRC_OVER, /* BlendOp */
293 0, /* BlendFlag */
294 255, /* SourceConstantAlpha */
295 AC_SRC_ALPHA /* AlphaFormat */
297 if (transparent == ALPHABLEND_BINARY) {
298 /* Ensure we don't pass any negative values to TransparentBlt */
299 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
300 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
301 transcolor);
303 if ((transparent == ALPHABLEND_NONE) ||
304 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
305 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
306 blendFunc))
308 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
309 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
310 SRCCOPY);
312 return TRUE;
315 /***********************************************************************
316 * UXTHEME_Blt
318 * Simplify sending same width/height for both source and dest
320 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
321 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
322 INT transparent, COLORREF transcolor)
324 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
325 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
326 transparent, transcolor);
329 /***********************************************************************
330 * UXTHEME_SizedBlt
332 * Stretches or tiles, depending on sizingtype.
334 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
335 int nWidthDst, int nHeightDst,
336 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
337 int nWidthSrc, int nHeightSrc,
338 int sizingtype,
339 INT transparent, COLORREF transcolor)
341 if (sizingtype == ST_TILE)
343 int yOfs = nYOriginDst;
344 int yRemaining = nHeightDst;
345 while (yRemaining > 0)
347 int bltHeight = min (yRemaining, nHeightSrc);
348 int xOfs = nXOriginDst;
349 int xRemaining = nWidthDst;
350 while (xRemaining > 0)
352 int bltWidth = min (xRemaining, nWidthSrc);
353 if (!UXTHEME_Blt (hdcDst, xOfs, yOfs, bltWidth, bltHeight,
354 hdcSrc, nXOriginSrc, nYOriginSrc,
355 transparent, transcolor))
356 return FALSE;
357 xOfs += nWidthSrc;
358 xRemaining -= nWidthSrc;
360 yOfs += nHeightSrc;
361 yRemaining -= nHeightSrc;
363 return TRUE;
365 else
367 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
368 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
369 transparent, transcolor);
373 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
374 * depend on whether the image has full alpha or whether it is
375 * color-transparent or just opaque. */
376 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
377 BOOL hasImageAlpha, INT* transparent,
378 COLORREF* transparentcolor, BOOL glyph)
380 if (hasImageAlpha)
382 *transparent = ALPHABLEND_FULL;
383 *transparentcolor = RGB (255, 0, 255);
385 else
387 BOOL trans = FALSE;
388 GetThemeBool(hTheme, iPartId, iStateId,
389 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
390 if(trans) {
391 *transparent = ALPHABLEND_BINARY;
392 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
393 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
394 transparentcolor))) {
395 /* If image is transparent, but no color was specified, use magenta */
396 *transparentcolor = RGB(255, 0, 255);
399 else
400 *transparent = ALPHABLEND_NONE;
404 /***********************************************************************
405 * UXTHEME_DrawImageGlyph
407 * Draw an imagefile glyph
409 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
410 int iStateId, RECT *pRect,
411 const DTBGOPTS *pOptions)
413 HRESULT hr;
414 HBITMAP bmpSrc = NULL;
415 HDC hdcSrc = NULL;
416 HGDIOBJ oldSrc = NULL;
417 RECT rcSrc;
418 INT transparent = FALSE;
419 COLORREF transparentcolor;
420 int valign = VA_CENTER;
421 int halign = HA_CENTER;
422 POINT dstSize;
423 POINT srcSize;
424 POINT topleft;
425 BOOL hasAlpha;
427 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
428 &bmpSrc, &rcSrc, &hasAlpha);
429 if(FAILED(hr)) return hr;
430 hdcSrc = CreateCompatibleDC(hdc);
431 if(!hdcSrc) {
432 hr = HRESULT_FROM_WIN32(GetLastError());
433 return hr;
435 oldSrc = SelectObject(hdcSrc, bmpSrc);
437 dstSize.x = pRect->right-pRect->left;
438 dstSize.y = pRect->bottom-pRect->top;
439 srcSize.x = rcSrc.right-rcSrc.left;
440 srcSize.y = rcSrc.bottom-rcSrc.top;
442 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
443 &transparentcolor, TRUE);
444 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
445 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
447 topleft.x = pRect->left;
448 topleft.y = pRect->top;
449 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
450 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
451 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
452 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
454 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
455 hdcSrc, rcSrc.left, rcSrc.top,
456 transparent, transparentcolor)) {
457 hr = HRESULT_FROM_WIN32(GetLastError());
460 SelectObject(hdcSrc, oldSrc);
461 DeleteDC(hdcSrc);
462 return hr;
465 /***********************************************************************
466 * UXTHEME_DrawImageGlyph
468 * Draw glyph on top of background, if appropriate
470 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
471 int iStateId, RECT *pRect,
472 const DTBGOPTS *pOptions)
474 int glyphtype = GT_NONE;
476 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
478 if(glyphtype == GT_IMAGEGLYPH) {
479 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
481 else if(glyphtype == GT_FONTGLYPH) {
482 /* I don't know what a font glyph is, I've never seen it used in any themes */
483 FIXME("Font glyph\n");
485 return S_OK;
488 /***********************************************************************
489 * get_image_part_size
491 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
493 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
494 int iStateId, RECT *prc, THEMESIZE eSize,
495 POINT *psz)
497 HRESULT hr = S_OK;
498 HBITMAP bmpSrc;
499 RECT rcSrc;
500 BOOL hasAlpha;
502 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
503 &bmpSrc, &rcSrc, &hasAlpha);
504 if (FAILED(hr)) return hr;
506 switch (eSize)
508 case TS_DRAW:
509 if (prc != NULL)
511 RECT rcDst;
512 POINT dstSize;
513 POINT srcSize;
514 int sizingtype = ST_STRETCH;
515 BOOL uniformsizing = FALSE;
517 CopyRect(&rcDst, prc);
519 dstSize.x = rcDst.right-rcDst.left;
520 dstSize.y = rcDst.bottom-rcDst.top;
521 srcSize.x = rcSrc.right-rcSrc.left;
522 srcSize.y = rcSrc.bottom-rcSrc.top;
524 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
525 if(uniformsizing) {
526 /* Scale height and width equally */
527 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
529 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
530 rcDst.bottom = rcDst.top + dstSize.y;
532 else
534 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
535 rcDst.right = rcDst.left + dstSize.x;
539 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
540 if(sizingtype == ST_TRUESIZE) {
541 int truesizestretchmark = 100;
543 if(dstSize.x < 0 || dstSize.y < 0) {
544 BOOL mirrorimage = TRUE;
545 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
546 if(mirrorimage) {
547 if(dstSize.x < 0) {
548 rcDst.left += dstSize.x;
549 rcDst.right += dstSize.x;
551 if(dstSize.y < 0) {
552 rcDst.top += dstSize.y;
553 rcDst.bottom += dstSize.y;
557 /* Whatever TrueSizeStretchMark does - it does not seem to
558 * be what's outlined below. It appears as if native
559 * uxtheme always stretches if dest is smaller than source
560 * (ie as if TrueSizeStretchMark==100 with the code below) */
561 #if 0
562 /* Only stretch when target exceeds source by truesizestretchmark percent */
563 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
564 #endif
565 if(dstSize.x < 0 || dstSize.y < 0 ||
566 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
567 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
568 memcpy (psz, &dstSize, sizeof (SIZE));
570 else {
571 memcpy (psz, &srcSize, sizeof (SIZE));
574 else
576 psz->x = abs(dstSize.x);
577 psz->y = abs(dstSize.y);
579 break;
581 /* else fall through */
582 case TS_MIN:
583 /* FIXME: couldn't figure how native uxtheme computes min size */
584 case TS_TRUE:
585 psz->x = rcSrc.right - rcSrc.left;
586 psz->y = rcSrc.bottom - rcSrc.top;
587 break;
589 return hr;
592 /***********************************************************************
593 * UXTHEME_DrawImageBackground
595 * Draw an imagefile background
597 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
598 int iStateId, RECT *pRect,
599 const DTBGOPTS *pOptions)
601 HRESULT hr = S_OK;
602 HBITMAP bmpSrc;
603 HGDIOBJ oldSrc;
604 HDC hdcSrc;
605 RECT rcSrc;
606 RECT rcDst;
607 POINT dstSize;
608 POINT srcSize;
609 POINT drawSize;
610 int sizingtype = ST_STRETCH;
611 INT transparent;
612 COLORREF transparentcolor = 0;
613 BOOL hasAlpha;
615 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
616 &bmpSrc, &rcSrc, &hasAlpha);
617 if(FAILED(hr)) return hr;
618 hdcSrc = CreateCompatibleDC(hdc);
619 if(!hdcSrc) {
620 hr = HRESULT_FROM_WIN32(GetLastError());
621 return hr;
623 oldSrc = SelectObject(hdcSrc, bmpSrc);
625 CopyRect(&rcDst, pRect);
627 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
628 &transparentcolor, FALSE);
630 dstSize.x = rcDst.right-rcDst.left;
631 dstSize.y = rcDst.bottom-rcDst.top;
632 srcSize.x = rcSrc.right-rcSrc.left;
633 srcSize.y = rcSrc.bottom-rcSrc.top;
635 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
636 if(sizingtype == ST_TRUESIZE) {
637 int valign = VA_CENTER, halign = HA_CENTER;
639 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
640 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
641 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
643 if (halign == HA_CENTER)
644 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
645 else if (halign == HA_RIGHT)
646 rcDst.left = rcDst.right - drawSize.x;
647 if (valign == VA_CENTER)
648 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
649 else if (valign == VA_BOTTOM)
650 rcDst.top = rcDst.bottom - drawSize.y;
651 rcDst.right = rcDst.left + drawSize.x;
652 rcDst.bottom = rcDst.top + drawSize.y;
653 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
654 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
655 transparent, transparentcolor))
656 hr = HRESULT_FROM_WIN32(GetLastError());
658 else {
659 HDC hdcDst = NULL;
660 MARGINS sm;
661 POINT org;
663 dstSize.x = abs(dstSize.x);
664 dstSize.y = abs(dstSize.y);
666 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
668 hdcDst = hdc;
669 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
671 /* Upper left corner */
672 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
673 hdcSrc, rcSrc.left, rcSrc.top,
674 transparent, transparentcolor)) {
675 hr = HRESULT_FROM_WIN32(GetLastError());
676 goto draw_error;
678 /* Upper right corner */
679 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
680 sm.cxRightWidth, sm.cyTopHeight,
681 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
682 transparent, transparentcolor)) {
683 hr = HRESULT_FROM_WIN32(GetLastError());
684 goto draw_error;
686 /* Lower left corner */
687 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
688 sm.cxLeftWidth, sm.cyBottomHeight,
689 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
690 transparent, transparentcolor)) {
691 hr = HRESULT_FROM_WIN32(GetLastError());
692 goto draw_error;
694 /* Lower right corner */
695 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
696 sm.cxRightWidth, sm.cyBottomHeight,
697 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
698 transparent, transparentcolor)) {
699 hr = HRESULT_FROM_WIN32(GetLastError());
700 goto draw_error;
703 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
704 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
705 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
706 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
707 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
709 if(destCenterWidth > 0) {
710 /* Center top */
711 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
712 destCenterWidth, sm.cyTopHeight,
713 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
714 srcCenterWidth, sm.cyTopHeight,
715 sizingtype, transparent, transparentcolor)) {
716 hr = HRESULT_FROM_WIN32(GetLastError());
717 goto draw_error;
719 /* Center bottom */
720 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
721 destCenterWidth, sm.cyBottomHeight,
722 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
723 srcCenterWidth, sm.cyBottomHeight,
724 sizingtype, transparent, transparentcolor)) {
725 hr = HRESULT_FROM_WIN32(GetLastError());
726 goto draw_error;
729 if(destCenterHeight > 0) {
730 /* Left center */
731 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
732 sm.cxLeftWidth, destCenterHeight,
733 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
734 sm.cxLeftWidth, srcCenterHeight,
735 sizingtype,
736 transparent, transparentcolor)) {
737 hr = HRESULT_FROM_WIN32(GetLastError());
738 goto draw_error;
740 /* Right center */
741 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
742 sm.cxRightWidth, destCenterHeight,
743 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
744 sm.cxRightWidth, srcCenterHeight,
745 sizingtype, transparent, transparentcolor)) {
746 hr = HRESULT_FROM_WIN32(GetLastError());
747 goto draw_error;
750 if(destCenterHeight > 0 && destCenterWidth > 0) {
751 BOOL borderonly = FALSE;
752 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
753 if(!borderonly) {
754 /* Center */
755 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
756 destCenterWidth, destCenterHeight,
757 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
758 srcCenterWidth, srcCenterHeight,
759 sizingtype, transparent, transparentcolor)) {
760 hr = HRESULT_FROM_WIN32(GetLastError());
761 goto draw_error;
767 draw_error:
768 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
770 SelectObject(hdcSrc, oldSrc);
771 DeleteDC(hdcSrc);
772 CopyRect(pRect, &rcDst);
773 return hr;
776 /***********************************************************************
777 * UXTHEME_DrawBorderRectangle
779 * Draw the bounding rectangle for a borderfill background
781 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
782 int iStateId, RECT *pRect,
783 const DTBGOPTS *pOptions)
785 HRESULT hr = S_OK;
786 HPEN hPen;
787 HGDIOBJ oldPen;
788 COLORREF bordercolor = RGB(0,0,0);
789 int bordersize = 1;
791 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
792 if(bordersize > 0) {
793 POINT ptCorners[5];
794 ptCorners[0].x = pRect->left;
795 ptCorners[0].y = pRect->top;
796 ptCorners[1].x = pRect->right-1;
797 ptCorners[1].y = pRect->top;
798 ptCorners[2].x = pRect->right-1;
799 ptCorners[2].y = pRect->bottom-1;
800 ptCorners[3].x = pRect->left;
801 ptCorners[3].y = pRect->bottom-1;
802 ptCorners[4].x = pRect->left;
803 ptCorners[4].y = pRect->top;
805 InflateRect(pRect, -bordersize, -bordersize);
806 if(pOptions->dwFlags & DTBG_OMITBORDER)
807 return S_OK;
808 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
809 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
810 if(!hPen)
811 return HRESULT_FROM_WIN32(GetLastError());
812 oldPen = SelectObject(hdc, hPen);
814 if(!Polyline(hdc, ptCorners, 5))
815 hr = HRESULT_FROM_WIN32(GetLastError());
817 SelectObject(hdc, oldPen);
818 DeleteObject(hPen);
820 return hr;
823 /***********************************************************************
824 * UXTHEME_DrawBackgroundFill
826 * Fill a borderfill background rectangle
828 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
829 int iStateId, RECT *pRect,
830 const DTBGOPTS *pOptions)
832 HRESULT hr = S_OK;
833 int filltype = FT_SOLID;
835 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
837 if(pOptions->dwFlags & DTBG_OMITCONTENT)
838 return S_OK;
840 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
842 if(filltype == FT_SOLID) {
843 HBRUSH hBrush;
844 COLORREF fillcolor = RGB(255,255,255);
846 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
847 hBrush = CreateSolidBrush(fillcolor);
848 if(!FillRect(hdc, pRect, hBrush))
849 hr = HRESULT_FROM_WIN32(GetLastError());
850 DeleteObject(hBrush);
852 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
853 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
854 the gradient ratios (no idea how those work)
855 Few themes use this, and the ones I've seen only use 2 colors with
856 a gradient ratio of 0 and 255 respectivly
859 COLORREF gradient1 = RGB(0,0,0);
860 COLORREF gradient2 = RGB(255,255,255);
861 TRIVERTEX vert[2];
862 GRADIENT_RECT gRect;
864 FIXME("Gradient implementation not complete\n");
866 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
867 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
869 vert[0].x = pRect->left;
870 vert[0].y = pRect->top;
871 vert[0].Red = GetRValue(gradient1) << 8;
872 vert[0].Green = GetGValue(gradient1) << 8;
873 vert[0].Blue = GetBValue(gradient1) << 8;
874 vert[0].Alpha = 0x0000;
876 vert[1].x = pRect->right;
877 vert[1].y = pRect->bottom;
878 vert[1].Red = GetRValue(gradient2) << 8;
879 vert[1].Green = GetGValue(gradient2) << 8;
880 vert[1].Blue = GetBValue(gradient2) << 8;
881 vert[1].Alpha = 0x0000;
883 gRect.UpperLeft = 0;
884 gRect.LowerRight = 1;
885 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
887 else if(filltype == FT_RADIALGRADIENT) {
888 /* I've never seen this used in a theme */
889 FIXME("Radial gradient\n");
891 else if(filltype == FT_TILEIMAGE) {
892 /* I've never seen this used in a theme */
893 FIXME("Tile image\n");
895 return hr;
898 /***********************************************************************
899 * UXTHEME_DrawBorderBackground
901 * Draw an imagefile background
903 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
904 int iStateId, const RECT *pRect,
905 const DTBGOPTS *pOptions)
907 HRESULT hr;
908 RECT rt;
910 CopyRect(&rt, pRect);
912 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
913 if(FAILED(hr))
914 return hr;
915 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
918 /***********************************************************************
919 * DrawThemeBackgroundEx (UXTHEME.@)
921 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
922 int iStateId, const RECT *pRect,
923 const DTBGOPTS *pOptions)
925 HRESULT hr;
926 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
927 const DTBGOPTS *opts;
928 HRGN clip = NULL;
929 int hasClip = -1;
930 int bgtype = BT_BORDERFILL;
931 RECT rt;
933 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
934 if(!hTheme)
935 return E_HANDLE;
937 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
938 if (bgtype == BT_NONE) return S_OK;
940 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
941 opts = pOptions;
942 if(!opts) opts = &defaultOpts;
944 if(opts->dwFlags & DTBG_CLIPRECT) {
945 clip = CreateRectRgn(0,0,1,1);
946 hasClip = GetClipRgn(hdc, clip);
947 if(hasClip == -1)
948 TRACE("Failed to get original clipping region\n");
949 else
950 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
952 CopyRect(&rt, pRect);
954 if(bgtype == BT_IMAGEFILE)
955 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
956 else if(bgtype == BT_BORDERFILL)
957 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
958 else {
959 FIXME("Unknown background type\n");
960 /* This should never happen, and hence I don't know what to return */
961 hr = E_FAIL;
963 if(SUCCEEDED(hr))
964 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
965 if(opts->dwFlags & DTBG_CLIPRECT) {
966 if(hasClip == 0)
967 SelectClipRgn(hdc, NULL);
968 else if(hasClip == 1)
969 SelectClipRgn(hdc, clip);
970 DeleteObject(clip);
972 return hr;
976 * DrawThemeEdge() implementation
978 * Since it basically is DrawEdge() with different colors, I copied its code
979 * from user32's uitools.c.
982 enum
984 EDGE_LIGHT,
985 EDGE_HIGHLIGHT,
986 EDGE_SHADOW,
987 EDGE_DARKSHADOW,
988 EDGE_FILL,
990 EDGE_WINDOW,
991 EDGE_WINDOWFRAME,
993 EDGE_NUMCOLORS
996 static const struct
998 int themeProp;
999 int sysColor;
1000 } EdgeColorMap[EDGE_NUMCOLORS] = {
1001 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1002 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1003 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1004 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1005 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1006 {-1, COLOR_WINDOW},
1007 {-1, COLOR_WINDOWFRAME}
1010 static const signed char LTInnerNormal[] = {
1011 -1, -1, -1, -1,
1012 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1013 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1014 -1, -1, -1, -1
1017 static const signed char LTOuterNormal[] = {
1018 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1019 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1020 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1021 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1024 static const signed char RBInnerNormal[] = {
1025 -1, -1, -1, -1,
1026 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1027 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1028 -1, -1, -1, -1
1031 static const signed char RBOuterNormal[] = {
1032 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1033 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1034 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1035 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1038 static const signed char LTInnerSoft[] = {
1039 -1, -1, -1, -1,
1040 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1041 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1042 -1, -1, -1, -1
1045 static const signed char LTOuterSoft[] = {
1046 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1047 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1048 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1049 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1052 #define RBInnerSoft RBInnerNormal /* These are the same */
1053 #define RBOuterSoft RBOuterNormal
1055 static const signed char LTRBOuterMono[] = {
1056 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1057 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1058 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1059 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1062 static const signed char LTRBInnerMono[] = {
1063 -1, -1, -1, -1,
1064 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1065 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1066 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1069 static const signed char LTRBOuterFlat[] = {
1070 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1071 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1072 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1073 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1076 static const signed char LTRBInnerFlat[] = {
1077 -1, -1, -1, -1,
1078 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1079 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1080 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1083 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1085 COLORREF col;
1086 if ((EdgeColorMap[edgeType].themeProp == -1)
1087 || FAILED (GetThemeColor (theme, part, state,
1088 EdgeColorMap[edgeType].themeProp, &col)))
1089 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1090 return col;
1093 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1095 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1098 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1100 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1103 /***********************************************************************
1104 * draw_diag_edge
1106 * Same as DrawEdge invoked with BF_DIAGONAL
1108 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1109 const RECT* rc, UINT uType,
1110 UINT uFlags, LPRECT contentsRect)
1112 POINT Points[4];
1113 signed char InnerI, OuterI;
1114 HPEN InnerPen, OuterPen;
1115 POINT SavePoint;
1116 HPEN SavePen;
1117 int spx, spy;
1118 int epx, epy;
1119 int Width = rc->right - rc->left;
1120 int Height= rc->bottom - rc->top;
1121 int SmallDiam = Width > Height ? Height : Width;
1122 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1123 || (uType & BDR_OUTER) == BDR_OUTER)
1124 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1125 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1126 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1128 /* Init some vars */
1129 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1130 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1131 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1133 /* Determine the colors of the edges */
1134 if(uFlags & BF_MONO)
1136 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1137 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1139 else if(uFlags & BF_FLAT)
1141 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1142 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1144 else if(uFlags & BF_SOFT)
1146 if(uFlags & BF_BOTTOM)
1148 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1149 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1151 else
1153 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1154 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1157 else
1159 if(uFlags & BF_BOTTOM)
1161 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1162 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1164 else
1166 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1167 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1171 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1172 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1174 MoveToEx(hdc, 0, 0, &SavePoint);
1176 /* Don't ask me why, but this is what is visible... */
1177 /* This must be possible to do much simpler, but I fail to */
1178 /* see the logic in the MS implementation (sigh...). */
1179 /* So, this might look a bit brute force here (and it is), but */
1180 /* it gets the job done;) */
1182 switch(uFlags & BF_RECT)
1184 case 0:
1185 case BF_LEFT:
1186 case BF_BOTTOM:
1187 case BF_BOTTOMLEFT:
1188 /* Left bottom endpoint */
1189 epx = rc->left-1;
1190 spx = epx + SmallDiam;
1191 epy = rc->bottom;
1192 spy = epy - SmallDiam;
1193 break;
1195 case BF_TOPLEFT:
1196 case BF_BOTTOMRIGHT:
1197 /* Left top endpoint */
1198 epx = rc->left-1;
1199 spx = epx + SmallDiam;
1200 epy = rc->top-1;
1201 spy = epy + SmallDiam;
1202 break;
1204 case BF_TOP:
1205 case BF_RIGHT:
1206 case BF_TOPRIGHT:
1207 case BF_RIGHT|BF_LEFT:
1208 case BF_RIGHT|BF_LEFT|BF_TOP:
1209 case BF_BOTTOM|BF_TOP:
1210 case BF_BOTTOM|BF_TOP|BF_LEFT:
1211 case BF_BOTTOMRIGHT|BF_LEFT:
1212 case BF_BOTTOMRIGHT|BF_TOP:
1213 case BF_RECT:
1214 /* Right top endpoint */
1215 spx = rc->left;
1216 epx = spx + SmallDiam;
1217 spy = rc->bottom-1;
1218 epy = spy - SmallDiam;
1219 break;
1222 MoveToEx(hdc, spx, spy, NULL);
1223 SelectObject(hdc, OuterPen);
1224 LineTo(hdc, epx, epy);
1226 SelectObject(hdc, InnerPen);
1228 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1230 case BF_DIAGONAL_ENDBOTTOMLEFT:
1231 case (BF_DIAGONAL|BF_BOTTOM):
1232 case BF_DIAGONAL:
1233 case (BF_DIAGONAL|BF_LEFT):
1234 MoveToEx(hdc, spx-1, spy, NULL);
1235 LineTo(hdc, epx, epy-1);
1236 Points[0].x = spx-add;
1237 Points[0].y = spy;
1238 Points[1].x = rc->left;
1239 Points[1].y = rc->top;
1240 Points[2].x = epx+1;
1241 Points[2].y = epy-1-add;
1242 Points[3] = Points[2];
1243 break;
1245 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1246 MoveToEx(hdc, spx-1, spy, NULL);
1247 LineTo(hdc, epx, epy+1);
1248 Points[0].x = spx-add;
1249 Points[0].y = spy;
1250 Points[1].x = rc->left;
1251 Points[1].y = rc->bottom-1;
1252 Points[2].x = epx+1;
1253 Points[2].y = epy+1+add;
1254 Points[3] = Points[2];
1255 break;
1257 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1258 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1259 case BF_DIAGONAL_ENDTOPRIGHT:
1260 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1261 MoveToEx(hdc, spx+1, spy, NULL);
1262 LineTo(hdc, epx, epy+1);
1263 Points[0].x = epx-1;
1264 Points[0].y = epy+1+add;
1265 Points[1].x = rc->right-1;
1266 Points[1].y = rc->top+add;
1267 Points[2].x = rc->right-1;
1268 Points[2].y = rc->bottom-1;
1269 Points[3].x = spx+add;
1270 Points[3].y = spy;
1271 break;
1273 case BF_DIAGONAL_ENDTOPLEFT:
1274 MoveToEx(hdc, spx, spy-1, NULL);
1275 LineTo(hdc, epx+1, epy);
1276 Points[0].x = epx+1+add;
1277 Points[0].y = epy+1;
1278 Points[1].x = rc->right-1;
1279 Points[1].y = rc->top;
1280 Points[2].x = rc->right-1;
1281 Points[2].y = rc->bottom-1-add;
1282 Points[3].x = spx;
1283 Points[3].y = spy-add;
1284 break;
1286 case (BF_DIAGONAL|BF_TOP):
1287 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1288 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1289 MoveToEx(hdc, spx+1, spy-1, NULL);
1290 LineTo(hdc, epx, epy);
1291 Points[0].x = epx-1;
1292 Points[0].y = epy+1;
1293 Points[1].x = rc->right-1;
1294 Points[1].y = rc->top;
1295 Points[2].x = rc->right-1;
1296 Points[2].y = rc->bottom-1-add;
1297 Points[3].x = spx+add;
1298 Points[3].y = spy-add;
1299 break;
1301 case (BF_DIAGONAL|BF_RIGHT):
1302 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1303 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1304 MoveToEx(hdc, spx, spy, NULL);
1305 LineTo(hdc, epx-1, epy+1);
1306 Points[0].x = spx;
1307 Points[0].y = spy;
1308 Points[1].x = rc->left;
1309 Points[1].y = rc->top+add;
1310 Points[2].x = epx-1-add;
1311 Points[2].y = epy+1+add;
1312 Points[3] = Points[2];
1313 break;
1316 /* Fill the interior if asked */
1317 if((uFlags & BF_MIDDLE) && retval)
1319 HBRUSH hbsave;
1320 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1321 theme, part, state);
1322 HPEN hpsave;
1323 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1324 theme, part, state);
1325 hbsave = (HBRUSH)SelectObject(hdc, hb);
1326 hpsave = (HPEN)SelectObject(hdc, hp);
1327 Polygon(hdc, Points, 4);
1328 SelectObject(hdc, hbsave);
1329 SelectObject(hdc, hpsave);
1330 DeleteObject (hp);
1331 DeleteObject (hb);
1334 /* Adjust rectangle if asked */
1335 if(uFlags & BF_ADJUST)
1337 *contentsRect = *rc;
1338 if(uFlags & BF_LEFT) contentsRect->left += add;
1339 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1340 if(uFlags & BF_TOP) contentsRect->top += add;
1341 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1344 /* Cleanup */
1345 SelectObject(hdc, SavePen);
1346 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1347 if(InnerI != -1) DeleteObject (InnerPen);
1348 if(OuterI != -1) DeleteObject (OuterPen);
1350 return retval;
1353 /***********************************************************************
1354 * draw_rect_edge
1356 * Same as DrawEdge invoked without BF_DIAGONAL
1358 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1359 const RECT* rc, UINT uType,
1360 UINT uFlags, LPRECT contentsRect)
1362 signed char LTInnerI, LTOuterI;
1363 signed char RBInnerI, RBOuterI;
1364 HPEN LTInnerPen, LTOuterPen;
1365 HPEN RBInnerPen, RBOuterPen;
1366 RECT InnerRect = *rc;
1367 POINT SavePoint;
1368 HPEN SavePen;
1369 int LBpenplus = 0;
1370 int LTpenplus = 0;
1371 int RTpenplus = 0;
1372 int RBpenplus = 0;
1373 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1374 || (uType & BDR_OUTER) == BDR_OUTER)
1375 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1377 /* Init some vars */
1378 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1379 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1381 /* Determine the colors of the edges */
1382 if(uFlags & BF_MONO)
1384 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1385 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1387 else if(uFlags & BF_FLAT)
1389 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1390 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1392 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1394 else if(uFlags & BF_SOFT)
1396 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1397 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1398 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1399 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1401 else
1403 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1404 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1405 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1406 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1409 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1410 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1411 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1412 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1414 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1415 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1416 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1417 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1419 MoveToEx(hdc, 0, 0, &SavePoint);
1421 /* Draw the outer edge */
1422 SelectObject(hdc, LTOuterPen);
1423 if(uFlags & BF_TOP)
1425 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1426 LineTo(hdc, InnerRect.right, InnerRect.top);
1428 if(uFlags & BF_LEFT)
1430 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1431 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1433 SelectObject(hdc, RBOuterPen);
1434 if(uFlags & BF_BOTTOM)
1436 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1437 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1439 if(uFlags & BF_RIGHT)
1441 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1442 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1445 /* Draw the inner edge */
1446 SelectObject(hdc, LTInnerPen);
1447 if(uFlags & BF_TOP)
1449 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1450 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1452 if(uFlags & BF_LEFT)
1454 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1455 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1457 SelectObject(hdc, RBInnerPen);
1458 if(uFlags & BF_BOTTOM)
1460 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1461 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1463 if(uFlags & BF_RIGHT)
1465 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1466 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1469 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1471 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1472 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1474 if(uFlags & BF_LEFT) InnerRect.left += add;
1475 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1476 if(uFlags & BF_TOP) InnerRect.top += add;
1477 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1479 if((uFlags & BF_MIDDLE) && retval)
1481 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1482 theme, part, state);
1483 FillRect(hdc, &InnerRect, br);
1484 DeleteObject (br);
1487 if(uFlags & BF_ADJUST)
1488 *contentsRect = InnerRect;
1491 /* Cleanup */
1492 SelectObject(hdc, SavePen);
1493 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1494 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1495 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1496 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1497 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1498 return retval;
1502 /***********************************************************************
1503 * DrawThemeEdge (UXTHEME.@)
1505 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1506 * difference is that it does not rely on the system colors alone, but
1507 * also allows color specification in the theme.
1509 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1510 int iStateId, const RECT *pDestRect, UINT uEdge,
1511 UINT uFlags, RECT *pContentRect)
1513 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1514 if(!hTheme)
1515 return E_HANDLE;
1517 if(uFlags & BF_DIAGONAL)
1518 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1519 uEdge, uFlags, pContentRect);
1520 else
1521 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1522 uEdge, uFlags, pContentRect);
1526 /***********************************************************************
1527 * DrawThemeIcon (UXTHEME.@)
1529 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1530 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1532 FIXME("%d %d: stub\n", iPartId, iStateId);
1533 if(!hTheme)
1534 return E_HANDLE;
1535 return ERROR_CALL_NOT_IMPLEMENTED;
1538 /***********************************************************************
1539 * DrawThemeText (UXTHEME.@)
1541 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1542 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1543 DWORD dwTextFlags2, const RECT *pRect)
1545 HRESULT hr;
1546 HFONT hFont = NULL;
1547 HGDIOBJ oldFont = NULL;
1548 LOGFONTW logfont;
1549 COLORREF textColor;
1550 COLORREF oldTextColor;
1551 int oldBkMode;
1552 RECT rt;
1554 TRACE("%d %d: stub\n", iPartId, iStateId);
1555 if(!hTheme)
1556 return E_HANDLE;
1558 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1559 if(SUCCEEDED(hr)) {
1560 hFont = CreateFontIndirectW(&logfont);
1561 if(!hFont)
1562 TRACE("Failed to create font\n");
1564 CopyRect(&rt, pRect);
1565 if(hFont)
1566 oldFont = SelectObject(hdc, hFont);
1568 if(dwTextFlags2 & DTT_GRAYED)
1569 textColor = GetSysColor(COLOR_GRAYTEXT);
1570 else {
1571 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1572 textColor = GetTextColor(hdc);
1574 oldTextColor = SetTextColor(hdc, textColor);
1575 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1576 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1577 SetBkMode(hdc, oldBkMode);
1578 SetTextColor(hdc, oldTextColor);
1580 if(hFont) {
1581 SelectObject(hdc, oldFont);
1582 DeleteObject(hFont);
1584 return S_OK;
1587 /***********************************************************************
1588 * GetThemeBackgroundContentRect (UXTHEME.@)
1590 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1591 int iStateId,
1592 const RECT *pBoundingRect,
1593 RECT *pContentRect)
1595 MARGINS margin;
1596 HRESULT hr;
1598 TRACE("(%d,%d)\n", iPartId, iStateId);
1599 if(!hTheme)
1600 return E_HANDLE;
1602 /* try content margins property... */
1603 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1604 if(SUCCEEDED(hr)) {
1605 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1606 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1607 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1608 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1609 } else {
1610 /* otherwise, try to determine content rect from the background type and props */
1611 int bgtype = BT_BORDERFILL;
1612 memcpy(pContentRect, pBoundingRect, sizeof(RECT));
1614 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1615 if(bgtype == BT_BORDERFILL) {
1616 int bordersize = 1;
1618 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1619 InflateRect(pContentRect, -bordersize, -bordersize);
1620 } else if ((bgtype == BT_IMAGEFILE)
1621 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1622 TMT_SIZINGMARGINS, NULL, &margin)))) {
1623 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1624 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1625 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1626 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1628 /* If nothing was found, leave unchanged */
1631 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1633 return S_OK;
1636 /***********************************************************************
1637 * GetThemeBackgroundExtent (UXTHEME.@)
1639 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1640 int iStateId, const RECT *pContentRect,
1641 RECT *pExtentRect)
1643 MARGINS margin;
1644 HRESULT hr;
1646 TRACE("(%d,%d)\n", iPartId, iStateId);
1647 if(!hTheme)
1648 return E_HANDLE;
1650 /* try content margins property... */
1651 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1652 if(SUCCEEDED(hr)) {
1653 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1654 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1655 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1656 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1657 } else {
1658 /* otherwise, try to determine content rect from the background type and props */
1659 int bgtype = BT_BORDERFILL;
1660 memcpy(pExtentRect, pContentRect, sizeof(RECT));
1662 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1663 if(bgtype == BT_BORDERFILL) {
1664 int bordersize = 1;
1666 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1667 InflateRect(pExtentRect, bordersize, bordersize);
1668 } else if ((bgtype == BT_IMAGEFILE)
1669 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1670 TMT_SIZINGMARGINS, NULL, &margin)))) {
1671 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1672 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1673 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1674 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1676 /* If nothing was found, leave unchanged */
1679 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1681 return S_OK;
1684 /***********************************************************************
1685 * GetThemeBackgroundRegion (UXTHEME.@)
1687 * Calculate the background region, taking into consideration transparent areas
1688 * of the background image.
1690 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1691 int iStateId, const RECT *pRect,
1692 HRGN *pRegion)
1694 HRESULT hr = S_OK;
1695 int bgtype = BT_BORDERFILL;
1697 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1698 if(!hTheme)
1699 return E_HANDLE;
1700 if(!pRect || !pRegion)
1701 return E_POINTER;
1703 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1704 if(bgtype == BT_IMAGEFILE) {
1705 FIXME("Images not handled yet\n");
1706 hr = ERROR_CALL_NOT_IMPLEMENTED;
1708 else if(bgtype == BT_BORDERFILL) {
1709 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1710 if(!*pRegion)
1711 hr = HRESULT_FROM_WIN32(GetLastError());
1713 else {
1714 FIXME("Unknown background type\n");
1715 /* This should never happen, and hence I don't know what to return */
1716 hr = E_FAIL;
1718 return hr;
1721 /* compute part size for "borderfill" backgrounds */
1722 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1723 int iStateId, THEMESIZE eSize, POINT* psz)
1725 HRESULT hr = S_OK;
1726 int bordersize = 1;
1728 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1729 &bordersize)))
1731 psz->x = psz->y = 2*bordersize;
1732 if (eSize != TS_MIN)
1734 psz->x++;
1735 psz->y++;
1738 return hr;
1741 /***********************************************************************
1742 * GetThemePartSize (UXTHEME.@)
1744 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1745 int iStateId, RECT *prc, THEMESIZE eSize,
1746 SIZE *psz)
1748 int bgtype = BT_BORDERFILL;
1749 HRESULT hr = S_OK;
1750 POINT size = {1, 1};
1752 if(!hTheme)
1753 return E_HANDLE;
1755 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1756 if (bgtype == BT_NONE)
1757 /* do nothing */;
1758 else if(bgtype == BT_IMAGEFILE)
1759 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1760 else if(bgtype == BT_BORDERFILL)
1761 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1762 else {
1763 FIXME("Unknown background type\n");
1764 /* This should never happen, and hence I don't know what to return */
1765 hr = E_FAIL;
1767 psz->cx = size.x;
1768 psz->cy = size.y;
1769 return hr;
1773 /***********************************************************************
1774 * GetThemeTextExtent (UXTHEME.@)
1776 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1777 int iStateId, LPCWSTR pszText, int iCharCount,
1778 DWORD dwTextFlags, const RECT *pBoundingRect,
1779 RECT *pExtentRect)
1781 HRESULT hr;
1782 HFONT hFont = NULL;
1783 HGDIOBJ oldFont = NULL;
1784 LOGFONTW logfont;
1785 RECT rt = {0,0,0xFFFF,0xFFFF};
1787 TRACE("%d %d: stub\n", iPartId, iStateId);
1788 if(!hTheme)
1789 return E_HANDLE;
1791 if(pBoundingRect)
1792 CopyRect(&rt, pBoundingRect);
1794 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1795 if(SUCCEEDED(hr)) {
1796 hFont = CreateFontIndirectW(&logfont);
1797 if(!hFont)
1798 TRACE("Failed to create font\n");
1800 if(hFont)
1801 oldFont = SelectObject(hdc, hFont);
1803 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1804 CopyRect(pExtentRect, &rt);
1806 if(hFont) {
1807 SelectObject(hdc, oldFont);
1808 DeleteObject(hFont);
1810 return S_OK;
1813 /***********************************************************************
1814 * GetThemeTextMetrics (UXTHEME.@)
1816 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1817 int iStateId, TEXTMETRICW *ptm)
1819 HRESULT hr;
1820 HFONT hFont = NULL;
1821 HGDIOBJ oldFont = NULL;
1822 LOGFONTW logfont;
1824 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1825 if(!hTheme)
1826 return E_HANDLE;
1828 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1829 if(SUCCEEDED(hr)) {
1830 hFont = CreateFontIndirectW(&logfont);
1831 if(!hFont)
1832 TRACE("Failed to create font\n");
1834 if(hFont)
1835 oldFont = SelectObject(hdc, hFont);
1837 if(!GetTextMetricsW(hdc, ptm))
1838 hr = HRESULT_FROM_WIN32(GetLastError());
1840 if(hFont) {
1841 SelectObject(hdc, oldFont);
1842 DeleteObject(hFont);
1844 return hr;
1847 /***********************************************************************
1848 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1850 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1851 int iStateId)
1853 int bgtype = BT_BORDERFILL;
1854 RECT rect = {0, 0, 0, 0};
1855 HBITMAP bmpSrc;
1856 RECT rcSrc;
1857 BOOL hasAlpha;
1858 INT transparent;
1859 COLORREF transparentcolor;
1861 TRACE("(%d,%d)\n", iPartId, iStateId);
1863 if(!hTheme)
1864 return FALSE;
1866 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1868 if (bgtype != BT_IMAGEFILE) return FALSE;
1870 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1871 &bmpSrc, &rcSrc, &hasAlpha)))
1872 return FALSE;
1874 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1875 &transparentcolor, FALSE);
1876 return (transparent != ALPHABLEND_NONE);