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