2 * Win32 5.1 Theme drawing
4 * Copyright (C) 2003 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "uxthemedll.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
41 /***********************************************************************
42 * Defines and global variables
45 extern ATOM atDialogThemeEnabled;
47 /***********************************************************************/
49 /***********************************************************************
50 * EnableThemeDialogTexture (UXTHEME.@)
52 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
54 static const WCHAR szTab[] = { 'T','a','b',0 };
57 TRACE("(%p,0x%08x\n", hwnd, dwFlags);
58 res = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled),
59 (HANDLE)(dwFlags|0x80000000));
60 /* 0x80000000 serves as a "flags set" flag */
62 return HRESULT_FROM_WIN32(GetLastError());
63 if (dwFlags & ETDT_USETABTEXTURE)
64 return SetWindowTheme (hwnd, NULL, szTab);
66 return SetWindowTheme (hwnd, NULL, NULL);
69 /***********************************************************************
70 * IsThemeDialogTextureEnabled (UXTHEME.@)
72 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd)
74 DWORD dwDialogTextureFlags;
75 TRACE("(%p)\n", hwnd);
77 dwDialogTextureFlags = (DWORD)GetPropW (hwnd,
78 (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled));
79 if (dwDialogTextureFlags == 0)
80 /* Means EnableThemeDialogTexture wasn't called for this dialog */
83 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE);
86 /***********************************************************************
87 * DrawThemeParentBackground (UXTHEME.@)
89 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
97 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc);
98 hParent = GetParent(hwnd);
103 MapWindowPoints(hwnd, NULL, (LPPOINT)&rt, 2);
105 clip = CreateRectRgn(0,0,1,1);
106 hasClip = GetClipRgn(hdc, clip);
108 TRACE("Failed to get original clipping region\n");
110 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
113 GetClientRect(hParent, &rt);
114 MapWindowPoints(hParent, NULL, (LPPOINT)&rt, 2);
117 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org);
119 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0);
120 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT);
122 SetViewportOrgEx(hdc, org.x, org.y, NULL);
125 SelectClipRgn(hdc, NULL);
126 else if(hasClip == 1)
127 SelectClipRgn(hdc, clip);
134 /***********************************************************************
135 * DrawThemeBackground (UXTHEME.@)
137 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
138 int iStateId, const RECT *pRect,
139 const RECT *pClipRect)
142 opts.dwSize = sizeof(DTBGOPTS);
145 opts.dwFlags |= DTBG_CLIPRECT;
146 CopyRect(&opts.rcClip, pClipRect);
148 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts);
151 /***********************************************************************
152 * UXTHEME_SelectImage
154 * Select the image to use
156 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph)
159 int imageselecttype = IST_NONE;
163 image = TMT_GLYPHIMAGEFILE;
165 image = TMT_IMAGEFILE;
167 if((tp=MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, image)))
169 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype);
171 if(imageselecttype == IST_DPI) {
173 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX);
174 for(i=4; i>=0; i--) {
176 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) {
177 if(reqdpi != 0 && screendpi >= reqdpi) {
178 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1);
179 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
183 /* If an image couldn't be selected, choose the first one */
184 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
186 else if(imageselecttype == IST_SIZE) {
187 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top};
189 for(i=4; i>=0; i--) {
190 PTHEME_PROPERTY fileProp =
191 MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1);
192 if (!fileProp) continue;
193 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) {
194 /* fall back to size of Nth image */
195 WCHAR szPath[MAX_PATH];
196 int imagelayout = IL_HORIZONTAL;
202 lstrcpynW(szPath, fileProp->lpValue,
203 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
204 hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, &hasAlpha);
207 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
208 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
210 GetObjectW(hBmp, sizeof(bmp), &bmp);
211 if(imagelayout == IL_VERTICAL) {
212 reqsize.x = bmp.bmWidth;
213 reqsize.y = bmp.bmHeight/imagecount;
216 reqsize.x = bmp.bmWidth/imagecount;
217 reqsize.y = bmp.bmHeight;
220 if(reqsize.x <= size.x && reqsize.y <= size.y) {
221 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1);
225 /* If an image couldn't be selected, choose the smallest one */
226 return MSSTYLES_FindProperty(hTheme, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1);
231 /***********************************************************************
234 * Load image for part/state
236 static HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph,
237 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha)
239 int imagelayout = IL_HORIZONTAL;
243 WCHAR szPath[MAX_PATH];
244 PTHEME_PROPERTY tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph);
246 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId);
247 return E_PROP_ID_UNSUPPORTED;
249 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0])));
250 *hBmp = MSSTYLES_LoadBitmap(hTheme, szPath, hasImageAlpha);
252 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath));
253 return HRESULT_FROM_WIN32(GetLastError());
256 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout);
257 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount);
259 imagenum = max (min (imagecount, iStateId), 1) - 1;
260 GetObjectW(*hBmp, sizeof(bmp), &bmp);
261 if(imagelayout == IL_VERTICAL) {
262 int height = bmp.bmHeight/imagecount;
264 bmpRect->right = bmp.bmWidth;
265 bmpRect->top = imagenum * height;
266 bmpRect->bottom = bmpRect->top + height;
269 int width = bmp.bmWidth/imagecount;
270 bmpRect->left = imagenum * width;
271 bmpRect->right = bmpRect->left + width;
273 bmpRect->bottom = bmp.bmHeight;
278 /***********************************************************************
281 * Pseudo TransparentBlt/StretchBlt
283 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
284 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
285 INT transparent, COLORREF transcolor)
287 static const BLENDFUNCTION blendFunc =
289 AC_SRC_OVER, /* BlendOp */
291 255, /* SourceConstantAlpha */
292 AC_SRC_ALPHA /* AlphaFormat */
294 if (transparent == ALPHABLEND_BINARY) {
295 /* Ensure we don't pass any negative values to TransparentBlt */
296 return TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
297 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
300 if ((transparent == ALPHABLEND_NONE) ||
301 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
302 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
305 return StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
306 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
312 /***********************************************************************
315 * Simplify sending same width/height for both source and dest
317 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
318 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
319 INT transparent, COLORREF transcolor)
321 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
322 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
323 transparent, transcolor);
326 /***********************************************************************
329 * Stretches or tiles, depending on sizingtype.
331 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
332 int nWidthDst, int nHeightDst,
333 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
334 int nWidthSrc, int nHeightSrc,
336 INT transparent, COLORREF transcolor)
338 if (sizingtype == ST_TILE)
343 if (!nWidthSrc || !nHeightSrc) return TRUE;
345 /* For destination width/height less than or equal to source
346 width/height, do not bother with memory bitmap optimization */
347 if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
349 int bltWidth = min (nWidthDst, nWidthSrc);
350 int bltHeight = min (nHeightDst, nHeightSrc);
352 return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
353 hdcSrc, nXOriginSrc, nYOriginSrc,
354 transparent, transcolor);
357 /* Create a DC with a bitmap consisting of a tiling of the source
358 bitmap, with standard GDI functions. This is faster than an
359 iteration with UXTHEME_Blt(). */
360 hdcTemp = CreateCompatibleDC(hdcSrc);
365 int nWidthTemp, nHeightTemp;
366 int xOfs, xRemaining;
367 int yOfs, yRemaining;
370 /* Calculate temp dimensions of integer multiples of source dimensions */
371 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
372 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
373 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
374 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
376 /* Initial copy of bitmap */
377 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
379 /* Extend bitmap in the X direction. Growth of width is exponential */
381 xRemaining = nWidthTemp - nWidthSrc;
382 growSize = nWidthSrc;
383 while (xRemaining > 0)
385 growSize = min(growSize, xRemaining);
386 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
388 xRemaining -= growSize;
392 /* Extend bitmap in the Y direction. Growth of height is exponential */
394 yRemaining = nHeightTemp - nHeightSrc;
395 growSize = nHeightSrc;
396 while (yRemaining > 0)
398 growSize = min(growSize, yRemaining);
399 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
401 yRemaining -= growSize;
405 /* Use temporary hdc for source */
406 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
408 transparent, transcolor);
410 SelectObject(hdcTemp, bitmapOrig);
411 DeleteObject(bitmapTemp);
418 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
419 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
420 transparent, transcolor);
424 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
425 * depend on whether the image has full alpha or whether it is
426 * color-transparent or just opaque. */
427 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
428 BOOL hasImageAlpha, INT* transparent,
429 COLORREF* transparentcolor, BOOL glyph)
433 *transparent = ALPHABLEND_FULL;
434 *transparentcolor = RGB (255, 0, 255);
439 GetThemeBool(hTheme, iPartId, iStateId,
440 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
442 *transparent = ALPHABLEND_BINARY;
443 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
444 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
445 transparentcolor))) {
446 /* If image is transparent, but no color was specified, use magenta */
447 *transparentcolor = RGB(255, 0, 255);
451 *transparent = ALPHABLEND_NONE;
455 /***********************************************************************
456 * UXTHEME_DrawImageGlyph
458 * Draw an imagefile glyph
460 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
461 int iStateId, RECT *pRect,
462 const DTBGOPTS *pOptions)
465 HBITMAP bmpSrc = NULL;
467 HGDIOBJ oldSrc = NULL;
469 INT transparent = FALSE;
470 COLORREF transparentcolor;
471 int valign = VA_CENTER;
472 int halign = HA_CENTER;
478 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
479 &bmpSrc, &rcSrc, &hasAlpha);
480 if(FAILED(hr)) return hr;
481 hdcSrc = CreateCompatibleDC(hdc);
483 hr = HRESULT_FROM_WIN32(GetLastError());
486 oldSrc = SelectObject(hdcSrc, bmpSrc);
488 dstSize.x = pRect->right-pRect->left;
489 dstSize.y = pRect->bottom-pRect->top;
490 srcSize.x = rcSrc.right-rcSrc.left;
491 srcSize.y = rcSrc.bottom-rcSrc.top;
493 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
494 &transparentcolor, TRUE);
495 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
496 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
498 topleft.x = pRect->left;
499 topleft.y = pRect->top;
500 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
501 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
502 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
503 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
505 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
506 hdcSrc, rcSrc.left, rcSrc.top,
507 transparent, transparentcolor)) {
508 hr = HRESULT_FROM_WIN32(GetLastError());
511 SelectObject(hdcSrc, oldSrc);
516 /***********************************************************************
517 * UXTHEME_DrawImageGlyph
519 * Draw glyph on top of background, if appropriate
521 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
522 int iStateId, RECT *pRect,
523 const DTBGOPTS *pOptions)
525 int glyphtype = GT_NONE;
527 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
529 if(glyphtype == GT_IMAGEGLYPH) {
530 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
532 else if(glyphtype == GT_FONTGLYPH) {
533 /* I don't know what a font glyph is, I've never seen it used in any themes */
534 FIXME("Font glyph\n");
539 /***********************************************************************
540 * get_image_part_size
542 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
544 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
545 int iStateId, RECT *prc, THEMESIZE eSize,
553 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
554 &bmpSrc, &rcSrc, &hasAlpha);
555 if (FAILED(hr)) return hr;
565 int sizingtype = ST_STRETCH;
566 BOOL uniformsizing = FALSE;
568 CopyRect(&rcDst, prc);
570 dstSize.x = rcDst.right-rcDst.left;
571 dstSize.y = rcDst.bottom-rcDst.top;
572 srcSize.x = rcSrc.right-rcSrc.left;
573 srcSize.y = rcSrc.bottom-rcSrc.top;
575 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
577 /* Scale height and width equally */
578 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
580 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
581 rcDst.bottom = rcDst.top + dstSize.y;
585 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
586 rcDst.right = rcDst.left + dstSize.x;
590 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
591 if(sizingtype == ST_TRUESIZE) {
592 int truesizestretchmark = 100;
594 if(dstSize.x < 0 || dstSize.y < 0) {
595 BOOL mirrorimage = TRUE;
596 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
599 rcDst.left += dstSize.x;
600 rcDst.right += dstSize.x;
603 rcDst.top += dstSize.y;
604 rcDst.bottom += dstSize.y;
608 /* Whatever TrueSizeStretchMark does - it does not seem to
609 * be what's outlined below. It appears as if native
610 * uxtheme always stretches if dest is smaller than source
611 * (ie as if TrueSizeStretchMark==100 with the code below) */
613 /* Only stretch when target exceeds source by truesizestretchmark percent */
614 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
616 if(dstSize.x < 0 || dstSize.y < 0 ||
617 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
618 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
619 memcpy (psz, &dstSize, sizeof (SIZE));
622 memcpy (psz, &srcSize, sizeof (SIZE));
627 psz->x = abs(dstSize.x);
628 psz->y = abs(dstSize.y);
632 /* else fall through */
634 /* FIXME: couldn't figure how native uxtheme computes min size */
636 psz->x = rcSrc.right - rcSrc.left;
637 psz->y = rcSrc.bottom - rcSrc.top;
643 /***********************************************************************
644 * UXTHEME_DrawImageBackground
646 * Draw an imagefile background
648 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
649 int iStateId, RECT *pRect,
650 const DTBGOPTS *pOptions)
661 int sizingtype = ST_STRETCH;
663 COLORREF transparentcolor = 0;
666 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
667 &bmpSrc, &rcSrc, &hasAlpha);
668 if(FAILED(hr)) return hr;
669 hdcSrc = CreateCompatibleDC(hdc);
671 hr = HRESULT_FROM_WIN32(GetLastError());
674 oldSrc = SelectObject(hdcSrc, bmpSrc);
676 CopyRect(&rcDst, pRect);
678 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
679 &transparentcolor, FALSE);
681 dstSize.x = rcDst.right-rcDst.left;
682 dstSize.y = rcDst.bottom-rcDst.top;
683 srcSize.x = rcSrc.right-rcSrc.left;
684 srcSize.y = rcSrc.bottom-rcSrc.top;
686 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
687 if(sizingtype == ST_TRUESIZE) {
688 int valign = VA_CENTER, halign = HA_CENTER;
690 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
691 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
692 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
694 if (halign == HA_CENTER)
695 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
696 else if (halign == HA_RIGHT)
697 rcDst.left = rcDst.right - drawSize.x;
698 if (valign == VA_CENTER)
699 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
700 else if (valign == VA_BOTTOM)
701 rcDst.top = rcDst.bottom - drawSize.y;
702 rcDst.right = rcDst.left + drawSize.x;
703 rcDst.bottom = rcDst.top + drawSize.y;
704 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
705 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
706 transparent, transparentcolor))
707 hr = HRESULT_FROM_WIN32(GetLastError());
714 dstSize.x = abs(dstSize.x);
715 dstSize.y = abs(dstSize.y);
717 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
720 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
722 /* Upper left corner */
723 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
724 hdcSrc, rcSrc.left, rcSrc.top,
725 transparent, transparentcolor)) {
726 hr = HRESULT_FROM_WIN32(GetLastError());
729 /* Upper right corner */
730 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
731 sm.cxRightWidth, sm.cyTopHeight,
732 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
733 transparent, transparentcolor)) {
734 hr = HRESULT_FROM_WIN32(GetLastError());
737 /* Lower left corner */
738 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
739 sm.cxLeftWidth, sm.cyBottomHeight,
740 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
741 transparent, transparentcolor)) {
742 hr = HRESULT_FROM_WIN32(GetLastError());
745 /* Lower right corner */
746 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
747 sm.cxRightWidth, sm.cyBottomHeight,
748 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
749 transparent, transparentcolor)) {
750 hr = HRESULT_FROM_WIN32(GetLastError());
754 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
755 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
756 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
757 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
758 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
760 if(destCenterWidth > 0) {
762 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
763 destCenterWidth, sm.cyTopHeight,
764 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
765 srcCenterWidth, sm.cyTopHeight,
766 sizingtype, transparent, transparentcolor)) {
767 hr = HRESULT_FROM_WIN32(GetLastError());
771 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
772 destCenterWidth, sm.cyBottomHeight,
773 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
774 srcCenterWidth, sm.cyBottomHeight,
775 sizingtype, transparent, transparentcolor)) {
776 hr = HRESULT_FROM_WIN32(GetLastError());
780 if(destCenterHeight > 0) {
782 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
783 sm.cxLeftWidth, destCenterHeight,
784 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
785 sm.cxLeftWidth, srcCenterHeight,
787 transparent, transparentcolor)) {
788 hr = HRESULT_FROM_WIN32(GetLastError());
792 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
793 sm.cxRightWidth, destCenterHeight,
794 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
795 sm.cxRightWidth, srcCenterHeight,
796 sizingtype, transparent, transparentcolor)) {
797 hr = HRESULT_FROM_WIN32(GetLastError());
801 if(destCenterHeight > 0 && destCenterWidth > 0) {
802 BOOL borderonly = FALSE;
803 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
806 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
807 destCenterWidth, destCenterHeight,
808 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
809 srcCenterWidth, srcCenterHeight,
810 sizingtype, transparent, transparentcolor)) {
811 hr = HRESULT_FROM_WIN32(GetLastError());
819 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
821 SelectObject(hdcSrc, oldSrc);
823 CopyRect(pRect, &rcDst);
827 /***********************************************************************
828 * UXTHEME_DrawBorderRectangle
830 * Draw the bounding rectangle for a borderfill background
832 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
833 int iStateId, RECT *pRect,
834 const DTBGOPTS *pOptions)
839 COLORREF bordercolor = RGB(0,0,0);
842 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
845 ptCorners[0].x = pRect->left;
846 ptCorners[0].y = pRect->top;
847 ptCorners[1].x = pRect->right-1;
848 ptCorners[1].y = pRect->top;
849 ptCorners[2].x = pRect->right-1;
850 ptCorners[2].y = pRect->bottom-1;
851 ptCorners[3].x = pRect->left;
852 ptCorners[3].y = pRect->bottom-1;
853 ptCorners[4].x = pRect->left;
854 ptCorners[4].y = pRect->top;
856 InflateRect(pRect, -bordersize, -bordersize);
857 if(pOptions->dwFlags & DTBG_OMITBORDER)
859 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
860 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
862 return HRESULT_FROM_WIN32(GetLastError());
863 oldPen = SelectObject(hdc, hPen);
865 if(!Polyline(hdc, ptCorners, 5))
866 hr = HRESULT_FROM_WIN32(GetLastError());
868 SelectObject(hdc, oldPen);
874 /***********************************************************************
875 * UXTHEME_DrawBackgroundFill
877 * Fill a borderfill background rectangle
879 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
880 int iStateId, RECT *pRect,
881 const DTBGOPTS *pOptions)
884 int filltype = FT_SOLID;
886 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
888 if(pOptions->dwFlags & DTBG_OMITCONTENT)
891 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
893 if(filltype == FT_SOLID) {
895 COLORREF fillcolor = RGB(255,255,255);
897 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
898 hBrush = CreateSolidBrush(fillcolor);
899 if(!FillRect(hdc, pRect, hBrush))
900 hr = HRESULT_FROM_WIN32(GetLastError());
901 DeleteObject(hBrush);
903 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
904 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
905 the gradient ratios (no idea how those work)
906 Few themes use this, and the ones I've seen only use 2 colors with
907 a gradient ratio of 0 and 255 respectively
910 COLORREF gradient1 = RGB(0,0,0);
911 COLORREF gradient2 = RGB(255,255,255);
915 FIXME("Gradient implementation not complete\n");
917 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
918 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
920 vert[0].x = pRect->left;
921 vert[0].y = pRect->top;
922 vert[0].Red = GetRValue(gradient1) << 8;
923 vert[0].Green = GetGValue(gradient1) << 8;
924 vert[0].Blue = GetBValue(gradient1) << 8;
925 vert[0].Alpha = 0x0000;
927 vert[1].x = pRect->right;
928 vert[1].y = pRect->bottom;
929 vert[1].Red = GetRValue(gradient2) << 8;
930 vert[1].Green = GetGValue(gradient2) << 8;
931 vert[1].Blue = GetBValue(gradient2) << 8;
932 vert[1].Alpha = 0x0000;
935 gRect.LowerRight = 1;
936 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
938 else if(filltype == FT_RADIALGRADIENT) {
939 /* I've never seen this used in a theme */
940 FIXME("Radial gradient\n");
942 else if(filltype == FT_TILEIMAGE) {
943 /* I've never seen this used in a theme */
944 FIXME("Tile image\n");
949 /***********************************************************************
950 * UXTHEME_DrawBorderBackground
952 * Draw an imagefile background
954 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
955 int iStateId, const RECT *pRect,
956 const DTBGOPTS *pOptions)
961 CopyRect(&rt, pRect);
963 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
966 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
969 /***********************************************************************
970 * DrawThemeBackgroundEx (UXTHEME.@)
972 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
973 int iStateId, const RECT *pRect,
974 const DTBGOPTS *pOptions)
977 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
978 const DTBGOPTS *opts;
981 int bgtype = BT_BORDERFILL;
984 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
988 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
989 if (bgtype == BT_NONE) return S_OK;
991 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
993 if(!opts) opts = &defaultOpts;
995 if(opts->dwFlags & DTBG_CLIPRECT) {
996 clip = CreateRectRgn(0,0,1,1);
997 hasClip = GetClipRgn(hdc, clip);
999 TRACE("Failed to get original clipping region\n");
1001 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
1003 CopyRect(&rt, pRect);
1005 if(bgtype == BT_IMAGEFILE)
1006 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
1007 else if(bgtype == BT_BORDERFILL)
1008 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
1010 FIXME("Unknown background type\n");
1011 /* This should never happen, and hence I don't know what to return */
1015 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1016 if(opts->dwFlags & DTBG_CLIPRECT) {
1018 SelectClipRgn(hdc, NULL);
1019 else if(hasClip == 1)
1020 SelectClipRgn(hdc, clip);
1027 * DrawThemeEdge() implementation
1029 * Since it basically is DrawEdge() with different colors, I copied its code
1030 * from user32's uitools.c.
1051 } EdgeColorMap[EDGE_NUMCOLORS] = {
1052 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1053 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1054 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1055 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1056 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1058 {-1, COLOR_WINDOWFRAME}
1061 static const signed char LTInnerNormal[] = {
1063 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1064 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1068 static const signed char LTOuterNormal[] = {
1069 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1070 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1071 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1072 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1075 static const signed char RBInnerNormal[] = {
1077 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1078 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1082 static const signed char RBOuterNormal[] = {
1083 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1084 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1085 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1086 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1089 static const signed char LTInnerSoft[] = {
1091 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1092 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1096 static const signed char LTOuterSoft[] = {
1097 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1098 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1099 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1100 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1103 #define RBInnerSoft RBInnerNormal /* These are the same */
1104 #define RBOuterSoft RBOuterNormal
1106 static const signed char LTRBOuterMono[] = {
1107 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1108 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1109 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1110 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1113 static const signed char LTRBInnerMono[] = {
1115 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1116 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1117 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1120 static const signed char LTRBOuterFlat[] = {
1121 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1122 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1123 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1124 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1127 static const signed char LTRBInnerFlat[] = {
1129 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1130 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1131 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1134 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1137 if ((EdgeColorMap[edgeType].themeProp == -1)
1138 || FAILED (GetThemeColor (theme, part, state,
1139 EdgeColorMap[edgeType].themeProp, &col)))
1140 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1144 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1146 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1149 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1151 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1154 /***********************************************************************
1157 * Same as DrawEdge invoked with BF_DIAGONAL
1159 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1160 const RECT* rc, UINT uType,
1161 UINT uFlags, LPRECT contentsRect)
1164 signed char InnerI, OuterI;
1165 HPEN InnerPen, OuterPen;
1170 int Width = rc->right - rc->left;
1171 int Height= rc->bottom - rc->top;
1172 int SmallDiam = Width > Height ? Height : Width;
1173 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1174 || (uType & BDR_OUTER) == BDR_OUTER)
1175 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1176 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1177 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1179 /* Init some vars */
1180 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1181 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1182 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1184 /* Determine the colors of the edges */
1185 if(uFlags & BF_MONO)
1187 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1188 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1190 else if(uFlags & BF_FLAT)
1192 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1193 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1195 else if(uFlags & BF_SOFT)
1197 if(uFlags & BF_BOTTOM)
1199 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1200 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1204 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1205 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1210 if(uFlags & BF_BOTTOM)
1212 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1213 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1217 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1218 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1222 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1223 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1225 MoveToEx(hdc, 0, 0, &SavePoint);
1227 /* Don't ask me why, but this is what is visible... */
1228 /* This must be possible to do much simpler, but I fail to */
1229 /* see the logic in the MS implementation (sigh...). */
1230 /* So, this might look a bit brute force here (and it is), but */
1231 /* it gets the job done;) */
1233 switch(uFlags & BF_RECT)
1239 /* Left bottom endpoint */
1241 spx = epx + SmallDiam;
1243 spy = epy - SmallDiam;
1247 case BF_BOTTOMRIGHT:
1248 /* Left top endpoint */
1250 spx = epx + SmallDiam;
1252 spy = epy + SmallDiam;
1258 case BF_RIGHT|BF_LEFT:
1259 case BF_RIGHT|BF_LEFT|BF_TOP:
1260 case BF_BOTTOM|BF_TOP:
1261 case BF_BOTTOM|BF_TOP|BF_LEFT:
1262 case BF_BOTTOMRIGHT|BF_LEFT:
1263 case BF_BOTTOMRIGHT|BF_TOP:
1265 /* Right top endpoint */
1267 epx = spx + SmallDiam;
1269 epy = spy - SmallDiam;
1273 MoveToEx(hdc, spx, spy, NULL);
1274 SelectObject(hdc, OuterPen);
1275 LineTo(hdc, epx, epy);
1277 SelectObject(hdc, InnerPen);
1279 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1281 case BF_DIAGONAL_ENDBOTTOMLEFT:
1282 case (BF_DIAGONAL|BF_BOTTOM):
1284 case (BF_DIAGONAL|BF_LEFT):
1285 MoveToEx(hdc, spx-1, spy, NULL);
1286 LineTo(hdc, epx, epy-1);
1287 Points[0].x = spx-add;
1289 Points[1].x = rc->left;
1290 Points[1].y = rc->top;
1291 Points[2].x = epx+1;
1292 Points[2].y = epy-1-add;
1293 Points[3] = Points[2];
1296 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1297 MoveToEx(hdc, spx-1, spy, NULL);
1298 LineTo(hdc, epx, epy+1);
1299 Points[0].x = spx-add;
1301 Points[1].x = rc->left;
1302 Points[1].y = rc->bottom-1;
1303 Points[2].x = epx+1;
1304 Points[2].y = epy+1+add;
1305 Points[3] = Points[2];
1308 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1309 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1310 case BF_DIAGONAL_ENDTOPRIGHT:
1311 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1312 MoveToEx(hdc, spx+1, spy, NULL);
1313 LineTo(hdc, epx, epy+1);
1314 Points[0].x = epx-1;
1315 Points[0].y = epy+1+add;
1316 Points[1].x = rc->right-1;
1317 Points[1].y = rc->top+add;
1318 Points[2].x = rc->right-1;
1319 Points[2].y = rc->bottom-1;
1320 Points[3].x = spx+add;
1324 case BF_DIAGONAL_ENDTOPLEFT:
1325 MoveToEx(hdc, spx, spy-1, NULL);
1326 LineTo(hdc, epx+1, epy);
1327 Points[0].x = epx+1+add;
1328 Points[0].y = epy+1;
1329 Points[1].x = rc->right-1;
1330 Points[1].y = rc->top;
1331 Points[2].x = rc->right-1;
1332 Points[2].y = rc->bottom-1-add;
1334 Points[3].y = spy-add;
1337 case (BF_DIAGONAL|BF_TOP):
1338 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1339 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1340 MoveToEx(hdc, spx+1, spy-1, NULL);
1341 LineTo(hdc, epx, epy);
1342 Points[0].x = epx-1;
1343 Points[0].y = epy+1;
1344 Points[1].x = rc->right-1;
1345 Points[1].y = rc->top;
1346 Points[2].x = rc->right-1;
1347 Points[2].y = rc->bottom-1-add;
1348 Points[3].x = spx+add;
1349 Points[3].y = spy-add;
1352 case (BF_DIAGONAL|BF_RIGHT):
1353 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1354 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1355 MoveToEx(hdc, spx, spy, NULL);
1356 LineTo(hdc, epx-1, epy+1);
1359 Points[1].x = rc->left;
1360 Points[1].y = rc->top+add;
1361 Points[2].x = epx-1-add;
1362 Points[2].y = epy+1+add;
1363 Points[3] = Points[2];
1367 /* Fill the interior if asked */
1368 if((uFlags & BF_MIDDLE) && retval)
1371 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1372 theme, part, state);
1374 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1375 theme, part, state);
1376 hbsave = (HBRUSH)SelectObject(hdc, hb);
1377 hpsave = (HPEN)SelectObject(hdc, hp);
1378 Polygon(hdc, Points, 4);
1379 SelectObject(hdc, hbsave);
1380 SelectObject(hdc, hpsave);
1385 /* Adjust rectangle if asked */
1386 if(uFlags & BF_ADJUST)
1388 *contentsRect = *rc;
1389 if(uFlags & BF_LEFT) contentsRect->left += add;
1390 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1391 if(uFlags & BF_TOP) contentsRect->top += add;
1392 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1396 SelectObject(hdc, SavePen);
1397 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1398 if(InnerI != -1) DeleteObject (InnerPen);
1399 if(OuterI != -1) DeleteObject (OuterPen);
1404 /***********************************************************************
1407 * Same as DrawEdge invoked without BF_DIAGONAL
1409 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1410 const RECT* rc, UINT uType,
1411 UINT uFlags, LPRECT contentsRect)
1413 signed char LTInnerI, LTOuterI;
1414 signed char RBInnerI, RBOuterI;
1415 HPEN LTInnerPen, LTOuterPen;
1416 HPEN RBInnerPen, RBOuterPen;
1417 RECT InnerRect = *rc;
1424 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1425 || (uType & BDR_OUTER) == BDR_OUTER)
1426 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1428 /* Init some vars */
1429 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1430 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1432 /* Determine the colors of the edges */
1433 if(uFlags & BF_MONO)
1435 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1436 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1438 else if(uFlags & BF_FLAT)
1440 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1441 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1443 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1445 else if(uFlags & BF_SOFT)
1447 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1448 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1449 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1450 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1454 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1455 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1456 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1457 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1460 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1461 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1462 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1463 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1465 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1466 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1467 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1468 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1470 MoveToEx(hdc, 0, 0, &SavePoint);
1472 /* Draw the outer edge */
1473 SelectObject(hdc, LTOuterPen);
1476 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1477 LineTo(hdc, InnerRect.right, InnerRect.top);
1479 if(uFlags & BF_LEFT)
1481 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1482 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1484 SelectObject(hdc, RBOuterPen);
1485 if(uFlags & BF_BOTTOM)
1487 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1488 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1490 if(uFlags & BF_RIGHT)
1492 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1493 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1496 /* Draw the inner edge */
1497 SelectObject(hdc, LTInnerPen);
1500 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1501 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1503 if(uFlags & BF_LEFT)
1505 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1506 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1508 SelectObject(hdc, RBInnerPen);
1509 if(uFlags & BF_BOTTOM)
1511 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1512 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1514 if(uFlags & BF_RIGHT)
1516 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1517 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1520 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1522 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1523 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1525 if(uFlags & BF_LEFT) InnerRect.left += add;
1526 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1527 if(uFlags & BF_TOP) InnerRect.top += add;
1528 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1530 if((uFlags & BF_MIDDLE) && retval)
1532 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1533 theme, part, state);
1534 FillRect(hdc, &InnerRect, br);
1538 if(uFlags & BF_ADJUST)
1539 *contentsRect = InnerRect;
1543 SelectObject(hdc, SavePen);
1544 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1545 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1546 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1547 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1548 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1553 /***********************************************************************
1554 * DrawThemeEdge (UXTHEME.@)
1556 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1557 * difference is that it does not rely on the system colors alone, but
1558 * also allows color specification in the theme.
1560 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1561 int iStateId, const RECT *pDestRect, UINT uEdge,
1562 UINT uFlags, RECT *pContentRect)
1564 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1568 if(uFlags & BF_DIAGONAL)
1569 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1570 uEdge, uFlags, pContentRect);
1572 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1573 uEdge, uFlags, pContentRect);
1577 /***********************************************************************
1578 * DrawThemeIcon (UXTHEME.@)
1580 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1581 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1583 FIXME("%d %d: stub\n", iPartId, iStateId);
1586 return ERROR_CALL_NOT_IMPLEMENTED;
1589 /***********************************************************************
1590 * DrawThemeText (UXTHEME.@)
1592 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1593 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1594 DWORD dwTextFlags2, const RECT *pRect)
1598 HGDIOBJ oldFont = NULL;
1601 COLORREF oldTextColor;
1605 TRACE("%d %d: stub\n", iPartId, iStateId);
1609 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1611 hFont = CreateFontIndirectW(&logfont);
1613 TRACE("Failed to create font\n");
1615 CopyRect(&rt, pRect);
1617 oldFont = SelectObject(hdc, hFont);
1619 if(dwTextFlags2 & DTT_GRAYED)
1620 textColor = GetSysColor(COLOR_GRAYTEXT);
1622 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1623 textColor = GetTextColor(hdc);
1625 oldTextColor = SetTextColor(hdc, textColor);
1626 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1627 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1628 SetBkMode(hdc, oldBkMode);
1629 SetTextColor(hdc, oldTextColor);
1632 SelectObject(hdc, oldFont);
1633 DeleteObject(hFont);
1638 /***********************************************************************
1639 * GetThemeBackgroundContentRect (UXTHEME.@)
1641 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1643 const RECT *pBoundingRect,
1649 TRACE("(%d,%d)\n", iPartId, iStateId);
1653 /* try content margins property... */
1654 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1656 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1657 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1658 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1659 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1661 /* otherwise, try to determine content rect from the background type and props */
1662 int bgtype = BT_BORDERFILL;
1663 *pContentRect = *pBoundingRect;
1665 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1666 if(bgtype == BT_BORDERFILL) {
1669 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1670 InflateRect(pContentRect, -bordersize, -bordersize);
1671 } else if ((bgtype == BT_IMAGEFILE)
1672 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1673 TMT_SIZINGMARGINS, NULL, &margin)))) {
1674 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1675 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1676 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1677 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1679 /* If nothing was found, leave unchanged */
1682 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1687 /***********************************************************************
1688 * GetThemeBackgroundExtent (UXTHEME.@)
1690 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1691 int iStateId, const RECT *pContentRect,
1697 TRACE("(%d,%d)\n", iPartId, iStateId);
1701 /* try content margins property... */
1702 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1704 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1705 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1706 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1707 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1709 /* otherwise, try to determine content rect from the background type and props */
1710 int bgtype = BT_BORDERFILL;
1711 *pExtentRect = *pContentRect;
1713 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1714 if(bgtype == BT_BORDERFILL) {
1717 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1718 InflateRect(pExtentRect, bordersize, bordersize);
1719 } else if ((bgtype == BT_IMAGEFILE)
1720 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1721 TMT_SIZINGMARGINS, NULL, &margin)))) {
1722 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1723 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1724 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1725 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1727 /* If nothing was found, leave unchanged */
1730 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1735 /***********************************************************************
1736 * GetThemeBackgroundRegion (UXTHEME.@)
1738 * Calculate the background region, taking into consideration transparent areas
1739 * of the background image.
1741 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1742 int iStateId, const RECT *pRect,
1746 int bgtype = BT_BORDERFILL;
1748 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1751 if(!pRect || !pRegion)
1754 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1755 if(bgtype == BT_IMAGEFILE) {
1756 FIXME("Images not handled yet\n");
1757 hr = ERROR_CALL_NOT_IMPLEMENTED;
1759 else if(bgtype == BT_BORDERFILL) {
1760 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1762 hr = HRESULT_FROM_WIN32(GetLastError());
1765 FIXME("Unknown background type\n");
1766 /* This should never happen, and hence I don't know what to return */
1772 /* compute part size for "borderfill" backgrounds */
1773 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1774 int iStateId, THEMESIZE eSize, POINT* psz)
1779 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1782 psz->x = psz->y = 2*bordersize;
1783 if (eSize != TS_MIN)
1792 /***********************************************************************
1793 * GetThemePartSize (UXTHEME.@)
1795 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1796 int iStateId, RECT *prc, THEMESIZE eSize,
1799 int bgtype = BT_BORDERFILL;
1801 POINT size = {1, 1};
1806 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1807 if (bgtype == BT_NONE)
1809 else if(bgtype == BT_IMAGEFILE)
1810 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1811 else if(bgtype == BT_BORDERFILL)
1812 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1814 FIXME("Unknown background type\n");
1815 /* This should never happen, and hence I don't know what to return */
1824 /***********************************************************************
1825 * GetThemeTextExtent (UXTHEME.@)
1827 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1828 int iStateId, LPCWSTR pszText, int iCharCount,
1829 DWORD dwTextFlags, const RECT *pBoundingRect,
1834 HGDIOBJ oldFont = NULL;
1836 RECT rt = {0,0,0xFFFF,0xFFFF};
1838 TRACE("%d %d: stub\n", iPartId, iStateId);
1843 CopyRect(&rt, pBoundingRect);
1845 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1847 hFont = CreateFontIndirectW(&logfont);
1849 TRACE("Failed to create font\n");
1852 oldFont = SelectObject(hdc, hFont);
1854 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1855 CopyRect(pExtentRect, &rt);
1858 SelectObject(hdc, oldFont);
1859 DeleteObject(hFont);
1864 /***********************************************************************
1865 * GetThemeTextMetrics (UXTHEME.@)
1867 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1868 int iStateId, TEXTMETRICW *ptm)
1872 HGDIOBJ oldFont = NULL;
1875 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1879 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1881 hFont = CreateFontIndirectW(&logfont);
1883 TRACE("Failed to create font\n");
1886 oldFont = SelectObject(hdc, hFont);
1888 if(!GetTextMetricsW(hdc, ptm))
1889 hr = HRESULT_FROM_WIN32(GetLastError());
1892 SelectObject(hdc, oldFont);
1893 DeleteObject(hFont);
1898 /***********************************************************************
1899 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1901 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1904 int bgtype = BT_BORDERFILL;
1905 RECT rect = {0, 0, 0, 0};
1910 COLORREF transparentcolor;
1912 TRACE("(%d,%d)\n", iPartId, iStateId);
1917 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1919 if (bgtype != BT_IMAGEFILE) return FALSE;
1921 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1922 &bmpSrc, &rcSrc, &hasAlpha)))
1925 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1926 &transparentcolor, FALSE);
1927 return (transparent != ALPHABLEND_NONE);