~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/uxtheme/draw.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.