update for HEAD-2003021201
[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 #include <debug.h>
34
35 /* GLOBALS *******************************************************************/
36
37 #define COLOR_MAX (28)
38
39 /* HPEN STDCALL W32kGetSysColorPen(int nIndex); */
40
41 static const WORD wPattern_AA55[8] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555,
42                                        0xaaaa, 0x5555, 0xaaaa, 0x5555 };
43
44 /* These tables are used in:
45  * UITOOLS_DrawDiagEdge()
46  * UITOOLS_DrawRectEdge()
47  */
48 static const signed char LTInnerNormal[] = {
49     -1,           -1,                 -1,                 -1,
50     -1,           COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
51     -1,           COLOR_3DDKSHADOW,   COLOR_3DDKSHADOW,   -1,
52     -1,           -1,                 -1,                 -1
53 };
54
55 static const signed char LTOuterNormal[] = {
56     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
57     COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
58     COLOR_3DDKSHADOW,   COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
59     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1
60 };
61
62 static const signed char RBInnerNormal[] = {
63     -1,           -1,                -1,              -1,
64     -1,           COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
65     -1,           COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
66     -1,           -1,                -1,              -1
67 };
68
69 static const signed char RBOuterNormal[] = {
70     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
71     COLOR_BTNSHADOW, COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
72     COLOR_3DLIGHT,   COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
73     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1
74 };
75
76 static const signed char LTInnerSoft[] = {
77     -1,                  -1,                -1,              -1,
78     -1,                  COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
79     -1,                  COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
80     -1,                  -1,                -1,              -1
81 };
82
83 static const signed char LTOuterSoft[] = {
84     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
85     COLOR_3DLIGHT,   COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
86     COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
87     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
88 };
89
90 #define RBInnerSoft RBInnerNormal   /* These are the same */
91 #define RBOuterSoft RBOuterNormal
92
93 static const signed char LTRBOuterMono[] = {
94     -1,           COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
95     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
96     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
97     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
98 };
99
100 static const signed char LTRBInnerMono[] = {
101     -1, -1,           -1,           -1,
102     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
103     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
104     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
105 };
106
107 static const signed char LTRBOuterFlat[] = {
108     -1,                COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
109     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
110     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
111     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
112 };
113
114 static const signed char LTRBInnerFlat[] = {
115     -1, -1,              -1,              -1,
116     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
117     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
118     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
119 };
120
121 /* FUNCTIONS *****************************************************************/
122
123
124 HPEN STDCALL GetSysColorPen(int nIndex);
125 HBRUSH STDCALL GetSysColorBrush(int nIndex);
126
127 /* Ported from WINE20020904 */
128 /* Same as DrawEdge invoked with BF_DIAGONAL */
129 static BOOL UITOOLS95_DrawDiagEdge(HDC hdc, LPRECT rc,
130                                      UINT uType, UINT uFlags)
131 {
132     POINT Points[4];
133     signed char InnerI, OuterI;
134     HPEN InnerPen, OuterPen;
135     POINT SavePoint;
136     HPEN SavePen;
137     int spx, spy;
138     int epx, epy;
139     int Width = rc->right - rc->left;
140     int Height= rc->bottom - rc->top;
141     int SmallDiam = Width > Height ? Height : Width;
142     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
143                        || (uType & BDR_OUTER) == BDR_OUTER)
144                       && !(uFlags & (BF_FLAT|BF_MONO)) );
145     int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
146             + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
147
148     /* Init some vars */
149     OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
150     SavePen = (HPEN)SelectObject(hdc, InnerPen);
151     spx = spy = epx = epy = 0; /* Satisfy the compiler... */
152
153     /* Determine the colors of the edges */
154     if(uFlags & BF_MONO)
155     {
156         InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
157         OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
158     }
159     else if(uFlags & BF_FLAT)
160     {
161         InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
162         OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
163     }
164     else if(uFlags & BF_SOFT)
165     {
166         if(uFlags & BF_BOTTOM)
167         {
168             InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
169             OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
170         }
171         else
172         {
173             InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
174             OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
175         }
176     }
177     else
178     {
179         if(uFlags & BF_BOTTOM)
180         {
181             InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
182             OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
183         }
184         else
185         {
186             InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
187             OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
188         }
189     }
190
191     if(InnerI != -1) InnerPen = GetSysColorPen(InnerI);
192     if(OuterI != -1) OuterPen = GetSysColorPen(OuterI);
193
194     MoveToEx(hdc, 0, 0, &SavePoint);
195
196     /* Don't ask me why, but this is what is visible... */
197     /* This must be possible to do much simpler, but I fail to */
198     /* see the logic in the MS implementation (sigh...). */
199     /* So, this might look a bit brute force here (and it is), but */
200     /* it gets the job done;) */
201
202     switch(uFlags & BF_RECT)
203     {
204     case 0:
205     case BF_LEFT:
206     case BF_BOTTOM:
207     case BF_BOTTOMLEFT:
208         /* Left bottom endpoint */
209         epx = rc->left-1;
210         spx = epx + SmallDiam;
211         epy = rc->bottom;
212         spy = epy - SmallDiam;
213         break;
214
215     case BF_TOPLEFT:
216     case BF_BOTTOMRIGHT:
217         /* Left top endpoint */
218         epx = rc->left-1;
219         spx = epx + SmallDiam;
220         epy = rc->top-1;
221         spy = epy + SmallDiam;
222         break;
223
224     case BF_TOP:
225     case BF_RIGHT:
226     case BF_TOPRIGHT:
227     case BF_RIGHT|BF_LEFT:
228     case BF_RIGHT|BF_LEFT|BF_TOP:
229     case BF_BOTTOM|BF_TOP:
230     case BF_BOTTOM|BF_TOP|BF_LEFT:
231     case BF_BOTTOMRIGHT|BF_LEFT:
232     case BF_BOTTOMRIGHT|BF_TOP:
233     case BF_RECT:
234         /* Right top endpoint */
235         spx = rc->left;
236         epx = spx + SmallDiam;
237         spy = rc->bottom-1;
238         epy = spy - SmallDiam;
239         break;
240     }
241
242     MoveToEx(hdc, spx, spy, NULL);
243     SelectObject(hdc, OuterPen);
244     LineTo(hdc, epx, epy);
245
246     SelectObject(hdc, InnerPen);
247
248     switch(uFlags & (BF_RECT|BF_DIAGONAL))
249     {
250     case BF_DIAGONAL_ENDBOTTOMLEFT:
251     case (BF_DIAGONAL|BF_BOTTOM):
252     case BF_DIAGONAL:
253     case (BF_DIAGONAL|BF_LEFT):
254         MoveToEx(hdc, spx-1, spy, NULL);
255         LineTo(hdc, epx, epy-1);
256         Points[0].x = spx-add;
257         Points[0].y = spy;
258         Points[1].x = rc->left;
259         Points[1].y = rc->top;
260         Points[2].x = epx+1;
261         Points[2].y = epy-1-add;
262         Points[3] = Points[2];
263         break;
264
265     case BF_DIAGONAL_ENDBOTTOMRIGHT:
266         MoveToEx(hdc, spx-1, spy, NULL);
267         LineTo(hdc, epx, epy+1);
268         Points[0].x = spx-add;
269         Points[0].y = spy;
270         Points[1].x = rc->left;
271         Points[1].y = rc->bottom-1;
272         Points[2].x = epx+1;
273         Points[2].y = epy+1+add;
274         Points[3] = Points[2];
275         break;
276
277     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
278     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
279     case BF_DIAGONAL_ENDTOPRIGHT:
280     case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
281         MoveToEx(hdc, spx+1, spy, NULL);
282         LineTo(hdc, epx, epy+1);
283         Points[0].x = epx-1;
284         Points[0].y = epy+1+add;
285         Points[1].x = rc->right-1;
286         Points[1].y = rc->top+add;
287         Points[2].x = rc->right-1;
288         Points[2].y = rc->bottom-1;
289         Points[3].x = spx+add;
290         Points[3].y = spy;
291         break;
292
293     case BF_DIAGONAL_ENDTOPLEFT:
294         MoveToEx(hdc, spx, spy-1, NULL);
295         LineTo(hdc, epx+1, epy);
296         Points[0].x = epx+1+add;
297         Points[0].y = epy+1;
298         Points[1].x = rc->right-1;
299         Points[1].y = rc->top;
300         Points[2].x = rc->right-1;
301         Points[2].y = rc->bottom-1-add;
302         Points[3].x = spx;
303         Points[3].y = spy-add;
304         break;
305
306     case (BF_DIAGONAL|BF_TOP):
307     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
308     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
309         MoveToEx(hdc, spx+1, spy-1, NULL);
310         LineTo(hdc, epx, epy);
311         Points[0].x = epx-1;
312         Points[0].y = epy+1;
313         Points[1].x = rc->right-1;
314         Points[1].y = rc->top;
315         Points[2].x = rc->right-1;
316         Points[2].y = rc->bottom-1-add;
317         Points[3].x = spx+add;
318         Points[3].y = spy-add;
319         break;
320
321     case (BF_DIAGONAL|BF_RIGHT):
322     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
323     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
324         MoveToEx(hdc, spx, spy, NULL);
325         LineTo(hdc, epx-1, epy+1);
326         Points[0].x = spx;
327         Points[0].y = spy;
328         Points[1].x = rc->left;
329         Points[1].y = rc->top+add;
330         Points[2].x = epx-1-add;
331         Points[2].y = epy+1+add;
332         Points[3] = Points[2];
333         break;
334     }
335
336     /* Fill the interior if asked */
337     if((uFlags & BF_MIDDLE) && retval)
338     {
339         HBRUSH hbsave;
340         HBRUSH hb = GetSysColorBrush(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE);
341         HPEN hpsave;
342         HPEN hp = GetSysColorPen(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE);
343         hbsave = (HBRUSH)SelectObject(hdc, hb);
344         hpsave = (HPEN)SelectObject(hdc, hp);
345         Polygon(hdc, Points, 4);
346         SelectObject(hdc, hbsave);
347         SelectObject(hdc, hpsave);
348     }
349
350     /* Adjust rectangle if asked */
351     if(uFlags & BF_ADJUST)
352     {
353         if(uFlags & BF_LEFT)   rc->left   += add;
354         if(uFlags & BF_RIGHT)  rc->right  -= add;
355         if(uFlags & BF_TOP)    rc->top    += add;
356         if(uFlags & BF_BOTTOM) rc->bottom -= add;
357     }
358
359     /* Cleanup */
360     SelectObject(hdc, SavePen);
361     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
362
363     return retval;
364 }
365
366 /* Ported from WINE20020904 */
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 static BOOL UITOOLS95_DrawRectEdge(HDC hdc, LPRECT rc,
437                                      UINT uType, UINT uFlags)
438 {
439     signed char LTInnerI, LTOuterI;
440     signed char RBInnerI, RBOuterI;
441     HPEN LTInnerPen, LTOuterPen;
442     HPEN RBInnerPen, RBOuterPen;
443     RECT InnerRect = *rc;
444     POINT SavePoint;
445     HPEN SavePen;
446     int LBpenplus = 0;
447     int LTpenplus = 0;
448     int RTpenplus = 0;
449     int RBpenplus = 0;
450     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
451                        || (uType & BDR_OUTER) == BDR_OUTER)
452                       && !(uFlags & (BF_FLAT|BF_MONO)) );
453
454     /* Init some vars */
455     LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
456     SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
457
458     /* Determine the colors of the edges */
459     if(uFlags & BF_MONO)
460     {
461         LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
462         LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
463     }
464     else if(uFlags & BF_FLAT)
465     {
466         LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
467         LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
468
469         /* Bertho Stultiens states above that this function exactly matches win95
470          * In win98 BF_FLAT rectangles have an inner border same color as the
471          * middle (COLOR_BTNFACE). I believe it's the same for win95 but since
472          * I don't know I go with Bertho and just sets it for win98 until proven
473          * otherwise.
474          *                                          Dennis Björklund, 10 June, 99
475          */
476 /*      if( TWEAK_WineLook == WIN98_LOOK && LTInnerI != -1 )
477             LTInnerI = RBInnerI = COLOR_BTNFACE; */
478     }
479     else if(uFlags & BF_SOFT)
480     {
481         LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
482         LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
483         RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
484         RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
485     }
486     else
487     {
488         LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
489         LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
490         RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
491         RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
492     }
493
494     if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT)   LBpenplus = 1;
495     if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT)       RTpenplus = 1;
496     if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
497     if((uFlags & BF_TOPLEFT) == BF_TOPLEFT)         LTpenplus = 1;
498
499     if(LTInnerI != -1) LTInnerPen = GetSysColorPen(LTInnerI);
500     if(LTOuterI != -1) LTOuterPen = GetSysColorPen(LTOuterI);
501     if(RBInnerI != -1) RBInnerPen = GetSysColorPen(RBInnerI);
502     if(RBOuterI != -1) RBOuterPen = GetSysColorPen(RBOuterI);
503
504     MoveToEx(hdc, 0, 0, &SavePoint);
505
506     /* Draw the outer edge */
507     SelectObject(hdc, LTOuterPen);
508     if(uFlags & BF_TOP)
509     {
510         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
511         LineTo(hdc, InnerRect.right, InnerRect.top);
512     }
513     if(uFlags & BF_LEFT)
514     {
515         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
516         LineTo(hdc, InnerRect.left, InnerRect.bottom);
517     }
518     SelectObject(hdc, RBOuterPen);
519     if(uFlags & BF_BOTTOM)
520     {
521         MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
522         LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
523     }
524     if(uFlags & BF_RIGHT)
525     {
526         MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
527         LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
528     }
529
530     /* Draw the inner edge */
531     SelectObject(hdc, LTInnerPen);
532     if(uFlags & BF_TOP)
533     {
534         MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
535         LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
536     }
537     if(uFlags & BF_LEFT)
538     {
539         MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
540         LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
541     }
542     SelectObject(hdc, RBInnerPen);
543     if(uFlags & BF_BOTTOM)
544     {
545         MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
546         LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
547     }
548     if(uFlags & BF_RIGHT)
549     {
550         MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
551         LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
552     }
553
554     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
555     {
556         int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
557                 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
558
559         if(uFlags & BF_LEFT)   InnerRect.left   += add;
560         if(uFlags & BF_RIGHT)  InnerRect.right  -= add;
561         if(uFlags & BF_TOP)    InnerRect.top    += add;
562         if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
563
564         if((uFlags & BF_MIDDLE) && retval)
565         {
566             FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
567                          COLOR_WINDOW : COLOR_BTNFACE));
568         }
569
570         if(uFlags & BF_ADJUST)
571             *rc = InnerRect;
572     }
573
574     /* Cleanup */
575     SelectObject(hdc, SavePen);
576     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
577     return retval;
578 }
579
580 /* Ported from WINE20020904 */
581 /* Utility to create a square rectangle and returning the width */
582 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
583 {
584     int Width  = src->right - src->left;
585     int Height = src->bottom - src->top;
586     int SmallDiam = Width > Height ? Height : Width;
587
588     *dst = *src;
589
590     /* Make it a square box */
591     if(Width < Height)      /* SmallDiam == Width */
592     {
593         dst->top += (Height-Width)/2;
594         dst->bottom = dst->top + SmallDiam;
595     }
596     else if(Width > Height) /* SmallDiam == Height */
597     {
598         dst->left += (Width-Height)/2;
599         dst->right = dst->left + SmallDiam;
600     }
601
602    return SmallDiam;
603 }
604
605 /* Ported from WINE20020904 */
606 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
607 {
608     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
609     {
610       HBITMAP hbm = CreateBitmap(8, 8, 1, 1, wPattern_AA55);
611       HBRUSH hbsave;
612       HBRUSH hb = CreatePatternBrush(hbm);
613       COLORREF bg;
614
615       FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
616       bg = SetBkColor(dc, RGB(255, 255, 255));
617       hbsave = (HBRUSH)SelectObject(dc, hb);
618       PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
619       SelectObject(dc, hbsave);
620       SetBkColor(dc, bg);
621       DeleteObject(hb);
622       DeleteObject(hbm);
623     }
624     else
625     {
626         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
627     }
628 }
629
630 /* Ported from WINE20020904 */
631 /* Draw a push button coming from DrawFrameControl()
632  *
633  * Does a pretty good job in emulating MS behavior. Some quirks are
634  * however there because MS uses a TrueType font (Marlett) to draw
635  * the buttons.
636  */
637 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
638 {
639     UINT edge;
640     RECT myr = *r;
641
642     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
643         edge = EDGE_SUNKEN;
644     else
645         edge = EDGE_RAISED;
646
647     if(uFlags & DFCS_CHECKED)
648     {
649         if(uFlags & DFCS_MONO)
650             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
651         else
652             UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
653
654         UITOOLS_DrawCheckedRect( dc, &myr );
655         }
656         else
657         {
658         if(uFlags & DFCS_MONO)
659         {
660             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
661             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
662         }
663         else
664         {
665             UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT);
666         }
667     }
668
669     /* Adjust rectangle if asked */
670     if(uFlags & DFCS_ADJUSTRECT)
671     {
672         r->left   += 2;
673         r->right  -= 2;
674         r->top    += 2;
675         r->bottom -= 2;
676     }
677
678     return TRUE;
679 }
680
681 /* Ported from WINE20020904 */
682 /* Draw a check/3state button coming from DrawFrameControl()
683  *
684  * Does a pretty good job in emulating MS behavior. Some quirks are
685  * however there because MS uses a TrueType font (Marlett) to draw
686  * the buttons.
687  */
688 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
689 {
690     RECT myr, bar;
691     UINT flags = BF_RECT | BF_ADJUST;
692     UITOOLS_MakeSquareRect(r, &myr);
693
694     if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
695     else if(uFlags & DFCS_MONO) flags |= BF_MONO;
696
697     UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
698
699     if(uFlags & (DFCS_INACTIVE|DFCS_PUSHED))
700         FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
701     else if( (uFlags & DFCS_BUTTON3STATE) && (uFlags & DFCS_CHECKED) )
702         UITOOLS_DrawCheckedRect( dc, &myr );
703     else
704     {
705         FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
706     }
707
708     if(uFlags & DFCS_CHECKED)
709     {
710         int i, k;
711         i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
712                 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
713
714         /* draw 7 bars, with h=3w to form the check */
715         bar.left = myr.left;
716         bar.top = myr.top + 2;
717         for (k = 0; k < 7; k++) {
718             bar.left = bar.left + 1;
719             bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
720             bar.bottom = bar.top + 3;
721             bar.right = bar.left + 1;
722             FillRect(dc, &bar, GetSysColorBrush(i));
723         }
724     }
725     return TRUE;
726 }
727
728 /* Ported from WINE20020904 */
729 /* Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
730  *
731  * Does a pretty good job in emulating MS behavior. Some quirks are
732  * however there because MS uses a TrueType font (Marlett) to draw
733  * the buttons.
734  */
735 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
736 {
737     RECT myr;
738     int i;
739     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
740     int BorderShrink = SmallDiam / 16;
741     HPEN hpsave;
742     HBRUSH hbsave;
743     int xc, yc;
744
745     if(BorderShrink < 1) BorderShrink = 1;
746
747     if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
748     {
749         FillRect(dc, r, (HBRUSH)GetStockObject(BLACK_BRUSH));
750     }
751
752     xc = myr.left + SmallDiam - SmallDiam/2;
753     yc = myr.top  + SmallDiam - SmallDiam/2;
754
755     /* Define bounding box */
756     i = 14*SmallDiam/16;
757     myr.left   = xc - i+i/2;
758     myr.right  = xc + i/2;
759     myr.top    = yc - i+i/2;
760     myr.bottom = yc + i/2;
761
762     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
763     {
764         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
765         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
766         SelectObject(dc, hbsave);
767     }
768     else
769     {
770         if(uFlags & (DFCS_FLAT|DFCS_MONO))
771         {
772             hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_WINDOWFRAME));
773             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
774             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
775             SelectObject(dc, hbsave);
776             SelectObject(dc, hpsave);
777         }
778         else
779         {
780             hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
781             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
782             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
783
784             SelectObject(dc, GetSysColorPen(COLOR_BTNSHADOW));
785             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
786             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
787
788             myr.left   += BorderShrink;
789             myr.right  -= BorderShrink;
790             myr.top    += BorderShrink;
791             myr.bottom -= BorderShrink;
792
793             SelectObject(dc, GetSysColorPen(COLOR_3DLIGHT));
794             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
795             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
796
797             SelectObject(dc, GetSysColorPen(COLOR_3DDKSHADOW));
798             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
799             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
800             SelectObject(dc, hbsave);
801             SelectObject(dc, hpsave);
802         }
803
804         i = 10*SmallDiam/16;
805         myr.left   = xc - i+i/2;
806         myr.right  = xc + i/2;
807         myr.top    = yc - i+i/2;
808         myr.bottom = yc + i/2;
809         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
810         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
811         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
812         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
813         SelectObject(dc, hbsave);
814         SelectObject(dc, hpsave);
815     }
816
817     if(uFlags & DFCS_CHECKED)
818     {
819         i = 6*SmallDiam/16;
820         i = i < 1 ? 1 : i;
821         myr.left   = xc - i+i/2;
822         myr.right  = xc + i/2;
823         myr.top    = yc - i+i/2;
824         myr.bottom = yc + i/2;
825
826         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
827         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
828         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
829         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
830         SelectObject(dc, hpsave);
831         SelectObject(dc, hbsave);
832     }
833
834     /* FIXME: M$ has a Polygon in the center at relative points: */
835     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
836     /* 0.476, 0.525 */
837     /* 0.500, 0.500 */
838     /* 0.500, 0.499 */
839     /* when the button is unchecked. The reason for it is unknown. The */
840     /* color is COLOR_BTNHIGHLIGHT, although the Polygon gets painted at */
841     /* least 3 times (it looks like a clip-region when you see it happen). */
842     /* I do not really see a reason why this should be implemented. If you */
843     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
844     /* font. */
845
846     return TRUE;
847 }
848
849 /* Ported from WINE20020904 */
850 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
851 {
852     switch(uState & 0xff)
853     {
854     case DFCS_BUTTONPUSH:
855         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
856
857     case DFCS_BUTTONCHECK:
858     case DFCS_BUTTON3STATE:
859         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
860
861     case DFCS_BUTTONRADIOIMAGE:
862     case DFCS_BUTTONRADIOMASK:
863     case DFCS_BUTTONRADIO:
864         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
865
866     default:
867         DbgPrint("Invalid button state=0x%04x\n", uState);
868     }
869
870     return FALSE;
871 }
872
873 /* Ported from WINE20020904 */
874 /* Draw caption buttons (win95), coming from DrawFrameControl() */
875 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
876 {
877     POINT Line1[10];
878     POINT Line2[10];
879     int Line1N;
880     int Line2N;
881     RECT myr;
882     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
883     int i;
884     HBRUSH hbsave;
885     HPEN hpsave;
886     HFONT hfsave, hf;
887     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
888     int xc = (myr.left+myr.right)/2;
889     int yc = (myr.top+myr.bottom)/2;
890     int edge, move;
891     char str[2] = "?";
892     UINT alignsave;
893     int bksave;
894     COLORREF clrsave;
895     SIZE size;
896
897     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
898
899     switch(uFlags & 0xff)
900     {
901     case DFCS_CAPTIONCLOSE:
902     {
903         /* The "X" is made by drawing a series of lines.
904          * The number of lines drawn depends on the size
905          * of the bounding rect.  e.g. For a 6x5 inside rect,
906          * two lines are drawn from top-left to bottom-right,
907          * and two lines from top-right to bottom-left.
908          *
909          * 0 1 2 3 4 5       0 1 2 3 4 5
910          * 1 * *                     * *
911          * 2   * *                 * *
912          * 3     * *             * *
913          * 4       * *         * *
914          *
915          * Drawing one line for every 6 pixels in width
916          * seems to provide the best proportions.
917          */
918
919         POINT start, oldPos;
920         INT width = myr.right - myr.left - 5;
921         INT height = myr.bottom - myr.top - 6;
922         INT numLines = (width / 6) + 1;
923
924         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
925
926         start.x = myr.left + 2;
927         start.y = myr.top + 2;
928
929         if (width < 6)
930             height = width;
931         else
932             start.y++;
933
934         if (uFlags & DFCS_PUSHED)
935         {
936             start.x++;
937                         start.y++;
938         }
939
940         /* now use the width of each line */
941         width -= numLines - 1;
942
943         for (i = 0; i < numLines; i++)
944         {
945             MoveToEx(dc, start.x + i, start.y, &oldPos);
946             LineTo(dc, start.x + i + width, start.y + height);
947
948             MoveToEx(dc, start.x + i, start.y + height - 1, &oldPos);
949             LineTo(dc, start.x + i + width, start.y - 1);
950         }
951
952         SelectObject(dc, hpsave);
953         return TRUE;
954     }
955
956     case DFCS_CAPTIONHELP:
957         /* This one breaks the flow */
958         /* FIXME: We need the Marlett font in order to get this right. */
959
960         hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
961                          ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
962                          DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
963         alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
964         bksave = SetBkMode(dc, TRANSPARENT);
965         clrsave = GetTextColor(dc);
966         hfsave = (HFONT)SelectObject(dc, hf);
967         GetTextExtentPoint32A(dc, str, 1, &size);
968
969         if(uFlags & DFCS_INACTIVE)
970         {
971             SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
972             TextOutA(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
973         }
974         SetTextColor(dc, GetSysColor(colorIdx));
975         TextOutA(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
976
977         SelectObject(dc, hfsave);
978         SetTextColor(dc, clrsave);
979         SetBkMode(dc, bksave);
980         SetTextAlign(dc, alignsave);
981         DeleteObject(hf);
982         return TRUE;
983
984     case DFCS_CAPTIONMIN:
985         Line1[0].x = Line1[3].x = myr.left   +  96*SmallDiam/750+2;
986         Line1[1].x = Line1[2].x = Line1[0].x + 372*SmallDiam/750;
987         Line1[0].y = Line1[1].y = myr.top    + 563*SmallDiam/750+1;
988         Line1[2].y = Line1[3].y = Line1[0].y +  92*SmallDiam/750;
989         Line1N = 4;
990         Line2N = 0;
991         break;
992
993     case DFCS_CAPTIONMAX:
994         edge = 47*SmallDiam/750;
995         Line1[0].x = Line1[5].x = myr.left +  57*SmallDiam/750+3;
996         Line1[0].y = Line1[1].y = myr.top  + 143*SmallDiam/750+1;
997         Line1[1].x = Line1[2].x = Line1[0].x + 562*SmallDiam/750;
998         Line1[5].y = Line1[4].y = Line1[0].y +  93*SmallDiam/750;
999         Line1[2].y = Line1[3].y = Line1[0].y + 513*SmallDiam/750;
1000         Line1[3].x = Line1[4].x = Line1[1].x -  edge;
1001
1002         Line2[0].x = Line2[5].x = Line1[0].x;
1003         Line2[3].x = Line2[4].x = Line1[1].x;
1004         Line2[1].x = Line2[2].x = Line1[0].x + edge;
1005         Line2[0].y = Line2[1].y = Line1[0].y;
1006         Line2[4].y = Line2[5].y = Line1[2].y;
1007         Line2[2].y = Line2[3].y = Line1[2].y - edge;
1008         Line1N = 6;
1009         Line2N = 6;
1010         break;
1011
1012     case DFCS_CAPTIONRESTORE:
1013         /* FIXME: this one looks bad at small sizes < 15x15 :( */
1014         edge = 47*SmallDiam/750;
1015         move = 420*SmallDiam/750;
1016         Line1[0].x = Line1[9].x = myr.left + 198*SmallDiam/750+2;
1017         Line1[0].y = Line1[1].y = myr.top  + 169*SmallDiam/750+1;
1018         Line1[6].y = Line1[7].y = Line1[0].y + 93*SmallDiam/750;
1019         Line1[7].x = Line1[8].x = Line1[0].x + edge;
1020         Line1[1].x = Line1[2].x = Line1[0].x + move;
1021         Line1[5].x = Line1[6].x = Line1[1].x - edge;
1022         Line1[9].y = Line1[8].y = Line1[0].y + 187*SmallDiam/750;
1023         Line1[2].y = Line1[3].y = Line1[0].y + 327*SmallDiam/750;
1024         Line1[4].y = Line1[5].y = Line1[2].y - edge;
1025         Line1[3].x = Line1[4].x = Line1[2].x - 140*SmallDiam/750;
1026
1027         Line2[1].x = Line2[2].x = Line1[3].x;
1028         Line2[7].x = Line2[8].x = Line2[1].x - edge;
1029         Line2[0].x = Line2[9].x = Line2[3].x = Line2[4].x = Line2[1].x - move;
1030         Line2[5].x = Line2[6].x = Line2[0].x + edge;
1031         Line2[0].y = Line2[1].y = Line1[9].y;
1032         Line2[4].y = Line2[5].y = Line2[8].y = Line2[9].y = Line2[0].y + 93*SmallDiam/750;
1033         Line2[2].y = Line2[3].y = Line2[0].y + 327*SmallDiam/750;
1034         Line2[6].y = Line2[7].y = Line2[2].y - edge;
1035         Line1N = 10;
1036         Line2N = 10;
1037         break;
1038
1039     default:
1040         DbgPrint("Invalid caption; flags=0x%04x\n", uFlags);
1041         return FALSE;
1042     }
1043
1044     /* Here the drawing takes place */
1045     if(uFlags & DFCS_INACTIVE)
1046     {
1047         /* If we have an inactive button, then you see a shadow */
1048         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1049         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1050         Polygon(dc, Line1, Line1N);
1051         if(Line2N > 0)
1052             Polygon(dc, Line2, Line2N);
1053         SelectObject(dc, hpsave);
1054         SelectObject(dc, hbsave);
1055     }
1056
1057     /* Correct for the shadow shift */
1058     if (!(uFlags & DFCS_PUSHED))
1059     {
1060         for(i = 0; i < Line1N; i++)
1061         {
1062             Line1[i].x--;
1063             Line1[i].y--;
1064         }
1065         for(i = 0; i < Line2N; i++)
1066         {
1067             Line2[i].x--;
1068             Line2[i].y--;
1069         }
1070     }
1071
1072     /* Make the final picture */
1073     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(colorIdx));
1074     hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
1075
1076     Polygon(dc, Line1, Line1N);
1077     if(Line2N > 0)
1078         Polygon(dc, Line2, Line2N);
1079     SelectObject(dc, hpsave);
1080     SelectObject(dc, hbsave);
1081
1082     return TRUE;
1083 }
1084
1085 /* Ported from WINE20020904 */
1086 /* Draw a scroll-bar control coming from DrawFrameControl() */
1087 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
1088 {
1089     POINT Line[4];
1090     RECT myr;
1091     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
1092     int i;
1093     HBRUSH hbsave, hb, hb2;
1094     HPEN hpsave, hp, hp2;
1095     int tri = 290*SmallDiam/1000 - 1;
1096     int d46, d93;
1097
1098     /*
1099      * This fixes a problem with really tiny "scroll" buttons. In particular
1100      * with the updown control.
1101      * Making sure that the arrow is as least 3 pixels wide (or high).
1102      */
1103     if (tri == 0)
1104       tri = 1;
1105
1106     switch(uFlags & 0xff)
1107     {
1108     case DFCS_SCROLLCOMBOBOX:
1109     case DFCS_SCROLLDOWN:
1110         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1111         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1112         Line[0].x = Line[2].x - tri;
1113         Line[1].x = Line[2].x + tri;
1114         Line[0].y = Line[1].y = Line[2].y - tri;
1115         break;
1116
1117     case DFCS_SCROLLUP:
1118         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1119         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1120         Line[0].x = Line[2].x - tri;
1121         Line[1].x = Line[2].x + tri;
1122         Line[0].y = Line[1].y = Line[2].y + tri;
1123         break;
1124
1125     case DFCS_SCROLLLEFT:
1126         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1127         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1128         Line[0].y = Line[2].y - tri;
1129         Line[1].y = Line[2].y + tri;
1130         Line[0].x = Line[1].x = Line[2].x + tri;
1131         break;
1132
1133     case DFCS_SCROLLRIGHT:
1134         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1135         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1136         Line[0].y = Line[2].y - tri;
1137         Line[1].y = Line[2].y + tri;
1138         Line[0].x = Line[1].x = Line[2].x - tri;
1139         break;
1140
1141     case DFCS_SCROLLSIZEGRIP:
1142         /* This one breaks the flow... */
1143         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1144         hpsave = (HPEN)SelectObject(dc, GetStockObject(NULL_PEN));
1145         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(NULL_BRUSH));
1146         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1147         {
1148             hp = hp2 = GetSysColorPen(COLOR_WINDOWFRAME);
1149             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1150         }
1151         else
1152         {
1153             hp  = GetSysColorPen(COLOR_BTNHIGHLIGHT);
1154             hp2 = GetSysColorPen(COLOR_BTNSHADOW);
1155             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1156             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1157         }
1158         Line[0].x = Line[1].x = r->right-1;
1159         Line[2].y = Line[3].y = r->bottom-1;
1160         d46 = 46*SmallDiam/750;
1161         d93 = 93*SmallDiam/750;
1162
1163         i = 586*SmallDiam/750;
1164         Line[0].y = r->bottom - i - 1;
1165         Line[3].x = r->right - i - 1;
1166         Line[1].y = Line[0].y + d46;
1167         Line[2].x = Line[3].x + d46;
1168         SelectObject(dc, hb);
1169         SelectObject(dc, hp);
1170         Polygon(dc, Line, 4);
1171
1172         Line[1].y++; Line[2].x++;
1173         Line[0].y = Line[1].y + d93;
1174         Line[3].x = Line[2].x + d93;
1175         SelectObject(dc, hb2);
1176         SelectObject(dc, hp2);
1177         Polygon(dc, Line, 4);
1178
1179         i = 398*SmallDiam/750;
1180         Line[0].y = r->bottom - i - 1;
1181         Line[3].x = r->right - i - 1;
1182         Line[1].y = Line[0].y + d46;
1183         Line[2].x = Line[3].x + d46;
1184         SelectObject(dc, hb);
1185         SelectObject(dc, hp);
1186         Polygon(dc, Line, 4);
1187
1188         Line[1].y++; Line[2].x++;
1189         Line[0].y = Line[1].y + d93;
1190         Line[3].x = Line[2].x + d93;
1191         SelectObject(dc, hb2);
1192         SelectObject(dc, hp2);
1193         Polygon(dc, Line, 4);
1194
1195         i = 210*SmallDiam/750;
1196         Line[0].y = r->bottom - i - 1;
1197         Line[3].x = r->right - i - 1;
1198         Line[1].y = Line[0].y + d46;
1199         Line[2].x = Line[3].x + d46;
1200         SelectObject(dc, hb);
1201         SelectObject(dc, hp);
1202         Polygon(dc, Line, 4);
1203
1204         Line[1].y++; Line[2].x++;
1205         Line[0].y = Line[1].y + d93;
1206         Line[3].x = Line[2].x + d93;
1207         SelectObject(dc, hb2);
1208         SelectObject(dc, hp2);
1209         Polygon(dc, Line, 4);
1210
1211         SelectObject(dc, hpsave);
1212         SelectObject(dc, hbsave);
1213         return TRUE;
1214
1215     default:
1216         DbgPrint("Invalid scroll; flags=0x%04x\n", uFlags);
1217         return FALSE;
1218     }
1219
1220     /* Here do the real scroll-bar controls end up */
1221     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1222       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1223       /* want for the normal scroll-arrow button. */
1224       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1225     else
1226       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1227
1228     if(uFlags & DFCS_INACTIVE)
1229     {
1230         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1231         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1232         Polygon(dc, Line, 3);
1233         SelectObject(dc, hpsave);
1234         SelectObject(dc, hbsave);
1235     }
1236
1237     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1238       for(i = 0; i < 3; i++)
1239       {
1240         Line[i].x--;
1241         Line[i].y--;
1242       }
1243
1244     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1245     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1246     hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
1247     Polygon(dc, Line, 3);
1248     SelectObject(dc, hpsave);
1249     SelectObject(dc, hbsave);
1250
1251     return TRUE;
1252 }
1253
1254 /* Ported from WINE20020904 */
1255 /* Draw a menu control coming from DrawFrameControl() */
1256 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1257 {
1258     POINT Points[6];
1259     RECT myr;
1260     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1261     int i;
1262     HBRUSH hbsave;
1263     HPEN hpsave;
1264     int xe, ye;
1265     int xc, yc;
1266     BOOL retval = TRUE;
1267
1268     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1269     /* use anything else. I think I tried all sys-colors to change things */
1270     /* without luck. It seems as if this behavior is inherited from the */
1271     /* win31 DFC() implementation... (you remember, B/W menus). */
1272
1273     FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
1274
1275     hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
1276     hpsave = (HPEN)SelectObject(dc, GetStockObject(BLACK_PEN));
1277
1278     switch(uFlags & 0xff)
1279     {
1280     case DFCS_MENUARROW:
1281         i = 187*SmallDiam/750;
1282         Points[2].x = myr.left + 468*SmallDiam/750;
1283         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1284         Points[0].y = Points[2].y - i;
1285         Points[1].y = Points[2].y + i;
1286         Points[0].x = Points[1].x = Points[2].x - i;
1287         Polygon(dc, Points, 3);
1288         break;
1289
1290     case DFCS_MENUBULLET:
1291         xe = myr.left;
1292         ye = myr.top  + SmallDiam - SmallDiam/2;
1293         xc = myr.left + SmallDiam - SmallDiam/2;
1294         yc = myr.top  + SmallDiam - SmallDiam/2;
1295         i = 234*SmallDiam/750;
1296         i = i < 1 ? 1 : i;
1297         myr.left   = xc - i+i/2;
1298         myr.right  = xc + i/2;
1299         myr.top    = yc - i+i/2;
1300         myr.bottom = yc + i/2;
1301         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1302         break;
1303
1304     case DFCS_MENUCHECK:
1305         Points[0].x = myr.left + 253*SmallDiam/1000;
1306         Points[0].y = myr.top  + 445*SmallDiam/1000;
1307         Points[1].x = myr.left + 409*SmallDiam/1000;
1308         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1309         Points[2].x = myr.left + 690*SmallDiam/1000;
1310         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1311         Points[3].x = Points[2].x;
1312         Points[3].y = Points[2].y + 3*SmallDiam/16;
1313         Points[4].x = Points[1].x;
1314         Points[4].y = Points[1].y + 3*SmallDiam/16;
1315         Points[5].x = Points[0].x;
1316         Points[5].y = Points[0].y + 3*SmallDiam/16;
1317         Polygon(dc, Points, 6);
1318         break;
1319
1320     default:
1321         DbgPrint("Invalid menu; flags=0x%04x\n", uFlags);
1322         retval = FALSE;
1323         break;
1324     }
1325
1326     SelectObject(dc, hpsave);
1327     SelectObject(dc, hbsave);
1328     return retval;
1329 }
1330
1331 /* Ported from WINE20020904 */
1332 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1333                                   UINT uState )
1334 {
1335     /* Win95 doesn't support drawing in other mapping modes */
1336     if(GetMapMode(hdc) != MM_TEXT)
1337         return FALSE;
1338
1339     switch(uType)
1340     {
1341     case DFC_BUTTON:
1342       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1343     case DFC_CAPTION:
1344       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1345     case DFC_MENU:
1346       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1347     case DFC_SCROLL:
1348       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1349     default:
1350       DbgPrint("(%x,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1351     }
1352     return FALSE;
1353 }
1354
1355 /* Ported from WINE20020904 */
1356 BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
1357 {
1358     DbgPrint("%04x %d,%d-%d,%d %04x %04x\n",
1359              hdc, rc->left, rc->top, rc->right, rc->bottom, edge, flags );
1360
1361     if(flags & BF_DIAGONAL)
1362       return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
1363     else
1364       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
1365 }
1366
1367 WINBOOL
1368 STDCALL
1369 GrayStringA(
1370   HDC hDC,
1371   HBRUSH hBrush,
1372   GRAYSTRINGPROC lpOutputFunc,
1373   LPARAM lpData,
1374   int nCount,
1375   int X,
1376   int Y,
1377   int nWidth,
1378   int nHeight)
1379 {
1380   return FALSE;
1381 }
1382
1383 WINBOOL
1384 STDCALL
1385 GrayStringW(
1386   HDC hDC,
1387   HBRUSH hBrush,
1388   GRAYSTRINGPROC lpOutputFunc,
1389   LPARAM lpData,
1390   int nCount,
1391   int X,
1392   int Y,
1393   int nWidth,
1394   int nHeight)
1395 {
1396   return FALSE;
1397 }
1398 WINBOOL
1399 STDCALL
1400 InvertRect(
1401   HDC hDC,
1402   CONST RECT *lprc)
1403 {
1404   return FALSE;
1405 }
1406 LONG
1407 STDCALL
1408 TabbedTextOutA(
1409   HDC hDC,
1410   int X,
1411   int Y,
1412   LPCSTR lpString,
1413   int nCount,
1414   int nTabPositions,
1415   CONST LPINT lpnTabStopPositions,
1416   int nTabOrigin)
1417 {
1418   return 0;
1419 }
1420
1421 LONG
1422 STDCALL
1423 TabbedTextOutW(
1424   HDC hDC,
1425   int X,
1426   int Y,
1427   LPCWSTR lpString,
1428   int nCount,
1429   int nTabPositions,
1430   CONST LPINT lpnTabStopPositions,
1431   int nTabOrigin)
1432 {
1433   return 0;
1434 }
1435 int
1436 STDCALL
1437 FrameRect(
1438   HDC hDC,
1439   CONST RECT *lprc,
1440   HBRUSH hbr)
1441 {
1442   return 0;
1443 }
1444 WINBOOL
1445 STDCALL
1446 FlashWindow(
1447   HWND hWnd,
1448   WINBOOL bInvert)
1449 {
1450   return FALSE;
1451 }
1452
1453 WINBOOL
1454 STDCALL
1455 FlashWindowEx(
1456   PFLASHWINFO pfwi)
1457 {
1458   return FALSE;
1459 }
1460
1461 int STDCALL
1462 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1463 {
1464   HBRUSH prevhbr;
1465   /*if (hbr <= (HBRUSH)(COLOR_MAX + 1))
1466     {
1467       hbr = GetSysColorBrush((INT)hbr - 1);
1468       }*/
1469   if ((prevhbr = SelectObject(hDC, hbr)) == NULL)
1470     {
1471       return(FALSE);
1472     }
1473   PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1474          lprc->bottom - lprc->top, PATCOPY);
1475   SelectObject(hDC, prevhbr);
1476   return(TRUE);
1477 }
1478
1479 WINBOOL
1480 STDCALL
1481 DrawAnimatedRects(
1482   HWND hwnd,
1483   int idAni,
1484   CONST RECT *lprcFrom,
1485   CONST RECT *lprcTo)
1486 {
1487   return FALSE;
1488 }
1489
1490 WINBOOL
1491 STDCALL
1492 DrawCaption(
1493   HWND hwnd,
1494   HDC hdc,
1495   LPRECT lprc,
1496   UINT uFlags)
1497 {
1498   return FALSE;
1499 }
1500
1501 WINBOOL
1502 STDCALL
1503 DrawFocusRect(
1504   HDC hDC,
1505   CONST RECT *lprc)
1506 {
1507   return FALSE;
1508 }
1509
1510
1511 WINBOOL
1512 STDCALL
1513 DrawStateA(
1514   HDC hdc,
1515   HBRUSH hbr,
1516   DRAWSTATEPROC lpOutputFunc,
1517   LPARAM lData,
1518   WPARAM wData,
1519   int x,
1520   int y,
1521   int cx,
1522   int cy,
1523   UINT fuFlags)
1524 {
1525   return FALSE;
1526 }
1527
1528 WINBOOL
1529 STDCALL
1530 DrawStateW(
1531   HDC hdc,
1532   HBRUSH hbr,
1533   DRAWSTATEPROC lpOutputFunc,
1534   LPARAM lData,
1535   WPARAM wData,
1536   int x,
1537   int y,
1538   int cx,
1539   int cy,
1540   UINT fuFlags)
1541 {
1542   return FALSE;
1543 }