Spelling fixes.
[wine/gsoc_dplay.git] / dlls / uxtheme / draw.c
blob493cf0bd9ec4f8b536555b10698acd092664e17a
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 HDC hdcTemp;
344 BOOL result = FALSE;
346 /* Create a DC with a bitmap consisting of a tiling of the source
347 bitmap, with standard GDI functions. This is faster than an
348 iteration with UXTHEME_Blt(). */
349 hdcTemp = CreateCompatibleDC(hdcSrc);
350 if (hdcTemp != 0)
352 HBITMAP bitmapTemp;
353 HBITMAP bitmapOrig;
354 int nWidthTemp, nHeightTemp;
355 int xOfs, xRemaining;
356 int yOfs, yRemaining;
357 int growSize;
359 /* Calculate temp dimensions of integer multiples of source dimensions */
360 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
361 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
362 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
363 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
365 /* Initial copy of bitmap */
366 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
368 /* Extend bitmap in the X direction. Growth of width is exponential */
369 xOfs = nWidthSrc;
370 xRemaining = nWidthTemp - nWidthSrc;
371 growSize = nWidthSrc;
372 while (xRemaining > 0)
374 growSize = min(growSize, xRemaining);
375 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
376 xOfs += growSize;
377 xRemaining -= growSize;
378 growSize *= 2;
381 /* Extend bitmap in the Y direction. Growth of height is exponential */
382 yOfs = nHeightSrc;
383 yRemaining = nHeightTemp - nHeightSrc;
384 growSize = nHeightSrc;
385 while (yRemaining > 0)
387 growSize = min(growSize, yRemaining);
388 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
389 yOfs += growSize;
390 yRemaining -= growSize;
391 growSize *= 2;
394 /* Use temporary hdc for source */
395 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
396 hdcTemp, 0, 0,
397 transparent, transcolor);
399 SelectObject(hdcTemp, bitmapOrig);
400 DeleteObject(bitmapTemp);
402 DeleteDC(hdcTemp);
403 return result;
405 else
407 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
408 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
409 transparent, transcolor);
413 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
414 * depend on whether the image has full alpha or whether it is
415 * color-transparent or just opaque. */
416 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
417 BOOL hasImageAlpha, INT* transparent,
418 COLORREF* transparentcolor, BOOL glyph)
420 if (hasImageAlpha)
422 *transparent = ALPHABLEND_FULL;
423 *transparentcolor = RGB (255, 0, 255);
425 else
427 BOOL trans = FALSE;
428 GetThemeBool(hTheme, iPartId, iStateId,
429 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
430 if(trans) {
431 *transparent = ALPHABLEND_BINARY;
432 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
433 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
434 transparentcolor))) {
435 /* If image is transparent, but no color was specified, use magenta */
436 *transparentcolor = RGB(255, 0, 255);
439 else
440 *transparent = ALPHABLEND_NONE;
444 /***********************************************************************
445 * UXTHEME_DrawImageGlyph
447 * Draw an imagefile glyph
449 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
450 int iStateId, RECT *pRect,
451 const DTBGOPTS *pOptions)
453 HRESULT hr;
454 HBITMAP bmpSrc = NULL;
455 HDC hdcSrc = NULL;
456 HGDIOBJ oldSrc = NULL;
457 RECT rcSrc;
458 INT transparent = FALSE;
459 COLORREF transparentcolor;
460 int valign = VA_CENTER;
461 int halign = HA_CENTER;
462 POINT dstSize;
463 POINT srcSize;
464 POINT topleft;
465 BOOL hasAlpha;
467 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
468 &bmpSrc, &rcSrc, &hasAlpha);
469 if(FAILED(hr)) return hr;
470 hdcSrc = CreateCompatibleDC(hdc);
471 if(!hdcSrc) {
472 hr = HRESULT_FROM_WIN32(GetLastError());
473 return hr;
475 oldSrc = SelectObject(hdcSrc, bmpSrc);
477 dstSize.x = pRect->right-pRect->left;
478 dstSize.y = pRect->bottom-pRect->top;
479 srcSize.x = rcSrc.right-rcSrc.left;
480 srcSize.y = rcSrc.bottom-rcSrc.top;
482 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
483 &transparentcolor, TRUE);
484 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
485 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
487 topleft.x = pRect->left;
488 topleft.y = pRect->top;
489 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
490 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
491 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
492 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
494 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
495 hdcSrc, rcSrc.left, rcSrc.top,
496 transparent, transparentcolor)) {
497 hr = HRESULT_FROM_WIN32(GetLastError());
500 SelectObject(hdcSrc, oldSrc);
501 DeleteDC(hdcSrc);
502 return hr;
505 /***********************************************************************
506 * UXTHEME_DrawImageGlyph
508 * Draw glyph on top of background, if appropriate
510 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
511 int iStateId, RECT *pRect,
512 const DTBGOPTS *pOptions)
514 int glyphtype = GT_NONE;
516 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
518 if(glyphtype == GT_IMAGEGLYPH) {
519 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
521 else if(glyphtype == GT_FONTGLYPH) {
522 /* I don't know what a font glyph is, I've never seen it used in any themes */
523 FIXME("Font glyph\n");
525 return S_OK;
528 /***********************************************************************
529 * get_image_part_size
531 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
533 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
534 int iStateId, RECT *prc, THEMESIZE eSize,
535 POINT *psz)
537 HRESULT hr = S_OK;
538 HBITMAP bmpSrc;
539 RECT rcSrc;
540 BOOL hasAlpha;
542 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
543 &bmpSrc, &rcSrc, &hasAlpha);
544 if (FAILED(hr)) return hr;
546 switch (eSize)
548 case TS_DRAW:
549 if (prc != NULL)
551 RECT rcDst;
552 POINT dstSize;
553 POINT srcSize;
554 int sizingtype = ST_STRETCH;
555 BOOL uniformsizing = FALSE;
557 CopyRect(&rcDst, prc);
559 dstSize.x = rcDst.right-rcDst.left;
560 dstSize.y = rcDst.bottom-rcDst.top;
561 srcSize.x = rcSrc.right-rcSrc.left;
562 srcSize.y = rcSrc.bottom-rcSrc.top;
564 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
565 if(uniformsizing) {
566 /* Scale height and width equally */
567 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
569 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
570 rcDst.bottom = rcDst.top + dstSize.y;
572 else
574 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
575 rcDst.right = rcDst.left + dstSize.x;
579 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
580 if(sizingtype == ST_TRUESIZE) {
581 int truesizestretchmark = 100;
583 if(dstSize.x < 0 || dstSize.y < 0) {
584 BOOL mirrorimage = TRUE;
585 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
586 if(mirrorimage) {
587 if(dstSize.x < 0) {
588 rcDst.left += dstSize.x;
589 rcDst.right += dstSize.x;
591 if(dstSize.y < 0) {
592 rcDst.top += dstSize.y;
593 rcDst.bottom += dstSize.y;
597 /* Whatever TrueSizeStretchMark does - it does not seem to
598 * be what's outlined below. It appears as if native
599 * uxtheme always stretches if dest is smaller than source
600 * (ie as if TrueSizeStretchMark==100 with the code below) */
601 #if 0
602 /* Only stretch when target exceeds source by truesizestretchmark percent */
603 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
604 #endif
605 if(dstSize.x < 0 || dstSize.y < 0 ||
606 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
607 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
608 memcpy (psz, &dstSize, sizeof (SIZE));
610 else {
611 memcpy (psz, &srcSize, sizeof (SIZE));
614 else
616 psz->x = abs(dstSize.x);
617 psz->y = abs(dstSize.y);
619 break;
621 /* else fall through */
622 case TS_MIN:
623 /* FIXME: couldn't figure how native uxtheme computes min size */
624 case TS_TRUE:
625 psz->x = rcSrc.right - rcSrc.left;
626 psz->y = rcSrc.bottom - rcSrc.top;
627 break;
629 return hr;
632 /***********************************************************************
633 * UXTHEME_DrawImageBackground
635 * Draw an imagefile background
637 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
638 int iStateId, RECT *pRect,
639 const DTBGOPTS *pOptions)
641 HRESULT hr = S_OK;
642 HBITMAP bmpSrc;
643 HGDIOBJ oldSrc;
644 HDC hdcSrc;
645 RECT rcSrc;
646 RECT rcDst;
647 POINT dstSize;
648 POINT srcSize;
649 POINT drawSize;
650 int sizingtype = ST_STRETCH;
651 INT transparent;
652 COLORREF transparentcolor = 0;
653 BOOL hasAlpha;
655 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
656 &bmpSrc, &rcSrc, &hasAlpha);
657 if(FAILED(hr)) return hr;
658 hdcSrc = CreateCompatibleDC(hdc);
659 if(!hdcSrc) {
660 hr = HRESULT_FROM_WIN32(GetLastError());
661 return hr;
663 oldSrc = SelectObject(hdcSrc, bmpSrc);
665 CopyRect(&rcDst, pRect);
667 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
668 &transparentcolor, FALSE);
670 dstSize.x = rcDst.right-rcDst.left;
671 dstSize.y = rcDst.bottom-rcDst.top;
672 srcSize.x = rcSrc.right-rcSrc.left;
673 srcSize.y = rcSrc.bottom-rcSrc.top;
675 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
676 if(sizingtype == ST_TRUESIZE) {
677 int valign = VA_CENTER, halign = HA_CENTER;
679 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
680 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
681 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
683 if (halign == HA_CENTER)
684 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
685 else if (halign == HA_RIGHT)
686 rcDst.left = rcDst.right - drawSize.x;
687 if (valign == VA_CENTER)
688 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
689 else if (valign == VA_BOTTOM)
690 rcDst.top = rcDst.bottom - drawSize.y;
691 rcDst.right = rcDst.left + drawSize.x;
692 rcDst.bottom = rcDst.top + drawSize.y;
693 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
694 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
695 transparent, transparentcolor))
696 hr = HRESULT_FROM_WIN32(GetLastError());
698 else {
699 HDC hdcDst = NULL;
700 MARGINS sm;
701 POINT org;
703 dstSize.x = abs(dstSize.x);
704 dstSize.y = abs(dstSize.y);
706 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
708 hdcDst = hdc;
709 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
711 /* Upper left corner */
712 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
713 hdcSrc, rcSrc.left, rcSrc.top,
714 transparent, transparentcolor)) {
715 hr = HRESULT_FROM_WIN32(GetLastError());
716 goto draw_error;
718 /* Upper right corner */
719 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
720 sm.cxRightWidth, sm.cyTopHeight,
721 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
722 transparent, transparentcolor)) {
723 hr = HRESULT_FROM_WIN32(GetLastError());
724 goto draw_error;
726 /* Lower left corner */
727 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
728 sm.cxLeftWidth, sm.cyBottomHeight,
729 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
730 transparent, transparentcolor)) {
731 hr = HRESULT_FROM_WIN32(GetLastError());
732 goto draw_error;
734 /* Lower right corner */
735 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
736 sm.cxRightWidth, sm.cyBottomHeight,
737 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
738 transparent, transparentcolor)) {
739 hr = HRESULT_FROM_WIN32(GetLastError());
740 goto draw_error;
743 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
744 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
745 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
746 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
747 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
749 if(destCenterWidth > 0) {
750 /* Center top */
751 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
752 destCenterWidth, sm.cyTopHeight,
753 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
754 srcCenterWidth, sm.cyTopHeight,
755 sizingtype, transparent, transparentcolor)) {
756 hr = HRESULT_FROM_WIN32(GetLastError());
757 goto draw_error;
759 /* Center bottom */
760 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
761 destCenterWidth, sm.cyBottomHeight,
762 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
763 srcCenterWidth, sm.cyBottomHeight,
764 sizingtype, transparent, transparentcolor)) {
765 hr = HRESULT_FROM_WIN32(GetLastError());
766 goto draw_error;
769 if(destCenterHeight > 0) {
770 /* Left center */
771 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
772 sm.cxLeftWidth, destCenterHeight,
773 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
774 sm.cxLeftWidth, srcCenterHeight,
775 sizingtype,
776 transparent, transparentcolor)) {
777 hr = HRESULT_FROM_WIN32(GetLastError());
778 goto draw_error;
780 /* Right center */
781 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
782 sm.cxRightWidth, destCenterHeight,
783 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
784 sm.cxRightWidth, srcCenterHeight,
785 sizingtype, transparent, transparentcolor)) {
786 hr = HRESULT_FROM_WIN32(GetLastError());
787 goto draw_error;
790 if(destCenterHeight > 0 && destCenterWidth > 0) {
791 BOOL borderonly = FALSE;
792 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
793 if(!borderonly) {
794 /* Center */
795 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
796 destCenterWidth, destCenterHeight,
797 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
798 srcCenterWidth, srcCenterHeight,
799 sizingtype, transparent, transparentcolor)) {
800 hr = HRESULT_FROM_WIN32(GetLastError());
801 goto draw_error;
807 draw_error:
808 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
810 SelectObject(hdcSrc, oldSrc);
811 DeleteDC(hdcSrc);
812 CopyRect(pRect, &rcDst);
813 return hr;
816 /***********************************************************************
817 * UXTHEME_DrawBorderRectangle
819 * Draw the bounding rectangle for a borderfill background
821 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
822 int iStateId, RECT *pRect,
823 const DTBGOPTS *pOptions)
825 HRESULT hr = S_OK;
826 HPEN hPen;
827 HGDIOBJ oldPen;
828 COLORREF bordercolor = RGB(0,0,0);
829 int bordersize = 1;
831 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
832 if(bordersize > 0) {
833 POINT ptCorners[5];
834 ptCorners[0].x = pRect->left;
835 ptCorners[0].y = pRect->top;
836 ptCorners[1].x = pRect->right-1;
837 ptCorners[1].y = pRect->top;
838 ptCorners[2].x = pRect->right-1;
839 ptCorners[2].y = pRect->bottom-1;
840 ptCorners[3].x = pRect->left;
841 ptCorners[3].y = pRect->bottom-1;
842 ptCorners[4].x = pRect->left;
843 ptCorners[4].y = pRect->top;
845 InflateRect(pRect, -bordersize, -bordersize);
846 if(pOptions->dwFlags & DTBG_OMITBORDER)
847 return S_OK;
848 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
849 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
850 if(!hPen)
851 return HRESULT_FROM_WIN32(GetLastError());
852 oldPen = SelectObject(hdc, hPen);
854 if(!Polyline(hdc, ptCorners, 5))
855 hr = HRESULT_FROM_WIN32(GetLastError());
857 SelectObject(hdc, oldPen);
858 DeleteObject(hPen);
860 return hr;
863 /***********************************************************************
864 * UXTHEME_DrawBackgroundFill
866 * Fill a borderfill background rectangle
868 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
869 int iStateId, RECT *pRect,
870 const DTBGOPTS *pOptions)
872 HRESULT hr = S_OK;
873 int filltype = FT_SOLID;
875 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
877 if(pOptions->dwFlags & DTBG_OMITCONTENT)
878 return S_OK;
880 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
882 if(filltype == FT_SOLID) {
883 HBRUSH hBrush;
884 COLORREF fillcolor = RGB(255,255,255);
886 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
887 hBrush = CreateSolidBrush(fillcolor);
888 if(!FillRect(hdc, pRect, hBrush))
889 hr = HRESULT_FROM_WIN32(GetLastError());
890 DeleteObject(hBrush);
892 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
893 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
894 the gradient ratios (no idea how those work)
895 Few themes use this, and the ones I've seen only use 2 colors with
896 a gradient ratio of 0 and 255 respectively
899 COLORREF gradient1 = RGB(0,0,0);
900 COLORREF gradient2 = RGB(255,255,255);
901 TRIVERTEX vert[2];
902 GRADIENT_RECT gRect;
904 FIXME("Gradient implementation not complete\n");
906 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
907 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
909 vert[0].x = pRect->left;
910 vert[0].y = pRect->top;
911 vert[0].Red = GetRValue(gradient1) << 8;
912 vert[0].Green = GetGValue(gradient1) << 8;
913 vert[0].Blue = GetBValue(gradient1) << 8;
914 vert[0].Alpha = 0x0000;
916 vert[1].x = pRect->right;
917 vert[1].y = pRect->bottom;
918 vert[1].Red = GetRValue(gradient2) << 8;
919 vert[1].Green = GetGValue(gradient2) << 8;
920 vert[1].Blue = GetBValue(gradient2) << 8;
921 vert[1].Alpha = 0x0000;
923 gRect.UpperLeft = 0;
924 gRect.LowerRight = 1;
925 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
927 else if(filltype == FT_RADIALGRADIENT) {
928 /* I've never seen this used in a theme */
929 FIXME("Radial gradient\n");
931 else if(filltype == FT_TILEIMAGE) {
932 /* I've never seen this used in a theme */
933 FIXME("Tile image\n");
935 return hr;
938 /***********************************************************************
939 * UXTHEME_DrawBorderBackground
941 * Draw an imagefile background
943 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
944 int iStateId, const RECT *pRect,
945 const DTBGOPTS *pOptions)
947 HRESULT hr;
948 RECT rt;
950 CopyRect(&rt, pRect);
952 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
953 if(FAILED(hr))
954 return hr;
955 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
958 /***********************************************************************
959 * DrawThemeBackgroundEx (UXTHEME.@)
961 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
962 int iStateId, const RECT *pRect,
963 const DTBGOPTS *pOptions)
965 HRESULT hr;
966 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
967 const DTBGOPTS *opts;
968 HRGN clip = NULL;
969 int hasClip = -1;
970 int bgtype = BT_BORDERFILL;
971 RECT rt;
973 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
974 if(!hTheme)
975 return E_HANDLE;
977 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
978 if (bgtype == BT_NONE) return S_OK;
980 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
981 opts = pOptions;
982 if(!opts) opts = &defaultOpts;
984 if(opts->dwFlags & DTBG_CLIPRECT) {
985 clip = CreateRectRgn(0,0,1,1);
986 hasClip = GetClipRgn(hdc, clip);
987 if(hasClip == -1)
988 TRACE("Failed to get original clipping region\n");
989 else
990 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
992 CopyRect(&rt, pRect);
994 if(bgtype == BT_IMAGEFILE)
995 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
996 else if(bgtype == BT_BORDERFILL)
997 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
998 else {
999 FIXME("Unknown background type\n");
1000 /* This should never happen, and hence I don't know what to return */
1001 hr = E_FAIL;
1003 if(SUCCEEDED(hr))
1004 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1005 if(opts->dwFlags & DTBG_CLIPRECT) {
1006 if(hasClip == 0)
1007 SelectClipRgn(hdc, NULL);
1008 else if(hasClip == 1)
1009 SelectClipRgn(hdc, clip);
1010 DeleteObject(clip);
1012 return hr;
1016 * DrawThemeEdge() implementation
1018 * Since it basically is DrawEdge() with different colors, I copied its code
1019 * from user32's uitools.c.
1022 enum
1024 EDGE_LIGHT,
1025 EDGE_HIGHLIGHT,
1026 EDGE_SHADOW,
1027 EDGE_DARKSHADOW,
1028 EDGE_FILL,
1030 EDGE_WINDOW,
1031 EDGE_WINDOWFRAME,
1033 EDGE_NUMCOLORS
1036 static const struct
1038 int themeProp;
1039 int sysColor;
1040 } EdgeColorMap[EDGE_NUMCOLORS] = {
1041 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1042 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1043 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1044 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1045 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1046 {-1, COLOR_WINDOW},
1047 {-1, COLOR_WINDOWFRAME}
1050 static const signed char LTInnerNormal[] = {
1051 -1, -1, -1, -1,
1052 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1053 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1054 -1, -1, -1, -1
1057 static const signed char LTOuterNormal[] = {
1058 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1059 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1060 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1061 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1064 static const signed char RBInnerNormal[] = {
1065 -1, -1, -1, -1,
1066 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1067 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1068 -1, -1, -1, -1
1071 static const signed char RBOuterNormal[] = {
1072 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1073 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1074 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1075 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1078 static const signed char LTInnerSoft[] = {
1079 -1, -1, -1, -1,
1080 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1081 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1082 -1, -1, -1, -1
1085 static const signed char LTOuterSoft[] = {
1086 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1087 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1088 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1089 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1092 #define RBInnerSoft RBInnerNormal /* These are the same */
1093 #define RBOuterSoft RBOuterNormal
1095 static const signed char LTRBOuterMono[] = {
1096 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1097 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1098 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1099 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1102 static const signed char LTRBInnerMono[] = {
1103 -1, -1, -1, -1,
1104 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1105 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1106 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1109 static const signed char LTRBOuterFlat[] = {
1110 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1111 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1112 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1113 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1116 static const signed char LTRBInnerFlat[] = {
1117 -1, -1, -1, -1,
1118 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1119 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1120 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1123 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1125 COLORREF col;
1126 if ((EdgeColorMap[edgeType].themeProp == -1)
1127 || FAILED (GetThemeColor (theme, part, state,
1128 EdgeColorMap[edgeType].themeProp, &col)))
1129 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1130 return col;
1133 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1135 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1138 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1140 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1143 /***********************************************************************
1144 * draw_diag_edge
1146 * Same as DrawEdge invoked with BF_DIAGONAL
1148 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1149 const RECT* rc, UINT uType,
1150 UINT uFlags, LPRECT contentsRect)
1152 POINT Points[4];
1153 signed char InnerI, OuterI;
1154 HPEN InnerPen, OuterPen;
1155 POINT SavePoint;
1156 HPEN SavePen;
1157 int spx, spy;
1158 int epx, epy;
1159 int Width = rc->right - rc->left;
1160 int Height= rc->bottom - rc->top;
1161 int SmallDiam = Width > Height ? Height : Width;
1162 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1163 || (uType & BDR_OUTER) == BDR_OUTER)
1164 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1165 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1166 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1168 /* Init some vars */
1169 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1170 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1171 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1173 /* Determine the colors of the edges */
1174 if(uFlags & BF_MONO)
1176 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1177 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1179 else if(uFlags & BF_FLAT)
1181 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1182 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1184 else if(uFlags & BF_SOFT)
1186 if(uFlags & BF_BOTTOM)
1188 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1189 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1191 else
1193 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1194 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1197 else
1199 if(uFlags & BF_BOTTOM)
1201 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1202 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1204 else
1206 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1207 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1211 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1212 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1214 MoveToEx(hdc, 0, 0, &SavePoint);
1216 /* Don't ask me why, but this is what is visible... */
1217 /* This must be possible to do much simpler, but I fail to */
1218 /* see the logic in the MS implementation (sigh...). */
1219 /* So, this might look a bit brute force here (and it is), but */
1220 /* it gets the job done;) */
1222 switch(uFlags & BF_RECT)
1224 case 0:
1225 case BF_LEFT:
1226 case BF_BOTTOM:
1227 case BF_BOTTOMLEFT:
1228 /* Left bottom endpoint */
1229 epx = rc->left-1;
1230 spx = epx + SmallDiam;
1231 epy = rc->bottom;
1232 spy = epy - SmallDiam;
1233 break;
1235 case BF_TOPLEFT:
1236 case BF_BOTTOMRIGHT:
1237 /* Left top endpoint */
1238 epx = rc->left-1;
1239 spx = epx + SmallDiam;
1240 epy = rc->top-1;
1241 spy = epy + SmallDiam;
1242 break;
1244 case BF_TOP:
1245 case BF_RIGHT:
1246 case BF_TOPRIGHT:
1247 case BF_RIGHT|BF_LEFT:
1248 case BF_RIGHT|BF_LEFT|BF_TOP:
1249 case BF_BOTTOM|BF_TOP:
1250 case BF_BOTTOM|BF_TOP|BF_LEFT:
1251 case BF_BOTTOMRIGHT|BF_LEFT:
1252 case BF_BOTTOMRIGHT|BF_TOP:
1253 case BF_RECT:
1254 /* Right top endpoint */
1255 spx = rc->left;
1256 epx = spx + SmallDiam;
1257 spy = rc->bottom-1;
1258 epy = spy - SmallDiam;
1259 break;
1262 MoveToEx(hdc, spx, spy, NULL);
1263 SelectObject(hdc, OuterPen);
1264 LineTo(hdc, epx, epy);
1266 SelectObject(hdc, InnerPen);
1268 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1270 case BF_DIAGONAL_ENDBOTTOMLEFT:
1271 case (BF_DIAGONAL|BF_BOTTOM):
1272 case BF_DIAGONAL:
1273 case (BF_DIAGONAL|BF_LEFT):
1274 MoveToEx(hdc, spx-1, spy, NULL);
1275 LineTo(hdc, epx, epy-1);
1276 Points[0].x = spx-add;
1277 Points[0].y = spy;
1278 Points[1].x = rc->left;
1279 Points[1].y = rc->top;
1280 Points[2].x = epx+1;
1281 Points[2].y = epy-1-add;
1282 Points[3] = Points[2];
1283 break;
1285 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1286 MoveToEx(hdc, spx-1, spy, NULL);
1287 LineTo(hdc, epx, epy+1);
1288 Points[0].x = spx-add;
1289 Points[0].y = spy;
1290 Points[1].x = rc->left;
1291 Points[1].y = rc->bottom-1;
1292 Points[2].x = epx+1;
1293 Points[2].y = epy+1+add;
1294 Points[3] = Points[2];
1295 break;
1297 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1298 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1299 case BF_DIAGONAL_ENDTOPRIGHT:
1300 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1301 MoveToEx(hdc, spx+1, spy, NULL);
1302 LineTo(hdc, epx, epy+1);
1303 Points[0].x = epx-1;
1304 Points[0].y = epy+1+add;
1305 Points[1].x = rc->right-1;
1306 Points[1].y = rc->top+add;
1307 Points[2].x = rc->right-1;
1308 Points[2].y = rc->bottom-1;
1309 Points[3].x = spx+add;
1310 Points[3].y = spy;
1311 break;
1313 case BF_DIAGONAL_ENDTOPLEFT:
1314 MoveToEx(hdc, spx, spy-1, NULL);
1315 LineTo(hdc, epx+1, epy);
1316 Points[0].x = epx+1+add;
1317 Points[0].y = epy+1;
1318 Points[1].x = rc->right-1;
1319 Points[1].y = rc->top;
1320 Points[2].x = rc->right-1;
1321 Points[2].y = rc->bottom-1-add;
1322 Points[3].x = spx;
1323 Points[3].y = spy-add;
1324 break;
1326 case (BF_DIAGONAL|BF_TOP):
1327 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1328 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1329 MoveToEx(hdc, spx+1, spy-1, NULL);
1330 LineTo(hdc, epx, epy);
1331 Points[0].x = epx-1;
1332 Points[0].y = epy+1;
1333 Points[1].x = rc->right-1;
1334 Points[1].y = rc->top;
1335 Points[2].x = rc->right-1;
1336 Points[2].y = rc->bottom-1-add;
1337 Points[3].x = spx+add;
1338 Points[3].y = spy-add;
1339 break;
1341 case (BF_DIAGONAL|BF_RIGHT):
1342 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1343 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1344 MoveToEx(hdc, spx, spy, NULL);
1345 LineTo(hdc, epx-1, epy+1);
1346 Points[0].x = spx;
1347 Points[0].y = spy;
1348 Points[1].x = rc->left;
1349 Points[1].y = rc->top+add;
1350 Points[2].x = epx-1-add;
1351 Points[2].y = epy+1+add;
1352 Points[3] = Points[2];
1353 break;
1356 /* Fill the interior if asked */
1357 if((uFlags & BF_MIDDLE) && retval)
1359 HBRUSH hbsave;
1360 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1361 theme, part, state);
1362 HPEN hpsave;
1363 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1364 theme, part, state);
1365 hbsave = (HBRUSH)SelectObject(hdc, hb);
1366 hpsave = (HPEN)SelectObject(hdc, hp);
1367 Polygon(hdc, Points, 4);
1368 SelectObject(hdc, hbsave);
1369 SelectObject(hdc, hpsave);
1370 DeleteObject (hp);
1371 DeleteObject (hb);
1374 /* Adjust rectangle if asked */
1375 if(uFlags & BF_ADJUST)
1377 *contentsRect = *rc;
1378 if(uFlags & BF_LEFT) contentsRect->left += add;
1379 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1380 if(uFlags & BF_TOP) contentsRect->top += add;
1381 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1384 /* Cleanup */
1385 SelectObject(hdc, SavePen);
1386 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1387 if(InnerI != -1) DeleteObject (InnerPen);
1388 if(OuterI != -1) DeleteObject (OuterPen);
1390 return retval;
1393 /***********************************************************************
1394 * draw_rect_edge
1396 * Same as DrawEdge invoked without BF_DIAGONAL
1398 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1399 const RECT* rc, UINT uType,
1400 UINT uFlags, LPRECT contentsRect)
1402 signed char LTInnerI, LTOuterI;
1403 signed char RBInnerI, RBOuterI;
1404 HPEN LTInnerPen, LTOuterPen;
1405 HPEN RBInnerPen, RBOuterPen;
1406 RECT InnerRect = *rc;
1407 POINT SavePoint;
1408 HPEN SavePen;
1409 int LBpenplus = 0;
1410 int LTpenplus = 0;
1411 int RTpenplus = 0;
1412 int RBpenplus = 0;
1413 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1414 || (uType & BDR_OUTER) == BDR_OUTER)
1415 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1417 /* Init some vars */
1418 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1419 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1421 /* Determine the colors of the edges */
1422 if(uFlags & BF_MONO)
1424 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1425 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1427 else if(uFlags & BF_FLAT)
1429 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1430 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1432 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1434 else if(uFlags & BF_SOFT)
1436 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1437 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1438 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1439 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1441 else
1443 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1444 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1445 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1446 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1449 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1450 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1451 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1452 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1454 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1455 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1456 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1457 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1459 MoveToEx(hdc, 0, 0, &SavePoint);
1461 /* Draw the outer edge */
1462 SelectObject(hdc, LTOuterPen);
1463 if(uFlags & BF_TOP)
1465 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1466 LineTo(hdc, InnerRect.right, InnerRect.top);
1468 if(uFlags & BF_LEFT)
1470 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1471 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1473 SelectObject(hdc, RBOuterPen);
1474 if(uFlags & BF_BOTTOM)
1476 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1477 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1479 if(uFlags & BF_RIGHT)
1481 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1482 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1485 /* Draw the inner edge */
1486 SelectObject(hdc, LTInnerPen);
1487 if(uFlags & BF_TOP)
1489 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1490 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1492 if(uFlags & BF_LEFT)
1494 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1495 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1497 SelectObject(hdc, RBInnerPen);
1498 if(uFlags & BF_BOTTOM)
1500 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1501 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1503 if(uFlags & BF_RIGHT)
1505 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1506 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1509 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1511 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1512 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1514 if(uFlags & BF_LEFT) InnerRect.left += add;
1515 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1516 if(uFlags & BF_TOP) InnerRect.top += add;
1517 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1519 if((uFlags & BF_MIDDLE) && retval)
1521 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1522 theme, part, state);
1523 FillRect(hdc, &InnerRect, br);
1524 DeleteObject (br);
1527 if(uFlags & BF_ADJUST)
1528 *contentsRect = InnerRect;
1531 /* Cleanup */
1532 SelectObject(hdc, SavePen);
1533 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1534 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1535 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1536 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1537 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1538 return retval;
1542 /***********************************************************************
1543 * DrawThemeEdge (UXTHEME.@)
1545 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1546 * difference is that it does not rely on the system colors alone, but
1547 * also allows color specification in the theme.
1549 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1550 int iStateId, const RECT *pDestRect, UINT uEdge,
1551 UINT uFlags, RECT *pContentRect)
1553 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1554 if(!hTheme)
1555 return E_HANDLE;
1557 if(uFlags & BF_DIAGONAL)
1558 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1559 uEdge, uFlags, pContentRect);
1560 else
1561 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1562 uEdge, uFlags, pContentRect);
1566 /***********************************************************************
1567 * DrawThemeIcon (UXTHEME.@)
1569 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1570 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1572 FIXME("%d %d: stub\n", iPartId, iStateId);
1573 if(!hTheme)
1574 return E_HANDLE;
1575 return ERROR_CALL_NOT_IMPLEMENTED;
1578 /***********************************************************************
1579 * DrawThemeText (UXTHEME.@)
1581 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1582 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1583 DWORD dwTextFlags2, const RECT *pRect)
1585 HRESULT hr;
1586 HFONT hFont = NULL;
1587 HGDIOBJ oldFont = NULL;
1588 LOGFONTW logfont;
1589 COLORREF textColor;
1590 COLORREF oldTextColor;
1591 int oldBkMode;
1592 RECT rt;
1594 TRACE("%d %d: stub\n", iPartId, iStateId);
1595 if(!hTheme)
1596 return E_HANDLE;
1598 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1599 if(SUCCEEDED(hr)) {
1600 hFont = CreateFontIndirectW(&logfont);
1601 if(!hFont)
1602 TRACE("Failed to create font\n");
1604 CopyRect(&rt, pRect);
1605 if(hFont)
1606 oldFont = SelectObject(hdc, hFont);
1608 if(dwTextFlags2 & DTT_GRAYED)
1609 textColor = GetSysColor(COLOR_GRAYTEXT);
1610 else {
1611 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1612 textColor = GetTextColor(hdc);
1614 oldTextColor = SetTextColor(hdc, textColor);
1615 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1616 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1617 SetBkMode(hdc, oldBkMode);
1618 SetTextColor(hdc, oldTextColor);
1620 if(hFont) {
1621 SelectObject(hdc, oldFont);
1622 DeleteObject(hFont);
1624 return S_OK;
1627 /***********************************************************************
1628 * GetThemeBackgroundContentRect (UXTHEME.@)
1630 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1631 int iStateId,
1632 const RECT *pBoundingRect,
1633 RECT *pContentRect)
1635 MARGINS margin;
1636 HRESULT hr;
1638 TRACE("(%d,%d)\n", iPartId, iStateId);
1639 if(!hTheme)
1640 return E_HANDLE;
1642 /* try content margins property... */
1643 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1644 if(SUCCEEDED(hr)) {
1645 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1646 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1647 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1648 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1649 } else {
1650 /* otherwise, try to determine content rect from the background type and props */
1651 int bgtype = BT_BORDERFILL;
1652 *pContentRect = *pBoundingRect;
1654 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1655 if(bgtype == BT_BORDERFILL) {
1656 int bordersize = 1;
1658 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1659 InflateRect(pContentRect, -bordersize, -bordersize);
1660 } else if ((bgtype == BT_IMAGEFILE)
1661 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1662 TMT_SIZINGMARGINS, NULL, &margin)))) {
1663 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1664 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1665 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1666 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1668 /* If nothing was found, leave unchanged */
1671 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1673 return S_OK;
1676 /***********************************************************************
1677 * GetThemeBackgroundExtent (UXTHEME.@)
1679 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1680 int iStateId, const RECT *pContentRect,
1681 RECT *pExtentRect)
1683 MARGINS margin;
1684 HRESULT hr;
1686 TRACE("(%d,%d)\n", iPartId, iStateId);
1687 if(!hTheme)
1688 return E_HANDLE;
1690 /* try content margins property... */
1691 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1692 if(SUCCEEDED(hr)) {
1693 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1694 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1695 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1696 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1697 } else {
1698 /* otherwise, try to determine content rect from the background type and props */
1699 int bgtype = BT_BORDERFILL;
1700 *pExtentRect = *pContentRect;
1702 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1703 if(bgtype == BT_BORDERFILL) {
1704 int bordersize = 1;
1706 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1707 InflateRect(pExtentRect, bordersize, bordersize);
1708 } else if ((bgtype == BT_IMAGEFILE)
1709 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1710 TMT_SIZINGMARGINS, NULL, &margin)))) {
1711 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1712 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1713 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1714 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1716 /* If nothing was found, leave unchanged */
1719 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1721 return S_OK;
1724 /***********************************************************************
1725 * GetThemeBackgroundRegion (UXTHEME.@)
1727 * Calculate the background region, taking into consideration transparent areas
1728 * of the background image.
1730 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1731 int iStateId, const RECT *pRect,
1732 HRGN *pRegion)
1734 HRESULT hr = S_OK;
1735 int bgtype = BT_BORDERFILL;
1737 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1738 if(!hTheme)
1739 return E_HANDLE;
1740 if(!pRect || !pRegion)
1741 return E_POINTER;
1743 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1744 if(bgtype == BT_IMAGEFILE) {
1745 FIXME("Images not handled yet\n");
1746 hr = ERROR_CALL_NOT_IMPLEMENTED;
1748 else if(bgtype == BT_BORDERFILL) {
1749 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1750 if(!*pRegion)
1751 hr = HRESULT_FROM_WIN32(GetLastError());
1753 else {
1754 FIXME("Unknown background type\n");
1755 /* This should never happen, and hence I don't know what to return */
1756 hr = E_FAIL;
1758 return hr;
1761 /* compute part size for "borderfill" backgrounds */
1762 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1763 int iStateId, THEMESIZE eSize, POINT* psz)
1765 HRESULT hr = S_OK;
1766 int bordersize = 1;
1768 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1769 &bordersize)))
1771 psz->x = psz->y = 2*bordersize;
1772 if (eSize != TS_MIN)
1774 psz->x++;
1775 psz->y++;
1778 return hr;
1781 /***********************************************************************
1782 * GetThemePartSize (UXTHEME.@)
1784 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1785 int iStateId, RECT *prc, THEMESIZE eSize,
1786 SIZE *psz)
1788 int bgtype = BT_BORDERFILL;
1789 HRESULT hr = S_OK;
1790 POINT size = {1, 1};
1792 if(!hTheme)
1793 return E_HANDLE;
1795 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1796 if (bgtype == BT_NONE)
1797 /* do nothing */;
1798 else if(bgtype == BT_IMAGEFILE)
1799 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1800 else if(bgtype == BT_BORDERFILL)
1801 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1802 else {
1803 FIXME("Unknown background type\n");
1804 /* This should never happen, and hence I don't know what to return */
1805 hr = E_FAIL;
1807 psz->cx = size.x;
1808 psz->cy = size.y;
1809 return hr;
1813 /***********************************************************************
1814 * GetThemeTextExtent (UXTHEME.@)
1816 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1817 int iStateId, LPCWSTR pszText, int iCharCount,
1818 DWORD dwTextFlags, const RECT *pBoundingRect,
1819 RECT *pExtentRect)
1821 HRESULT hr;
1822 HFONT hFont = NULL;
1823 HGDIOBJ oldFont = NULL;
1824 LOGFONTW logfont;
1825 RECT rt = {0,0,0xFFFF,0xFFFF};
1827 TRACE("%d %d: stub\n", iPartId, iStateId);
1828 if(!hTheme)
1829 return E_HANDLE;
1831 if(pBoundingRect)
1832 CopyRect(&rt, pBoundingRect);
1834 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1835 if(SUCCEEDED(hr)) {
1836 hFont = CreateFontIndirectW(&logfont);
1837 if(!hFont)
1838 TRACE("Failed to create font\n");
1840 if(hFont)
1841 oldFont = SelectObject(hdc, hFont);
1843 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1844 CopyRect(pExtentRect, &rt);
1846 if(hFont) {
1847 SelectObject(hdc, oldFont);
1848 DeleteObject(hFont);
1850 return S_OK;
1853 /***********************************************************************
1854 * GetThemeTextMetrics (UXTHEME.@)
1856 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1857 int iStateId, TEXTMETRICW *ptm)
1859 HRESULT hr;
1860 HFONT hFont = NULL;
1861 HGDIOBJ oldFont = NULL;
1862 LOGFONTW logfont;
1864 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1865 if(!hTheme)
1866 return E_HANDLE;
1868 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1869 if(SUCCEEDED(hr)) {
1870 hFont = CreateFontIndirectW(&logfont);
1871 if(!hFont)
1872 TRACE("Failed to create font\n");
1874 if(hFont)
1875 oldFont = SelectObject(hdc, hFont);
1877 if(!GetTextMetricsW(hdc, ptm))
1878 hr = HRESULT_FROM_WIN32(GetLastError());
1880 if(hFont) {
1881 SelectObject(hdc, oldFont);
1882 DeleteObject(hFont);
1884 return hr;
1887 /***********************************************************************
1888 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1890 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1891 int iStateId)
1893 int bgtype = BT_BORDERFILL;
1894 RECT rect = {0, 0, 0, 0};
1895 HBITMAP bmpSrc;
1896 RECT rcSrc;
1897 BOOL hasAlpha;
1898 INT transparent;
1899 COLORREF transparentcolor;
1901 TRACE("(%d,%d)\n", iPartId, iStateId);
1903 if(!hTheme)
1904 return FALSE;
1906 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1908 if (bgtype != BT_IMAGEFILE) return FALSE;
1910 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1911 &bmpSrc, &rcSrc, &hasAlpha)))
1912 return FALSE;
1914 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1915 &transparentcolor, FALSE);
1916 return (transparent != ALPHABLEND_NONE);