user32: Draw the rect edges from left to right and top to bottom.
[wine] / dlls / user32 / uitools.c
1 /*
2  * User Interface Functions
3  *
4  * Copyright 1997 Dimitrie O. Paun
5  * Copyright 1997 Bertho A. Stultiens
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "user_private.h"
29 #include "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 = GetStockObject(NULL_PEN);
145     SavePen = 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 = SelectObject(hdc, hb);
341         hpsave = 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 awful 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 = GetStockObject(NULL_PEN);
457     SavePen = 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.left, InnerRect.bottom-1, NULL);
515         LineTo(hdc, InnerRect.right-1, InnerRect.bottom-1);
516     }
517     if(uFlags & BF_RIGHT)
518     {
519         MoveToEx(hdc, InnerRect.right-1, InnerRect.top, NULL);
520         LineTo(hdc, InnerRect.right-1, InnerRect.bottom);
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.left+LBpenplus, InnerRect.bottom-2, NULL);
539         LineTo(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2);
540     }
541     if(uFlags & BF_RIGHT)
542     {
543         MoveToEx(hdc, InnerRect.right-2, InnerRect.top+2-RBpenplus, NULL);
544         LineTo(hdc, InnerRect.right-2, InnerRect.bottom-2+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 %s %04x %04x\n", hdc, wine_dbgstr_rect(rc), edge, flags );
580
581     if(flags & BF_DIAGONAL)
582       return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
583     else
584       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
585 }
586
587
588 /************************************************************************
589  *      UITOOLS_MakeSquareRect
590  *
591  * Utility to create a square rectangle and returning the width
592  */
593 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
594 {
595     int Width  = src->right - src->left;
596     int Height = src->bottom - src->top;
597     int SmallDiam = Width > Height ? Height : Width;
598
599     *dst = *src;
600
601     /* Make it a square box */
602     if(Width < Height)      /* SmallDiam == Width */
603     {
604         dst->top += (Height-Width)/2;
605         dst->bottom = dst->top + SmallDiam;
606     }
607     else if(Width > Height) /* SmallDiam == Height */
608     {
609         dst->left += (Width-Height)/2;
610         dst->right = dst->left + SmallDiam;
611     }
612
613    return SmallDiam;
614 }
615
616 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
617 {
618     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
619     {
620       HBRUSH hbsave;
621       COLORREF bg;
622
623       FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
624       bg = SetBkColor(dc, RGB(255, 255, 255));
625       hbsave = SelectObject(dc, SYSCOLOR_55AABrush);
626       PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
627       SelectObject(dc, hbsave);
628       SetBkColor(dc, bg);
629     }
630     else
631     {
632         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
633     }
634 }
635
636 /************************************************************************
637  *      UITOOLS_DFC_ButtonPush
638  *
639  * Draw a push button coming from DrawFrameControl()
640  *
641  * Does a pretty good job in emulating MS behavior. Some quirks are
642  * however there because MS uses a TrueType font (Marlett) to draw
643  * the buttons.
644  */
645 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
646 {
647     UINT edge;
648     RECT myr = *r;
649
650     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
651         edge = EDGE_SUNKEN;
652     else
653         edge = EDGE_RAISED;
654
655     if(uFlags & DFCS_CHECKED)
656     {
657         if(uFlags & DFCS_MONO)
658             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
659         else
660             UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
661
662         if (!(uFlags & DFCS_TRANSPARENT))
663             UITOOLS_DrawCheckedRect( dc, &myr );
664     }
665     else
666     {
667         if(uFlags & DFCS_MONO)
668         {
669             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
670             if (!(uFlags & DFCS_TRANSPARENT))
671                 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
672         }
673         else
674         {
675             UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags & DFCS_FLAT) | ((uFlags & DFCS_TRANSPARENT) ? 0 : BF_MIDDLE) | BF_RECT | BF_SOFT);
676         }
677     }
678
679     /* Adjust rectangle if asked */
680     if(uFlags & DFCS_ADJUSTRECT)
681     {
682         r->left   += 2;
683         r->right  -= 2;
684         r->top    += 2;
685         r->bottom -= 2;
686     }
687
688     return TRUE;
689 }
690
691
692 /************************************************************************
693  *      UITOOLS_DFC_ButtonChcek
694  *
695  * Draw a check/3state button coming from DrawFrameControl()
696  *
697  * Does a pretty good job in emulating MS behavior. Some quirks are
698  * however there because MS uses a TrueType font (Marlett) to draw
699  * the buttons.
700  */
701
702 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
703 {
704     RECT myr, bar;
705     UINT flags = BF_RECT | BF_ADJUST;
706
707     UITOOLS_MakeSquareRect(r, &myr);
708
709     if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
710     else if(uFlags & DFCS_MONO) flags |= BF_MONO;
711
712     UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
713
714     if (!(uFlags & DFCS_TRANSPARENT))
715     {
716         if(uFlags & (DFCS_INACTIVE | DFCS_PUSHED))
717             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
718         else if( (uFlags & DFCS_BUTTON3STATE) && (uFlags & DFCS_CHECKED) )
719             UITOOLS_DrawCheckedRect( dc, &myr );
720         else
721             FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
722     }
723
724     if(uFlags & DFCS_CHECKED)
725     {
726         int i, k;
727         i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
728                 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
729
730         /* draw 7 bars, with h=3w to form the check */
731         bar.left = myr.left;
732         bar.top = myr.top + 2;
733         for (k = 0; k < 7; k++) {
734             bar.left = bar.left + 1;
735             bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
736             bar.bottom = bar.top + 3;
737             bar.right = bar.left + 1;
738             FillRect(dc, &bar, GetSysColorBrush(i));
739         }
740     }
741     return TRUE;
742 }
743
744
745 /************************************************************************
746  *      UITOOLS_DFC_ButtonRadio
747  *
748  * Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
749  *
750  * Does a pretty good job in emulating MS behavior. Some quirks are
751  * however there because MS uses a TrueType font (Marlett) to draw
752  * the buttons.
753  */
754 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
755 {
756     RECT myr;
757     int i;
758     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
759     int BorderShrink = SmallDiam / 16;
760     HPEN hpsave;
761     HBRUSH hbsave;
762     int xc, yc;
763
764     if(BorderShrink < 1) BorderShrink = 1;
765
766     if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
767         FillRect(dc, r, GetStockObject(BLACK_BRUSH));
768
769     xc = myr.left + SmallDiam - SmallDiam/2;
770     yc = myr.top  + SmallDiam - SmallDiam/2;
771
772     /* Define bounding box */
773     i = 14*SmallDiam/16;
774     myr.left   = xc - i+i/2;
775     myr.right  = xc + i/2;
776     myr.top    = yc - i+i/2;
777     myr.bottom = yc + i/2;
778
779     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
780     {
781         hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
782         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
783         SelectObject(dc, hbsave);
784     }
785     else
786     {
787         if(uFlags & (DFCS_FLAT|DFCS_MONO))
788         {
789             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
790             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
791             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
792             SelectObject(dc, hbsave);
793             SelectObject(dc, hpsave);
794         }
795         else
796         {
797             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
798             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
799             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
800
801             SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNSHADOW));
802             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
803             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
804
805             myr.left   += BorderShrink;
806             myr.right  -= BorderShrink;
807             myr.top    += BorderShrink;
808             myr.bottom -= BorderShrink;
809
810             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DLIGHT));
811             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
812             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
813
814             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DDKSHADOW));
815             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
816             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
817             SelectObject(dc, hbsave);
818             SelectObject(dc, hpsave);
819         }
820
821         i = 10*SmallDiam/16;
822         myr.left   = xc - i+i/2;
823         myr.right  = xc + i/2;
824         myr.top    = yc - i+i/2;
825         myr.bottom = yc + i/2;
826         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
827         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
828         hbsave = SelectObject(dc, GetSysColorBrush(i));
829         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
830         SelectObject(dc, hbsave);
831         SelectObject(dc, hpsave);
832     }
833
834     if(uFlags & DFCS_CHECKED)
835     {
836         i = 6*SmallDiam/16;
837         i = i < 1 ? 1 : i;
838         myr.left   = xc - i+i/2;
839         myr.right  = xc + i/2;
840         myr.top    = yc - i+i/2;
841         myr.bottom = yc + i/2;
842
843         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
844         hbsave = SelectObject(dc, GetSysColorBrush(i));
845         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
846         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
847         SelectObject(dc, hpsave);
848         SelectObject(dc, hbsave);
849     }
850
851     /* FIXME: M$ has a polygon in the center at relative points: */
852     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
853     /* 0.476, 0.525 */
854     /* 0.500, 0.500 */
855     /* 0.500, 0.499 */
856     /* when the button is unchecked. The reason for it is unknown. The */
857     /* color is COLOR_BTNHIGHLIGHT, although the polygon gets painted at */
858     /* least 3 times (it looks like a clip-region when you see it happen). */
859     /* I do not really see a reason why this should be implemented. If you */
860     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
861     /* font. */
862
863     return TRUE;
864 }
865
866 /***********************************************************************
867  *           UITOOLS_DrawFrameButton
868  */
869 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
870 {
871     switch(uState & 0xff)
872     {
873     case DFCS_BUTTONPUSH:
874         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
875
876     case DFCS_BUTTONCHECK:
877     case DFCS_BUTTON3STATE:
878         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
879
880     case DFCS_BUTTONRADIOIMAGE:
881     case DFCS_BUTTONRADIOMASK:
882     case DFCS_BUTTONRADIO:
883         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
884
885     default:
886         WARN("Invalid button state=0x%04x\n", uState);
887     }
888
889     return FALSE;
890 }
891
892 /***********************************************************************
893  *           UITOOLS_DrawFrameCaption
894  *
895  * Draw caption buttons (win95), coming from DrawFrameControl()
896  */
897
898 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
899 {
900     RECT myr;
901     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
902     HFONT hfsave, hf;
903     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
904     int xc = (myr.left+myr.right)/2;
905     int yc = (myr.top+myr.bottom)/2;
906     WCHAR str[2] = {0, 0};
907     static const WCHAR glyphFontName[] = { 'M','a','r','l','e','t','t',0 };
908     UINT alignsave;
909     int bksave;
910     COLORREF clrsave;
911     SIZE size;
912
913     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
914
915     switch(uFlags & 0xff)
916     {
917     case DFCS_CAPTIONCLOSE:     str[0] = 0x72; break;
918     case DFCS_CAPTIONHELP:      str[0] = 0x73; break;
919     case DFCS_CAPTIONMIN:       str[0] = 0x30; break;
920     case DFCS_CAPTIONMAX:       str[0] = 0x31; break;
921     case DFCS_CAPTIONRESTORE:   str[0] = 0x32; break;
922     default:
923         WARN("Invalid caption; flags=0x%04x\n", uFlags);
924         return FALSE;
925     }
926     
927     hf = CreateFontW(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
928                     SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
929                     DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, glyphFontName);
930     alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
931     bksave = SetBkMode(dc, TRANSPARENT);
932     clrsave = GetTextColor(dc);
933     hfsave = SelectObject(dc, hf);
934     GetTextExtentPoint32W(dc, str, 1, &size);
935
936     if(uFlags & DFCS_INACTIVE)
937     {
938         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
939         TextOutW(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
940     }
941     SetTextColor(dc, GetSysColor(colorIdx));
942     TextOutW(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
943
944     SelectObject(dc, hfsave);
945     SetTextColor(dc, clrsave);
946     SetBkMode(dc, bksave);
947     SetTextAlign(dc, alignsave);
948     DeleteObject(hf);
949   
950     return TRUE;
951 }
952
953
954 /************************************************************************
955  *      UITOOLS_DrawFrameScroll
956  *
957  * Draw a scroll-bar control coming from DrawFrameControl()
958  */
959 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
960 {
961     POINT Line[4];
962     RECT myr;
963     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
964     int i;
965     HBRUSH hbsave, hb, hb2;
966     HPEN hpsave, hp, hp2;
967     int tri = 290*SmallDiam/1000 - 1;
968     int d46, d93;
969
970     /*
971      * This fixes a problem with really tiny "scroll" buttons. In particular
972      * with the updown control.
973      * Making sure that the arrow is as least 3 pixels wide (or high).
974      */
975     if (tri == 0)
976       tri = 1;
977
978     switch(uFlags & 0xff)
979     {
980     case DFCS_SCROLLCOMBOBOX:
981     case DFCS_SCROLLDOWN:
982         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
983         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
984         Line[0].x = Line[2].x - tri;
985         Line[1].x = Line[2].x + tri;
986         Line[0].y = Line[1].y = Line[2].y - tri;
987         break;
988
989     case DFCS_SCROLLUP:
990         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
991         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
992         Line[0].x = Line[2].x - tri;
993         Line[1].x = Line[2].x + tri;
994         Line[0].y = Line[1].y = Line[2].y + tri;
995         break;
996
997     case DFCS_SCROLLLEFT:
998         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
999         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1000         Line[0].y = Line[2].y - tri;
1001         Line[1].y = Line[2].y + tri;
1002         Line[0].x = Line[1].x = Line[2].x + tri;
1003         break;
1004
1005     case DFCS_SCROLLRIGHT:
1006         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1007         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1008         Line[0].y = Line[2].y - tri;
1009         Line[1].y = Line[2].y + tri;
1010         Line[0].x = Line[1].x = Line[2].x - tri;
1011         break;
1012
1013     case DFCS_SCROLLSIZEGRIP:
1014         /* This one breaks the flow... */
1015         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1016         hpsave = SelectObject(dc, GetStockObject(NULL_PEN));
1017         hbsave = SelectObject(dc, GetStockObject(NULL_BRUSH));
1018         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1019         {
1020             hp = hp2 = SYSCOLOR_GetPen(COLOR_WINDOWFRAME);
1021             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1022         }
1023         else
1024         {
1025             hp  = SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT);
1026             hp2 = SYSCOLOR_GetPen(COLOR_BTNSHADOW);
1027             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1028             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1029         }
1030         Line[0].x = Line[1].x = r->right-1;
1031         Line[2].y = Line[3].y = r->bottom-1;
1032         d46 = 46*SmallDiam/750;
1033         d93 = 93*SmallDiam/750;
1034
1035         i = 586*SmallDiam/750;
1036         Line[0].y = r->bottom - i - 1;
1037         Line[3].x = r->right - i - 1;
1038         Line[1].y = Line[0].y + d46;
1039         Line[2].x = Line[3].x + d46;
1040         SelectObject(dc, hb);
1041         SelectObject(dc, hp);
1042         Polygon(dc, Line, 4);
1043
1044         Line[1].y++; Line[2].x++;
1045         Line[0].y = Line[1].y + d93;
1046         Line[3].x = Line[2].x + d93;
1047         SelectObject(dc, hb2);
1048         SelectObject(dc, hp2);
1049         Polygon(dc, Line, 4);
1050
1051         i = 398*SmallDiam/750;
1052         Line[0].y = r->bottom - i - 1;
1053         Line[3].x = r->right - i - 1;
1054         Line[1].y = Line[0].y + d46;
1055         Line[2].x = Line[3].x + d46;
1056         SelectObject(dc, hb);
1057         SelectObject(dc, hp);
1058         Polygon(dc, Line, 4);
1059
1060         Line[1].y++; Line[2].x++;
1061         Line[0].y = Line[1].y + d93;
1062         Line[3].x = Line[2].x + d93;
1063         SelectObject(dc, hb2);
1064         SelectObject(dc, hp2);
1065         Polygon(dc, Line, 4);
1066
1067         i = 210*SmallDiam/750;
1068         Line[0].y = r->bottom - i - 1;
1069         Line[3].x = r->right - i - 1;
1070         Line[1].y = Line[0].y + d46;
1071         Line[2].x = Line[3].x + d46;
1072         SelectObject(dc, hb);
1073         SelectObject(dc, hp);
1074         Polygon(dc, Line, 4);
1075
1076         Line[1].y++; Line[2].x++;
1077         Line[0].y = Line[1].y + d93;
1078         Line[3].x = Line[2].x + d93;
1079         SelectObject(dc, hb2);
1080         SelectObject(dc, hp2);
1081         Polygon(dc, Line, 4);
1082
1083         SelectObject(dc, hpsave);
1084         SelectObject(dc, hbsave);
1085         return TRUE;
1086
1087     default:
1088         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1089         return FALSE;
1090     }
1091
1092     /* Here do the real scroll-bar controls end up */
1093     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1094       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1095       /* want for the normal scroll-arrow button. */
1096       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1097     else
1098       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1099
1100     if(uFlags & DFCS_INACTIVE)
1101     {
1102         hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1103         hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1104         Polygon(dc, Line, 3);
1105         SelectObject(dc, hpsave);
1106         SelectObject(dc, hbsave);
1107     }
1108
1109     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1110       for(i = 0; i < 3; i++)
1111       {
1112         Line[i].x--;
1113         Line[i].y--;
1114       }
1115
1116     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1117     hbsave = SelectObject(dc, GetSysColorBrush(i));
1118     hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
1119     Polygon(dc, Line, 3);
1120     SelectObject(dc, hpsave);
1121     SelectObject(dc, hbsave);
1122
1123     return TRUE;
1124 }
1125
1126 /************************************************************************
1127  *      UITOOLS_DrawFrameMenu
1128  *
1129  * Draw a menu control coming from DrawFrameControl()
1130  */
1131 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1132 {
1133     POINT Points[6];
1134     RECT myr;
1135     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1136     int i;
1137     HBRUSH hbsave;
1138     HPEN hpsave;
1139     int xe, ye;
1140     int xc, yc;
1141     BOOL retval = TRUE;
1142
1143     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1144     /* use anything else. I think I tried all sys-colors to change things */
1145     /* without luck. It seems as if this behavior is inherited from the */
1146     /* win31 DFC() implementation... (you remember, B/W menus). */
1147
1148     FillRect(dc, r, GetStockObject(WHITE_BRUSH));
1149
1150     hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
1151     hpsave = SelectObject(dc, GetStockObject(BLACK_PEN));
1152
1153     switch(uFlags & 0xff)
1154     {
1155     case DFCS_MENUARROW:
1156         i = 187*SmallDiam/750;
1157         Points[2].x = myr.left + 468*SmallDiam/750;
1158         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1159         Points[0].y = Points[2].y - i;
1160         Points[1].y = Points[2].y + i;
1161         Points[0].x = Points[1].x = Points[2].x - i;
1162         Polygon(dc, Points, 3);
1163         break;
1164
1165     case DFCS_MENUBULLET:
1166         xe = myr.left;
1167         ye = myr.top  + SmallDiam - SmallDiam/2;
1168         xc = myr.left + SmallDiam - SmallDiam/2;
1169         yc = myr.top  + SmallDiam - SmallDiam/2;
1170         i = 234*SmallDiam/750;
1171         i = i < 1 ? 1 : i;
1172         myr.left   = xc - i+i/2;
1173         myr.right  = xc + i/2;
1174         myr.top    = yc - i+i/2;
1175         myr.bottom = yc + i/2;
1176         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1177         break;
1178
1179     case DFCS_MENUCHECK:
1180         Points[0].x = myr.left + 253*SmallDiam/1000;
1181         Points[0].y = myr.top  + 445*SmallDiam/1000;
1182         Points[1].x = myr.left + 409*SmallDiam/1000;
1183         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1184         Points[2].x = myr.left + 690*SmallDiam/1000;
1185         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1186         Points[3].x = Points[2].x;
1187         Points[3].y = Points[2].y + 3*SmallDiam/16;
1188         Points[4].x = Points[1].x;
1189         Points[4].y = Points[1].y + 3*SmallDiam/16;
1190         Points[5].x = Points[0].x;
1191         Points[5].y = Points[0].y + 3*SmallDiam/16;
1192         Polygon(dc, Points, 6);
1193         break;
1194
1195     default:
1196         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1197         retval = FALSE;
1198         break;
1199     }
1200
1201     SelectObject(dc, hpsave);
1202     SelectObject(dc, hbsave);
1203     return retval;
1204 }
1205
1206
1207 /**********************************************************************
1208  *          DrawFrameControl  (USER32.@)
1209  */
1210 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1211                                   UINT uState )
1212 {
1213     /* Win95 doesn't support drawing in other mapping modes */
1214     if(GetMapMode(hdc) != MM_TEXT)
1215         return FALSE;
1216
1217     switch(uType)
1218     {
1219     case DFC_BUTTON:
1220       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1221     case DFC_CAPTION:
1222       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1223     case DFC_MENU:
1224       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1225     /*case DFC_POPUPMENU:
1226       FIXME("DFC_POPUPMENU: not implemented\n");
1227       break;*/
1228     case DFC_SCROLL:
1229       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1230     default:
1231       WARN("(%p,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1232     }
1233     return FALSE;
1234 }
1235
1236
1237 /***********************************************************************
1238  *              SetRect (USER32.@)
1239  */
1240 BOOL WINAPI SetRect( LPRECT rect, INT left, INT top,
1241                        INT right, INT bottom )
1242 {
1243     if (!rect) return FALSE;
1244     rect->left   = left;
1245     rect->right  = right;
1246     rect->top    = top;
1247     rect->bottom = bottom;
1248     return TRUE;
1249 }
1250
1251
1252 /***********************************************************************
1253  *              SetRectEmpty (USER32.@)
1254  */
1255 BOOL WINAPI SetRectEmpty( LPRECT rect )
1256 {
1257     if (!rect) return FALSE;
1258     rect->left = rect->right = rect->top = rect->bottom = 0;
1259     return TRUE;
1260 }
1261
1262
1263 /***********************************************************************
1264  *              CopyRect (USER32.@)
1265  */
1266 BOOL WINAPI CopyRect( RECT *dest, const RECT *src )
1267 {
1268     if (!dest || !src) return FALSE;
1269     *dest = *src;
1270     return TRUE;
1271 }
1272
1273
1274 /***********************************************************************
1275  *              IsRectEmpty (USER32.@)
1276  *
1277  * Bug compat: Windows checks for 0 or negative width/height.
1278  */
1279 BOOL WINAPI IsRectEmpty( const RECT *rect )
1280 {
1281     if (!rect) return TRUE;
1282     return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
1283 }
1284
1285
1286 /***********************************************************************
1287  *              PtInRect (USER32.@)
1288  */
1289 BOOL WINAPI PtInRect( const RECT *rect, POINT pt )
1290 {
1291     if (!rect) return FALSE;
1292     return ((pt.x >= rect->left) && (pt.x < rect->right) &&
1293             (pt.y >= rect->top) && (pt.y < rect->bottom));
1294 }
1295
1296
1297 /***********************************************************************
1298  *              OffsetRect (USER32.@)
1299  */
1300 BOOL WINAPI OffsetRect( LPRECT rect, INT x, INT y )
1301 {
1302     if (!rect) return FALSE;
1303     rect->left   += x;
1304     rect->right  += x;
1305     rect->top    += y;
1306     rect->bottom += y;
1307     return TRUE;
1308 }
1309
1310
1311 /***********************************************************************
1312  *              InflateRect (USER32.@)
1313  */
1314 BOOL WINAPI InflateRect( LPRECT rect, INT x, INT y )
1315 {
1316     if (!rect) return FALSE;
1317     rect->left   -= x;
1318     rect->top    -= y;
1319     rect->right  += x;
1320     rect->bottom += y;
1321     return TRUE;
1322 }
1323
1324
1325 /***********************************************************************
1326  *              IntersectRect (USER32.@)
1327  */
1328 BOOL WINAPI IntersectRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1329 {
1330     if (!dest || !src1 || !src2) return FALSE;
1331     if (IsRectEmpty(src1) || IsRectEmpty(src2) ||
1332         (src1->left >= src2->right) || (src2->left >= src1->right) ||
1333         (src1->top >= src2->bottom) || (src2->top >= src1->bottom))
1334     {
1335         SetRectEmpty( dest );
1336         return FALSE;
1337     }
1338     dest->left   = max( src1->left, src2->left );
1339     dest->right  = min( src1->right, src2->right );
1340     dest->top    = max( src1->top, src2->top );
1341     dest->bottom = min( src1->bottom, src2->bottom );
1342     return TRUE;
1343 }
1344
1345
1346 /***********************************************************************
1347  *              UnionRect (USER32.@)
1348  */
1349 BOOL WINAPI UnionRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1350 {
1351     if (!dest) return FALSE;
1352     if (IsRectEmpty(src1))
1353     {
1354         if (IsRectEmpty(src2))
1355         {
1356             SetRectEmpty( dest );
1357             return FALSE;
1358         }
1359         else *dest = *src2;
1360     }
1361     else
1362     {
1363         if (IsRectEmpty(src2)) *dest = *src1;
1364         else
1365         {
1366             dest->left   = min( src1->left, src2->left );
1367             dest->right  = max( src1->right, src2->right );
1368             dest->top    = min( src1->top, src2->top );
1369             dest->bottom = max( src1->bottom, src2->bottom );
1370         }
1371     }
1372     return TRUE;
1373 }
1374
1375
1376 /***********************************************************************
1377  *              EqualRect (USER32.@)
1378  */
1379 BOOL WINAPI EqualRect( const RECT* rect1, const RECT* rect2 )
1380 {
1381     if (!rect1 || !rect2) return FALSE;
1382     return ((rect1->left == rect2->left) && (rect1->right == rect2->right) &&
1383             (rect1->top == rect2->top) && (rect1->bottom == rect2->bottom));
1384 }
1385
1386
1387 /***********************************************************************
1388  *              SubtractRect (USER32.@)
1389  */
1390 BOOL WINAPI SubtractRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1391 {
1392     RECT tmp;
1393
1394     if (!dest) return FALSE;
1395     if (IsRectEmpty( src1 ))
1396     {
1397         SetRectEmpty( dest );
1398         return FALSE;
1399     }
1400     *dest = *src1;
1401     if (IntersectRect( &tmp, src1, src2 ))
1402     {
1403         if (EqualRect( &tmp, dest ))
1404         {
1405             SetRectEmpty( dest );
1406             return FALSE;
1407         }
1408         if ((tmp.top == dest->top) && (tmp.bottom == dest->bottom))
1409         {
1410             if (tmp.left == dest->left) dest->left = tmp.right;
1411             else if (tmp.right == dest->right) dest->right = tmp.left;
1412         }
1413         else if ((tmp.left == dest->left) && (tmp.right == dest->right))
1414         {
1415             if (tmp.top == dest->top) dest->top = tmp.bottom;
1416             else if (tmp.bottom == dest->bottom) dest->bottom = tmp.top;
1417         }
1418     }
1419     return TRUE;
1420 }
1421
1422
1423 /***********************************************************************
1424  *              FillRect (USER32.@)
1425  */
1426 INT WINAPI FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1427 {
1428     HBRUSH prev_brush;
1429
1430     if (hbrush <= (HBRUSH) (COLOR_MAX + 1)) hbrush = GetSysColorBrush( HandleToULong(hbrush) - 1 );
1431
1432     prev_brush = SelectObject( hdc, hbrush );
1433     PatBlt( hdc, rect->left, rect->top,
1434               rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
1435     if (prev_brush) SelectObject( hdc, prev_brush );
1436     return 1;
1437 }
1438
1439
1440 /***********************************************************************
1441  *              InvertRect (USER32.@)
1442  */
1443 BOOL WINAPI InvertRect( HDC hdc, const RECT *rect )
1444 {
1445     return PatBlt( hdc, rect->left, rect->top,
1446                    rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
1447 }
1448
1449
1450 /***********************************************************************
1451  *              FrameRect (USER32.@)
1452  */
1453 INT WINAPI FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1454 {
1455     HBRUSH prevBrush;
1456     RECT r = *rect;
1457
1458     if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
1459     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
1460
1461     PatBlt( hdc, r.left, r.top, 1, r.bottom - r.top, PATCOPY );
1462     PatBlt( hdc, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY );
1463     PatBlt( hdc, r.left, r.top, r.right - r.left, 1, PATCOPY );
1464     PatBlt( hdc, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY );
1465
1466     SelectObject( hdc, prevBrush );
1467     return TRUE;
1468 }
1469
1470
1471 /***********************************************************************
1472  *              DrawFocusRect (USER32.@)
1473  *
1474  * FIXME: PatBlt(PATINVERT) with background brush.
1475  */
1476 BOOL WINAPI DrawFocusRect( HDC hdc, const RECT* rc )
1477 {
1478     HBRUSH hOldBrush;
1479     HPEN hOldPen, hNewPen;
1480     INT oldDrawMode, oldBkMode;
1481     LOGBRUSH lb;
1482
1483     hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
1484     lb.lbStyle = BS_SOLID;
1485     lb.lbColor = GetSysColor(COLOR_WINDOWTEXT);
1486     hNewPen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
1487     hOldPen = SelectObject(hdc, hNewPen);
1488     oldDrawMode = SetROP2(hdc, R2_XORPEN);
1489     oldBkMode = SetBkMode(hdc, TRANSPARENT);
1490
1491     Rectangle(hdc, rc->left, rc->top, rc->right, rc->bottom);
1492
1493     SetBkMode(hdc, oldBkMode);
1494     SetROP2(hdc, oldDrawMode);
1495     SelectObject(hdc, hOldPen);
1496     DeleteObject(hNewPen);
1497     SelectObject(hdc, hOldBrush);
1498
1499     return TRUE;
1500 }
1501
1502
1503 /**********************************************************************
1504  *              DrawAnimatedRects (USER32.@)
1505  */
1506 BOOL WINAPI DrawAnimatedRects( HWND hwnd, INT idAni, const RECT* lprcFrom, const RECT* lprcTo )
1507 {
1508     FIXME("(%p,%d,%p,%p): stub\n",hwnd,idAni,lprcFrom,lprcTo);
1509     return TRUE;
1510 }
1511
1512
1513 /**********************************************************************
1514  *          UITOOLS_DrawStateJam
1515  *
1516  * Jams in the requested type in the dc
1517  */
1518 static BOOL UITOOLS_DrawStateJam( HDC hdc, UINT opcode, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1519                                   LPRECT rc, UINT dtflags, BOOL unicode )
1520 {
1521     HDC memdc;
1522     HBITMAP hbmsave;
1523     BOOL retval;
1524     INT cx = rc->right - rc->left;
1525     INT cy = rc->bottom - rc->top;
1526
1527     switch(opcode)
1528     {
1529     case DST_TEXT:
1530     case DST_PREFIXTEXT:
1531         if(unicode)
1532             return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1533         else
1534             return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1535
1536     case DST_ICON:
1537         return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, 0, 0, 0, NULL, DI_NORMAL);
1538
1539     case DST_BITMAP:
1540         memdc = CreateCompatibleDC(hdc);
1541         if(!memdc) return FALSE;
1542         hbmsave = SelectObject(memdc, (HBITMAP)lp);
1543         if(!hbmsave)
1544         {
1545             DeleteDC(memdc);
1546             return FALSE;
1547         }
1548         retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1549         SelectObject(memdc, hbmsave);
1550         DeleteDC(memdc);
1551         return retval;
1552
1553     case DST_COMPLEX:
1554         if(func) {
1555             BOOL bRet;
1556             /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */
1557
1558             OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1559             bRet = func(hdc, lp, wp, cx, cy);
1560             /* Restore origin */
1561             OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1562             return bRet;
1563         } else
1564             return FALSE;
1565     }
1566     return FALSE;
1567 }
1568
1569 /**********************************************************************
1570  *      UITOOLS_DrawState()
1571  */
1572 static BOOL UITOOLS_DrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1573                               INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode )
1574 {
1575     HBITMAP hbm, hbmsave;
1576     HFONT hfsave;
1577     HBRUSH hbsave, hbrtmp = 0;
1578     HDC memdc;
1579     RECT rc;
1580     UINT dtflags = DT_NOCLIP;
1581     COLORREF fg, bg;
1582     UINT opcode = flags & 0xf;
1583     INT len = wp;
1584     BOOL retval, tmp;
1585
1586     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1587     {
1588         if (!lp) return FALSE;
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         BITMAP bm;
1601
1602         switch(opcode)
1603         {
1604         case DST_TEXT:
1605         case DST_PREFIXTEXT:
1606             if(unicode)
1607                 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1608             else
1609                 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1610             if(!retval) return FALSE;
1611             break;
1612
1613         case DST_ICON:
1614             if (!get_icon_size( (HICON)lp, &s )) return FALSE;
1615             break;
1616
1617         case DST_BITMAP:
1618             if(!GetObjectA((HBITMAP)lp, sizeof(bm), &bm)) return FALSE;
1619             s.cx = bm.bmWidth;
1620             s.cy = bm.bmHeight;
1621             break;
1622
1623         case DST_COMPLEX: /* cx and cy must be set in this mode */
1624             return FALSE;
1625         }
1626
1627         if(!cx) cx = s.cx;
1628         if(!cy) cy = s.cy;
1629     }
1630
1631     rc.left   = x;
1632     rc.top    = y;
1633     rc.right  = x + cx;
1634     rc.bottom = y + cy;
1635
1636     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1637         dtflags |= DT_RIGHT;
1638     if(opcode == DST_TEXT)
1639         dtflags |= DT_NOPREFIX;
1640
1641     /* For DSS_NORMAL we just jam in the image and return */
1642     if((flags & 0x7ff0) == DSS_NORMAL)
1643     {
1644         return UITOOLS_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1645     }
1646
1647     /* For all other states we need to convert the image to B/W in a local bitmap */
1648     /* before it is displayed */
1649     fg = SetTextColor(hdc, RGB(0, 0, 0));
1650     bg = SetBkColor(hdc, RGB(255, 255, 255));
1651     hbm = NULL; hbmsave = NULL;
1652     memdc = NULL; hbsave = NULL;
1653     retval = FALSE; /* assume failure */
1654
1655     /* From here on we must use "goto cleanup" when something goes wrong */
1656     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1657     if(!hbm) goto cleanup;
1658     memdc   = CreateCompatibleDC(hdc);
1659     if(!memdc) goto cleanup;
1660     hbmsave = SelectObject(memdc, hbm);
1661     if(!hbmsave) goto cleanup;
1662     rc.left = rc.top = 0;
1663     rc.right = cx;
1664     rc.bottom = cy;
1665     if(!FillRect(memdc, &rc, GetStockObject(WHITE_BRUSH))) goto cleanup;
1666     SetBkColor(memdc, RGB(255, 255, 255));
1667     SetTextColor(memdc, RGB(0, 0, 0));
1668     hfsave  = SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1669
1670     /* DST_COMPLEX may draw text as well,
1671      * so we must be sure that correct font is selected
1672      */
1673     if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1674     tmp = UITOOLS_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1675     if(hfsave) SelectObject(memdc, hfsave);
1676     if(!tmp) goto cleanup;
1677
1678     /* This state cause the image to be dithered */
1679     if(flags & DSS_UNION)
1680     {
1681         hbsave = SelectObject(memdc, SYSCOLOR_55AABrush);
1682         if(!hbsave) goto cleanup;
1683         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1684         SelectObject(memdc, hbsave);
1685         if(!tmp) goto cleanup;
1686     }
1687
1688     if (flags & DSS_DISABLED)
1689        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1690     else if (flags & DSS_DEFAULT)
1691        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1692
1693     /* Draw light or dark shadow */
1694     if (flags & (DSS_DISABLED|DSS_DEFAULT))
1695     {
1696        if(!hbrtmp) goto cleanup;
1697        hbsave = SelectObject(hdc, hbrtmp);
1698        if(!hbsave) goto cleanup;
1699        if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1700        SelectObject(hdc, hbsave);
1701        DeleteObject(hbrtmp);
1702        hbrtmp = 0;
1703     }
1704
1705     if (flags & DSS_DISABLED)
1706     {
1707        hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1708        if(!hbrtmp) goto cleanup;
1709     }
1710     else if (!hbr)
1711     {
1712        hbr = GetStockObject(BLACK_BRUSH);
1713     }
1714
1715     hbsave = SelectObject(hdc, hbr);
1716
1717     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1718
1719     retval = TRUE; /* We succeeded */
1720
1721 cleanup:
1722     SetTextColor(hdc, fg);
1723     SetBkColor(hdc, bg);
1724
1725     if(hbsave)  SelectObject(hdc, hbsave);
1726     if(hbmsave) SelectObject(memdc, hbmsave);
1727     if(hbrtmp)  DeleteObject(hbrtmp);
1728     if(hbm)     DeleteObject(hbm);
1729     if(memdc)   DeleteDC(memdc);
1730
1731     return retval;
1732 }
1733
1734 /**********************************************************************
1735  *              DrawStateA (USER32.@)
1736  */
1737 BOOL WINAPI DrawStateA(HDC hdc, HBRUSH hbr,
1738                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1739                    INT x, INT y, INT cx, INT cy, UINT flags)
1740 {
1741     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, FALSE);
1742 }
1743
1744 /**********************************************************************
1745  *              DrawStateW (USER32.@)
1746  */
1747 BOOL WINAPI DrawStateW(HDC hdc, HBRUSH hbr,
1748                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1749                    INT x, INT y, INT cx, INT cy, UINT flags)
1750 {
1751     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, TRUE);
1752 }