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