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 if (!nWidthSrc || !nHeightSrc) return TRUE;
348 /* For destination width/height less than or equal to source
349 width/height, do not bother with memory bitmap optimization */
350 if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
352 int bltWidth = min (nWidthDst, nWidthSrc);
353 int bltHeight = min (nHeightDst, nHeightSrc);
355 return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
356 hdcSrc, nXOriginSrc, nYOriginSrc,
357 transparent, transcolor);
360 /* Create a DC with a bitmap consisting of a tiling of the source
361 bitmap, with standard GDI functions. This is faster than an
362 iteration with UXTHEME_Blt(). */
363 hdcTemp = CreateCompatibleDC(hdcSrc);
368 int nWidthTemp, nHeightTemp;
369 int xOfs, xRemaining;
370 int yOfs, yRemaining;
373 /* Calculate temp dimensions of integer multiples of source dimensions */
374 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
375 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
376 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
377 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
379 /* Initial copy of bitmap */
380 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
382 /* Extend bitmap in the X direction. Growth of width is exponential */
384 xRemaining = nWidthTemp - nWidthSrc;
385 growSize = nWidthSrc;
386 while (xRemaining > 0)
388 growSize = min(growSize, xRemaining);
389 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
391 xRemaining -= growSize;
395 /* Extend bitmap in the Y direction. Growth of height is exponential */
397 yRemaining = nHeightTemp - nHeightSrc;
398 growSize = nHeightSrc;
399 while (yRemaining > 0)
401 growSize = min(growSize, yRemaining);
402 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
404 yRemaining -= growSize;
408 /* Use temporary hdc for source */
409 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
411 transparent, transcolor);
413 SelectObject(hdcTemp, bitmapOrig);
414 DeleteObject(bitmapTemp);
421 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
422 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
423 transparent, transcolor);
427 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters
428 * depend on whether the image has full alpha or whether it is
429 * color-transparent or just opaque. */
430 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId,
431 BOOL hasImageAlpha, INT* transparent,
432 COLORREF* transparentcolor, BOOL glyph)
436 *transparent = ALPHABLEND_FULL;
437 *transparentcolor = RGB (255, 0, 255);
442 GetThemeBool(hTheme, iPartId, iStateId,
443 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans);
445 *transparent = ALPHABLEND_BINARY;
446 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId,
447 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR,
448 transparentcolor))) {
449 /* If image is transparent, but no color was specified, use magenta */
450 *transparentcolor = RGB(255, 0, 255);
454 *transparent = ALPHABLEND_NONE;
458 /***********************************************************************
459 * UXTHEME_DrawImageGlyph
461 * Draw an imagefile glyph
463 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId,
464 int iStateId, RECT *pRect,
465 const DTBGOPTS *pOptions)
468 HBITMAP bmpSrc = NULL;
470 HGDIOBJ oldSrc = NULL;
472 INT transparent = FALSE;
473 COLORREF transparentcolor;
474 int valign = VA_CENTER;
475 int halign = HA_CENTER;
481 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE,
482 &bmpSrc, &rcSrc, &hasAlpha);
483 if(FAILED(hr)) return hr;
484 hdcSrc = CreateCompatibleDC(hdc);
486 hr = HRESULT_FROM_WIN32(GetLastError());
489 oldSrc = SelectObject(hdcSrc, bmpSrc);
491 dstSize.x = pRect->right-pRect->left;
492 dstSize.y = pRect->bottom-pRect->top;
493 srcSize.x = rcSrc.right-rcSrc.left;
494 srcSize.y = rcSrc.bottom-rcSrc.top;
496 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
497 &transparentcolor, TRUE);
498 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
499 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
501 topleft.x = pRect->left;
502 topleft.y = pRect->top;
503 if(halign == HA_CENTER) topleft.x += (dstSize.x/2)-(srcSize.x/2);
504 else if(halign == HA_RIGHT) topleft.x += dstSize.x-srcSize.x;
505 if(valign == VA_CENTER) topleft.y += (dstSize.y/2)-(srcSize.y/2);
506 else if(valign == VA_BOTTOM) topleft.y += dstSize.y-srcSize.y;
508 if(!UXTHEME_Blt(hdc, topleft.x, topleft.y, srcSize.x, srcSize.y,
509 hdcSrc, rcSrc.left, rcSrc.top,
510 transparent, transparentcolor)) {
511 hr = HRESULT_FROM_WIN32(GetLastError());
514 SelectObject(hdcSrc, oldSrc);
519 /***********************************************************************
520 * UXTHEME_DrawImageGlyph
522 * Draw glyph on top of background, if appropriate
524 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId,
525 int iStateId, RECT *pRect,
526 const DTBGOPTS *pOptions)
528 int glyphtype = GT_NONE;
530 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype);
532 if(glyphtype == GT_IMAGEGLYPH) {
533 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions);
535 else if(glyphtype == GT_FONTGLYPH) {
536 /* I don't know what a font glyph is, I've never seen it used in any themes */
537 FIXME("Font glyph\n");
542 /***********************************************************************
543 * get_image_part_size
545 * Used by GetThemePartSize and UXTHEME_DrawImageBackground
547 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId,
548 int iStateId, RECT *prc, THEMESIZE eSize,
556 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE,
557 &bmpSrc, &rcSrc, &hasAlpha);
558 if (FAILED(hr)) return hr;
568 int sizingtype = ST_STRETCH;
569 BOOL uniformsizing = FALSE;
571 CopyRect(&rcDst, prc);
573 dstSize.x = rcDst.right-rcDst.left;
574 dstSize.y = rcDst.bottom-rcDst.top;
575 srcSize.x = rcSrc.right-rcSrc.left;
576 srcSize.y = rcSrc.bottom-rcSrc.top;
578 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing);
580 /* Scale height and width equally */
581 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x)
583 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x);
584 rcDst.bottom = rcDst.top + dstSize.y;
588 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y);
589 rcDst.right = rcDst.left + dstSize.x;
593 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
594 if(sizingtype == ST_TRUESIZE) {
595 int truesizestretchmark = 100;
597 if(dstSize.x < 0 || dstSize.y < 0) {
598 BOOL mirrorimage = TRUE;
599 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage);
602 rcDst.left += dstSize.x;
603 rcDst.right += dstSize.x;
606 rcDst.top += dstSize.y;
607 rcDst.bottom += dstSize.y;
611 /* Whatever TrueSizeStretchMark does - it does not seem to
612 * be what's outlined below. It appears as if native
613 * uxtheme always stretches if dest is smaller than source
614 * (ie as if TrueSizeStretchMark==100 with the code below) */
616 /* Only stretch when target exceeds source by truesizestretchmark percent */
617 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark);
619 if(dstSize.x < 0 || dstSize.y < 0 ||
620 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark &&
621 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) {
622 memcpy (psz, &dstSize, sizeof (SIZE));
625 memcpy (psz, &srcSize, sizeof (SIZE));
630 psz->x = abs(dstSize.x);
631 psz->y = abs(dstSize.y);
635 /* else fall through */
637 /* FIXME: couldn't figure how native uxtheme computes min size */
639 psz->x = rcSrc.right - rcSrc.left;
640 psz->y = rcSrc.bottom - rcSrc.top;
646 /***********************************************************************
647 * UXTHEME_DrawImageBackground
649 * Draw an imagefile background
651 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId,
652 int iStateId, RECT *pRect,
653 const DTBGOPTS *pOptions)
664 int sizingtype = ST_STRETCH;
666 COLORREF transparentcolor = 0;
669 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE,
670 &bmpSrc, &rcSrc, &hasAlpha);
671 if(FAILED(hr)) return hr;
672 hdcSrc = CreateCompatibleDC(hdc);
674 hr = HRESULT_FROM_WIN32(GetLastError());
677 oldSrc = SelectObject(hdcSrc, bmpSrc);
679 CopyRect(&rcDst, pRect);
681 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
682 &transparentcolor, FALSE);
684 dstSize.x = rcDst.right-rcDst.left;
685 dstSize.y = rcDst.bottom-rcDst.top;
686 srcSize.x = rcSrc.right-rcSrc.left;
687 srcSize.y = rcSrc.bottom-rcSrc.top;
689 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype);
690 if(sizingtype == ST_TRUESIZE) {
691 int valign = VA_CENTER, halign = HA_CENTER;
693 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize);
694 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign);
695 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign);
697 if (halign == HA_CENTER)
698 rcDst.left += (dstSize.x/2)-(drawSize.x/2);
699 else if (halign == HA_RIGHT)
700 rcDst.left = rcDst.right - drawSize.x;
701 if (valign == VA_CENTER)
702 rcDst.top += (dstSize.y/2)-(drawSize.y/2);
703 else if (valign == VA_BOTTOM)
704 rcDst.top = rcDst.bottom - drawSize.y;
705 rcDst.right = rcDst.left + drawSize.x;
706 rcDst.bottom = rcDst.top + drawSize.y;
707 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, drawSize.x, drawSize.y,
708 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
709 transparent, transparentcolor))
710 hr = HRESULT_FROM_WIN32(GetLastError());
717 dstSize.x = abs(dstSize.x);
718 dstSize.y = abs(dstSize.y);
720 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm);
723 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
725 /* Upper left corner */
726 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
727 hdcSrc, rcSrc.left, rcSrc.top,
728 transparent, transparentcolor)) {
729 hr = HRESULT_FROM_WIN32(GetLastError());
732 /* Upper right corner */
733 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
734 sm.cxRightWidth, sm.cyTopHeight,
735 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
736 transparent, transparentcolor)) {
737 hr = HRESULT_FROM_WIN32(GetLastError());
740 /* Lower left corner */
741 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
742 sm.cxLeftWidth, sm.cyBottomHeight,
743 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
744 transparent, transparentcolor)) {
745 hr = HRESULT_FROM_WIN32(GetLastError());
748 /* Lower right corner */
749 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
750 sm.cxRightWidth, sm.cyBottomHeight,
751 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
752 transparent, transparentcolor)) {
753 hr = HRESULT_FROM_WIN32(GetLastError());
757 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
758 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
759 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
760 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
761 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
763 if(destCenterWidth > 0) {
765 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
766 destCenterWidth, sm.cyTopHeight,
767 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
768 srcCenterWidth, sm.cyTopHeight,
769 sizingtype, transparent, transparentcolor)) {
770 hr = HRESULT_FROM_WIN32(GetLastError());
774 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
775 destCenterWidth, sm.cyBottomHeight,
776 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
777 srcCenterWidth, sm.cyBottomHeight,
778 sizingtype, transparent, transparentcolor)) {
779 hr = HRESULT_FROM_WIN32(GetLastError());
783 if(destCenterHeight > 0) {
785 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
786 sm.cxLeftWidth, destCenterHeight,
787 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
788 sm.cxLeftWidth, srcCenterHeight,
790 transparent, transparentcolor)) {
791 hr = HRESULT_FROM_WIN32(GetLastError());
795 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
796 sm.cxRightWidth, destCenterHeight,
797 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
798 sm.cxRightWidth, srcCenterHeight,
799 sizingtype, transparent, transparentcolor)) {
800 hr = HRESULT_FROM_WIN32(GetLastError());
804 if(destCenterHeight > 0 && destCenterWidth > 0) {
805 BOOL borderonly = FALSE;
806 GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);
809 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
810 destCenterWidth, destCenterHeight,
811 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
812 srcCenterWidth, srcCenterHeight,
813 sizingtype, transparent, transparentcolor)) {
814 hr = HRESULT_FROM_WIN32(GetLastError());
822 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
824 SelectObject(hdcSrc, oldSrc);
826 CopyRect(pRect, &rcDst);
830 /***********************************************************************
831 * UXTHEME_DrawBorderRectangle
833 * Draw the bounding rectangle for a borderfill background
835 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId,
836 int iStateId, RECT *pRect,
837 const DTBGOPTS *pOptions)
842 COLORREF bordercolor = RGB(0,0,0);
845 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
848 ptCorners[0].x = pRect->left;
849 ptCorners[0].y = pRect->top;
850 ptCorners[1].x = pRect->right-1;
851 ptCorners[1].y = pRect->top;
852 ptCorners[2].x = pRect->right-1;
853 ptCorners[2].y = pRect->bottom-1;
854 ptCorners[3].x = pRect->left;
855 ptCorners[3].y = pRect->bottom-1;
856 ptCorners[4].x = pRect->left;
857 ptCorners[4].y = pRect->top;
859 InflateRect(pRect, -bordersize, -bordersize);
860 if(pOptions->dwFlags & DTBG_OMITBORDER)
862 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor);
863 hPen = CreatePen(PS_SOLID, bordersize, bordercolor);
865 return HRESULT_FROM_WIN32(GetLastError());
866 oldPen = SelectObject(hdc, hPen);
868 if(!Polyline(hdc, ptCorners, 5))
869 hr = HRESULT_FROM_WIN32(GetLastError());
871 SelectObject(hdc, oldPen);
877 /***********************************************************************
878 * UXTHEME_DrawBackgroundFill
880 * Fill a borderfill background rectangle
882 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId,
883 int iStateId, RECT *pRect,
884 const DTBGOPTS *pOptions)
887 int filltype = FT_SOLID;
889 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags);
891 if(pOptions->dwFlags & DTBG_OMITCONTENT)
894 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype);
896 if(filltype == FT_SOLID) {
898 COLORREF fillcolor = RGB(255,255,255);
900 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor);
901 hBrush = CreateSolidBrush(fillcolor);
902 if(!FillRect(hdc, pRect, hBrush))
903 hr = HRESULT_FROM_WIN32(GetLastError());
904 DeleteObject(hBrush);
906 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) {
907 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores
908 the gradient ratios (no idea how those work)
909 Few themes use this, and the ones I've seen only use 2 colors with
910 a gradient ratio of 0 and 255 respectively
913 COLORREF gradient1 = RGB(0,0,0);
914 COLORREF gradient2 = RGB(255,255,255);
918 FIXME("Gradient implementation not complete\n");
920 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1);
921 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2);
923 vert[0].x = pRect->left;
924 vert[0].y = pRect->top;
925 vert[0].Red = GetRValue(gradient1) << 8;
926 vert[0].Green = GetGValue(gradient1) << 8;
927 vert[0].Blue = GetBValue(gradient1) << 8;
928 vert[0].Alpha = 0x0000;
930 vert[1].x = pRect->right;
931 vert[1].y = pRect->bottom;
932 vert[1].Red = GetRValue(gradient2) << 8;
933 vert[1].Green = GetGValue(gradient2) << 8;
934 vert[1].Blue = GetBValue(gradient2) << 8;
935 vert[1].Alpha = 0x0000;
938 gRect.LowerRight = 1;
939 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V);
941 else if(filltype == FT_RADIALGRADIENT) {
942 /* I've never seen this used in a theme */
943 FIXME("Radial gradient\n");
945 else if(filltype == FT_TILEIMAGE) {
946 /* I've never seen this used in a theme */
947 FIXME("Tile image\n");
952 /***********************************************************************
953 * UXTHEME_DrawBorderBackground
955 * Draw an imagefile background
957 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId,
958 int iStateId, const RECT *pRect,
959 const DTBGOPTS *pOptions)
964 CopyRect(&rt, pRect);
966 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
969 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions);
972 /***********************************************************************
973 * DrawThemeBackgroundEx (UXTHEME.@)
975 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId,
976 int iStateId, const RECT *pRect,
977 const DTBGOPTS *pOptions)
980 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}};
981 const DTBGOPTS *opts;
984 int bgtype = BT_BORDERFILL;
987 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top);
991 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
992 if (bgtype == BT_NONE) return S_OK;
994 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */
996 if(!opts) opts = &defaultOpts;
998 if(opts->dwFlags & DTBG_CLIPRECT) {
999 clip = CreateRectRgn(0,0,1,1);
1000 hasClip = GetClipRgn(hdc, clip);
1002 TRACE("Failed to get original clipping region\n");
1004 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom);
1006 CopyRect(&rt, pRect);
1008 if(bgtype == BT_IMAGEFILE)
1009 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts);
1010 else if(bgtype == BT_BORDERFILL)
1011 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts);
1013 FIXME("Unknown background type\n");
1014 /* This should never happen, and hence I don't know what to return */
1018 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rt, opts);
1019 if(opts->dwFlags & DTBG_CLIPRECT) {
1021 SelectClipRgn(hdc, NULL);
1022 else if(hasClip == 1)
1023 SelectClipRgn(hdc, clip);
1030 * DrawThemeEdge() implementation
1032 * Since it basically is DrawEdge() with different colors, I copied its code
1033 * from user32's uitools.c.
1054 } EdgeColorMap[EDGE_NUMCOLORS] = {
1055 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT},
1056 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT},
1057 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW},
1058 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW},
1059 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE},
1061 {-1, COLOR_WINDOWFRAME}
1064 static const signed char LTInnerNormal[] = {
1066 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1,
1067 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1,
1071 static const signed char LTOuterNormal[] = {
1072 -1, EDGE_LIGHT, EDGE_SHADOW, -1,
1073 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1,
1074 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1,
1075 -1, EDGE_LIGHT, EDGE_SHADOW, -1
1078 static const signed char RBInnerNormal[] = {
1080 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1081 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1085 static const signed char RBOuterNormal[] = {
1086 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1087 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1088 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1,
1089 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1
1092 static const signed char LTInnerSoft[] = {
1094 -1, EDGE_LIGHT, EDGE_LIGHT, -1,
1095 -1, EDGE_SHADOW, EDGE_SHADOW, -1,
1099 static const signed char LTOuterSoft[] = {
1100 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1101 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1102 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1,
1103 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1
1106 #define RBInnerSoft RBInnerNormal /* These are the same */
1107 #define RBOuterSoft RBOuterNormal
1109 static const signed char LTRBOuterMono[] = {
1110 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1111 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1112 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1113 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME,
1116 static const signed char LTRBInnerMono[] = {
1118 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1119 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1120 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW,
1123 static const signed char LTRBOuterFlat[] = {
1124 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1125 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1126 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1127 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW,
1130 static const signed char LTRBInnerFlat[] = {
1132 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1133 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1134 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL,
1137 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state)
1140 if ((EdgeColorMap[edgeType].themeProp == -1)
1141 || FAILED (GetThemeColor (theme, part, state,
1142 EdgeColorMap[edgeType].themeProp, &col)))
1143 col = GetSysColor (EdgeColorMap[edgeType].sysColor);
1147 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state)
1149 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state));
1152 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state)
1154 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state));
1157 /***********************************************************************
1160 * Same as DrawEdge invoked with BF_DIAGONAL
1162 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state,
1163 const RECT* rc, UINT uType,
1164 UINT uFlags, LPRECT contentsRect)
1167 signed char InnerI, OuterI;
1168 HPEN InnerPen, OuterPen;
1173 int Width = rc->right - rc->left;
1174 int Height= rc->bottom - rc->top;
1175 int SmallDiam = Width > Height ? Height : Width;
1176 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1177 || (uType & BDR_OUTER) == BDR_OUTER)
1178 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1179 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1180 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1182 /* Init some vars */
1183 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
1184 SavePen = (HPEN)SelectObject(hdc, InnerPen);
1185 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
1187 /* Determine the colors of the edges */
1188 if(uFlags & BF_MONO)
1190 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1191 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1193 else if(uFlags & BF_FLAT)
1195 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1196 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1198 else if(uFlags & BF_SOFT)
1200 if(uFlags & BF_BOTTOM)
1202 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1203 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1207 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1208 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1213 if(uFlags & BF_BOTTOM)
1215 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1216 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1220 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1221 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1225 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state);
1226 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state);
1228 MoveToEx(hdc, 0, 0, &SavePoint);
1230 /* Don't ask me why, but this is what is visible... */
1231 /* This must be possible to do much simpler, but I fail to */
1232 /* see the logic in the MS implementation (sigh...). */
1233 /* So, this might look a bit brute force here (and it is), but */
1234 /* it gets the job done;) */
1236 switch(uFlags & BF_RECT)
1242 /* Left bottom endpoint */
1244 spx = epx + SmallDiam;
1246 spy = epy - SmallDiam;
1250 case BF_BOTTOMRIGHT:
1251 /* Left top endpoint */
1253 spx = epx + SmallDiam;
1255 spy = epy + SmallDiam;
1261 case BF_RIGHT|BF_LEFT:
1262 case BF_RIGHT|BF_LEFT|BF_TOP:
1263 case BF_BOTTOM|BF_TOP:
1264 case BF_BOTTOM|BF_TOP|BF_LEFT:
1265 case BF_BOTTOMRIGHT|BF_LEFT:
1266 case BF_BOTTOMRIGHT|BF_TOP:
1268 /* Right top endpoint */
1270 epx = spx + SmallDiam;
1272 epy = spy - SmallDiam;
1276 MoveToEx(hdc, spx, spy, NULL);
1277 SelectObject(hdc, OuterPen);
1278 LineTo(hdc, epx, epy);
1280 SelectObject(hdc, InnerPen);
1282 switch(uFlags & (BF_RECT|BF_DIAGONAL))
1284 case BF_DIAGONAL_ENDBOTTOMLEFT:
1285 case (BF_DIAGONAL|BF_BOTTOM):
1287 case (BF_DIAGONAL|BF_LEFT):
1288 MoveToEx(hdc, spx-1, spy, NULL);
1289 LineTo(hdc, epx, epy-1);
1290 Points[0].x = spx-add;
1292 Points[1].x = rc->left;
1293 Points[1].y = rc->top;
1294 Points[2].x = epx+1;
1295 Points[2].y = epy-1-add;
1296 Points[3] = Points[2];
1299 case BF_DIAGONAL_ENDBOTTOMRIGHT:
1300 MoveToEx(hdc, spx-1, spy, NULL);
1301 LineTo(hdc, epx, epy+1);
1302 Points[0].x = spx-add;
1304 Points[1].x = rc->left;
1305 Points[1].y = rc->bottom-1;
1306 Points[2].x = epx+1;
1307 Points[2].y = epy+1+add;
1308 Points[3] = Points[2];
1311 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
1312 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
1313 case BF_DIAGONAL_ENDTOPRIGHT:
1314 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
1315 MoveToEx(hdc, spx+1, spy, NULL);
1316 LineTo(hdc, epx, epy+1);
1317 Points[0].x = epx-1;
1318 Points[0].y = epy+1+add;
1319 Points[1].x = rc->right-1;
1320 Points[1].y = rc->top+add;
1321 Points[2].x = rc->right-1;
1322 Points[2].y = rc->bottom-1;
1323 Points[3].x = spx+add;
1327 case BF_DIAGONAL_ENDTOPLEFT:
1328 MoveToEx(hdc, spx, spy-1, NULL);
1329 LineTo(hdc, epx+1, epy);
1330 Points[0].x = epx+1+add;
1331 Points[0].y = epy+1;
1332 Points[1].x = rc->right-1;
1333 Points[1].y = rc->top;
1334 Points[2].x = rc->right-1;
1335 Points[2].y = rc->bottom-1-add;
1337 Points[3].y = spy-add;
1340 case (BF_DIAGONAL|BF_TOP):
1341 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
1342 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
1343 MoveToEx(hdc, spx+1, spy-1, NULL);
1344 LineTo(hdc, epx, epy);
1345 Points[0].x = epx-1;
1346 Points[0].y = epy+1;
1347 Points[1].x = rc->right-1;
1348 Points[1].y = rc->top;
1349 Points[2].x = rc->right-1;
1350 Points[2].y = rc->bottom-1-add;
1351 Points[3].x = spx+add;
1352 Points[3].y = spy-add;
1355 case (BF_DIAGONAL|BF_RIGHT):
1356 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
1357 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
1358 MoveToEx(hdc, spx, spy, NULL);
1359 LineTo(hdc, epx-1, epy+1);
1362 Points[1].x = rc->left;
1363 Points[1].y = rc->top+add;
1364 Points[2].x = epx-1-add;
1365 Points[2].y = epy+1+add;
1366 Points[3] = Points[2];
1370 /* Fill the interior if asked */
1371 if((uFlags & BF_MIDDLE) && retval)
1374 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1375 theme, part, state);
1377 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1378 theme, part, state);
1379 hbsave = (HBRUSH)SelectObject(hdc, hb);
1380 hpsave = (HPEN)SelectObject(hdc, hp);
1381 Polygon(hdc, Points, 4);
1382 SelectObject(hdc, hbsave);
1383 SelectObject(hdc, hpsave);
1388 /* Adjust rectangle if asked */
1389 if(uFlags & BF_ADJUST)
1391 *contentsRect = *rc;
1392 if(uFlags & BF_LEFT) contentsRect->left += add;
1393 if(uFlags & BF_RIGHT) contentsRect->right -= add;
1394 if(uFlags & BF_TOP) contentsRect->top += add;
1395 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add;
1399 SelectObject(hdc, SavePen);
1400 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1401 if(InnerI != -1) DeleteObject (InnerPen);
1402 if(OuterI != -1) DeleteObject (OuterPen);
1407 /***********************************************************************
1410 * Same as DrawEdge invoked without BF_DIAGONAL
1412 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state,
1413 const RECT* rc, UINT uType,
1414 UINT uFlags, LPRECT contentsRect)
1416 signed char LTInnerI, LTOuterI;
1417 signed char RBInnerI, RBOuterI;
1418 HPEN LTInnerPen, LTOuterPen;
1419 HPEN RBInnerPen, RBOuterPen;
1420 RECT InnerRect = *rc;
1427 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER
1428 || (uType & BDR_OUTER) == BDR_OUTER)
1429 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK;
1431 /* Init some vars */
1432 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
1433 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
1435 /* Determine the colors of the edges */
1436 if(uFlags & BF_MONO)
1438 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
1439 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
1441 else if(uFlags & BF_FLAT)
1443 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
1444 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
1446 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL;
1448 else if(uFlags & BF_SOFT)
1450 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1451 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1452 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
1453 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
1457 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1458 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1459 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
1460 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
1463 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
1464 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
1465 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
1466 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
1468 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state);
1469 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state);
1470 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state);
1471 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state);
1473 MoveToEx(hdc, 0, 0, &SavePoint);
1475 /* Draw the outer edge */
1476 SelectObject(hdc, LTOuterPen);
1479 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1480 LineTo(hdc, InnerRect.right, InnerRect.top);
1482 if(uFlags & BF_LEFT)
1484 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
1485 LineTo(hdc, InnerRect.left, InnerRect.bottom);
1487 SelectObject(hdc, RBOuterPen);
1488 if(uFlags & BF_BOTTOM)
1490 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1491 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
1493 if(uFlags & BF_RIGHT)
1495 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
1496 LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
1499 /* Draw the inner edge */
1500 SelectObject(hdc, LTInnerPen);
1503 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
1504 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
1506 if(uFlags & BF_LEFT)
1508 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
1509 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
1511 SelectObject(hdc, RBInnerPen);
1512 if(uFlags & BF_BOTTOM)
1514 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
1515 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
1517 if(uFlags & BF_RIGHT)
1519 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
1520 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
1523 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
1525 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
1526 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
1528 if(uFlags & BF_LEFT) InnerRect.left += add;
1529 if(uFlags & BF_RIGHT) InnerRect.right -= add;
1530 if(uFlags & BF_TOP) InnerRect.top += add;
1531 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
1533 if((uFlags & BF_MIDDLE) && retval)
1535 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL,
1536 theme, part, state);
1537 FillRect(hdc, &InnerRect, br);
1541 if(uFlags & BF_ADJUST)
1542 *contentsRect = InnerRect;
1546 SelectObject(hdc, SavePen);
1547 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
1548 if(LTInnerI != -1) DeleteObject (LTInnerPen);
1549 if(LTOuterI != -1) DeleteObject (LTOuterPen);
1550 if(RBInnerI != -1) DeleteObject (RBInnerPen);
1551 if(RBOuterI != -1) DeleteObject (RBOuterPen);
1556 /***********************************************************************
1557 * DrawThemeEdge (UXTHEME.@)
1559 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the
1560 * difference is that it does not rely on the system colors alone, but
1561 * also allows color specification in the theme.
1563 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId,
1564 int iStateId, const RECT *pDestRect, UINT uEdge,
1565 UINT uFlags, RECT *pContentRect)
1567 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags);
1571 if(uFlags & BF_DIAGONAL)
1572 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1573 uEdge, uFlags, pContentRect);
1575 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect,
1576 uEdge, uFlags, pContentRect);
1580 /***********************************************************************
1581 * DrawThemeIcon (UXTHEME.@)
1583 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1584 const RECT *pRect, HIMAGELIST himl, int iImageIndex)
1586 FIXME("%d %d: stub\n", iPartId, iStateId);
1589 return ERROR_CALL_NOT_IMPLEMENTED;
1592 /***********************************************************************
1593 * DrawThemeText (UXTHEME.@)
1595 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
1596 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
1597 DWORD dwTextFlags2, const RECT *pRect)
1601 HGDIOBJ oldFont = NULL;
1604 COLORREF oldTextColor;
1608 TRACE("%d %d: stub\n", iPartId, iStateId);
1612 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1614 hFont = CreateFontIndirectW(&logfont);
1616 TRACE("Failed to create font\n");
1618 CopyRect(&rt, pRect);
1620 oldFont = SelectObject(hdc, hFont);
1622 if(dwTextFlags2 & DTT_GRAYED)
1623 textColor = GetSysColor(COLOR_GRAYTEXT);
1625 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTCOLOR, &textColor)))
1626 textColor = GetTextColor(hdc);
1628 oldTextColor = SetTextColor(hdc, textColor);
1629 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1630 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
1631 SetBkMode(hdc, oldBkMode);
1632 SetTextColor(hdc, oldTextColor);
1635 SelectObject(hdc, oldFont);
1636 DeleteObject(hFont);
1641 /***********************************************************************
1642 * GetThemeBackgroundContentRect (UXTHEME.@)
1644 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId,
1646 const RECT *pBoundingRect,
1652 TRACE("(%d,%d)\n", iPartId, iStateId);
1656 /* try content margins property... */
1657 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1659 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1660 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1661 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1662 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1664 /* otherwise, try to determine content rect from the background type and props */
1665 int bgtype = BT_BORDERFILL;
1666 *pContentRect = *pBoundingRect;
1668 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1669 if(bgtype == BT_BORDERFILL) {
1672 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1673 InflateRect(pContentRect, -bordersize, -bordersize);
1674 } else if ((bgtype == BT_IMAGEFILE)
1675 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1676 TMT_SIZINGMARGINS, NULL, &margin)))) {
1677 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth;
1678 pContentRect->top = pBoundingRect->top + margin.cyTopHeight;
1679 pContentRect->right = pBoundingRect->right - margin.cxRightWidth;
1680 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight;
1682 /* If nothing was found, leave unchanged */
1685 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pContentRect->left, pContentRect->top, pContentRect->right, pContentRect->bottom);
1690 /***********************************************************************
1691 * GetThemeBackgroundExtent (UXTHEME.@)
1693 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId,
1694 int iStateId, const RECT *pContentRect,
1700 TRACE("(%d,%d)\n", iPartId, iStateId);
1704 /* try content margins property... */
1705 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin);
1707 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1708 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1709 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1710 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1712 /* otherwise, try to determine content rect from the background type and props */
1713 int bgtype = BT_BORDERFILL;
1714 *pExtentRect = *pContentRect;
1716 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1717 if(bgtype == BT_BORDERFILL) {
1720 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize);
1721 InflateRect(pExtentRect, bordersize, bordersize);
1722 } else if ((bgtype == BT_IMAGEFILE)
1723 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId,
1724 TMT_SIZINGMARGINS, NULL, &margin)))) {
1725 pExtentRect->left = pContentRect->left - margin.cxLeftWidth;
1726 pExtentRect->top = pContentRect->top - margin.cyTopHeight;
1727 pExtentRect->right = pContentRect->right + margin.cxRightWidth;
1728 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight;
1730 /* If nothing was found, leave unchanged */
1733 TRACE("left:%d,top:%d,right:%d,bottom:%d\n", pExtentRect->left, pExtentRect->top, pExtentRect->right, pExtentRect->bottom);
1738 /***********************************************************************
1739 * GetThemeBackgroundRegion (UXTHEME.@)
1741 * Calculate the background region, taking into consideration transparent areas
1742 * of the background image.
1744 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId,
1745 int iStateId, const RECT *pRect,
1749 int bgtype = BT_BORDERFILL;
1751 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId);
1754 if(!pRect || !pRegion)
1757 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1758 if(bgtype == BT_IMAGEFILE) {
1759 FIXME("Images not handled yet\n");
1760 hr = ERROR_CALL_NOT_IMPLEMENTED;
1762 else if(bgtype == BT_BORDERFILL) {
1763 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
1765 hr = HRESULT_FROM_WIN32(GetLastError());
1768 FIXME("Unknown background type\n");
1769 /* This should never happen, and hence I don't know what to return */
1775 /* compute part size for "borderfill" backgrounds */
1776 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId,
1777 int iStateId, THEMESIZE eSize, POINT* psz)
1782 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE,
1785 psz->x = psz->y = 2*bordersize;
1786 if (eSize != TS_MIN)
1795 /***********************************************************************
1796 * GetThemePartSize (UXTHEME.@)
1798 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId,
1799 int iStateId, RECT *prc, THEMESIZE eSize,
1802 int bgtype = BT_BORDERFILL;
1804 POINT size = {1, 1};
1809 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1810 if (bgtype == BT_NONE)
1812 else if(bgtype == BT_IMAGEFILE)
1813 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size);
1814 else if(bgtype == BT_BORDERFILL)
1815 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size);
1817 FIXME("Unknown background type\n");
1818 /* This should never happen, and hence I don't know what to return */
1827 /***********************************************************************
1828 * GetThemeTextExtent (UXTHEME.@)
1830 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId,
1831 int iStateId, LPCWSTR pszText, int iCharCount,
1832 DWORD dwTextFlags, const RECT *pBoundingRect,
1837 HGDIOBJ oldFont = NULL;
1839 RECT rt = {0,0,0xFFFF,0xFFFF};
1841 TRACE("%d %d: stub\n", iPartId, iStateId);
1846 CopyRect(&rt, pBoundingRect);
1848 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1850 hFont = CreateFontIndirectW(&logfont);
1852 TRACE("Failed to create font\n");
1855 oldFont = SelectObject(hdc, hFont);
1857 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT);
1858 CopyRect(pExtentRect, &rt);
1861 SelectObject(hdc, oldFont);
1862 DeleteObject(hFont);
1867 /***********************************************************************
1868 * GetThemeTextMetrics (UXTHEME.@)
1870 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId,
1871 int iStateId, TEXTMETRICW *ptm)
1875 HGDIOBJ oldFont = NULL;
1878 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId);
1882 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont);
1884 hFont = CreateFontIndirectW(&logfont);
1886 TRACE("Failed to create font\n");
1889 oldFont = SelectObject(hdc, hFont);
1891 if(!GetTextMetricsW(hdc, ptm))
1892 hr = HRESULT_FROM_WIN32(GetLastError());
1895 SelectObject(hdc, oldFont);
1896 DeleteObject(hFont);
1901 /***********************************************************************
1902 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@)
1904 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId,
1907 int bgtype = BT_BORDERFILL;
1908 RECT rect = {0, 0, 0, 0};
1913 COLORREF transparentcolor;
1915 TRACE("(%d,%d)\n", iPartId, iStateId);
1920 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
1922 if (bgtype != BT_IMAGEFILE) return FALSE;
1924 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE,
1925 &bmpSrc, &rcSrc, &hasAlpha)))
1928 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent,
1929 &transparentcolor, FALSE);
1930 return (transparent != ALPHABLEND_NONE);