1 /* 2 * Win32 5.1 Theme drawing 3 * 4 * Copyright (C) 2003 Kevin Koltzau 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 #include "uxthemep.h" 22 23 #include <stdlib.h> 24 25 /*********************************************************************** 26 * Defines and global variables 27 */ 28 29 extern ATOM atDialogThemeEnabled; 30 31 /***********************************************************************/ 32 33 /*********************************************************************** 34 * EnableThemeDialogTexture (UXTHEME.@) 35 */ 36 HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD dwFlags) 37 { 38 static const WCHAR szTab[] = { 'T','a','b',0 }; 39 BOOL res; 40 41 TRACE("(%p,0x%08x\n", hwnd, dwFlags); 42 res = SetPropW (hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled), 43 UlongToHandle(dwFlags|0x80000000)); 44 /* 0x80000000 serves as a "flags set" flag */ 45 if (!res) 46 return HRESULT_FROM_WIN32(GetLastError()); 47 if (dwFlags & ETDT_USETABTEXTURE) 48 return SetWindowTheme (hwnd, NULL, szTab); 49 else 50 return S_OK; 51 } 52 53 /*********************************************************************** 54 * IsThemeDialogTextureEnabled (UXTHEME.@) 55 */ 56 BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd) 57 { 58 DWORD dwDialogTextureFlags; 59 TRACE("(%p)\n", hwnd); 60 61 dwDialogTextureFlags = HandleToUlong( GetPropW( hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled) )); 62 if (dwDialogTextureFlags == 0) 63 /* Means EnableThemeDialogTexture wasn't called for this dialog */ 64 return FALSE; 65 66 return (dwDialogTextureFlags & ETDT_ENABLE) && !(dwDialogTextureFlags & ETDT_DISABLE); 67 } 68 69 /*********************************************************************** 70 * DrawThemeParentBackground (UXTHEME.@) 71 */ 72 HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc) 73 { 74 RECT rt; 75 POINT org; 76 HWND hParent; 77 HRGN clip = NULL; 78 int hasClip = -1; 79 80 TRACE("(%p,%p,%p)\n", hwnd, hdc, prc); 81 82 if (!IsWindow(hwnd) || !hdc) 83 return E_HANDLE; 84 85 if (prc && IsBadReadPtr (prc, sizeof(RECT))) 86 return E_POINTER; 87 88 hParent = GetParent(hwnd); 89 if(!hParent) 90 return S_OK; 91 92 if(prc) { 93 rt = *prc; 94 MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2); 95 96 clip = CreateRectRgn(0,0,1,1); 97 hasClip = GetClipRgn(hdc, clip); 98 if(hasClip == -1) 99 TRACE("Failed to get original clipping region\n"); 100 else 101 IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom); 102 } 103 else { 104 GetClientRect(hwnd, &rt); 105 MapWindowPoints(hwnd, hParent, (LPPOINT)&rt, 2); 106 } 107 108 OffsetViewportOrgEx(hdc, -rt.left, -rt.top, &org); 109 110 SendMessageW(hParent, WM_ERASEBKGND, (WPARAM)hdc, 0); 111 SendMessageW(hParent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT); 112 113 SetViewportOrgEx(hdc, org.x, org.y, NULL); 114 if(prc) { 115 if(hasClip == 0) 116 SelectClipRgn(hdc, NULL); 117 else if(hasClip == 1) 118 SelectClipRgn(hdc, clip); 119 DeleteObject(clip); 120 } 121 return S_OK; 122 } 123 124 125 /*********************************************************************** 126 * DrawThemeBackground (UXTHEME.@) 127 */ 128 HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, 129 int iStateId, const RECT *pRect, 130 const RECT *pClipRect) 131 { 132 DTBGOPTS opts; 133 opts.dwSize = sizeof(DTBGOPTS); 134 opts.dwFlags = 0; 135 if(pClipRect) { 136 opts.dwFlags |= DTBG_CLIPRECT; 137 opts.rcClip = *pClipRect; 138 } 139 return DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, &opts); 140 } 141 142 /*********************************************************************** 143 * UXTHEME_SelectImage 144 * 145 * Select the image to use 146 */ 147 static PTHEME_PROPERTY UXTHEME_SelectImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph) 148 { 149 PTHEME_CLASS pClass; 150 PTHEME_PROPERTY tp; 151 int imageselecttype = IST_NONE; 152 int i; 153 int image; 154 155 if(glyph) 156 image = TMT_GLYPHIMAGEFILE; 157 else 158 image = TMT_IMAGEFILE; 159 160 pClass = ValidateHandle(hTheme); 161 if((tp=MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, image))) 162 return tp; 163 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGESELECTTYPE, &imageselecttype); 164 165 if(imageselecttype == IST_DPI) { 166 int reqdpi = 0; 167 int screendpi = GetDeviceCaps(hdc, LOGPIXELSX); 168 for(i=4; i>=0; i--) { 169 reqdpi = 0; 170 if(SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, i + TMT_MINDPI1, &reqdpi))) { 171 if(reqdpi != 0 && screendpi >= reqdpi) { 172 TRACE("Using %d DPI, image %d\n", reqdpi, i + TMT_IMAGEFILE1); 173 return MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1); 174 } 175 } 176 } 177 /* If an image couldn't be selected, choose the first one */ 178 return MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1); 179 } 180 else if(imageselecttype == IST_SIZE) { 181 POINT size = {pRect->right-pRect->left, pRect->bottom-pRect->top}; 182 POINT reqsize; 183 for(i=4; i>=0; i--) { 184 PTHEME_PROPERTY fileProp = 185 MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, i + TMT_IMAGEFILE1); 186 if (!fileProp) continue; 187 if(FAILED(GetThemePosition(hTheme, iPartId, iStateId, i + TMT_MINSIZE1, &reqsize))) { 188 /* fall back to size of Nth image */ 189 WCHAR szPath[MAX_PATH]; 190 int imagelayout = IL_HORIZONTAL; 191 int imagecount = 1; 192 BITMAP bmp; 193 HBITMAP hBmp; 194 BOOL hasAlpha; 195 196 lstrcpynW(szPath, fileProp->lpValue, 197 min(fileProp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0]))); 198 hBmp = MSSTYLES_LoadBitmap(pClass, szPath, &hasAlpha); 199 if(!hBmp) continue; 200 201 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout); 202 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount); 203 204 GetObjectW(hBmp, sizeof(bmp), &bmp); 205 if(imagelayout == IL_VERTICAL) { 206 reqsize.x = bmp.bmWidth; 207 reqsize.y = bmp.bmHeight/imagecount; 208 } 209 else { 210 reqsize.x = bmp.bmWidth/imagecount; 211 reqsize.y = bmp.bmHeight; 212 } 213 } 214 if(reqsize.x <= size.x && reqsize.y <= size.y) { 215 TRACE("Using image size %dx%d, image %d\n", reqsize.x, reqsize.y, i + TMT_IMAGEFILE1); 216 return fileProp; 217 } 218 } 219 /* If an image couldn't be selected, choose the smallest one */ 220 return MSSTYLES_FindProperty(pClass, iPartId, iStateId, TMT_FILENAME, TMT_IMAGEFILE1); 221 } 222 return NULL; 223 } 224 225 /*********************************************************************** 226 * UXTHEME_LoadImage 227 * 228 * Load image for part/state 229 */ 230 HRESULT UXTHEME_LoadImage(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, BOOL glyph, 231 HBITMAP *hBmp, RECT *bmpRect, BOOL* hasImageAlpha) 232 { 233 int imagelayout = IL_HORIZONTAL; 234 int imagecount = 1; 235 int imagenum; 236 BITMAP bmp; 237 WCHAR szPath[MAX_PATH]; 238 PTHEME_PROPERTY tp; 239 PTHEME_CLASS pClass; 240 241 pClass = ValidateHandle(hTheme); 242 if (!pClass) 243 return E_HANDLE; 244 245 tp = UXTHEME_SelectImage(hTheme, hdc, iPartId, iStateId, pRect, glyph); 246 if(!tp) { 247 FIXME("Couldn't determine image for part/state %d/%d, invalid theme?\n", iPartId, iStateId); 248 return E_PROP_ID_UNSUPPORTED; 249 } 250 lstrcpynW(szPath, tp->lpValue, min(tp->dwValueLen+1, sizeof(szPath)/sizeof(szPath[0]))); 251 *hBmp = MSSTYLES_LoadBitmap(pClass, szPath, hasImageAlpha); 252 if(!*hBmp) { 253 TRACE("Failed to load bitmap %s\n", debugstr_w(szPath)); 254 return HRESULT_FROM_WIN32(GetLastError()); 255 } 256 257 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_IMAGELAYOUT, &imagelayout); 258 GetThemeInt(hTheme, iPartId, iStateId, TMT_IMAGECOUNT, &imagecount); 259 260 imagenum = max (min (imagecount, iStateId), 1) - 1; 261 GetObjectW(*hBmp, sizeof(bmp), &bmp); 262 263 if(imagecount < 1) imagecount = 1; 264 265 if(imagelayout == IL_VERTICAL) { 266 int height = bmp.bmHeight/imagecount; 267 bmpRect->left = 0; 268 bmpRect->right = bmp.bmWidth; 269 bmpRect->top = imagenum * height; 270 bmpRect->bottom = bmpRect->top + height; 271 } 272 else { 273 int width = bmp.bmWidth/imagecount; 274 bmpRect->left = imagenum * width; 275 bmpRect->right = bmpRect->left + width; 276 bmpRect->top = 0; 277 bmpRect->bottom = bmp.bmHeight; 278 } 279 return S_OK; 280 } 281 282 /* Get transparency parameters passed to UXTHEME_StretchBlt() - the parameters 283 * depend on whether the image has full alpha or whether it is 284 * color-transparent or just opaque. */ 285 static inline void get_transparency (HTHEME hTheme, int iPartId, int iStateId, 286 BOOL hasImageAlpha, INT* transparent, 287 COLORREF* transparentcolor, BOOL glyph) 288 { 289 if (hasImageAlpha) 290 { 291 *transparent = ALPHABLEND_FULL; 292 *transparentcolor = RGB (255, 0, 255); 293 } 294 else 295 { 296 BOOL trans = FALSE; 297 GetThemeBool(hTheme, iPartId, iStateId, 298 glyph ? TMT_GLYPHTRANSPARENT : TMT_TRANSPARENT, &trans); 299 if(trans) { 300 *transparent = ALPHABLEND_BINARY; 301 if(FAILED(GetThemeColor(hTheme, iPartId, iStateId, 302 glyph ? TMT_GLYPHTRANSPARENTCOLOR : TMT_TRANSPARENTCOLOR, 303 transparentcolor))) { 304 /* If image is transparent, but no color was specified, use magenta */ 305 *transparentcolor = RGB(255, 0, 255); 306 } 307 } 308 else 309 *transparent = ALPHABLEND_NONE; 310 } 311 } 312 313 /*********************************************************************** 314 * UXTHEME_DrawImageGlyph 315 * 316 * Draw an imagefile glyph 317 */ 318 static HRESULT UXTHEME_DrawImageGlyph(HTHEME hTheme, HDC hdc, int iPartId, 319 int iStateId, RECT *pRect, 320 const DTBGOPTS *pOptions) 321 { 322 HRESULT hr; 323 HBITMAP bmpSrc = NULL; 324 RECT rcSrc; 325 INT transparent = 0; 326 COLORREF transparentcolor; 327 int valign = VA_CENTER; 328 int halign = HA_CENTER; 329 POINT dstSize; 330 POINT srcSize; 331 BOOL hasAlpha; 332 RECT rcDst; 333 GDI_DRAW_STREAM DrawStream; 334 335 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, TRUE, 336 &bmpSrc, &rcSrc, &hasAlpha); 337 if(FAILED(hr)) return hr; 338 339 dstSize.x = pRect->right-pRect->left; 340 dstSize.y = pRect->bottom-pRect->top; 341 srcSize.x = rcSrc.right-rcSrc.left; 342 srcSize.y = rcSrc.bottom-rcSrc.top; 343 344 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent, 345 &transparentcolor, TRUE); 346 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign); 347 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign); 348 349 rcDst = *pRect; 350 if(halign == HA_CENTER) rcDst.left += (dstSize.x/2)-(srcSize.x/2); 351 else if(halign == HA_RIGHT) rcDst.left += dstSize.x-srcSize.x; 352 if(valign == VA_CENTER) rcDst.top += (dstSize.y/2)-(srcSize.y/2); 353 else if(valign == VA_BOTTOM) rcDst.top += dstSize.y-srcSize.y; 354 355 rcDst.right = rcDst.left + srcSize.x; 356 rcDst.bottom = rcDst.top + srcSize.y; 357 358 DrawStream.signature = 0x44727753; 359 DrawStream.reserved = 0; 360 DrawStream.unknown1 = 1; 361 DrawStream.unknown2 = 9; 362 DrawStream.hDC = hdc; 363 DrawStream.hImage = bmpSrc; 364 DrawStream.crTransparent = transparentcolor; 365 DrawStream.rcSrc = rcSrc; 366 DrawStream.rcDest = rcDst; 367 DrawStream.leftSizingMargin = 0; 368 DrawStream.rightSizingMargin = 0; 369 DrawStream.topSizingMargin = 0; 370 DrawStream.bottomSizingMargin = 0; 371 DrawStream.drawOption = DS_TRUESIZE; 372 373 if (transparent == ALPHABLEND_FULL) 374 DrawStream.drawOption |= DS_TRANSPARENTALPHA; 375 else if (transparent == ALPHABLEND_BINARY) 376 DrawStream.drawOption |= DS_TRANSPARENTCLR; 377 378 GdiDrawStream(hdc, sizeof(DrawStream), &DrawStream); 379 return HRESULT_FROM_WIN32(GetLastError()); 380 } 381 382 /*********************************************************************** 383 * UXTHEME_DrawImageGlyph 384 * 385 * Draw glyph on top of background, if appropriate 386 */ 387 static HRESULT UXTHEME_DrawGlyph(HTHEME hTheme, HDC hdc, int iPartId, 388 int iStateId, RECT *pRect, 389 const DTBGOPTS *pOptions) 390 { 391 int glyphtype = GT_NONE; 392 393 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_GLYPHTYPE, &glyphtype); 394 395 if(glyphtype == GT_IMAGEGLYPH) { 396 return UXTHEME_DrawImageGlyph(hTheme, hdc, iPartId, iStateId, pRect, pOptions); 397 } 398 else if(glyphtype == GT_FONTGLYPH) { 399 /* I don't know what a font glyph is, I've never seen it used in any themes */ 400 FIXME("Font glyph\n"); 401 } 402 return S_OK; 403 } 404 405 /*********************************************************************** 406 * get_image_part_size 407 * 408 * Used by GetThemePartSize and UXTHEME_DrawImageBackground 409 */ 410 static HRESULT get_image_part_size (HTHEME hTheme, HDC hdc, int iPartId, 411 int iStateId, RECT *prc, THEMESIZE eSize, 412 POINT *psz) 413 { 414 HRESULT hr = S_OK; 415 HBITMAP bmpSrc; 416 RECT rcSrc; 417 BOOL hasAlpha; 418 419 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, prc, FALSE, 420 &bmpSrc, &rcSrc, &hasAlpha); 421 if (FAILED(hr)) return hr; 422 423 switch (eSize) 424 { 425 case TS_DRAW: 426 if (prc != NULL) 427 { 428 RECT rcDst; 429 POINT dstSize; 430 POINT srcSize; 431 int sizingtype = ST_STRETCH; 432 BOOL uniformsizing = FALSE; 433 434 rcDst = *prc; 435 436 dstSize.x = rcDst.right-rcDst.left; 437 dstSize.y = rcDst.bottom-rcDst.top; 438 srcSize.x = rcSrc.right-rcSrc.left; 439 srcSize.y = rcSrc.bottom-rcSrc.top; 440 441 GetThemeBool(hTheme, iPartId, iStateId, TMT_UNIFORMSIZING, &uniformsizing); 442 if(uniformsizing) { 443 /* Scale height and width equally */ 444 if (dstSize.x*srcSize.y < dstSize.y*srcSize.x) 445 { 446 dstSize.y = MulDiv (srcSize.y, dstSize.x, srcSize.x); 447 rcDst.bottom = rcDst.top + dstSize.y; 448 } 449 else 450 { 451 dstSize.x = MulDiv (srcSize.x, dstSize.y, srcSize.y); 452 rcDst.right = rcDst.left + dstSize.x; 453 } 454 } 455 456 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype); 457 if(sizingtype == ST_TRUESIZE) { 458 int truesizestretchmark = 100; 459 460 if(dstSize.x < 0 || dstSize.y < 0) { 461 BOOL mirrorimage = TRUE; 462 GetThemeBool(hTheme, iPartId, iStateId, TMT_MIRRORIMAGE, &mirrorimage); 463 if(mirrorimage) { 464 if(dstSize.x < 0) { 465 rcDst.left += dstSize.x; 466 rcDst.right += dstSize.x; 467 } 468 if(dstSize.y < 0) { 469 rcDst.top += dstSize.y; 470 rcDst.bottom += dstSize.y; 471 } 472 } 473 } 474 /* Whatever TrueSizeStretchMark does - it does not seem to 475 * be what's outlined below. It appears as if native 476 * uxtheme always stretches if dest is smaller than source 477 * (ie as if TrueSizeStretchMark==100 with the code below) */ 478 #if 0 479 /* Only stretch when target exceeds source by truesizestretchmark percent */ 480 GetThemeInt(hTheme, iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &truesizestretchmark); 481 #endif 482 if(dstSize.x < 0 || dstSize.y < 0 || 483 (MulDiv(srcSize.x, 100, dstSize.x) > truesizestretchmark && 484 MulDiv(srcSize.y, 100, dstSize.y) > truesizestretchmark)) { 485 memcpy (psz, &dstSize, sizeof (SIZE)); 486 } 487 else { 488 memcpy (psz, &srcSize, sizeof (SIZE)); 489 } 490 } 491 else 492 { 493 psz->x = abs(dstSize.x); 494 psz->y = abs(dstSize.y); 495 } 496 break; 497 } 498 /* else fall through */ 499 case TS_MIN: 500 /* FIXME: couldn't figure how native uxtheme computes min size */ 501 case TS_TRUE: 502 psz->x = rcSrc.right - rcSrc.left; 503 psz->y = rcSrc.bottom - rcSrc.top; 504 break; 505 } 506 return hr; 507 } 508 509 /*********************************************************************** 510 * UXTHEME_DrawImageBackground 511 * 512 * Draw an imagefile background 513 */ 514 static HRESULT UXTHEME_DrawImageBackground(HTHEME hTheme, HDC hdc, int iPartId, 515 int iStateId, RECT *pRect, 516 const DTBGOPTS *pOptions) 517 { 518 HRESULT hr = S_OK; 519 HBITMAP bmpSrc; 520 RECT rcSrc; 521 RECT rcDst; 522 POINT dstSize; 523 POINT drawSize; 524 int sizingtype = ST_STRETCH; 525 INT transparent; 526 COLORREF transparentcolor = 0; 527 BOOL hasAlpha; 528 MARGINS sm; 529 GDI_DRAW_STREAM DrawStream; 530 531 hr = UXTHEME_LoadImage(hTheme, hdc, iPartId, iStateId, pRect, FALSE, &bmpSrc, &rcSrc, &hasAlpha); 532 if(FAILED(hr)) 533 return hr; 534 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent, &transparentcolor, FALSE); 535 536 rcDst = *pRect; 537 dstSize.x = rcDst.right-rcDst.left; 538 dstSize.y = rcDst.bottom-rcDst.top; 539 540 GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_SIZINGMARGINS, NULL, &sm); 541 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_SIZINGTYPE, &sizingtype); 542 543 /*FIXME: Is this ever used? */ 544 /*GetThemeBool(hTheme, iPartId, iStateId, TMT_BORDERONLY, &borderonly);*/ 545 546 if(sizingtype == ST_TRUESIZE) { 547 int valign = VA_CENTER, halign = HA_CENTER; 548 549 get_image_part_size (hTheme, hdc, iPartId, iStateId, pRect, TS_DRAW, &drawSize); 550 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_VALIGN, &valign); 551 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_HALIGN, &halign); 552 553 if (halign == HA_CENTER) 554 rcDst.left += (dstSize.x/2)-(drawSize.x/2); 555 else if (halign == HA_RIGHT) 556 rcDst.left = rcDst.right - drawSize.x; 557 if (valign == VA_CENTER) 558 rcDst.top += (dstSize.y/2)-(drawSize.y/2); 559 else if (valign == VA_BOTTOM) 560 rcDst.top = rcDst.bottom - drawSize.y; 561 rcDst.right = rcDst.left + drawSize.x; 562 rcDst.bottom = rcDst.top + drawSize.y; 563 *pRect = rcDst; 564 } 565 566 DrawStream.signature = 0x44727753; 567 DrawStream.reserved = 0; 568 DrawStream.unknown1 = 1; 569 DrawStream.unknown2 = 9; 570 DrawStream.hDC = hdc; 571 DrawStream.hImage = bmpSrc; 572 DrawStream.crTransparent = transparentcolor; 573 DrawStream.rcSrc = rcSrc; 574 DrawStream.rcDest = rcDst; 575 DrawStream.leftSizingMargin = sm.cxLeftWidth; 576 DrawStream.rightSizingMargin = sm.cxRightWidth; 577 DrawStream.topSizingMargin = sm.cyTopHeight; 578 DrawStream.bottomSizingMargin = sm.cyBottomHeight; 579 DrawStream.drawOption = 0; 580 581 if (transparent == ALPHABLEND_FULL) 582 DrawStream.drawOption |= DS_TRANSPARENTALPHA; 583 else if (transparent == ALPHABLEND_BINARY) 584 DrawStream.drawOption |= DS_TRANSPARENTCLR; 585 586 if (sizingtype == ST_TILE) 587 DrawStream.drawOption |= DS_TILE; 588 else if (sizingtype == ST_TRUESIZE) 589 DrawStream.drawOption |= DS_TRUESIZE; 590 591 GdiDrawStream(hdc, sizeof(DrawStream), &DrawStream); 592 return HRESULT_FROM_WIN32(GetLastError()); 593 } 594 595 /*********************************************************************** 596 * UXTHEME_DrawBorderRectangle 597 * 598 * Draw the bounding rectangle for a borderfill background 599 */ 600 static HRESULT UXTHEME_DrawBorderRectangle(HTHEME hTheme, HDC hdc, int iPartId, 601 int iStateId, RECT *pRect, 602 const DTBGOPTS *pOptions) 603 { 604 HRESULT hr = S_OK; 605 HPEN hPen; 606 HGDIOBJ oldPen; 607 COLORREF bordercolor = RGB(0,0,0); 608 int bordersize = 1; 609 610 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize); 611 if(bordersize > 0) { 612 POINT ptCorners[5]; 613 ptCorners[0].x = pRect->left; 614 ptCorners[0].y = pRect->top; 615 ptCorners[1].x = pRect->right-1; 616 ptCorners[1].y = pRect->top; 617 ptCorners[2].x = pRect->right-1; 618 ptCorners[2].y = pRect->bottom-1; 619 ptCorners[3].x = pRect->left; 620 ptCorners[3].y = pRect->bottom-1; 621 ptCorners[4].x = pRect->left; 622 ptCorners[4].y = pRect->top; 623 624 InflateRect(pRect, -bordersize, -bordersize); 625 if(pOptions->dwFlags & DTBG_OMITBORDER) 626 return S_OK; 627 GetThemeColor(hTheme, iPartId, iStateId, TMT_BORDERCOLOR, &bordercolor); 628 hPen = CreatePen(PS_SOLID, bordersize, bordercolor); 629 if(!hPen) 630 return HRESULT_FROM_WIN32(GetLastError()); 631 oldPen = SelectObject(hdc, hPen); 632 633 if(!Polyline(hdc, ptCorners, 5)) 634 hr = HRESULT_FROM_WIN32(GetLastError()); 635 636 SelectObject(hdc, oldPen); 637 DeleteObject(hPen); 638 } 639 return hr; 640 } 641 642 /*********************************************************************** 643 * UXTHEME_DrawBackgroundFill 644 * 645 * Fill a borderfill background rectangle 646 */ 647 static HRESULT UXTHEME_DrawBackgroundFill(HTHEME hTheme, HDC hdc, int iPartId, 648 int iStateId, RECT *pRect, 649 const DTBGOPTS *pOptions) 650 { 651 HRESULT hr = S_OK; 652 int filltype = FT_SOLID; 653 654 TRACE("(%d,%d,%d)\n", iPartId, iStateId, pOptions->dwFlags); 655 656 if(pOptions->dwFlags & DTBG_OMITCONTENT) 657 return S_OK; 658 659 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_FILLTYPE, &filltype); 660 661 if(filltype == FT_SOLID) { 662 HBRUSH hBrush; 663 COLORREF fillcolor = RGB(255,255,255); 664 665 GetThemeColor(hTheme, iPartId, iStateId, TMT_FILLCOLOR, &fillcolor); 666 hBrush = CreateSolidBrush(fillcolor); 667 if(!FillRect(hdc, pRect, hBrush)) 668 hr = HRESULT_FROM_WIN32(GetLastError()); 669 DeleteObject(hBrush); 670 } 671 else if(filltype == FT_VERTGRADIENT || filltype == FT_HORZGRADIENT) { 672 /* FIXME: This only accounts for 2 gradient colors (out of 5) and ignores 673 the gradient ratios (no idea how those work) 674 Few themes use this, and the ones I've seen only use 2 colors with 675 a gradient ratio of 0 and 255 respectively 676 */ 677 678 COLORREF gradient1 = RGB(0,0,0); 679 COLORREF gradient2 = RGB(255,255,255); 680 TRIVERTEX vert[2]; 681 GRADIENT_RECT gRect; 682 683 FIXME("Gradient implementation not complete\n"); 684 685 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR1, &gradient1); 686 GetThemeColor(hTheme, iPartId, iStateId, TMT_GRADIENTCOLOR2, &gradient2); 687 688 vert[0].x = pRect->left; 689 vert[0].y = pRect->top; 690 vert[0].Red = GetRValue(gradient1) << 8; 691 vert[0].Green = GetGValue(gradient1) << 8; 692 vert[0].Blue = GetBValue(gradient1) << 8; 693 vert[0].Alpha = 0xff00; 694 695 vert[1].x = pRect->right; 696 vert[1].y = pRect->bottom; 697 vert[1].Red = GetRValue(gradient2) << 8; 698 vert[1].Green = GetGValue(gradient2) << 8; 699 vert[1].Blue = GetBValue(gradient2) << 8; 700 vert[1].Alpha = 0xff00; 701 702 gRect.UpperLeft = 0; 703 gRect.LowerRight = 1; 704 GradientFill(hdc,vert,2,&gRect,1,filltype==FT_HORZGRADIENT?GRADIENT_FILL_RECT_H:GRADIENT_FILL_RECT_V); 705 } 706 else if(filltype == FT_RADIALGRADIENT) { 707 /* I've never seen this used in a theme */ 708 FIXME("Radial gradient\n"); 709 } 710 else if(filltype == FT_TILEIMAGE) { 711 /* I've never seen this used in a theme */ 712 FIXME("Tile image\n"); 713 } 714 return hr; 715 } 716 717 /*********************************************************************** 718 * UXTHEME_DrawBorderBackground 719 * 720 * Draw an imagefile background 721 */ 722 static HRESULT UXTHEME_DrawBorderBackground(HTHEME hTheme, HDC hdc, int iPartId, 723 int iStateId, const RECT *pRect, 724 const DTBGOPTS *pOptions) 725 { 726 HRESULT hr; 727 RECT rt; 728 729 rt = *pRect; 730 731 hr = UXTHEME_DrawBorderRectangle(hTheme, hdc, iPartId, iStateId, &rt, pOptions); 732 if(FAILED(hr)) 733 return hr; 734 return UXTHEME_DrawBackgroundFill(hTheme, hdc, iPartId, iStateId, &rt, pOptions); 735 } 736 737 /*********************************************************************** 738 * DrawThemeBackgroundEx (UXTHEME.@) 739 */ 740 HRESULT WINAPI DrawThemeBackgroundEx(HTHEME hTheme, HDC hdc, int iPartId, 741 int iStateId, const RECT *pRect, 742 const DTBGOPTS *pOptions) 743 { 744 HRESULT hr; 745 const DTBGOPTS defaultOpts = {sizeof(DTBGOPTS), 0, {0,0,0,0}}; 746 const DTBGOPTS *opts; 747 HRGN clip = NULL; 748 int hasClip = -1; 749 int bgtype = BT_BORDERFILL; 750 RECT rt; 751 752 TRACE("(%p,%p,%d,%d,%d,%d)\n", hTheme, hdc, iPartId, iStateId,pRect->left,pRect->top); 753 if(!hTheme) 754 return E_HANDLE; 755 756 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype); 757 if (bgtype == BT_NONE) return S_OK; 758 759 /* Ensure we have a DTBGOPTS structure available, simplifies some of the code */ 760 opts = pOptions; 761 if(!opts) opts = &defaultOpts; 762 763 if(opts->dwFlags & DTBG_CLIPRECT) { 764 clip = CreateRectRgn(0,0,1,1); 765 hasClip = GetClipRgn(hdc, clip); 766 if(hasClip == -1) 767 TRACE("Failed to get original clipping region\n"); 768 else 769 IntersectClipRect(hdc, opts->rcClip.left, opts->rcClip.top, opts->rcClip.right, opts->rcClip.bottom); 770 } 771 rt = *pRect; 772 773 if(bgtype == BT_IMAGEFILE) 774 hr = UXTHEME_DrawImageBackground(hTheme, hdc, iPartId, iStateId, &rt, opts); 775 else if(bgtype == BT_BORDERFILL) 776 hr = UXTHEME_DrawBorderBackground(hTheme, hdc, iPartId, iStateId, pRect, opts); 777 else { 778 FIXME("Unknown background type\n"); 779 /* This should never happen, and hence I don't know what to return */ 780 hr = E_FAIL; 781 } 782 #if 0 783 if(SUCCEEDED(hr)) 784 #endif 785 { 786 RECT rcGlyph = *pRect; 787 MARGINS margin; 788 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin); 789 if(SUCCEEDED(hr)) 790 { 791 rcGlyph.left += margin.cxLeftWidth; 792 rcGlyph.right -= margin.cxRightWidth; 793 rcGlyph.top += margin.cyTopHeight; 794 rcGlyph.bottom -= margin.cyBottomHeight; 795 } 796 hr = UXTHEME_DrawGlyph(hTheme, hdc, iPartId, iStateId, &rcGlyph, opts); 797 } 798 if(opts->dwFlags & DTBG_CLIPRECT) { 799 if(hasClip == 0) 800 SelectClipRgn(hdc, NULL); 801 else if(hasClip == 1) 802 SelectClipRgn(hdc, clip); 803 DeleteObject(clip); 804 } 805 return hr; 806 } 807 808 /* 809 * DrawThemeEdge() implementation 810 * 811 * Since it basically is DrawEdge() with different colors, I copied its code 812 * from user32's uitools.c. 813 */ 814 815 enum 816 { 817 EDGE_LIGHT, 818 EDGE_HIGHLIGHT, 819 EDGE_SHADOW, 820 EDGE_DARKSHADOW, 821 EDGE_FILL, 822 823 EDGE_WINDOW, 824 EDGE_WINDOWFRAME, 825 826 EDGE_NUMCOLORS 827 }; 828 829 static const struct 830 { 831 int themeProp; 832 int sysColor; 833 } EdgeColorMap[EDGE_NUMCOLORS] = { 834 {TMT_EDGELIGHTCOLOR, COLOR_3DLIGHT}, 835 {TMT_EDGEHIGHLIGHTCOLOR, COLOR_BTNHIGHLIGHT}, 836 {TMT_EDGESHADOWCOLOR, COLOR_BTNSHADOW}, 837 {TMT_EDGEDKSHADOWCOLOR, COLOR_3DDKSHADOW}, 838 {TMT_EDGEFILLCOLOR, COLOR_BTNFACE}, 839 {-1, COLOR_WINDOW}, 840 {-1, COLOR_WINDOWFRAME} 841 }; 842 843 static const signed char LTInnerNormal[] = { 844 -1, -1, -1, -1, 845 -1, EDGE_HIGHLIGHT, EDGE_HIGHLIGHT, -1, 846 -1, EDGE_DARKSHADOW, EDGE_DARKSHADOW, -1, 847 -1, -1, -1, -1 848 }; 849 850 static const signed char LTOuterNormal[] = { 851 -1, EDGE_LIGHT, EDGE_SHADOW, -1, 852 EDGE_HIGHLIGHT, EDGE_LIGHT, EDGE_SHADOW, -1, 853 EDGE_DARKSHADOW, EDGE_LIGHT, EDGE_SHADOW, -1, 854 -1, EDGE_LIGHT, EDGE_SHADOW, -1 855 }; 856 857 static const signed char RBInnerNormal[] = { 858 -1, -1, -1, -1, 859 -1, EDGE_SHADOW, EDGE_SHADOW, -1, 860 -1, EDGE_LIGHT, EDGE_LIGHT, -1, 861 -1, -1, -1, -1 862 }; 863 864 static const signed char RBOuterNormal[] = { 865 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1, 866 EDGE_SHADOW, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1, 867 EDGE_LIGHT, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1, 868 -1, EDGE_DARKSHADOW, EDGE_HIGHLIGHT, -1 869 }; 870 871 static const signed char LTInnerSoft[] = { 872 -1, -1, -1, -1, 873 -1, EDGE_LIGHT, EDGE_LIGHT, -1, 874 -1, EDGE_SHADOW, EDGE_SHADOW, -1, 875 -1, -1, -1, -1 876 }; 877 878 static const signed char LTOuterSoft[] = { 879 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1, 880 EDGE_LIGHT, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1, 881 EDGE_SHADOW, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1, 882 -1, EDGE_HIGHLIGHT, EDGE_DARKSHADOW, -1 883 }; 884 885 #define RBInnerSoft RBInnerNormal /* These are the same */ 886 #define RBOuterSoft RBOuterNormal 887 888 static const signed char LTRBOuterMono[] = { 889 -1, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, 890 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, 891 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, 892 EDGE_WINDOW, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, EDGE_WINDOWFRAME, 893 }; 894 895 static const signed char LTRBInnerMono[] = { 896 -1, -1, -1, -1, 897 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW, 898 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW, 899 -1, EDGE_WINDOW, EDGE_WINDOW, EDGE_WINDOW, 900 }; 901 902 static const signed char LTRBOuterFlat[] = { 903 -1, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW, 904 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW, 905 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW, 906 EDGE_FILL, EDGE_SHADOW, EDGE_SHADOW, EDGE_SHADOW, 907 }; 908 909 static const signed char LTRBInnerFlat[] = { 910 -1, -1, -1, -1, 911 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL, 912 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL, 913 -1, EDGE_FILL, EDGE_FILL, EDGE_FILL, 914 }; 915 916 static COLORREF get_edge_color (int edgeType, HTHEME theme, int part, int state) 917 { 918 COLORREF col; 919 if ((EdgeColorMap[edgeType].themeProp == -1) 920 || FAILED (GetThemeColor (theme, part, state, 921 EdgeColorMap[edgeType].themeProp, &col))) 922 col = GetSysColor (EdgeColorMap[edgeType].sysColor); 923 return col; 924 } 925 926 static inline HPEN get_edge_pen (int edgeType, HTHEME theme, int part, int state) 927 { 928 return CreatePen (PS_SOLID, 1, get_edge_color (edgeType, theme, part, state)); 929 } 930 931 static inline HBRUSH get_edge_brush (int edgeType, HTHEME theme, int part, int state) 932 { 933 return CreateSolidBrush (get_edge_color (edgeType, theme, part, state)); 934 } 935 936 /*********************************************************************** 937 * draw_diag_edge 938 * 939 * Same as DrawEdge invoked with BF_DIAGONAL 940 */ 941 static HRESULT draw_diag_edge (HDC hdc, HTHEME theme, int part, int state, 942 const RECT* rc, UINT uType, 943 UINT uFlags, LPRECT contentsRect) 944 { 945 POINT Points[4]; 946 signed char InnerI, OuterI; 947 HPEN InnerPen, OuterPen; 948 POINT SavePoint; 949 HPEN SavePen; 950 int spx, spy; 951 int epx, epy; 952 int Width = rc->right - rc->left; 953 int Height= rc->bottom - rc->top; 954 int SmallDiam = Width > Height ? Height : Width; 955 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER 956 || (uType & BDR_OUTER) == BDR_OUTER) 957 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK; 958 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0) 959 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0); 960 961 /* Init some vars */ 962 OuterPen = InnerPen = GetStockObject(NULL_PEN); 963 SavePen = SelectObject(hdc, InnerPen); 964 spx = spy = epx = epy = 0; /* Satisfy the compiler... */ 965 966 /* Determine the colors of the edges */ 967 if(uFlags & BF_MONO) 968 { 969 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)]; 970 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)]; 971 } 972 else if(uFlags & BF_FLAT) 973 { 974 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)]; 975 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)]; 976 } 977 else if(uFlags & BF_SOFT) 978 { 979 if(uFlags & BF_BOTTOM) 980 { 981 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)]; 982 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)]; 983 } 984 else 985 { 986 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)]; 987 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)]; 988 } 989 } 990 else 991 { 992 if(uFlags & BF_BOTTOM) 993 { 994 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)]; 995 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)]; 996 } 997 else 998 { 999 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)]; 1000 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)]; 1001 } 1002 } 1003 1004 if(InnerI != -1) InnerPen = get_edge_pen (InnerI, theme, part, state); 1005 if(OuterI != -1) OuterPen = get_edge_pen (OuterI, theme, part, state); 1006 1007 MoveToEx(hdc, 0, 0, &SavePoint); 1008 1009 /* Don't ask me why, but this is what is visible... */ 1010 /* This must be possible to do much simpler, but I fail to */ 1011 /* see the logic in the MS implementation (sigh...). */ 1012 /* So, this might look a bit brute force here (and it is), but */ 1013 /* it gets the job done;) */ 1014 1015 switch(uFlags & BF_RECT) 1016 { 1017 case 0: 1018 case BF_LEFT: 1019 case BF_BOTTOM: 1020 case BF_BOTTOMLEFT: 1021 /* Left bottom endpoint */ 1022 epx = rc->left-1; 1023 spx = epx + SmallDiam; 1024 epy = rc->bottom; 1025 spy = epy - SmallDiam; 1026 break; 1027 1028 case BF_TOPLEFT: 1029 case BF_BOTTOMRIGHT: 1030 /* Left top endpoint */ 1031 epx = rc->left-1; 1032 spx = epx + SmallDiam; 1033 epy = rc->top-1; 1034 spy = epy + SmallDiam; 1035 break; 1036 1037 case BF_TOP: 1038 case BF_RIGHT: 1039 case BF_TOPRIGHT: 1040 case BF_RIGHT|BF_LEFT: 1041 case BF_RIGHT|BF_LEFT|BF_TOP: 1042 case BF_BOTTOM|BF_TOP: 1043 case BF_BOTTOM|BF_TOP|BF_LEFT: 1044 case BF_BOTTOMRIGHT|BF_LEFT: 1045 case BF_BOTTOMRIGHT|BF_TOP: 1046 case BF_RECT: 1047 /* Right top endpoint */ 1048 spx = rc->left; 1049 epx = spx + SmallDiam; 1050 spy = rc->bottom-1; 1051 epy = spy - SmallDiam; 1052 break; 1053 } 1054 1055 MoveToEx(hdc, spx, spy, NULL); 1056 SelectObject(hdc, OuterPen); 1057 LineTo(hdc, epx, epy); 1058 1059 SelectObject(hdc, InnerPen); 1060 1061 switch(uFlags & (BF_RECT|BF_DIAGONAL)) 1062 { 1063 case BF_DIAGONAL_ENDBOTTOMLEFT: 1064 case (BF_DIAGONAL|BF_BOTTOM): 1065 case BF_DIAGONAL: 1066 case (BF_DIAGONAL|BF_LEFT): 1067 MoveToEx(hdc, spx-1, spy, NULL); 1068 LineTo(hdc, epx, epy-1); 1069 Points[0].x = spx-add; 1070 Points[0].y = spy; 1071 Points[1].x = rc->left; 1072 Points[1].y = rc->top; 1073 Points[2].x = epx+1; 1074 Points[2].y = epy-1-add; 1075 Points[3] = Points[2]; 1076 break; 1077 1078 case BF_DIAGONAL_ENDBOTTOMRIGHT: 1079 MoveToEx(hdc, spx-1, spy, NULL); 1080 LineTo(hdc, epx, epy+1); 1081 Points[0].x = spx-add; 1082 Points[0].y = spy; 1083 Points[1].x = rc->left; 1084 Points[1].y = rc->bottom-1; 1085 Points[2].x = epx+1; 1086 Points[2].y = epy+1+add; 1087 Points[3] = Points[2]; 1088 break; 1089 1090 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP): 1091 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT): 1092 case BF_DIAGONAL_ENDTOPRIGHT: 1093 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT): 1094 MoveToEx(hdc, spx+1, spy, NULL); 1095 LineTo(hdc, epx, epy+1); 1096 Points[0].x = epx-1; 1097 Points[0].y = epy+1+add; 1098 Points[1].x = rc->right-1; 1099 Points[1].y = rc->top+add; 1100 Points[2].x = rc->right-1; 1101 Points[2].y = rc->bottom-1; 1102 Points[3].x = spx+add; 1103 Points[3].y = spy; 1104 break; 1105 1106 case BF_DIAGONAL_ENDTOPLEFT: 1107 MoveToEx(hdc, spx, spy-1, NULL); 1108 LineTo(hdc, epx+1, epy); 1109 Points[0].x = epx+1+add; 1110 Points[0].y = epy+1; 1111 Points[1].x = rc->right-1; 1112 Points[1].y = rc->top; 1113 Points[2].x = rc->right-1; 1114 Points[2].y = rc->bottom-1-add; 1115 Points[3].x = spx; 1116 Points[3].y = spy-add; 1117 break; 1118 1119 case (BF_DIAGONAL|BF_TOP): 1120 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP): 1121 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT): 1122 MoveToEx(hdc, spx+1, spy-1, NULL); 1123 LineTo(hdc, epx, epy); 1124 Points[0].x = epx-1; 1125 Points[0].y = epy+1; 1126 Points[1].x = rc->right-1; 1127 Points[1].y = rc->top; 1128 Points[2].x = rc->right-1; 1129 Points[2].y = rc->bottom-1-add; 1130 Points[3].x = spx+add; 1131 Points[3].y = spy-add; 1132 break; 1133 1134 case (BF_DIAGONAL|BF_RIGHT): 1135 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT): 1136 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM): 1137 MoveToEx(hdc, spx, spy, NULL); 1138 LineTo(hdc, epx-1, epy+1); 1139 Points[0].x = spx; 1140 Points[0].y = spy; 1141 Points[1].x = rc->left; 1142 Points[1].y = rc->top+add; 1143 Points[2].x = epx-1-add; 1144 Points[2].y = epy+1+add; 1145 Points[3] = Points[2]; 1146 break; 1147 } 1148 1149 /* Fill the interior if asked */ 1150 if((uFlags & BF_MIDDLE) && retval) 1151 { 1152 HBRUSH hbsave; 1153 HBRUSH hb = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL, 1154 theme, part, state); 1155 HPEN hpsave; 1156 HPEN hp = get_edge_pen ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL, 1157 theme, part, state); 1158 hbsave = SelectObject(hdc, hb); 1159 hpsave = SelectObject(hdc, hp); 1160 Polygon(hdc, Points, 4); 1161 SelectObject(hdc, hbsave); 1162 SelectObject(hdc, hpsave); 1163 DeleteObject (hp); 1164 DeleteObject (hb); 1165 } 1166 1167 /* Adjust rectangle if asked */ 1168 if(uFlags & BF_ADJUST) 1169 { 1170 *contentsRect = *rc; 1171 if(uFlags & BF_LEFT) contentsRect->left += add; 1172 if(uFlags & BF_RIGHT) contentsRect->right -= add; 1173 if(uFlags & BF_TOP) contentsRect->top += add; 1174 if(uFlags & BF_BOTTOM) contentsRect->bottom -= add; 1175 } 1176 1177 /* Cleanup */ 1178 SelectObject(hdc, SavePen); 1179 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL); 1180 if(InnerI != -1) DeleteObject (InnerPen); 1181 if(OuterI != -1) DeleteObject (OuterPen); 1182 1183 return retval; 1184 } 1185 1186 /*********************************************************************** 1187 * draw_rect_edge 1188 * 1189 * Same as DrawEdge invoked without BF_DIAGONAL 1190 */ 1191 static HRESULT draw_rect_edge (HDC hdc, HTHEME theme, int part, int state, 1192 const RECT* rc, UINT uType, 1193 UINT uFlags, LPRECT contentsRect) 1194 { 1195 signed char LTInnerI, LTOuterI; 1196 signed char RBInnerI, RBOuterI; 1197 HPEN LTInnerPen, LTOuterPen; 1198 HPEN RBInnerPen, RBOuterPen; 1199 RECT InnerRect = *rc; 1200 POINT SavePoint; 1201 HPEN SavePen; 1202 int LBpenplus = 0; 1203 int LTpenplus = 0; 1204 int RTpenplus = 0; 1205 int RBpenplus = 0; 1206 HRESULT retval = (((uType & BDR_INNER) == BDR_INNER 1207 || (uType & BDR_OUTER) == BDR_OUTER) 1208 && !(uFlags & (BF_FLAT|BF_MONO)) ) ? E_FAIL : S_OK; 1209 1210 /* Init some vars */ 1211 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = GetStockObject(NULL_PEN); 1212 SavePen = SelectObject(hdc, LTInnerPen); 1213 1214 /* Determine the colors of the edges */ 1215 if(uFlags & BF_MONO) 1216 { 1217 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)]; 1218 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)]; 1219 } 1220 else if(uFlags & BF_FLAT) 1221 { 1222 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)]; 1223 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)]; 1224 1225 if( LTInnerI != -1 ) LTInnerI = RBInnerI = EDGE_FILL; 1226 } 1227 else if(uFlags & BF_SOFT) 1228 { 1229 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)]; 1230 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)]; 1231 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)]; 1232 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)]; 1233 } 1234 else 1235 { 1236 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)]; 1237 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)]; 1238 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)]; 1239 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)]; 1240 } 1241 1242 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1; 1243 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1; 1244 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1; 1245 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1; 1246 1247 if(LTInnerI != -1) LTInnerPen = get_edge_pen (LTInnerI, theme, part, state); 1248 if(LTOuterI != -1) LTOuterPen = get_edge_pen (LTOuterI, theme, part, state); 1249 if(RBInnerI != -1) RBInnerPen = get_edge_pen (RBInnerI, theme, part, state); 1250 if(RBOuterI != -1) RBOuterPen = get_edge_pen (RBOuterI, theme, part, state); 1251 1252 MoveToEx(hdc, 0, 0, &SavePoint); 1253 1254 /* Draw the outer edge */ 1255 SelectObject(hdc, LTOuterPen); 1256 if(uFlags & BF_TOP) 1257 { 1258 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL); 1259 LineTo(hdc, InnerRect.right, InnerRect.top); 1260 } 1261 if(uFlags & BF_LEFT) 1262 { 1263 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL); 1264 LineTo(hdc, InnerRect.left, InnerRect.bottom); 1265 } 1266 SelectObject(hdc, RBOuterPen); 1267 if(uFlags & BF_BOTTOM) 1268 { 1269 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL); 1270 LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1); 1271 } 1272 if(uFlags & BF_RIGHT) 1273 { 1274 MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL); 1275 LineTo(hdc, InnerRect.right-1, InnerRect.top-1); 1276 } 1277 1278 /* Draw the inner edge */ 1279 SelectObject(hdc, LTInnerPen); 1280 if(uFlags & BF_TOP) 1281 { 1282 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL); 1283 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1); 1284 } 1285 if(uFlags & BF_LEFT) 1286 { 1287 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL); 1288 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus); 1289 } 1290 SelectObject(hdc, RBInnerPen); 1291 if(uFlags & BF_BOTTOM) 1292 { 1293 MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL); 1294 LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2); 1295 } 1296 if(uFlags & BF_RIGHT) 1297 { 1298 MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL); 1299 LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus); 1300 } 1301 1302 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) ) 1303 { 1304 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0) 1305 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0); 1306 1307 if(uFlags & BF_LEFT) InnerRect.left += add; 1308 if(uFlags & BF_RIGHT) InnerRect.right -= add; 1309 if(uFlags & BF_TOP) InnerRect.top += add; 1310 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add; 1311 1312 if((uFlags & BF_MIDDLE) && retval) 1313 { 1314 HBRUSH br = get_edge_brush ((uFlags & BF_MONO) ? EDGE_WINDOW : EDGE_FILL, 1315 theme, part, state); 1316 FillRect(hdc, &InnerRect, br); 1317 DeleteObject (br); 1318 } 1319 1320 if(uFlags & BF_ADJUST) 1321 *contentsRect = InnerRect; 1322 } 1323 1324 /* Cleanup */ 1325 SelectObject(hdc, SavePen); 1326 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL); 1327 if(LTInnerI != -1) DeleteObject (LTInnerPen); 1328 if(LTOuterI != -1) DeleteObject (LTOuterPen); 1329 if(RBInnerI != -1) DeleteObject (RBInnerPen); 1330 if(RBOuterI != -1) DeleteObject (RBOuterPen); 1331 return retval; 1332 } 1333 1334 1335 /*********************************************************************** 1336 * DrawThemeEdge (UXTHEME.@) 1337 * 1338 * DrawThemeEdge() is pretty similar to the vanilla DrawEdge() - the 1339 * difference is that it does not rely on the system colors alone, but 1340 * also allows color specification in the theme. 1341 */ 1342 HRESULT WINAPI DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId, 1343 int iStateId, const RECT *pDestRect, UINT uEdge, 1344 UINT uFlags, RECT *pContentRect) 1345 { 1346 TRACE("%d %d 0x%08x 0x%08x\n", iPartId, iStateId, uEdge, uFlags); 1347 if(!hTheme) 1348 return E_HANDLE; 1349 1350 if(uFlags & BF_DIAGONAL) 1351 return draw_diag_edge (hdc, hTheme, iPartId, iStateId, pDestRect, 1352 uEdge, uFlags, pContentRect); 1353 else 1354 return draw_rect_edge (hdc, hTheme, iPartId, iStateId, pDestRect, 1355 uEdge, uFlags, pContentRect); 1356 } 1357 1358 1359 /*********************************************************************** 1360 * DrawThemeIcon (UXTHEME.@) 1361 */ 1362 HRESULT WINAPI DrawThemeIcon(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, 1363 const RECT *pRect, HIMAGELIST himl, int iImageIndex) 1364 { 1365 FIXME("%d %d: stub\n", iPartId, iStateId); 1366 if(!hTheme) 1367 return E_HANDLE; 1368 return E_NOTIMPL; 1369 } 1370 1371 typedef int (WINAPI * DRAWSHADOWTEXT)(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags, 1372 COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset); 1373 1374 /*********************************************************************** 1375 * DrawThemeTextEx (UXTHEME.@) 1376 */ 1377 HRESULT 1378 WINAPI 1379 DrawThemeTextEx( 1380 _In_ HTHEME hTheme, 1381 _In_ HDC hdc, 1382 _In_ int iPartId, 1383 _In_ int iStateId, 1384 _In_ LPCWSTR pszText, 1385 _In_ int iCharCount, 1386 _In_ DWORD dwTextFlags, 1387 _Inout_ LPRECT pRect, 1388 _In_ const DTTOPTS *options 1389 ) 1390 { 1391 HRESULT hr; 1392 HFONT hFont = NULL; 1393 HGDIOBJ oldFont = NULL; 1394 LOGFONTW logfont; 1395 COLORREF textColor; 1396 COLORREF oldTextColor; 1397 COLORREF shadowColor; 1398 POINT ptShadowOffset; 1399 int oldBkMode; 1400 RECT rt; 1401 int iShadowType; 1402 DWORD optFlags; 1403 1404 if(!hTheme) 1405 return E_HANDLE; 1406 if (!options) 1407 return E_NOTIMPL; 1408 1409 optFlags = options->dwFlags; 1410 1411 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont); 1412 if(SUCCEEDED(hr)) 1413 { 1414 hFont = CreateFontIndirectW(&logfont); 1415 if(!hFont) 1416 { 1417 ERR("Failed to create font\n"); 1418 } 1419 } 1420 1421 CopyRect(&rt, pRect); 1422 if(hFont) 1423 oldFont = SelectObject(hdc, hFont); 1424 1425 oldBkMode = SetBkMode(hdc, TRANSPARENT); 1426 1427 if (optFlags & DTT_TEXTCOLOR) 1428 { 1429 textColor = options->crText; 1430 } 1431 else 1432 { 1433 int textColorProp = TMT_TEXTCOLOR; 1434 if (optFlags & DTT_COLORPROP) 1435 textColorProp = options->iColorPropId; 1436 1437 if (FAILED(GetThemeColor(hTheme, iPartId, iStateId, textColorProp, &textColor))) 1438 textColor = GetTextColor(hdc); 1439 } 1440 1441 hr = GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_TEXTSHADOWTYPE, &iShadowType); 1442 if (SUCCEEDED(hr)) 1443 { 1444 hr = GetThemeColor(hTheme, iPartId, iStateId, TMT_TEXTSHADOWCOLOR, &shadowColor); 1445 if (FAILED(hr)) 1446 { 1447 ERR("GetThemeColor failed\n"); 1448 } 1449 1450 hr = GetThemePosition(hTheme, iPartId, iStateId, TMT_TEXTSHADOWOFFSET, &ptShadowOffset); 1451 if (FAILED(hr)) 1452 { 1453 ERR("GetThemePosition failed\n"); 1454 } 1455 1456 if (iShadowType == TST_SINGLE) 1457 { 1458 oldTextColor = SetTextColor(hdc, shadowColor); 1459 OffsetRect(&rt, ptShadowOffset.x, ptShadowOffset.y); 1460 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags); 1461 OffsetRect(&rt, -ptShadowOffset.x, -ptShadowOffset.y); 1462 SetTextColor(hdc, oldTextColor); 1463 } 1464 else if (iShadowType == TST_CONTINUOUS) 1465 { 1466 HANDLE hcomctl32 = GetModuleHandleW(L"comctl32.dll"); 1467 DRAWSHADOWTEXT pDrawShadowText; 1468 if (!hcomctl32) 1469 { 1470 hcomctl32 = LoadLibraryW(L"comctl32.dll"); 1471 if (!hcomctl32) 1472 ERR("Failed to load comctl32\n"); 1473 } 1474 1475 pDrawShadowText = (DRAWSHADOWTEXT)GetProcAddress(hcomctl32, "DrawShadowText"); 1476 if (pDrawShadowText) 1477 { 1478 pDrawShadowText(hdc, pszText, iCharCount, &rt, dwTextFlags, textColor, shadowColor, ptShadowOffset.x, ptShadowOffset.y); 1479 goto cleanup; 1480 } 1481 } 1482 } 1483 1484 oldTextColor = SetTextColor(hdc, textColor); 1485 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags); 1486 SetTextColor(hdc, oldTextColor); 1487 cleanup: 1488 SetBkMode(hdc, oldBkMode); 1489 1490 if(hFont) { 1491 SelectObject(hdc, oldFont); 1492 DeleteObject(hFont); 1493 } 1494 return S_OK; 1495 } 1496 1497 /*********************************************************************** 1498 * DrawThemeText (UXTHEME.@) 1499 */ 1500 HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, 1501 LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, 1502 DWORD dwTextFlags2, const RECT *pRect) 1503 { 1504 DTTOPTS opts = { 0 }; 1505 RECT rt = *pRect; 1506 1507 TRACE("(%p %p %d %d %s:%d 0x%08lx 0x%08lx %p)\n", hTheme, hdc, iPartId, iStateId, 1508 debugstr_wn(pszText, iCharCount), iCharCount, dwTextFlags, dwTextFlags2, pRect); 1509 1510 if (dwTextFlags2 & DTT_GRAYED) 1511 { 1512 opts.dwFlags = DTT_TEXTCOLOR; 1513 opts.crText = GetSysColor(COLOR_GRAYTEXT); 1514 } 1515 opts.dwSize = sizeof(opts); 1516 1517 return DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, &rt, &opts); 1518 } 1519 1520 /*********************************************************************** 1521 * GetThemeBackgroundContentRect (UXTHEME.@) 1522 */ 1523 HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId, 1524 int iStateId, 1525 const RECT *pBoundingRect, 1526 RECT *pContentRect) 1527 { 1528 MARGINS margin; 1529 HRESULT hr; 1530 1531 TRACE("(%d,%d)\n", iPartId, iStateId); 1532 if(!hTheme) 1533 return E_HANDLE; 1534 1535 /* try content margins property... */ 1536 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin); 1537 if(SUCCEEDED(hr)) { 1538 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth; 1539 pContentRect->top = pBoundingRect->top + margin.cyTopHeight; 1540 pContentRect->right = pBoundingRect->right - margin.cxRightWidth; 1541 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight; 1542 } else { 1543 /* otherwise, try to determine content rect from the background type and props */ 1544 int bgtype = BT_BORDERFILL; 1545 *pContentRect = *pBoundingRect; 1546 1547 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype); 1548 if(bgtype == BT_BORDERFILL) { 1549 int bordersize = 1; 1550 1551 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize); 1552 InflateRect(pContentRect, -bordersize, -bordersize); 1553 } else if ((bgtype == BT_IMAGEFILE) 1554 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, 1555 TMT_SIZINGMARGINS, NULL, &margin)))) { 1556 pContentRect->left = pBoundingRect->left + margin.cxLeftWidth; 1557 pContentRect->top = pBoundingRect->top + margin.cyTopHeight; 1558 pContentRect->right = pBoundingRect->right - margin.cxRightWidth; 1559 pContentRect->bottom = pBoundingRect->bottom - margin.cyBottomHeight; 1560 } 1561 /* If nothing was found, leave unchanged */ 1562 } 1563 1564 TRACE("%s\n", wine_dbgstr_rect(pContentRect)); 1565 1566 return S_OK; 1567 } 1568 1569 /*********************************************************************** 1570 * GetThemeBackgroundExtent (UXTHEME.@) 1571 */ 1572 HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId, 1573 int iStateId, const RECT *pContentRect, 1574 RECT *pExtentRect) 1575 { 1576 MARGINS margin; 1577 HRESULT hr; 1578 1579 TRACE("(%d,%d)\n", iPartId, iStateId); 1580 if(!hTheme) 1581 return E_HANDLE; 1582 1583 /* try content margins property... */ 1584 hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margin); 1585 if(SUCCEEDED(hr)) { 1586 pExtentRect->left = pContentRect->left - margin.cxLeftWidth; 1587 pExtentRect->top = pContentRect->top - margin.cyTopHeight; 1588 pExtentRect->right = pContentRect->right + margin.cxRightWidth; 1589 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight; 1590 } else { 1591 /* otherwise, try to determine content rect from the background type and props */ 1592 int bgtype = BT_BORDERFILL; 1593 *pExtentRect = *pContentRect; 1594 1595 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype); 1596 if(bgtype == BT_BORDERFILL) { 1597 int bordersize = 1; 1598 1599 GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, &bordersize); 1600 InflateRect(pExtentRect, bordersize, bordersize); 1601 } else if ((bgtype == BT_IMAGEFILE) 1602 && (SUCCEEDED(hr = GetThemeMargins(hTheme, hdc, iPartId, iStateId, 1603 TMT_SIZINGMARGINS, NULL, &margin)))) { 1604 pExtentRect->left = pContentRect->left - margin.cxLeftWidth; 1605 pExtentRect->top = pContentRect->top - margin.cyTopHeight; 1606 pExtentRect->right = pContentRect->right + margin.cxRightWidth; 1607 pExtentRect->bottom = pContentRect->bottom + margin.cyBottomHeight; 1608 } 1609 /* If nothing was found, leave unchanged */ 1610 } 1611 1612 TRACE("%s\n", wine_dbgstr_rect(pExtentRect)); 1613 1614 return S_OK; 1615 } 1616 1617 1618 static HBITMAP UXTHEME_DrawThemePartToDib(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect) 1619 { 1620 HDC hdcMem; 1621 BITMAPINFO bmi; 1622 HBITMAP hbmp, hbmpOld; 1623 HBRUSH hbrBack; 1624 1625 hdcMem = CreateCompatibleDC(0); 1626 1627 memset(&bmi, 0, sizeof(bmi)); 1628 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); 1629 bmi.bmiHeader.biWidth = pRect->right; 1630 bmi.bmiHeader.biHeight = -pRect->bottom; 1631 bmi.bmiHeader.biPlanes = 1; 1632 bmi.bmiHeader.biBitCount = 32; 1633 hbmp = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS , NULL, 0, 0); 1634 1635 hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp); 1636 1637 /* FIXME: use an internal function that doesn't do transparent blt */ 1638 hbrBack = CreateSolidBrush(RGB(255,0,255)); 1639 1640 FillRect(hdcMem, pRect, hbrBack); 1641 1642 DrawThemeBackground(hTheme, hdcMem, iPartId, iStateId, pRect, NULL); 1643 1644 DeleteObject(hbrBack); 1645 SelectObject(hdcMem, hbmpOld); 1646 DeleteObject(hdcMem); 1647 1648 return hbmp; 1649 } 1650 1651 #define PT_IN_RECT(lprc,x,y) ( x >= lprc->left && x < lprc->right && \ 1652 y >= lprc->top && y < lprc->bottom) 1653 1654 static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent, LPCRECT pRect) 1655 { 1656 int x, y, xstart; 1657 int cMaxRgnRects, cRgnDataSize, cRgnRects; 1658 RECT* prcCurrent; 1659 PRGNDATA prgnData; 1660 ULONG clrTransparent, *pclrCurrent; 1661 HRGN hrgnRet; 1662 1663 pclrCurrent = (PULONG)pBuffer; 1664 clrTransparent = *(PULONG)pclrTransparent; 1665 1666 /* Create a region and pre-allocate memory enough for 3 spaces in one row*/ 1667 cRgnRects = 0; 1668 cMaxRgnRects = 4* (pRect->bottom-pRect->top); 1669 cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT); 1670 1671 /* Allocate the region data */ 1672 prgnData = (PRGNDATA)HeapAlloc(GetProcessHeap(), 0, cRgnDataSize); 1673 1674 prcCurrent = (PRECT)prgnData->Buffer; 1675 1676 /* Calculate the region rects */ 1677 y=0; 1678 /* Scan each line of the bitmap */ 1679 while(y<pRect->bottom) 1680 { 1681 x=0; 1682 /* Scan each pixel */ 1683 while (x<pRect->right) 1684 { 1685 /* Check if the pixel is not transparent and it is in the requested rect */ 1686 if(*pclrCurrent != clrTransparent && PT_IN_RECT(pRect,x,y)) 1687 { 1688 xstart = x; 1689 /* Find the end of the opaque row of pixels */ 1690 while (x<pRect->right) 1691 { 1692 if(*pclrCurrent == clrTransparent || !PT_IN_RECT(pRect,x,y)) 1693 break; 1694 x++; 1695 pclrCurrent++; 1696 } 1697 1698 /* Add the scaned line to the region */ 1699 SetRect(prcCurrent, xstart, y,x,y+1); 1700 prcCurrent++; 1701 cRgnRects++; 1702 1703 /* Increase the size of the buffer if it is full */ 1704 if(cRgnRects == cMaxRgnRects) 1705 { 1706 cMaxRgnRects *=2; 1707 cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT); 1708 prgnData = (PRGNDATA)HeapReAlloc(GetProcessHeap(), 1709 0, 1710 prgnData, 1711 cRgnDataSize); 1712 prcCurrent = (RECT*)prgnData->Buffer + cRgnRects; 1713 } 1714 } 1715 else 1716 { 1717 x++; 1718 pclrCurrent++; 1719 } 1720 } 1721 y++; 1722 } 1723 1724 /* Fill the region data header */ 1725 prgnData->rdh.dwSize = sizeof(prgnData->rdh); 1726 prgnData->rdh.iType = RDH_RECTANGLES; 1727 prgnData->rdh.nCount = cRgnRects; 1728 prgnData->rdh.nRgnSize = cRgnDataSize; 1729 prgnData->rdh.rcBound = *pRect; 1730 1731 /* Create the region*/ 1732 hrgnRet = ExtCreateRegion (NULL, cRgnDataSize, prgnData); 1733 1734 /* Free the region data*/ 1735 HeapFree(GetProcessHeap(),0,prgnData); 1736 1737 /* return the region*/ 1738 return hrgnRet; 1739 } 1740 1741 HRESULT UXTHEME_GetImageBackBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, HRGN *pRegion) 1742 { 1743 HBITMAP hbmp; 1744 DIBSECTION dib; 1745 RGBQUAD clrTransparent = {0xFF,0x0, 0xFF,0x0}; 1746 1747 /* Draw the theme part to a dib */ 1748 hbmp = UXTHEME_DrawThemePartToDib(hTheme, hdc, iPartId, iStateId, pRect); 1749 1750 /* Retrieve the info of the dib section */ 1751 GetObjectW(hbmp, sizeof (DIBSECTION), &dib); 1752 1753 /* Convert the bits of the dib section to a region */ 1754 *pRegion = UXTHEME_RegionFromDibBits((RGBQUAD*)dib.dsBm.bmBits, &clrTransparent, pRect); 1755 1756 /* Free the temp bitmap */ 1757 DeleteObject(hbmp); 1758 1759 return S_OK; 1760 } 1761 1762 /*********************************************************************** 1763 * GetThemeBackgroundRegion (UXTHEME.@) 1764 * 1765 * Calculate the background region, taking into consideration transparent areas 1766 * of the background image. 1767 */ 1768 HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId, 1769 int iStateId, const RECT *pRect, 1770 HRGN *pRegion) 1771 { 1772 HRESULT hr = S_OK; 1773 int bgtype = BT_BORDERFILL; 1774 1775 TRACE("(%p,%p,%d,%d)\n", hTheme, hdc, iPartId, iStateId); 1776 if(!hTheme) 1777 return E_HANDLE; 1778 if(!pRect || !pRegion) 1779 return E_POINTER; 1780 1781 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype); 1782 if(bgtype == BT_IMAGEFILE) { 1783 hr = UXTHEME_GetImageBackBackgroundRegion(hTheme, hdc, iPartId, iStateId, pRect, pRegion); 1784 } 1785 else if(bgtype == BT_BORDERFILL) { 1786 *pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom); 1787 if(!*pRegion) 1788 hr = HRESULT_FROM_WIN32(GetLastError()); 1789 } 1790 else { 1791 FIXME("Unknown background type\n"); 1792 /* This should never happen, and hence I don't know what to return */ 1793 hr = E_FAIL; 1794 } 1795 return hr; 1796 } 1797 1798 /* compute part size for "borderfill" backgrounds */ 1799 static HRESULT get_border_background_size (HTHEME hTheme, int iPartId, 1800 int iStateId, THEMESIZE eSize, POINT* psz) 1801 { 1802 HRESULT hr = S_OK; 1803 int bordersize = 1; 1804 1805 if (SUCCEEDED (hr = GetThemeInt(hTheme, iPartId, iStateId, TMT_BORDERSIZE, 1806 &bordersize))) 1807 { 1808 psz->x = psz->y = 2*bordersize; 1809 if (eSize != TS_MIN) 1810 { 1811 psz->x++; 1812 psz->y++; 1813 } 1814 } 1815 return hr; 1816 } 1817 1818 /*********************************************************************** 1819 * GetThemePartSize (UXTHEME.@) 1820 */ 1821 HRESULT WINAPI GetThemePartSize(HTHEME hTheme, HDC hdc, int iPartId, 1822 int iStateId, RECT *prc, THEMESIZE eSize, 1823 SIZE *psz) 1824 { 1825 int bgtype = BT_BORDERFILL; 1826 HRESULT hr = S_OK; 1827 POINT size = {1, 1}; 1828 1829 if(!hTheme) 1830 return E_HANDLE; 1831 1832 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype); 1833 if (bgtype == BT_NONE) 1834 /* do nothing */; 1835 else if(bgtype == BT_IMAGEFILE) 1836 hr = get_image_part_size (hTheme, hdc, iPartId, iStateId, prc, eSize, &size); 1837 else if(bgtype == BT_BORDERFILL) 1838 hr = get_border_background_size (hTheme, iPartId, iStateId, eSize, &size); 1839 else { 1840 FIXME("Unknown background type\n"); 1841 /* This should never happen, and hence I don't know what to return */ 1842 hr = E_FAIL; 1843 } 1844 psz->cx = size.x; 1845 psz->cy = size.y; 1846 return hr; 1847 } 1848 1849 1850 /*********************************************************************** 1851 * GetThemeTextExtent (UXTHEME.@) 1852 */ 1853 HRESULT WINAPI GetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId, 1854 int iStateId, LPCWSTR pszText, int iCharCount, 1855 DWORD dwTextFlags, const RECT *pBoundingRect, 1856 RECT *pExtentRect) 1857 { 1858 HRESULT hr; 1859 HFONT hFont = NULL; 1860 HGDIOBJ oldFont = NULL; 1861 LOGFONTW logfont; 1862 RECT rt = {0,0,0xFFFF,0xFFFF}; 1863 1864 TRACE("%d %d: stub\n", iPartId, iStateId); 1865 if(!hTheme) 1866 return E_HANDLE; 1867 1868 if(pBoundingRect) 1869 rt = *pBoundingRect; 1870 1871 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont); 1872 if(SUCCEEDED(hr)) { 1873 hFont = CreateFontIndirectW(&logfont); 1874 if(!hFont) 1875 TRACE("Failed to create font\n"); 1876 } 1877 if(hFont) 1878 oldFont = SelectObject(hdc, hFont); 1879 1880 DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags|DT_CALCRECT); 1881 *pExtentRect = rt; 1882 1883 if(hFont) { 1884 SelectObject(hdc, oldFont); 1885 DeleteObject(hFont); 1886 } 1887 return S_OK; 1888 } 1889 1890 /*********************************************************************** 1891 * GetThemeTextMetrics (UXTHEME.@) 1892 */ 1893 HRESULT WINAPI GetThemeTextMetrics(HTHEME hTheme, HDC hdc, int iPartId, 1894 int iStateId, TEXTMETRICW *ptm) 1895 { 1896 HRESULT hr; 1897 HFONT hFont = NULL; 1898 HGDIOBJ oldFont = NULL; 1899 LOGFONTW logfont; 1900 1901 TRACE("(%p, %p, %d, %d)\n", hTheme, hdc, iPartId, iStateId); 1902 if(!hTheme) 1903 return E_HANDLE; 1904 1905 hr = GetThemeFont(hTheme, hdc, iPartId, iStateId, TMT_FONT, &logfont); 1906 if(SUCCEEDED(hr)) { 1907 hFont = CreateFontIndirectW(&logfont); 1908 if(!hFont) 1909 TRACE("Failed to create font\n"); 1910 } 1911 if(hFont) 1912 oldFont = SelectObject(hdc, hFont); 1913 1914 if(!GetTextMetricsW(hdc, ptm)) 1915 hr = HRESULT_FROM_WIN32(GetLastError()); 1916 1917 if(hFont) { 1918 SelectObject(hdc, oldFont); 1919 DeleteObject(hFont); 1920 } 1921 return hr; 1922 } 1923 1924 /*********************************************************************** 1925 * IsThemeBackgroundPartiallyTransparent (UXTHEME.@) 1926 */ 1927 BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId, 1928 int iStateId) 1929 { 1930 int bgtype = BT_BORDERFILL; 1931 RECT rect = {0, 0, 0, 0}; 1932 HBITMAP bmpSrc; 1933 RECT rcSrc; 1934 BOOL hasAlpha; 1935 INT transparent; 1936 COLORREF transparentcolor; 1937 1938 TRACE("(%d,%d)\n", iPartId, iStateId); 1939 1940 if(!hTheme) 1941 return FALSE; 1942 1943 GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype); 1944 1945 #ifdef __REACTOS__ 1946 if (bgtype == BT_NONE) return TRUE; 1947 #endif 1948 if (bgtype != BT_IMAGEFILE) return FALSE; 1949 1950 if(FAILED (UXTHEME_LoadImage (hTheme, 0, iPartId, iStateId, &rect, FALSE, 1951 &bmpSrc, &rcSrc, &hasAlpha))) 1952 return FALSE; 1953 1954 get_transparency (hTheme, iPartId, iStateId, hasAlpha, &transparent, 1955 &transparentcolor, FALSE); 1956 return (transparent != ALPHABLEND_NONE); 1957 } 1958