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