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