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 hr = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled),
59 (HANDLE)(dwFlags|0x80000000));
60 /* 0x80000000 serves as a "flags set" flag */
63 if (dwFlags & ETDT_USETABTEXTURE)
64 return SetWindowTheme (hwnd, NULL, szTab);
66 return SetWindowTheme (hwnd, NULL, NULL);
70 /***********************************************************************
71 * IsThemeDialogTextureEnabled (UXTHEME.@)
73 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
75 DWORD dwDialogTextureFlags;
76 TRACE("(%p)\n", hwnd);
78 dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
79 (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled));
80 if (dwDialogTextureFlags == 0)
81 /* Means EnableThemeDialogTexture wasn't called for this dialog */
84 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
87 /***********************************************************************
88 * DrawThemeParentBackground (UXTHEME.@)
90 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
98 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
99 hParent = GetParent(hwnd);
104 MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
106 clip = CreateRectRgn(0,0,1,1);
107 hasClip = GetClipRgn(hdc, clip);
109 TRACE("Failed to get original clipping region\n");
111 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
114 GetClientRect(hParent, &rt);
115 MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
118 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
120 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
121 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
123 SetViewportOrgEx(hdc, org.x, org.y, NULL);
126 SelectClipRgn(hdc, NULL);
127 else if(hasClip == 1)
128 SelectClipRgn(hdc, clip);
135 /***********************************************************************
136 * DrawThemeBackground (UXTHEME.@)
138 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
139 int iStateId, const RECT *pRect,
140 const RECT *pClipRect)
143 opts.dwSize = sizeof(DTBGOPTS);
146 opts.dwFlags |= DTBG_CLIPRECT;
147 CopyRect(&opts.rcClip, pClipRect);
149 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
152 /***********************************************************************
153 * UXTHEME_SelectImage
155 * Select the image to use
157 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
160 int imageselecttype = IST_NONE;
164 image = TMT_GLYPHIMAGEFILE;
166 image = TMT_IMAGEFILE;
168 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
170 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
172 if(imageselecttype == IST_DPI) {
174 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
175 for(i=4; i>=0; i--) {
177 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
178 if(reqdpi != 0 && screendpi >= reqdpi) {
179 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
180 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
184 /* If an image couldn't be selected, choose the first one */
185 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
187 else if(imageselecttype == IST_SIZE) {
188 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
190 for(i=4; i>=0; i--) {
191 PTHEME_PROPERTY fileProp =
192 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
193 if (!fileProp) continue;
194 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
195 /* fall back to size of Nth image */
196 WCHAR szPath[MAX_PATH];
197 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 GetObjectW(hBmp, sizeof(bmp), &bmp);
212 if(imagelayout == IL_VERTICAL) {
213 reqsize.x = bmp.bmWidth;
214 reqsize.y = bmp.bmHeight/imagecount;
217 reqsize.x = bmp.bmWidth/imagecount;
218 reqsize.y = bmp.bmHeight;
221 if(reqsize.x <= size.x && reqsize.y <= size.y) {
222 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
226 /* If an image couldn't be selected, choose the smallest one */
227 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
232 /***********************************************************************
235 * Load image for part/state
237 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
238 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
240 int imagelayout = IL_HORIZONTAL;
244 WCHAR szPath[MAX_PATH];
245 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
247 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
248 return E_PROP_ID_UNSUPPORTED;
250 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
251 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
253 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
254 return HRESULT_FROM_WIN32(GetLastError());
257 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
258 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
260 imagenum = max (min (imagecount, iStateId), 1) - 1;
261 GetObjectW(*hBmp, sizeof(bmp), &bmp);
262 if(imagelayout == IL_VERTICAL) {
263 int height = bmp.bmHeight/imagecount;
265 bmpRect->right = bmp.bmWidth;
266 bmpRect->top = imagenum * height;
267 bmpRect->bottom = bmpRect->top + height;
270 int width = bmp.bmWidth/imagecount;
271 bmpRect->left = imagenum * width;
272 bmpRect->right = bmpRect->left + width;
274 bmpRect->bottom = bmp.bmHeight;
279 /***********************************************************************
282 * Pseudo TransparentBlt/StretchBlt
284 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
285 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
286 INT transparent, COLORREF transcolor)
288 static const BLENDFUNCTION blendFunc =
290 AC_SRC_OVER, /* BlendOp */
292 255, /* SourceConstantAlpha */
293 AC_SRC_ALPHA /* AlphaFormat */
295 if (transparent == ALPHABLEND_BINARY) {
296 /* Ensure we don't pass any negative values to TransparentBlt */
297 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
298 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
301 if ((transparent == ALPHABLEND_NONE) ||
302 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
303 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
306 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
307 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
313 /***********************************************************************
316 * Simplify sending same width/height for both source and dest
318 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
319 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
320 INT transparent, COLORREF transcolor)
322 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
323 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
324 transparent, transcolor);
327 /***********************************************************************
330 * Stretches or tiles, depending on sizingtype.
332 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
333 int nWidthDst, int nHeightDst,
334 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
335 int nWidthSrc, int nHeightSrc,
337 INT transparent, COLORREF transcolor)
339 if (sizingtype == ST_TILE)
344 if (!nWidthSrc || !nHeightSrc) return TRUE;
346 /* For destination width/height less than or equal to source
347 width/height, do not bother with memory bitmap optimization */
348 if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
350 int bltWidth = min (nWidthDst, nWidthSrc);
351 int bltHeight = min (nHeightDst, nHeightSrc);
353 return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
354 hdcSrc, nXOriginSrc, nYOriginSrc,
355 transparent, transcolor);
358 /* Create a DC with a bitmap consisting of a tiling of the source
359 bitmap, with standard GDI functions. This is faster than an
360 iteration with UXTHEME_Blt(). */
361 hdcTemp = CreateCompatibleDC(hdcSrc);
366 int nWidthTemp, nHeightTemp;
367 int xOfs, xRemaining;
368 int yOfs, yRemaining;
371 /* Calculate temp dimensions of integer multiples of source dimensions */
372 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
373 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
374 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
375 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
377 /* Initial copy of bitmap */
378 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
380 /* Extend bitmap in the X direction. Growth of width is exponential */
382 xRemaining = nWidthTemp - nWidthSrc;
383 growSize = nWidthSrc;
384 while (xRemaining > 0)
386 growSize = min(growSize, xRemaining);
387 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
389 xRemaining -= growSize;
393 /* Extend bitmap in the Y direction. Growth of height is exponential */
395 yRemaining = nHeightTemp - nHeightSrc;
396 growSize = nHeightSrc;
397 while (yRemaining > 0)
399 growSize = min(growSize, yRemaining);
400 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
402 yRemaining -= growSize;
406 /* Use temporary hdc for source */
407 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
409 transparent, transcolor);
411 SelectObject(hdcTemp, bitmapOrig);
412 DeleteObject(bitmapTemp);
419 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
420 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
421 transparent, transcolor);
425 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
426 * depend on whether the image has full alpha or whether it is
427 * color-transparent or just opaque. */
428 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
429 BOOL hasImageAlpha, INT* transparent,
430 COLORREF* transparentcolor, BOOL glyph)
434 *transparent = ALPHABLEND_FULL;
435 *transparentcolor = RGB (255, 0, 255);
440 GetThemeBool(hTheme, iPartId, iStateId,
441 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
443 *transparent = ALPHABLEND_BINARY;
444 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
445 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
446 transparentcolor))) {
447 /* If image is transparent, but no color was specified, use magenta */
448 *transparentcolor = RGB(255, 0, 255);
452 *transparent = ALPHABLEND_NONE;
456 /***********************************************************************
457 * UXTHEME_DrawImageGlyph
459 * Draw an imagefile glyph
461 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
462 int iStateId, RECT *pRect,
463 const DTBGOPTS *pOptions)
466 HBITMAP bmpSrc = NULL;
468 HGDIOBJ oldSrc = NULL;
470 INT transparent = FALSE;
471 COLORREF transparentcolor;
472 int valign = VA_CENTER;
473 int halign = HA_CENTER;
479 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
480 &bmpSrc, &rcSrc, &hasAlpha);
481 if(FAILED(hr)) return hr;
482 hdcSrc = CreateCompatibleDC(hdc);
484 hr = HRESULT_FROM_WIN32(GetLastError());
487 oldSrc = SelectObject(hdcSrc, bmpSrc);
489 dstSize.x = pRect->right-pRect->left;
490 dstSize.y = pRect->bottom-pRect->top;
491 srcSize.x = rcSrc.right-rcSrc.left;
492 srcSize.y = rcSrc.bottom-rcSrc.top;
494 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
495 &transparentcolor, TRUE);
496 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
497 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
499 topleft.x = pRect->left;
500 topleft.y = pRect->top;
501 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
502 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
503 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
504 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
506 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
507 hdcSrc, rcSrc.left, rcSrc.top,
508 transparent, transparentcolor)) {
509 hr = HRESULT_FROM_WIN32(GetLastError());
512 SelectObject(hdcSrc, oldSrc);
517 /***********************************************************************
518 * UXTHEME_DrawImageGlyph
520 * Draw glyph on top of background, if appropriate
522 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
523 int iStateId, RECT *pRect,
524 const DTBGOPTS *pOptions)
526 int glyphtype = GT_NONE;
528 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
530 if(glyphtype == GT_IMAGEGLYPH) {
531 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
533 else if(glyphtype == GT_FONTGLYPH) {
534 /* I don't know what a font glyph is, I've never seen it used in any themes */
535 FIXME("Font glyph\n");
540 /***********************************************************************
541 * get_image_part_size
543 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
545 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
546 int iStateId, RECT *prc, THEMESIZE eSize,
554 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
555 &bmpSrc, &rcSrc, &hasAlpha);
556 if (FAILED(hr)) return hr;
566 int sizingtype = ST_STRETCH;
567 BOOL uniformsizing = FALSE;
569 CopyRect(&rcDst, prc);
571 dstSize.x = rcDst.right-rcDst.left;
572 dstSize.y = rcDst.bottom-rcDst.top;
573 srcSize.x = rcSrc.right-rcSrc.left;
574 srcSize.y = rcSrc.bottom-rcSrc.top;
576 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
578 /* Scale height and width equally */
579 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
581 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
582 rcDst.bottom = rcDst.top + dstSize.y;
586 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
587 rcDst.right = rcDst.left + dstSize.x;
591 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
592 if(sizingtype == ST_TRUESIZE) {
593 int truesizestretchmark = 100;
595 if(dstSize.x < 0 || dstSize.y < 0) {
596 BOOL mirrorimage = TRUE;
597 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
600 rcDst.left += dstSize.x;
601 rcDst.right += dstSize.x;
604 rcDst.top += dstSize.y;
605 rcDst.bottom += dstSize.y;
609 /* Whatever TrueSizeStretchMark does - it does not seem to
610 * be what's outlined below. It appears as if native
611 * uxtheme always stretches if dest is smaller than source
612 * (ie as if TrueSizeStretchMark==100 with the code below) */
614 /* Only stretch when target exceeds source by truesizestretchmark percent */
615 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
617 if(dstSize.x < 0 || dstSize.y < 0 ||
618 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
619 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
620 memcpy (psz, &dstSize, sizeof (SIZE));
623 memcpy (psz, &srcSize, sizeof (SIZE));
628 psz->x = abs(dstSize.x);
629 psz->y = abs(dstSize.y);
633 /* else fall through */
635 /* FIXME: couldn't figure how native uxtheme computes min size */
637 psz->x = rcSrc.right - rcSrc.left;
638 psz->y = rcSrc.bottom - rcSrc.top;
644 /***********************************************************************
645 * UXTHEME_DrawImageBackground
647 * Draw an imagefile background
649 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
650 int iStateId, RECT *pRect,
651 const DTBGOPTS *pOptions)
662 int sizingtype = ST_STRETCH;
664 COLORREF transparentcolor = 0;
667 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
668 &bmpSrc, &rcSrc, &hasAlpha);
669 if(FAILED(hr)) return hr;
670 hdcSrc = CreateCompatibleDC(hdc);
672 hr = HRESULT_FROM_WIN32(GetLastError());
675 oldSrc = SelectObject(hdcSrc, bmpSrc);
677 CopyRect(&rcDst, pRect);
679 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
680 &transparentcolor, FALSE);
682 dstSize.x = rcDst.right-rcDst.left;
683 dstSize.y = rcDst.bottom-rcDst.top;
684 srcSize.x = rcSrc.right-rcSrc.left;
685 srcSize.y = rcSrc.bottom-rcSrc.top;
687 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
688 if(sizingtype == ST_TRUESIZE) {
689 int valign = VA_CENTER, halign = HA_CENTER;
691 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
692 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
693 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
695 if (halign == HA_CENTER)
696 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
697 else if (halign == HA_RIGHT)
698 rcDst.left = rcDst.right - drawSize.x;
699 if (valign == VA_CENTER)
700 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
701 else if (valign == VA_BOTTOM)
702 rcDst.top = rcDst.bottom - drawSize.y;
703 rcDst.right = rcDst.left + drawSize.x;
704 rcDst.bottom = rcDst.top + drawSize.y;
705 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
706 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
707 transparent, transparentcolor))
708 hr = HRESULT_FROM_WIN32(GetLastError());
715 dstSize.x = abs(dstSize.x);
716 dstSize.y = abs(dstSize.y);
718 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
721 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
723 /* Upper left corner */
724 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
725 hdcSrc, rcSrc.left, rcSrc.top,
726 transparent, transparentcolor)) {
727 hr = HRESULT_FROM_WIN32(GetLastError());
730 /* Upper right corner */
731 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
732 sm.cxRightWidth, sm.cyTopHeight,
733 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
734 transparent, transparentcolor)) {
735 hr = HRESULT_FROM_WIN32(GetLastError());
738 /* Lower left corner */
739 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
740 sm.cxLeftWidth, sm.cyBottomHeight,
741 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
742 transparent, transparentcolor)) {
743 hr = HRESULT_FROM_WIN32(GetLastError());
746 /* Lower right corner */
747 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
748 sm.cxRightWidth, sm.cyBottomHeight,
749 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
750 transparent, transparentcolor)) {
751 hr = HRESULT_FROM_WIN32(GetLastError());
755 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
756 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
757 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
758 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
759 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
761 if(destCenterWidth > 0) {
763 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
764 destCenterWidth, sm.cyTopHeight,
765 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
766 srcCenterWidth, sm.cyTopHeight,
767 sizingtype, transparent, transparentcolor)) {
768 hr = HRESULT_FROM_WIN32(GetLastError());
772 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
773 destCenterWidth, sm.cyBottomHeight,
774 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
775 srcCenterWidth, sm.cyBottomHeight,
776 sizingtype, transparent, transparentcolor)) {
777 hr = HRESULT_FROM_WIN32(GetLastError());
781 if(destCenterHeight > 0) {
783 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
784 sm.cxLeftWidth, destCenterHeight,
785 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
786 sm.cxLeftWidth, srcCenterHeight,
788 transparent, transparentcolor)) {
789 hr = HRESULT_FROM_WIN32(GetLastError());
793 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
794 sm.cxRightWidth, destCenterHeight,
795 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
796 sm.cxRightWidth, srcCenterHeight,
797 sizingtype, transparent, transparentcolor)) {
798 hr = HRESULT_FROM_WIN32(GetLastError());
802 if(destCenterHeight > 0 && destCenterWidth > 0) {
803 BOOL borderonly = FALSE;
804 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
807 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
808 destCenterWidth, destCenterHeight,
809 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
810 srcCenterWidth, srcCenterHeight,
811 sizingtype, transparent, transparentcolor)) {
812 hr = HRESULT_FROM_WIN32(GetLastError());
820 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
822 SelectObject(hdcSrc, oldSrc);
824 CopyRect(pRect, &rcDst);
828 /***********************************************************************
829 * UXTHEME_DrawBorderRectangle
831 * Draw the bounding rectangle for a borderfill background
833 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
834 int iStateId, RECT *pRect,
835 const DTBGOPTS *pOptions)
840 COLORREF bordercolor = RGB(0,0,0);
843 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
846 ptCorners[0].x = pRect->left;
847 ptCorners[0].y = pRect->top;
848 ptCorners[1].x = pRect->right-1;
849 ptCorners[1].y = pRect->top;
850 ptCorners[2].x = pRect->right-1;
851 ptCorners[2].y = pRect->bottom-1;
852 ptCorners[3].x = pRect->left;
853 ptCorners[3].y = pRect->bottom-1;
854 ptCorners[4].x = pRect->left;
855 ptCorners[4].y = pRect->top;
857 InflateRect(pRect, -bordersize, -bordersize);
858 if(pOptions->dwFlags & DTBG_OMITBORDER)
860 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
861 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
863 return HRESULT_FROM_WIN32(GetLastError());
864 oldPen = SelectObject(hdc, hPen);
866 if(!Polyline(hdc, ptCorners, 5))
867 hr = HRESULT_FROM_WIN32(GetLastError());
869 SelectObject(hdc, oldPen);
875 /***********************************************************************
876 * UXTHEME_DrawBackgroundFill
878 * Fill a borderfill background rectangle
880 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
881 int iStateId, RECT *pRect,
882 const DTBGOPTS *pOptions)
885 int filltype = FT_SOLID;
887 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
889 if(pOptions->dwFlags & DTBG_OMITCONTENT)
892 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
894 if(filltype == FT_SOLID) {
896 COLORREF fillcolor = RGB(255,255,255);
898 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
899 hBrush = CreateSolidBrush(fillcolor);
900 if(!FillRect(hdc, pRect, hBrush))
901 hr = HRESULT_FROM_WIN32(GetLastError());
902 DeleteObject(hBrush);
904 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
905 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
906 the gradient ratios (no idea how those work)
907 Few themes use this, and the ones I've seen only use 2 colors with
908 a gradient ratio of 0 and 255 respectively
911 COLORREF gradient1 = RGB(0,0,0);
912 COLORREF gradient2 = RGB(255,255,255);
916 FIXME("Gradient implementation not complete\n");
918 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
919 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
921 vert[0].x = pRect->left;
922 vert[0].y = pRect->top;
923 vert[0].Red = GetRValue(gradient1) << 8;
924 vert[0].Green = GetGValue(gradient1) << 8;
925 vert[0].Blue = GetBValue(gradient1) << 8;
926 vert[0].Alpha = 0x0000;
928 vert[1].x = pRect->right;
929 vert[1].y = pRect->bottom;
930 vert[1].Red = GetRValue(gradient2) << 8;
931 vert[1].Green = GetGValue(gradient2) << 8;
932 vert[1].Blue = GetBValue(gradient2) << 8;
933 vert[1].Alpha = 0x0000;
936 gRect.LowerRight = 1;
937 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
939 else if(filltype == FT_RADIALGRADIENT) {
940 /* I've never seen this used in a theme */
941 FIXME("Radial gradient\n");
943 else if(filltype == FT_TILEIMAGE) {
944 /* I've never seen this used in a theme */
945 FIXME("Tile image\n");
950 /***********************************************************************
951 * UXTHEME_DrawBorderBackground
953 * Draw an imagefile background
955 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
956 int iStateId, const RECT *pRect,
957 const DTBGOPTS *pOptions)
962 CopyRect(&rt, pRect);
964 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
967 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
970 /***********************************************************************
971 * DrawThemeBackgroundEx (UXTHEME.@)
973 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
974 int iStateId, const RECT *pRect,
975 const DTBGOPTS *pOptions)
978 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
979 const DTBGOPTS *opts;
982 int bgtype = BT_BORDERFILL;
985 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
989 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
990 if (bgtype == BT_NONE) return S_OK;
992 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
994 if(!opts) opts = &defaultOpts;
996 if(opts->dwFlags & DTBG_CLIPRECT) {
997 clip = CreateRectRgn(0,0,1,1);
998 hasClip = GetClipRgn(hdc, clip);
1000 TRACE("Failed to get original clipping region\n");
1002 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
1004 CopyRect(&rt, pRect);
1006 if(bgtype == BT_IMAGEFILE)
1007 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
1008 else if(bgtype == BT_BORDERFILL)
1009 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
1011 FIXME("Unknown background type\n");
1012 /* This should never happen, and hence I don't know what to return */
1016 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1017 if(opts->dwFlags & DTBG_CLIPRECT) {
1019 SelectClipRgn(hdc, NULL);
1020 else if(hasClip == 1)
1021 SelectClipRgn(hdc, clip);
1028 * DrawThemeEdge() implementation
1030 * Since it basically is DrawEdge() with different colors, I copied its code
1031 * from user32's uitools.c.
1052 } EdgeColorMap[EDGE_NUMCOLORS] = {
1053 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1054 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1055 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1056 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1057 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1059 {-1, COLOR_WINDOWFRAME}
1062 static const signed char LTInnerNormal[] = {
1064 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1065 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1069 static const signed char LTOuterNormal[] = {
1070 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1071 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1072 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1073 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1076 static const signed char RBInnerNormal[] = {
1078 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1079 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1083 static const signed char RBOuterNormal[] = {
1084 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1085 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1086 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1087 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1090 static const signed char LTInnerSoft[] = {
1092 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1093 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1097 static const signed char LTOuterSoft[] = {
1098 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1099 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1100 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1101 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1104 #define RBInnerSoft RBInnerNormal /* These are the same */
1105 #define RBOuterSoft RBOuterNormal
1107 static const signed char LTRBOuterMono[] = {
1108 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1109 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1110 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1111 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1114 static const signed char LTRBInnerMono[] = {
1116 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1117 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1118 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1121 static const signed char LTRBOuterFlat[] = {
1122 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1123 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1124 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1125 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1128 static const signed char LTRBInnerFlat[] = {
1130 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1131 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1132 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1135 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1138 if ((EdgeColorMap[edgeType].themeProp == -1)
1139 || FAILED (GetThemeColor (theme, part, state,
1140 EdgeColorMap[edgeType].themeProp, &col)))
1141 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1145 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1147 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1150 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1152 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1155 /***********************************************************************
1158 * Same as DrawEdge invoked with BF_DIAGONAL
1160 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1161 const RECT* rc, UINT uType,
1162 UINT uFlags, LPRECT contentsRect)
1165 signed char InnerI, OuterI;
1166 HPEN InnerPen, OuterPen;
1171 int Width = rc->right - rc->left;
1172 int Height= rc->bottom - rc->top;
1173 int SmallDiam = Width > Height ? Height : Width;
1174 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1175 || (uType & BDR_OUTER) == BDR_OUTER)
1176 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1177 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1178 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1180 /* Init some vars */
1181 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1182 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1183 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1185 /* Determine the colors of the edges */
1186 if(uFlags & BF_MONO)
1188 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1189 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1191 else if(uFlags & BF_FLAT)
1193 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1194 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1196 else if(uFlags & BF_SOFT)
1198 if(uFlags & BF_BOTTOM)
1200 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1201 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1205 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1206 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1211 if(uFlags & BF_BOTTOM)
1213 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1214 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1218 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1219 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1223 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1224 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1226 MoveToEx(hdc, 0, 0, &SavePoint);
1228 /* Don't ask me why, but this is what is visible... */
1229 /* This must be possible to do much simpler, but I fail to */
1230 /* see the logic in the MS implementation (sigh...). */
1231 /* So, this might look a bit brute force here (and it is), but */
1232 /* it gets the job done;) */
1234 switch(uFlags & BF_RECT)
1240 /* Left bottom endpoint */
1242 spx = epx + SmallDiam;
1244 spy = epy - SmallDiam;
1248 case BF_BOTTOMRIGHT:
1249 /* Left top endpoint */
1251 spx = epx + SmallDiam;
1253 spy = epy + SmallDiam;
1259 case BF_RIGHT|BF_LEFT:
1260 case BF_RIGHT|BF_LEFT|BF_TOP:
1261 case BF_BOTTOM|BF_TOP:
1262 case BF_BOTTOM|BF_TOP|BF_LEFT:
1263 case BF_BOTTOMRIGHT|BF_LEFT:
1264 case BF_BOTTOMRIGHT|BF_TOP:
1266 /* Right top endpoint */
1268 epx = spx + SmallDiam;
1270 epy = spy - SmallDiam;
1274 MoveToEx(hdc, spx, spy, NULL);
1275 SelectObject(hdc, OuterPen);
1276 LineTo(hdc, epx, epy);
1278 SelectObject(hdc, InnerPen);
1280 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1282 case BF_DIAGONAL_ENDBOTTOMLEFT:
1283 case (BF_DIAGONAL|BF_BOTTOM):
1285 case (BF_DIAGONAL|BF_LEFT):
1286 MoveToEx(hdc, spx-1, spy, NULL);
1287 LineTo(hdc, epx, epy-1);
1288 Points[0].x = spx-add;
1290 Points[1].x = rc->left;
1291 Points[1].y = rc->top;
1292 Points[2].x = epx+1;
1293 Points[2].y = epy-1-add;
1294 Points[3] = Points[2];
1297 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1298 MoveToEx(hdc, spx-1, spy, NULL);
1299 LineTo(hdc, epx, epy+1);
1300 Points[0].x = spx-add;
1302 Points[1].x = rc->left;
1303 Points[1].y = rc->bottom-1;
1304 Points[2].x = epx+1;
1305 Points[2].y = epy+1+add;
1306 Points[3] = Points[2];
1309 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1310 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1311 case BF_DIAGONAL_ENDTOPRIGHT:
1312 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1313 MoveToEx(hdc, spx+1, spy, NULL);
1314 LineTo(hdc, epx, epy+1);
1315 Points[0].x = epx-1;
1316 Points[0].y = epy+1+add;
1317 Points[1].x = rc->right-1;
1318 Points[1].y = rc->top+add;
1319 Points[2].x = rc->right-1;
1320 Points[2].y = rc->bottom-1;
1321 Points[3].x = spx+add;
1325 case BF_DIAGONAL_ENDTOPLEFT:
1326 MoveToEx(hdc, spx, spy-1, NULL);
1327 LineTo(hdc, epx+1, epy);
1328 Points[0].x = epx+1+add;
1329 Points[0].y = epy+1;
1330 Points[1].x = rc->right-1;
1331 Points[1].y = rc->top;
1332 Points[2].x = rc->right-1;
1333 Points[2].y = rc->bottom-1-add;
1335 Points[3].y = spy-add;
1338 case (BF_DIAGONAL|BF_TOP):
1339 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1340 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1341 MoveToEx(hdc, spx+1, spy-1, NULL);
1342 LineTo(hdc, epx, epy);
1343 Points[0].x = epx-1;
1344 Points[0].y = epy+1;
1345 Points[1].x = rc->right-1;
1346 Points[1].y = rc->top;
1347 Points[2].x = rc->right-1;
1348 Points[2].y = rc->bottom-1-add;
1349 Points[3].x = spx+add;
1350 Points[3].y = spy-add;
1353 case (BF_DIAGONAL|BF_RIGHT):
1354 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1355 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1356 MoveToEx(hdc, spx, spy, NULL);
1357 LineTo(hdc, epx-1, epy+1);
1360 Points[1].x = rc->left;
1361 Points[1].y = rc->top+add;
1362 Points[2].x = epx-1-add;
1363 Points[2].y = epy+1+add;
1364 Points[3] = Points[2];
1368 /* Fill the interior if asked */
1369 if((uFlags & BF_MIDDLE) && retval)
1372 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1373 theme, part, state);
1375 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1376 theme, part, state);
1377 hbsave = (HBRUSH)SelectObject(hdc, hb);
1378 hpsave = (HPEN)SelectObject(hdc, hp);
1379 Polygon(hdc, Points, 4);
1380 SelectObject(hdc, hbsave);
1381 SelectObject(hdc, hpsave);
1386 /* Adjust rectangle if asked */
1387 if(uFlags & BF_ADJUST)
1389 *contentsRect = *rc;
1390 if(uFlags & BF_LEFT) contentsRect->left += add;
1391 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1392 if(uFlags & BF_TOP) contentsRect->top += add;
1393 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1397 SelectObject(hdc, SavePen);
1398 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1399 if(InnerI != -1) DeleteObject (InnerPen);
1400 if(OuterI != -1) DeleteObject (OuterPen);
1405 /***********************************************************************
1408 * Same as DrawEdge invoked without BF_DIAGONAL
1410 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1411 const RECT* rc, UINT uType,
1412 UINT uFlags, LPRECT contentsRect)
1414 signed char LTInnerI, LTOuterI;
1415 signed char RBInnerI, RBOuterI;
1416 HPEN LTInnerPen, LTOuterPen;
1417 HPEN RBInnerPen, RBOuterPen;
1418 RECT InnerRect = *rc;
1425 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1426 || (uType & BDR_OUTER) == BDR_OUTER)
1427 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1429 /* Init some vars */
1430 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1431 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1433 /* Determine the colors of the edges */
1434 if(uFlags & BF_MONO)
1436 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1437 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1439 else if(uFlags & BF_FLAT)
1441 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1442 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1444 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1446 else if(uFlags & BF_SOFT)
1448 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1449 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1450 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1451 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1455 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1456 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1457 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1458 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1461 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1462 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1463 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1464 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1466 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1467 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1468 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1469 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1471 MoveToEx(hdc, 0, 0, &SavePoint);
1473 /* Draw the outer edge */
1474 SelectObject(hdc, LTOuterPen);
1477 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1478 LineTo(hdc, InnerRect.right, InnerRect.top);
1480 if(uFlags & BF_LEFT)
1482 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1483 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1485 SelectObject(hdc, RBOuterPen);
1486 if(uFlags & BF_BOTTOM)
1488 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1489 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1491 if(uFlags & BF_RIGHT)
1493 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1494 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1497 /* Draw the inner edge */
1498 SelectObject(hdc, LTInnerPen);
1501 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1502 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1504 if(uFlags & BF_LEFT)
1506 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1507 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1509 SelectObject(hdc, RBInnerPen);
1510 if(uFlags & BF_BOTTOM)
1512 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1513 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1515 if(uFlags & BF_RIGHT)
1517 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1518 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1521 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1523 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1524 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1526 if(uFlags & BF_LEFT) InnerRect.left += add;
1527 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1528 if(uFlags & BF_TOP) InnerRect.top += add;
1529 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1531 if((uFlags & BF_MIDDLE) && retval)
1533 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1534 theme, part, state);
1535 FillRect(hdc, &InnerRect, br);
1539 if(uFlags & BF_ADJUST)
1540 *contentsRect = InnerRect;
1544 SelectObject(hdc, SavePen);
1545 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1546 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1547 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1548 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1549 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1554 /***********************************************************************
1555 * DrawThemeEdge (UXTHEME.@)
1557 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1558 * difference is that it does not rely on the system colors alone, but
1559 * also allows color specification in the theme.
1561 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1562 int iStateId, const RECT *pDestRect, UINT uEdge,
1563 UINT uFlags, RECT *pContentRect)
1565 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1569 if(uFlags & BF_DIAGONAL)
1570 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1571 uEdge, uFlags, pContentRect);
1573 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1574 uEdge, uFlags, pContentRect);
1578 /***********************************************************************
1579 * DrawThemeIcon (UXTHEME.@)
1581 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1582 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1584 FIXME("%d %d: stub\n", iPartId, iStateId);
1587 return ERROR_CALL_NOT_IMPLEMENTED;
1590 /***********************************************************************
1591 * DrawThemeText (UXTHEME.@)
1593 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1594 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1595 DWORD dwTextFlags2, const RECT *pRect)
1599 HGDIOBJ oldFont = NULL;
1602 COLORREF oldTextColor;
1606 TRACE("%d %d: stub\n", iPartId, iStateId);
1610 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1612 hFont = CreateFontIndirectW(&logfont);
1614 TRACE("Failed to create font\n");
1616 CopyRect(&rt, pRect);
1618 oldFont = SelectObject(hdc, hFont);
1620 if(dwTextFlags2 & DTT_GRAYED)
1621 textColor = GetSysColor(COLOR_GRAYTEXT);
1623 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1624 textColor = GetTextColor(hdc);
1626 oldTextColor = SetTextColor(hdc, textColor);
1627 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1628 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1629 SetBkMode(hdc, oldBkMode);
1630 SetTextColor(hdc, oldTextColor);
1633 SelectObject(hdc, oldFont);
1634 DeleteObject(hFont);
1639 /***********************************************************************
1640 * GetThemeBackgroundContentRect (UXTHEME.@)
1642 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1644 const RECT *pBoundingRect,
1650 TRACE("(%d,%d)\n", iPartId, iStateId);
1654 /* try content margins property... */
1655 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1657 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1658 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1659 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1660 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1662 /* otherwise, try to determine content rect from the background type and props */
1663 int bgtype = BT_BORDERFILL;
1664 *pContentRect = *pBoundingRect;
1666 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1667 if(bgtype == BT_BORDERFILL) {
1670 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1671 InflateRect(pContentRect, -bordersize, -bordersize);
1672 } else if ((bgtype == BT_IMAGEFILE)
1673 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1674 TMT_SIZINGMARGINS, NULL, &margin)))) {
1675 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1676 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1677 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1678 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1680 /* If nothing was found, leave unchanged */
1683 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1688 /***********************************************************************
1689 * GetThemeBackgroundExtent (UXTHEME.@)
1691 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1692 int iStateId, const RECT *pContentRect,
1698 TRACE("(%d,%d)\n", iPartId, iStateId);
1702 /* try content margins property... */
1703 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1705 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1706 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1707 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1708 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1710 /* otherwise, try to determine content rect from the background type and props */
1711 int bgtype = BT_BORDERFILL;
1712 *pExtentRect = *pContentRect;
1714 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1715 if(bgtype == BT_BORDERFILL) {
1718 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1719 InflateRect(pExtentRect, bordersize, bordersize);
1720 } else if ((bgtype == BT_IMAGEFILE)
1721 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1722 TMT_SIZINGMARGINS, NULL, &margin)))) {
1723 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1724 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1725 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1726 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1728 /* If nothing was found, leave unchanged */
1731 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1736 /***********************************************************************
1737 * GetThemeBackgroundRegion (UXTHEME.@)
1739 * Calculate the background region, taking into consideration transparent areas
1740 * of the background image.
1742 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1743 int iStateId, const RECT *pRect,
1747 int bgtype = BT_BORDERFILL;
1749 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1752 if(!pRect || !pRegion)
1755 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1756 if(bgtype == BT_IMAGEFILE) {
1757 FIXME("Images not handled yet\n");
1758 hr = ERROR_CALL_NOT_IMPLEMENTED;
1760 else if(bgtype == BT_BORDERFILL) {
1761 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1763 hr = HRESULT_FROM_WIN32(GetLastError());
1766 FIXME("Unknown background type\n");
1767 /* This should never happen, and hence I don't know what to return */
1773 /* compute part size for "borderfill" backgrounds */
1774 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1775 int iStateId, THEMESIZE eSize, POINT* psz)
1780 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1783 psz->x = psz->y = 2*bordersize;
1784 if (eSize != TS_MIN)
1793 /***********************************************************************
1794 * GetThemePartSize (UXTHEME.@)
1796 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1797 int iStateId, RECT *prc, THEMESIZE eSize,
1800 int bgtype = BT_BORDERFILL;
1802 POINT size = {1, 1};
1807 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1808 if (bgtype == BT_NONE)
1810 else if(bgtype == BT_IMAGEFILE)
1811 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1812 else if(bgtype == BT_BORDERFILL)
1813 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1815 FIXME("Unknown background type\n");
1816 /* This should never happen, and hence I don't know what to return */
1825 /***********************************************************************
1826 * GetThemeTextExtent (UXTHEME.@)
1828 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1829 int iStateId, LPCWSTR pszText, int iCharCount,
1830 DWORD dwTextFlags, const RECT *pBoundingRect,
1835 HGDIOBJ oldFont = NULL;
1837 RECT rt = {0,0,0xFFFF,0xFFFF};
1839 TRACE("%d %d: stub\n", iPartId, iStateId);
1844 CopyRect(&rt, pBoundingRect);
1846 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1848 hFont = CreateFontIndirectW(&logfont);
1850 TRACE("Failed to create font\n");
1853 oldFont = SelectObject(hdc, hFont);
1855 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1856 CopyRect(pExtentRect, &rt);
1859 SelectObject(hdc, oldFont);
1860 DeleteObject(hFont);
1865 /***********************************************************************
1866 * GetThemeTextMetrics (UXTHEME.@)
1868 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1869 int iStateId, TEXTMETRICW *ptm)
1873 HGDIOBJ oldFont = NULL;
1876 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1880 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1882 hFont = CreateFontIndirectW(&logfont);
1884 TRACE("Failed to create font\n");
1887 oldFont = SelectObject(hdc, hFont);
1889 if(!GetTextMetricsW(hdc, ptm))
1890 hr = HRESULT_FROM_WIN32(GetLastError());
1893 SelectObject(hdc, oldFont);
1894 DeleteObject(hFont);
1899 /***********************************************************************
1900 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1902 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1905 int bgtype = BT_BORDERFILL;
1906 RECT rect = {0, 0, 0, 0};
1911 COLORREF transparentcolor;
1913 TRACE("(%d,%d)\n", iPartId, iStateId);
1918 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1920 if (bgtype != BT_IMAGEFILE) return FALSE;
1922 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1923 &bmpSrc, &rcSrc, &hasAlpha)))
1926 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1927 &transparentcolor, FALSE);
1928 return (transparent != ALPHABLEND_NONE);