2 * Win32 5.1 Theme drawing
4 * Copyright (C) 2003 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "uxthemedll.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
41 /***********************************************************************
42 * Defines and global variables
45 extern ATOM atDialogThemeEnabled;
47 /***********************************************************************/
49 /***********************************************************************
50 * EnableThemeDialogTexture (UXTHEME.@)
52 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
54 static const WCHAR szTab[] = { 'T','a','b',0 };
57 TRACE("(%p,0x%08x\n", hwnd, dwFlags);
58 res = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled),
59 UlongToHandle(dwFlags|0x80000000));
60 /* 0x80000000 serves as a "flags set" flag */
62 return HRESULT_FROM_WIN32(GetLastError());
63 if (dwFlags & ETDT_USETABTEXTURE)
64 return SetWindowTheme (hwnd, NULL, szTab);
66 return SetWindowTheme (hwnd, NULL, NULL);
69 /***********************************************************************
70 * IsThemeDialogTextureEnabled (UXTHEME.@)
72 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
74 DWORD dwDialogTextureFlags;
75 TRACE("(%p)\n", hwnd);
77 dwDialogTextureFlags = HandleToUlong( GetPropW( hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled) ));
78 if (dwDialogTextureFlags == 0)
79 /* Means EnableThemeDialogTexture wasn't called for this dialog */
82 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
85 /***********************************************************************
86 * DrawThemeParentBackground (UXTHEME.@)
88 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
96 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
97 hParent = GetParent(hwnd);
102 MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2);
104 clip = CreateRectRgn(0,0,1,1);
105 hasClip = GetClipRgn(hdc, clip);
107 TRACE("Failed to get original clipping region\n");
109 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
112 GetClientRect(hwnd, &rt);
113 MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2);
116 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
118 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
119 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
121 SetViewportOrgEx(hdc, org.x, org.y, NULL);
124 SelectClipRgn(hdc, NULL);
125 else if(hasClip == 1)
126 SelectClipRgn(hdc, clip);
133 /***********************************************************************
134 * DrawThemeBackground (UXTHEME.@)
136 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
137 int iStateId, const RECT *pRect,
138 const RECT *pClipRect)
141 opts.dwSize = sizeof(DTBGOPTS);
144 opts.dwFlags |= DTBG_CLIPRECT;
145 CopyRect(&opts.rcClip, pClipRect);
147 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
150 /***********************************************************************
151 * UXTHEME_SelectImage
153 * Select the image to use
155 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
158 int imageselecttype = IST_NONE;
162 image = TMT_GLYPHIMAGEFILE;
164 image = TMT_IMAGEFILE;
166 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
168 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
170 if(imageselecttype == IST_DPI) {
172 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
173 for(i=4; i>=0; i--) {
175 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
176 if(reqdpi != 0 && screendpi >= reqdpi) {
177 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
178 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
182 /* If an image couldn't be selected, choose the first one */
183 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
185 else if(imageselecttype == IST_SIZE) {
186 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
188 for(i=4; i>=0; i--) {
189 PTHEME_PROPERTY fileProp =
190 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
191 if (!fileProp) continue;
192 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
193 /* fall back to size of Nth image */
194 WCHAR szPath[MAX_PATH];
195 int imagelayout = IL_HORIZONTAL;
201 lstrcpynW(szPath, fileProp->lpValue,
202 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
203 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
206 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
207 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
209 GetObjectW(hBmp, sizeof(bmp), &bmp);
210 if(imagelayout == IL_VERTICAL) {
211 reqsize.x = bmp.bmWidth;
212 reqsize.y = bmp.bmHeight/imagecount;
215 reqsize.x = bmp.bmWidth/imagecount;
216 reqsize.y = bmp.bmHeight;
219 if(reqsize.x <= size.x && reqsize.y <= size.y) {
220 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
224 /* If an image couldn't be selected, choose the smallest one */
225 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
230 /***********************************************************************
233 * Load image for part/state
235 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
236 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
238 int imagelayout = IL_HORIZONTAL;
242 WCHAR szPath[MAX_PATH];
243 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
245 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
246 return E_PROP_ID_UNSUPPORTED;
248 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
249 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
251 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
252 return HRESULT_FROM_WIN32(GetLastError());
255 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
256 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
258 imagenum = max (min (imagecount, iStateId), 1) - 1;
259 GetObjectW(*hBmp, sizeof(bmp), &bmp);
260 if(imagelayout == IL_VERTICAL) {
261 int height = bmp.bmHeight/imagecount;
263 bmpRect->right = bmp.bmWidth;
264 bmpRect->top = imagenum * height;
265 bmpRect->bottom = bmpRect->top + height;
268 int width = bmp.bmWidth/imagecount;
269 bmpRect->left = imagenum * width;
270 bmpRect->right = bmpRect->left + width;
272 bmpRect->bottom = bmp.bmHeight;
277 /***********************************************************************
280 * Pseudo TransparentBlt/StretchBlt
282 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
283 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
284 INT transparent, COLORREF transcolor)
286 static const BLENDFUNCTION blendFunc =
288 AC_SRC_OVER, /* BlendOp */
290 255, /* SourceConstantAlpha */
291 AC_SRC_ALPHA /* AlphaFormat */
293 if (transparent == ALPHABLEND_BINARY) {
294 /* Ensure we don't pass any negative values to TransparentBlt */
295 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
296 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
299 if ((transparent == ALPHABLEND_NONE) ||
300 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
301 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
304 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
305 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
311 /***********************************************************************
314 * Simplify sending same width/height for both source and dest
316 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
317 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
318 INT transparent, COLORREF transcolor)
320 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
321 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
322 transparent, transcolor);
325 /***********************************************************************
328 * Stretches or tiles, depending on sizingtype.
330 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
331 int nWidthDst, int nHeightDst,
332 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
333 int nWidthSrc, int nHeightSrc,
335 INT transparent, COLORREF transcolor)
337 if (sizingtype == ST_TILE)
342 if (!nWidthSrc || !nHeightSrc) return TRUE;
344 /* For destination width/height less than or equal to source
345 width/height, do not bother with memory bitmap optimization */
346 if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
348 int bltWidth = min (nWidthDst, nWidthSrc);
349 int bltHeight = min (nHeightDst, nHeightSrc);
351 return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
352 hdcSrc, nXOriginSrc, nYOriginSrc,
353 transparent, transcolor);
356 /* Create a DC with a bitmap consisting of a tiling of the source
357 bitmap, with standard GDI functions. This is faster than an
358 iteration with UXTHEME_Blt(). */
359 hdcTemp = CreateCompatibleDC(hdcSrc);
364 int nWidthTemp, nHeightTemp;
365 int xOfs, xRemaining;
366 int yOfs, yRemaining;
369 /* Calculate temp dimensions of integer multiples of source dimensions */
370 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
371 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
372 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
373 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
375 /* Initial copy of bitmap */
376 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
378 /* Extend bitmap in the X direction. Growth of width is exponential */
380 xRemaining = nWidthTemp - nWidthSrc;
381 growSize = nWidthSrc;
382 while (xRemaining > 0)
384 growSize = min(growSize, xRemaining);
385 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
387 xRemaining -= growSize;
391 /* Extend bitmap in the Y direction. Growth of height is exponential */
393 yRemaining = nHeightTemp - nHeightSrc;
394 growSize = nHeightSrc;
395 while (yRemaining > 0)
397 growSize = min(growSize, yRemaining);
398 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
400 yRemaining -= growSize;
404 /* Use temporary hdc for source */
405 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
407 transparent, transcolor);
409 SelectObject(hdcTemp, bitmapOrig);
410 DeleteObject(bitmapTemp);
417 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
418 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
419 transparent, transcolor);
423 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
424 * depend on whether the image has full alpha or whether it is
425 * color-transparent or just opaque. */
426 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
427 BOOL hasImageAlpha, INT* transparent,
428 COLORREF* transparentcolor, BOOL glyph)
432 *transparent = ALPHABLEND_FULL;
433 *transparentcolor = RGB (255, 0, 255);
438 GetThemeBool(hTheme, iPartId, iStateId,
439 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
441 *transparent = ALPHABLEND_BINARY;
442 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
443 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
444 transparentcolor))) {
445 /* If image is transparent, but no color was specified, use magenta */
446 *transparentcolor = RGB(255, 0, 255);
450 *transparent = ALPHABLEND_NONE;
454 /***********************************************************************
455 * UXTHEME_DrawImageGlyph
457 * Draw an imagefile glyph
459 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
460 int iStateId, RECT *pRect,
461 const DTBGOPTS *pOptions)
464 HBITMAP bmpSrc = NULL;
466 HGDIOBJ oldSrc = NULL;
468 INT transparent = FALSE;
469 COLORREF transparentcolor;
470 int valign = VA_CENTER;
471 int halign = HA_CENTER;
477 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
478 &bmpSrc, &rcSrc, &hasAlpha);
479 if(FAILED(hr)) return hr;
480 hdcSrc = CreateCompatibleDC(hdc);
482 hr = HRESULT_FROM_WIN32(GetLastError());
485 oldSrc = SelectObject(hdcSrc, bmpSrc);
487 dstSize.x = pRect->right-pRect->left;
488 dstSize.y = pRect->bottom-pRect->top;
489 srcSize.x = rcSrc.right-rcSrc.left;
490 srcSize.y = rcSrc.bottom-rcSrc.top;
492 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
493 &transparentcolor, TRUE);
494 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
495 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
497 topleft.x = pRect->left;
498 topleft.y = pRect->top;
499 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
500 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
501 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
502 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
504 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
505 hdcSrc, rcSrc.left, rcSrc.top,
506 transparent, transparentcolor)) {
507 hr = HRESULT_FROM_WIN32(GetLastError());
510 SelectObject(hdcSrc, oldSrc);
515 /***********************************************************************
516 * UXTHEME_DrawImageGlyph
518 * Draw glyph on top of background, if appropriate
520 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
521 int iStateId, RECT *pRect,
522 const DTBGOPTS *pOptions)
524 int glyphtype = GT_NONE;
526 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
528 if(glyphtype == GT_IMAGEGLYPH) {
529 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
531 else if(glyphtype == GT_FONTGLYPH) {
532 /* I don't know what a font glyph is, I've never seen it used in any themes */
533 FIXME("Font glyph\n");
538 /***********************************************************************
539 * get_image_part_size
541 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
543 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
544 int iStateId, RECT *prc, THEMESIZE eSize,
552 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
553 &bmpSrc, &rcSrc, &hasAlpha);
554 if (FAILED(hr)) return hr;
564 int sizingtype = ST_STRETCH;
565 BOOL uniformsizing = FALSE;
567 CopyRect(&rcDst, prc);
569 dstSize.x = rcDst.right-rcDst.left;
570 dstSize.y = rcDst.bottom-rcDst.top;
571 srcSize.x = rcSrc.right-rcSrc.left;
572 srcSize.y = rcSrc.bottom-rcSrc.top;
574 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
576 /* Scale height and width equally */
577 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
579 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
580 rcDst.bottom = rcDst.top + dstSize.y;
584 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
585 rcDst.right = rcDst.left + dstSize.x;
589 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
590 if(sizingtype == ST_TRUESIZE) {
591 int truesizestretchmark = 100;
593 if(dstSize.x < 0 || dstSize.y < 0) {
594 BOOL mirrorimage = TRUE;
595 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
598 rcDst.left += dstSize.x;
599 rcDst.right += dstSize.x;
602 rcDst.top += dstSize.y;
603 rcDst.bottom += dstSize.y;
607 /* Whatever TrueSizeStretchMark does - it does not seem to
608 * be what's outlined below. It appears as if native
609 * uxtheme always stretches if dest is smaller than source
610 * (ie as if TrueSizeStretchMark==100 with the code below) */
612 /* Only stretch when target exceeds source by truesizestretchmark percent */
613 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
615 if(dstSize.x < 0 || dstSize.y < 0 ||
616 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
617 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
618 memcpy (psz, &dstSize, sizeof (SIZE));
621 memcpy (psz, &srcSize, sizeof (SIZE));
626 psz->x = abs(dstSize.x);
627 psz->y = abs(dstSize.y);
631 /* else fall through */
633 /* FIXME: couldn't figure how native uxtheme computes min size */
635 psz->x = rcSrc.right - rcSrc.left;
636 psz->y = rcSrc.bottom - rcSrc.top;
642 /***********************************************************************
643 * UXTHEME_DrawImageBackground
645 * Draw an imagefile background
647 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
648 int iStateId, RECT *pRect,
649 const DTBGOPTS *pOptions)
660 int sizingtype = ST_STRETCH;
662 COLORREF transparentcolor = 0;
665 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
666 &bmpSrc, &rcSrc, &hasAlpha);
667 if(FAILED(hr)) return hr;
668 hdcSrc = CreateCompatibleDC(hdc);
670 hr = HRESULT_FROM_WIN32(GetLastError());
673 oldSrc = SelectObject(hdcSrc, bmpSrc);
675 CopyRect(&rcDst, pRect);
677 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
678 &transparentcolor, FALSE);
680 dstSize.x = rcDst.right-rcDst.left;
681 dstSize.y = rcDst.bottom-rcDst.top;
682 srcSize.x = rcSrc.right-rcSrc.left;
683 srcSize.y = rcSrc.bottom-rcSrc.top;
685 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
686 if(sizingtype == ST_TRUESIZE) {
687 int valign = VA_CENTER, halign = HA_CENTER;
689 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
690 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
691 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
693 if (halign == HA_CENTER)
694 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
695 else if (halign == HA_RIGHT)
696 rcDst.left = rcDst.right - drawSize.x;
697 if (valign == VA_CENTER)
698 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
699 else if (valign == VA_BOTTOM)
700 rcDst.top = rcDst.bottom - drawSize.y;
701 rcDst.right = rcDst.left + drawSize.x;
702 rcDst.bottom = rcDst.top + drawSize.y;
703 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
704 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
705 transparent, transparentcolor))
706 hr = HRESULT_FROM_WIN32(GetLastError());
713 dstSize.x = abs(dstSize.x);
714 dstSize.y = abs(dstSize.y);
716 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
719 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
721 /* Upper left corner */
722 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
723 hdcSrc, rcSrc.left, rcSrc.top,
724 transparent, transparentcolor)) {
725 hr = HRESULT_FROM_WIN32(GetLastError());
728 /* Upper right corner */
729 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
730 sm.cxRightWidth, sm.cyTopHeight,
731 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
732 transparent, transparentcolor)) {
733 hr = HRESULT_FROM_WIN32(GetLastError());
736 /* Lower left corner */
737 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
738 sm.cxLeftWidth, sm.cyBottomHeight,
739 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
740 transparent, transparentcolor)) {
741 hr = HRESULT_FROM_WIN32(GetLastError());
744 /* Lower right corner */
745 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
746 sm.cxRightWidth, sm.cyBottomHeight,
747 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
748 transparent, transparentcolor)) {
749 hr = HRESULT_FROM_WIN32(GetLastError());
753 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
754 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
755 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
756 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
757 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
759 if(destCenterWidth > 0) {
761 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
762 destCenterWidth, sm.cyTopHeight,
763 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
764 srcCenterWidth, sm.cyTopHeight,
765 sizingtype, transparent, transparentcolor)) {
766 hr = HRESULT_FROM_WIN32(GetLastError());
770 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
771 destCenterWidth, sm.cyBottomHeight,
772 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
773 srcCenterWidth, sm.cyBottomHeight,
774 sizingtype, transparent, transparentcolor)) {
775 hr = HRESULT_FROM_WIN32(GetLastError());
779 if(destCenterHeight > 0) {
781 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
782 sm.cxLeftWidth, destCenterHeight,
783 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
784 sm.cxLeftWidth, srcCenterHeight,
786 transparent, transparentcolor)) {
787 hr = HRESULT_FROM_WIN32(GetLastError());
791 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
792 sm.cxRightWidth, destCenterHeight,
793 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
794 sm.cxRightWidth, srcCenterHeight,
795 sizingtype, transparent, transparentcolor)) {
796 hr = HRESULT_FROM_WIN32(GetLastError());
800 if(destCenterHeight > 0 && destCenterWidth > 0) {
801 BOOL borderonly = FALSE;
802 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
805 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
806 destCenterWidth, destCenterHeight,
807 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
808 srcCenterWidth, srcCenterHeight,
809 sizingtype, transparent, transparentcolor)) {
810 hr = HRESULT_FROM_WIN32(GetLastError());
818 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
820 SelectObject(hdcSrc, oldSrc);
822 CopyRect(pRect, &rcDst);
826 /***********************************************************************
827 * UXTHEME_DrawBorderRectangle
829 * Draw the bounding rectangle for a borderfill background
831 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
832 int iStateId, RECT *pRect,
833 const DTBGOPTS *pOptions)
838 COLORREF bordercolor = RGB(0,0,0);
841 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
844 ptCorners[0].x = pRect->left;
845 ptCorners[0].y = pRect->top;
846 ptCorners[1].x = pRect->right-1;
847 ptCorners[1].y = pRect->top;
848 ptCorners[2].x = pRect->right-1;
849 ptCorners[2].y = pRect->bottom-1;
850 ptCorners[3].x = pRect->left;
851 ptCorners[3].y = pRect->bottom-1;
852 ptCorners[4].x = pRect->left;
853 ptCorners[4].y = pRect->top;
855 InflateRect(pRect, -bordersize, -bordersize);
856 if(pOptions->dwFlags & DTBG_OMITBORDER)
858 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
859 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
861 return HRESULT_FROM_WIN32(GetLastError());
862 oldPen = SelectObject(hdc, hPen);
864 if(!Polyline(hdc, ptCorners, 5))
865 hr = HRESULT_FROM_WIN32(GetLastError());
867 SelectObject(hdc, oldPen);
873 /***********************************************************************
874 * UXTHEME_DrawBackgroundFill
876 * Fill a borderfill background rectangle
878 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
879 int iStateId, RECT *pRect,
880 const DTBGOPTS *pOptions)
883 int filltype = FT_SOLID;
885 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
887 if(pOptions->dwFlags & DTBG_OMITCONTENT)
890 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
892 if(filltype == FT_SOLID) {
894 COLORREF fillcolor = RGB(255,255,255);
896 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
897 hBrush = CreateSolidBrush(fillcolor);
898 if(!FillRect(hdc, pRect, hBrush))
899 hr = HRESULT_FROM_WIN32(GetLastError());
900 DeleteObject(hBrush);
902 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
903 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
904 the gradient ratios (no idea how those work)
905 Few themes use this, and the ones I've seen only use 2 colors with
906 a gradient ratio of 0 and 255 respectively
909 COLORREF gradient1 = RGB(0,0,0);
910 COLORREF gradient2 = RGB(255,255,255);
914 FIXME("Gradient implementation not complete\n");
916 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
917 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
919 vert[0].x = pRect->left;
920 vert[0].y = pRect->top;
921 vert[0].Red = GetRValue(gradient1) << 8;
922 vert[0].Green = GetGValue(gradient1) << 8;
923 vert[0].Blue = GetBValue(gradient1) << 8;
924 vert[0].Alpha = 0xff00;
926 vert[1].x = pRect->right;
927 vert[1].y = pRect->bottom;
928 vert[1].Red = GetRValue(gradient2) << 8;
929 vert[1].Green = GetGValue(gradient2) << 8;
930 vert[1].Blue = GetBValue(gradient2) << 8;
931 vert[1].Alpha = 0xff00;
934 gRect.LowerRight = 1;
935 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
937 else if(filltype == FT_RADIALGRADIENT) {
938 /* I've never seen this used in a theme */
939 FIXME("Radial gradient\n");
941 else if(filltype == FT_TILEIMAGE) {
942 /* I've never seen this used in a theme */
943 FIXME("Tile image\n");
948 /***********************************************************************
949 * UXTHEME_DrawBorderBackground
951 * Draw an imagefile background
953 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
954 int iStateId, const RECT *pRect,
955 const DTBGOPTS *pOptions)
960 CopyRect(&rt, pRect);
962 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
965 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
968 /***********************************************************************
969 * DrawThemeBackgroundEx (UXTHEME.@)
971 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
972 int iStateId, const RECT *pRect,
973 const DTBGOPTS *pOptions)
976 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
977 const DTBGOPTS *opts;
980 int bgtype = BT_BORDERFILL;
983 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
987 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
988 if (bgtype == BT_NONE) return S_OK;
990 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
992 if(!opts) opts = &defaultOpts;
994 if(opts->dwFlags & DTBG_CLIPRECT) {
995 clip = CreateRectRgn(0,0,1,1);
996 hasClip = GetClipRgn(hdc, clip);
998 TRACE("Failed to get original clipping region\n");
1000 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
1002 CopyRect(&rt, pRect);
1004 if(bgtype == BT_IMAGEFILE)
1005 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
1006 else if(bgtype == BT_BORDERFILL)
1007 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
1009 FIXME("Unknown background type\n");
1010 /* This should never happen, and hence I don't know what to return */
1014 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1015 if(opts->dwFlags & DTBG_CLIPRECT) {
1017 SelectClipRgn(hdc, NULL);
1018 else if(hasClip == 1)
1019 SelectClipRgn(hdc, clip);
1026 * DrawThemeEdge() implementation
1028 * Since it basically is DrawEdge() with different colors, I copied its code
1029 * from user32's uitools.c.
1050 } EdgeColorMap[EDGE_NUMCOLORS] = {
1051 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1052 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1053 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1054 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1055 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1057 {-1, COLOR_WINDOWFRAME}
1060 static const signed char LTInnerNormal[] = {
1062 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1063 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1067 static const signed char LTOuterNormal[] = {
1068 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1069 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1070 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1071 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1074 static const signed char RBInnerNormal[] = {
1076 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1077 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1081 static const signed char RBOuterNormal[] = {
1082 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1083 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1084 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1085 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1088 static const signed char LTInnerSoft[] = {
1090 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1091 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1095 static const signed char LTOuterSoft[] = {
1096 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1097 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1098 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1099 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1102 #define RBInnerSoft RBInnerNormal /* These are the same */
1103 #define RBOuterSoft RBOuterNormal
1105 static const signed char LTRBOuterMono[] = {
1106 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1107 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1108 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1109 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1112 static const signed char LTRBInnerMono[] = {
1114 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1115 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1116 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1119 static const signed char LTRBOuterFlat[] = {
1120 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1121 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1122 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1123 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1126 static const signed char LTRBInnerFlat[] = {
1128 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1129 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1130 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1133 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1136 if ((EdgeColorMap[edgeType].themeProp == -1)
1137 || FAILED (GetThemeColor (theme, part, state,
1138 EdgeColorMap[edgeType].themeProp, &col)))
1139 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1143 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1145 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1148 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1150 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1153 /***********************************************************************
1156 * Same as DrawEdge invoked with BF_DIAGONAL
1158 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1159 const RECT* rc, UINT uType,
1160 UINT uFlags, LPRECT contentsRect)
1163 signed char InnerI, OuterI;
1164 HPEN InnerPen, OuterPen;
1169 int Width = rc->right - rc->left;
1170 int Height= rc->bottom - rc->top;
1171 int SmallDiam = Width > Height ? Height : Width;
1172 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1173 || (uType & BDR_OUTER) == BDR_OUTER)
1174 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1175 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1176 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1178 /* Init some vars */
1179 OuterPen = InnerPen = GetStockObject(NULL_PEN);
1180 SavePen = SelectObject(hdc, InnerPen);
1181 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1183 /* Determine the colors of the edges */
1184 if(uFlags & BF_MONO)
1186 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1187 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1189 else if(uFlags & BF_FLAT)
1191 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1192 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1194 else if(uFlags & BF_SOFT)
1196 if(uFlags & BF_BOTTOM)
1198 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1199 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1203 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1204 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1209 if(uFlags & BF_BOTTOM)
1211 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1212 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1216 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1217 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1221 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1222 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1224 MoveToEx(hdc, 0, 0, &SavePoint);
1226 /* Don't ask me why, but this is what is visible... */
1227 /* This must be possible to do much simpler, but I fail to */
1228 /* see the logic in the MS implementation (sigh...). */
1229 /* So, this might look a bit brute force here (and it is), but */
1230 /* it gets the job done;) */
1232 switch(uFlags & BF_RECT)
1238 /* Left bottom endpoint */
1240 spx = epx + SmallDiam;
1242 spy = epy - SmallDiam;
1246 case BF_BOTTOMRIGHT:
1247 /* Left top endpoint */
1249 spx = epx + SmallDiam;
1251 spy = epy + SmallDiam;
1257 case BF_RIGHT|BF_LEFT:
1258 case BF_RIGHT|BF_LEFT|BF_TOP:
1259 case BF_BOTTOM|BF_TOP:
1260 case BF_BOTTOM|BF_TOP|BF_LEFT:
1261 case BF_BOTTOMRIGHT|BF_LEFT:
1262 case BF_BOTTOMRIGHT|BF_TOP:
1264 /* Right top endpoint */
1266 epx = spx + SmallDiam;
1268 epy = spy - SmallDiam;
1272 MoveToEx(hdc, spx, spy, NULL);
1273 SelectObject(hdc, OuterPen);
1274 LineTo(hdc, epx, epy);
1276 SelectObject(hdc, InnerPen);
1278 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1280 case BF_DIAGONAL_ENDBOTTOMLEFT:
1281 case (BF_DIAGONAL|BF_BOTTOM):
1283 case (BF_DIAGONAL|BF_LEFT):
1284 MoveToEx(hdc, spx-1, spy, NULL);
1285 LineTo(hdc, epx, epy-1);
1286 Points[0].x = spx-add;
1288 Points[1].x = rc->left;
1289 Points[1].y = rc->top;
1290 Points[2].x = epx+1;
1291 Points[2].y = epy-1-add;
1292 Points[3] = Points[2];
1295 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1296 MoveToEx(hdc, spx-1, spy, NULL);
1297 LineTo(hdc, epx, epy+1);
1298 Points[0].x = spx-add;
1300 Points[1].x = rc->left;
1301 Points[1].y = rc->bottom-1;
1302 Points[2].x = epx+1;
1303 Points[2].y = epy+1+add;
1304 Points[3] = Points[2];
1307 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1308 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1309 case BF_DIAGONAL_ENDTOPRIGHT:
1310 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1311 MoveToEx(hdc, spx+1, spy, NULL);
1312 LineTo(hdc, epx, epy+1);
1313 Points[0].x = epx-1;
1314 Points[0].y = epy+1+add;
1315 Points[1].x = rc->right-1;
1316 Points[1].y = rc->top+add;
1317 Points[2].x = rc->right-1;
1318 Points[2].y = rc->bottom-1;
1319 Points[3].x = spx+add;
1323 case BF_DIAGONAL_ENDTOPLEFT:
1324 MoveToEx(hdc, spx, spy-1, NULL);
1325 LineTo(hdc, epx+1, epy);
1326 Points[0].x = epx+1+add;
1327 Points[0].y = epy+1;
1328 Points[1].x = rc->right-1;
1329 Points[1].y = rc->top;
1330 Points[2].x = rc->right-1;
1331 Points[2].y = rc->bottom-1-add;
1333 Points[3].y = spy-add;
1336 case (BF_DIAGONAL|BF_TOP):
1337 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1338 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1339 MoveToEx(hdc, spx+1, spy-1, NULL);
1340 LineTo(hdc, epx, epy);
1341 Points[0].x = epx-1;
1342 Points[0].y = epy+1;
1343 Points[1].x = rc->right-1;
1344 Points[1].y = rc->top;
1345 Points[2].x = rc->right-1;
1346 Points[2].y = rc->bottom-1-add;
1347 Points[3].x = spx+add;
1348 Points[3].y = spy-add;
1351 case (BF_DIAGONAL|BF_RIGHT):
1352 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1353 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1354 MoveToEx(hdc, spx, spy, NULL);
1355 LineTo(hdc, epx-1, epy+1);
1358 Points[1].x = rc->left;
1359 Points[1].y = rc->top+add;
1360 Points[2].x = epx-1-add;
1361 Points[2].y = epy+1+add;
1362 Points[3] = Points[2];
1366 /* Fill the interior if asked */
1367 if((uFlags & BF_MIDDLE) && retval)
1370 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1371 theme, part, state);
1373 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1374 theme, part, state);
1375 hbsave = SelectObject(hdc, hb);
1376 hpsave = SelectObject(hdc, hp);
1377 Polygon(hdc, Points, 4);
1378 SelectObject(hdc, hbsave);
1379 SelectObject(hdc, hpsave);
1384 /* Adjust rectangle if asked */
1385 if(uFlags & BF_ADJUST)
1387 *contentsRect = *rc;
1388 if(uFlags & BF_LEFT) contentsRect->left += add;
1389 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1390 if(uFlags & BF_TOP) contentsRect->top += add;
1391 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1395 SelectObject(hdc, SavePen);
1396 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1397 if(InnerI != -1) DeleteObject (InnerPen);
1398 if(OuterI != -1) DeleteObject (OuterPen);
1403 /***********************************************************************
1406 * Same as DrawEdge invoked without BF_DIAGONAL
1408 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1409 const RECT* rc, UINT uType,
1410 UINT uFlags, LPRECT contentsRect)
1412 signed char LTInnerI, LTOuterI;
1413 signed char RBInnerI, RBOuterI;
1414 HPEN LTInnerPen, LTOuterPen;
1415 HPEN RBInnerPen, RBOuterPen;
1416 RECT InnerRect = *rc;
1423 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1424 || (uType & BDR_OUTER) == BDR_OUTER)
1425 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1427 /* Init some vars */
1428 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = GetStockObject(NULL_PEN);
1429 SavePen = SelectObject(hdc, LTInnerPen);
1431 /* Determine the colors of the edges */
1432 if(uFlags & BF_MONO)
1434 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1435 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1437 else if(uFlags & BF_FLAT)
1439 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1440 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1442 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1444 else if(uFlags & BF_SOFT)
1446 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1447 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1448 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1449 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1453 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1454 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1455 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1456 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1459 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1460 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1461 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1462 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1464 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1465 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1466 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1467 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1469 MoveToEx(hdc, 0, 0, &SavePoint);
1471 /* Draw the outer edge */
1472 SelectObject(hdc, LTOuterPen);
1475 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1476 LineTo(hdc, InnerRect.right, InnerRect.top);
1478 if(uFlags & BF_LEFT)
1480 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1481 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1483 SelectObject(hdc, RBOuterPen);
1484 if(uFlags & BF_BOTTOM)
1486 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1487 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1489 if(uFlags & BF_RIGHT)
1491 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1492 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1495 /* Draw the inner edge */
1496 SelectObject(hdc, LTInnerPen);
1499 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1500 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1502 if(uFlags & BF_LEFT)
1504 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1505 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1507 SelectObject(hdc, RBInnerPen);
1508 if(uFlags & BF_BOTTOM)
1510 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1511 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1513 if(uFlags & BF_RIGHT)
1515 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1516 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1519 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1521 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1522 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1524 if(uFlags & BF_LEFT) InnerRect.left += add;
1525 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1526 if(uFlags & BF_TOP) InnerRect.top += add;
1527 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1529 if((uFlags & BF_MIDDLE) && retval)
1531 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1532 theme, part, state);
1533 FillRect(hdc, &InnerRect, br);
1537 if(uFlags & BF_ADJUST)
1538 *contentsRect = InnerRect;
1542 SelectObject(hdc, SavePen);
1543 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1544 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1545 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1546 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1547 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1552 /***********************************************************************
1553 * DrawThemeEdge (UXTHEME.@)
1555 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1556 * difference is that it does not rely on the system colors alone, but
1557 * also allows color specification in the theme.
1559 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1560 int iStateId, const RECT *pDestRect, UINT uEdge,
1561 UINT uFlags, RECT *pContentRect)
1563 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1567 if(uFlags & BF_DIAGONAL)
1568 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1569 uEdge, uFlags, pContentRect);
1571 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1572 uEdge, uFlags, pContentRect);
1576 /***********************************************************************
1577 * DrawThemeIcon (UXTHEME.@)
1579 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1580 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1582 FIXME("%d %d: stub\n", iPartId, iStateId);
1585 return ERROR_CALL_NOT_IMPLEMENTED;
1588 /***********************************************************************
1589 * DrawThemeText (UXTHEME.@)
1591 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1592 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1593 DWORD dwTextFlags2, const RECT *pRect)
1597 HGDIOBJ oldFont = NULL;
1600 COLORREF oldTextColor;
1604 TRACE("%d %d: stub\n", iPartId, iStateId);
1608 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1610 hFont = CreateFontIndirectW(&logfont);
1612 TRACE("Failed to create font\n");
1614 CopyRect(&rt, pRect);
1616 oldFont = SelectObject(hdc, hFont);
1618 if(dwTextFlags2 & DTT_GRAYED)
1619 textColor = GetSysColor(COLOR_GRAYTEXT);
1621 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1622 textColor = GetTextColor(hdc);
1624 oldTextColor = SetTextColor(hdc, textColor);
1625 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1626 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1627 SetBkMode(hdc, oldBkMode);
1628 SetTextColor(hdc, oldTextColor);
1631 SelectObject(hdc, oldFont);
1632 DeleteObject(hFont);
1637 /***********************************************************************
1638 * GetThemeBackgroundContentRect (UXTHEME.@)
1640 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1642 const RECT *pBoundingRect,
1648 TRACE("(%d,%d)\n", iPartId, iStateId);
1652 /* try content margins property... */
1653 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1655 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1656 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1657 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1658 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1660 /* otherwise, try to determine content rect from the background type and props */
1661 int bgtype = BT_BORDERFILL;
1662 *pContentRect = *pBoundingRect;
1664 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1665 if(bgtype == BT_BORDERFILL) {
1668 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1669 InflateRect(pContentRect, -bordersize, -bordersize);
1670 } else if ((bgtype == BT_IMAGEFILE)
1671 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1672 TMT_SIZINGMARGINS, NULL, &margin)))) {
1673 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1674 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1675 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1676 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1678 /* If nothing was found, leave unchanged */
1681 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1686 /***********************************************************************
1687 * GetThemeBackgroundExtent (UXTHEME.@)
1689 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1690 int iStateId, const RECT *pContentRect,
1696 TRACE("(%d,%d)\n", iPartId, iStateId);
1700 /* try content margins property... */
1701 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1703 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1704 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1705 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1706 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1708 /* otherwise, try to determine content rect from the background type and props */
1709 int bgtype = BT_BORDERFILL;
1710 *pExtentRect = *pContentRect;
1712 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1713 if(bgtype == BT_BORDERFILL) {
1716 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1717 InflateRect(pExtentRect, bordersize, bordersize);
1718 } else if ((bgtype == BT_IMAGEFILE)
1719 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1720 TMT_SIZINGMARGINS, NULL, &margin)))) {
1721 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1722 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1723 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1724 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1726 /* If nothing was found, leave unchanged */
1729 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1734 /***********************************************************************
1735 * GetThemeBackgroundRegion (UXTHEME.@)
1737 * Calculate the background region, taking into consideration transparent areas
1738 * of the background image.
1740 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1741 int iStateId, const RECT *pRect,
1745 int bgtype = BT_BORDERFILL;
1747 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1750 if(!pRect || !pRegion)
1753 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1754 if(bgtype == BT_IMAGEFILE) {
1755 FIXME("Images not handled yet\n");
1756 hr = ERROR_CALL_NOT_IMPLEMENTED;
1758 else if(bgtype == BT_BORDERFILL) {
1759 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1761 hr = HRESULT_FROM_WIN32(GetLastError());
1764 FIXME("Unknown background type\n");
1765 /* This should never happen, and hence I don't know what to return */
1771 /* compute part size for "borderfill" backgrounds */
1772 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1773 int iStateId, THEMESIZE eSize, POINT* psz)
1778 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1781 psz->x = psz->y = 2*bordersize;
1782 if (eSize != TS_MIN)
1791 /***********************************************************************
1792 * GetThemePartSize (UXTHEME.@)
1794 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1795 int iStateId, RECT *prc, THEMESIZE eSize,
1798 int bgtype = BT_BORDERFILL;
1800 POINT size = {1, 1};
1805 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1806 if (bgtype == BT_NONE)
1808 else if(bgtype == BT_IMAGEFILE)
1809 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1810 else if(bgtype == BT_BORDERFILL)
1811 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1813 FIXME("Unknown background type\n");
1814 /* This should never happen, and hence I don't know what to return */
1823 /***********************************************************************
1824 * GetThemeTextExtent (UXTHEME.@)
1826 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1827 int iStateId, LPCWSTR pszText, int iCharCount,
1828 DWORD dwTextFlags, const RECT *pBoundingRect,
1833 HGDIOBJ oldFont = NULL;
1835 RECT rt = {0,0,0xFFFF,0xFFFF};
1837 TRACE("%d %d: stub\n", iPartId, iStateId);
1842 CopyRect(&rt, pBoundingRect);
1844 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1846 hFont = CreateFontIndirectW(&logfont);
1848 TRACE("Failed to create font\n");
1851 oldFont = SelectObject(hdc, hFont);
1853 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1854 CopyRect(pExtentRect, &rt);
1857 SelectObject(hdc, oldFont);
1858 DeleteObject(hFont);
1863 /***********************************************************************
1864 * GetThemeTextMetrics (UXTHEME.@)
1866 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1867 int iStateId, TEXTMETRICW *ptm)
1871 HGDIOBJ oldFont = NULL;
1874 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1878 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1880 hFont = CreateFontIndirectW(&logfont);
1882 TRACE("Failed to create font\n");
1885 oldFont = SelectObject(hdc, hFont);
1887 if(!GetTextMetricsW(hdc, ptm))
1888 hr = HRESULT_FROM_WIN32(GetLastError());
1891 SelectObject(hdc, oldFont);
1892 DeleteObject(hFont);
1897 /***********************************************************************
1898 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1900 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1903 int bgtype = BT_BORDERFILL;
1904 RECT rect = {0, 0, 0, 0};
1909 COLORREF transparentcolor;
1911 TRACE("(%d,%d)\n", iPartId, iStateId);
1916 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1918 if (bgtype != BT_IMAGEFILE) return FALSE;
1920 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1921 &bmpSrc, &rcSrc, &hasAlpha)))
1924 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1925 &transparentcolor, FALSE);
1926 return (transparent != ALPHABLEND_NONE);