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 */
EnableThemeDialogTexture(HWND hwnd,DWORD dwFlags)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 S_OK;
51 }
52
53 /***********************************************************************
54 * IsThemeDialogTextureEnabled (UXTHEME.@)
55 */
IsThemeDialogTextureEnabled(HWND hwnd)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 */
DrawThemeParentBackground(HWND hwnd,HDC hdc,RECT * prc)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 */
DrawThemeBackground(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,const RECT * pClipRect)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 */
UXTHEME_SelectImage(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,BOOL glyph)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 */
UXTHEME_LoadImage(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,BOOL glyph,HBITMAP * hBmp,RECT * bmpRect,BOOL * hasImageAlpha)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. */
get_transparency(HTHEME hTheme,int iPartId,int iStateId,BOOL hasImageAlpha,INT * transparent,COLORREF * transparentcolor,BOOL glyph)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 */
UXTHEME_DrawImageGlyph(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * pRect,const DTBGOPTS * pOptions)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 */
UXTHEME_DrawGlyph(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * pRect,const DTBGOPTS * pOptions)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 */
get_image_part_size(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * prc,THEMESIZE eSize,POINT * psz)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 */
UXTHEME_DrawImageBackground(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * pRect,const DTBGOPTS * pOptions)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 */
UXTHEME_DrawBorderRectangle(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * pRect,const DTBGOPTS * pOptions)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 */
UXTHEME_DrawBackgroundFill(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * pRect,const DTBGOPTS * pOptions)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 */
UXTHEME_DrawBorderBackground(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,const DTBGOPTS * pOptions)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 */
DrawThemeBackgroundEx(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,const DTBGOPTS * pOptions)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
get_edge_color(int edgeType,HTHEME theme,int part,int state)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
get_edge_pen(int edgeType,HTHEME theme,int part,int state)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
get_edge_brush(int edgeType,HTHEME theme,int part,int state)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 */
draw_diag_edge(HDC hdc,HTHEME theme,int part,int state,const RECT * rc,UINT uType,UINT uFlags,LPRECT contentsRect)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 */
draw_rect_edge(HDC hdc,HTHEME theme,int part,int state,const RECT * rc,UINT uType,UINT uFlags,LPRECT contentsRect)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 */
DrawThemeEdge(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pDestRect,UINT uEdge,UINT uFlags,RECT * pContentRect)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 */
DrawThemeIcon(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,HIMAGELIST himl,int iImageIndex)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 * DrawThemeTextEx (UXTHEME.@)
1376 */
1377 HRESULT
1378 WINAPI
DrawThemeTextEx(_In_ HTHEME hTheme,_In_ HDC hdc,_In_ int iPartId,_In_ int iStateId,_In_ LPCWSTR pszText,_In_ int iCharCount,_In_ DWORD dwTextFlags,_Inout_ LPRECT pRect,_In_ const DTTOPTS * options)1379 DrawThemeTextEx(
1380 _In_ HTHEME hTheme,
1381 _In_ HDC hdc,
1382 _In_ int iPartId,
1383 _In_ int iStateId,
1384 _In_ LPCWSTR pszText,
1385 _In_ int iCharCount,
1386 _In_ DWORD dwTextFlags,
1387 _Inout_ LPRECT pRect,
1388 _In_ const DTTOPTS *options
1389 )
1390 {
1391 HRESULT hr;
1392 HFONT hFont = NULL;
1393 HGDIOBJ oldFont = NULL;
1394 LOGFONTW logfont;
1395 COLORREF textColor;
1396 COLORREF oldTextColor;
1397 COLORREF shadowColor;
1398 POINT ptShadowOffset;
1399 int oldBkMode;
1400 RECT rt;
1401 int iShadowType;
1402 DWORD optFlags;
1403
1404 if(!hTheme)
1405 return E_HANDLE;
1406 if (!options)
1407 return E_NOTIMPL;
1408
1409 optFlags = options->dwFlags;
1410
1411 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1412 if(SUCCEEDED(hr))
1413 {
1414 hFont = CreateFontIndirectW(&logfont);
1415 if(!hFont)
1416 {
1417 ERR("Failed to create font\n");
1418 }
1419 }
1420
1421 CopyRect(&rt, pRect);
1422 if(hFont)
1423 oldFont = SelectObject(hdc, hFont);
1424
1425 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1426
1427 if (optFlags & DTT_TEXTCOLOR)
1428 {
1429 textColor = options->crText;
1430 }
1431 else
1432 {
1433 int textColorProp = TMT_TEXTCOLOR;
1434 if (optFlags & DTT_COLORPROP)
1435 textColorProp = options->iColorPropId;
1436
1437 if (FAILED(GetThemeColor(hTheme, iPartId, iStateId, textColorProp, &textColor)))
1438 textColor = GetTextColor(hdc);
1439 }
1440
1441 hr = GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_TEXTSHADOWTYPE, &iShadowType);
1442 if (SUCCEEDED(hr))
1443 {
1444 hr = GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTSHADOWCOLOR, &shadowColor);
1445 if (FAILED(hr))
1446 {
1447 ERR("GetThemeColor failed\n");
1448 }
1449
1450 hr = GetThemePosition(hTheme, iPartId, iStateId, TMT_TEXTSHADOWOFFSET, &ptShadowOffset);
1451 if (FAILED(hr))
1452 {
1453 ERR("GetThemePosition failed\n");
1454 }
1455
1456 if (iShadowType == TST_SINGLE)
1457 {
1458 oldTextColor = SetTextColor(hdc, shadowColor);
1459 OffsetRect(&rt, ptShadowOffset.x, ptShadowOffset.y);
1460 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1461 OffsetRect(&rt, -ptShadowOffset.x, -ptShadowOffset.y);
1462 SetTextColor(hdc, oldTextColor);
1463 }
1464 else if (iShadowType == TST_CONTINUOUS)
1465 {
1466 HANDLE hcomctl32 = GetModuleHandleW(L"comctl32.dll");
1467 DRAWSHADOWTEXT pDrawShadowText;
1468 if (!hcomctl32)
1469 {
1470 hcomctl32 = LoadLibraryW(L"comctl32.dll");
1471 if (!hcomctl32)
1472 ERR("Failed to load comctl32\n");
1473 }
1474
1475 pDrawShadowText = (DRAWSHADOWTEXT)GetProcAddress(hcomctl32, "DrawShadowText");
1476 if (pDrawShadowText)
1477 {
1478 pDrawShadowText(hdc, pszText, iCharCount, &rt, dwTextFlags, textColor, shadowColor, ptShadowOffset.x, ptShadowOffset.y);
1479 goto cleanup;
1480 }
1481 }
1482 }
1483
1484 oldTextColor = SetTextColor(hdc, textColor);
1485 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1486 SetTextColor(hdc, oldTextColor);
1487 cleanup:
1488 SetBkMode(hdc, oldBkMode);
1489
1490 if(hFont) {
1491 SelectObject(hdc, oldFont);
1492 DeleteObject(hFont);
1493 }
1494 return S_OK;
1495 }
1496
1497 /***********************************************************************
1498 * DrawThemeText (UXTHEME.@)
1499 */
DrawThemeText(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,LPCWSTR pszText,int iCharCount,DWORD dwTextFlags,DWORD dwTextFlags2,const RECT * pRect)1500 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1501 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1502 DWORD dwTextFlags2, const RECT *pRect)
1503 {
1504 DTTOPTS opts = { 0 };
1505 RECT rt = *pRect;
1506
1507 TRACE("(%p %p %d %d %s:%d 0x%08lx 0x%08lx %p)\n", hTheme, hdc, iPartId, iStateId,
1508 debugstr_wn(pszText, iCharCount), iCharCount, dwTextFlags, dwTextFlags2, pRect);
1509
1510 if (dwTextFlags2 & DTT_GRAYED)
1511 {
1512 opts.dwFlags = DTT_TEXTCOLOR;
1513 opts.crText = GetSysColor(COLOR_GRAYTEXT);
1514 }
1515 opts.dwSize = sizeof(opts);
1516
1517 return DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, &rt, &opts);
1518 }
1519
1520 /***********************************************************************
1521 * GetThemeBackgroundContentRect (UXTHEME.@)
1522 */
GetThemeBackgroundContentRect(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pBoundingRect,RECT * pContentRect)1523 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1524 int iStateId,
1525 const RECT *pBoundingRect,
1526 RECT *pContentRect)
1527 {
1528 MARGINS margin;
1529 HRESULT hr;
1530
1531 TRACE("(%d,%d)\n", iPartId, iStateId);
1532 if(!hTheme)
1533 return E_HANDLE;
1534
1535 /* try content margins property... */
1536 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1537 if(SUCCEEDED(hr)) {
1538 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1539 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1540 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1541 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1542 } else {
1543 /* otherwise, try to determine content rect from the background type and props */
1544 int bgtype = BT_BORDERFILL;
1545 *pContentRect = *pBoundingRect;
1546
1547 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1548 if(bgtype == BT_BORDERFILL) {
1549 int bordersize = 1;
1550
1551 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1552 InflateRect(pContentRect, -bordersize, -bordersize);
1553 } else if ((bgtype == BT_IMAGEFILE)
1554 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1555 TMT_SIZINGMARGINS, NULL, &margin)))) {
1556 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1557 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1558 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1559 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1560 }
1561 /* If nothing was found, leave unchanged */
1562 }
1563
1564 TRACE("%s\n", wine_dbgstr_rect(pContentRect));
1565
1566 return S_OK;
1567 }
1568
1569 /***********************************************************************
1570 * GetThemeBackgroundExtent (UXTHEME.@)
1571 */
GetThemeBackgroundExtent(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pContentRect,RECT * pExtentRect)1572 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1573 int iStateId, const RECT *pContentRect,
1574 RECT *pExtentRect)
1575 {
1576 MARGINS margin;
1577 HRESULT hr;
1578
1579 TRACE("(%d,%d)\n", iPartId, iStateId);
1580 if(!hTheme)
1581 return E_HANDLE;
1582
1583 /* try content margins property... */
1584 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1585 if(SUCCEEDED(hr)) {
1586 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1587 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1588 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1589 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1590 } else {
1591 /* otherwise, try to determine content rect from the background type and props */
1592 int bgtype = BT_BORDERFILL;
1593 *pExtentRect = *pContentRect;
1594
1595 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1596 if(bgtype == BT_BORDERFILL) {
1597 int bordersize = 1;
1598
1599 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1600 InflateRect(pExtentRect, bordersize, bordersize);
1601 } else if ((bgtype == BT_IMAGEFILE)
1602 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1603 TMT_SIZINGMARGINS, NULL, &margin)))) {
1604 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1605 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1606 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1607 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1608 }
1609 /* If nothing was found, leave unchanged */
1610 }
1611
1612 TRACE("%s\n", wine_dbgstr_rect(pExtentRect));
1613
1614 return S_OK;
1615 }
1616
1617
UXTHEME_DrawThemePartToDib(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,LPCRECT pRect)1618 static HBITMAP UXTHEME_DrawThemePartToDib(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect)
1619 {
1620 HDC hdcMem;
1621 BITMAPINFO bmi;
1622 HBITMAP hbmp, hbmpOld;
1623 HBRUSH hbrBack;
1624
1625 hdcMem = CreateCompatibleDC(0);
1626
1627 memset(&bmi, 0, sizeof(bmi));
1628 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1629 bmi.bmiHeader.biWidth = pRect->right;
1630 bmi.bmiHeader.biHeight = -pRect->bottom;
1631 bmi.bmiHeader.biPlanes = 1;
1632 bmi.bmiHeader.biBitCount = 32;
1633 hbmp = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS , NULL, 0, 0);
1634
1635 hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);
1636
1637 /* FIXME: use an internal function that doesn't do transparent blt */
1638 hbrBack = CreateSolidBrush(RGB(255,0,255));
1639
1640 FillRect(hdcMem, pRect, hbrBack);
1641
1642 DrawThemeBackground(hTheme, hdcMem, iPartId, iStateId, pRect, NULL);
1643
1644 DeleteObject(hbrBack);
1645 SelectObject(hdcMem, hbmpOld);
1646 DeleteObject(hdcMem);
1647
1648 return hbmp;
1649 }
1650
1651 #define PT_IN_RECT(lprc,x,y) ( x >= lprc->left && x < lprc->right && \
1652 y >= lprc->top && y < lprc->bottom)
1653
UXTHEME_RegionFromDibBits(RGBQUAD * pBuffer,RGBQUAD * pclrTransparent,LPCRECT pRect)1654 static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent, LPCRECT pRect)
1655 {
1656 int x, y, xstart;
1657 int cMaxRgnRects, cRgnDataSize, cRgnRects;
1658 RECT* prcCurrent;
1659 PRGNDATA prgnData;
1660 ULONG clrTransparent, *pclrCurrent;
1661 HRGN hrgnRet;
1662
1663 pclrCurrent = (PULONG)pBuffer;
1664 clrTransparent = *(PULONG)pclrTransparent;
1665
1666 /* Create a region and pre-allocate memory enough for 3 spaces in one row*/
1667 cRgnRects = 0;
1668 cMaxRgnRects = 4* (pRect->bottom-pRect->top);
1669 cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
1670
1671 /* Allocate the region data */
1672 prgnData = (PRGNDATA)HeapAlloc(GetProcessHeap(), 0, cRgnDataSize);
1673
1674 prcCurrent = (PRECT)prgnData->Buffer;
1675
1676 /* Calculate the region rects */
1677 y=0;
1678 /* Scan each line of the bitmap */
1679 while(y<pRect->bottom)
1680 {
1681 x=0;
1682 /* Scan each pixel */
1683 while (x<pRect->right)
1684 {
1685 /* Check if the pixel is not transparent and it is in the requested rect */
1686 if(*pclrCurrent != clrTransparent && PT_IN_RECT(pRect,x,y))
1687 {
1688 xstart = x;
1689 /* Find the end of the opaque row of pixels */
1690 while (x<pRect->right)
1691 {
1692 if(*pclrCurrent == clrTransparent || !PT_IN_RECT(pRect,x,y))
1693 break;
1694 x++;
1695 pclrCurrent++;
1696 }
1697
1698 /* Add the scaned line to the region */
1699 SetRect(prcCurrent, xstart, y,x,y+1);
1700 prcCurrent++;
1701 cRgnRects++;
1702
1703 /* Increase the size of the buffer if it is full */
1704 if(cRgnRects == cMaxRgnRects)
1705 {
1706 cMaxRgnRects *=2;
1707 cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
1708 prgnData = (PRGNDATA)HeapReAlloc(GetProcessHeap(),
1709 0,
1710 prgnData,
1711 cRgnDataSize);
1712 prcCurrent = (RECT*)prgnData->Buffer + cRgnRects;
1713 }
1714 }
1715 else
1716 {
1717 x++;
1718 pclrCurrent++;
1719 }
1720 }
1721 y++;
1722 }
1723
1724 /* Fill the region data header */
1725 prgnData->rdh.dwSize = sizeof(prgnData->rdh);
1726 prgnData->rdh.iType = RDH_RECTANGLES;
1727 prgnData->rdh.nCount = cRgnRects;
1728 prgnData->rdh.nRgnSize = cRgnDataSize;
1729 prgnData->rdh.rcBound = *pRect;
1730
1731 /* Create the region*/
1732 hrgnRet = ExtCreateRegion (NULL, cRgnDataSize, prgnData);
1733
1734 /* Free the region data*/
1735 HeapFree(GetProcessHeap(),0,prgnData);
1736
1737 /* return the region*/
1738 return hrgnRet;
1739 }
1740
UXTHEME_GetImageBackBackgroundRegion(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,LPCRECT pRect,HRGN * pRegion)1741 HRESULT UXTHEME_GetImageBackBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, HRGN *pRegion)
1742 {
1743 HBITMAP hbmp;
1744 DIBSECTION dib;
1745 RGBQUAD clrTransparent = {0xFF,0x0, 0xFF,0x0};
1746
1747 /* Draw the theme part to a dib */
1748 hbmp = UXTHEME_DrawThemePartToDib(hTheme, hdc, iPartId, iStateId, pRect);
1749
1750 /* Retrieve the info of the dib section */
1751 GetObjectW(hbmp, sizeof (DIBSECTION), &dib);
1752
1753 /* Convert the bits of the dib section to a region */
1754 *pRegion = UXTHEME_RegionFromDibBits((RGBQUAD*)dib.dsBm.bmBits, &clrTransparent, pRect);
1755
1756 /* Free the temp bitmap */
1757 DeleteObject(hbmp);
1758
1759 return S_OK;
1760 }
1761
1762 /***********************************************************************
1763 * GetThemeBackgroundRegion (UXTHEME.@)
1764 *
1765 * Calculate the background region, taking into consideration transparent areas
1766 * of the background image.
1767 */
GetThemeBackgroundRegion(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,HRGN * pRegion)1768 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1769 int iStateId, const RECT *pRect,
1770 HRGN *pRegion)
1771 {
1772 HRESULT hr = S_OK;
1773 int bgtype = BT_BORDERFILL;
1774
1775 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1776 if(!hTheme)
1777 return E_HANDLE;
1778 if(!pRect || !pRegion)
1779 return E_POINTER;
1780
1781 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1782 if(bgtype == BT_IMAGEFILE) {
1783 hr = UXTHEME_GetImageBackBackgroundRegion(hTheme, hdc, iPartId, iStateId, pRect, pRegion);
1784 }
1785 else if(bgtype == BT_BORDERFILL) {
1786 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1787 if(!*pRegion)
1788 hr = HRESULT_FROM_WIN32(GetLastError());
1789 }
1790 else {
1791 FIXME("Unknown background type\n");
1792 /* This should never happen, and hence I don't know what to return */
1793 hr = E_FAIL;
1794 }
1795 return hr;
1796 }
1797
1798 /* compute part size for "borderfill" backgrounds */
get_border_background_size(HTHEME hTheme,int iPartId,int iStateId,THEMESIZE eSize,POINT * psz)1799 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1800 int iStateId, THEMESIZE eSize, POINT* psz)
1801 {
1802 HRESULT hr = S_OK;
1803 int bordersize = 1;
1804
1805 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1806 &bordersize)))
1807 {
1808 psz->x = psz->y = 2*bordersize;
1809 if (eSize != TS_MIN)
1810 {
1811 psz->x++;
1812 psz->y++;
1813 }
1814 }
1815 return hr;
1816 }
1817
1818 /***********************************************************************
1819 * GetThemePartSize (UXTHEME.@)
1820 */
GetThemePartSize(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * prc,THEMESIZE eSize,SIZE * psz)1821 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1822 int iStateId, RECT *prc, THEMESIZE eSize,
1823 SIZE *psz)
1824 {
1825 int bgtype = BT_BORDERFILL;
1826 HRESULT hr = S_OK;
1827 POINT size = {1, 1};
1828
1829 if(!hTheme)
1830 return E_HANDLE;
1831
1832 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1833 if (bgtype == BT_NONE)
1834 /* do nothing */;
1835 else if(bgtype == BT_IMAGEFILE)
1836 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1837 else if(bgtype == BT_BORDERFILL)
1838 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1839 else {
1840 FIXME("Unknown background type\n");
1841 /* This should never happen, and hence I don't know what to return */
1842 hr = E_FAIL;
1843 }
1844 psz->cx = size.x;
1845 psz->cy = size.y;
1846 return hr;
1847 }
1848
1849
1850 /***********************************************************************
1851 * GetThemeTextExtent (UXTHEME.@)
1852 */
GetThemeTextExtent(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,LPCWSTR pszText,int iCharCount,DWORD dwTextFlags,const RECT * pBoundingRect,RECT * pExtentRect)1853 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1854 int iStateId, LPCWSTR pszText, int iCharCount,
1855 DWORD dwTextFlags, const RECT *pBoundingRect,
1856 RECT *pExtentRect)
1857 {
1858 HRESULT hr;
1859 HFONT hFont = NULL;
1860 HGDIOBJ oldFont = NULL;
1861 LOGFONTW logfont;
1862 RECT rt = {0,0,0xFFFF,0xFFFF};
1863
1864 TRACE("%d %d: stub\n", iPartId, iStateId);
1865 if(!hTheme)
1866 return E_HANDLE;
1867
1868 if(pBoundingRect)
1869 rt = *pBoundingRect;
1870
1871 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1872 if(SUCCEEDED(hr)) {
1873 hFont = CreateFontIndirectW(&logfont);
1874 if(!hFont)
1875 TRACE("Failed to create font\n");
1876 }
1877 if(hFont)
1878 oldFont = SelectObject(hdc, hFont);
1879
1880 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1881 *pExtentRect = rt;
1882
1883 if(hFont) {
1884 SelectObject(hdc, oldFont);
1885 DeleteObject(hFont);
1886 }
1887 return S_OK;
1888 }
1889
1890 /***********************************************************************
1891 * GetThemeTextMetrics (UXTHEME.@)
1892 */
GetThemeTextMetrics(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,TEXTMETRICW * ptm)1893 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1894 int iStateId, TEXTMETRICW *ptm)
1895 {
1896 HRESULT hr;
1897 HFONT hFont = NULL;
1898 HGDIOBJ oldFont = NULL;
1899 LOGFONTW logfont;
1900
1901 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1902 if(!hTheme)
1903 return E_HANDLE;
1904
1905 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1906 if(SUCCEEDED(hr)) {
1907 hFont = CreateFontIndirectW(&logfont);
1908 if(!hFont)
1909 TRACE("Failed to create font\n");
1910 }
1911 if(hFont)
1912 oldFont = SelectObject(hdc, hFont);
1913
1914 if(!GetTextMetricsW(hdc, ptm))
1915 hr = HRESULT_FROM_WIN32(GetLastError());
1916
1917 if(hFont) {
1918 SelectObject(hdc, oldFont);
1919 DeleteObject(hFont);
1920 }
1921 return hr;
1922 }
1923
1924 /***********************************************************************
1925 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1926 */
IsThemeBackgroundPartiallyTransparent(HTHEME hTheme,int iPartId,int iStateId)1927 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1928 int iStateId)
1929 {
1930 int bgtype = BT_BORDERFILL;
1931 RECT rect = {0, 0, 0, 0};
1932 HBITMAP bmpSrc;
1933 RECT rcSrc;
1934 BOOL hasAlpha;
1935 INT transparent;
1936 COLORREF transparentcolor;
1937
1938 TRACE("(%d,%d)\n", iPartId, iStateId);
1939
1940 if(!hTheme)
1941 return FALSE;
1942
1943 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1944
1945 #ifdef __REACTOS__
1946 if (bgtype == BT_NONE) return TRUE;
1947 #endif
1948 if (bgtype != BT_IMAGEFILE) return FALSE;
1949
1950 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1951 &bmpSrc, &rcSrc, &hasAlpha)))
1952 return FALSE;
1953
1954 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1955 &transparentcolor, FALSE);
1956 return (transparent != ALPHABLEND_NONE);
1957 }
1958