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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "uxthemedll.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
40 /***********************************************************************
41 * Defines and global variables
44 extern ATOM atDialogThemeEnabled;
46 /***********************************************************************/
48 /***********************************************************************
49 * EnableThemeDialogTexture (UXTHEME.@)
51 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
53 static const WCHAR szTab[] = { 'T','a','b',0 };
56 TRACE("(%p,0x%08lx\n", hwnd, dwFlags);
57 hr = SetPropW (hwnd, MAKEINTATOMW (atDialogThemeEnabled),
58 (HANDLE)(dwFlags|0x80000000));
59 /* 0x80000000 serves as a "flags set" flag */
62 if (dwFlags & ETDT_USETABTEXTURE)
63 return SetWindowTheme (hwnd, NULL, szTab);
65 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 = (DWORD)GetPropW (hwnd,
78 MAKEINTATOMW (atDialogThemeEnabled));
79 if (dwDialogTextureFlags == 0)
80 /* Means EnableThemeDialogTexture wasn't called for this dialog */
83 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
86 /***********************************************************************
87 * DrawThemeParentBackground (UXTHEME.@)
89 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
97 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
98 hParent = GetParent(hwnd);
103 MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
105 clip = CreateRectRgn(0,0,1,1);
106 hasClip = GetClipRgn(hdc, clip);
108 TRACE("Failed to get original clipping region\n");
110 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
113 GetClientRect(hParent, &rt);
114 MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
117 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
119 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
120 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
122 SetViewportOrgEx(hdc, org.x, org.y, NULL);
125 SelectClipRgn(hdc, NULL);
126 else if(hasClip == 1)
127 SelectClipRgn(hdc, clip);
134 /***********************************************************************
135 * DrawThemeBackground (UXTHEME.@)
137 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
138 int iStateId, const RECT *pRect,
139 const RECT *pClipRect)
142 opts.dwSize = sizeof(DTBGOPTS);
145 opts.dwFlags |= DTBG_CLIPRECT;
146 CopyRect(&opts.rcClip, pClipRect);
148 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
151 /***********************************************************************
152 * UXTHEME_SelectImage
154 * Select the image to use
156 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
159 int imageselecttype = IST_NONE;
163 image = TMT_GLYPHIMAGEFILE;
165 image = TMT_IMAGEFILE;
167 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
169 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
171 if(imageselecttype == IST_DPI) {
173 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
174 for(i=4; i>=0; i--) {
176 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
177 if(reqdpi != 0 && screendpi >= reqdpi) {
178 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
179 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
183 /* If an image couldn't be selected, choose the first one */
184 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
186 else if(imageselecttype == IST_SIZE) {
187 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
189 for(i=4; i>=0; i--) {
190 PTHEME_PROPERTY fileProp =
191 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
192 if (!fileProp) continue;
193 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
194 /* fall back to size of Nth image */
195 WCHAR szPath[MAX_PATH];
196 int imagelayout = IL_HORIZONTAL;
203 lstrcpynW(szPath, fileProp->lpValue,
204 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
205 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
208 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
209 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
211 imagenum = max (min (imagecount, iStateId), 1) - 1;
212 GetObjectW(hBmp, sizeof(bmp), &bmp);
213 if(imagelayout == IL_VERTICAL) {
214 reqsize.x = bmp.bmWidth;
215 reqsize.y = bmp.bmHeight/imagecount;
218 reqsize.x = bmp.bmWidth/imagecount;
219 reqsize.y = bmp.bmHeight;
222 if(reqsize.x <= size.x && reqsize.y <= size.y) {
223 TRACE("Using image size %ldx%ld, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
227 /* If an image couldn't be selected, choose the smallest one */
228 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
233 /***********************************************************************
236 * Load image for part/state
238 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
239 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
241 int imagelayout = IL_HORIZONTAL;
245 WCHAR szPath[MAX_PATH];
246 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
248 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
249 return E_PROP_ID_UNSUPPORTED;
251 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
252 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
254 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
255 return HRESULT_FROM_WIN32(GetLastError());
258 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
259 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
261 imagenum = max (min (imagecount, iStateId), 1) - 1;
262 GetObjectW(*hBmp, sizeof(bmp), &bmp);
263 if(imagelayout == IL_VERTICAL) {
264 int height = bmp.bmHeight/imagecount;
266 bmpRect->right = bmp.bmWidth;
267 bmpRect->top = imagenum * height;
268 bmpRect->bottom = bmpRect->top + height;
271 int width = bmp.bmWidth/imagecount;
272 bmpRect->left = imagenum * width;
273 bmpRect->right = bmpRect->left + width;
275 bmpRect->bottom = bmp.bmHeight;
280 /***********************************************************************
283 * Pseudo TransparentBlt/StretchBlt
285 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
286 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
287 INT transparent, COLORREF transcolor)
289 static const BLENDFUNCTION blendFunc =
291 AC_SRC_OVER, /* BlendOp */
293 255, /* SourceConstantAlpha */
294 AC_SRC_ALPHA /* AlphaFormat */
296 if (transparent == ALPHABLEND_BINARY) {
297 /* Ensure we don't pass any negative values to TransparentBlt */
298 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
299 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
302 if ((transparent == ALPHABLEND_NONE) ||
303 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
304 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
307 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
308 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
314 /***********************************************************************
317 * Simplify sending same width/height for both source and dest
319 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
320 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
321 INT transparent, COLORREF transcolor)
323 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
324 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
325 transparent, transcolor);
328 /***********************************************************************
331 * Stretches or tiles, depending on sizingtype.
333 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
334 int nWidthDst, int nHeightDst,
335 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
336 int nWidthSrc, int nHeightSrc,
338 INT transparent, COLORREF transcolor)
340 if (sizingtype == ST_TILE)
342 int yOfs = nYOriginDst;
343 int yRemaining = nHeightDst;
344 while (yRemaining > 0)
346 int bltHeight = min (yRemaining, nHeightSrc);
347 int xOfs = nXOriginDst;
348 int xRemaining = nWidthDst;
349 while (xRemaining > 0)
351 int bltWidth = min (xRemaining, nWidthSrc);
352 if (!UXTHEME_Blt (hdcDst, xOfs, yOfs, bltWidth, bltHeight,
353 hdcSrc, nXOriginSrc, nYOriginSrc,
354 transparent, transcolor))
357 xRemaining -= nWidthSrc;
360 yRemaining -= nHeightSrc;
366 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
367 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
368 transparent, transcolor);
372 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
373 * depend on whether the image has full alpha or whether it is
374 * color-transparent or just opaque. */
375 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
376 BOOL hasImageAlpha, INT* transparent,
377 COLORREF* transparentcolor, BOOL glyph)
381 *transparent = ALPHABLEND_FULL;
382 *transparentcolor = RGB (255, 0, 255);
387 GetThemeBool(hTheme, iPartId, iStateId,
388 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
390 *transparent = ALPHABLEND_BINARY;
391 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
392 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
393 transparentcolor))) {
394 /* If image is transparent, but no color was specified, use magenta */
395 *transparentcolor = RGB(255, 0, 255);
399 *transparent = ALPHABLEND_NONE;
403 /***********************************************************************
404 * UXTHEME_DrawImageGlyph
406 * Draw an imagefile glyph
408 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
409 int iStateId, RECT *pRect,
410 const DTBGOPTS *pOptions)
413 HBITMAP bmpSrc = NULL;
415 HGDIOBJ oldSrc = NULL;
417 INT transparent = FALSE;
418 COLORREF transparentcolor;
419 int valign = VA_CENTER;
420 int halign = HA_CENTER;
426 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
427 &bmpSrc, &rcSrc, &hasAlpha);
428 if(FAILED(hr)) return hr;
429 hdcSrc = CreateCompatibleDC(hdc);
431 hr = HRESULT_FROM_WIN32(GetLastError());
434 oldSrc = SelectObject(hdcSrc, bmpSrc);
436 dstSize.x = pRect->right-pRect->left;
437 dstSize.y = pRect->bottom-pRect->top;
438 srcSize.x = rcSrc.right-rcSrc.left;
439 srcSize.y = rcSrc.bottom-rcSrc.top;
441 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
442 &transparentcolor, TRUE);
443 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
444 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
446 topleft.x = pRect->left;
447 topleft.y = pRect->top;
448 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
449 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
450 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
451 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
453 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
454 hdcSrc, rcSrc.left, rcSrc.top,
455 transparent, transparentcolor)) {
456 hr = HRESULT_FROM_WIN32(GetLastError());
459 SelectObject(hdcSrc, oldSrc);
464 /***********************************************************************
465 * UXTHEME_DrawImageGlyph
467 * Draw glyph on top of background, if appropriate
469 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
470 int iStateId, RECT *pRect,
471 const DTBGOPTS *pOptions)
473 int glyphtype = GT_NONE;
475 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
477 if(glyphtype == GT_IMAGEGLYPH) {
478 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
480 else if(glyphtype == GT_FONTGLYPH) {
481 /* I don't know what a font glyph is, I've never seen it used in any themes */
482 FIXME("Font glyph\n");
487 /***********************************************************************
488 * get_image_part_size
490 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
492 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
493 int iStateId, RECT *prc, THEMESIZE eSize,
501 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
502 &bmpSrc, &rcSrc, &hasAlpha);
503 if (FAILED(hr)) return hr;
513 int sizingtype = ST_STRETCH;
514 BOOL uniformsizing = FALSE;
516 CopyRect(&rcDst, prc);
518 dstSize.x = rcDst.right-rcDst.left;
519 dstSize.y = rcDst.bottom-rcDst.top;
520 srcSize.x = rcSrc.right-rcSrc.left;
521 srcSize.y = rcSrc.bottom-rcSrc.top;
523 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
525 /* Scale height and width equally */
526 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
528 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
529 rcDst.bottom = rcDst.top + dstSize.y;
533 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
534 rcDst.right = rcDst.left + dstSize.x;
538 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
539 if(sizingtype == ST_TRUESIZE) {
540 int truesizestretchmark = 100;
542 if(dstSize.x < 0 || dstSize.y < 0) {
543 BOOL mirrorimage = TRUE;
544 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
547 rcDst.left += dstSize.x;
548 rcDst.right += dstSize.x;
551 rcDst.top += dstSize.y;
552 rcDst.bottom += dstSize.y;
556 /* Whatever TrueSizeStretchMark does - it does not seem to
557 * be what's outlined below. It appears as if native
558 * uxtheme always stretches if dest is smaller than source
559 * (ie as if TrueSizeStretchMark==100 with the code below) */
561 /* Only stretch when target exceeds source by truesizestretchmark percent */
562 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
564 if(dstSize.x < 0 || dstSize.y < 0 ||
565 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
566 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
567 memcpy (psz, &dstSize, sizeof (SIZE));
570 memcpy (psz, &srcSize, sizeof (SIZE));
575 psz->x = abs(dstSize.x);
576 psz->y = abs(dstSize.y);
580 /* else fall through */
582 /* FIXME: couldn't figure how native uxtheme computes min size */
584 psz->x = rcSrc.right - rcSrc.left;
585 psz->y = rcSrc.bottom - rcSrc.top;
591 /***********************************************************************
592 * UXTHEME_DrawImageBackground
594 * Draw an imagefile background
596 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
597 int iStateId, RECT *pRect,
598 const DTBGOPTS *pOptions)
609 int sizingtype = ST_STRETCH;
611 COLORREF transparentcolor = 0;
614 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
615 &bmpSrc, &rcSrc, &hasAlpha);
616 if(FAILED(hr)) return hr;
617 hdcSrc = CreateCompatibleDC(hdc);
619 hr = HRESULT_FROM_WIN32(GetLastError());
622 oldSrc = SelectObject(hdcSrc, bmpSrc);
624 CopyRect(&rcDst, pRect);
626 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
627 &transparentcolor, FALSE);
629 dstSize.x = rcDst.right-rcDst.left;
630 dstSize.y = rcDst.bottom-rcDst.top;
631 srcSize.x = rcSrc.right-rcSrc.left;
632 srcSize.y = rcSrc.bottom-rcSrc.top;
634 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
635 if(sizingtype == ST_TRUESIZE) {
636 int valign = VA_CENTER, halign = HA_CENTER;
638 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
639 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
640 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
642 if (halign == HA_CENTER)
643 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
644 else if (halign == HA_RIGHT)
645 rcDst.left = rcDst.right - drawSize.x;
646 if (valign == VA_CENTER)
647 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
648 else if (valign == VA_BOTTOM)
649 rcDst.top = rcDst.bottom - drawSize.y;
650 rcDst.right = rcDst.left + drawSize.x;
651 rcDst.bottom = rcDst.top + drawSize.y;
652 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
653 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
654 transparent, transparentcolor))
655 hr = HRESULT_FROM_WIN32(GetLastError());
662 dstSize.x = abs(dstSize.x);
663 dstSize.y = abs(dstSize.y);
665 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
668 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
670 /* Upper left corner */
671 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
672 hdcSrc, rcSrc.left, rcSrc.top,
673 transparent, transparentcolor)) {
674 hr = HRESULT_FROM_WIN32(GetLastError());
677 /* Upper right corner */
678 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
679 sm.cxRightWidth, sm.cyTopHeight,
680 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
681 transparent, transparentcolor)) {
682 hr = HRESULT_FROM_WIN32(GetLastError());
685 /* Lower left corner */
686 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
687 sm.cxLeftWidth, sm.cyBottomHeight,
688 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
689 transparent, transparentcolor)) {
690 hr = HRESULT_FROM_WIN32(GetLastError());
693 /* Lower right corner */
694 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
695 sm.cxRightWidth, sm.cyBottomHeight,
696 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
697 transparent, transparentcolor)) {
698 hr = HRESULT_FROM_WIN32(GetLastError());
702 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
703 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
704 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
705 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
706 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
708 if(destCenterWidth > 0) {
710 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
711 destCenterWidth, sm.cyTopHeight,
712 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
713 srcCenterWidth, sm.cyTopHeight,
714 sizingtype, transparent, transparentcolor)) {
715 hr = HRESULT_FROM_WIN32(GetLastError());
719 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
720 destCenterWidth, sm.cyBottomHeight,
721 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
722 srcCenterWidth, sm.cyBottomHeight,
723 sizingtype, transparent, transparentcolor)) {
724 hr = HRESULT_FROM_WIN32(GetLastError());
728 if(destCenterHeight > 0) {
730 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
731 sm.cxLeftWidth, destCenterHeight,
732 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
733 sm.cxLeftWidth, srcCenterHeight,
735 transparent, transparentcolor)) {
736 hr = HRESULT_FROM_WIN32(GetLastError());
740 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
741 sm.cxRightWidth, destCenterHeight,
742 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
743 sm.cxRightWidth, srcCenterHeight,
744 sizingtype, transparent, transparentcolor)) {
745 hr = HRESULT_FROM_WIN32(GetLastError());
749 if(destCenterHeight > 0 && destCenterWidth > 0) {
750 BOOL borderonly = FALSE;
751 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
754 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
755 destCenterWidth, destCenterHeight,
756 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
757 srcCenterWidth, srcCenterHeight,
758 sizingtype, transparent, transparentcolor)) {
759 hr = HRESULT_FROM_WIN32(GetLastError());
767 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
769 SelectObject(hdcSrc, oldSrc);
771 CopyRect(pRect, &rcDst);
775 /***********************************************************************
776 * UXTHEME_DrawBorderRectangle
778 * Draw the bounding rectangle for a borderfill background
780 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
781 int iStateId, RECT *pRect,
782 const DTBGOPTS *pOptions)
787 COLORREF bordercolor = RGB(0,0,0);
790 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
793 ptCorners[0].x = pRect->left;
794 ptCorners[0].y = pRect->top;
795 ptCorners[1].x = pRect->right-1;
796 ptCorners[1].y = pRect->top;
797 ptCorners[2].x = pRect->right-1;
798 ptCorners[2].y = pRect->bottom-1;
799 ptCorners[3].x = pRect->left;
800 ptCorners[3].y = pRect->bottom-1;
801 ptCorners[4].x = pRect->left;
802 ptCorners[4].y = pRect->top;
804 InflateRect(pRect, -bordersize, -bordersize);
805 if(pOptions->dwFlags & DTBG_OMITBORDER)
807 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
808 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
810 return HRESULT_FROM_WIN32(GetLastError());
811 oldPen = SelectObject(hdc, hPen);
813 if(!Polyline(hdc, ptCorners, 5))
814 hr = HRESULT_FROM_WIN32(GetLastError());
816 SelectObject(hdc, oldPen);
822 /***********************************************************************
823 * UXTHEME_DrawBackgroundFill
825 * Fill a borderfill background rectangle
827 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
828 int iStateId, RECT *pRect,
829 const DTBGOPTS *pOptions)
832 int filltype = FT_SOLID;
834 TRACE("(%d,%d,%ld)\n", iPartId, iStateId, pOptions->dwFlags);
836 if(pOptions->dwFlags & DTBG_OMITCONTENT)
839 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
841 if(filltype == FT_SOLID) {
843 COLORREF fillcolor = RGB(255,255,255);
845 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
846 hBrush = CreateSolidBrush(fillcolor);
847 if(!FillRect(hdc, pRect, hBrush))
848 hr = HRESULT_FROM_WIN32(GetLastError());
849 DeleteObject(hBrush);
851 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
852 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
853 the gradient ratios (no idea how those work)
854 Few themes use this, and the ones I've seen only use 2 colors with
855 a gradient ratio of 0 and 255 respectivly
858 COLORREF gradient1 = RGB(0,0,0);
859 COLORREF gradient2 = RGB(255,255,255);
863 FIXME("Gradient implementation not complete\n");
865 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
866 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
868 vert[0].x = pRect->left;
869 vert[0].y = pRect->top;
870 vert[0].Red = GetRValue(gradient1) << 8;
871 vert[0].Green = GetGValue(gradient1) << 8;
872 vert[0].Blue = GetBValue(gradient1) << 8;
873 vert[0].Alpha = 0x0000;
875 vert[1].x = pRect->right;
876 vert[1].y = pRect->bottom;
877 vert[1].Red = GetRValue(gradient2) << 8;
878 vert[1].Green = GetGValue(gradient2) << 8;
879 vert[1].Blue = GetBValue(gradient2) << 8;
880 vert[1].Alpha = 0x0000;
883 gRect.LowerRight = 1;
884 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
886 else if(filltype == FT_RADIALGRADIENT) {
887 /* I've never seen this used in a theme */
888 FIXME("Radial gradient\n");
890 else if(filltype == FT_TILEIMAGE) {
891 /* I've never seen this used in a theme */
892 FIXME("Tile image\n");
897 /***********************************************************************
898 * UXTHEME_DrawBorderBackground
900 * Draw an imagefile background
902 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
903 int iStateId, const RECT *pRect,
904 const DTBGOPTS *pOptions)
909 CopyRect(&rt, pRect);
911 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
914 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
917 /***********************************************************************
918 * DrawThemeBackgroundEx (UXTHEME.@)
920 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
921 int iStateId, const RECT *pRect,
922 const DTBGOPTS *pOptions)
925 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
926 const DTBGOPTS *opts;
929 int bgtype = BT_BORDERFILL;
932 TRACE("(%p,%p,%d,%d,%ld,%ld)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
936 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
937 if (bgtype == BT_NONE) return S_OK;
939 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
941 if(!opts) opts = &defaultOpts;
943 if(opts->dwFlags & DTBG_CLIPRECT) {
944 clip = CreateRectRgn(0,0,1,1);
945 hasClip = GetClipRgn(hdc, clip);
947 TRACE("Failed to get original clipping region\n");
949 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
951 CopyRect(&rt, pRect);
953 if(bgtype == BT_IMAGEFILE)
954 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
955 else if(bgtype == BT_BORDERFILL)
956 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
958 FIXME("Unknown background type\n");
959 /* This should never happen, and hence I don't know what to return */
963 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
964 if(opts->dwFlags & DTBG_CLIPRECT) {
966 SelectClipRgn(hdc, NULL);
967 else if(hasClip == 1)
968 SelectClipRgn(hdc, clip);
975 * DrawThemeEdge() implementation
977 * Since it basically is DrawEdge() with different colors, I copied its code
978 * from user32's uitools.c.
999 } EdgeColorMap[EDGE_NUMCOLORS] = {
1000 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1001 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1002 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1003 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1004 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1006 {-1, COLOR_WINDOWFRAME}
1009 static const signed char LTInnerNormal[] = {
1011 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1012 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1016 static const signed char LTOuterNormal[] = {
1017 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1018 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1019 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1020 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1023 static const signed char RBInnerNormal[] = {
1025 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1026 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1030 static const signed char RBOuterNormal[] = {
1031 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1032 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1033 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1034 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1037 static const signed char LTInnerSoft[] = {
1039 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1040 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1044 static const signed char LTOuterSoft[] = {
1045 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1046 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1047 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1048 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1051 #define RBInnerSoft RBInnerNormal /* These are the same */
1052 #define RBOuterSoft RBOuterNormal
1054 static const signed char LTRBOuterMono[] = {
1055 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1056 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1057 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1058 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1061 static const signed char LTRBInnerMono[] = {
1063 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1064 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1065 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1068 static const signed char LTRBOuterFlat[] = {
1069 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1070 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1071 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1072 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1075 static const signed char LTRBInnerFlat[] = {
1077 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1078 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1079 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1082 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1085 if ((EdgeColorMap[edgeType].themeProp == -1)
1086 || FAILED (GetThemeColor (theme, part, state,
1087 EdgeColorMap[edgeType].themeProp, &col)))
1088 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1092 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1094 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1097 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1099 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1102 /***********************************************************************
1105 * Same as DrawEdge invoked with BF_DIAGONAL
1107 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1108 const RECT* rc, UINT uType,
1109 UINT uFlags, LPRECT contentsRect)
1112 signed char InnerI, OuterI;
1113 HPEN InnerPen, OuterPen;
1118 int Width = rc->right - rc->left;
1119 int Height= rc->bottom - rc->top;
1120 int SmallDiam = Width > Height ? Height : Width;
1121 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1122 || (uType & BDR_OUTER) == BDR_OUTER)
1123 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1124 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1125 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1127 /* Init some vars */
1128 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1129 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1130 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1132 /* Determine the colors of the edges */
1133 if(uFlags & BF_MONO)
1135 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1136 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1138 else if(uFlags & BF_FLAT)
1140 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1141 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1143 else if(uFlags & BF_SOFT)
1145 if(uFlags & BF_BOTTOM)
1147 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1148 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1152 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1153 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1158 if(uFlags & BF_BOTTOM)
1160 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1161 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1165 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1166 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1170 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1171 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1173 MoveToEx(hdc, 0, 0, &SavePoint);
1175 /* Don't ask me why, but this is what is visible... */
1176 /* This must be possible to do much simpler, but I fail to */
1177 /* see the logic in the MS implementation (sigh...). */
1178 /* So, this might look a bit brute force here (and it is), but */
1179 /* it gets the job done;) */
1181 switch(uFlags & BF_RECT)
1187 /* Left bottom endpoint */
1189 spx = epx + SmallDiam;
1191 spy = epy - SmallDiam;
1195 case BF_BOTTOMRIGHT:
1196 /* Left top endpoint */
1198 spx = epx + SmallDiam;
1200 spy = epy + SmallDiam;
1206 case BF_RIGHT|BF_LEFT:
1207 case BF_RIGHT|BF_LEFT|BF_TOP:
1208 case BF_BOTTOM|BF_TOP:
1209 case BF_BOTTOM|BF_TOP|BF_LEFT:
1210 case BF_BOTTOMRIGHT|BF_LEFT:
1211 case BF_BOTTOMRIGHT|BF_TOP:
1213 /* Right top endpoint */
1215 epx = spx + SmallDiam;
1217 epy = spy - SmallDiam;
1221 MoveToEx(hdc, spx, spy, NULL);
1222 SelectObject(hdc, OuterPen);
1223 LineTo(hdc, epx, epy);
1225 SelectObject(hdc, InnerPen);
1227 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1229 case BF_DIAGONAL_ENDBOTTOMLEFT:
1230 case (BF_DIAGONAL|BF_BOTTOM):
1232 case (BF_DIAGONAL|BF_LEFT):
1233 MoveToEx(hdc, spx-1, spy, NULL);
1234 LineTo(hdc, epx, epy-1);
1235 Points[0].x = spx-add;
1237 Points[1].x = rc->left;
1238 Points[1].y = rc->top;
1239 Points[2].x = epx+1;
1240 Points[2].y = epy-1-add;
1241 Points[3] = Points[2];
1244 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1245 MoveToEx(hdc, spx-1, spy, NULL);
1246 LineTo(hdc, epx, epy+1);
1247 Points[0].x = spx-add;
1249 Points[1].x = rc->left;
1250 Points[1].y = rc->bottom-1;
1251 Points[2].x = epx+1;
1252 Points[2].y = epy+1+add;
1253 Points[3] = Points[2];
1256 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1257 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1258 case BF_DIAGONAL_ENDTOPRIGHT:
1259 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1260 MoveToEx(hdc, spx+1, spy, NULL);
1261 LineTo(hdc, epx, epy+1);
1262 Points[0].x = epx-1;
1263 Points[0].y = epy+1+add;
1264 Points[1].x = rc->right-1;
1265 Points[1].y = rc->top+add;
1266 Points[2].x = rc->right-1;
1267 Points[2].y = rc->bottom-1;
1268 Points[3].x = spx+add;
1272 case BF_DIAGONAL_ENDTOPLEFT:
1273 MoveToEx(hdc, spx, spy-1, NULL);
1274 LineTo(hdc, epx+1, epy);
1275 Points[0].x = epx+1+add;
1276 Points[0].y = epy+1;
1277 Points[1].x = rc->right-1;
1278 Points[1].y = rc->top;
1279 Points[2].x = rc->right-1;
1280 Points[2].y = rc->bottom-1-add;
1282 Points[3].y = spy-add;
1285 case (BF_DIAGONAL|BF_TOP):
1286 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1287 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1288 MoveToEx(hdc, spx+1, spy-1, NULL);
1289 LineTo(hdc, epx, epy);
1290 Points[0].x = epx-1;
1291 Points[0].y = epy+1;
1292 Points[1].x = rc->right-1;
1293 Points[1].y = rc->top;
1294 Points[2].x = rc->right-1;
1295 Points[2].y = rc->bottom-1-add;
1296 Points[3].x = spx+add;
1297 Points[3].y = spy-add;
1300 case (BF_DIAGONAL|BF_RIGHT):
1301 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1302 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1303 MoveToEx(hdc, spx, spy, NULL);
1304 LineTo(hdc, epx-1, epy+1);
1307 Points[1].x = rc->left;
1308 Points[1].y = rc->top+add;
1309 Points[2].x = epx-1-add;
1310 Points[2].y = epy+1+add;
1311 Points[3] = Points[2];
1315 /* Fill the interior if asked */
1316 if((uFlags & BF_MIDDLE) && retval)
1319 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1320 theme, part, state);
1322 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1323 theme, part, state);
1324 hbsave = (HBRUSH)SelectObject(hdc, hb);
1325 hpsave = (HPEN)SelectObject(hdc, hp);
1326 Polygon(hdc, Points, 4);
1327 SelectObject(hdc, hbsave);
1328 SelectObject(hdc, hpsave);
1333 /* Adjust rectangle if asked */
1334 if(uFlags & BF_ADJUST)
1336 *contentsRect = *rc;
1337 if(uFlags & BF_LEFT) contentsRect->left += add;
1338 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1339 if(uFlags & BF_TOP) contentsRect->top += add;
1340 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1344 SelectObject(hdc, SavePen);
1345 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1346 if(InnerI != -1) DeleteObject (InnerPen);
1347 if(OuterI != -1) DeleteObject (OuterPen);
1352 /***********************************************************************
1355 * Same as DrawEdge invoked without BF_DIAGONAL
1357 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1358 const RECT* rc, UINT uType,
1359 UINT uFlags, LPRECT contentsRect)
1361 signed char LTInnerI, LTOuterI;
1362 signed char RBInnerI, RBOuterI;
1363 HPEN LTInnerPen, LTOuterPen;
1364 HPEN RBInnerPen, RBOuterPen;
1365 RECT InnerRect = *rc;
1372 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1373 || (uType & BDR_OUTER) == BDR_OUTER)
1374 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1376 /* Init some vars */
1377 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1378 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1380 /* Determine the colors of the edges */
1381 if(uFlags & BF_MONO)
1383 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1384 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1386 else if(uFlags & BF_FLAT)
1388 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1389 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1391 if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
1393 else if(uFlags & BF_SOFT)
1395 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1396 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1397 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1398 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1402 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1403 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1404 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1405 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1408 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1409 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1410 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1411 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1413 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1414 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1415 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1416 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1418 MoveToEx(hdc, 0, 0, &SavePoint);
1420 /* Draw the outer edge */
1421 SelectObject(hdc, LTOuterPen);
1424 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1425 LineTo(hdc, InnerRect.right, InnerRect.top);
1427 if(uFlags & BF_LEFT)
1429 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1430 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1432 SelectObject(hdc, RBOuterPen);
1433 if(uFlags & BF_BOTTOM)
1435 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1436 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1438 if(uFlags & BF_RIGHT)
1440 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1441 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1444 /* Draw the inner edge */
1445 SelectObject(hdc, LTInnerPen);
1448 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1449 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1451 if(uFlags & BF_LEFT)
1453 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1454 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1456 SelectObject(hdc, RBInnerPen);
1457 if(uFlags & BF_BOTTOM)
1459 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1460 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1462 if(uFlags & BF_RIGHT)
1464 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1465 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1468 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1470 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1471 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1473 if(uFlags & BF_LEFT) InnerRect.left += add;
1474 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1475 if(uFlags & BF_TOP) InnerRect.top += add;
1476 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1478 if((uFlags & BF_MIDDLE) && retval)
1480 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1481 theme, part, state);
1482 FillRect(hdc, &InnerRect, br);
1486 if(uFlags & BF_ADJUST)
1487 *contentsRect = InnerRect;
1491 SelectObject(hdc, SavePen);
1492 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1493 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1494 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1495 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1496 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1501 /***********************************************************************
1502 * DrawThemeEdge (UXTHEME.@)
1504 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1505 * difference is that it does not rely on the system colors alone, but
1506 * also allows color specification in the theme.
1508 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1509 int iStateId, const RECT *pDestRect, UINT uEdge,
1510 UINT uFlags, RECT *pContentRect)
1512 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1516 if(uFlags & BF_DIAGONAL)
1517 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1518 uEdge, uFlags, pContentRect);
1520 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1521 uEdge, uFlags, pContentRect);
1525 /***********************************************************************
1526 * DrawThemeIcon (UXTHEME.@)
1528 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1529 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1531 FIXME("%d %d: stub\n", iPartId, iStateId);
1534 return ERROR_CALL_NOT_IMPLEMENTED;
1537 /***********************************************************************
1538 * DrawThemeText (UXTHEME.@)
1540 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1541 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1542 DWORD dwTextFlags2, const RECT *pRect)
1546 HGDIOBJ oldFont = NULL;
1549 COLORREF oldTextColor;
1553 TRACE("%d %d: stub\n", iPartId, iStateId);
1557 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1559 hFont = CreateFontIndirectW(&logfont);
1561 TRACE("Failed to create font\n");
1563 CopyRect(&rt, pRect);
1565 oldFont = SelectObject(hdc, hFont);
1567 if(dwTextFlags2 & DTT_GRAYED)
1568 textColor = GetSysColor(COLOR_GRAYTEXT);
1570 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1571 textColor = GetTextColor(hdc);
1573 oldTextColor = SetTextColor(hdc, textColor);
1574 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1575 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1576 SetBkMode(hdc, oldBkMode);
1577 SetTextColor(hdc, oldTextColor);
1580 SelectObject(hdc, oldFont);
1581 DeleteObject(hFont);
1586 /***********************************************************************
1587 * GetThemeBackgroundContentRect (UXTHEME.@)
1589 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1591 const RECT *pBoundingRect,
1597 TRACE("(%d,%d)\n", iPartId, iStateId);
1601 /* try content margins property... */
1602 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1604 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1605 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1606 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1607 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1609 /* otherwise, try to determine content rect from the background type and props */
1610 int bgtype = BT_BORDERFILL;
1611 memcpy(pContentRect, pBoundingRect, sizeof(RECT));
1613 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1614 if(bgtype == BT_BORDERFILL) {
1617 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1618 InflateRect(pContentRect, -bordersize, -bordersize);
1619 } else if ((bgtype == BT_IMAGEFILE)
1620 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1621 TMT_SIZINGMARGINS, NULL, &margin)))) {
1622 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1623 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1624 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1625 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1627 /* If nothing was found, leave unchanged */
1630 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1635 /***********************************************************************
1636 * GetThemeBackgroundExtent (UXTHEME.@)
1638 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1639 int iStateId, const RECT *pContentRect,
1645 TRACE("(%d,%d)\n", iPartId, iStateId);
1649 /* try content margins property... */
1650 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1652 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1653 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1654 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1655 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1657 /* otherwise, try to determine content rect from the background type and props */
1658 int bgtype = BT_BORDERFILL;
1659 memcpy(pExtentRect, pContentRect, sizeof(RECT));
1661 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1662 if(bgtype == BT_BORDERFILL) {
1665 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1666 InflateRect(pExtentRect, bordersize, bordersize);
1667 } else if ((bgtype == BT_IMAGEFILE)
1668 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1669 TMT_SIZINGMARGINS, NULL, &margin)))) {
1670 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1671 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1672 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1673 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1675 /* If nothing was found, leave unchanged */
1678 TRACE("left:%ld,top:%ld,right:%ld,bottom:%ld\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1683 /***********************************************************************
1684 * GetThemeBackgroundRegion (UXTHEME.@)
1686 * Calculate the background region, taking into consideration transparent areas
1687 * of the background image.
1689 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1690 int iStateId, const RECT *pRect,
1694 int bgtype = BT_BORDERFILL;
1696 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1699 if(!pRect || !pRegion)
1702 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1703 if(bgtype == BT_IMAGEFILE) {
1704 FIXME("Images not handled yet\n");
1705 hr = ERROR_CALL_NOT_IMPLEMENTED;
1707 else if(bgtype == BT_BORDERFILL) {
1708 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1710 hr = HRESULT_FROM_WIN32(GetLastError());
1713 FIXME("Unknown background type\n");
1714 /* This should never happen, and hence I don't know what to return */
1720 /* compute part size for "borderfill" backgrounds */
1721 HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1722 int iStateId, THEMESIZE eSize, POINT* psz)
1727 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1730 psz->x = psz->y = 2*bordersize;
1731 if (eSize != TS_MIN)
1740 /***********************************************************************
1741 * GetThemePartSize (UXTHEME.@)
1743 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1744 int iStateId, RECT *prc, THEMESIZE eSize,
1747 int bgtype = BT_BORDERFILL;
1749 POINT size = {1, 1};
1754 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1755 if (bgtype == BT_NONE)
1757 else if(bgtype == BT_IMAGEFILE)
1758 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1759 else if(bgtype == BT_BORDERFILL)
1760 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1762 FIXME("Unknown background type\n");
1763 /* This should never happen, and hence I don't know what to return */
1772 /***********************************************************************
1773 * GetThemeTextExtent (UXTHEME.@)
1775 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1776 int iStateId, LPCWSTR pszText, int iCharCount,
1777 DWORD dwTextFlags, const RECT *pBoundingRect,
1782 HGDIOBJ oldFont = NULL;
1784 RECT rt = {0,0,0xFFFF,0xFFFF};
1786 TRACE("%d %d: stub\n", iPartId, iStateId);
1791 CopyRect(&rt, pBoundingRect);
1793 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1795 hFont = CreateFontIndirectW(&logfont);
1797 TRACE("Failed to create font\n");
1800 oldFont = SelectObject(hdc, hFont);
1802 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1803 CopyRect(pExtentRect, &rt);
1806 SelectObject(hdc, oldFont);
1807 DeleteObject(hFont);
1812 /***********************************************************************
1813 * GetThemeTextMetrics (UXTHEME.@)
1815 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1816 int iStateId, TEXTMETRICW *ptm)
1820 HGDIOBJ oldFont = NULL;
1823 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1827 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1829 hFont = CreateFontIndirectW(&logfont);
1831 TRACE("Failed to create font\n");
1834 oldFont = SelectObject(hdc, hFont);
1836 if(!GetTextMetricsW(hdc, ptm))
1837 hr = HRESULT_FROM_WIN32(GetLastError());
1840 SelectObject(hdc, oldFont);
1841 DeleteObject(hFont);
1846 /***********************************************************************
1847 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1849 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1852 int bgtype = BT_BORDERFILL;
1853 RECT rect = {0, 0, 0, 0};
1858 COLORREF transparentcolor;
1860 TRACE("(%d,%d)\n", iPartId, iStateId);
1865 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1867 if (bgtype != BT_IMAGEFILE) return FALSE;
1869 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1870 &bmpSrc, &rcSrc, &hasAlpha)))
1873 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1874 &transparentcolor, FALSE);
1875 return (transparent != ALPHABLEND_NONE);