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