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