user32: Fix LoadImage behavior with zero size and no LR_DEFAULTSIZE.
[wine] / dlls / user32 / uitools.c
1 /*
2  * User Interface Functions
3  *
4  * Copyright 1997 Dimitrie O. Paun
5  * Copyright 1997 Bertho A. Stultiens
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "user_private.h"
29 #include "controls.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(graphics);
34
35 /* These tables are used in:
36  * UITOOLS_DrawDiagEdge()
37  * UITOOLS_DrawRectEdge()
38  */
39 static const signed char LTInnerNormal[] = {
40     -1,           -1,                 -1,                 -1,
41     -1,           COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
42     -1,           COLOR_3DDKSHADOW,   COLOR_3DDKSHADOW,   -1,
43     -1,           -1,                 -1,                 -1
44 };
45
46 static const signed char LTOuterNormal[] = {
47     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
48     COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
49     COLOR_3DDKSHADOW,   COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
50     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1
51 };
52
53 static const signed char RBInnerNormal[] = {
54     -1,           -1,                -1,              -1,
55     -1,           COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
56     -1,           COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
57     -1,           -1,                -1,              -1
58 };
59
60 static const signed char RBOuterNormal[] = {
61     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
62     COLOR_BTNSHADOW, COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
63     COLOR_3DLIGHT,   COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
64     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1
65 };
66
67 static const signed char LTInnerSoft[] = {
68     -1,                  -1,                -1,              -1,
69     -1,                  COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
70     -1,                  COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
71     -1,                  -1,                -1,              -1
72 };
73
74 static const signed char LTOuterSoft[] = {
75     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
76     COLOR_3DLIGHT,   COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
77     COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
78     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
79 };
80
81 #define RBInnerSoft RBInnerNormal   /* These are the same */
82 #define RBOuterSoft RBOuterNormal
83
84 static const signed char LTRBOuterMono[] = {
85     -1,           COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
86     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
87     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
88     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
89 };
90
91 static const signed char LTRBInnerMono[] = {
92     -1, -1,           -1,           -1,
93     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
94     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
95     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
96 };
97
98 static const signed char LTRBOuterFlat[] = {
99     -1,                COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
100     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
101     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
102     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
103 };
104
105 static const signed char LTRBInnerFlat[] = {
106     -1, -1,              -1,              -1,
107     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
108     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
109     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
110 };
111
112 /* last COLOR id */
113 #define COLOR_MAX   COLOR_MENUBAR
114
115
116 /***********************************************************************
117  *           set_control_clipping
118  *
119  * Set clipping for a builtin control that uses CS_PARENTDC.
120  * Return the previous clip region if any.
121  */
122 HRGN set_control_clipping( HDC hdc, const RECT *rect )
123 {
124     RECT rc = *rect;
125     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
126
127     if (GetClipRgn( hdc, hrgn ) != 1)
128     {
129         DeleteObject( hrgn );
130         hrgn = 0;
131     }
132     DPtoLP( hdc, (POINT *)&rc, 2 );
133     if (GetLayout( hdc ) & LAYOUT_RTL)  /* compensate for the shifting done by IntersectClipRect */
134     {
135         rc.left++;
136         rc.right++;
137     }
138     IntersectClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom );
139     return hrgn;
140 }
141
142 /***********************************************************************
143  *           UITOOLS_DrawDiagEdge
144  *
145  * Same as DrawEdge invoked with BF_DIAGONAL
146  *
147  * 03-Dec-1997: Changed by Bertho Stultiens
148  *
149  * See also comments with UITOOLS_DrawRectEdge()
150  */
151 static BOOL UITOOLS95_DrawDiagEdge(HDC hdc, LPRECT rc,
152                                      UINT uType, UINT uFlags)
153 {
154     POINT Points[4];
155     signed char InnerI, OuterI;
156     HPEN InnerPen, OuterPen;
157     POINT SavePoint;
158     HPEN SavePen;
159     int spx, spy;
160     int epx, epy;
161     int Width = rc->right - rc->left;
162     int Height= rc->bottom - rc->top;
163     int SmallDiam = Width > Height ? Height : Width;
164     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
165                        || (uType & BDR_OUTER) == BDR_OUTER)
166                       && !(uFlags & (BF_FLAT|BF_MONO)) );
167     int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
168             + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
169
170     /* Init some vars */
171     OuterPen = InnerPen = GetStockObject(NULL_PEN);
172     SavePen = SelectObject(hdc, InnerPen);
173     spx = spy = epx = epy = 0; /* Satisfy the compiler... */
174
175     /* Determine the colors of the edges */
176     if(uFlags & BF_MONO)
177     {
178         InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
179         OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
180     }
181     else if(uFlags & BF_FLAT)
182     {
183         InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
184         OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
185     }
186     else if(uFlags & BF_SOFT)
187     {
188         if(uFlags & BF_BOTTOM)
189         {
190             InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
191             OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
192         }
193         else
194         {
195             InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
196             OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
197         }
198     }
199     else
200     {
201         if(uFlags & BF_BOTTOM)
202         {
203             InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
204             OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
205         }
206         else
207         {
208             InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
209             OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
210         }
211     }
212
213     if(InnerI != -1) InnerPen = SYSCOLOR_GetPen(InnerI);
214     if(OuterI != -1) OuterPen = SYSCOLOR_GetPen(OuterI);
215
216     MoveToEx(hdc, 0, 0, &SavePoint);
217
218     /* Don't ask me why, but this is what is visible... */
219     /* This must be possible to do much simpler, but I fail to */
220     /* see the logic in the MS implementation (sigh...). */
221     /* So, this might look a bit brute force here (and it is), but */
222     /* it gets the job done;) */
223
224     switch(uFlags & BF_RECT)
225     {
226     case 0:
227     case BF_LEFT:
228     case BF_BOTTOM:
229     case BF_BOTTOMLEFT:
230         /* Left bottom endpoint */
231         epx = rc->left-1;
232         spx = epx + SmallDiam;
233         epy = rc->bottom;
234         spy = epy - SmallDiam;
235         break;
236
237     case BF_TOPLEFT:
238     case BF_BOTTOMRIGHT:
239         /* Left top endpoint */
240         epx = rc->left-1;
241         spx = epx + SmallDiam;
242         epy = rc->top-1;
243         spy = epy + SmallDiam;
244         break;
245
246     case BF_TOP:
247     case BF_RIGHT:
248     case BF_TOPRIGHT:
249     case BF_RIGHT|BF_LEFT:
250     case BF_RIGHT|BF_LEFT|BF_TOP:
251     case BF_BOTTOM|BF_TOP:
252     case BF_BOTTOM|BF_TOP|BF_LEFT:
253     case BF_BOTTOMRIGHT|BF_LEFT:
254     case BF_BOTTOMRIGHT|BF_TOP:
255     case BF_RECT:
256         /* Right top endpoint */
257         spx = rc->left;
258         epx = spx + SmallDiam;
259         spy = rc->bottom-1;
260         epy = spy - SmallDiam;
261         break;
262     }
263
264     MoveToEx(hdc, spx, spy, NULL);
265     SelectObject(hdc, OuterPen);
266     LineTo(hdc, epx, epy);
267
268     SelectObject(hdc, InnerPen);
269
270     switch(uFlags & (BF_RECT|BF_DIAGONAL))
271     {
272     case BF_DIAGONAL_ENDBOTTOMLEFT:
273     case (BF_DIAGONAL|BF_BOTTOM):
274     case BF_DIAGONAL:
275     case (BF_DIAGONAL|BF_LEFT):
276         MoveToEx(hdc, spx-1, spy, NULL);
277         LineTo(hdc, epx, epy-1);
278         Points[0].x = spx-add;
279         Points[0].y = spy;
280         Points[1].x = rc->left;
281         Points[1].y = rc->top;
282         Points[2].x = epx+1;
283         Points[2].y = epy-1-add;
284         Points[3] = Points[2];
285         break;
286
287     case BF_DIAGONAL_ENDBOTTOMRIGHT:
288         MoveToEx(hdc, spx-1, spy, NULL);
289         LineTo(hdc, epx, epy+1);
290         Points[0].x = spx-add;
291         Points[0].y = spy;
292         Points[1].x = rc->left;
293         Points[1].y = rc->bottom-1;
294         Points[2].x = epx+1;
295         Points[2].y = epy+1+add;
296         Points[3] = Points[2];
297         break;
298
299     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
300     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
301     case BF_DIAGONAL_ENDTOPRIGHT:
302     case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
303         MoveToEx(hdc, spx+1, spy, NULL);
304         LineTo(hdc, epx, epy+1);
305         Points[0].x = epx-1;
306         Points[0].y = epy+1+add;
307         Points[1].x = rc->right-1;
308         Points[1].y = rc->top+add;
309         Points[2].x = rc->right-1;
310         Points[2].y = rc->bottom-1;
311         Points[3].x = spx+add;
312         Points[3].y = spy;
313         break;
314
315     case BF_DIAGONAL_ENDTOPLEFT:
316         MoveToEx(hdc, spx, spy-1, NULL);
317         LineTo(hdc, epx+1, epy);
318         Points[0].x = epx+1+add;
319         Points[0].y = epy+1;
320         Points[1].x = rc->right-1;
321         Points[1].y = rc->top;
322         Points[2].x = rc->right-1;
323         Points[2].y = rc->bottom-1-add;
324         Points[3].x = spx;
325         Points[3].y = spy-add;
326         break;
327
328     case (BF_DIAGONAL|BF_TOP):
329     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
330     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
331         MoveToEx(hdc, spx+1, spy-1, NULL);
332         LineTo(hdc, epx, epy);
333         Points[0].x = epx-1;
334         Points[0].y = epy+1;
335         Points[1].x = rc->right-1;
336         Points[1].y = rc->top;
337         Points[2].x = rc->right-1;
338         Points[2].y = rc->bottom-1-add;
339         Points[3].x = spx+add;
340         Points[3].y = spy-add;
341         break;
342
343     case (BF_DIAGONAL|BF_RIGHT):
344     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
345     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
346         MoveToEx(hdc, spx, spy, NULL);
347         LineTo(hdc, epx-1, epy+1);
348         Points[0].x = spx;
349         Points[0].y = spy;
350         Points[1].x = rc->left;
351         Points[1].y = rc->top+add;
352         Points[2].x = epx-1-add;
353         Points[2].y = epy+1+add;
354         Points[3] = Points[2];
355         break;
356     }
357
358     /* Fill the interior if asked */
359     if((uFlags & BF_MIDDLE) && retval)
360     {
361         HBRUSH hbsave;
362         HBRUSH hb = GetSysColorBrush(uFlags & BF_MONO ? COLOR_WINDOW
363                                          :COLOR_BTNFACE);
364         HPEN hpsave;
365         HPEN hp = SYSCOLOR_GetPen(uFlags & BF_MONO ? COLOR_WINDOW
366                                      : COLOR_BTNFACE);
367         hbsave = SelectObject(hdc, hb);
368         hpsave = SelectObject(hdc, hp);
369         Polygon(hdc, Points, 4);
370         SelectObject(hdc, hbsave);
371         SelectObject(hdc, hpsave);
372     }
373
374     /* Adjust rectangle if asked */
375     if(uFlags & BF_ADJUST)
376     {
377         if(uFlags & BF_LEFT)   rc->left   += add;
378         if(uFlags & BF_RIGHT)  rc->right  -= add;
379         if(uFlags & BF_TOP)    rc->top    += add;
380         if(uFlags & BF_BOTTOM) rc->bottom -= add;
381     }
382
383     /* Cleanup */
384     SelectObject(hdc, SavePen);
385     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
386
387     return retval;
388 }
389
390 /***********************************************************************
391  *           UITOOLS_DrawRectEdge
392  *
393  * Same as DrawEdge invoked without BF_DIAGONAL
394  *
395  * 23-Nov-1997: Changed by Bertho Stultiens
396  *
397  * Well, I started testing this and found out that there are a few things
398  * that weren't quite as win95. The following rewrite should reproduce
399  * win95 results completely.
400  * The colorselection is table-driven to avoid awful if-statements.
401  * The table below show the color settings.
402  *
403  * Pen selection table for uFlags = 0
404  *
405  * uType |  LTI  |  LTO  |  RBI  |  RBO
406  * ------+-------+-------+-------+-------
407  *  0000 |   x   |   x   |   x   |   x
408  *  0001 |   x   |  22   |   x   |  21
409  *  0010 |   x   |  16   |   x   |  20
410  *  0011 |   x   |   x   |   x   |   x
411  * ------+-------+-------+-------+-------
412  *  0100 |   x   |  20   |   x   |  16
413  *  0101 |  20   |  22   |  16   |  21
414  *  0110 |  20   |  16   |  16   |  20
415  *  0111 |   x   |   x   |   x   |   x
416  * ------+-------+-------+-------+-------
417  *  1000 |   x   |  21   |   x   |  22
418  *  1001 |  21   |  22   |  22   |  21
419  *  1010 |  21   |  16   |  22   |  20
420  *  1011 |   x   |   x   |   x   |   x
421  * ------+-------+-------+-------+-------
422  *  1100 |   x   |   x   |   x   |   x
423  *  1101 |   x   | x (22)|   x   | x (21)
424  *  1110 |   x   | x (16)|   x   | x (20)
425  *  1111 |   x   |   x   |   x   |   x
426  *
427  * Pen selection table for uFlags = BF_SOFT
428  *
429  * uType |  LTI  |  LTO  |  RBI  |  RBO
430  * ------+-------+-------+-------+-------
431  *  0000 |   x   |   x   |   x   |   x
432  *  0001 |   x   |  20   |   x   |  21
433  *  0010 |   x   |  21   |   x   |  20
434  *  0011 |   x   |   x   |   x   |   x
435  * ------+-------+-------+-------+-------
436  *  0100 |   x   |  22   |   x   |  16
437  *  0101 |  22   |  20   |  16   |  21
438  *  0110 |  22   |  21   |  16   |  20
439  *  0111 |   x   |   x   |   x   |   x
440  * ------+-------+-------+-------+-------
441  *  1000 |   x   |  16   |   x   |  22
442  *  1001 |  16   |  20   |  22   |  21
443  *  1010 |  16   |  21   |  22   |  20
444  *  1011 |   x   |   x   |   x   |   x
445  * ------+-------+-------+-------+-------
446  *  1100 |   x   |   x   |   x   |   x
447  *  1101 |   x   | x (20)|   x   | x (21)
448  *  1110 |   x   | x (21)|   x   | x (20)
449  *  1111 |   x   |   x   |   x   |   x
450  *
451  * x = don't care; (n) = is what win95 actually uses
452  * LTI = left Top Inner line
453  * LTO = left Top Outer line
454  * RBI = Right Bottom Inner line
455  * RBO = Right Bottom Outer line
456  * 15 = COLOR_BTNFACE
457  * 16 = COLOR_BTNSHADOW
458  * 20 = COLOR_BTNHIGHLIGHT
459  * 21 = COLOR_3DDKSHADOW
460  * 22 = COLOR_3DLIGHT
461  */
462
463
464 static BOOL UITOOLS95_DrawRectEdge(HDC hdc, LPRECT rc,
465                                      UINT uType, UINT uFlags)
466 {
467     signed char LTInnerI, LTOuterI;
468     signed char RBInnerI, RBOuterI;
469     HPEN LTInnerPen, LTOuterPen;
470     HPEN RBInnerPen, RBOuterPen;
471     RECT InnerRect = *rc;
472     POINT SavePoint;
473     HPEN SavePen;
474     int LBpenplus = 0;
475     int LTpenplus = 0;
476     int RTpenplus = 0;
477     int RBpenplus = 0;
478     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
479                        || (uType & BDR_OUTER) == BDR_OUTER)
480                       && !(uFlags & (BF_FLAT|BF_MONO)) );
481
482     /* Init some vars */
483     LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = GetStockObject(NULL_PEN);
484     SavePen = SelectObject(hdc, LTInnerPen);
485
486     /* Determine the colors of the edges */
487     if(uFlags & BF_MONO)
488     {
489         LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
490         LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
491     }
492     else if(uFlags & BF_FLAT)
493     {
494         LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
495         LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
496
497         if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
498     }
499     else if(uFlags & BF_SOFT)
500     {
501         LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
502         LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
503         RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
504         RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
505     }
506     else
507     {
508         LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
509         LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
510         RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
511         RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
512     }
513
514     if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT)   LBpenplus = 1;
515     if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT)       RTpenplus = 1;
516     if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
517     if((uFlags & BF_TOPLEFT) == BF_TOPLEFT)         LTpenplus = 1;
518
519     if(LTInnerI != -1) LTInnerPen = SYSCOLOR_GetPen(LTInnerI);
520     if(LTOuterI != -1) LTOuterPen = SYSCOLOR_GetPen(LTOuterI);
521     if(RBInnerI != -1) RBInnerPen = SYSCOLOR_GetPen(RBInnerI);
522     if(RBOuterI != -1) RBOuterPen = SYSCOLOR_GetPen(RBOuterI);
523
524     MoveToEx(hdc, 0, 0, &SavePoint);
525
526     /* Draw the outer edge */
527     SelectObject(hdc, LTOuterPen);
528     if(uFlags & BF_TOP)
529     {
530         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
531         LineTo(hdc, InnerRect.right, InnerRect.top);
532     }
533     if(uFlags & BF_LEFT)
534     {
535         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
536         LineTo(hdc, InnerRect.left, InnerRect.bottom);
537     }
538     SelectObject(hdc, RBOuterPen);
539     if(uFlags & BF_BOTTOM)
540     {
541         MoveToEx(hdc, InnerRect.left, InnerRect.bottom-1, NULL);
542         LineTo(hdc, InnerRect.right-1, InnerRect.bottom-1);
543     }
544     if(uFlags & BF_RIGHT)
545     {
546         MoveToEx(hdc, InnerRect.right-1, InnerRect.top, NULL);
547         LineTo(hdc, InnerRect.right-1, InnerRect.bottom);
548     }
549
550     /* Draw the inner edge */
551     SelectObject(hdc, LTInnerPen);
552     if(uFlags & BF_TOP)
553     {
554         MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
555         LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
556     }
557     if(uFlags & BF_LEFT)
558     {
559         MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
560         LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
561     }
562     SelectObject(hdc, RBInnerPen);
563     if(uFlags & BF_BOTTOM)
564     {
565         MoveToEx(hdc, InnerRect.left+LBpenplus, InnerRect.bottom-2, NULL);
566         LineTo(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2);
567     }
568     if(uFlags & BF_RIGHT)
569     {
570         MoveToEx(hdc, InnerRect.right-2, InnerRect.top+2-RBpenplus, NULL);
571         LineTo(hdc, InnerRect.right-2, InnerRect.bottom-2+RTpenplus);
572     }
573
574     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
575     {
576         int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
577                 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
578
579         if(uFlags & BF_LEFT)   InnerRect.left   += add;
580         if(uFlags & BF_RIGHT)  InnerRect.right  -= add;
581         if(uFlags & BF_TOP)    InnerRect.top    += add;
582         if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
583
584         if((uFlags & BF_MIDDLE) && retval)
585         {
586             FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
587                                                        COLOR_WINDOW : COLOR_BTNFACE));
588         }
589
590         if(uFlags & BF_ADJUST)
591             *rc = InnerRect;
592     }
593
594     /* Cleanup */
595     SelectObject(hdc, SavePen);
596     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
597     return retval;
598 }
599
600
601 /**********************************************************************
602  *          DrawEdge   (USER32.@)
603  */
604 BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
605 {
606     TRACE("%p %s %04x %04x\n", hdc, wine_dbgstr_rect(rc), edge, flags );
607
608     if(flags & BF_DIAGONAL)
609       return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
610     else
611       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
612 }
613
614
615 /************************************************************************
616  *      UITOOLS_MakeSquareRect
617  *
618  * Utility to create a square rectangle and returning the width
619  */
620 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
621 {
622     int Width  = src->right - src->left;
623     int Height = src->bottom - src->top;
624     int SmallDiam = Width > Height ? Height : Width;
625
626     *dst = *src;
627
628     /* Make it a square box */
629     if(Width < Height)      /* SmallDiam == Width */
630     {
631         dst->top += (Height-Width)/2;
632         dst->bottom = dst->top + SmallDiam;
633     }
634     else if(Width > Height) /* SmallDiam == Height */
635     {
636         dst->left += (Width-Height)/2;
637         dst->right = dst->left + SmallDiam;
638     }
639
640    return SmallDiam;
641 }
642
643 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
644 {
645     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
646     {
647       HBRUSH hbsave;
648       COLORREF bg;
649
650       FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
651       bg = SetBkColor(dc, RGB(255, 255, 255));
652       hbsave = SelectObject(dc, SYSCOLOR_55AABrush);
653       PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
654       SelectObject(dc, hbsave);
655       SetBkColor(dc, bg);
656     }
657     else
658     {
659         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
660     }
661 }
662
663 /************************************************************************
664  *      UITOOLS_DFC_ButtonPush
665  *
666  * Draw a push button coming from DrawFrameControl()
667  *
668  * Does a pretty good job in emulating MS behavior. Some quirks are
669  * however there because MS uses a TrueType font (Marlett) to draw
670  * the buttons.
671  */
672 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
673 {
674     UINT edge;
675     RECT myr = *r;
676
677     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
678         edge = EDGE_SUNKEN;
679     else
680         edge = EDGE_RAISED;
681
682     if(uFlags & DFCS_CHECKED)
683     {
684         if(uFlags & DFCS_MONO)
685             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
686         else
687             UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
688
689         if (!(uFlags & DFCS_TRANSPARENT))
690             UITOOLS_DrawCheckedRect( dc, &myr );
691     }
692     else
693     {
694         if(uFlags & DFCS_MONO)
695         {
696             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
697             if (!(uFlags & DFCS_TRANSPARENT))
698                 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
699         }
700         else
701         {
702             UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags & DFCS_FLAT) | ((uFlags & DFCS_TRANSPARENT) ? 0 : BF_MIDDLE) | BF_RECT | BF_SOFT);
703         }
704     }
705
706     /* Adjust rectangle if asked */
707     if(uFlags & DFCS_ADJUSTRECT)
708     {
709         r->left   += 2;
710         r->right  -= 2;
711         r->top    += 2;
712         r->bottom -= 2;
713     }
714
715     return TRUE;
716 }
717
718
719 /************************************************************************
720  *      UITOOLS_DFC_ButtonChcek
721  *
722  * Draw a check/3state button coming from DrawFrameControl()
723  *
724  * Does a pretty good job in emulating MS behavior. Some quirks are
725  * however there because MS uses a TrueType font (Marlett) to draw
726  * the buttons.
727  */
728
729 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
730 {
731     RECT myr, bar;
732     UINT flags = BF_RECT | BF_ADJUST;
733
734     UITOOLS_MakeSquareRect(r, &myr);
735
736     if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
737     else if(uFlags & DFCS_MONO) flags |= BF_MONO;
738
739     UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
740
741     if (!(uFlags & DFCS_TRANSPARENT))
742     {
743         if(uFlags & (DFCS_INACTIVE | DFCS_PUSHED))
744             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
745         else if( (uFlags & DFCS_BUTTON3STATE) && (uFlags & DFCS_CHECKED) )
746             UITOOLS_DrawCheckedRect( dc, &myr );
747         else
748             FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
749     }
750
751     if(uFlags & DFCS_CHECKED)
752     {
753         int i, k;
754         i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
755                 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
756
757         /* draw 7 bars, with h=3w to form the check */
758         bar.left = myr.left;
759         bar.top = myr.top + 2;
760         for (k = 0; k < 7; k++) {
761             bar.left = bar.left + 1;
762             bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
763             bar.bottom = bar.top + 3;
764             bar.right = bar.left + 1;
765             FillRect(dc, &bar, GetSysColorBrush(i));
766         }
767     }
768     return TRUE;
769 }
770
771
772 /************************************************************************
773  *      UITOOLS_DFC_ButtonRadio
774  *
775  * Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
776  *
777  * Does a pretty good job in emulating MS behavior. Some quirks are
778  * however there because MS uses a TrueType font (Marlett) to draw
779  * the buttons.
780  */
781 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
782 {
783     RECT myr;
784     int i;
785     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
786     int BorderShrink = SmallDiam / 16;
787     HPEN hpsave;
788     HBRUSH hbsave;
789     int xc, yc;
790
791     if(BorderShrink < 1) BorderShrink = 1;
792
793     if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
794         FillRect(dc, r, GetStockObject(BLACK_BRUSH));
795
796     xc = myr.left + SmallDiam - SmallDiam/2;
797     yc = myr.top  + SmallDiam - SmallDiam/2;
798
799     /* Define bounding box */
800     i = 14*SmallDiam/16;
801     myr.left   = xc - i+i/2;
802     myr.right  = xc + i/2;
803     myr.top    = yc - i+i/2;
804     myr.bottom = yc + i/2;
805
806     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
807     {
808         hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
809         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
810         SelectObject(dc, hbsave);
811     }
812     else
813     {
814         if(uFlags & (DFCS_FLAT|DFCS_MONO))
815         {
816             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
817             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
818             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
819             SelectObject(dc, hbsave);
820             SelectObject(dc, hpsave);
821         }
822         else
823         {
824             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
825             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
826             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
827
828             SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNSHADOW));
829             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
830             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
831
832             myr.left   += BorderShrink;
833             myr.right  -= BorderShrink;
834             myr.top    += BorderShrink;
835             myr.bottom -= BorderShrink;
836
837             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DLIGHT));
838             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
839             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
840
841             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DDKSHADOW));
842             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
843             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
844             SelectObject(dc, hbsave);
845             SelectObject(dc, hpsave);
846         }
847
848         i = 10*SmallDiam/16;
849         myr.left   = xc - i+i/2;
850         myr.right  = xc + i/2;
851         myr.top    = yc - i+i/2;
852         myr.bottom = yc + i/2;
853         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
854         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
855         hbsave = SelectObject(dc, GetSysColorBrush(i));
856         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
857         SelectObject(dc, hbsave);
858         SelectObject(dc, hpsave);
859     }
860
861     if(uFlags & DFCS_CHECKED)
862     {
863         i = 6*SmallDiam/16;
864         i = i < 1 ? 1 : i;
865         myr.left   = xc - i+i/2;
866         myr.right  = xc + i/2;
867         myr.top    = yc - i+i/2;
868         myr.bottom = yc + i/2;
869
870         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
871         hbsave = SelectObject(dc, GetSysColorBrush(i));
872         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
873         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
874         SelectObject(dc, hpsave);
875         SelectObject(dc, hbsave);
876     }
877
878     /* FIXME: M$ has a polygon in the center at relative points: */
879     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
880     /* 0.476, 0.525 */
881     /* 0.500, 0.500 */
882     /* 0.500, 0.499 */
883     /* when the button is unchecked. The reason for it is unknown. The */
884     /* color is COLOR_BTNHIGHLIGHT, although the polygon gets painted at */
885     /* least 3 times (it looks like a clip-region when you see it happen). */
886     /* I do not really see a reason why this should be implemented. If you */
887     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
888     /* font. */
889
890     return TRUE;
891 }
892
893 /***********************************************************************
894  *           UITOOLS_DrawFrameButton
895  */
896 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
897 {
898     switch(uState & 0xff)
899     {
900     case DFCS_BUTTONPUSH:
901         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
902
903     case DFCS_BUTTONCHECK:
904     case DFCS_BUTTON3STATE:
905         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
906
907     case DFCS_BUTTONRADIOIMAGE:
908     case DFCS_BUTTONRADIOMASK:
909     case DFCS_BUTTONRADIO:
910         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
911
912     default:
913         WARN("Invalid button state=0x%04x\n", uState);
914     }
915
916     return FALSE;
917 }
918
919 /***********************************************************************
920  *           UITOOLS_DrawFrameCaption
921  *
922  * Draw caption buttons (win95), coming from DrawFrameControl()
923  */
924
925 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
926 {
927     RECT myr;
928     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
929     HFONT hfsave, hf;
930     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
931     int xc = (myr.left+myr.right)/2;
932     int yc = (myr.top+myr.bottom)/2;
933     WCHAR str[2] = {0, 0};
934     static const WCHAR glyphFontName[] = { 'M','a','r','l','e','t','t',0 };
935     UINT alignsave;
936     int bksave;
937     COLORREF clrsave;
938     SIZE size;
939
940     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
941
942     switch(uFlags & 0xf)
943     {
944     case DFCS_CAPTIONCLOSE:     str[0] = 0x72; break;
945     case DFCS_CAPTIONHELP:      str[0] = 0x73; break;
946     case DFCS_CAPTIONMIN:       str[0] = 0x30; break;
947     case DFCS_CAPTIONMAX:       str[0] = 0x31; break;
948     case DFCS_CAPTIONRESTORE:   str[0] = 0x32; break;
949     default:
950         WARN("Invalid caption; flags=0x%04x\n", uFlags);
951         return FALSE;
952     }
953     
954     hf = CreateFontW(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
955                     SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
956                     DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, glyphFontName);
957     alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
958     bksave = SetBkMode(dc, TRANSPARENT);
959     clrsave = GetTextColor(dc);
960     hfsave = SelectObject(dc, hf);
961     GetTextExtentPoint32W(dc, str, 1, &size);
962
963     if(uFlags & DFCS_INACTIVE)
964     {
965         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
966         TextOutW(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
967     }
968     SetTextColor(dc, GetSysColor(colorIdx));
969     TextOutW(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
970
971     SelectObject(dc, hfsave);
972     SetTextColor(dc, clrsave);
973     SetBkMode(dc, bksave);
974     SetTextAlign(dc, alignsave);
975     DeleteObject(hf);
976   
977     return TRUE;
978 }
979
980
981 /************************************************************************
982  *      UITOOLS_DrawFrameScroll
983  *
984  * Draw a scroll-bar control coming from DrawFrameControl()
985  */
986 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
987 {
988     POINT Line[4];
989     RECT myr;
990     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
991     int i;
992     HBRUSH hbsave, hb, hb2;
993     HPEN hpsave, hp, hp2;
994     int tri = 290*SmallDiam/1000 - 1;
995     int d46, d93;
996
997     /*
998      * This fixes a problem with really tiny "scroll" buttons. In particular
999      * with the updown control.
1000      * Making sure that the arrow is as least 3 pixels wide (or high).
1001      */
1002     if (tri == 0)
1003       tri = 1;
1004
1005     switch(uFlags & 0xff)
1006     {
1007     case DFCS_SCROLLCOMBOBOX:
1008     case DFCS_SCROLLDOWN:
1009         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1010         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1011         Line[0].x = Line[2].x - tri;
1012         Line[1].x = Line[2].x + tri;
1013         Line[0].y = Line[1].y = Line[2].y - tri;
1014         break;
1015
1016     case DFCS_SCROLLUP:
1017         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1018         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1019         Line[0].x = Line[2].x - tri;
1020         Line[1].x = Line[2].x + tri;
1021         Line[0].y = Line[1].y = Line[2].y + tri;
1022         break;
1023
1024     case DFCS_SCROLLLEFT:
1025         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1026         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1027         Line[0].y = Line[2].y - tri;
1028         Line[1].y = Line[2].y + tri;
1029         Line[0].x = Line[1].x = Line[2].x + tri;
1030         break;
1031
1032     case DFCS_SCROLLRIGHT:
1033         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1034         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1035         Line[0].y = Line[2].y - tri;
1036         Line[1].y = Line[2].y + tri;
1037         Line[0].x = Line[1].x = Line[2].x - tri;
1038         break;
1039
1040     case DFCS_SCROLLSIZEGRIP:
1041         /* This one breaks the flow... */
1042         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1043         hpsave = SelectObject(dc, GetStockObject(NULL_PEN));
1044         hbsave = SelectObject(dc, GetStockObject(NULL_BRUSH));
1045         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1046         {
1047             hp = hp2 = SYSCOLOR_GetPen(COLOR_WINDOWFRAME);
1048             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1049         }
1050         else
1051         {
1052             hp  = SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT);
1053             hp2 = SYSCOLOR_GetPen(COLOR_BTNSHADOW);
1054             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1055             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1056         }
1057         Line[0].x = Line[1].x = r->right-1;
1058         Line[2].y = Line[3].y = r->bottom-1;
1059         d46 = 46*SmallDiam/750;
1060         d93 = 93*SmallDiam/750;
1061
1062         i = 586*SmallDiam/750;
1063         Line[0].y = r->bottom - i - 1;
1064         Line[3].x = r->right - i - 1;
1065         Line[1].y = Line[0].y + d46;
1066         Line[2].x = Line[3].x + d46;
1067         SelectObject(dc, hb);
1068         SelectObject(dc, hp);
1069         Polygon(dc, Line, 4);
1070
1071         Line[1].y++; Line[2].x++;
1072         Line[0].y = Line[1].y + d93;
1073         Line[3].x = Line[2].x + d93;
1074         SelectObject(dc, hb2);
1075         SelectObject(dc, hp2);
1076         Polygon(dc, Line, 4);
1077
1078         i = 398*SmallDiam/750;
1079         Line[0].y = r->bottom - i - 1;
1080         Line[3].x = r->right - i - 1;
1081         Line[1].y = Line[0].y + d46;
1082         Line[2].x = Line[3].x + d46;
1083         SelectObject(dc, hb);
1084         SelectObject(dc, hp);
1085         Polygon(dc, Line, 4);
1086
1087         Line[1].y++; Line[2].x++;
1088         Line[0].y = Line[1].y + d93;
1089         Line[3].x = Line[2].x + d93;
1090         SelectObject(dc, hb2);
1091         SelectObject(dc, hp2);
1092         Polygon(dc, Line, 4);
1093
1094         i = 210*SmallDiam/750;
1095         Line[0].y = r->bottom - i - 1;
1096         Line[3].x = r->right - i - 1;
1097         Line[1].y = Line[0].y + d46;
1098         Line[2].x = Line[3].x + d46;
1099         SelectObject(dc, hb);
1100         SelectObject(dc, hp);
1101         Polygon(dc, Line, 4);
1102
1103         Line[1].y++; Line[2].x++;
1104         Line[0].y = Line[1].y + d93;
1105         Line[3].x = Line[2].x + d93;
1106         SelectObject(dc, hb2);
1107         SelectObject(dc, hp2);
1108         Polygon(dc, Line, 4);
1109
1110         SelectObject(dc, hpsave);
1111         SelectObject(dc, hbsave);
1112         return TRUE;
1113
1114     default:
1115         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1116         return FALSE;
1117     }
1118
1119     /* Here do the real scroll-bar controls end up */
1120     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1121       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1122       /* want for the normal scroll-arrow button. */
1123       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1124     else
1125       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1126
1127     if(uFlags & DFCS_INACTIVE)
1128     {
1129         hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1130         hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1131         Polygon(dc, Line, 3);
1132         SelectObject(dc, hpsave);
1133         SelectObject(dc, hbsave);
1134     }
1135
1136     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1137       for(i = 0; i < 3; i++)
1138       {
1139         Line[i].x--;
1140         Line[i].y--;
1141       }
1142
1143     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1144     hbsave = SelectObject(dc, GetSysColorBrush(i));
1145     hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
1146     Polygon(dc, Line, 3);
1147     SelectObject(dc, hpsave);
1148     SelectObject(dc, hbsave);
1149
1150     return TRUE;
1151 }
1152
1153 /************************************************************************
1154  *      UITOOLS_DrawFrameMenu
1155  *
1156  * Draw a menu control coming from DrawFrameControl()
1157  */
1158 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1159 {
1160     POINT Points[6];
1161     RECT myr;
1162     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1163     int i;
1164     HBRUSH hbsave;
1165     HPEN hpsave;
1166     int xe, ye;
1167     int xc, yc;
1168     BOOL retval = TRUE;
1169
1170     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1171     /* use anything else. I think I tried all sys-colors to change things */
1172     /* without luck. It seems as if this behavior is inherited from the */
1173     /* win31 DFC() implementation... (you remember, B/W menus). */
1174
1175     FillRect(dc, r, GetStockObject(WHITE_BRUSH));
1176
1177     hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
1178     hpsave = SelectObject(dc, GetStockObject(BLACK_PEN));
1179
1180     switch(uFlags & 0xff)
1181     {
1182     case DFCS_MENUARROW:
1183         i = 187*SmallDiam/750;
1184         Points[2].x = myr.left + 468*SmallDiam/750;
1185         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1186         Points[0].y = Points[2].y - i;
1187         Points[1].y = Points[2].y + i;
1188         Points[0].x = Points[1].x = Points[2].x - i;
1189         Polygon(dc, Points, 3);
1190         break;
1191
1192     case DFCS_MENUBULLET:
1193         xe = myr.left;
1194         ye = myr.top  + SmallDiam - SmallDiam/2;
1195         xc = myr.left + SmallDiam - SmallDiam/2;
1196         yc = myr.top  + SmallDiam - SmallDiam/2;
1197         i = 234*SmallDiam/750;
1198         i = i < 1 ? 1 : i;
1199         myr.left   = xc - i+i/2;
1200         myr.right  = xc + i/2;
1201         myr.top    = yc - i+i/2;
1202         myr.bottom = yc + i/2;
1203         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1204         break;
1205
1206     case DFCS_MENUCHECK:
1207         Points[0].x = myr.left + 253*SmallDiam/1000;
1208         Points[0].y = myr.top  + 445*SmallDiam/1000;
1209         Points[1].x = myr.left + 409*SmallDiam/1000;
1210         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1211         Points[2].x = myr.left + 690*SmallDiam/1000;
1212         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1213         Points[3].x = Points[2].x;
1214         Points[3].y = Points[2].y + 3*SmallDiam/16;
1215         Points[4].x = Points[1].x;
1216         Points[4].y = Points[1].y + 3*SmallDiam/16;
1217         Points[5].x = Points[0].x;
1218         Points[5].y = Points[0].y + 3*SmallDiam/16;
1219         Polygon(dc, Points, 6);
1220         break;
1221
1222     default:
1223         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1224         retval = FALSE;
1225         break;
1226     }
1227
1228     SelectObject(dc, hpsave);
1229     SelectObject(dc, hbsave);
1230     return retval;
1231 }
1232
1233
1234 /**********************************************************************
1235  *          DrawFrameControl  (USER32.@)
1236  */
1237 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1238                                   UINT uState )
1239 {
1240     switch(uType)
1241     {
1242     case DFC_BUTTON:
1243       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1244     case DFC_CAPTION:
1245       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1246     case DFC_MENU:
1247       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1248     /*case DFC_POPUPMENU:
1249       FIXME("DFC_POPUPMENU: not implemented\n");
1250       break;*/
1251     case DFC_SCROLL:
1252       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1253     default:
1254       WARN("(%p,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1255     }
1256     return FALSE;
1257 }
1258
1259
1260 /***********************************************************************
1261  *              SetRect (USER32.@)
1262  */
1263 BOOL WINAPI SetRect( LPRECT rect, INT left, INT top,
1264                        INT right, INT bottom )
1265 {
1266     if (!rect) return FALSE;
1267     rect->left   = left;
1268     rect->right  = right;
1269     rect->top    = top;
1270     rect->bottom = bottom;
1271     return TRUE;
1272 }
1273
1274
1275 /***********************************************************************
1276  *              SetRectEmpty (USER32.@)
1277  */
1278 BOOL WINAPI SetRectEmpty( LPRECT rect )
1279 {
1280     if (!rect) return FALSE;
1281     rect->left = rect->right = rect->top = rect->bottom = 0;
1282     return TRUE;
1283 }
1284
1285
1286 /***********************************************************************
1287  *              CopyRect (USER32.@)
1288  */
1289 BOOL WINAPI CopyRect( RECT *dest, const RECT *src )
1290 {
1291     if (!dest || !src) return FALSE;
1292     *dest = *src;
1293     return TRUE;
1294 }
1295
1296
1297 /***********************************************************************
1298  *              IsRectEmpty (USER32.@)
1299  *
1300  * Bug compat: Windows checks for 0 or negative width/height.
1301  */
1302 BOOL WINAPI IsRectEmpty( const RECT *rect )
1303 {
1304     if (!rect) return TRUE;
1305     return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
1306 }
1307
1308
1309 /***********************************************************************
1310  *              PtInRect (USER32.@)
1311  */
1312 BOOL WINAPI PtInRect( const RECT *rect, POINT pt )
1313 {
1314     if (!rect) return FALSE;
1315     return ((pt.x >= rect->left) && (pt.x < rect->right) &&
1316             (pt.y >= rect->top) && (pt.y < rect->bottom));
1317 }
1318
1319
1320 /***********************************************************************
1321  *              OffsetRect (USER32.@)
1322  */
1323 BOOL WINAPI OffsetRect( LPRECT rect, INT x, INT y )
1324 {
1325     if (!rect) return FALSE;
1326     rect->left   += x;
1327     rect->right  += x;
1328     rect->top    += y;
1329     rect->bottom += y;
1330     return TRUE;
1331 }
1332
1333
1334 /***********************************************************************
1335  *              InflateRect (USER32.@)
1336  */
1337 BOOL WINAPI InflateRect( LPRECT rect, INT x, INT y )
1338 {
1339     if (!rect) return FALSE;
1340     rect->left   -= x;
1341     rect->top    -= y;
1342     rect->right  += x;
1343     rect->bottom += y;
1344     return TRUE;
1345 }
1346
1347
1348 /***********************************************************************
1349  *              IntersectRect (USER32.@)
1350  */
1351 BOOL WINAPI IntersectRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1352 {
1353     if (!dest || !src1 || !src2) return FALSE;
1354     if (IsRectEmpty(src1) || IsRectEmpty(src2) ||
1355         (src1->left >= src2->right) || (src2->left >= src1->right) ||
1356         (src1->top >= src2->bottom) || (src2->top >= src1->bottom))
1357     {
1358         SetRectEmpty( dest );
1359         return FALSE;
1360     }
1361     dest->left   = max( src1->left, src2->left );
1362     dest->right  = min( src1->right, src2->right );
1363     dest->top    = max( src1->top, src2->top );
1364     dest->bottom = min( src1->bottom, src2->bottom );
1365     return TRUE;
1366 }
1367
1368
1369 /***********************************************************************
1370  *              UnionRect (USER32.@)
1371  */
1372 BOOL WINAPI UnionRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1373 {
1374     if (!dest) return FALSE;
1375     if (IsRectEmpty(src1))
1376     {
1377         if (IsRectEmpty(src2))
1378         {
1379             SetRectEmpty( dest );
1380             return FALSE;
1381         }
1382         else *dest = *src2;
1383     }
1384     else
1385     {
1386         if (IsRectEmpty(src2)) *dest = *src1;
1387         else
1388         {
1389             dest->left   = min( src1->left, src2->left );
1390             dest->right  = max( src1->right, src2->right );
1391             dest->top    = min( src1->top, src2->top );
1392             dest->bottom = max( src1->bottom, src2->bottom );
1393         }
1394     }
1395     return TRUE;
1396 }
1397
1398
1399 /***********************************************************************
1400  *              EqualRect (USER32.@)
1401  */
1402 BOOL WINAPI EqualRect( const RECT* rect1, const RECT* rect2 )
1403 {
1404     if (!rect1 || !rect2) return FALSE;
1405     return ((rect1->left == rect2->left) && (rect1->right == rect2->right) &&
1406             (rect1->top == rect2->top) && (rect1->bottom == rect2->bottom));
1407 }
1408
1409
1410 /***********************************************************************
1411  *              SubtractRect (USER32.@)
1412  */
1413 BOOL WINAPI SubtractRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1414 {
1415     RECT tmp;
1416
1417     if (!dest) return FALSE;
1418     if (IsRectEmpty( src1 ))
1419     {
1420         SetRectEmpty( dest );
1421         return FALSE;
1422     }
1423     *dest = *src1;
1424     if (IntersectRect( &tmp, src1, src2 ))
1425     {
1426         if (EqualRect( &tmp, dest ))
1427         {
1428             SetRectEmpty( dest );
1429             return FALSE;
1430         }
1431         if ((tmp.top == dest->top) && (tmp.bottom == dest->bottom))
1432         {
1433             if (tmp.left == dest->left) dest->left = tmp.right;
1434             else if (tmp.right == dest->right) dest->right = tmp.left;
1435         }
1436         else if ((tmp.left == dest->left) && (tmp.right == dest->right))
1437         {
1438             if (tmp.top == dest->top) dest->top = tmp.bottom;
1439             else if (tmp.bottom == dest->bottom) dest->bottom = tmp.top;
1440         }
1441     }
1442     return TRUE;
1443 }
1444
1445
1446 /***********************************************************************
1447  *              FillRect (USER32.@)
1448  */
1449 INT WINAPI FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1450 {
1451     HBRUSH prev_brush;
1452
1453     if (hbrush <= (HBRUSH) (COLOR_MAX + 1)) hbrush = GetSysColorBrush( HandleToULong(hbrush) - 1 );
1454
1455     prev_brush = SelectObject( hdc, hbrush );
1456     PatBlt( hdc, rect->left, rect->top,
1457               rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
1458     if (prev_brush) SelectObject( hdc, prev_brush );
1459     return 1;
1460 }
1461
1462
1463 /***********************************************************************
1464  *              InvertRect (USER32.@)
1465  */
1466 BOOL WINAPI InvertRect( HDC hdc, const RECT *rect )
1467 {
1468     return PatBlt( hdc, rect->left, rect->top,
1469                    rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
1470 }
1471
1472
1473 /***********************************************************************
1474  *              FrameRect (USER32.@)
1475  */
1476 INT WINAPI FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1477 {
1478     HBRUSH prevBrush;
1479     RECT r = *rect;
1480
1481     if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
1482     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
1483
1484     PatBlt( hdc, r.left, r.top, 1, r.bottom - r.top, PATCOPY );
1485     PatBlt( hdc, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY );
1486     PatBlt( hdc, r.left, r.top, r.right - r.left, 1, PATCOPY );
1487     PatBlt( hdc, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY );
1488
1489     SelectObject( hdc, prevBrush );
1490     return TRUE;
1491 }
1492
1493
1494 /***********************************************************************
1495  *              DrawFocusRect (USER32.@)
1496  *
1497  * FIXME: PatBlt(PATINVERT) with background brush.
1498  */
1499 BOOL WINAPI DrawFocusRect( HDC hdc, const RECT* rc )
1500 {
1501     HBRUSH hOldBrush;
1502     HPEN hOldPen, hNewPen;
1503     INT oldDrawMode, oldBkMode;
1504     LOGBRUSH lb;
1505
1506     hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
1507     lb.lbStyle = BS_SOLID;
1508     lb.lbColor = GetSysColor(COLOR_WINDOWTEXT);
1509     hNewPen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
1510     hOldPen = SelectObject(hdc, hNewPen);
1511     oldDrawMode = SetROP2(hdc, R2_XORPEN);
1512     oldBkMode = SetBkMode(hdc, TRANSPARENT);
1513
1514     Rectangle(hdc, rc->left, rc->top, rc->right, rc->bottom);
1515
1516     SetBkMode(hdc, oldBkMode);
1517     SetROP2(hdc, oldDrawMode);
1518     SelectObject(hdc, hOldPen);
1519     DeleteObject(hNewPen);
1520     SelectObject(hdc, hOldBrush);
1521
1522     return TRUE;
1523 }
1524
1525
1526 /**********************************************************************
1527  *              DrawAnimatedRects (USER32.@)
1528  */
1529 BOOL WINAPI DrawAnimatedRects( HWND hwnd, INT idAni, const RECT* lprcFrom, const RECT* lprcTo )
1530 {
1531     FIXME("(%p,%d,%p,%p): stub\n",hwnd,idAni,lprcFrom,lprcTo);
1532     return TRUE;
1533 }
1534
1535
1536 /**********************************************************************
1537  *          UITOOLS_DrawStateJam
1538  *
1539  * Jams in the requested type in the dc
1540  */
1541 static BOOL UITOOLS_DrawStateJam( HDC hdc, UINT opcode, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1542                                   LPRECT rc, UINT dtflags, BOOL unicode )
1543 {
1544     HDC memdc;
1545     HBITMAP hbmsave;
1546     BOOL retval;
1547     INT cx = rc->right - rc->left;
1548     INT cy = rc->bottom - rc->top;
1549
1550     switch(opcode)
1551     {
1552     case DST_TEXT:
1553     case DST_PREFIXTEXT:
1554         if(unicode)
1555             return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1556         else
1557             return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1558
1559     case DST_ICON:
1560         return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, 0, 0, 0, NULL, DI_NORMAL);
1561
1562     case DST_BITMAP:
1563         memdc = CreateCompatibleDC(hdc);
1564         if(!memdc) return FALSE;
1565         hbmsave = SelectObject(memdc, (HBITMAP)lp);
1566         if(!hbmsave)
1567         {
1568             DeleteDC(memdc);
1569             return FALSE;
1570         }
1571         retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1572         SelectObject(memdc, hbmsave);
1573         DeleteDC(memdc);
1574         return retval;
1575
1576     case DST_COMPLEX:
1577         if(func) {
1578             BOOL bRet;
1579             /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */
1580
1581             OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1582             bRet = func(hdc, lp, wp, cx, cy);
1583             /* Restore origin */
1584             OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1585             return bRet;
1586         } else
1587             return FALSE;
1588     }
1589     return FALSE;
1590 }
1591
1592 /**********************************************************************
1593  *      UITOOLS_DrawState()
1594  */
1595 static BOOL UITOOLS_DrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1596                               INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode )
1597 {
1598     HBITMAP hbm, hbmsave;
1599     HFONT hfsave;
1600     HBRUSH hbsave, hbrtmp = 0;
1601     HDC memdc;
1602     RECT rc;
1603     UINT dtflags = DT_NOCLIP;
1604     COLORREF fg, bg;
1605     UINT opcode = flags & 0xf;
1606     INT len = wp;
1607     BOOL retval, tmp;
1608
1609     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1610     {
1611         if (!lp) return FALSE;
1612
1613         if(unicode)
1614             len = strlenW((LPWSTR)lp);
1615         else
1616             len = strlen((LPSTR)lp);
1617     }
1618
1619     /* Find out what size the image has if not given by caller */
1620     if(!cx || !cy)
1621     {
1622         SIZE s;
1623         BITMAP bm;
1624
1625         switch(opcode)
1626         {
1627         case DST_TEXT:
1628         case DST_PREFIXTEXT:
1629             if(unicode)
1630                 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1631             else
1632                 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1633             if(!retval) return FALSE;
1634             break;
1635
1636         case DST_ICON:
1637             if (!get_icon_size( (HICON)lp, &s )) return FALSE;
1638             break;
1639
1640         case DST_BITMAP:
1641             if(!GetObjectA((HBITMAP)lp, sizeof(bm), &bm)) return FALSE;
1642             s.cx = bm.bmWidth;
1643             s.cy = bm.bmHeight;
1644             break;
1645
1646         case DST_COMPLEX: /* cx and cy must be set in this mode */
1647             return FALSE;
1648         }
1649
1650         if(!cx) cx = s.cx;
1651         if(!cy) cy = s.cy;
1652     }
1653
1654     rc.left   = x;
1655     rc.top    = y;
1656     rc.right  = x + cx;
1657     rc.bottom = y + cy;
1658
1659     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1660         dtflags |= DT_RIGHT;
1661     if(opcode == DST_TEXT)
1662         dtflags |= DT_NOPREFIX;
1663
1664     /* For DSS_NORMAL we just jam in the image and return */
1665     if((flags & 0x7ff0) == DSS_NORMAL)
1666     {
1667         return UITOOLS_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1668     }
1669
1670     /* For all other states we need to convert the image to B/W in a local bitmap */
1671     /* before it is displayed */
1672     fg = SetTextColor(hdc, RGB(0, 0, 0));
1673     bg = SetBkColor(hdc, RGB(255, 255, 255));
1674     hbm = NULL; hbmsave = NULL;
1675     memdc = NULL; hbsave = NULL;
1676     retval = FALSE; /* assume failure */
1677
1678     /* From here on we must use "goto cleanup" when something goes wrong */
1679     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1680     if(!hbm) goto cleanup;
1681     memdc   = CreateCompatibleDC(hdc);
1682     if(!memdc) goto cleanup;
1683     hbmsave = SelectObject(memdc, hbm);
1684     if(!hbmsave) goto cleanup;
1685     rc.left = rc.top = 0;
1686     rc.right = cx;
1687     rc.bottom = cy;
1688     if(!FillRect(memdc, &rc, GetStockObject(WHITE_BRUSH))) goto cleanup;
1689     SetBkColor(memdc, RGB(255, 255, 255));
1690     SetTextColor(memdc, RGB(0, 0, 0));
1691     hfsave  = SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1692
1693     /* DST_COMPLEX may draw text as well,
1694      * so we must be sure that correct font is selected
1695      */
1696     if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1697     tmp = UITOOLS_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1698     if(hfsave) SelectObject(memdc, hfsave);
1699     if(!tmp) goto cleanup;
1700
1701     /* This state cause the image to be dithered */
1702     if(flags & DSS_UNION)
1703     {
1704         hbsave = SelectObject(memdc, SYSCOLOR_55AABrush);
1705         if(!hbsave) goto cleanup;
1706         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1707         SelectObject(memdc, hbsave);
1708         if(!tmp) goto cleanup;
1709     }
1710
1711     if (flags & DSS_DISABLED)
1712        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1713     else if (flags & DSS_DEFAULT)
1714        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1715
1716     /* Draw light or dark shadow */
1717     if (flags & (DSS_DISABLED|DSS_DEFAULT))
1718     {
1719        if(!hbrtmp) goto cleanup;
1720        hbsave = SelectObject(hdc, hbrtmp);
1721        if(!hbsave) goto cleanup;
1722        if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1723        SelectObject(hdc, hbsave);
1724        DeleteObject(hbrtmp);
1725        hbrtmp = 0;
1726     }
1727
1728     if (flags & DSS_DISABLED)
1729     {
1730        hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1731        if(!hbrtmp) goto cleanup;
1732     }
1733     else if (!hbr)
1734     {
1735        hbr = GetStockObject(BLACK_BRUSH);
1736     }
1737
1738     hbsave = SelectObject(hdc, hbr);
1739
1740     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1741
1742     retval = TRUE; /* We succeeded */
1743
1744 cleanup:
1745     SetTextColor(hdc, fg);
1746     SetBkColor(hdc, bg);
1747
1748     if(hbsave)  SelectObject(hdc, hbsave);
1749     if(hbmsave) SelectObject(memdc, hbmsave);
1750     if(hbrtmp)  DeleteObject(hbrtmp);
1751     if(hbm)     DeleteObject(hbm);
1752     if(memdc)   DeleteDC(memdc);
1753
1754     return retval;
1755 }
1756
1757 /**********************************************************************
1758  *              DrawStateA (USER32.@)
1759  */
1760 BOOL WINAPI DrawStateA(HDC hdc, HBRUSH hbr,
1761                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1762                    INT x, INT y, INT cx, INT cy, UINT flags)
1763 {
1764     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, FALSE);
1765 }
1766
1767 /**********************************************************************
1768  *              DrawStateW (USER32.@)
1769  */
1770 BOOL WINAPI DrawStateW(HDC hdc, HBRUSH hbr,
1771                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1772                    INT x, INT y, INT cx, INT cy, UINT flags)
1773 {
1774     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, TRUE);
1775 }