user32: Make sure the scroll button arrows are really at least 3 pixels.
[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     else if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
796         FillRect(dc, r, GetStockObject(WHITE_BRUSH));
797
798     xc = myr.left + SmallDiam - SmallDiam/2;
799     yc = myr.top  + SmallDiam - SmallDiam/2;
800
801     /* Define bounding box */
802     i = 14*SmallDiam/16;
803     myr.left   = xc - i+i/2;
804     myr.right  = xc + i/2;
805     myr.top    = yc - i+i/2;
806     myr.bottom = yc + i/2;
807
808     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
809     {
810         hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
811         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
812         SelectObject(dc, hbsave);
813     }
814     else
815     {
816         if(uFlags & (DFCS_FLAT|DFCS_MONO))
817         {
818             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
819             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
820             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
821             SelectObject(dc, hbsave);
822             SelectObject(dc, hpsave);
823         }
824         else
825         {
826             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
827             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
828             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
829
830             SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNSHADOW));
831             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
832             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
833
834             myr.left   += BorderShrink;
835             myr.right  -= BorderShrink;
836             myr.top    += BorderShrink;
837             myr.bottom -= BorderShrink;
838
839             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DLIGHT));
840             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
841             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
842
843             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DDKSHADOW));
844             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
845             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
846             SelectObject(dc, hbsave);
847             SelectObject(dc, hpsave);
848         }
849
850         i = 10*SmallDiam/16;
851         myr.left   = xc - i+i/2;
852         myr.right  = xc + i/2;
853         myr.top    = yc - i+i/2;
854         myr.bottom = yc + i/2;
855         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
856         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
857         hbsave = SelectObject(dc, GetSysColorBrush(i));
858         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
859         SelectObject(dc, hbsave);
860         SelectObject(dc, hpsave);
861     }
862
863     if(uFlags & DFCS_CHECKED)
864     {
865         i = 6*SmallDiam/16;
866         i = i < 1 ? 1 : i;
867         myr.left   = xc - i+i/2;
868         myr.right  = xc + i/2;
869         myr.top    = yc - i+i/2;
870         myr.bottom = yc + i/2;
871
872         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
873         hbsave = SelectObject(dc, GetSysColorBrush(i));
874         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
875         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
876         SelectObject(dc, hpsave);
877         SelectObject(dc, hbsave);
878     }
879
880     /* FIXME: M$ has a polygon in the center at relative points: */
881     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
882     /* 0.476, 0.525 */
883     /* 0.500, 0.500 */
884     /* 0.500, 0.499 */
885     /* when the button is unchecked. The reason for it is unknown. The */
886     /* color is COLOR_BTNHIGHLIGHT, although the polygon gets painted at */
887     /* least 3 times (it looks like a clip-region when you see it happen). */
888     /* I do not really see a reason why this should be implemented. If you */
889     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
890     /* font. */
891
892     return TRUE;
893 }
894
895 /***********************************************************************
896  *           UITOOLS_DrawFrameButton
897  */
898 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
899 {
900     switch(uState & 0xff)
901     {
902     case DFCS_BUTTONPUSH:
903         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
904
905     case DFCS_BUTTONCHECK:
906     case DFCS_BUTTON3STATE:
907         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
908
909     case DFCS_BUTTONRADIOIMAGE:
910     case DFCS_BUTTONRADIOMASK:
911     case DFCS_BUTTONRADIO:
912         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
913
914     default:
915         WARN("Invalid button state=0x%04x\n", uState);
916     }
917
918     return FALSE;
919 }
920
921 /***********************************************************************
922  *           UITOOLS_DrawFrameCaption
923  *
924  * Draw caption buttons (win95), coming from DrawFrameControl()
925  */
926
927 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
928 {
929     RECT myr;
930     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
931     HFONT hfsave, hf;
932     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
933     int xc = (myr.left+myr.right)/2;
934     int yc = (myr.top+myr.bottom)/2;
935     WCHAR str[] = {0, 0};
936     static const WCHAR glyphFontName[] = { 'M','a','r','l','e','t','t',0 };
937     UINT alignsave;
938     int bksave;
939     COLORREF clrsave;
940     SIZE size;
941
942     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
943
944     switch(uFlags & 0xf)
945     {
946     case DFCS_CAPTIONCLOSE:     str[0] = 0x72; break;
947     case DFCS_CAPTIONHELP:      str[0] = 0x73; break;
948     case DFCS_CAPTIONMIN:       str[0] = 0x30; break;
949     case DFCS_CAPTIONMAX:       str[0] = 0x31; break;
950     case DFCS_CAPTIONRESTORE:   str[0] = 0x32; break;
951     default:
952         WARN("Invalid caption; flags=0x%04x\n", uFlags);
953         return FALSE;
954     }
955     
956     hf = CreateFontW(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
957                     SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
958                     DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, glyphFontName);
959     alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
960     bksave = SetBkMode(dc, TRANSPARENT);
961     clrsave = GetTextColor(dc);
962     hfsave = SelectObject(dc, hf);
963     GetTextExtentPoint32W(dc, str, 1, &size);
964
965     if(uFlags & DFCS_INACTIVE)
966     {
967         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
968         TextOutW(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
969     }
970     SetTextColor(dc, GetSysColor(colorIdx));
971     TextOutW(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
972
973     SelectObject(dc, hfsave);
974     SetTextColor(dc, clrsave);
975     SetBkMode(dc, bksave);
976     SetTextAlign(dc, alignsave);
977     DeleteObject(hf);
978   
979     return TRUE;
980 }
981
982
983 /************************************************************************
984  *      UITOOLS_DrawFrameScroll
985  *
986  * Draw a scroll-bar control coming from DrawFrameControl()
987  */
988 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
989 {
990     POINT Line[4];
991     RECT myr;
992     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
993     int i;
994     HBRUSH hbsave, hb, hb2;
995     HPEN hpsave, hp, hp2;
996     int tri = 290*SmallDiam/1000 - 1;
997     int d46, d93;
998
999     /*
1000      * This fixes a problem with really tiny "scroll" buttons. In particular
1001      * with the updown control.
1002      * Making sure that the arrow is as least 3 pixels wide (or high).
1003      */
1004     tri = max( 2, tri );
1005
1006     switch(uFlags & 0xff)
1007     {
1008     case DFCS_SCROLLCOMBOBOX:
1009     case DFCS_SCROLLDOWN:
1010         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1011         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1012         Line[0].x = Line[2].x - tri;
1013         Line[1].x = Line[2].x + tri;
1014         Line[0].y = Line[1].y = Line[2].y - tri;
1015         break;
1016
1017     case DFCS_SCROLLUP:
1018         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1019         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1020         Line[0].x = Line[2].x - tri;
1021         Line[1].x = Line[2].x + tri;
1022         Line[0].y = Line[1].y = Line[2].y + tri;
1023         break;
1024
1025     case DFCS_SCROLLLEFT:
1026         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1027         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1028         Line[0].y = Line[2].y - tri;
1029         Line[1].y = Line[2].y + tri;
1030         Line[0].x = Line[1].x = Line[2].x + tri;
1031         break;
1032
1033     case DFCS_SCROLLRIGHT:
1034         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1035         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1036         Line[0].y = Line[2].y - tri;
1037         Line[1].y = Line[2].y + tri;
1038         Line[0].x = Line[1].x = Line[2].x - tri;
1039         break;
1040
1041     case DFCS_SCROLLSIZEGRIP:
1042         /* This one breaks the flow... */
1043         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1044         hpsave = SelectObject(dc, GetStockObject(NULL_PEN));
1045         hbsave = SelectObject(dc, GetStockObject(NULL_BRUSH));
1046         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1047         {
1048             hp = hp2 = SYSCOLOR_GetPen(COLOR_WINDOWFRAME);
1049             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1050         }
1051         else
1052         {
1053             hp  = SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT);
1054             hp2 = SYSCOLOR_GetPen(COLOR_BTNSHADOW);
1055             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1056             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1057         }
1058         Line[0].x = Line[1].x = r->right-1;
1059         Line[2].y = Line[3].y = r->bottom-1;
1060         d46 = 46*SmallDiam/750;
1061         d93 = 93*SmallDiam/750;
1062
1063         i = 586*SmallDiam/750;
1064         Line[0].y = r->bottom - i - 1;
1065         Line[3].x = r->right - i - 1;
1066         Line[1].y = Line[0].y + d46;
1067         Line[2].x = Line[3].x + d46;
1068         SelectObject(dc, hb);
1069         SelectObject(dc, hp);
1070         Polygon(dc, Line, 4);
1071
1072         Line[1].y++; Line[2].x++;
1073         Line[0].y = Line[1].y + d93;
1074         Line[3].x = Line[2].x + d93;
1075         SelectObject(dc, hb2);
1076         SelectObject(dc, hp2);
1077         Polygon(dc, Line, 4);
1078
1079         i = 398*SmallDiam/750;
1080         Line[0].y = r->bottom - i - 1;
1081         Line[3].x = r->right - i - 1;
1082         Line[1].y = Line[0].y + d46;
1083         Line[2].x = Line[3].x + d46;
1084         SelectObject(dc, hb);
1085         SelectObject(dc, hp);
1086         Polygon(dc, Line, 4);
1087
1088         Line[1].y++; Line[2].x++;
1089         Line[0].y = Line[1].y + d93;
1090         Line[3].x = Line[2].x + d93;
1091         SelectObject(dc, hb2);
1092         SelectObject(dc, hp2);
1093         Polygon(dc, Line, 4);
1094
1095         i = 210*SmallDiam/750;
1096         Line[0].y = r->bottom - i - 1;
1097         Line[3].x = r->right - i - 1;
1098         Line[1].y = Line[0].y + d46;
1099         Line[2].x = Line[3].x + d46;
1100         SelectObject(dc, hb);
1101         SelectObject(dc, hp);
1102         Polygon(dc, Line, 4);
1103
1104         Line[1].y++; Line[2].x++;
1105         Line[0].y = Line[1].y + d93;
1106         Line[3].x = Line[2].x + d93;
1107         SelectObject(dc, hb2);
1108         SelectObject(dc, hp2);
1109         Polygon(dc, Line, 4);
1110
1111         SelectObject(dc, hpsave);
1112         SelectObject(dc, hbsave);
1113         return TRUE;
1114
1115     default:
1116         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1117         return FALSE;
1118     }
1119
1120     /* Here do the real scroll-bar controls end up */
1121     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1122       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1123       /* want for the normal scroll-arrow button. */
1124       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1125     else
1126       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1127
1128     if(uFlags & DFCS_INACTIVE)
1129     {
1130         hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1131         hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1132         Polygon(dc, Line, 3);
1133         SelectObject(dc, hpsave);
1134         SelectObject(dc, hbsave);
1135     }
1136
1137     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1138       for(i = 0; i < 3; i++)
1139       {
1140         Line[i].x--;
1141         Line[i].y--;
1142       }
1143
1144     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1145     hbsave = SelectObject(dc, GetSysColorBrush(i));
1146     hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
1147     Polygon(dc, Line, 3);
1148     SelectObject(dc, hpsave);
1149     SelectObject(dc, hbsave);
1150
1151     return TRUE;
1152 }
1153
1154 /************************************************************************
1155  *      UITOOLS_DrawFrameMenu
1156  *
1157  * Draw a menu control coming from DrawFrameControl()
1158  */
1159 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1160 {
1161     POINT Points[6];
1162     RECT myr;
1163     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1164     int i;
1165     HBRUSH hbsave;
1166     HPEN hpsave;
1167     int xe, ye;
1168     int xc, yc;
1169     BOOL retval = TRUE;
1170
1171     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1172     /* use anything else. I think I tried all sys-colors to change things */
1173     /* without luck. It seems as if this behavior is inherited from the */
1174     /* win31 DFC() implementation... (you remember, B/W menus). */
1175
1176     FillRect(dc, r, GetStockObject(WHITE_BRUSH));
1177
1178     hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
1179     hpsave = SelectObject(dc, GetStockObject(BLACK_PEN));
1180
1181     switch(uFlags & 0xff)
1182     {
1183     case DFCS_MENUARROW:
1184         i = 187*SmallDiam/750;
1185         Points[2].x = myr.left + 468*SmallDiam/750;
1186         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1187         Points[0].y = Points[2].y - i;
1188         Points[1].y = Points[2].y + i;
1189         Points[0].x = Points[1].x = Points[2].x - i;
1190         Polygon(dc, Points, 3);
1191         break;
1192
1193     case DFCS_MENUBULLET:
1194         xe = myr.left;
1195         ye = myr.top  + SmallDiam - SmallDiam/2;
1196         xc = myr.left + SmallDiam - SmallDiam/2;
1197         yc = myr.top  + SmallDiam - SmallDiam/2;
1198         i = 234*SmallDiam/750;
1199         i = i < 1 ? 1 : i;
1200         myr.left   = xc - i+i/2;
1201         myr.right  = xc + i/2;
1202         myr.top    = yc - i+i/2;
1203         myr.bottom = yc + i/2;
1204         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1205         break;
1206
1207     case DFCS_MENUCHECK:
1208         Points[0].x = myr.left + 253*SmallDiam/1000;
1209         Points[0].y = myr.top  + 445*SmallDiam/1000;
1210         Points[1].x = myr.left + 409*SmallDiam/1000;
1211         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1212         Points[2].x = myr.left + 690*SmallDiam/1000;
1213         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1214         Points[3].x = Points[2].x;
1215         Points[3].y = Points[2].y + 3*SmallDiam/16;
1216         Points[4].x = Points[1].x;
1217         Points[4].y = Points[1].y + 3*SmallDiam/16;
1218         Points[5].x = Points[0].x;
1219         Points[5].y = Points[0].y + 3*SmallDiam/16;
1220         Polygon(dc, Points, 6);
1221         break;
1222
1223     default:
1224         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1225         retval = FALSE;
1226         break;
1227     }
1228
1229     SelectObject(dc, hpsave);
1230     SelectObject(dc, hbsave);
1231     return retval;
1232 }
1233
1234
1235 /**********************************************************************
1236  *          DrawFrameControl  (USER32.@)
1237  */
1238 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1239                                   UINT uState )
1240 {
1241     switch(uType)
1242     {
1243     case DFC_BUTTON:
1244       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1245     case DFC_CAPTION:
1246       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1247     case DFC_MENU:
1248       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1249     /*case DFC_POPUPMENU:
1250       FIXME("DFC_POPUPMENU: not implemented\n");
1251       break;*/
1252     case DFC_SCROLL:
1253       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1254     default:
1255       WARN("(%p,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1256     }
1257     return FALSE;
1258 }
1259
1260
1261 /***********************************************************************
1262  *              SetRect (USER32.@)
1263  */
1264 BOOL WINAPI SetRect( LPRECT rect, INT left, INT top,
1265                        INT right, INT bottom )
1266 {
1267     if (!rect) return FALSE;
1268     rect->left   = left;
1269     rect->right  = right;
1270     rect->top    = top;
1271     rect->bottom = bottom;
1272     return TRUE;
1273 }
1274
1275
1276 /***********************************************************************
1277  *              SetRectEmpty (USER32.@)
1278  */
1279 BOOL WINAPI SetRectEmpty( LPRECT rect )
1280 {
1281     if (!rect) return FALSE;
1282     rect->left = rect->right = rect->top = rect->bottom = 0;
1283     return TRUE;
1284 }
1285
1286
1287 /***********************************************************************
1288  *              CopyRect (USER32.@)
1289  */
1290 BOOL WINAPI CopyRect( RECT *dest, const RECT *src )
1291 {
1292     if (!dest || !src) return FALSE;
1293     *dest = *src;
1294     return TRUE;
1295 }
1296
1297
1298 /***********************************************************************
1299  *              IsRectEmpty (USER32.@)
1300  *
1301  * Bug compat: Windows checks for 0 or negative width/height.
1302  */
1303 BOOL WINAPI IsRectEmpty( const RECT *rect )
1304 {
1305     if (!rect) return TRUE;
1306     return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
1307 }
1308
1309
1310 /***********************************************************************
1311  *              PtInRect (USER32.@)
1312  */
1313 BOOL WINAPI PtInRect( const RECT *rect, POINT pt )
1314 {
1315     if (!rect) return FALSE;
1316     return ((pt.x >= rect->left) && (pt.x < rect->right) &&
1317             (pt.y >= rect->top) && (pt.y < rect->bottom));
1318 }
1319
1320
1321 /***********************************************************************
1322  *              OffsetRect (USER32.@)
1323  */
1324 BOOL WINAPI OffsetRect( LPRECT rect, INT x, INT y )
1325 {
1326     if (!rect) return FALSE;
1327     rect->left   += x;
1328     rect->right  += x;
1329     rect->top    += y;
1330     rect->bottom += y;
1331     return TRUE;
1332 }
1333
1334
1335 /***********************************************************************
1336  *              InflateRect (USER32.@)
1337  */
1338 BOOL WINAPI InflateRect( LPRECT rect, INT x, INT y )
1339 {
1340     if (!rect) return FALSE;
1341     rect->left   -= x;
1342     rect->top    -= y;
1343     rect->right  += x;
1344     rect->bottom += y;
1345     return TRUE;
1346 }
1347
1348
1349 /***********************************************************************
1350  *              IntersectRect (USER32.@)
1351  */
1352 BOOL WINAPI IntersectRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1353 {
1354     if (!dest || !src1 || !src2) return FALSE;
1355     if (IsRectEmpty(src1) || IsRectEmpty(src2) ||
1356         (src1->left >= src2->right) || (src2->left >= src1->right) ||
1357         (src1->top >= src2->bottom) || (src2->top >= src1->bottom))
1358     {
1359         SetRectEmpty( dest );
1360         return FALSE;
1361     }
1362     dest->left   = max( src1->left, src2->left );
1363     dest->right  = min( src1->right, src2->right );
1364     dest->top    = max( src1->top, src2->top );
1365     dest->bottom = min( src1->bottom, src2->bottom );
1366     return TRUE;
1367 }
1368
1369
1370 /***********************************************************************
1371  *              UnionRect (USER32.@)
1372  */
1373 BOOL WINAPI UnionRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1374 {
1375     if (!dest) return FALSE;
1376     if (IsRectEmpty(src1))
1377     {
1378         if (IsRectEmpty(src2))
1379         {
1380             SetRectEmpty( dest );
1381             return FALSE;
1382         }
1383         else *dest = *src2;
1384     }
1385     else
1386     {
1387         if (IsRectEmpty(src2)) *dest = *src1;
1388         else
1389         {
1390             dest->left   = min( src1->left, src2->left );
1391             dest->right  = max( src1->right, src2->right );
1392             dest->top    = min( src1->top, src2->top );
1393             dest->bottom = max( src1->bottom, src2->bottom );
1394         }
1395     }
1396     return TRUE;
1397 }
1398
1399
1400 /***********************************************************************
1401  *              EqualRect (USER32.@)
1402  */
1403 BOOL WINAPI EqualRect( const RECT* rect1, const RECT* rect2 )
1404 {
1405     if (!rect1 || !rect2) return FALSE;
1406     return ((rect1->left == rect2->left) && (rect1->right == rect2->right) &&
1407             (rect1->top == rect2->top) && (rect1->bottom == rect2->bottom));
1408 }
1409
1410
1411 /***********************************************************************
1412  *              SubtractRect (USER32.@)
1413  */
1414 BOOL WINAPI SubtractRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1415 {
1416     RECT tmp;
1417
1418     if (!dest) return FALSE;
1419     if (IsRectEmpty( src1 ))
1420     {
1421         SetRectEmpty( dest );
1422         return FALSE;
1423     }
1424     *dest = *src1;
1425     if (IntersectRect( &tmp, src1, src2 ))
1426     {
1427         if (EqualRect( &tmp, dest ))
1428         {
1429             SetRectEmpty( dest );
1430             return FALSE;
1431         }
1432         if ((tmp.top == dest->top) && (tmp.bottom == dest->bottom))
1433         {
1434             if (tmp.left == dest->left) dest->left = tmp.right;
1435             else if (tmp.right == dest->right) dest->right = tmp.left;
1436         }
1437         else if ((tmp.left == dest->left) && (tmp.right == dest->right))
1438         {
1439             if (tmp.top == dest->top) dest->top = tmp.bottom;
1440             else if (tmp.bottom == dest->bottom) dest->bottom = tmp.top;
1441         }
1442     }
1443     return TRUE;
1444 }
1445
1446
1447 /***********************************************************************
1448  *              FillRect (USER32.@)
1449  */
1450 INT WINAPI FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1451 {
1452     HBRUSH prev_brush;
1453
1454     if (hbrush <= (HBRUSH) (COLOR_MAX + 1)) hbrush = GetSysColorBrush( HandleToULong(hbrush) - 1 );
1455
1456     prev_brush = SelectObject( hdc, hbrush );
1457     PatBlt( hdc, rect->left, rect->top,
1458               rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
1459     if (prev_brush) SelectObject( hdc, prev_brush );
1460     return 1;
1461 }
1462
1463
1464 /***********************************************************************
1465  *              InvertRect (USER32.@)
1466  */
1467 BOOL WINAPI InvertRect( HDC hdc, const RECT *rect )
1468 {
1469     return PatBlt( hdc, rect->left, rect->top,
1470                    rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
1471 }
1472
1473
1474 /***********************************************************************
1475  *              FrameRect (USER32.@)
1476  */
1477 INT WINAPI FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1478 {
1479     HBRUSH prevBrush;
1480     RECT r = *rect;
1481
1482     if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
1483     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
1484
1485     PatBlt( hdc, r.left, r.top, 1, r.bottom - r.top, PATCOPY );
1486     PatBlt( hdc, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY );
1487     PatBlt( hdc, r.left, r.top, r.right - r.left, 1, PATCOPY );
1488     PatBlt( hdc, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY );
1489
1490     SelectObject( hdc, prevBrush );
1491     return TRUE;
1492 }
1493
1494
1495 /***********************************************************************
1496  *              DrawFocusRect (USER32.@)
1497  *
1498  * FIXME: PatBlt(PATINVERT) with background brush.
1499  */
1500 BOOL WINAPI DrawFocusRect( HDC hdc, const RECT* rc )
1501 {
1502     HBRUSH hOldBrush;
1503     HPEN hOldPen, hNewPen;
1504     INT oldDrawMode, oldBkMode;
1505     LOGBRUSH lb;
1506
1507     hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
1508     lb.lbStyle = BS_SOLID;
1509     lb.lbColor = 0;
1510     hNewPen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
1511     hOldPen = SelectObject(hdc, hNewPen);
1512     oldDrawMode = SetROP2(hdc, R2_NOT);
1513     oldBkMode = SetBkMode(hdc, TRANSPARENT);
1514
1515     Rectangle(hdc, rc->left, rc->top, rc->right, rc->bottom);
1516
1517     SetBkMode(hdc, oldBkMode);
1518     SetROP2(hdc, oldDrawMode);
1519     SelectObject(hdc, hOldPen);
1520     DeleteObject(hNewPen);
1521     SelectObject(hdc, hOldBrush);
1522
1523     return TRUE;
1524 }
1525
1526
1527 /**********************************************************************
1528  *              DrawAnimatedRects (USER32.@)
1529  */
1530 BOOL WINAPI DrawAnimatedRects( HWND hwnd, INT idAni, const RECT* lprcFrom, const RECT* lprcTo )
1531 {
1532     FIXME("(%p,%d,%p,%p): stub\n",hwnd,idAni,lprcFrom,lprcTo);
1533     return TRUE;
1534 }
1535
1536
1537 /**********************************************************************
1538  *          UITOOLS_DrawStateJam
1539  *
1540  * Jams in the requested type in the dc
1541  */
1542 static BOOL UITOOLS_DrawStateJam( HDC hdc, UINT opcode, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1543                                   LPRECT rc, UINT dtflags, BOOL unicode )
1544 {
1545     HDC memdc;
1546     HBITMAP hbmsave;
1547     BOOL retval;
1548     INT cx = rc->right - rc->left;
1549     INT cy = rc->bottom - rc->top;
1550
1551     switch(opcode)
1552     {
1553     case DST_TEXT:
1554     case DST_PREFIXTEXT:
1555         if(unicode)
1556             return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1557         else
1558             return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1559
1560     case DST_ICON:
1561         return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, 0, 0, 0, NULL, DI_NORMAL);
1562
1563     case DST_BITMAP:
1564         memdc = CreateCompatibleDC(hdc);
1565         if(!memdc) return FALSE;
1566         hbmsave = SelectObject(memdc, (HBITMAP)lp);
1567         if(!hbmsave)
1568         {
1569             DeleteDC(memdc);
1570             return FALSE;
1571         }
1572         retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1573         SelectObject(memdc, hbmsave);
1574         DeleteDC(memdc);
1575         return retval;
1576
1577     case DST_COMPLEX:
1578         if(func) {
1579             BOOL bRet;
1580             /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */
1581
1582             OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1583             bRet = func(hdc, lp, wp, cx, cy);
1584             /* Restore origin */
1585             OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1586             return bRet;
1587         } else
1588             return FALSE;
1589     }
1590     return FALSE;
1591 }
1592
1593 /**********************************************************************
1594  *      UITOOLS_DrawState()
1595  */
1596 static BOOL UITOOLS_DrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1597                               INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode )
1598 {
1599     HBITMAP hbm, hbmsave;
1600     HFONT hfsave;
1601     HBRUSH hbsave, hbrtmp = 0;
1602     HDC memdc;
1603     RECT rc;
1604     UINT dtflags = DT_NOCLIP;
1605     COLORREF fg, bg;
1606     UINT opcode = flags & 0xf;
1607     INT len = wp;
1608     BOOL retval, tmp;
1609
1610     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1611     {
1612         if (!lp) return FALSE;
1613
1614         if(unicode)
1615             len = strlenW((LPWSTR)lp);
1616         else
1617             len = strlen((LPSTR)lp);
1618     }
1619
1620     /* Find out what size the image has if not given by caller */
1621     if(!cx || !cy)
1622     {
1623         SIZE s;
1624         BITMAP bm;
1625
1626         switch(opcode)
1627         {
1628         case DST_TEXT:
1629         case DST_PREFIXTEXT:
1630             if(unicode)
1631                 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1632             else
1633                 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1634             if(!retval) return FALSE;
1635             break;
1636
1637         case DST_ICON:
1638             if (!get_icon_size( (HICON)lp, &s )) return FALSE;
1639             break;
1640
1641         case DST_BITMAP:
1642             if(!GetObjectA((HBITMAP)lp, sizeof(bm), &bm)) return FALSE;
1643             s.cx = bm.bmWidth;
1644             s.cy = bm.bmHeight;
1645             break;
1646
1647         case DST_COMPLEX: /* cx and cy must be set in this mode */
1648             return FALSE;
1649         }
1650
1651         if(!cx) cx = s.cx;
1652         if(!cy) cy = s.cy;
1653     }
1654
1655     rc.left   = x;
1656     rc.top    = y;
1657     rc.right  = x + cx;
1658     rc.bottom = y + cy;
1659
1660     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1661         dtflags |= DT_RIGHT;
1662     if(opcode == DST_TEXT)
1663         dtflags |= DT_NOPREFIX;
1664
1665     /* For DSS_NORMAL we just jam in the image and return */
1666     if((flags & 0x7ff0) == DSS_NORMAL)
1667     {
1668         return UITOOLS_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1669     }
1670
1671     /* For all other states we need to convert the image to B/W in a local bitmap */
1672     /* before it is displayed */
1673     fg = SetTextColor(hdc, RGB(0, 0, 0));
1674     bg = SetBkColor(hdc, RGB(255, 255, 255));
1675     hbm = NULL; hbmsave = NULL;
1676     memdc = NULL; hbsave = NULL;
1677     retval = FALSE; /* assume failure */
1678
1679     /* From here on we must use "goto cleanup" when something goes wrong */
1680     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1681     if(!hbm) goto cleanup;
1682     memdc   = CreateCompatibleDC(hdc);
1683     if(!memdc) goto cleanup;
1684     hbmsave = SelectObject(memdc, hbm);
1685     if(!hbmsave) goto cleanup;
1686     rc.left = rc.top = 0;
1687     rc.right = cx;
1688     rc.bottom = cy;
1689     if(!FillRect(memdc, &rc, GetStockObject(WHITE_BRUSH))) goto cleanup;
1690     SetBkColor(memdc, RGB(255, 255, 255));
1691     SetTextColor(memdc, RGB(0, 0, 0));
1692     hfsave  = SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1693
1694     /* DST_COMPLEX may draw text as well,
1695      * so we must be sure that correct font is selected
1696      */
1697     if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1698     tmp = UITOOLS_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1699     if(hfsave) SelectObject(memdc, hfsave);
1700     if(!tmp) goto cleanup;
1701
1702     /* This state cause the image to be dithered */
1703     if(flags & DSS_UNION)
1704     {
1705         hbsave = SelectObject(memdc, SYSCOLOR_55AABrush);
1706         if(!hbsave) goto cleanup;
1707         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1708         SelectObject(memdc, hbsave);
1709         if(!tmp) goto cleanup;
1710     }
1711
1712     if (flags & DSS_DISABLED)
1713        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1714     else if (flags & DSS_DEFAULT)
1715        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1716
1717     /* Draw light or dark shadow */
1718     if (flags & (DSS_DISABLED|DSS_DEFAULT))
1719     {
1720        if(!hbrtmp) goto cleanup;
1721        hbsave = SelectObject(hdc, hbrtmp);
1722        if(!hbsave) goto cleanup;
1723        if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1724        SelectObject(hdc, hbsave);
1725        DeleteObject(hbrtmp);
1726        hbrtmp = 0;
1727     }
1728
1729     if (flags & DSS_DISABLED)
1730     {
1731        hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1732        if(!hbrtmp) goto cleanup;
1733     }
1734     else if (!hbr)
1735     {
1736        hbr = GetStockObject(BLACK_BRUSH);
1737     }
1738
1739     hbsave = SelectObject(hdc, hbr);
1740
1741     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1742
1743     retval = TRUE; /* We succeeded */
1744
1745 cleanup:
1746     SetTextColor(hdc, fg);
1747     SetBkColor(hdc, bg);
1748
1749     if(hbsave)  SelectObject(hdc, hbsave);
1750     if(hbmsave) SelectObject(memdc, hbmsave);
1751     if(hbrtmp)  DeleteObject(hbrtmp);
1752     if(hbm)     DeleteObject(hbm);
1753     if(memdc)   DeleteDC(memdc);
1754
1755     return retval;
1756 }
1757
1758 /**********************************************************************
1759  *              DrawStateA (USER32.@)
1760  */
1761 BOOL WINAPI DrawStateA(HDC hdc, HBRUSH hbr,
1762                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1763                    INT x, INT y, INT cx, INT cy, UINT flags)
1764 {
1765     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, FALSE);
1766 }
1767
1768 /**********************************************************************
1769  *              DrawStateW (USER32.@)
1770  */
1771 BOOL WINAPI DrawStateW(HDC hdc, HBRUSH hbr,
1772                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1773                    INT x, INT y, INT cx, INT cy, UINT flags)
1774 {
1775     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, TRUE);
1776 }