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;
204 lstrcpynW(szPath, fileProp->lpValue,
205 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
206 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
209 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
210 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
212 imagenum = max (min (imagecount, iStateId), 1) - 1;
213 GetObjectW(hBmp, sizeof(bmp), &bmp);
214 if(imagelayout == IL_VERTICAL) {
215 reqsize.x = bmp.bmWidth;
216 reqsize.y = bmp.bmHeight/imagecount;
219 reqsize.x = bmp.bmWidth/imagecount;
220 reqsize.y = bmp.bmHeight;
223 if(reqsize.x <= size.x && reqsize.y <= size.y) {
224 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
228 /* If an image couldn't be selected, choose the smallest one */
229 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
234 /***********************************************************************
237 * Load image for part/state
239 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
240 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
242 int imagelayout = IL_HORIZONTAL;
246 WCHAR szPath[MAX_PATH];
247 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
249 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
250 return E_PROP_ID_UNSUPPORTED;
252 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
253 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
255 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
256 return HRESULT_FROM_WIN32(GetLastError());
259 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
260 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
262 imagenum = max (min (imagecount, iStateId), 1) - 1;
263 GetObjectW(*hBmp, sizeof(bmp), &bmp);
264 if(imagelayout == IL_VERTICAL) {
265 int height = bmp.bmHeight/imagecount;
267 bmpRect->right = bmp.bmWidth;
268 bmpRect->top = imagenum * height;
269 bmpRect->bottom = bmpRect->top + height;
272 int width = bmp.bmWidth/imagecount;
273 bmpRect->left = imagenum * width;
274 bmpRect->right = bmpRect->left + width;
276 bmpRect->bottom = bmp.bmHeight;
281 /***********************************************************************
284 * Pseudo TransparentBlt/StretchBlt
286 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
287 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
288 INT transparent, COLORREF transcolor)
290 static const BLENDFUNCTION blendFunc =
292 AC_SRC_OVER, /* BlendOp */
294 255, /* SourceConstantAlpha */
295 AC_SRC_ALPHA /* AlphaFormat */
297 if (transparent == ALPHABLEND_BINARY) {
298 /* Ensure we don't pass any negative values to TransparentBlt */
299 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
300 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
303 if ((transparent == ALPHABLEND_NONE) ||
304 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
305 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
308 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
309 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
315 /***********************************************************************
318 * Simplify sending same width/height for both source and dest
320 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
321 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
322 INT transparent, COLORREF transcolor)
324 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
325 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
326 transparent, transcolor);
329 /***********************************************************************
332 * Stretches or tiles, depending on sizingtype.
334 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
335 int nWidthDst, int nHeightDst,
336 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
337 int nWidthSrc, int nHeightSrc,
339 INT transparent, COLORREF transcolor)
341 if (sizingtype == ST_TILE)
346 /* Create a DC with a bitmap consisting of a tiling of the source
347 bitmap, with standard GDI functions. This is faster than an
348 iteration with UXTHEME_Blt(). */
349 hdcTemp = CreateCompatibleDC(hdcSrc);
354 int nWidthTemp, nHeightTemp;
355 int xOfs, xRemaining;
356 int yOfs, yRemaining;
359 /* Calculate temp dimensions of integer multiples of source dimensions */
360 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
361 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
362 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
363 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
365 /* Initial copy of bitmap */
366 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
368 /* Extend bitmap in the X direction. Growth of width is exponential */
370 xRemaining = nWidthTemp - nWidthSrc;
371 growSize = nWidthSrc;
372 while (xRemaining > 0)
374 growSize = min(growSize, xRemaining);
375 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
377 xRemaining -= growSize;
381 /* Extend bitmap in the Y direction. Growth of height is exponential */
383 yRemaining = nHeightTemp - nHeightSrc;
384 growSize = nHeightSrc;
385 while (yRemaining > 0)
387 growSize = min(growSize, yRemaining);
388 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
390 yRemaining -= growSize;
394 /* Use temporary hdc for source */
395 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
397 transparent, transcolor);
399 SelectObject(hdcTemp, bitmapOrig);
400 DeleteObject(bitmapTemp);
407 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
408 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
409 transparent, transcolor);
413 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
414 * depend on whether the image has full alpha or whether it is
415 * color-transparent or just opaque. */
416 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
417 BOOL hasImageAlpha, INT* transparent,
418 COLORREF* transparentcolor, BOOL glyph)
422 *transparent = ALPHABLEND_FULL;
423 *transparentcolor = RGB (255, 0, 255);
428 GetThemeBool(hTheme, iPartId, iStateId,
429 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
431 *transparent = ALPHABLEND_BINARY;
432 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
433 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
434 transparentcolor))) {
435 /* If image is transparent, but no color was specified, use magenta */
436 *transparentcolor = RGB(255, 0, 255);
440 *transparent = ALPHABLEND_NONE;
444 /***********************************************************************
445 * UXTHEME_DrawImageGlyph
447 * Draw an imagefile glyph
449 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
450 int iStateId, RECT *pRect,
451 const DTBGOPTS *pOptions)
454 HBITMAP bmpSrc = NULL;
456 HGDIOBJ oldSrc = NULL;
458 INT transparent = FALSE;
459 COLORREF transparentcolor;
460 int valign = VA_CENTER;
461 int halign = HA_CENTER;
467 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
468 &bmpSrc, &rcSrc, &hasAlpha);
469 if(FAILED(hr)) return hr;
470 hdcSrc = CreateCompatibleDC(hdc);
472 hr = HRESULT_FROM_WIN32(GetLastError());
475 oldSrc = SelectObject(hdcSrc, bmpSrc);
477 dstSize.x = pRect->right-pRect->left;
478 dstSize.y = pRect->bottom-pRect->top;
479 srcSize.x = rcSrc.right-rcSrc.left;
480 srcSize.y = rcSrc.bottom-rcSrc.top;
482 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
483 &transparentcolor, TRUE);
484 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
485 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
487 topleft.x = pRect->left;
488 topleft.y = pRect->top;
489 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
490 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
491 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
492 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
494 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
495 hdcSrc, rcSrc.left, rcSrc.top,
496 transparent, transparentcolor)) {
497 hr = HRESULT_FROM_WIN32(GetLastError());
500 SelectObject(hdcSrc, oldSrc);
505 /***********************************************************************
506 * UXTHEME_DrawImageGlyph
508 * Draw glyph on top of background, if appropriate
510 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
511 int iStateId, RECT *pRect,
512 const DTBGOPTS *pOptions)
514 int glyphtype = GT_NONE;
516 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
518 if(glyphtype == GT_IMAGEGLYPH) {
519 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
521 else if(glyphtype == GT_FONTGLYPH) {
522 /* I don't know what a font glyph is, I've never seen it used in any themes */
523 FIXME("Font glyph\n");
528 /***********************************************************************
529 * get_image_part_size
531 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
533 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
534 int iStateId, RECT *prc, THEMESIZE eSize,
542 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
543 &bmpSrc, &rcSrc, &hasAlpha);
544 if (FAILED(hr)) return hr;
554 int sizingtype = ST_STRETCH;
555 BOOL uniformsizing = FALSE;
557 CopyRect(&rcDst, prc);
559 dstSize.x = rcDst.right-rcDst.left;
560 dstSize.y = rcDst.bottom-rcDst.top;
561 srcSize.x = rcSrc.right-rcSrc.left;
562 srcSize.y = rcSrc.bottom-rcSrc.top;
564 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
566 /* Scale height and width equally */
567 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
569 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
570 rcDst.bottom = rcDst.top + dstSize.y;
574 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
575 rcDst.right = rcDst.left + dstSize.x;
579 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
580 if(sizingtype == ST_TRUESIZE) {
581 int truesizestretchmark = 100;
583 if(dstSize.x < 0 || dstSize.y < 0) {
584 BOOL mirrorimage = TRUE;
585 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
588 rcDst.left += dstSize.x;
589 rcDst.right += dstSize.x;
592 rcDst.top += dstSize.y;
593 rcDst.bottom += dstSize.y;
597 /* Whatever TrueSizeStretchMark does - it does not seem to
598 * be what's outlined below. It appears as if native
599 * uxtheme always stretches if dest is smaller than source
600 * (ie as if TrueSizeStretchMark==100 with the code below) */
602 /* Only stretch when target exceeds source by truesizestretchmark percent */
603 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
605 if(dstSize.x < 0 || dstSize.y < 0 ||
606 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
607 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
608 memcpy (psz, &dstSize, sizeof (SIZE));
611 memcpy (psz, &srcSize, sizeof (SIZE));
616 psz->x = abs(dstSize.x);
617 psz->y = abs(dstSize.y);
621 /* else fall through */
623 /* FIXME: couldn't figure how native uxtheme computes min size */
625 psz->x = rcSrc.right - rcSrc.left;
626 psz->y = rcSrc.bottom - rcSrc.top;
632 /***********************************************************************
633 * UXTHEME_DrawImageBackground
635 * Draw an imagefile background
637 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
638 int iStateId, RECT *pRect,
639 const DTBGOPTS *pOptions)
650 int sizingtype = ST_STRETCH;
652 COLORREF transparentcolor = 0;
655 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
656 &bmpSrc, &rcSrc, &hasAlpha);
657 if(FAILED(hr)) return hr;
658 hdcSrc = CreateCompatibleDC(hdc);
660 hr = HRESULT_FROM_WIN32(GetLastError());
663 oldSrc = SelectObject(hdcSrc, bmpSrc);
665 CopyRect(&rcDst, pRect);
667 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
668 &transparentcolor, FALSE);
670 dstSize.x = rcDst.right-rcDst.left;
671 dstSize.y = rcDst.bottom-rcDst.top;
672 srcSize.x = rcSrc.right-rcSrc.left;
673 srcSize.y = rcSrc.bottom-rcSrc.top;
675 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
676 if(sizingtype == ST_TRUESIZE) {
677 int valign = VA_CENTER, halign = HA_CENTER;
679 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
680 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
681 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
683 if (halign == HA_CENTER)
684 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
685 else if (halign == HA_RIGHT)
686 rcDst.left = rcDst.right - drawSize.x;
687 if (valign == VA_CENTER)
688 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
689 else if (valign == VA_BOTTOM)
690 rcDst.top = rcDst.bottom - drawSize.y;
691 rcDst.right = rcDst.left + drawSize.x;
692 rcDst.bottom = rcDst.top + drawSize.y;
693 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
694 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
695 transparent, transparentcolor))
696 hr = HRESULT_FROM_WIN32(GetLastError());
703 dstSize.x = abs(dstSize.x);
704 dstSize.y = abs(dstSize.y);
706 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
709 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
711 /* Upper left corner */
712 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
713 hdcSrc, rcSrc.left, rcSrc.top,
714 transparent, transparentcolor)) {
715 hr = HRESULT_FROM_WIN32(GetLastError());
718 /* Upper right corner */
719 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
720 sm.cxRightWidth, sm.cyTopHeight,
721 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
722 transparent, transparentcolor)) {
723 hr = HRESULT_FROM_WIN32(GetLastError());
726 /* Lower left corner */
727 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
728 sm.cxLeftWidth, sm.cyBottomHeight,
729 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
730 transparent, transparentcolor)) {
731 hr = HRESULT_FROM_WIN32(GetLastError());
734 /* Lower right corner */
735 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
736 sm.cxRightWidth, sm.cyBottomHeight,
737 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
738 transparent, transparentcolor)) {
739 hr = HRESULT_FROM_WIN32(GetLastError());
743 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
744 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
745 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
746 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
747 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
749 if(destCenterWidth > 0) {
751 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
752 destCenterWidth, sm.cyTopHeight,
753 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
754 srcCenterWidth, sm.cyTopHeight,
755 sizingtype, transparent, transparentcolor)) {
756 hr = HRESULT_FROM_WIN32(GetLastError());
760 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
761 destCenterWidth, sm.cyBottomHeight,
762 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
763 srcCenterWidth, sm.cyBottomHeight,
764 sizingtype, transparent, transparentcolor)) {
765 hr = HRESULT_FROM_WIN32(GetLastError());
769 if(destCenterHeight > 0) {
771 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
772 sm.cxLeftWidth, destCenterHeight,
773 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
774 sm.cxLeftWidth, srcCenterHeight,
776 transparent, transparentcolor)) {
777 hr = HRESULT_FROM_WIN32(GetLastError());
781 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
782 sm.cxRightWidth, destCenterHeight,
783 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
784 sm.cxRightWidth, srcCenterHeight,
785 sizingtype, transparent, transparentcolor)) {
786 hr = HRESULT_FROM_WIN32(GetLastError());
790 if(destCenterHeight > 0 && destCenterWidth > 0) {
791 BOOL borderonly = FALSE;
792 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
795 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
796 destCenterWidth, destCenterHeight,
797 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
798 srcCenterWidth, srcCenterHeight,
799 sizingtype, transparent, transparentcolor)) {
800 hr = HRESULT_FROM_WIN32(GetLastError());
808 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
810 SelectObject(hdcSrc, oldSrc);
812 CopyRect(pRect, &rcDst);
816 /***********************************************************************
817 * UXTHEME_DrawBorderRectangle
819 * Draw the bounding rectangle for a borderfill background
821 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
822 int iStateId, RECT *pRect,
823 const DTBGOPTS *pOptions)
828 COLORREF bordercolor = RGB(0,0,0);
831 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
834 ptCorners[0].x = pRect->left;
835 ptCorners[0].y = pRect->top;
836 ptCorners[1].x = pRect->right-1;
837 ptCorners[1].y = pRect->top;
838 ptCorners[2].x = pRect->right-1;
839 ptCorners[2].y = pRect->bottom-1;
840 ptCorners[3].x = pRect->left;
841 ptCorners[3].y = pRect->bottom-1;
842 ptCorners[4].x = pRect->left;
843 ptCorners[4].y = pRect->top;
845 InflateRect(pRect, -bordersize, -bordersize);
846 if(pOptions->dwFlags & DTBG_OMITBORDER)
848 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
849 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
851 return HRESULT_FROM_WIN32(GetLastError());
852 oldPen = SelectObject(hdc, hPen);
854 if(!Polyline(hdc, ptCorners, 5))
855 hr = HRESULT_FROM_WIN32(GetLastError());
857 SelectObject(hdc, oldPen);
863 /***********************************************************************
864 * UXTHEME_DrawBackgroundFill
866 * Fill a borderfill background rectangle
868 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
869 int iStateId, RECT *pRect,
870 const DTBGOPTS *pOptions)
873 int filltype = FT_SOLID;
875 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
877 if(pOptions->dwFlags & DTBG_OMITCONTENT)
880 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
882 if(filltype == FT_SOLID) {
884 COLORREF fillcolor = RGB(255,255,255);
886 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
887 hBrush = CreateSolidBrush(fillcolor);
888 if(!FillRect(hdc, pRect, hBrush))
889 hr = HRESULT_FROM_WIN32(GetLastError());
890 DeleteObject(hBrush);
892 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
893 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
894 the gradient ratios (no idea how those work)
895 Few themes use this, and the ones I've seen only use 2 colors with
896 a gradient ratio of 0 and 255 respectively
899 COLORREF gradient1 = RGB(0,0,0);
900 COLORREF gradient2 = RGB(255,255,255);
904 FIXME("Gradient implementation not complete\n");
906 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
907 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
909 vert[0].x = pRect->left;
910 vert[0].y = pRect->top;
911 vert[0].Red = GetRValue(gradient1) << 8;
912 vert[0].Green = GetGValue(gradient1) << 8;
913 vert[0].Blue = GetBValue(gradient1) << 8;
914 vert[0].Alpha = 0x0000;
916 vert[1].x = pRect->right;
917 vert[1].y = pRect->bottom;
918 vert[1].Red = GetRValue(gradient2) << 8;
919 vert[1].Green = GetGValue(gradient2) << 8;
920 vert[1].Blue = GetBValue(gradient2) << 8;
921 vert[1].Alpha = 0x0000;
924 gRect.LowerRight = 1;
925 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
927 else if(filltype == FT_RADIALGRADIENT) {
928 /* I've never seen this used in a theme */
929 FIXME("Radial gradient\n");
931 else if(filltype == FT_TILEIMAGE) {
932 /* I've never seen this used in a theme */
933 FIXME("Tile image\n");
938 /***********************************************************************
939 * UXTHEME_DrawBorderBackground
941 * Draw an imagefile background
943 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
944 int iStateId, const RECT *pRect,
945 const DTBGOPTS *pOptions)
950 CopyRect(&rt, pRect);
952 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
955 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
958 /***********************************************************************
959 * DrawThemeBackgroundEx (UXTHEME.@)
961 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
962 int iStateId, const RECT *pRect,
963 const DTBGOPTS *pOptions)
966 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
967 const DTBGOPTS *opts;
970 int bgtype = BT_BORDERFILL;
973 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
977 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
978 if (bgtype == BT_NONE) return S_OK;
980 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
982 if(!opts) opts = &defaultOpts;
984 if(opts->dwFlags & DTBG_CLIPRECT) {
985 clip = CreateRectRgn(0,0,1,1);
986 hasClip = GetClipRgn(hdc, clip);
988 TRACE("Failed to get original clipping region\n");
990 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
992 CopyRect(&rt, pRect);
994 if(bgtype == BT_IMAGEFILE)
995 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
996 else if(bgtype == BT_BORDERFILL)
997 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
999 FIXME("Unknown background type\n");
1000 /* This should never happen, and hence I don't know what to return */
1004 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1005 if(opts->dwFlags & DTBG_CLIPRECT) {
1007 SelectClipRgn(hdc, NULL);
1008 else if(hasClip == 1)
1009 SelectClipRgn(hdc, clip);
1016 * DrawThemeEdge() implementation
1018 * Since it basically is DrawEdge() with different colors, I copied its code
1019 * from user32's uitools.c.
1040 } EdgeColorMap[EDGE_NUMCOLORS] = {
1041 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1042 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1043 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1044 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1045 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1047 {-1, COLOR_WINDOWFRAME}
1050 static const signed char LTInnerNormal[] = {
1052 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1053 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1057 static const signed char LTOuterNormal[] = {
1058 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1059 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1060 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1061 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1064 static const signed char RBInnerNormal[] = {
1066 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1067 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1071 static const signed char RBOuterNormal[] = {
1072 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1073 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1074 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1075 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1078 static const signed char LTInnerSoft[] = {
1080 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1081 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1085 static const signed char LTOuterSoft[] = {
1086 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1087 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1088 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1089 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1092 #define RBInnerSoft RBInnerNormal /* These are the same */
1093 #define RBOuterSoft RBOuterNormal
1095 static const signed char LTRBOuterMono[] = {
1096 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1097 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1098 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1099 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1102 static const signed char LTRBInnerMono[] = {
1104 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1105 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1106 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1109 static const signed char LTRBOuterFlat[] = {
1110 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1111 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1112 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1113 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1116 static const signed char LTRBInnerFlat[] = {
1118 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1119 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1120 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1123 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1126 if ((EdgeColorMap[edgeType].themeProp == -1)
1127 || FAILED (GetThemeColor (theme, part, state,
1128 EdgeColorMap[edgeType].themeProp, &col)))
1129 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1133 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1135 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1138 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1140 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1143 /***********************************************************************
1146 * Same as DrawEdge invoked with BF_DIAGONAL
1148 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1149 const RECT* rc, UINT uType,
1150 UINT uFlags, LPRECT contentsRect)
1153 signed char InnerI, OuterI;
1154 HPEN InnerPen, OuterPen;
1159 int Width = rc->right - rc->left;
1160 int Height= rc->bottom - rc->top;
1161 int SmallDiam = Width > Height ? Height : Width;
1162 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1163 || (uType & BDR_OUTER) == BDR_OUTER)
1164 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1165 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1166 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1168 /* Init some vars */
1169 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1170 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1171 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1173 /* Determine the colors of the edges */
1174 if(uFlags & BF_MONO)
1176 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1177 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1179 else if(uFlags & BF_FLAT)
1181 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1182 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1184 else if(uFlags & BF_SOFT)
1186 if(uFlags & BF_BOTTOM)
1188 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1189 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1193 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1194 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1199 if(uFlags & BF_BOTTOM)
1201 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1202 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1206 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1207 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1211 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1212 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1214 MoveToEx(hdc, 0, 0, &SavePoint);
1216 /* Don't ask me why, but this is what is visible... */
1217 /* This must be possible to do much simpler, but I fail to */
1218 /* see the logic in the MS implementation (sigh...). */
1219 /* So, this might look a bit brute force here (and it is), but */
1220 /* it gets the job done;) */
1222 switch(uFlags & BF_RECT)
1228 /* Left bottom endpoint */
1230 spx = epx + SmallDiam;
1232 spy = epy - SmallDiam;
1236 case BF_BOTTOMRIGHT:
1237 /* Left top endpoint */
1239 spx = epx + SmallDiam;
1241 spy = epy + SmallDiam;
1247 case BF_RIGHT|BF_LEFT:
1248 case BF_RIGHT|BF_LEFT|BF_TOP:
1249 case BF_BOTTOM|BF_TOP:
1250 case BF_BOTTOM|BF_TOP|BF_LEFT:
1251 case BF_BOTTOMRIGHT|BF_LEFT:
1252 case BF_BOTTOMRIGHT|BF_TOP:
1254 /* Right top endpoint */
1256 epx = spx + SmallDiam;
1258 epy = spy - SmallDiam;
1262 MoveToEx(hdc, spx, spy, NULL);
1263 SelectObject(hdc, OuterPen);
1264 LineTo(hdc, epx, epy);
1266 SelectObject(hdc, InnerPen);
1268 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1270 case BF_DIAGONAL_ENDBOTTOMLEFT:
1271 case (BF_DIAGONAL|BF_BOTTOM):
1273 case (BF_DIAGONAL|BF_LEFT):
1274 MoveToEx(hdc, spx-1, spy, NULL);
1275 LineTo(hdc, epx, epy-1);
1276 Points[0].x = spx-add;
1278 Points[1].x = rc->left;
1279 Points[1].y = rc->top;
1280 Points[2].x = epx+1;
1281 Points[2].y = epy-1-add;
1282 Points[3] = Points[2];
1285 case BF_DIAGONAL_ENDBOTTOMRIGHT:
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->bottom-1;
1292 Points[2].x = epx+1;
1293 Points[2].y = epy+1+add;
1294 Points[3] = Points[2];
1297 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1298 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1299 case BF_DIAGONAL_ENDTOPRIGHT:
1300 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1301 MoveToEx(hdc, spx+1, spy, NULL);
1302 LineTo(hdc, epx, epy+1);
1303 Points[0].x = epx-1;
1304 Points[0].y = epy+1+add;
1305 Points[1].x = rc->right-1;
1306 Points[1].y = rc->top+add;
1307 Points[2].x = rc->right-1;
1308 Points[2].y = rc->bottom-1;
1309 Points[3].x = spx+add;
1313 case BF_DIAGONAL_ENDTOPLEFT:
1314 MoveToEx(hdc, spx, spy-1, NULL);
1315 LineTo(hdc, epx+1, epy);
1316 Points[0].x = epx+1+add;
1317 Points[0].y = epy+1;
1318 Points[1].x = rc->right-1;
1319 Points[1].y = rc->top;
1320 Points[2].x = rc->right-1;
1321 Points[2].y = rc->bottom-1-add;
1323 Points[3].y = spy-add;
1326 case (BF_DIAGONAL|BF_TOP):
1327 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1328 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1329 MoveToEx(hdc, spx+1, spy-1, NULL);
1330 LineTo(hdc, epx, epy);
1331 Points[0].x = epx-1;
1332 Points[0].y = epy+1;
1333 Points[1].x = rc->right-1;
1334 Points[1].y = rc->top;
1335 Points[2].x = rc->right-1;
1336 Points[2].y = rc->bottom-1-add;
1337 Points[3].x = spx+add;
1338 Points[3].y = spy-add;
1341 case (BF_DIAGONAL|BF_RIGHT):
1342 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1343 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1344 MoveToEx(hdc, spx, spy, NULL);
1345 LineTo(hdc, epx-1, epy+1);
1348 Points[1].x = rc->left;
1349 Points[1].y = rc->top+add;
1350 Points[2].x = epx-1-add;
1351 Points[2].y = epy+1+add;
1352 Points[3] = Points[2];
1356 /* Fill the interior if asked */
1357 if((uFlags & BF_MIDDLE) && retval)
1360 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1361 theme, part, state);
1363 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1364 theme, part, state);
1365 hbsave = (HBRUSH)SelectObject(hdc, hb);
1366 hpsave = (HPEN)SelectObject(hdc, hp);
1367 Polygon(hdc, Points, 4);
1368 SelectObject(hdc, hbsave);
1369 SelectObject(hdc, hpsave);
1374 /* Adjust rectangle if asked */
1375 if(uFlags & BF_ADJUST)
1377 *contentsRect = *rc;
1378 if(uFlags & BF_LEFT) contentsRect->left += add;
1379 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1380 if(uFlags & BF_TOP) contentsRect->top += add;
1381 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1385 SelectObject(hdc, SavePen);
1386 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1387 if(InnerI != -1) DeleteObject (InnerPen);
1388 if(OuterI != -1) DeleteObject (OuterPen);
1393 /***********************************************************************
1396 * Same as DrawEdge invoked without BF_DIAGONAL
1398 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1399 const RECT* rc, UINT uType,
1400 UINT uFlags, LPRECT contentsRect)
1402 signed char LTInnerI, LTOuterI;
1403 signed char RBInnerI, RBOuterI;
1404 HPEN LTInnerPen, LTOuterPen;
1405 HPEN RBInnerPen, RBOuterPen;
1406 RECT InnerRect = *rc;
1413 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1414 || (uType & BDR_OUTER) == BDR_OUTER)
1415 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1417 /* Init some vars */
1418 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1419 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1421 /* Determine the colors of the edges */
1422 if(uFlags & BF_MONO)
1424 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1425 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1427 else if(uFlags & BF_FLAT)
1429 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1430 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1432 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1434 else if(uFlags & BF_SOFT)
1436 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1437 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1438 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1439 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1443 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1444 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1445 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1446 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1449 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1450 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1451 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1452 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1454 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1455 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1456 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1457 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1459 MoveToEx(hdc, 0, 0, &SavePoint);
1461 /* Draw the outer edge */
1462 SelectObject(hdc, LTOuterPen);
1465 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1466 LineTo(hdc, InnerRect.right, InnerRect.top);
1468 if(uFlags & BF_LEFT)
1470 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1471 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1473 SelectObject(hdc, RBOuterPen);
1474 if(uFlags & BF_BOTTOM)
1476 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1477 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1479 if(uFlags & BF_RIGHT)
1481 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1482 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1485 /* Draw the inner edge */
1486 SelectObject(hdc, LTInnerPen);
1489 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1490 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1492 if(uFlags & BF_LEFT)
1494 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1495 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1497 SelectObject(hdc, RBInnerPen);
1498 if(uFlags & BF_BOTTOM)
1500 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1501 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1503 if(uFlags & BF_RIGHT)
1505 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1506 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1509 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1511 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1512 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1514 if(uFlags & BF_LEFT) InnerRect.left += add;
1515 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1516 if(uFlags & BF_TOP) InnerRect.top += add;
1517 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1519 if((uFlags & BF_MIDDLE) && retval)
1521 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1522 theme, part, state);
1523 FillRect(hdc, &InnerRect, br);
1527 if(uFlags & BF_ADJUST)
1528 *contentsRect = InnerRect;
1532 SelectObject(hdc, SavePen);
1533 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1534 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1535 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1536 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1537 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1542 /***********************************************************************
1543 * DrawThemeEdge (UXTHEME.@)
1545 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1546 * difference is that it does not rely on the system colors alone, but
1547 * also allows color specification in the theme.
1549 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1550 int iStateId, const RECT *pDestRect, UINT uEdge,
1551 UINT uFlags, RECT *pContentRect)
1553 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1557 if(uFlags & BF_DIAGONAL)
1558 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1559 uEdge, uFlags, pContentRect);
1561 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1562 uEdge, uFlags, pContentRect);
1566 /***********************************************************************
1567 * DrawThemeIcon (UXTHEME.@)
1569 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1570 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1572 FIXME("%d %d: stub\n", iPartId, iStateId);
1575 return ERROR_CALL_NOT_IMPLEMENTED;
1578 /***********************************************************************
1579 * DrawThemeText (UXTHEME.@)
1581 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1582 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1583 DWORD dwTextFlags2, const RECT *pRect)
1587 HGDIOBJ oldFont = NULL;
1590 COLORREF oldTextColor;
1594 TRACE("%d %d: stub\n", iPartId, iStateId);
1598 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1600 hFont = CreateFontIndirectW(&logfont);
1602 TRACE("Failed to create font\n");
1604 CopyRect(&rt, pRect);
1606 oldFont = SelectObject(hdc, hFont);
1608 if(dwTextFlags2 & DTT_GRAYED)
1609 textColor = GetSysColor(COLOR_GRAYTEXT);
1611 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1612 textColor = GetTextColor(hdc);
1614 oldTextColor = SetTextColor(hdc, textColor);
1615 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1616 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1617 SetBkMode(hdc, oldBkMode);
1618 SetTextColor(hdc, oldTextColor);
1621 SelectObject(hdc, oldFont);
1622 DeleteObject(hFont);
1627 /***********************************************************************
1628 * GetThemeBackgroundContentRect (UXTHEME.@)
1630 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1632 const RECT *pBoundingRect,
1638 TRACE("(%d,%d)\n", iPartId, iStateId);
1642 /* try content margins property... */
1643 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1645 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1646 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1647 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1648 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1650 /* otherwise, try to determine content rect from the background type and props */
1651 int bgtype = BT_BORDERFILL;
1652 *pContentRect = *pBoundingRect;
1654 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1655 if(bgtype == BT_BORDERFILL) {
1658 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1659 InflateRect(pContentRect, -bordersize, -bordersize);
1660 } else if ((bgtype == BT_IMAGEFILE)
1661 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1662 TMT_SIZINGMARGINS, NULL, &margin)))) {
1663 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1664 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1665 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1666 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1668 /* If nothing was found, leave unchanged */
1671 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1676 /***********************************************************************
1677 * GetThemeBackgroundExtent (UXTHEME.@)
1679 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1680 int iStateId, const RECT *pContentRect,
1686 TRACE("(%d,%d)\n", iPartId, iStateId);
1690 /* try content margins property... */
1691 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1693 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1694 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1695 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1696 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1698 /* otherwise, try to determine content rect from the background type and props */
1699 int bgtype = BT_BORDERFILL;
1700 *pExtentRect = *pContentRect;
1702 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1703 if(bgtype == BT_BORDERFILL) {
1706 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1707 InflateRect(pExtentRect, bordersize, bordersize);
1708 } else if ((bgtype == BT_IMAGEFILE)
1709 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1710 TMT_SIZINGMARGINS, NULL, &margin)))) {
1711 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1712 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1713 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1714 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1716 /* If nothing was found, leave unchanged */
1719 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1724 /***********************************************************************
1725 * GetThemeBackgroundRegion (UXTHEME.@)
1727 * Calculate the background region, taking into consideration transparent areas
1728 * of the background image.
1730 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1731 int iStateId, const RECT *pRect,
1735 int bgtype = BT_BORDERFILL;
1737 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1740 if(!pRect || !pRegion)
1743 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1744 if(bgtype == BT_IMAGEFILE) {
1745 FIXME("Images not handled yet\n");
1746 hr = ERROR_CALL_NOT_IMPLEMENTED;
1748 else if(bgtype == BT_BORDERFILL) {
1749 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1751 hr = HRESULT_FROM_WIN32(GetLastError());
1754 FIXME("Unknown background type\n");
1755 /* This should never happen, and hence I don't know what to return */
1761 /* compute part size for "borderfill" backgrounds */
1762 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1763 int iStateId, THEMESIZE eSize, POINT* psz)
1768 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1771 psz->x = psz->y = 2*bordersize;
1772 if (eSize != TS_MIN)
1781 /***********************************************************************
1782 * GetThemePartSize (UXTHEME.@)
1784 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1785 int iStateId, RECT *prc, THEMESIZE eSize,
1788 int bgtype = BT_BORDERFILL;
1790 POINT size = {1, 1};
1795 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1796 if (bgtype == BT_NONE)
1798 else if(bgtype == BT_IMAGEFILE)
1799 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1800 else if(bgtype == BT_BORDERFILL)
1801 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1803 FIXME("Unknown background type\n");
1804 /* This should never happen, and hence I don't know what to return */
1813 /***********************************************************************
1814 * GetThemeTextExtent (UXTHEME.@)
1816 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1817 int iStateId, LPCWSTR pszText, int iCharCount,
1818 DWORD dwTextFlags, const RECT *pBoundingRect,
1823 HGDIOBJ oldFont = NULL;
1825 RECT rt = {0,0,0xFFFF,0xFFFF};
1827 TRACE("%d %d: stub\n", iPartId, iStateId);
1832 CopyRect(&rt, pBoundingRect);
1834 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1836 hFont = CreateFontIndirectW(&logfont);
1838 TRACE("Failed to create font\n");
1841 oldFont = SelectObject(hdc, hFont);
1843 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1844 CopyRect(pExtentRect, &rt);
1847 SelectObject(hdc, oldFont);
1848 DeleteObject(hFont);
1853 /***********************************************************************
1854 * GetThemeTextMetrics (UXTHEME.@)
1856 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1857 int iStateId, TEXTMETRICW *ptm)
1861 HGDIOBJ oldFont = NULL;
1864 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1868 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1870 hFont = CreateFontIndirectW(&logfont);
1872 TRACE("Failed to create font\n");
1875 oldFont = SelectObject(hdc, hFont);
1877 if(!GetTextMetricsW(hdc, ptm))
1878 hr = HRESULT_FROM_WIN32(GetLastError());
1881 SelectObject(hdc, oldFont);
1882 DeleteObject(hFont);
1887 /***********************************************************************
1888 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1890 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1893 int bgtype = BT_BORDERFILL;
1894 RECT rect = {0, 0, 0, 0};
1899 COLORREF transparentcolor;
1901 TRACE("(%d,%d)\n", iPartId, iStateId);
1906 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1908 if (bgtype != BT_IMAGEFILE) return FALSE;
1910 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1911 &bmpSrc, &rcSrc, &hasAlpha)))
1914 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1915 &transparentcolor, FALSE);
1916 return (transparent != ALPHABLEND_NONE);