Sync to Wine-0_9_2:
[reactos.git] / reactos / lib / uxtheme / draw.c
1 /*
2 * Win32 5.1 Theme drawing
3 *
4 * Copyright (C) 2003 Kevin Koltzau
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "uxtheme.h"
31 #include "tmschema.h"
32
33 #include "msstyles.h"
34 #include "uxthemedll.h"
35
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
39
40 /***********************************************************************
41 * Defines and global variables
42 */
43
44 extern ATOM atDialogThemeEnabled;
45
46 /***********************************************************************/
47
48 /***********************************************************************
49 * EnableThemeDialogTexture (UXTHEME.@)
50 */
51 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
52 {
53 static const WCHAR szTab[] = { 'T','a','b',0 };
54 HRESULT hr;
55
56 TRACE("(%p,0x%08lx\n", hwnd, dwFlags);
57 hr = SetPropW (hwnd, MAKEINTATOMW (atDialogThemeEnabled),
58 (HANDLE)(dwFlags|0x80000000));
59 /* 0x80000000 serves as a "flags set" flag */
60 if (FAILED(hr))
61 return hr;
62 if (dwFlags & ETDT_USETABTEXTURE)
63 return SetWindowTheme (hwnd, NULL, szTab);
64 else
65 return SetWindowTheme (hwnd, NULL, NULL);
66 return S_OK;
67 }
68
69 /***********************************************************************
70 * IsThemeDialogTextureEnabled (UXTHEME.@)
71 */
72 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
73 {
74 DWORD dwDialogTextureFlags;
75 TRACE("(%p)\n", hwnd);
76
77 dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
78 MAKEINTATOMW (atDialogThemeEnabled));
79 if (dwDialogTextureFlags == 0)
80 /* Means EnableThemeDialogTexture wasn't called for this dialog */
81 return TRUE;
82
83 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
84 }
85
86 /***********************************************************************
87 * DrawThemeParentBackground (UXTHEME.@)
88 */
89 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
90 {
91 RECT rt;
92 POINT org;
93 HWND hParent;
94 HRGN clip = NULL;
95 int hasClip = -1;
96
97 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
98 hParent = GetParent(hwnd);
99 if(!hParent)
100 hParent = hwnd;
101 if(prc) {
102 CopyRect(&rt, prc);
103 MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
104
105 clip = CreateRectRgn(0,0,1,1);
106 hasClip = GetClipRgn(hdc, clip);
107 if(hasClip == -1)
108 TRACE("Failed to get original clipping region\n");
109 else
110 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
111 }
112 else {
113 GetClientRect(hParent, &rt);
114 MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
115 }
116
117 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
118
119 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
120 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
121
122 SetViewportOrgEx(hdc, org.x, org.y, NULL);
123 if(prc) {
124 if(hasClip == 0)
125 SelectClipRgn(hdc, NULL);
126 else if(hasClip == 1)
127 SelectClipRgn(hdc, clip);
128 DeleteObject(clip);
129 }
130 return S_OK;
131 }
132
133
134 /***********************************************************************
135 * DrawThemeBackground (UXTHEME.@)
136 */
137 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
138 int iStateId, const RECT *pRect,
139 const RECT *pClipRect)
140 {
141 DTBGOPTS opts;
142 opts.dwSize = sizeof(DTBGOPTS);
143 opts.dwFlags = 0;
144 if(pClipRect) {
145 opts.dwFlags |= DTBG_CLIPRECT;
146 CopyRect(&opts.rcClip, pClipRect);
147 }
148 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
149 }
150
151 /***********************************************************************
152 * UXTHEME_SelectImage
153 *
154 * Select the image to use
155 */
156 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
157 {
158 PTHEME_PROPERTY tp;
159 int imageselecttype = IST_NONE;
160 int i;
161 int image;
162 if(glyph)
163 image = TMT_GLYPHIMAGEFILE;
164 else
165 image = TMT_IMAGEFILE;
166
167 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
168 return tp;
169 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
170
171 if(imageselecttype == IST_DPI) {
172 int reqdpi = 0;
173 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
174 for(i=4; i>=0; i--) {
175 reqdpi = 0;
176 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
177 if(reqdpi != 0 && screendpi >= reqdpi) {
178 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
179 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
180 }
181 }
182 }
183 /* If an image couldn't be selected, choose the first one */
184 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
185 }
186 else if(imageselecttype == IST_SIZE) {
187 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
188 POINT reqsize;
189 for(i=4; i>=0; i--) {
190 PTHEME_PROPERTY fileProp =
191 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
192 if (!fileProp) continue;
193 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
194 /* fall back to size of Nth image */
195 WCHAR szPath[MAX_PATH];
196 int imagelayout = IL_HORIZONTAL;
197 int imagecount = 1;
198 int imagenum;
199 BITMAP bmp;
200 HBITMAP hBmp;
201 BOOL hasAlpha;
202
203 lstrcpynW(szPath, fileProp->lpValue,
204 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
205 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
206 if(!hBmp) continue;
207
208 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
209 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
210
211 imagenum = max (min (imagecount, iStateId), 1) - 1;
212 GetObjectW(hBmp, sizeof(bmp), &bmp);
213 if(imagelayout == IL_VERTICAL) {
214 reqsize.x = bmp.bmWidth;
215 reqsize.y = bmp.bmHeight/imagecount;
216 }
217 else {
218 reqsize.x = bmp.bmWidth/imagecount;
219 reqsize.y = bmp.bmHeight;
220 }
221 }
222 if(reqsize.x <= size.x && reqsize.y <= size.y) {
223 TRACE("Using image size %ldx%ld, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
224 return fileProp;
225 }
226 }
227 /* If an image couldn't be selected, choose the smallest one */
228 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
229 }
230 return NULL;
231 }
232
233 /***********************************************************************
234 * UXTHEME_LoadImage
235 *
236 * Load image for part/state
237 */
238 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
239 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
240 {
241 int imagelayout = IL_HORIZONTAL;
242 int imagecount = 1;
243 int imagenum;
244 BITMAP bmp;
245 WCHAR szPath[MAX_PATH];
246 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
247 if(!tp) {
248 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
249 return E_PROP_ID_UNSUPPORTED;
250 }
251 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
252 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
253 if(!*hBmp) {
254 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
255 return HRESULT_FROM_WIN32(GetLastError());
256 }
257
258 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
259 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
260
261 imagenum = max (min (imagecount, iStateId), 1) - 1;
262 GetObjectW(*hBmp, sizeof(bmp), &bmp);
263 if(imagelayout == IL_VERTICAL) {
264 int height = bmp.bmHeight/imagecount;
265 bmpRect->left = 0;
266 bmpRect->right = bmp.bmWidth;
267 bmpRect->top = imagenum * height;
268 bmpRect->bottom = bmpRect->top + height;
269 }
270 else {
271 int width = bmp.bmWidth/imagecount;
272 bmpRect->left = imagenum * width;
273 bmpRect->right = bmpRect->left + width;
274 bmpRect->top = 0;
275 bmpRect->bottom = bmp.bmHeight;
276 }
277 return S_OK;
278 }
279
280 /***********************************************************************
281 * UXTHEME_StretchBlt
282 *
283 * Pseudo TransparentBlt/StretchBlt
284 */
285 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
286 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
287 INT transparent, COLORREF transcolor)
288 {
289 static const BLENDFUNCTION blendFunc =
290 {
291 AC_SRC_OVER, /* BlendOp */
292 0, /* BlendFlag */
293 255, /* SourceConstantAlpha */
294 AC_SRC_ALPHA /* AlphaFormat */
295 };
296 if (transparent == ALPHABLEND_BINARY) {
297 /* Ensure we don't pass any negative values to TransparentBlt */
298 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
299 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
300 transcolor);
301 }
302 if ((transparent == ALPHABLEND_NONE) ||
303 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
304 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
305 blendFunc))
306 {
307 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
308 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
309 SRCCOPY);
310 }
311 return TRUE;
312 }
313
314 /***********************************************************************
315 * UXTHEME_Blt
316 *
317 * Simplify sending same width/height for both source and dest
318 */
319 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
320 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
321 INT transparent, COLORREF transcolor)
322 {
323 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
324 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
325 transparent, transcolor);
326 }
327
328 /***********************************************************************
329 * UXTHEME_SizedBlt
330 *
331 * Stretches or tiles, depending on sizingtype.
332 */
333 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
334 int nWidthDst, int nHeightDst,
335 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
336 int nWidthSrc, int nHeightSrc,
337 int sizingtype,
338 INT transparent, COLORREF transcolor)
339 {
340 if (sizingtype == ST_TILE)
341 {
342 int yOfs = nYOriginDst;
343 int yRemaining = nHeightDst;
344 while (yRemaining > 0)
345 {
346 int bltHeight = min (yRemaining, nHeightSrc);
347 int xOfs = nXOriginDst;
348 int xRemaining = nWidthDst;
349 while (xRemaining > 0)
350 {
351 int bltWidth = min (xRemaining, nWidthSrc);
352 if (!UXTHEME_Blt (hdcDst, xOfs, yOfs, bltWidth, bltHeight,
353 hdcSrc, nXOriginSrc, nYOriginSrc,
354 transparent, transcolor))
355 return FALSE;
356 xOfs += nWidthSrc;
357 xRemaining -= nWidthSrc;
358 }
359 yOfs += nHeightSrc;
360 yRemaining -= nHeightSrc;
361 }
362 return TRUE;
363 }
364 else
365 {
366 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
367 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
368 transparent, transcolor);
369 }
370 }
371
372 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
373 * depend on whether the image has full alpha or whether it is
374 * color-transparent or just opaque. */
375 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
376 BOOL hasImageAlpha, INT* transparent,
377 COLORREF* transparentcolor, BOOL glyph)
378 {
379 if (hasImageAlpha)
380 {
381 *transparent = ALPHABLEND_FULL;
382 *transparentcolor = RGB (255, 0, 255);
383 }
384 else
385 {
386 BOOL trans = FALSE;
387 GetThemeBool(hTheme, iPartId, iStateId,
388 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
389 if(trans) {
390 *transparent = ALPHABLEND_BINARY;
391 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
392 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
393 transparentcolor))) {
394 /* If image is transparent, but no color was specified, use magenta */
395 *transparentcolor = RGB(255, 0, 255);
396 }
397 }
398 else
399 *transparent = ALPHABLEND_NONE;
400 }
401 }
402
403 /***********************************************************************
404 * UXTHEME_DrawImageGlyph
405 *
406 * Draw an imagefile glyph
407 */
408 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
409 int iStateId, RECT *pRect,
410 const DTBGOPTS *pOptions)
411 {
412 HRESULT hr;
413 HBITMAP bmpSrc = NULL;
414 HDC hdcSrc = NULL;
415 HGDIOBJ oldSrc = NULL;
416 RECT rcSrc;
417 INT transparent = FALSE;
418 COLORREF transparentcolor;
419 int valign = VA_CENTER;
420 int halign = HA_CENTER;
421 POINT dstSize;
422 POINT srcSize;
423 POINT topleft;
424 BOOL hasAlpha;
425
426 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
427 &bmpSrc, &rcSrc, &hasAlpha);
428 if(FAILED(hr)) return hr;
429 hdcSrc = CreateCompatibleDC(hdc);
430 if(!hdcSrc) {
431 hr = HRESULT_FROM_WIN32(GetLastError());
432 return hr;
433 }
434 oldSrc = SelectObject(hdcSrc, bmpSrc);
435
436 dstSize.x = pRect->right-pRect->left;
437 dstSize.y = pRect->bottom-pRect->top;
438 srcSize.x = rcSrc.right-rcSrc.left;
439 srcSize.y = rcSrc.bottom-rcSrc.top;
440
441 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
442 &transparentcolor, TRUE);
443 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
444 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
445
446 topleft.x = pRect->left;
447 topleft.y = pRect->top;
448 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
449 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
450 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
451 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
452
453 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
454 hdcSrc, rcSrc.left, rcSrc.top,
455 transparent, transparentcolor)) {
456 hr = HRESULT_FROM_WIN32(GetLastError());
457 }
458
459 SelectObject(hdcSrc, oldSrc);
460 DeleteDC(hdcSrc);
461 return hr;
462 }
463
464 /***********************************************************************
465 * UXTHEME_DrawImageGlyph
466 *
467 * Draw glyph on top of background, if appropriate
468 */
469 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
470 int iStateId, RECT *pRect,
471 const DTBGOPTS *pOptions)
472 {
473 int glyphtype = GT_NONE;
474
475 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
476
477 if(glyphtype == GT_IMAGEGLYPH) {
478 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
479 }
480 else if(glyphtype == GT_FONTGLYPH) {
481 /* I don't know what a font glyph is, I've never seen it used in any themes */
482 FIXME("Font glyph\n");
483 }
484 return S_OK;
485 }
486
487 /***********************************************************************
488 * get_image_part_size
489 *
490 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
491 */
492 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
493 int iStateId, RECT *prc, THEMESIZE eSize,
494 POINT *psz)
495 {
496 HRESULT hr = S_OK;
497 HBITMAP bmpSrc;
498 RECT rcSrc;
499 BOOL hasAlpha;
500
501 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
502 &bmpSrc, &rcSrc, &hasAlpha);
503 if (FAILED(hr)) return hr;
504
505 switch (eSize)
506 {
507 case TS_DRAW:
508 if (prc != NULL)
509 {
510 RECT rcDst;
511 POINT dstSize;
512 POINT srcSize;
513 int sizingtype = ST_STRETCH;
514 BOOL uniformsizing = FALSE;
515
516 CopyRect(&rcDst, prc);
517
518 dstSize.x = rcDst.right-rcDst.left;
519 dstSize.y = rcDst.bottom-rcDst.top;
520 srcSize.x = rcSrc.right-rcSrc.left;
521 srcSize.y = rcSrc.bottom-rcSrc.top;
522
523 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
524 if(uniformsizing) {
525 /* Scale height and width equally */
526 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
527 {
528 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
529 rcDst.bottom = rcDst.top + dstSize.y;
530 }
531 else
532 {
533 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
534 rcDst.right = rcDst.left + dstSize.x;
535 }
536 }
537
538 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
539 if(sizingtype == ST_TRUESIZE) {
540 int truesizestretchmark = 100;
541
542 if(dstSize.x < 0 || dstSize.y < 0) {
543 BOOL mirrorimage = TRUE;
544 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
545 if(mirrorimage) {
546 if(dstSize.x < 0) {
547 rcDst.left += dstSize.x;
548 rcDst.right += dstSize.x;
549 }
550 if(dstSize.y < 0) {
551 rcDst.top += dstSize.y;
552 rcDst.bottom += dstSize.y;
553 }
554 }
555 }
556 /* Whatever TrueSizeStretchMark does - it does not seem to
557 * be what's outlined below. It appears as if native
558 * uxtheme always stretches if dest is smaller than source
559 * (ie as if TrueSizeStretchMark==100 with the code below) */
560 #if 0
561 /* Only stretch when target exceeds source by truesizestretchmark percent */
562 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
563 #endif
564 if(dstSize.x < 0 || dstSize.y < 0 ||
565 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
566 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
567 memcpy (psz, &dstSize, sizeof (SIZE));
568 }
569 else {
570 memcpy (psz, &srcSize, sizeof (SIZE));
571 }
572 }
573 else
574 {
575 psz->x = abs(dstSize.x);
576 psz->y = abs(dstSize.y);
577 }
578 break;
579 }
580 /* else fall through */
581 case TS_MIN:
582 /* FIXME: couldn't figure how native uxtheme computes min size */
583 case TS_TRUE:
584 psz->x = rcSrc.right - rcSrc.left;
585 psz->y = rcSrc.bottom - rcSrc.top;
586 break;
587 }
588 return hr;
589 }
590
591 /***********************************************************************
592 * UXTHEME_DrawImageBackground
593 *
594 * Draw an imagefile background
595 */
596 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
597 int iStateId, RECT *pRect,
598 const DTBGOPTS *pOptions)
599 {
600 HRESULT hr = S_OK;
601 HBITMAP bmpSrc;
602 HGDIOBJ oldSrc;
603 HDC hdcSrc;
604 RECT rcSrc;
605 RECT rcDst;
606 POINT dstSize;
607 POINT srcSize;
608 POINT drawSize;
609 int sizingtype = ST_STRETCH;
610 INT transparent;
611 COLORREF transparentcolor = 0;
612 BOOL hasAlpha;
613
614 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
615 &bmpSrc, &rcSrc, &hasAlpha);
616 if(FAILED(hr)) return hr;
617 hdcSrc = CreateCompatibleDC(hdc);
618 if(!hdcSrc) {
619 hr = HRESULT_FROM_WIN32(GetLastError());
620 return hr;
621 }
622 oldSrc = SelectObject(hdcSrc, bmpSrc);
623
624 CopyRect(&rcDst, pRect);
625
626 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
627 &transparentcolor, FALSE);
628
629 dstSize.x = rcDst.right-rcDst.left;
630 dstSize.y = rcDst.bottom-rcDst.top;
631 srcSize.x = rcSrc.right-rcSrc.left;
632 srcSize.y = rcSrc.bottom-rcSrc.top;
633
634 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
635 if(sizingtype == ST_TRUESIZE) {
636 int valign = VA_CENTER, halign = HA_CENTER;
637
638 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
639 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
640 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
641
642 if (halign == HA_CENTER)
643 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
644 else if (halign == HA_RIGHT)
645 rcDst.left = rcDst.right - drawSize.x;
646 if (valign == VA_CENTER)
647 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
648 else if (valign == VA_BOTTOM)
649 rcDst.top = rcDst.bottom - drawSize.y;
650 rcDst.right = rcDst.left + drawSize.x;
651 rcDst.bottom = rcDst.top + drawSize.y;
652 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
653 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
654 transparent, transparentcolor))
655 hr = HRESULT_FROM_WIN32(GetLastError());
656 }
657 else {
658 HDC hdcDst = NULL;
659 MARGINS sm;
660 POINT org;
661
662 dstSize.x = abs(dstSize.x);
663 dstSize.y = abs(dstSize.y);
664
665 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
666
667 hdcDst = hdc;
668 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
669
670 /* Upper left corner */
671 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
672 hdcSrc, rcSrc.left, rcSrc.top,
673 transparent, transparentcolor)) {
674 hr = HRESULT_FROM_WIN32(GetLastError());
675 goto draw_error;
676 }
677 /* Upper right corner */
678 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
679 sm.cxRightWidth, sm.cyTopHeight,
680 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
681 transparent, transparentcolor)) {
682 hr = HRESULT_FROM_WIN32(GetLastError());
683 goto draw_error;
684 }
685 /* Lower left corner */
686 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
687 sm.cxLeftWidth, sm.cyBottomHeight,
688 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
689 transparent, transparentcolor)) {
690 hr = HRESULT_FROM_WIN32(GetLastError());
691 goto draw_error;
692 }
693 /* Lower right corner */
694 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
695 sm.cxRightWidth, sm.cyBottomHeight,
696 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
697 transparent, transparentcolor)) {
698 hr = HRESULT_FROM_WIN32(GetLastError());
699 goto draw_error;
700 }
701
702 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
703 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
704 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
705 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
706 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
707
708 if(destCenterWidth > 0) {
709 /* Center top */
710 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
711 destCenterWidth, sm.cyTopHeight,
712 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
713 srcCenterWidth, sm.cyTopHeight,
714 sizingtype, transparent, transparentcolor)) {
715 hr = HRESULT_FROM_WIN32(GetLastError());
716 goto draw_error;
717 }
718 /* Center bottom */
719 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
720 destCenterWidth, sm.cyBottomHeight,
721 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
722 srcCenterWidth, sm.cyBottomHeight,
723 sizingtype, transparent, transparentcolor)) {
724 hr = HRESULT_FROM_WIN32(GetLastError());
725 goto draw_error;
726 }
727 }
728 if(destCenterHeight > 0) {
729 /* Left center */
730 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
731 sm.cxLeftWidth, destCenterHeight,
732 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
733 sm.cxLeftWidth, srcCenterHeight,
734 sizingtype,
735 transparent, transparentcolor)) {
736 hr = HRESULT_FROM_WIN32(GetLastError());
737 goto draw_error;
738 }
739 /* Right center */
740 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
741 sm.cxRightWidth, destCenterHeight,
742 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
743 sm.cxRightWidth, srcCenterHeight,
744 sizingtype, transparent, transparentcolor)) {
745 hr = HRESULT_FROM_WIN32(GetLastError());
746 goto draw_error;
747 }
748 }
749 if(destCenterHeight > 0 && destCenterWidth > 0) {
750 BOOL borderonly = FALSE;
751 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
752 if(!borderonly) {
753 /* Center */
754 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
755 destCenterWidth, destCenterHeight,
756 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
757 srcCenterWidth, srcCenterHeight,
758 sizingtype, transparent, transparentcolor)) {
759 hr = HRESULT_FROM_WIN32(GetLastError());
760 goto draw_error;
761 }
762 }
763 }
764 }
765
766 draw_error:
767 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
768 }
769 SelectObject(hdcSrc, oldSrc);
770 DeleteDC(hdcSrc);
771 CopyRect(pRect, &rcDst);
772 return hr;
773 }
774
775 /***********************************************************************
776 * UXTHEME_DrawBorderRectangle
777 *
778 * Draw the bounding rectangle for a borderfill background
779 */
780 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
781 int iStateId, RECT *pRect,
782 const DTBGOPTS *pOptions)
783 {
784 HRESULT hr = S_OK;
785 HPEN hPen;
786 HGDIOBJ oldPen;
787 COLORREF bordercolor = RGB(0,0,0);
788 int bordersize = 1;
789
790 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
791 if(bordersize > 0) {
792 POINT ptCorners[5];
793 ptCorners[0].x = pRect->left;
794 ptCorners[0].y = pRect->top;
795 ptCorners[1].x = pRect->right-1;
796 ptCorners[1].y = pRect->top;
797 ptCorners[2].x = pRect->right-1;
798 ptCorners[2].y = pRect->bottom-1;
799 ptCorners[3].x = pRect->left;
800 ptCorners[3].y = pRect->bottom-1;
801 ptCorners[4].x = pRect->left;
802 ptCorners[4].y = pRect->top;
803
804 InflateRect(pRect, -bordersize, -bordersize);
805 if(pOptions->dwFlags & DTBG_OMITBORDER)
806 return S_OK;
807 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
808 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
809 if(!hPen)
810 return HRESULT_FROM_WIN32(GetLastError());
811 oldPen = SelectObject(hdc, hPen);
812
813 if(!Polyline(hdc, ptCorners, 5))
814 hr = HRESULT_FROM_WIN32(GetLastError());
815
816 SelectObject(hdc, oldPen);
817 DeleteObject(hPen);
818 }
819 return hr;
820 }
821
822 /***********************************************************************
823 * UXTHEME_DrawBackgroundFill
824 *
825 * Fill a borderfill background rectangle
826 */
827 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
828 int iStateId, RECT *pRect,
829 const DTBGOPTS *pOptions)
830 {
831 HRESULT hr = S_OK;
832 int filltype = FT_SOLID;
833
834 TRACE("(%d,%d,%ld)\n", iPartId, iStateId, pOptions->dwFlags);
835
836 if(pOptions->dwFlags & DTBG_OMITCONTENT)
837 return S_OK;
838
839 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
840
841 if(filltype == FT_SOLID) {
842 HBRUSH hBrush;
843 COLORREF fillcolor = RGB(255,255,255);
844
845 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
846 hBrush = CreateSolidBrush(fillcolor);
847 if(!FillRect(hdc, pRect, hBrush))
848 hr = HRESULT_FROM_WIN32(GetLastError());
849 DeleteObject(hBrush);
850 }
851 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
852 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
853 the gradient ratios (no idea how those work)
854 Few themes use this, and the ones I've seen only use 2 colors with
855 a gradient ratio of 0 and 255 respectivly
856 */
857
858 COLORREF gradient1 = RGB(0,0,0);
859 COLORREF gradient2 = RGB(255,255,255);
860 TRIVERTEX vert[2];
861 GRADIENT_RECT gRect;
862
863 FIXME("Gradient implementation not complete\n");
864
865 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
866 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
867
868 vert[0].x = pRect->left;
869 vert[0].y = pRect->top;
870 vert[0].Red = GetRValue(gradient1) << 8;
871 vert[0].Green = GetGValue(gradient1) << 8;
872 vert[0].Blue = GetBValue(gradient1) << 8;
873 vert[0].Alpha = 0x0000;
874
875 vert[1].x = pRect->right;
876 vert[1].y = pRect->bottom;
877 vert[1].Red = GetRValue(gradient2) << 8;
878 vert[1].Green = GetGValue(gradient2) << 8;
879 vert[1].Blue = GetBValue(gradient2) << 8;
880 vert[1].Alpha = 0x0000;
881
882 gRect.UpperLeft = 0;
883 gRect.LowerRight = 1;
884 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
885 }
886 else if(filltype == FT_RADIALGRADIENT) {
887 /* I've never seen this used in a theme */
888 FIXME("Radial gradient\n");
889 }
890 else if(filltype == FT_TILEIMAGE) {
891 /* I've never seen this used in a theme */
892 FIXME("Tile image\n");
893 }
894 return hr;
895 }
896
897 /***********************************************************************
898 * UXTHEME_DrawBorderBackground
899 *
900 * Draw an imagefile background
901 */
902 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
903 int iStateId, const RECT *pRect,
904 const DTBGOPTS *pOptions)
905 {
906 HRESULT hr;
907 RECT rt;
908
909 CopyRect(&rt, pRect);
910
911 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
912 if(FAILED(hr))
913 return hr;
914 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
915 }
916
917 /***********************************************************************
918 * DrawThemeBackgroundEx (UXTHEME.@)
919 */
920 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
921 int iStateId, const RECT *pRect,
922 const DTBGOPTS *pOptions)
923 {
924 HRESULT hr;
925 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
926 const DTBGOPTS *opts;
927 HRGN clip = NULL;
928 int hasClip = -1;
929 int bgtype = BT_BORDERFILL;
930 RECT rt;
931
932 TRACE("(%p,%p,%d,%d,%ld,%ld)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
933 if(!hTheme)
934 return E_HANDLE;
935
936 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
937 if (bgtype == BT_NONE) return S_OK;
938
939 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
940 opts = pOptions;
941 if(!opts) opts = &defaultOpts;
942
943 if(opts->dwFlags & DTBG_CLIPRECT) {
944 clip = CreateRectRgn(0,0,1,1);
945 hasClip = GetClipRgn(hdc, clip);
946 if(hasClip == -1)
947 TRACE("Failed to get original clipping region\n");
948 else
949 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
950 }
951 CopyRect(&rt, pRect);
952
953 if(bgtype == BT_IMAGEFILE)
954 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
955 else if(bgtype == BT_BORDERFILL)
956 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
957 else {
958 FIXME("Unknown background type\n");
959 /* This should never happen, and hence I don't know what to return */
960 hr = E_FAIL;
961 }
962 if(SUCCEEDED(hr))
963 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
964 if(opts->dwFlags & DTBG_CLIPRECT) {
965 if(hasClip == 0)
966 SelectClipRgn(hdc, NULL);
967 else if(hasClip == 1)
968 SelectClipRgn(hdc, clip);
969 DeleteObject(clip);
970 }
971 return hr;
972 }
973
974 /*
975 * DrawThemeEdge() implementation
976 *
977 * Since it basically is DrawEdge() with different colors, I copied its code
978 * from user32's uitools.c.
979 */
980
981 enum
982 {
983 EDGE_LIGHT,
984 EDGE_HIGHLIGHT,
985 EDGE_SHADOW,
986 EDGE_DARKSHADOW,
987 EDGE_FILL,
988
989 EDGE_WINDOW,
990 EDGE_WINDOWFRAME,
991
992 EDGE_NUMCOLORS
993 };
994
995 static const struct
996 {
997 int themeProp;
998 int sysColor;
999 } EdgeColorMap[EDGE_NUMCOLORS] = {
1000 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1001 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1002 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1003 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1004 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1005 {-1, COLOR_WINDOW},
1006 {-1, COLOR_WINDOWFRAME}
1007 };
1008
1009 static const signed char LTInnerNormal[] = {
1010 -1, -1, -1, -1,
1011 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1012 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1013 -1, -1, -1, -1
1014 };
1015
1016 static const signed char LTOuterNormal[] = {
1017 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1018 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1019 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1020 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1021 };
1022
1023 static const signed char RBInnerNormal[] = {
1024 -1, -1, -1, -1,
1025 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1026 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1027 -1, -1, -1, -1
1028 };
1029
1030 static const signed char RBOuterNormal[] = {
1031 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1032 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1033 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1034 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1035 };
1036
1037 static const signed char LTInnerSoft[] = {
1038 -1, -1, -1, -1,
1039 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1040 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1041 -1, -1, -1, -1
1042 };
1043
1044 static const signed char LTOuterSoft[] = {
1045 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1046 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1047 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1048 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1049 };
1050
1051 #define RBInnerSoft RBInnerNormal /* These are the same */
1052 #define RBOuterSoft RBOuterNormal
1053
1054 static const signed char LTRBOuterMono[] = {
1055 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1056 EDGE_WINDOW, 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 };
1060
1061 static const signed char LTRBInnerMono[] = {
1062 -1, -1, -1, -1,
1063 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1064 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1065 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1066 };
1067
1068 static const signed char LTRBOuterFlat[] = {
1069 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1070 EDGE_FILL, 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 };
1074
1075 static const signed char LTRBInnerFlat[] = {
1076 -1, -1, -1, -1,
1077 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1078 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1079 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1080 };
1081
1082 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1083 {
1084 COLORREF col;
1085 if ((EdgeColorMap[edgeType].themeProp == -1)
1086 || FAILED (GetThemeColor (theme, part, state,
1087 EdgeColorMap[edgeType].themeProp, &col)))
1088 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1089 return col;
1090 }
1091
1092 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1093 {
1094 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1095 }
1096
1097 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1098 {
1099 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1100 }
1101
1102 /***********************************************************************
1103 * draw_diag_edge
1104 *
1105 * Same as DrawEdge invoked with BF_DIAGONAL
1106 */
1107 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1108 const RECT* rc, UINT uType,
1109 UINT uFlags, LPRECT contentsRect)
1110 {
1111 POINT Points[4];
1112 signed char InnerI, OuterI;
1113 HPEN InnerPen, OuterPen;
1114 POINT SavePoint;
1115 HPEN SavePen;
1116 int spx, spy;
1117 int epx, epy;
1118 int Width = rc->right - rc->left;
1119 int Height= rc->bottom - rc->top;
1120 int SmallDiam = Width > Height ? Height : Width;
1121 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1122 || (uType & BDR_OUTER) == BDR_OUTER)
1123 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1124 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1125 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1126
1127 /* Init some vars */
1128 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1129 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1130 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1131
1132 /* Determine the colors of the edges */
1133 if(uFlags & BF_MONO)
1134 {
1135 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1136 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1137 }
1138 else if(uFlags & BF_FLAT)
1139 {
1140 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1141 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1142 }
1143 else if(uFlags & BF_SOFT)
1144 {
1145 if(uFlags & BF_BOTTOM)
1146 {
1147 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1148 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1149 }
1150 else
1151 {
1152 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1153 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1154 }
1155 }
1156 else
1157 {
1158 if(uFlags & BF_BOTTOM)
1159 {
1160 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1161 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1162 }
1163 else
1164 {
1165 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1166 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1167 }
1168 }
1169
1170 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1171 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1172
1173 MoveToEx(hdc, 0, 0, &SavePoint);
1174
1175 /* Don't ask me why, but this is what is visible... */
1176 /* This must be possible to do much simpler, but I fail to */
1177 /* see the logic in the MS implementation (sigh...). */
1178 /* So, this might look a bit brute force here (and it is), but */
1179 /* it gets the job done;) */
1180
1181 switch(uFlags & BF_RECT)
1182 {
1183 case 0:
1184 case BF_LEFT:
1185 case BF_BOTTOM:
1186 case BF_BOTTOMLEFT:
1187 /* Left bottom endpoint */
1188 epx = rc->left-1;
1189 spx = epx + SmallDiam;
1190 epy = rc->bottom;
1191 spy = epy - SmallDiam;
1192 break;
1193
1194 case BF_TOPLEFT:
1195 case BF_BOTTOMRIGHT:
1196 /* Left top endpoint */
1197 epx = rc->left-1;
1198 spx = epx + SmallDiam;
1199 epy = rc->top-1;
1200 spy = epy + SmallDiam;
1201 break;
1202
1203 case BF_TOP:
1204 case BF_RIGHT:
1205 case BF_TOPRIGHT:
1206 case BF_RIGHT|BF_LEFT:
1207 case BF_RIGHT|BF_LEFT|BF_TOP:
1208 case BF_BOTTOM|BF_TOP:
1209 case BF_BOTTOM|BF_TOP|BF_LEFT:
1210 case BF_BOTTOMRIGHT|BF_LEFT:
1211 case BF_BOTTOMRIGHT|BF_TOP:
1212 case BF_RECT:
1213 /* Right top endpoint */
1214 spx = rc->left;
1215 epx = spx + SmallDiam;
1216 spy = rc->bottom-1;
1217 epy = spy - SmallDiam;
1218 break;
1219 }
1220
1221 MoveToEx(hdc, spx, spy, NULL);
1222 SelectObject(hdc, OuterPen);
1223 LineTo(hdc, epx, epy);
1224
1225 SelectObject(hdc, InnerPen);
1226
1227 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1228 {
1229 case BF_DIAGONAL_ENDBOTTOMLEFT:
1230 case (BF_DIAGONAL|BF_BOTTOM):
1231 case BF_DIAGONAL:
1232 case (BF_DIAGONAL|BF_LEFT):
1233 MoveToEx(hdc, spx-1, spy, NULL);
1234 LineTo(hdc, epx, epy-1);
1235 Points[0].x = spx-add;
1236 Points[0].y = spy;
1237 Points[1].x = rc->left;
1238 Points[1].y = rc->top;
1239 Points[2].x = epx+1;
1240 Points[2].y = epy-1-add;
1241 Points[3] = Points[2];
1242 break;
1243
1244 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1245 MoveToEx(hdc, spx-1, spy, NULL);
1246 LineTo(hdc, epx, epy+1);
1247 Points[0].x = spx-add;
1248 Points[0].y = spy;
1249 Points[1].x = rc->left;
1250 Points[1].y = rc->bottom-1;
1251 Points[2].x = epx+1;
1252 Points[2].y = epy+1+add;
1253 Points[3] = Points[2];
1254 break;
1255
1256 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1257 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1258 case BF_DIAGONAL_ENDTOPRIGHT:
1259 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1260 MoveToEx(hdc, spx+1, spy, NULL);
1261 LineTo(hdc, epx, epy+1);
1262 Points[0].x = epx-1;
1263 Points[0].y = epy+1+add;
1264 Points[1].x = rc->right-1;
1265 Points[1].y = rc->top+add;
1266 Points[2].x = rc->right-1;
1267 Points[2].y = rc->bottom-1;
1268 Points[3].x = spx+add;
1269 Points[3].y = spy;
1270 break;
1271
1272 case BF_DIAGONAL_ENDTOPLEFT:
1273 MoveToEx(hdc, spx, spy-1, NULL);
1274 LineTo(hdc, epx+1, epy);
1275 Points[0].x = epx+1+add;
1276 Points[0].y = epy+1;
1277 Points[1].x = rc->right-1;
1278 Points[1].y = rc->top;
1279 Points[2].x = rc->right-1;
1280 Points[2].y = rc->bottom-1-add;
1281 Points[3].x = spx;
1282 Points[3].y = spy-add;
1283 break;
1284
1285 case (BF_DIAGONAL|BF_TOP):
1286 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1287 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1288 MoveToEx(hdc, spx+1, spy-1, NULL);
1289 LineTo(hdc, epx, epy);
1290 Points[0].x = epx-1;
1291 Points[0].y = epy+1;
1292 Points[1].x = rc->right-1;
1293 Points[1].y = rc->top;
1294 Points[2].x = rc->right-1;
1295 Points[2].y = rc->bottom-1-add;
1296 Points[3].x = spx+add;
1297 Points[3].y = spy-add;
1298 break;
1299
1300 case (BF_DIAGONAL|BF_RIGHT):
1301 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1302 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1303 MoveToEx(hdc, spx, spy, NULL);
1304 LineTo(hdc, epx-1, epy+1);
1305 Points[0].x = spx;
1306 Points[0].y = spy;
1307 Points[1].x = rc->left;
1308 Points[1].y = rc->top+add;
1309 Points[2].x = epx-1-add;
1310 Points[2].y = epy+1+add;
1311 Points[3] = Points[2];
1312 break;
1313 }
1314
1315 /* Fill the interior if asked */
1316 if((uFlags & BF_MIDDLE) && retval)
1317 {
1318 HBRUSH hbsave;
1319 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1320 theme, part, state);
1321 HPEN hpsave;
1322 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1323 theme, part, state);
1324 hbsave = (HBRUSH)SelectObject(hdc, hb);
1325 hpsave = (HPEN)SelectObject(hdc, hp);
1326 Polygon(hdc, Points, 4);
1327 SelectObject(hdc, hbsave);
1328 SelectObject(hdc, hpsave);
1329 DeleteObject (hp);
1330 DeleteObject (hb);
1331 }
1332
1333 /* Adjust rectangle if asked */
1334 if(uFlags & BF_ADJUST)
1335 {
1336 *contentsRect = *rc;
1337 if(uFlags & BF_LEFT) contentsRect->left += add;
1338 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1339 if(uFlags & BF_TOP) contentsRect->top += add;
1340 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1341 }
1342
1343 /* Cleanup */
1344 SelectObject(hdc, SavePen);
1345 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1346 if(InnerI != -1) DeleteObject (InnerPen);
1347 if(OuterI != -1) DeleteObject (OuterPen);
1348
1349 return retval;
1350 }
1351
1352 /***********************************************************************
1353 * draw_rect_edge
1354 *
1355 * Same as DrawEdge invoked without BF_DIAGONAL
1356 */
1357 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1358 const RECT* rc, UINT uType,
1359 UINT uFlags, LPRECT contentsRect)
1360 {
1361 signed char LTInnerI, LTOuterI;
1362 signed char RBInnerI, RBOuterI;
1363 HPEN LTInnerPen, LTOuterPen;
1364 HPEN RBInnerPen, RBOuterPen;
1365 RECT InnerRect = *rc;
1366 POINT SavePoint;
1367 HPEN SavePen;
1368 int LBpenplus = 0;
1369 int LTpenplus = 0;
1370 int RTpenplus = 0;
1371 int RBpenplus = 0;
1372 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1373 || (uType & BDR_OUTER) == BDR_OUTER)
1374 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1375
1376 /* Init some vars */
1377 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1378 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1379
1380 /* Determine the colors of the edges */
1381 if(uFlags & BF_MONO)
1382 {
1383 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1384 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1385 }
1386 else if(uFlags & BF_FLAT)
1387 {
1388 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1389 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1390
1391 if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
1392 }
1393 else if(uFlags & BF_SOFT)
1394 {
1395 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1396 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1397 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1398 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1399 }
1400 else
1401 {
1402 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1403 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1404 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1405 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1406 }
1407
1408 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1409 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1410 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1411 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1412
1413 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1414 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1415 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1416 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1417
1418 MoveToEx(hdc, 0, 0, &SavePoint);
1419
1420 /* Draw the outer edge */
1421 SelectObject(hdc, LTOuterPen);
1422 if(uFlags & BF_TOP)
1423 {
1424 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1425 LineTo(hdc, InnerRect.right, InnerRect.top);
1426 }
1427 if(uFlags & BF_LEFT)
1428 {
1429 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1430 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1431 }
1432 SelectObject(hdc, RBOuterPen);
1433 if(uFlags & BF_BOTTOM)
1434 {
1435 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1436 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1437 }
1438 if(uFlags & BF_RIGHT)
1439 {
1440 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1441 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1442 }
1443
1444 /* Draw the inner edge */
1445 SelectObject(hdc, LTInnerPen);
1446 if(uFlags & BF_TOP)
1447 {
1448 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1449 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1450 }
1451 if(uFlags & BF_LEFT)
1452 {
1453 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1454 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1455 }
1456 SelectObject(hdc, RBInnerPen);
1457 if(uFlags & BF_BOTTOM)
1458 {
1459 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1460 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1461 }
1462 if(uFlags & BF_RIGHT)
1463 {
1464 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1465 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1466 }
1467
1468 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1469 {
1470 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1471 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1472
1473 if(uFlags & BF_LEFT) InnerRect.left += add;
1474 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1475 if(uFlags & BF_TOP) InnerRect.top += add;
1476 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1477
1478 if((uFlags & BF_MIDDLE) && retval)
1479 {
1480 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1481 theme, part, state);
1482 FillRect(hdc, &InnerRect, br);
1483 DeleteObject (br);
1484 }
1485
1486 if(uFlags & BF_ADJUST)
1487 *contentsRect = InnerRect;
1488 }
1489
1490 /* Cleanup */
1491 SelectObject(hdc, SavePen);
1492 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1493 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1494 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1495 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1496 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1497 return retval;
1498 }
1499
1500
1501 /***********************************************************************
1502 * DrawThemeEdge (UXTHEME.@)
1503 *
1504 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1505 * difference is that it does not rely on the system colors alone, but
1506 * also allows color specification in the theme.
1507 */
1508 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1509 int iStateId, const RECT *pDestRect, UINT uEdge,
1510 UINT uFlags, RECT *pContentRect)
1511 {
1512 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1513 if(!hTheme)
1514 return E_HANDLE;
1515
1516 if(uFlags & BF_DIAGONAL)
1517 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1518 uEdge, uFlags, pContentRect);
1519 else
1520 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1521 uEdge, uFlags, pContentRect);
1522 }
1523
1524
1525 /***********************************************************************
1526 * DrawThemeIcon (UXTHEME.@)
1527 */
1528 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1529 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1530 {
1531 FIXME("%d %d: stub\n", iPartId, iStateId);
1532 if(!hTheme)
1533 return E_HANDLE;
1534 return ERROR_CALL_NOT_IMPLEMENTED;
1535 }
1536
1537 /***********************************************************************
1538 * DrawThemeText (UXTHEME.@)
1539 */
1540 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1541 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1542 DWORD dwTextFlags2, const RECT *pRect)
1543 {
1544 HRESULT hr;
1545 HFONT hFont = NULL;
1546 HGDIOBJ oldFont = NULL;
1547 LOGFONTW logfont;
1548 COLORREF textColor;
1549 COLORREF oldTextColor;
1550 int oldBkMode;
1551 RECT rt;
1552
1553 TRACE("%d %d: stub\n", iPartId, iStateId);
1554 if(!hTheme)
1555 return E_HANDLE;
1556
1557 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1558 if(SUCCEEDED(hr)) {
1559 hFont = CreateFontIndirectW(&logfont);
1560 if(!hFont)
1561 TRACE("Failed to create font\n");
1562 }
1563 CopyRect(&rt, pRect);
1564 if(hFont)
1565 oldFont = SelectObject(hdc, hFont);
1566
1567 if(dwTextFlags2 & DTT_GRAYED)
1568 textColor = GetSysColor(COLOR_GRAYTEXT);
1569 else {
1570 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1571 textColor = GetTextColor(hdc);
1572 }
1573 oldTextColor = SetTextColor(hdc, textColor);
1574 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1575 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1576 SetBkMode(hdc, oldBkMode);
1577 SetTextColor(hdc, oldTextColor);
1578
1579 if(hFont) {
1580 SelectObject(hdc, oldFont);
1581 DeleteObject(hFont);
1582 }
1583 return S_OK;
1584 }
1585
1586 /***********************************************************************
1587 * GetThemeBackgroundContentRect (UXTHEME.@)
1588 */
1589 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1590 int iStateId,
1591 const RECT *pBoundingRect,
1592 RECT *pContentRect)
1593 {
1594 MARGINS margin;
1595 HRESULT hr;
1596
1597 TRACE("(%d,%d)\n", iPartId, iStateId);
1598 if(!hTheme)
1599 return E_HANDLE;
1600
1601 /* try content margins property... */
1602 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1603 if(SUCCEEDED(hr)) {
1604 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1605 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1606 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1607 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1608 } else {
1609 /* otherwise, try to determine content rect from the background type and props */
1610 int bgtype = BT_BORDERFILL;
1611 memcpy(pContentRect, pBoundingRect, sizeof(RECT));
1612
1613 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1614 if(bgtype == BT_BORDERFILL) {
1615 int bordersize = 1;
1616
1617 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1618 InflateRect(pContentRect, -bordersize, -bordersize);
1619 } else if ((bgtype == BT_IMAGEFILE)
1620 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1621 TMT_SIZINGMARGINS, NULL, &margin)))) {
1622 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1623 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1624 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1625 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1626 }
1627 /* If nothing was found, leave unchanged */
1628 }
1629
1630 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1631
1632 return S_OK;
1633 }
1634
1635 /***********************************************************************
1636 * GetThemeBackgroundExtent (UXTHEME.@)
1637 */
1638 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1639 int iStateId, const RECT *pContentRect,
1640 RECT *pExtentRect)
1641 {
1642 MARGINS margin;
1643 HRESULT hr;
1644
1645 TRACE("(%d,%d)\n", iPartId, iStateId);
1646 if(!hTheme)
1647 return E_HANDLE;
1648
1649 /* try content margins property... */
1650 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1651 if(SUCCEEDED(hr)) {
1652 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1653 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1654 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1655 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1656 } else {
1657 /* otherwise, try to determine content rect from the background type and props */
1658 int bgtype = BT_BORDERFILL;
1659 memcpy(pExtentRect, pContentRect, sizeof(RECT));
1660
1661 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1662 if(bgtype == BT_BORDERFILL) {
1663 int bordersize = 1;
1664
1665 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1666 InflateRect(pExtentRect, bordersize, bordersize);
1667 } else if ((bgtype == BT_IMAGEFILE)
1668 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1669 TMT_SIZINGMARGINS, NULL, &margin)))) {
1670 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1671 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1672 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1673 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1674 }
1675 /* If nothing was found, leave unchanged */
1676 }
1677
1678 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1679
1680 return S_OK;
1681 }
1682
1683 /***********************************************************************
1684 * GetThemeBackgroundRegion (UXTHEME.@)
1685 *
1686 * Calculate the background region, taking into consideration transparent areas
1687 * of the background image.
1688 */
1689 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1690 int iStateId, const RECT *pRect,
1691 HRGN *pRegion)
1692 {
1693 HRESULT hr = S_OK;
1694 int bgtype = BT_BORDERFILL;
1695
1696 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1697 if(!hTheme)
1698 return E_HANDLE;
1699 if(!pRect || !pRegion)
1700 return E_POINTER;
1701
1702 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1703 if(bgtype == BT_IMAGEFILE) {
1704 FIXME("Images not handled yet\n");
1705 hr = ERROR_CALL_NOT_IMPLEMENTED;
1706 }
1707 else if(bgtype == BT_BORDERFILL) {
1708 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1709 if(!*pRegion)
1710 hr = HRESULT_FROM_WIN32(GetLastError());
1711 }
1712 else {
1713 FIXME("Unknown background type\n");
1714 /* This should never happen, and hence I don't know what to return */
1715 hr = E_FAIL;
1716 }
1717 return hr;
1718 }
1719
1720 /* compute part size for "borderfill" backgrounds */
1721 HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1722 int iStateId, THEMESIZE eSize, POINT* psz)
1723 {
1724 HRESULT hr = S_OK;
1725 int bordersize = 1;
1726
1727 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1728 &bordersize)))
1729 {
1730 psz->x = psz->y = 2*bordersize;
1731 if (eSize != TS_MIN)
1732 {
1733 psz->x++;
1734 psz->y++;
1735 }
1736 }
1737 return hr;
1738 }
1739
1740 /***********************************************************************
1741 * GetThemePartSize (UXTHEME.@)
1742 */
1743 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1744 int iStateId, RECT *prc, THEMESIZE eSize,
1745 SIZE *psz)
1746 {
1747 int bgtype = BT_BORDERFILL;
1748 HRESULT hr = S_OK;
1749 POINT size = {1, 1};
1750
1751 if(!hTheme)
1752 return E_HANDLE;
1753
1754 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1755 if (bgtype == BT_NONE)
1756 /* do nothing */;
1757 else if(bgtype == BT_IMAGEFILE)
1758 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1759 else if(bgtype == BT_BORDERFILL)
1760 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1761 else {
1762 FIXME("Unknown background type\n");
1763 /* This should never happen, and hence I don't know what to return */
1764 hr = E_FAIL;
1765 }
1766 psz->cx = size.x;
1767 psz->cy = size.y;
1768 return hr;
1769 }
1770
1771
1772 /***********************************************************************
1773 * GetThemeTextExtent (UXTHEME.@)
1774 */
1775 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1776 int iStateId, LPCWSTR pszText, int iCharCount,
1777 DWORD dwTextFlags, const RECT *pBoundingRect,
1778 RECT *pExtentRect)
1779 {
1780 HRESULT hr;
1781 HFONT hFont = NULL;
1782 HGDIOBJ oldFont = NULL;
1783 LOGFONTW logfont;
1784 RECT rt = {0,0,0xFFFF,0xFFFF};
1785
1786 TRACE("%d %d: stub\n", iPartId, iStateId);
1787 if(!hTheme)
1788 return E_HANDLE;
1789
1790 if(pBoundingRect)
1791 CopyRect(&rt, pBoundingRect);
1792
1793 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1794 if(SUCCEEDED(hr)) {
1795 hFont = CreateFontIndirectW(&logfont);
1796 if(!hFont)
1797 TRACE("Failed to create font\n");
1798 }
1799 if(hFont)
1800 oldFont = SelectObject(hdc, hFont);
1801
1802 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1803 CopyRect(pExtentRect, &rt);
1804
1805 if(hFont) {
1806 SelectObject(hdc, oldFont);
1807 DeleteObject(hFont);
1808 }
1809 return S_OK;
1810 }
1811
1812 /***********************************************************************
1813 * GetThemeTextMetrics (UXTHEME.@)
1814 */
1815 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1816 int iStateId, TEXTMETRICW *ptm)
1817 {
1818 HRESULT hr;
1819 HFONT hFont = NULL;
1820 HGDIOBJ oldFont = NULL;
1821 LOGFONTW logfont;
1822
1823 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1824 if(!hTheme)
1825 return E_HANDLE;
1826
1827 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1828 if(SUCCEEDED(hr)) {
1829 hFont = CreateFontIndirectW(&logfont);
1830 if(!hFont)
1831 TRACE("Failed to create font\n");
1832 }
1833 if(hFont)
1834 oldFont = SelectObject(hdc, hFont);
1835
1836 if(!GetTextMetricsW(hdc, ptm))
1837 hr = HRESULT_FROM_WIN32(GetLastError());
1838
1839 if(hFont) {
1840 SelectObject(hdc, oldFont);
1841 DeleteObject(hFont);
1842 }
1843 return hr;
1844 }
1845
1846 /***********************************************************************
1847 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1848 */
1849 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1850 int iStateId)
1851 {
1852 int bgtype = BT_BORDERFILL;
1853 RECT rect = {0, 0, 0, 0};
1854 HBITMAP bmpSrc;
1855 RECT rcSrc;
1856 BOOL hasAlpha;
1857 INT transparent;
1858 COLORREF transparentcolor;
1859
1860 TRACE("(%d,%d)\n", iPartId, iStateId);
1861
1862 if(!hTheme)
1863 return FALSE;
1864
1865 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1866
1867 if (bgtype != BT_IMAGEFILE) return FALSE;
1868
1869 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1870 &bmpSrc, &rcSrc, &hasAlpha)))
1871 return FALSE;
1872
1873 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1874 &transparentcolor, FALSE);
1875 return (transparent != ALPHABLEND_NONE);
1876 }