winejack.drv only supports 16bit sound so we can simplify the sound
[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         if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
470     }
471     else if(uFlags & BF_SOFT)
472     {
473         LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
474         LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
475         RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
476         RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
477     }
478     else
479     {
480         LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
481         LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
482         RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
483         RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
484     }
485
486     if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT)   LBpenplus = 1;
487     if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT)       RTpenplus = 1;
488     if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
489     if((uFlags & BF_TOPLEFT) == BF_TOPLEFT)         LTpenplus = 1;
490
491     if(LTInnerI != -1) LTInnerPen = SYSCOLOR_GetPen(LTInnerI);
492     if(LTOuterI != -1) LTOuterPen = SYSCOLOR_GetPen(LTOuterI);
493     if(RBInnerI != -1) RBInnerPen = SYSCOLOR_GetPen(RBInnerI);
494     if(RBOuterI != -1) RBOuterPen = SYSCOLOR_GetPen(RBOuterI);
495
496     MoveToEx(hdc, 0, 0, &SavePoint);
497
498     /* Draw the outer edge */
499     SelectObject(hdc, LTOuterPen);
500     if(uFlags & BF_TOP)
501     {
502         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
503         LineTo(hdc, InnerRect.right, InnerRect.top);
504     }
505     if(uFlags & BF_LEFT)
506     {
507         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
508         LineTo(hdc, InnerRect.left, InnerRect.bottom);
509     }
510     SelectObject(hdc, RBOuterPen);
511     if(uFlags & BF_BOTTOM)
512     {
513         MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
514         LineTo(hdc, InnerRect.left-1, InnerRect.bottom-1);
515     }
516     if(uFlags & BF_RIGHT)
517     {
518         MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom-1, NULL);
519         LineTo(hdc, InnerRect.right-1, InnerRect.top-1);
520     }
521
522     /* Draw the inner edge */
523     SelectObject(hdc, LTInnerPen);
524     if(uFlags & BF_TOP)
525     {
526         MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
527         LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
528     }
529     if(uFlags & BF_LEFT)
530     {
531         MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
532         LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
533     }
534     SelectObject(hdc, RBInnerPen);
535     if(uFlags & BF_BOTTOM)
536     {
537         MoveToEx(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2, NULL);
538         LineTo(hdc, InnerRect.left-1+LBpenplus, InnerRect.bottom-2);
539     }
540     if(uFlags & BF_RIGHT)
541     {
542         MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-1-RBpenplus, NULL);
543         LineTo(hdc, InnerRect.right-2, InnerRect.top-1+RTpenplus);
544     }
545
546     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
547     {
548         int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
549                 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
550
551         if(uFlags & BF_LEFT)   InnerRect.left   += add;
552         if(uFlags & BF_RIGHT)  InnerRect.right  -= add;
553         if(uFlags & BF_TOP)    InnerRect.top    += add;
554         if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
555
556         if((uFlags & BF_MIDDLE) && retval)
557         {
558             FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
559                                                        COLOR_WINDOW : COLOR_BTNFACE));
560         }
561
562         if(uFlags & BF_ADJUST)
563             *rc = InnerRect;
564     }
565
566     /* Cleanup */
567     SelectObject(hdc, SavePen);
568     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
569     return retval;
570 }
571
572
573 /**********************************************************************
574  *          DrawEdge   (USER32.@)
575  */
576 BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
577 {
578     TRACE("%p %ld,%ld-%ld,%ld %04x %04x\n",
579           hdc, rc->left, rc->top, rc->right, rc->bottom, edge, flags );
580
581     if(flags & BF_DIAGONAL)
582       return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
583     else
584       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
585 }
586
587
588 /************************************************************************
589  *      UITOOLS_MakeSquareRect
590  *
591  * Utility to create a square rectangle and returning the width
592  */
593 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
594 {
595     int Width  = src->right - src->left;
596     int Height = src->bottom - src->top;
597     int SmallDiam = Width > Height ? Height : Width;
598
599     *dst = *src;
600
601     /* Make it a square box */
602     if(Width < Height)      /* SmallDiam == Width */
603     {
604         dst->top += (Height-Width)/2;
605         dst->bottom = dst->top + SmallDiam;
606     }
607     else if(Width > Height) /* SmallDiam == Height */
608     {
609         dst->left += (Width-Height)/2;
610         dst->right = dst->left + SmallDiam;
611     }
612
613    return SmallDiam;
614 }
615
616 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
617 {
618     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
619     {
620       HBITMAP hbm = CreateBitmap(8, 8, 1, 1, wPattern_AA55);
621       HBRUSH hbsave;
622       HBRUSH hb = CreatePatternBrush(hbm);
623       COLORREF bg;
624
625       FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
626       bg = SetBkColor(dc, RGB(255, 255, 255));
627       hbsave = (HBRUSH)SelectObject(dc, hb);
628       PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
629       SelectObject(dc, hbsave);
630       SetBkColor(dc, bg);
631       DeleteObject(hb);
632       DeleteObject(hbm);
633     }
634     else
635     {
636         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
637     }
638 }
639
640 /************************************************************************
641  *      UITOOLS_DFC_ButtonPush
642  *
643  * Draw a push button coming from DrawFrameControl()
644  *
645  * Does a pretty good job in emulating MS behavior. Some quirks are
646  * however there because MS uses a TrueType font (Marlett) to draw
647  * the buttons.
648  */
649 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
650 {
651     UINT edge;
652     RECT myr = *r;
653
654     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
655         edge = EDGE_SUNKEN;
656     else
657         edge = EDGE_RAISED;
658
659     if(uFlags & DFCS_CHECKED)
660     {
661         if(uFlags & DFCS_MONO)
662             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
663         else
664             UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
665
666         if (!(uFlags & DFCS_TRANSPARENT))
667             UITOOLS_DrawCheckedRect( dc, &myr );
668     }
669     else
670     {
671         if(uFlags & DFCS_MONO)
672         {
673             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
674             if (!(uFlags & DFCS_TRANSPARENT))
675                 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
676         }
677         else
678         {
679             UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags & DFCS_FLAT) | ((uFlags & DFCS_TRANSPARENT) ? 0 : BF_MIDDLE) | BF_RECT);
680         }
681     }
682
683     /* Adjust rectangle if asked */
684     if(uFlags & DFCS_ADJUSTRECT)
685     {
686         r->left   += 2;
687         r->right  -= 2;
688         r->top    += 2;
689         r->bottom -= 2;
690     }
691
692     return TRUE;
693 }
694
695
696 /************************************************************************
697  *      UITOOLS_DFC_ButtonChcek
698  *
699  * Draw a check/3state button coming from DrawFrameControl()
700  *
701  * Does a pretty good job in emulating MS behavior. Some quirks are
702  * however there because MS uses a TrueType font (Marlett) to draw
703  * the buttons.
704  */
705
706 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
707 {
708     RECT myr, bar;
709     UINT flags = BF_RECT | BF_ADJUST;
710
711     UITOOLS_MakeSquareRect(r, &myr);
712
713     if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
714     else if(uFlags & DFCS_MONO) flags |= BF_MONO;
715
716     UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
717
718     if (!(uFlags & DFCS_TRANSPARENT))
719     {
720         if(uFlags & (DFCS_INACTIVE | DFCS_PUSHED))
721             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
722         else if( (uFlags & DFCS_BUTTON3STATE) && (uFlags & DFCS_CHECKED) )
723             UITOOLS_DrawCheckedRect( dc, &myr );
724         else
725             FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
726     }
727
728     if(uFlags & DFCS_CHECKED)
729     {
730         int i, k;
731         i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
732                 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
733
734         /* draw 7 bars, with h=3w to form the check */
735         bar.left = myr.left;
736         bar.top = myr.top + 2;
737         for (k = 0; k < 7; k++) {
738             bar.left = bar.left + 1;
739             bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
740             bar.bottom = bar.top + 3;
741             bar.right = bar.left + 1;
742             FillRect(dc, &bar, GetSysColorBrush(i));
743         }
744     }
745     return TRUE;
746 }
747
748
749 /************************************************************************
750  *      UITOOLS_DFC_ButtonRadio
751  *
752  * Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
753  *
754  * Does a pretty good job in emulating MS behavior. Some quirks are
755  * however there because MS uses a TrueType font (Marlett) to draw
756  * the buttons.
757  */
758 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
759 {
760     RECT myr;
761     int i;
762     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
763     int BorderShrink = SmallDiam / 16;
764     HPEN hpsave;
765     HBRUSH hbsave;
766     int xc, yc;
767
768     if(BorderShrink < 1) BorderShrink = 1;
769
770     if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
771         FillRect(dc, r, (HBRUSH)GetStockObject(BLACK_BRUSH));
772
773     xc = myr.left + SmallDiam - SmallDiam/2;
774     yc = myr.top  + SmallDiam - SmallDiam/2;
775
776     /* Define bounding box */
777     i = 14*SmallDiam/16;
778     myr.left   = xc - i+i/2;
779     myr.right  = xc + i/2;
780     myr.top    = yc - i+i/2;
781     myr.bottom = yc + i/2;
782
783     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
784     {
785         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
786         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
787         SelectObject(dc, hbsave);
788     }
789     else
790     {
791         if(uFlags & (DFCS_FLAT|DFCS_MONO))
792         {
793             hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
794             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
795             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
796             SelectObject(dc, hbsave);
797             SelectObject(dc, hpsave);
798         }
799         else
800         {
801             hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
802             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
803             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
804
805             SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNSHADOW));
806             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
807             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
808
809             myr.left   += BorderShrink;
810             myr.right  -= BorderShrink;
811             myr.top    += BorderShrink;
812             myr.bottom -= BorderShrink;
813
814             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DLIGHT));
815             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
816             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
817
818             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DDKSHADOW));
819             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
820             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
821             SelectObject(dc, hbsave);
822             SelectObject(dc, hpsave);
823         }
824
825         i = 10*SmallDiam/16;
826         myr.left   = xc - i+i/2;
827         myr.right  = xc + i/2;
828         myr.top    = yc - i+i/2;
829         myr.bottom = yc + i/2;
830         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
831         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(i));
832         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
833         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
834         SelectObject(dc, hbsave);
835         SelectObject(dc, hpsave);
836     }
837
838     if(uFlags & DFCS_CHECKED)
839     {
840         i = 6*SmallDiam/16;
841         i = i < 1 ? 1 : i;
842         myr.left   = xc - i+i/2;
843         myr.right  = xc + i/2;
844         myr.top    = yc - i+i/2;
845         myr.bottom = yc + i/2;
846
847         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
848         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
849         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(i));
850         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
851         SelectObject(dc, hpsave);
852         SelectObject(dc, hbsave);
853     }
854
855     /* FIXME: M$ has a polygon in the center at relative points: */
856     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
857     /* 0.476, 0.525 */
858     /* 0.500, 0.500 */
859     /* 0.500, 0.499 */
860     /* when the button is unchecked. The reason for it is unknown. The */
861     /* color is COLOR_BTNHIGHLIGHT, although the polygon gets painted at */
862     /* least 3 times (it looks like a clip-region when you see it happen). */
863     /* I do not really see a reason why this should be implemented. If you */
864     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
865     /* font. */
866
867     return TRUE;
868 }
869
870 /***********************************************************************
871  *           UITOOLS_DrawFrameButton
872  */
873 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
874 {
875     switch(uState & 0xff)
876     {
877     case DFCS_BUTTONPUSH:
878         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
879
880     case DFCS_BUTTONCHECK:
881     case DFCS_BUTTON3STATE:
882         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
883
884     case DFCS_BUTTONRADIOIMAGE:
885     case DFCS_BUTTONRADIOMASK:
886     case DFCS_BUTTONRADIO:
887         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
888
889     default:
890         WARN("Invalid button state=0x%04x\n", uState);
891     }
892
893     return FALSE;
894 }
895
896 /***********************************************************************
897  *           UITOOLS_DrawFrameCaption
898  *
899  * Draw caption buttons (win95), coming from DrawFrameControl()
900  */
901
902 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
903 {
904     POINT Line1[10];
905     POINT Line2[10];
906     int Line1N;
907     int Line2N;
908     RECT myr;
909     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
910     int i;
911     HBRUSH hbsave;
912     HPEN hpsave;
913     HFONT hfsave, hf;
914     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
915     int xc = (myr.left+myr.right)/2;
916     int yc = (myr.top+myr.bottom)/2;
917     int edge, move;
918     char str[2] = "?";
919     UINT alignsave;
920     int bksave;
921     COLORREF clrsave;
922     SIZE size;
923
924     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
925
926     switch(uFlags & 0xff)
927     {
928     case DFCS_CAPTIONCLOSE:
929     {
930         /* The "X" is made by drawing a series of lines.
931          * The number of lines drawn depends on the size
932          * of the bounding rect.  e.g. For a 6x5 inside rect,
933          * two lines are drawn from top-left to bottom-right,
934          * and two lines from top-right to bottom-left.
935          *
936          * 0 1 2 3 4 5       0 1 2 3 4 5
937          * 1 * *                     * *
938          * 2   * *                 * *
939          * 3     * *             * *
940          * 4       * *         * *
941          *
942          * Drawing one line for every 6 pixels in width
943          * seems to provide the best proportions.
944          */
945
946         POINT start, oldPos;
947         INT width = myr.right - myr.left - 5;
948         INT height = myr.bottom - myr.top - 6;
949         INT numLines = (width / 6) + 1;
950
951         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(colorIdx));
952
953         start.x = myr.left + 2;
954         start.y = myr.top + 2;
955
956         if (width < 6)
957             height = width;
958         else
959             start.y++;
960
961         if (uFlags & DFCS_PUSHED)
962         {
963             start.x++;
964                         start.y++;
965         }
966
967         /* now use the width of each line */
968         width -= numLines - 1;
969
970         for (i = 0; i < numLines; i++)
971         {
972             MoveToEx(dc, start.x + i, start.y, &oldPos);
973             LineTo(dc, start.x + i + width, start.y + height);
974
975             MoveToEx(dc, start.x + i, start.y + height - 1, &oldPos);
976             LineTo(dc, start.x + i + width, start.y - 1);
977         }
978
979         SelectObject(dc, hpsave);
980         return TRUE;
981     }
982
983     case DFCS_CAPTIONHELP:
984         /* This one breaks the flow */
985         /* FIXME: We need the Marlett font in order to get this right. */
986
987         hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
988                         ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
989                         DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
990         alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
991         bksave = SetBkMode(dc, TRANSPARENT);
992         clrsave = GetTextColor(dc);
993         hfsave = (HFONT)SelectObject(dc, hf);
994         GetTextExtentPoint32A(dc, str, 1, &size);
995
996         if(uFlags & DFCS_INACTIVE)
997         {
998             SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
999             TextOutA(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
1000         }
1001         SetTextColor(dc, GetSysColor(colorIdx));
1002         TextOutA(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
1003
1004         SelectObject(dc, hfsave);
1005         SetTextColor(dc, clrsave);
1006         SetBkMode(dc, bksave);
1007         SetTextAlign(dc, alignsave);
1008         DeleteObject(hf);
1009         return TRUE;
1010
1011     case DFCS_CAPTIONMIN:
1012         Line1[0].x = Line1[3].x = myr.left   +  96*SmallDiam/750+2;
1013         Line1[1].x = Line1[2].x = Line1[0].x + 372*SmallDiam/750;
1014         Line1[0].y = Line1[1].y = myr.top    + 563*SmallDiam/750+1;
1015         Line1[2].y = Line1[3].y = Line1[0].y +  92*SmallDiam/750;
1016         Line1N = 4;
1017         Line2N = 0;
1018         break;
1019
1020     case DFCS_CAPTIONMAX:
1021         edge = 47*SmallDiam/750;
1022         Line1[0].x = Line1[5].x = myr.left +  57*SmallDiam/750+3;
1023         Line1[0].y = Line1[1].y = myr.top  + 143*SmallDiam/750+1;
1024         Line1[1].x = Line1[2].x = Line1[0].x + 562*SmallDiam/750;
1025         Line1[5].y = Line1[4].y = Line1[0].y +  93*SmallDiam/750;
1026         Line1[2].y = Line1[3].y = Line1[0].y + 513*SmallDiam/750;
1027         Line1[3].x = Line1[4].x = Line1[1].x -  edge;
1028
1029         Line2[0].x = Line2[5].x = Line1[0].x;
1030         Line2[3].x = Line2[4].x = Line1[1].x;
1031         Line2[1].x = Line2[2].x = Line1[0].x + edge;
1032         Line2[0].y = Line2[1].y = Line1[0].y;
1033         Line2[4].y = Line2[5].y = Line1[2].y;
1034         Line2[2].y = Line2[3].y = Line1[2].y - edge;
1035         Line1N = 6;
1036         Line2N = 6;
1037         break;
1038
1039     case DFCS_CAPTIONRESTORE:
1040         /* FIXME: this one looks bad at small sizes < 15x15 :( */
1041         edge = 47*SmallDiam/750;
1042         move = 420*SmallDiam/750;
1043         Line1[0].x = Line1[9].x = myr.left + 198*SmallDiam/750+2;
1044         Line1[0].y = Line1[1].y = myr.top  + 169*SmallDiam/750+1;
1045         Line1[6].y = Line1[7].y = Line1[0].y + 93*SmallDiam/750;
1046         Line1[7].x = Line1[8].x = Line1[0].x + edge;
1047         Line1[1].x = Line1[2].x = Line1[0].x + move;
1048         Line1[5].x = Line1[6].x = Line1[1].x - edge;
1049         Line1[9].y = Line1[8].y = Line1[0].y + 187*SmallDiam/750;
1050         Line1[2].y = Line1[3].y = Line1[0].y + 327*SmallDiam/750;
1051         Line1[4].y = Line1[5].y = Line1[2].y - edge;
1052         Line1[3].x = Line1[4].x = Line1[2].x - 140*SmallDiam/750;
1053
1054         Line2[1].x = Line2[2].x = Line1[3].x;
1055         Line2[7].x = Line2[8].x = Line2[1].x - edge;
1056         Line2[0].x = Line2[9].x = Line2[3].x = Line2[4].x = Line2[1].x - move;
1057         Line2[5].x = Line2[6].x = Line2[0].x + edge;
1058         Line2[0].y = Line2[1].y = Line1[9].y;
1059         Line2[4].y = Line2[5].y = Line2[8].y = Line2[9].y = Line2[0].y + 93*SmallDiam/750;
1060         Line2[2].y = Line2[3].y = Line2[0].y + 327*SmallDiam/750;
1061         Line2[6].y = Line2[7].y = Line2[2].y - edge;
1062         Line1N = 10;
1063         Line2N = 10;
1064         break;
1065
1066     default:
1067         WARN("Invalid caption; flags=0x%04x\n", uFlags);
1068         return FALSE;
1069     }
1070
1071     /* Here the drawing takes place */
1072     if(uFlags & DFCS_INACTIVE)
1073     {
1074         /* If we have an inactive button, then you see a shadow */
1075         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1076         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1077         Polygon(dc, Line1, Line1N);
1078         if(Line2N > 0)
1079             Polygon(dc, Line2, Line2N);
1080         SelectObject(dc, hpsave);
1081         SelectObject(dc, hbsave);
1082     }
1083
1084     /* Correct for the shadow shift */
1085     if (!(uFlags & DFCS_PUSHED))
1086     {
1087         for(i = 0; i < Line1N; i++)
1088         {
1089             Line1[i].x--;
1090             Line1[i].y--;
1091         }
1092         for(i = 0; i < Line2N; i++)
1093         {
1094             Line2[i].x--;
1095             Line2[i].y--;
1096         }
1097     }
1098
1099     /* Make the final picture */
1100     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(colorIdx));
1101     hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(colorIdx));
1102
1103     Polygon(dc, Line1, Line1N);
1104     if(Line2N > 0)
1105         Polygon(dc, Line2, Line2N);
1106     SelectObject(dc, hpsave);
1107     SelectObject(dc, hbsave);
1108
1109     return TRUE;
1110 }
1111
1112
1113 /************************************************************************
1114  *      UITOOLS_DrawFrameScroll
1115  *
1116  * Draw a scroll-bar control coming from DrawFrameControl()
1117  */
1118 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
1119 {
1120     POINT Line[4];
1121     RECT myr;
1122     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
1123     int i;
1124     HBRUSH hbsave, hb, hb2;
1125     HPEN hpsave, hp, hp2;
1126     int tri = 290*SmallDiam/1000 - 1;
1127     int d46, d93;
1128
1129     /*
1130      * This fixes a problem with really tiny "scroll" buttons. In particular
1131      * with the updown control.
1132      * Making sure that the arrow is as least 3 pixels wide (or high).
1133      */
1134     if (tri == 0)
1135       tri = 1;
1136
1137     switch(uFlags & 0xff)
1138     {
1139     case DFCS_SCROLLCOMBOBOX:
1140     case DFCS_SCROLLDOWN:
1141         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1142         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1143         Line[0].x = Line[2].x - tri;
1144         Line[1].x = Line[2].x + tri;
1145         Line[0].y = Line[1].y = Line[2].y - tri;
1146         break;
1147
1148     case DFCS_SCROLLUP:
1149         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1150         Line[2].y = myr.bottom - (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_SCROLLLEFT:
1157         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1158         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1159         Line[0].y = Line[2].y - tri;
1160         Line[1].y = Line[2].y + tri;
1161         Line[0].x = Line[1].x = Line[2].x + tri;
1162         break;
1163
1164     case DFCS_SCROLLRIGHT:
1165         Line[2].x = myr.left + 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_SCROLLSIZEGRIP:
1173         /* This one breaks the flow... */
1174         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1175         hpsave = (HPEN)SelectObject(dc, GetStockObject(NULL_PEN));
1176         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(NULL_BRUSH));
1177         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1178         {
1179             hp = hp2 = SYSCOLOR_GetPen(COLOR_WINDOWFRAME);
1180             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1181         }
1182         else
1183         {
1184             hp  = SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT);
1185             hp2 = SYSCOLOR_GetPen(COLOR_BTNSHADOW);
1186             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1187             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1188         }
1189         Line[0].x = Line[1].x = r->right-1;
1190         Line[2].y = Line[3].y = r->bottom-1;
1191         d46 = 46*SmallDiam/750;
1192         d93 = 93*SmallDiam/750;
1193
1194         i = 586*SmallDiam/750;
1195         Line[0].y = r->bottom - i - 1;
1196         Line[3].x = r->right - i - 1;
1197         Line[1].y = Line[0].y + d46;
1198         Line[2].x = Line[3].x + d46;
1199         SelectObject(dc, hb);
1200         SelectObject(dc, hp);
1201         Polygon(dc, Line, 4);
1202
1203         Line[1].y++; Line[2].x++;
1204         Line[0].y = Line[1].y + d93;
1205         Line[3].x = Line[2].x + d93;
1206         SelectObject(dc, hb2);
1207         SelectObject(dc, hp2);
1208         Polygon(dc, Line, 4);
1209
1210         i = 398*SmallDiam/750;
1211         Line[0].y = r->bottom - i - 1;
1212         Line[3].x = r->right - i - 1;
1213         Line[1].y = Line[0].y + d46;
1214         Line[2].x = Line[3].x + d46;
1215         SelectObject(dc, hb);
1216         SelectObject(dc, hp);
1217         Polygon(dc, Line, 4);
1218
1219         Line[1].y++; Line[2].x++;
1220         Line[0].y = Line[1].y + d93;
1221         Line[3].x = Line[2].x + d93;
1222         SelectObject(dc, hb2);
1223         SelectObject(dc, hp2);
1224         Polygon(dc, Line, 4);
1225
1226         i = 210*SmallDiam/750;
1227         Line[0].y = r->bottom - i - 1;
1228         Line[3].x = r->right - i - 1;
1229         Line[1].y = Line[0].y + d46;
1230         Line[2].x = Line[3].x + d46;
1231         SelectObject(dc, hb);
1232         SelectObject(dc, hp);
1233         Polygon(dc, Line, 4);
1234
1235         Line[1].y++; Line[2].x++;
1236         Line[0].y = Line[1].y + d93;
1237         Line[3].x = Line[2].x + d93;
1238         SelectObject(dc, hb2);
1239         SelectObject(dc, hp2);
1240         Polygon(dc, Line, 4);
1241
1242         SelectObject(dc, hpsave);
1243         SelectObject(dc, hbsave);
1244         return TRUE;
1245
1246     default:
1247         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1248         return FALSE;
1249     }
1250
1251     /* Here do the real scroll-bar controls end up */
1252     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1253       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1254       /* want for the normal scroll-arrow button. */
1255       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1256     else
1257       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1258
1259     if(uFlags & DFCS_INACTIVE)
1260     {
1261         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1262         hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1263         Polygon(dc, Line, 3);
1264         SelectObject(dc, hpsave);
1265         SelectObject(dc, hbsave);
1266     }
1267
1268     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1269       for(i = 0; i < 3; i++)
1270       {
1271         Line[i].x--;
1272         Line[i].y--;
1273       }
1274
1275     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1276     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1277     hpsave = (HPEN)SelectObject(dc, SYSCOLOR_GetPen(i));
1278     Polygon(dc, Line, 3);
1279     SelectObject(dc, hpsave);
1280     SelectObject(dc, hbsave);
1281
1282     return TRUE;
1283 }
1284
1285 /************************************************************************
1286  *      UITOOLS_DrawFrameMenu
1287  *
1288  * Draw a menu control coming from DrawFrameControl()
1289  */
1290 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1291 {
1292     POINT Points[6];
1293     RECT myr;
1294     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1295     int i;
1296     HBRUSH hbsave;
1297     HPEN hpsave;
1298     int xe, ye;
1299     int xc, yc;
1300     BOOL retval = TRUE;
1301
1302     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1303     /* use anything else. I think I tried all sys-colors to change things */
1304     /* without luck. It seems as if this behavior is inherited from the */
1305     /* win31 DFC() implementation... (you remember, B/W menus). */
1306
1307     FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
1308
1309     hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
1310     hpsave = (HPEN)SelectObject(dc, GetStockObject(BLACK_PEN));
1311
1312     switch(uFlags & 0xff)
1313     {
1314     case DFCS_MENUARROW:
1315         i = 187*SmallDiam/750;
1316         Points[2].x = myr.left + 468*SmallDiam/750;
1317         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1318         Points[0].y = Points[2].y - i;
1319         Points[1].y = Points[2].y + i;
1320         Points[0].x = Points[1].x = Points[2].x - i;
1321         Polygon(dc, Points, 3);
1322         break;
1323
1324     case DFCS_MENUBULLET:
1325         xe = myr.left;
1326         ye = myr.top  + SmallDiam - SmallDiam/2;
1327         xc = myr.left + SmallDiam - SmallDiam/2;
1328         yc = myr.top  + SmallDiam - SmallDiam/2;
1329         i = 234*SmallDiam/750;
1330         i = i < 1 ? 1 : i;
1331         myr.left   = xc - i+i/2;
1332         myr.right  = xc + i/2;
1333         myr.top    = yc - i+i/2;
1334         myr.bottom = yc + i/2;
1335         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1336         break;
1337
1338     case DFCS_MENUCHECK:
1339         Points[0].x = myr.left + 253*SmallDiam/1000;
1340         Points[0].y = myr.top  + 445*SmallDiam/1000;
1341         Points[1].x = myr.left + 409*SmallDiam/1000;
1342         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1343         Points[2].x = myr.left + 690*SmallDiam/1000;
1344         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1345         Points[3].x = Points[2].x;
1346         Points[3].y = Points[2].y + 3*SmallDiam/16;
1347         Points[4].x = Points[1].x;
1348         Points[4].y = Points[1].y + 3*SmallDiam/16;
1349         Points[5].x = Points[0].x;
1350         Points[5].y = Points[0].y + 3*SmallDiam/16;
1351         Polygon(dc, Points, 6);
1352         break;
1353
1354     default:
1355         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1356         retval = FALSE;
1357         break;
1358     }
1359
1360     SelectObject(dc, hpsave);
1361     SelectObject(dc, hbsave);
1362     return retval;
1363 }
1364
1365
1366 /**********************************************************************
1367  *          DrawFrameControl  (USER32.@)
1368  */
1369 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1370                                   UINT uState )
1371 {
1372     /* Win95 doesn't support drawing in other mapping modes */
1373     if(GetMapMode(hdc) != MM_TEXT)
1374         return FALSE;
1375
1376     switch(uType)
1377     {
1378     case DFC_BUTTON:
1379       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1380     case DFC_CAPTION:
1381       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1382     case DFC_MENU:
1383       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1384     /*case DFC_POPUPMENU:
1385       FIXME("DFC_POPUPMENU: not implemented\n");
1386       break;*/
1387     case DFC_SCROLL:
1388       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1389     default:
1390       WARN("(%p,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1391     }
1392     return FALSE;
1393 }