Change parameter in SHGetSpecialFolderPathA/W to int as documented in
[wine] / controls / uitools.c
1 /*
2  * User Interface Functions
3  *
4  * Copyright 1997 Dimitrie O. Paun
5  * Copyright 1997 Bertho A. Stultiens
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "wine/winuser16.h"
28 #include "winuser.h"
29 #include "user.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(graphics);
33
34 static const WORD wPattern_AA55[8] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555,
35                                        0xaaaa, 0x5555, 0xaaaa, 0x5555 };
36
37 /* These tables are used in:
38  * UITOOLS_DrawDiagEdge()
39  * UITOOLS_DrawRectEdge()
40  */
41 static const signed char LTInnerNormal[] = {
42     -1,           -1,                 -1,                 -1,
43     -1,           COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
44     -1,           COLOR_3DDKSHADOW,   COLOR_3DDKSHADOW,   -1,
45     -1,           -1,                 -1,                 -1
46 };
47
48 static const signed char LTOuterNormal[] = {
49     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
50     COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
51     COLOR_3DDKSHADOW,   COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
52     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1
53 };
54
55 static const signed char RBInnerNormal[] = {
56     -1,           -1,                -1,              -1,
57     -1,           COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
58     -1,           COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
59     -1,           -1,                -1,              -1
60 };
61
62 static const signed char RBOuterNormal[] = {
63     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
64     COLOR_BTNSHADOW, COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
65     COLOR_3DLIGHT,   COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
66     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1
67 };
68
69 static const signed char LTInnerSoft[] = {
70     -1,                  -1,                -1,              -1,
71     -1,                  COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
72     -1,                  COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
73     -1,                  -1,                -1,              -1
74 };
75
76 static const signed char LTOuterSoft[] = {
77     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
78     COLOR_3DLIGHT,   COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
79     COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
80     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
81 };
82
83 #define RBInnerSoft RBInnerNormal   /* These are the same */
84 #define RBOuterSoft RBOuterNormal
85
86 static const signed char LTRBOuterMono[] = {
87     -1,           COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
88     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
89     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
90     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
91 };
92
93 static const signed char LTRBInnerMono[] = {
94     -1, -1,           -1,           -1,
95     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
96     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
97     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
98 };
99
100 static const signed char LTRBOuterFlat[] = {
101     -1,                COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
102     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
103     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
104     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
105 };
106
107 static const signed char LTRBInnerFlat[] = {
108     -1, -1,              -1,              -1,
109     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
110     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
111     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
112 };
113
114 /***********************************************************************
115  *           UITOOLS_DrawDiagEdge
116  *
117  * Same as DrawEdge invoked with BF_DIAGONAL
118  *
119  * 03-Dec-1997: Changed by Bertho Stultiens
120  *
121  * See also comments with UITOOLS_DrawRectEdge()
122  */
123 static BOOL UITOOLS95_DrawDiagEdge(HDC hdc, LPRECT rc,
124                                      UINT uType, UINT uFlags)
125 {
126     POINT Points[4];
127     signed char InnerI, OuterI;
128     HPEN InnerPen, OuterPen;
129     POINT SavePoint;
130     HPEN SavePen;
131     int spx, spy;
132     int epx, epy;
133     int Width = rc->right - rc->left;
134     int Height= rc->bottom - rc->top;
135     int SmallDiam = Width > Height ? Height : Width;
136     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
137                        || (uType & BDR_OUTER) == BDR_OUTER)
138                       && !(uFlags & (BF_FLAT|BF_MONO)) );
139     int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
140             + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
141
142     /* Init some vars */
143     OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
144     SavePen = (HPEN)SelectObject(hdc, InnerPen);
145     spx = spy = epx = epy = 0; /* Satisfy the compiler... */
146
147     /* Determine the colors of the edges */
148     if(uFlags & BF_MONO)
149     {
150         InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
151         OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
152     }
153     else if(uFlags & BF_FLAT)
154     {
155         InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
156         OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
157     }
158     else if(uFlags & BF_SOFT)
159     {
160         if(uFlags & BF_BOTTOM)
161         {
162             InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
163             OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
164         }
165         else
166         {
167             InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
168             OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
169         }
170     }
171     else
172     {
173         if(uFlags & BF_BOTTOM)
174         {
175             InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
176             OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
177         }
178         else
179         {
180             InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
181             OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
182         }
183     }
184
185     if(InnerI != -1) InnerPen = SYSCOLOR_GetPen(InnerI);
186     if(OuterI != -1) OuterPen = SYSCOLOR_GetPen(OuterI);
187
188     MoveToEx(hdc, 0, 0, &SavePoint);
189
190     /* Don't ask me why, but this is what is visible... */
191     /* This must be possible to do much simpler, but I fail to */
192     /* see the logic in the MS implementation (sigh...). */
193     /* So, this might look a bit brute force here (and it is), but */
194     /* it gets the job done;) */
195
196     switch(uFlags & BF_RECT)
197     {
198     case 0:
199     case BF_LEFT:
200     case BF_BOTTOM:
201     case BF_BOTTOMLEFT:
202         /* Left bottom endpoint */
203         epx = rc->left-1;
204         spx = epx + SmallDiam;
205         epy = rc->bottom;
206         spy = epy - SmallDiam;
207         break;
208
209     case BF_TOPLEFT:
210     case BF_BOTTOMRIGHT:
211         /* Left top endpoint */
212         epx = rc->left-1;
213         spx = epx + SmallDiam;
214         epy = rc->top-1;
215         spy = epy + SmallDiam;
216         break;
217
218     case BF_TOP:
219     case BF_RIGHT:
220     case BF_TOPRIGHT:
221     case BF_RIGHT|BF_LEFT:
222     case BF_RIGHT|BF_LEFT|BF_TOP:
223     case BF_BOTTOM|BF_TOP:
224     case BF_BOTTOM|BF_TOP|BF_LEFT:
225     case BF_BOTTOMRIGHT|BF_LEFT:
226     case BF_BOTTOMRIGHT|BF_TOP:
227     case BF_RECT:
228         /* Right top endpoint */
229         spx = rc->left;
230         epx = spx + SmallDiam;
231         spy = rc->bottom-1;
232         epy = spy - SmallDiam;
233         break;
234     }
235
236     MoveToEx(hdc, spx, spy, NULL);
237     SelectObject(hdc, OuterPen);
238     LineTo(hdc, epx, epy);
239
240     SelectObject(hdc, InnerPen);
241
242     switch(uFlags & (BF_RECT|BF_DIAGONAL))
243     {
244     case BF_DIAGONAL_ENDBOTTOMLEFT:
245     case (BF_DIAGONAL|BF_BOTTOM):
246     case BF_DIAGONAL:
247     case (BF_DIAGONAL|BF_LEFT):
248         MoveToEx(hdc, spx-1, spy, NULL);
249         LineTo(hdc, epx, epy-1);
250         Points[0].x = spx-add;
251         Points[0].y = spy;
252         Points[1].x = rc->left;
253         Points[1].y = rc->top;
254         Points[2].x = epx+1;
255         Points[2].y = epy-1-add;
256         Points[3] = Points[2];
257         break;
258
259     case BF_DIAGONAL_ENDBOTTOMRIGHT:
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->bottom-1;
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|BF_BOTTOM|BF_RIGHT|BF_TOP):
272     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
273     case BF_DIAGONAL_ENDTOPRIGHT:
274     case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
275         MoveToEx(hdc, spx+1, spy, NULL);
276         LineTo(hdc, epx, epy+1);
277         Points[0].x = epx-1;
278         Points[0].y = epy+1+add;
279         Points[1].x = rc->right-1;
280         Points[1].y = rc->top+add;
281         Points[2].x = rc->right-1;
282         Points[2].y = rc->bottom-1;
283         Points[3].x = spx+add;
284         Points[3].y = spy;
285         break;
286
287     case BF_DIAGONAL_ENDTOPLEFT:
288         MoveToEx(hdc, spx, spy-1, NULL);
289         LineTo(hdc, epx+1, epy);
290         Points[0].x = epx+1+add;
291         Points[0].y = epy+1;
292         Points[1].x = rc->right-1;
293         Points[1].y = rc->top;
294         Points[2].x = rc->right-1;
295         Points[2].y = rc->bottom-1-add;
296         Points[3].x = spx;
297         Points[3].y = spy-add;
298         break;
299
300     case (BF_DIAGONAL|BF_TOP):
301     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
302     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
303         MoveToEx(hdc, spx+1, spy-1, NULL);
304         LineTo(hdc, epx, epy);
305         Points[0].x = epx-1;
306         Points[0].y = epy+1;
307         Points[1].x = rc->right-1;
308         Points[1].y = rc->top;
309         Points[2].x = rc->right-1;
310         Points[2].y = rc->bottom-1-add;
311         Points[3].x = spx+add;
312         Points[3].y = spy-add;
313         break;
314
315     case (BF_DIAGONAL|BF_RIGHT):
316     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
317     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
318         MoveToEx(hdc, spx, spy, NULL);
319         LineTo(hdc, epx-1, epy+1);
320         Points[0].x = spx;
321         Points[0].y = spy;
322         Points[1].x = rc->left;
323         Points[1].y = rc->top+add;
324         Points[2].x = epx-1-add;
325         Points[2].y = epy+1+add;
326         Points[3] = Points[2];
327         break;
328     }
329
330     /* Fill the interior if asked */
331     if((uFlags & BF_MIDDLE) && retval)
332     {
333         HBRUSH hbsave;
334         HBRUSH hb = GetSysColorBrush(uFlags & BF_MONO ? COLOR_WINDOW
335                                          :COLOR_BTNFACE);
336         HPEN hpsave;
337         HPEN hp = SYSCOLOR_GetPen(uFlags & BF_MONO ? COLOR_WINDOW
338                                      : COLOR_BTNFACE);
339         hbsave = (HBRUSH)SelectObject(hdc, hb);
340         hpsave = (HPEN)SelectObject(hdc, hp);
341         Polygon(hdc, Points, 4);
342         SelectObject(hdc, hbsave);
343         SelectObject(hdc, hpsave);
344     }
345
346     /* Adjust rectangle if asked */
347     if(uFlags & BF_ADJUST)
348     {
349         if(uFlags & BF_LEFT)   rc->left   += add;
350         if(uFlags & BF_RIGHT)  rc->right  -= add;
351         if(uFlags & BF_TOP)    rc->top    += add;
352         if(uFlags & BF_BOTTOM) rc->bottom -= add;
353     }
354
355     /* Cleanup */
356     SelectObject(hdc, SavePen);
357     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
358
359     return retval;
360 }
361
362 /***********************************************************************
363  *           UITOOLS_DrawRectEdge
364  *
365  * Same as DrawEdge invoked without BF_DIAGONAL
366  *
367  * 23-Nov-1997: Changed by Bertho Stultiens
368  *
369  * Well, I started testing this and found out that there are a few things
370  * that weren't quite as win95. The following rewrite should reproduce
371  * win95 results completely.
372  * The colorselection is table-driven to avoid awfull if-statements.
373  * The table below show the color settings.
374  *
375  * Pen selection table for uFlags = 0
376  *
377  * uType |  LTI  |  LTO  |  RBI  |  RBO
378  * ------+-------+-------+-------+-------
379  *  0000 |   x   |   x   |   x   |   x
380  *  0001 |   x   |  22   |   x   |  21
381  *  0010 |   x   |  16   |   x   |  20
382  *  0011 |   x   |   x   |   x   |   x
383  * ------+-------+-------+-------+-------
384  *  0100 |   x   |  20   |   x   |  16
385  *  0101 |  20   |  22   |  16   |  21
386  *  0110 |  20   |  16   |  16   |  20
387  *  0111 |   x   |   x   |   x   |   x
388  * ------+-------+-------+-------+-------
389  *  1000 |   x   |  21   |   x   |  22
390  *  1001 |  21   |  22   |  22   |  21
391  *  1010 |  21   |  16   |  22   |  20
392  *  1011 |   x   |   x   |   x   |   x
393  * ------+-------+-------+-------+-------
394  *  1100 |   x   |   x   |   x   |   x
395  *  1101 |   x   | x (22)|   x   | x (21)
396  *  1110 |   x   | x (16)|   x   | x (20)
397  *  1111 |   x   |   x   |   x   |   x
398  *
399  * Pen selection table for uFlags = BF_SOFT
400  *
401  * uType |  LTI  |  LTO  |  RBI  |  RBO
402  * ------+-------+-------+-------+-------
403  *  0000 |   x   |   x   |   x   |   x
404  *  0001 |   x   |  20   |   x   |  21
405  *  0010 |   x   |  21   |   x   |  20
406  *  0011 |   x   |   x   |   x   |   x
407  * ------+-------+-------+-------+-------
408  *  0100 |   x   |  22   |   x   |  16
409  *  0101 |  22   |  20   |  16   |  21
410  *  0110 |  22   |  21   |  16   |  20
411  *  0111 |   x   |   x   |   x   |   x
412  * ------+-------+-------+-------+-------
413  *  1000 |   x   |  16   |   x   |  22
414  *  1001 |  16   |  20   |  22   |  21
415  *  1010 |  16   |  21   |  22   |  20
416  *  1011 |   x   |   x   |   x   |   x
417  * ------+-------+-------+-------+-------
418  *  1100 |   x   |   x   |   x   |   x
419  *  1101 |   x   | x (20)|   x   | x (21)
420  *  1110 |   x   | x (21)|   x   | x (20)
421  *  1111 |   x   |   x   |   x   |   x
422  *
423  * x = don't care; (n) = is what win95 actually uses
424  * LTI = left Top Inner line
425  * LTO = left Top Outer line
426  * RBI = Right Bottom Inner line
427  * RBO = Right Bottom Outer line
428  * 15 = COLOR_BTNFACE
429  * 16 = COLOR_BTNSHADOW
430  * 20 = COLOR_BTNHIGHLIGHT
431  * 21 = COLOR_3DDKSHADOW
432  * 22 = COLOR_3DLIGHT
433  */
434
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 = SYSCOLOR_GetPen(LTInnerI);
500     if(LTOuterI != -1) LTOuterPen = SYSCOLOR_GetPen(LTOuterI);
501     if(RBInnerI != -1) RBInnerPen = SYSCOLOR_GetPen(RBInnerI);
502     if(RBOuterI != -1) RBOuterPen = SYSCOLOR_GetPen(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
581 /**********************************************************************
582  *          DrawEdge   (USER32.@)
583  */
584 BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
585 {
586     TRACE("%p %ld,%ld-%ld,%ld %04x %04x\n",
587           hdc, rc->left, rc->top, rc->right, rc->bottom, edge, flags );
588
589     if(flags & BF_DIAGONAL)
590       return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
591     else
592       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
593 }
594
595
596 /************************************************************************
597  *      UITOOLS_MakeSquareRect
598  *
599  * Utility to create a square rectangle and returning the width
600  */
601 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
602 {
603     int Width  = src->right - src->left;
604     int Height = src->bottom - src->top;
605     int SmallDiam = Width > Height ? Height : Width;
606
607     *dst = *src;
608
609     /* Make it a square box */
610     if(Width < Height)      /* SmallDiam == Width */
611     {
612         dst->top += (Height-Width)/2;
613         dst->bottom = dst->top + SmallDiam;
614     }
615     else if(Width > Height) /* SmallDiam == Height */
616     {
617         dst->left += (Width-Height)/2;
618         dst->right = dst->left + SmallDiam;
619     }
620
621    return SmallDiam;
622 }
623
624 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
625 {
626     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
627     {
628       HBITMAP hbm = CreateBitmap(8, 8, 1, 1, wPattern_AA55);
629       HBRUSH hbsave;
630       HBRUSH hb = CreatePatternBrush(hbm);
631       COLORREF bg;
632
633       FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
634       bg = SetBkColor(dc, RGB(255, 255, 255));
635       hbsave = (HBRUSH)SelectObject(dc, hb);
636       PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
637       SelectObject(dc, hbsave);
638       SetBkColor(dc, bg);
639       DeleteObject(hb);
640       DeleteObject(hbm);
641     }
642     else
643     {
644         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
645     }
646 }
647
648 /************************************************************************
649  *      UITOOLS_DFC_ButtonPush
650  *
651  * Draw a push button coming from DrawFrameControl()
652  *
653  * Does a pretty good job in emulating MS behavior. Some quirks are
654  * however there because MS uses a TrueType font (Marlett) to draw
655  * the buttons.
656  */
657 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
658 {
659     UINT edge;
660     RECT myr = *r;
661
662     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
663         edge = EDGE_SUNKEN;
664     else
665         edge = EDGE_RAISED;
666
667     if(uFlags & DFCS_CHECKED)
668     {
669         if(uFlags & DFCS_MONO)
670             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
671         else
672             UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
673
674         if (!(uFlags & DFCS_TRANSPARENT))
675             UITOOLS_DrawCheckedRect( dc, &myr );
676     }
677     else
678     {
679         if(uFlags & DFCS_MONO)
680         {
681             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
682             if (!(uFlags & DFCS_TRANSPARENT))
683                 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
684         }
685         else
686         {
687             UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags & DFCS_FLAT) | ((uFlags & DFCS_TRANSPARENT) ? 0 : BF_MIDDLE) | BF_RECT);
688         }
689     }
690
691     /* Adjust rectangle if asked */
692     if(uFlags & DFCS_ADJUSTRECT)
693     {
694         r->left   += 2;
695         r->right  -= 2;
696         r->top    += 2;
697         r->bottom -= 2;
698     }
699
700     return TRUE;
701 }
702
703
704 /************************************************************************
705  *      UITOOLS_DFC_ButtonChcek
706  *
707  * Draw a check/3state button coming from DrawFrameControl()
708  *
709  * Does a pretty good job in emulating MS behavior. Some quirks are
710  * however there because MS uses a TrueType font (Marlett) to draw
711  * the buttons.
712  */
713
714 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
715 {
716     RECT myr, bar;
717     UINT flags = BF_RECT | BF_ADJUST;
718
719     UITOOLS_MakeSquareRect(r, &myr);
720
721     if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
722     else if(uFlags & DFCS_MONO) flags |= BF_MONO;
723
724     UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
725
726     if (!(uFlags & DFCS_TRANSPARENT))
727     {
728         if(uFlags & (DFCS_INACTIVE | DFCS_PUSHED))
729             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
730         else if( (uFlags & DFCS_BUTTON3STATE) && (uFlags & DFCS_CHECKED) )
731             UITOOLS_DrawCheckedRect( dc, &myr );
732         else
733             FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
734     }
735
736     if(uFlags & DFCS_CHECKED)
737     {
738         int i, k;
739         i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
740                 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
741
742         /* draw 7 bars, with h=3w to form the check */
743         bar.left = myr.left;
744         bar.top = myr.top + 2;
745         for (k = 0; k < 7; k++) {
746             bar.left = bar.left + 1;
747             bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
748             bar.bottom = bar.top + 3;
749             bar.right = bar.left + 1;
750             FillRect(dc, &bar, GetSysColorBrush(i));
751         }
752     }
753     return TRUE;
754 }
755
756
757 /************************************************************************
758  *      UITOOLS_DFC_ButtonRadio
759  *
760  * Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
761  *
762  * Does a pretty good job in emulating MS behavior. Some quirks are
763  * however there because MS uses a TrueType font (Marlett) to draw
764  * the buttons.
765  */
766 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
767 {
768     RECT myr;
769     int i;
770     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
771     int BorderShrink = SmallDiam / 16;
772     HPEN hpsave;
773     HBRUSH hbsave;
774     int xc, yc;
775
776     if(BorderShrink < 1) BorderShrink = 1;
777
778     if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
779         FillRect(dc, r, (HBRUSH)GetStockObject(BLACK_BRUSH));
780
781     xc = myr.left + SmallDiam - SmallDiam/2;
782     yc = myr.top  + SmallDiam - SmallDiam/2;
783
784     /* Define bounding box */
785     i = 14*SmallDiam/16;
786     myr.left   = xc - i+i/2;
787     myr.right  = xc + i/2;
788     myr.top    = yc - i+i/2;
789     myr.bottom = yc + i/2;
790
791     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
792     {
793         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
794         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
795         SelectObject(dc, hbsave);
796     }
797     else
798     {
799         if(uFlags & (DFCS_FLAT|DFCS_MONO))
800         {
801             hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
802             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
803             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
804             SelectObject(dc, hbsave);
805             SelectObject(dc, hpsave);
806         }
807         else
808         {
809             hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
810             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
811             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
812
813             SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNSHADOW));
814             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
815             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
816
817             myr.left   += BorderShrink;
818             myr.right  -= BorderShrink;
819             myr.top    += BorderShrink;
820             myr.bottom -= BorderShrink;
821
822             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DLIGHT));
823             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
824             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
825
826             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DDKSHADOW));
827             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
828             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
829             SelectObject(dc, hbsave);
830             SelectObject(dc, hpsave);
831         }
832
833         i = 10*SmallDiam/16;
834         myr.left   = xc - i+i/2;
835         myr.right  = xc + i/2;
836         myr.top    = yc - i+i/2;
837         myr.bottom = yc + i/2;
838         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
839         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(i));
840         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
841         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
842         SelectObject(dc, hbsave);
843         SelectObject(dc, hpsave);
844     }
845
846     if(uFlags & DFCS_CHECKED)
847     {
848         i = 6*SmallDiam/16;
849         i = i < 1 ? 1 : i;
850         myr.left   = xc - i+i/2;
851         myr.right  = xc + i/2;
852         myr.top    = yc - i+i/2;
853         myr.bottom = yc + i/2;
854
855         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
856         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
857         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(i));
858         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
859         SelectObject(dc, hpsave);
860         SelectObject(dc, hbsave);
861     }
862
863     /* FIXME: M$ has a polygon in the center at relative points: */
864     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
865     /* 0.476, 0.525 */
866     /* 0.500, 0.500 */
867     /* 0.500, 0.499 */
868     /* when the button is unchecked. The reason for it is unknown. The */
869     /* color is COLOR_BTNHIGHLIGHT, although the polygon gets painted at */
870     /* least 3 times (it looks like a clip-region when you see it happen). */
871     /* I do not really see a reason why this should be implemented. If you */
872     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
873     /* font. */
874
875     return TRUE;
876 }
877
878 /***********************************************************************
879  *           UITOOLS_DrawFrameButton
880  */
881 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
882 {
883     switch(uState & 0xff)
884     {
885     case DFCS_BUTTONPUSH:
886         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
887
888     case DFCS_BUTTONCHECK:
889     case DFCS_BUTTON3STATE:
890         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
891
892     case DFCS_BUTTONRADIOIMAGE:
893     case DFCS_BUTTONRADIOMASK:
894     case DFCS_BUTTONRADIO:
895         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
896
897     default:
898         WARN("Invalid button state=0x%04x\n", uState);
899     }
900
901     return FALSE;
902 }
903
904 /***********************************************************************
905  *           UITOOLS_DrawFrameCaption
906  *
907  * Draw caption buttons (win95), coming from DrawFrameControl()
908  */
909
910 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
911 {
912     POINT Line1[10];
913     POINT Line2[10];
914     int Line1N;
915     int Line2N;
916     RECT myr;
917     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
918     int i;
919     HBRUSH hbsave;
920     HPEN hpsave;
921     HFONT hfsave, hf;
922     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
923     int xc = (myr.left+myr.right)/2;
924     int yc = (myr.top+myr.bottom)/2;
925     int edge, move;
926     char str[2] = "?";
927     UINT alignsave;
928     int bksave;
929     COLORREF clrsave;
930     SIZE size;
931
932     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
933
934     switch(uFlags & 0xff)
935     {
936     case DFCS_CAPTIONCLOSE:
937     {
938         /* The "X" is made by drawing a series of lines.
939          * The number of lines drawn depends on the size
940          * of the bounding rect.  e.g. For a 6x5 inside rect,
941          * two lines are drawn from top-left to bottom-right,
942          * and two lines from top-right to bottom-left.
943          *
944          * 0 1 2 3 4 5       0 1 2 3 4 5
945          * 1 * *                     * *
946          * 2   * *                 * *
947          * 3     * *             * *
948          * 4       * *         * *
949          *
950          * Drawing one line for every 6 pixels in width
951          * seems to provide the best proportions.
952          */
953
954         POINT start, oldPos;
955         INT width = myr.right - myr.left - 5;
956         INT height = myr.bottom - myr.top - 6;
957         INT numLines = (width / 6) + 1;
958
959         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(colorIdx));
960
961         start.x = myr.left + 2;
962         start.y = myr.top + 2;
963
964         if (width < 6)
965             height = width;
966         else
967             start.y++;
968
969         if (uFlags & DFCS_PUSHED)
970         {
971             start.x++;
972                         start.y++;
973         }
974
975         /* now use the width of each line */
976         width -= numLines - 1;
977
978         for (i = 0; i < numLines; i++)
979         {
980             MoveToEx(dc, start.x + i, start.y, &oldPos);
981             LineTo(dc, start.x + i + width, start.y + height);
982
983             MoveToEx(dc, start.x + i, start.y + height - 1, &oldPos);
984             LineTo(dc, start.x + i + width, start.y - 1);
985         }
986
987         SelectObject(dc, hpsave);
988         return TRUE;
989     }
990
991     case DFCS_CAPTIONHELP:
992         /* This one breaks the flow */
993         /* FIXME: We need the Marlett font in order to get this right. */
994
995         hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
996                         ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
997                         DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
998         alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
999         bksave = SetBkMode(dc, TRANSPARENT);
1000         clrsave = GetTextColor(dc);
1001         hfsave = (HFONT)SelectObject(dc, hf);
1002         GetTextExtentPoint32A(dc, str, 1, &size);
1003
1004         if(uFlags & DFCS_INACTIVE)
1005         {
1006             SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1007             TextOutA(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
1008         }
1009         SetTextColor(dc, GetSysColor(colorIdx));
1010         TextOutA(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
1011
1012         SelectObject(dc, hfsave);
1013         SetTextColor(dc, clrsave);
1014         SetBkMode(dc, bksave);
1015         SetTextAlign(dc, alignsave);
1016         DeleteObject(hf);
1017         return TRUE;
1018
1019     case DFCS_CAPTIONMIN:
1020         Line1[0].x = Line1[3].x = myr.left   +  96*SmallDiam/750+2;
1021         Line1[1].x = Line1[2].x = Line1[0].x + 372*SmallDiam/750;
1022         Line1[0].y = Line1[1].y = myr.top    + 563*SmallDiam/750+1;
1023         Line1[2].y = Line1[3].y = Line1[0].y +  92*SmallDiam/750;
1024         Line1N = 4;
1025         Line2N = 0;
1026         break;
1027
1028     case DFCS_CAPTIONMAX:
1029         edge = 47*SmallDiam/750;
1030         Line1[0].x = Line1[5].x = myr.left +  57*SmallDiam/750+3;
1031         Line1[0].y = Line1[1].y = myr.top  + 143*SmallDiam/750+1;
1032         Line1[1].x = Line1[2].x = Line1[0].x + 562*SmallDiam/750;
1033         Line1[5].y = Line1[4].y = Line1[0].y +  93*SmallDiam/750;
1034         Line1[2].y = Line1[3].y = Line1[0].y + 513*SmallDiam/750;
1035         Line1[3].x = Line1[4].x = Line1[1].x -  edge;
1036
1037         Line2[0].x = Line2[5].x = Line1[0].x;
1038         Line2[3].x = Line2[4].x = Line1[1].x;
1039         Line2[1].x = Line2[2].x = Line1[0].x + edge;
1040         Line2[0].y = Line2[1].y = Line1[0].y;
1041         Line2[4].y = Line2[5].y = Line1[2].y;
1042         Line2[2].y = Line2[3].y = Line1[2].y - edge;
1043         Line1N = 6;
1044         Line2N = 6;
1045         break;
1046
1047     case DFCS_CAPTIONRESTORE:
1048         /* FIXME: this one looks bad at small sizes < 15x15 :( */
1049         edge = 47*SmallDiam/750;
1050         move = 420*SmallDiam/750;
1051         Line1[0].x = Line1[9].x = myr.left + 198*SmallDiam/750+2;
1052         Line1[0].y = Line1[1].y = myr.top  + 169*SmallDiam/750+1;
1053         Line1[6].y = Line1[7].y = Line1[0].y + 93*SmallDiam/750;
1054         Line1[7].x = Line1[8].x = Line1[0].x + edge;
1055         Line1[1].x = Line1[2].x = Line1[0].x + move;
1056         Line1[5].x = Line1[6].x = Line1[1].x - edge;
1057         Line1[9].y = Line1[8].y = Line1[0].y + 187*SmallDiam/750;
1058         Line1[2].y = Line1[3].y = Line1[0].y + 327*SmallDiam/750;
1059         Line1[4].y = Line1[5].y = Line1[2].y - edge;
1060         Line1[3].x = Line1[4].x = Line1[2].x - 140*SmallDiam/750;
1061
1062         Line2[1].x = Line2[2].x = Line1[3].x;
1063         Line2[7].x = Line2[8].x = Line2[1].x - edge;
1064         Line2[0].x = Line2[9].x = Line2[3].x = Line2[4].x = Line2[1].x - move;
1065         Line2[5].x = Line2[6].x = Line2[0].x + edge;
1066         Line2[0].y = Line2[1].y = Line1[9].y;
1067         Line2[4].y = Line2[5].y = Line2[8].y = Line2[9].y = Line2[0].y + 93*SmallDiam/750;
1068         Line2[2].y = Line2[3].y = Line2[0].y + 327*SmallDiam/750;
1069         Line2[6].y = Line2[7].y = Line2[2].y - edge;
1070         Line1N = 10;
1071         Line2N = 10;
1072         break;
1073
1074     default:
1075         WARN("Invalid caption; flags=0x%04x\n", uFlags);
1076         return FALSE;
1077     }
1078
1079     /* Here the drawing takes place */
1080     if(uFlags & DFCS_INACTIVE)
1081     {
1082         /* If we have an inactive button, then you see a shadow */
1083         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1084         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1085         Polygon(dc, Line1, Line1N);
1086         if(Line2N > 0)
1087             Polygon(dc, Line2, Line2N);
1088         SelectObject(dc, hpsave);
1089         SelectObject(dc, hbsave);
1090     }
1091
1092     /* Correct for the shadow shift */
1093     if (!(uFlags & DFCS_PUSHED))
1094     {
1095         for(i = 0; i < Line1N; i++)
1096         {
1097             Line1[i].x--;
1098             Line1[i].y--;
1099         }
1100         for(i = 0; i < Line2N; i++)
1101         {
1102             Line2[i].x--;
1103             Line2[i].y--;
1104         }
1105     }
1106
1107     /* Make the final picture */
1108     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(colorIdx));
1109     hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(colorIdx));
1110
1111     Polygon(dc, Line1, Line1N);
1112     if(Line2N > 0)
1113         Polygon(dc, Line2, Line2N);
1114     SelectObject(dc, hpsave);
1115     SelectObject(dc, hbsave);
1116
1117     return TRUE;
1118 }
1119
1120
1121 /************************************************************************
1122  *      UITOOLS_DrawFrameScroll
1123  *
1124  * Draw a scroll-bar control coming from DrawFrameControl()
1125  */
1126 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
1127 {
1128     POINT Line[4];
1129     RECT myr;
1130     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
1131     int i;
1132     HBRUSH hbsave, hb, hb2;
1133     HPEN hpsave, hp, hp2;
1134     int tri = 290*SmallDiam/1000 - 1;
1135     int d46, d93;
1136
1137     /*
1138      * This fixes a problem with really tiny "scroll" buttons. In particular
1139      * with the updown control.
1140      * Making sure that the arrow is as least 3 pixels wide (or high).
1141      */
1142     if (tri == 0)
1143       tri = 1;
1144
1145     switch(uFlags & 0xff)
1146     {
1147     case DFCS_SCROLLCOMBOBOX:
1148     case DFCS_SCROLLDOWN:
1149         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1150         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1151         Line[0].x = Line[2].x - tri;
1152         Line[1].x = Line[2].x + tri;
1153         Line[0].y = Line[1].y = Line[2].y - tri;
1154         break;
1155
1156     case DFCS_SCROLLUP:
1157         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1158         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1159         Line[0].x = Line[2].x - tri;
1160         Line[1].x = Line[2].x + tri;
1161         Line[0].y = Line[1].y = Line[2].y + tri;
1162         break;
1163
1164     case DFCS_SCROLLLEFT:
1165         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1166         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1167         Line[0].y = Line[2].y - tri;
1168         Line[1].y = Line[2].y + tri;
1169         Line[0].x = Line[1].x = Line[2].x + tri;
1170         break;
1171
1172     case DFCS_SCROLLRIGHT:
1173         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1174         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1175         Line[0].y = Line[2].y - tri;
1176         Line[1].y = Line[2].y + tri;
1177         Line[0].x = Line[1].x = Line[2].x - tri;
1178         break;
1179
1180     case DFCS_SCROLLSIZEGRIP:
1181         /* This one breaks the flow... */
1182         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1183         hpsave = (HPEN)SelectObject(dc, GetStockObject(NULL_PEN));
1184         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(NULL_BRUSH));
1185         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1186         {
1187             hp = hp2 = SYSCOLOR_GetPen(COLOR_WINDOWFRAME);
1188             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1189         }
1190         else
1191         {
1192             hp  = SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT);
1193             hp2 = SYSCOLOR_GetPen(COLOR_BTNSHADOW);
1194             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1195             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1196         }
1197         Line[0].x = Line[1].x = r->right-1;
1198         Line[2].y = Line[3].y = r->bottom-1;
1199         d46 = 46*SmallDiam/750;
1200         d93 = 93*SmallDiam/750;
1201
1202         i = 586*SmallDiam/750;
1203         Line[0].y = r->bottom - i - 1;
1204         Line[3].x = r->right - i - 1;
1205         Line[1].y = Line[0].y + d46;
1206         Line[2].x = Line[3].x + d46;
1207         SelectObject(dc, hb);
1208         SelectObject(dc, hp);
1209         Polygon(dc, Line, 4);
1210
1211         Line[1].y++; Line[2].x++;
1212         Line[0].y = Line[1].y + d93;
1213         Line[3].x = Line[2].x + d93;
1214         SelectObject(dc, hb2);
1215         SelectObject(dc, hp2);
1216         Polygon(dc, Line, 4);
1217
1218         i = 398*SmallDiam/750;
1219         Line[0].y = r->bottom - i - 1;
1220         Line[3].x = r->right - i - 1;
1221         Line[1].y = Line[0].y + d46;
1222         Line[2].x = Line[3].x + d46;
1223         SelectObject(dc, hb);
1224         SelectObject(dc, hp);
1225         Polygon(dc, Line, 4);
1226
1227         Line[1].y++; Line[2].x++;
1228         Line[0].y = Line[1].y + d93;
1229         Line[3].x = Line[2].x + d93;
1230         SelectObject(dc, hb2);
1231         SelectObject(dc, hp2);
1232         Polygon(dc, Line, 4);
1233
1234         i = 210*SmallDiam/750;
1235         Line[0].y = r->bottom - i - 1;
1236         Line[3].x = r->right - i - 1;
1237         Line[1].y = Line[0].y + d46;
1238         Line[2].x = Line[3].x + d46;
1239         SelectObject(dc, hb);
1240         SelectObject(dc, hp);
1241         Polygon(dc, Line, 4);
1242
1243         Line[1].y++; Line[2].x++;
1244         Line[0].y = Line[1].y + d93;
1245         Line[3].x = Line[2].x + d93;
1246         SelectObject(dc, hb2);
1247         SelectObject(dc, hp2);
1248         Polygon(dc, Line, 4);
1249
1250         SelectObject(dc, hpsave);
1251         SelectObject(dc, hbsave);
1252         return TRUE;
1253
1254     default:
1255         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1256         return FALSE;
1257     }
1258
1259     /* Here do the real scroll-bar controls end up */
1260     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1261       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1262       /* want for the normal scroll-arrow button. */
1263       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1264     else
1265       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1266
1267     if(uFlags & DFCS_INACTIVE)
1268     {
1269         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1270         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1271         Polygon(dc, Line, 3);
1272         SelectObject(dc, hpsave);
1273         SelectObject(dc, hbsave);
1274     }
1275
1276     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1277       for(i = 0; i < 3; i++)
1278       {
1279         Line[i].x--;
1280         Line[i].y--;
1281       }
1282
1283     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1284     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1285     hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(i));
1286     Polygon(dc, Line, 3);
1287     SelectObject(dc, hpsave);
1288     SelectObject(dc, hbsave);
1289
1290     return TRUE;
1291 }
1292
1293 /************************************************************************
1294  *      UITOOLS_DrawFrameMenu
1295  *
1296  * Draw a menu control coming from DrawFrameControl()
1297  */
1298 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1299 {
1300     POINT Points[6];
1301     RECT myr;
1302     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1303     int i;
1304     HBRUSH hbsave;
1305     HPEN hpsave;
1306     int xe, ye;
1307     int xc, yc;
1308     BOOL retval = TRUE;
1309
1310     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1311     /* use anything else. I think I tried all sys-colors to change things */
1312     /* without luck. It seems as if this behavior is inherited from the */
1313     /* win31 DFC() implementation... (you remember, B/W menus). */
1314
1315     FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
1316
1317     hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
1318     hpsave = (HPEN)SelectObject(dc, GetStockObject(BLACK_PEN));
1319
1320     switch(uFlags & 0xff)
1321     {
1322     case DFCS_MENUARROW:
1323         i = 187*SmallDiam/750;
1324         Points[2].x = myr.left + 468*SmallDiam/750;
1325         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1326         Points[0].y = Points[2].y - i;
1327         Points[1].y = Points[2].y + i;
1328         Points[0].x = Points[1].x = Points[2].x - i;
1329         Polygon(dc, Points, 3);
1330         break;
1331
1332     case DFCS_MENUBULLET:
1333         xe = myr.left;
1334         ye = myr.top  + SmallDiam - SmallDiam/2;
1335         xc = myr.left + SmallDiam - SmallDiam/2;
1336         yc = myr.top  + SmallDiam - SmallDiam/2;
1337         i = 234*SmallDiam/750;
1338         i = i < 1 ? 1 : i;
1339         myr.left   = xc - i+i/2;
1340         myr.right  = xc + i/2;
1341         myr.top    = yc - i+i/2;
1342         myr.bottom = yc + i/2;
1343         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1344         break;
1345
1346     case DFCS_MENUCHECK:
1347         Points[0].x = myr.left + 253*SmallDiam/1000;
1348         Points[0].y = myr.top  + 445*SmallDiam/1000;
1349         Points[1].x = myr.left + 409*SmallDiam/1000;
1350         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1351         Points[2].x = myr.left + 690*SmallDiam/1000;
1352         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1353         Points[3].x = Points[2].x;
1354         Points[3].y = Points[2].y + 3*SmallDiam/16;
1355         Points[4].x = Points[1].x;
1356         Points[4].y = Points[1].y + 3*SmallDiam/16;
1357         Points[5].x = Points[0].x;
1358         Points[5].y = Points[0].y + 3*SmallDiam/16;
1359         Polygon(dc, Points, 6);
1360         break;
1361
1362     default:
1363         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1364         retval = FALSE;
1365         break;
1366     }
1367
1368     SelectObject(dc, hpsave);
1369     SelectObject(dc, hbsave);
1370     return retval;
1371 }
1372
1373
1374 /**********************************************************************
1375  *          DrawFrameControl  (USER32.@)
1376  */
1377 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1378                                   UINT uState )
1379 {
1380     /* Win95 doesn't support drawing in other mapping modes */
1381     if(GetMapMode(hdc) != MM_TEXT)
1382         return FALSE;
1383
1384     switch(uType)
1385     {
1386     case DFC_BUTTON:
1387       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1388     case DFC_CAPTION:
1389       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1390     case DFC_MENU:
1391       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1392     /*case DFC_POPUPMENU:
1393       FIXME("DFC_POPUPMENU: not implemented\n");
1394       break;*/
1395     case DFC_SCROLL:
1396       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1397     default:
1398       WARN("(%p,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1399     }
1400     return FALSE;
1401 }