Added stubs for msrle32.dll and implemented RLE8 decoder.
[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 "user.h"
13 #include "debugtools.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 signed 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 signed 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 signed 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 signed 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 signed 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 signed 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 signed 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 signed 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 signed char LTRBOuterFlat[] = {
84     -1,                COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
85     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
86     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
87     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
88 };
89
90 static const signed char LTRBInnerFlat[] = {
91     -1, -1,              -1,              -1,
92     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,    
93     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,    
94     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,    
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     signed 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     signed char LTInnerI, LTOuterI;
423     signed 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 rectangles 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  *          DrawEdge   (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.@)
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_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
709 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
710 {
711     RECT myr, bar;
712     UINT flags = BF_RECT | BF_ADJUST;
713     UITOOLS_MakeSquareRect(r, &myr);
714
715     if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
716     else if(uFlags & DFCS_MONO) flags |= BF_MONO;
717
718     UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
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     {
726         FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
727     }
728
729     if(uFlags & DFCS_CHECKED)
730     {
731         int i, k;
732         i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
733                 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
734
735         /* draw 7 bars, with h=3w to form the check */
736         bar.left = myr.left;
737         bar.top = myr.top + 2;
738         for (k = 0; k < 7; k++) {
739             bar.left = bar.left + 1;
740             bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
741             bar.bottom = bar.top + 3;
742             bar.right = bar.left + 1;
743             FillRect(dc, &bar, GetSysColorBrush(i));
744         }
745     }
746     return TRUE;
747 }
748
749
750 /************************************************************************
751  *      UITOOLS_DFC_ButtonRadio
752  *
753  * Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
754  *
755  * Does a pretty good job in emulating MS behavior. Some quirks are
756  * however there because MS uses a TrueType font (Marlett) to draw
757  * the buttons.
758  */
759 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
760 {
761     RECT myr;
762     int i;
763     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
764     int BorderShrink = SmallDiam / 16;
765     HPEN hpsave;
766     HBRUSH hbsave;
767     int xc, yc;
768
769     if(BorderShrink < 1) BorderShrink = 1;
770
771     if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
772     {
773         FillRect(dc, r, (HBRUSH)GetStockObject(BLACK_BRUSH));
774     }
775
776     xc = myr.left + SmallDiam - SmallDiam/2;
777     yc = myr.top  + SmallDiam - SmallDiam/2;
778
779     /* Define bounding box */
780     i = 14*SmallDiam/16;
781     myr.left   = xc - i+i/2;
782     myr.right  = xc + i/2;
783     myr.top    = yc - i+i/2;
784     myr.bottom = yc + i/2;
785
786     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
787     {
788         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
789         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
790         SelectObject(dc, hbsave);
791     }
792     else
793     {
794         if(uFlags & (DFCS_FLAT|DFCS_MONO))
795         {
796             hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_WINDOWFRAME));
797             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
798             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
799             SelectObject(dc, hbsave);
800             SelectObject(dc, hpsave);
801         }
802         else
803         {
804             hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
805             hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
806             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
807
808             SelectObject(dc, GetSysColorPen(COLOR_BTNSHADOW));
809             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
810             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
811
812             myr.left   += BorderShrink;
813             myr.right  -= BorderShrink;
814             myr.top    += BorderShrink;
815             myr.bottom -= BorderShrink;
816
817             SelectObject(dc, GetSysColorPen(COLOR_3DLIGHT));
818             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
819             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
820
821             SelectObject(dc, GetSysColorPen(COLOR_3DDKSHADOW));
822             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
823             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
824             SelectObject(dc, hbsave);
825             SelectObject(dc, hpsave);
826         }
827
828         i = 10*SmallDiam/16;
829         myr.left   = xc - i+i/2;
830         myr.right  = xc + i/2;
831         myr.top    = yc - i+i/2;
832         myr.bottom = yc + i/2;
833         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
834         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
835         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
836         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
837         SelectObject(dc, hbsave);
838         SelectObject(dc, hpsave);
839     }
840
841     if(uFlags & DFCS_CHECKED)
842     {
843         i = 6*SmallDiam/16;
844         i = i < 1 ? 1 : i;
845         myr.left   = xc - i+i/2;
846         myr.right  = xc + i/2;
847         myr.top    = yc - i+i/2;
848         myr.bottom = yc + i/2;
849
850         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
851         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
852         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
853         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
854         SelectObject(dc, hpsave);
855         SelectObject(dc, hbsave);
856     }
857
858     /* FIXME: M$ has a polygon in the center at relative points: */
859     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
860     /* 0.476, 0.525 */
861     /* 0.500, 0.500 */
862     /* 0.500, 0.499 */
863     /* when the button is unchecked. The reason for it is unknown. The */
864     /* color is COLOR_BTNHIGHLIGHT, although the polygon gets painted at */
865     /* least 3 times (it looks like a clip-region when you see it happen). */
866     /* I do not really see a reason why this should be implemented. If you */
867     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
868     /* font. */
869
870     return TRUE;
871 }
872
873 /***********************************************************************
874  *           UITOOLS_DrawFrameButton
875  */
876 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
877 {
878     switch(uState & 0xff)
879     {
880     case DFCS_BUTTONPUSH:
881         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
882
883     case DFCS_BUTTONCHECK:
884     case DFCS_BUTTON3STATE:
885         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
886
887     case DFCS_BUTTONRADIOIMAGE:
888     case DFCS_BUTTONRADIOMASK:
889     case DFCS_BUTTONRADIO:
890         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
891
892     default:
893         WARN("Invalid button state=0x%04x\n", uState);
894     }
895
896     return FALSE;
897 }
898
899 /***********************************************************************
900  *           UITOOLS_DrawFrameCaption
901  *
902  * Draw caption buttons (win95), coming from DrawFrameControl()
903  */
904
905 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
906 {
907     POINT Line1[10];
908     POINT Line2[10];
909     int Line1N;
910     int Line2N;
911     RECT myr;
912     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
913     int i;
914     HBRUSH hbsave;
915     HPEN hpsave;
916     HFONT hfsave, hf;
917     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
918     int xc = (myr.left+myr.right)/2;
919     int yc = (myr.top+myr.bottom)/2;
920     int edge, move;
921     char str[2] = "?";
922     UINT alignsave;
923     int bksave;
924     COLORREF clrsave;
925     SIZE size;
926
927     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
928
929     switch(uFlags & 0xff)
930     {
931     case DFCS_CAPTIONCLOSE:
932     {
933         /* The "X" is made by drawing a series of lines.  
934          * The number of lines drawn depends on the size 
935          * of the bounding rect.  e.g. For a 6x5 inside rect,
936          * two lines are drawn from top-left to bottom-right,
937          * and two lines from top-right to bottom-left.
938          *
939          * 0 1 2 3 4 5       0 1 2 3 4 5
940          * 1 * *                     * *
941          * 2   * *                 * *
942          * 3     * *             * *
943          * 4       * *         * *
944          *
945          * Drawing one line for every 6 pixels in width
946          * seems to provide the best proportions.
947          */
948
949         POINT start, oldPos;
950         INT width = myr.right - myr.left - 5;
951         INT height = myr.bottom - myr.top - 6;
952         INT numLines = (width / 6) + 1;
953
954         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
955
956         start.x = myr.left + 2;
957         start.y = myr.top + 2;
958
959         if (width < 6)
960             height = width;
961         else
962             start.y++;
963
964         if (uFlags & DFCS_PUSHED)
965         {
966             start.x++;
967                         start.y++;
968         }
969
970         /* now use the width of each line */
971         width -= numLines - 1;
972
973         for (i = 0; i < numLines; i++)
974         {
975             MoveToEx(dc, start.x + i, start.y, &oldPos);
976             LineTo(dc, start.x + i + width, start.y + height);
977
978             MoveToEx(dc, start.x + i, start.y + height - 1, &oldPos);
979             LineTo(dc, start.x + i + width, start.y - 1);
980         }
981
982         SelectObject(dc, hpsave);
983         return TRUE;
984     }
985
986     case DFCS_CAPTIONHELP:
987         /* This one breaks the flow */
988         /* FIXME: We need the Marlett font in order to get this right. */
989
990         hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
991                         ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
992                         DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
993         alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
994         bksave = SetBkMode(dc, TRANSPARENT);
995         clrsave = GetTextColor(dc);
996         hfsave = (HFONT)SelectObject(dc, hf);
997         GetTextExtentPoint32A(dc, str, 1, &size);
998
999         if(uFlags & DFCS_INACTIVE)
1000         {
1001             SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1002             TextOutA(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
1003         }
1004         SetTextColor(dc, GetSysColor(colorIdx));
1005         TextOutA(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
1006
1007         SelectObject(dc, hfsave);
1008         SetTextColor(dc, clrsave);
1009         SetBkMode(dc, bksave);
1010         SetTextAlign(dc, alignsave);
1011         DeleteObject(hf);
1012         return TRUE;
1013
1014     case DFCS_CAPTIONMIN:
1015         Line1[0].x = Line1[3].x = myr.left   +  96*SmallDiam/750+2;
1016         Line1[1].x = Line1[2].x = Line1[0].x + 372*SmallDiam/750;
1017         Line1[0].y = Line1[1].y = myr.top    + 563*SmallDiam/750+1;
1018         Line1[2].y = Line1[3].y = Line1[0].y +  92*SmallDiam/750;
1019         Line1N = 4;
1020         Line2N = 0;
1021         break;
1022
1023     case DFCS_CAPTIONMAX:
1024         edge = 47*SmallDiam/750;
1025         Line1[0].x = Line1[5].x = myr.left +  57*SmallDiam/750+3;
1026         Line1[0].y = Line1[1].y = myr.top  + 143*SmallDiam/750+1;
1027         Line1[1].x = Line1[2].x = Line1[0].x + 562*SmallDiam/750;
1028         Line1[5].y = Line1[4].y = Line1[0].y +  93*SmallDiam/750;
1029         Line1[2].y = Line1[3].y = Line1[0].y + 513*SmallDiam/750;
1030         Line1[3].x = Line1[4].x = Line1[1].x -  edge;
1031
1032         Line2[0].x = Line2[5].x = Line1[0].x;
1033         Line2[3].x = Line2[4].x = Line1[1].x;
1034         Line2[1].x = Line2[2].x = Line1[0].x + edge;
1035         Line2[0].y = Line2[1].y = Line1[0].y;
1036         Line2[4].y = Line2[5].y = Line1[2].y;
1037         Line2[2].y = Line2[3].y = Line1[2].y - edge;
1038         Line1N = 6;
1039         Line2N = 6;
1040         break;
1041
1042     case DFCS_CAPTIONRESTORE:
1043         /* FIXME: this one looks bad at small sizes < 15x15 :( */
1044         edge = 47*SmallDiam/750;
1045         move = 420*SmallDiam/750;
1046         Line1[0].x = Line1[9].x = myr.left + 198*SmallDiam/750+2;
1047         Line1[0].y = Line1[1].y = myr.top  + 169*SmallDiam/750+1;
1048         Line1[6].y = Line1[7].y = Line1[0].y + 93*SmallDiam/750;
1049         Line1[7].x = Line1[8].x = Line1[0].x + edge;
1050         Line1[1].x = Line1[2].x = Line1[0].x + move;
1051         Line1[5].x = Line1[6].x = Line1[1].x - edge;
1052         Line1[9].y = Line1[8].y = Line1[0].y + 187*SmallDiam/750;
1053         Line1[2].y = Line1[3].y = Line1[0].y + 327*SmallDiam/750;
1054         Line1[4].y = Line1[5].y = Line1[2].y - edge;
1055         Line1[3].x = Line1[4].x = Line1[2].x - 140*SmallDiam/750;
1056
1057         Line2[1].x = Line2[2].x = Line1[3].x;
1058         Line2[7].x = Line2[8].x = Line2[1].x - edge;
1059         Line2[0].x = Line2[9].x = Line2[3].x = Line2[4].x = Line2[1].x - move;
1060         Line2[5].x = Line2[6].x = Line2[0].x + edge;
1061         Line2[0].y = Line2[1].y = Line1[9].y;
1062         Line2[4].y = Line2[5].y = Line2[8].y = Line2[9].y = Line2[0].y + 93*SmallDiam/750;
1063         Line2[2].y = Line2[3].y = Line2[0].y + 327*SmallDiam/750;
1064         Line2[6].y = Line2[7].y = Line2[2].y - edge;
1065         Line1N = 10;
1066         Line2N = 10;
1067         break;
1068
1069     default:
1070         WARN("Invalid caption; flags=0x%04x\n", uFlags);
1071         return FALSE;
1072     }
1073
1074     /* Here the drawing takes place */
1075     if(uFlags & DFCS_INACTIVE)
1076     {
1077         /* If we have an inactive button, then you see a shadow */
1078         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1079         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1080         Polygon(dc, Line1, Line1N);
1081         if(Line2N > 0)
1082             Polygon(dc, Line2, Line2N);
1083         SelectObject(dc, hpsave);
1084         SelectObject(dc, hbsave);
1085     }
1086
1087     /* Correct for the shadow shift */
1088     if (!(uFlags & DFCS_PUSHED))
1089     {
1090         for(i = 0; i < Line1N; i++)
1091         {
1092             Line1[i].x--;
1093             Line1[i].y--;
1094         }
1095         for(i = 0; i < Line2N; i++)
1096         {
1097             Line2[i].x--;
1098             Line2[i].y--;
1099         }
1100     }
1101
1102     /* Make the final picture */
1103     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(colorIdx));
1104     hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
1105
1106     Polygon(dc, Line1, Line1N);
1107     if(Line2N > 0)
1108         Polygon(dc, Line2, Line2N);
1109     SelectObject(dc, hpsave);
1110     SelectObject(dc, hbsave);
1111
1112     return TRUE;
1113 }
1114
1115
1116 /************************************************************************
1117  *      UITOOLS_DrawFrameScroll
1118  *
1119  * Draw a scroll-bar control coming from DrawFrameControl()
1120  */
1121 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
1122 {
1123     POINT Line[4];
1124     RECT myr;
1125     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
1126     int i;
1127     HBRUSH hbsave, hb, hb2;
1128     HPEN hpsave, hp, hp2;
1129     int tri = 290*SmallDiam/1000 - 1;
1130     int d46, d93;
1131
1132     /*
1133      * This fixes a problem with really tiny "scroll" buttons. In particular
1134      * with the updown control. 
1135      * Making sure that the arrow is as least 3 pixels wide (or high).
1136      */
1137     if (tri == 0)
1138       tri = 1;
1139
1140     switch(uFlags & 0xff)
1141     {
1142     case DFCS_SCROLLCOMBOBOX:
1143     case DFCS_SCROLLDOWN:
1144         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1145         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1146         Line[0].x = Line[2].x - tri;
1147         Line[1].x = Line[2].x + tri;
1148         Line[0].y = Line[1].y = Line[2].y - tri;
1149         break;
1150
1151     case DFCS_SCROLLUP:
1152         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1153         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1154         Line[0].x = Line[2].x - tri;
1155         Line[1].x = Line[2].x + tri;
1156         Line[0].y = Line[1].y = Line[2].y + tri;
1157         break;
1158
1159     case DFCS_SCROLLLEFT:
1160         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1161         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1162         Line[0].y = Line[2].y - tri;
1163         Line[1].y = Line[2].y + tri;
1164         Line[0].x = Line[1].x = Line[2].x + tri;
1165         break;
1166
1167     case DFCS_SCROLLRIGHT:
1168         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1169         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1170         Line[0].y = Line[2].y - tri;
1171         Line[1].y = Line[2].y + tri;
1172         Line[0].x = Line[1].x = Line[2].x - tri;
1173         break;
1174
1175     case DFCS_SCROLLSIZEGRIP:
1176         /* This one breaks the flow... */
1177         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1178         hpsave = (HPEN)SelectObject(dc, GetStockObject(NULL_PEN));
1179         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(NULL_BRUSH));
1180         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1181         {
1182             hp = hp2 = GetSysColorPen(COLOR_WINDOWFRAME);
1183             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1184         }
1185         else
1186         {
1187             hp  = GetSysColorPen(COLOR_BTNHIGHLIGHT);
1188             hp2 = GetSysColorPen(COLOR_BTNSHADOW);
1189             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1190             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1191         }
1192         Line[0].x = Line[1].x = r->right-1;
1193         Line[2].y = Line[3].y = r->bottom-1;
1194         d46 = 46*SmallDiam/750;
1195         d93 = 93*SmallDiam/750;
1196
1197         i = 586*SmallDiam/750;
1198         Line[0].y = r->bottom - i - 1;
1199         Line[3].x = r->right - i - 1;
1200         Line[1].y = Line[0].y + d46;
1201         Line[2].x = Line[3].x + d46;
1202         SelectObject(dc, hb);
1203         SelectObject(dc, hp);
1204         Polygon(dc, Line, 4);
1205
1206         Line[1].y++; Line[2].x++;
1207         Line[0].y = Line[1].y + d93;
1208         Line[3].x = Line[2].x + d93;
1209         SelectObject(dc, hb2);
1210         SelectObject(dc, hp2);
1211         Polygon(dc, Line, 4);
1212
1213         i = 398*SmallDiam/750;
1214         Line[0].y = r->bottom - i - 1;
1215         Line[3].x = r->right - i - 1;
1216         Line[1].y = Line[0].y + d46;
1217         Line[2].x = Line[3].x + d46;
1218         SelectObject(dc, hb);
1219         SelectObject(dc, hp);
1220         Polygon(dc, Line, 4);
1221
1222         Line[1].y++; Line[2].x++;
1223         Line[0].y = Line[1].y + d93;
1224         Line[3].x = Line[2].x + d93;
1225         SelectObject(dc, hb2);
1226         SelectObject(dc, hp2);
1227         Polygon(dc, Line, 4);
1228
1229         i = 210*SmallDiam/750;
1230         Line[0].y = r->bottom - i - 1;
1231         Line[3].x = r->right - i - 1;
1232         Line[1].y = Line[0].y + d46;
1233         Line[2].x = Line[3].x + d46;
1234         SelectObject(dc, hb);
1235         SelectObject(dc, hp);
1236         Polygon(dc, Line, 4);
1237
1238         Line[1].y++; Line[2].x++;
1239         Line[0].y = Line[1].y + d93;
1240         Line[3].x = Line[2].x + d93;
1241         SelectObject(dc, hb2);
1242         SelectObject(dc, hp2);
1243         Polygon(dc, Line, 4);
1244
1245         SelectObject(dc, hpsave);
1246         SelectObject(dc, hbsave);
1247         return TRUE;
1248
1249     default:
1250         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1251         return FALSE;
1252     }
1253
1254     /* Here do the real scroll-bar controls end up */
1255     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1256       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1257       /* want for the normal scroll-arrow button. */
1258       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1259     else
1260       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1261
1262     if(uFlags & DFCS_INACTIVE)
1263     {
1264         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1265         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1266         Polygon(dc, Line, 3);
1267         SelectObject(dc, hpsave);
1268         SelectObject(dc, hbsave);
1269     }
1270
1271     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1272       for(i = 0; i < 3; i++)
1273       {
1274         Line[i].x--;
1275         Line[i].y--;
1276       }
1277
1278     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1279     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1280     hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
1281     Polygon(dc, Line, 3);
1282     SelectObject(dc, hpsave);
1283     SelectObject(dc, hbsave);
1284
1285     return TRUE;
1286 }
1287
1288 /************************************************************************
1289  *      UITOOLS_DrawFrameMenu
1290  *
1291  * Draw a menu control coming from DrawFrameControl()
1292  */
1293 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1294 {
1295     POINT Points[6];
1296     RECT myr;
1297     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1298     int i;
1299     HBRUSH hbsave;
1300     HPEN hpsave;
1301     int xe, ye;
1302     int xc, yc;
1303     BOOL retval = TRUE;
1304
1305     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1306     /* use anything else. I think I tried all sys-colors to change things */
1307     /* without luck. It seems as if this behavior is inherited from the */
1308     /* win31 DFC() implementation... (you remember, B/W menus). */
1309
1310     FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
1311
1312     hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
1313     hpsave = (HPEN)SelectObject(dc, GetStockObject(BLACK_PEN));
1314
1315     switch(uFlags & 0xff)
1316     {
1317     case DFCS_MENUARROW:
1318         i = 187*SmallDiam/750;
1319         Points[2].x = myr.left + 468*SmallDiam/750;
1320         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1321         Points[0].y = Points[2].y - i;
1322         Points[1].y = Points[2].y + i;
1323         Points[0].x = Points[1].x = Points[2].x - i;
1324         Polygon(dc, Points, 3);
1325         break;
1326
1327     case DFCS_MENUBULLET:
1328         xe = myr.left;
1329         ye = myr.top  + SmallDiam - SmallDiam/2;
1330         xc = myr.left + SmallDiam - SmallDiam/2;
1331         yc = myr.top  + SmallDiam - SmallDiam/2;
1332         i = 234*SmallDiam/750;
1333         i = i < 1 ? 1 : i;
1334         myr.left   = xc - i+i/2;
1335         myr.right  = xc + i/2;
1336         myr.top    = yc - i+i/2;
1337         myr.bottom = yc + i/2;
1338         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1339         break;
1340
1341     case DFCS_MENUCHECK:
1342         Points[0].x = myr.left + 253*SmallDiam/1000;
1343         Points[0].y = myr.top  + 445*SmallDiam/1000;
1344         Points[1].x = myr.left + 409*SmallDiam/1000;
1345         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1346         Points[2].x = myr.left + 690*SmallDiam/1000;
1347         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1348         Points[3].x = Points[2].x;
1349         Points[3].y = Points[2].y + 3*SmallDiam/16;
1350         Points[4].x = Points[1].x;
1351         Points[4].y = Points[1].y + 3*SmallDiam/16;
1352         Points[5].x = Points[0].x;
1353         Points[5].y = Points[0].y + 3*SmallDiam/16;
1354         Polygon(dc, Points, 6);
1355         break;
1356
1357     default:
1358         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1359         retval = FALSE;
1360         break;
1361     }
1362
1363     SelectObject(dc, hpsave);
1364     SelectObject(dc, hbsave);
1365     return retval;
1366 }
1367
1368
1369 /**********************************************************************
1370  *          DrawFrameControl  (USER.656)
1371  */
1372 BOOL16 WINAPI DrawFrameControl16( HDC16 hdc, LPRECT16 rc, UINT16 uType,
1373                                   UINT16 uState )
1374 {
1375     RECT rect32;
1376     BOOL ret;
1377
1378     CONV_RECT16TO32( rc, &rect32 );
1379     ret = DrawFrameControl( hdc, &rect32, uType, uState );
1380     CONV_RECT32TO16( &rect32, rc );
1381     return ret;
1382 }
1383
1384
1385 /**********************************************************************
1386  *          DrawFrameControl  (USER32.@)
1387  */
1388 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1389                                   UINT uState )
1390 {
1391     /* Win95 doesn't support drawing in other mapping modes */
1392     if(GetMapMode(hdc) != MM_TEXT)
1393         return FALSE;
1394         
1395     switch(uType)
1396     {
1397     case DFC_BUTTON:
1398       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1399     case DFC_CAPTION:
1400       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1401     case DFC_MENU:
1402       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1403     case DFC_SCROLL:
1404       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1405     default:
1406       WARN("(%x,%p,%d,%x), bad type!\n",
1407            hdc,rc,uType,uState );
1408     }
1409     return FALSE;
1410 }
1411