CreateIcon must perform color depth conversion if the provided bitmap
[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_WINDOWFRAME, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
86     COLOR_WINDOWFRAME, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
87     COLOR_WINDOWFRAME, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
88 };
89
90 static const signed char LTRBInnerFlat[] = {
91     -1, -1,              -1,              -1,
92     -1, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
93     -1, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
94     -1, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
95 };
96
97 /***********************************************************************
98  *           UITOOLS_DrawDiagEdge
99  *
100  * Same as DrawEdge invoked with BF_DIAGONAL
101  *
102  * 03-Dec-1997: Changed by Bertho Stultiens
103  *
104  * See also comments with UITOOLS_DrawRectEdge()
105  */
106 static BOOL UITOOLS95_DrawDiagEdge(HDC hdc, LPRECT rc, 
107                                      UINT uType, UINT uFlags)
108 {
109     POINT Points[4];
110     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  *          DrawEdge16   (USER.659)
566  */
567 BOOL16 WINAPI DrawEdge16( HDC16 hdc, LPRECT16 rc, UINT16 edge, UINT16 flags )
568 {
569     RECT rect32;
570     BOOL ret;
571
572     CONV_RECT16TO32( rc, &rect32 );
573     ret = DrawEdge( hdc, &rect32, edge, flags );
574     CONV_RECT32TO16( &rect32, rc );
575     return ret;
576 }
577
578 /**********************************************************************
579  *          DrawEdge   (USER32.@)
580  */
581 BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
582 {
583     TRACE("%04x %d,%d-%d,%d %04x %04x\n",
584           hdc, rc->left, rc->top, rc->right, rc->bottom, edge, flags );
585
586     if(flags & BF_DIAGONAL)
587       return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
588     else
589       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
590 }
591
592
593 /************************************************************************
594  *      UITOOLS_MakeSquareRect
595  *
596  * Utility to create a square rectangle and returning the width
597  */
598 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
599 {
600     int Width  = src->right - src->left;
601     int Height = src->bottom - src->top;
602     int SmallDiam = Width > Height ? Height : Width;
603
604     *dst = *src;
605
606     /* Make it a square box */
607     if(Width < Height)      /* SmallDiam == Width */
608     {
609         dst->top += (Height-Width)/2;
610         dst->bottom = dst->top + SmallDiam;
611     }
612     else if(Width > Height) /* SmallDiam == Height */
613     {
614         dst->left += (Width-Height)/2;
615         dst->right = dst->left + SmallDiam;
616     }
617
618    return SmallDiam;
619 }
620
621 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
622 {
623     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
624     {
625       HBITMAP hbm = CreateBitmap(8, 8, 1, 1, wPattern_AA55);
626       HBRUSH hbsave;
627       HBRUSH hb = CreatePatternBrush(hbm);
628       COLORREF bg;
629
630       FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
631       bg = SetBkColor(dc, RGB(255, 255, 255));
632       hbsave = (HBRUSH)SelectObject(dc, hb);
633       PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
634       SelectObject(dc, hbsave);
635       SetBkColor(dc, bg);
636       DeleteObject(hb);
637       DeleteObject(hbm);
638     }
639     else
640     {
641         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
642     }
643 }
644
645 /************************************************************************
646  *      UITOOLS_DFC_ButtonPush
647  *
648  * Draw a push button coming from DrawFrameControl()
649  *
650  * Does a pretty good job in emulating MS behavior. Some quirks are
651  * however there because MS uses a TrueType font (Marlett) to draw
652  * the buttons.
653  */
654 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
655 {
656     UINT edge;
657     RECT myr = *r;
658
659     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
660         edge = EDGE_SUNKEN;
661     else
662         edge = EDGE_RAISED;
663
664     if(uFlags & DFCS_CHECKED)
665     {
666         if(uFlags & DFCS_MONO)
667             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
668         else
669             UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
670
671         UITOOLS_DrawCheckedRect( dc, &myr );
672         }
673         else
674         {
675         if(uFlags & DFCS_MONO)
676         {
677             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
678             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
679         }
680         else
681         {
682             UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags&DFCS_FLAT) | BF_MIDDLE |BF_SOFT| BF_RECT);
683         }
684     }
685
686     /* Adjust rectangle if asked */
687     if(uFlags & DFCS_ADJUSTRECT)
688     {
689         r->left   += 2;
690         r->right  -= 2;
691         r->top    += 2;
692         r->bottom -= 2;
693     }
694
695     return TRUE;
696 }
697
698
699 /************************************************************************
700  *      UITOOLS_DFC_ButtonChcek
701  *
702  * Draw a check/3state button coming from DrawFrameControl()
703  *
704  * Does a pretty good job in emulating MS behavior. Some quirks are
705  * however there because MS uses a TrueType font (Marlett) to draw
706  * the buttons.
707  */
708
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 xc = (myr.left+myr.right)/2;
918     int yc = (myr.top+myr.bottom)/2;
919     int edge, move;
920     char str[2] = "?";
921     UINT alignsave;
922     int bksave;
923     COLORREF clrsave;
924     SIZE size;
925
926     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
927
928     switch(uFlags & 0xff)
929     {
930     case DFCS_CAPTIONCLOSE:
931         edge = 328*SmallDiam/1000;
932         move = 95*SmallDiam/1000;
933         Line1[0].x = Line2[0].x = Line1[1].x = Line2[1].x = xc - edge;
934         Line1[2].y = Line2[5].y = Line1[1].y = Line2[4].y = yc - edge;
935         Line1[3].x = Line2[3].x = Line1[4].x = Line2[4].x = xc + edge;
936         Line1[5].y = Line2[2].y = Line1[4].y = Line2[1].y = yc + edge;
937         Line1[2].x = Line2[2].x = Line1[1].x + move;
938         Line1[0].y = Line2[3].y = Line1[1].y + move;
939         Line1[5].x = Line2[5].x = Line1[4].x - move;
940         Line1[3].y = Line2[0].y = Line1[4].y - move;
941         Line1N = 6;
942         Line2N = 6;
943         break;
944
945     case DFCS_CAPTIONHELP:
946         /* This one breaks the flow */
947         /* FIXME: We need the Marlett font in order to get this right. */
948
949         hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
950                         ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
951                         DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
952         alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
953         bksave = SetBkMode(dc, TRANSPARENT);
954         clrsave = GetTextColor(dc);
955         hfsave = (HFONT)SelectObject(dc, hf);
956         GetTextExtentPoint32A(dc, str, 1, &size);
957
958         if(uFlags & DFCS_INACTIVE)
959         {
960             SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
961             TextOutA(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
962         }
963         SetTextColor(dc, GetSysColor(uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
964         TextOutA(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
965
966         SelectObject(dc, hfsave);
967         SetTextColor(dc, clrsave);
968         SetBkMode(dc, bksave);
969         SetTextAlign(dc, alignsave);
970         DeleteObject(hf);
971         return TRUE;
972
973     case DFCS_CAPTIONMIN:
974         Line1[0].x = Line1[3].x = myr.left   +  96*SmallDiam/750+2;
975         Line1[1].x = Line1[2].x = Line1[0].x + 372*SmallDiam/750;
976         Line1[0].y = Line1[1].y = myr.top    + 563*SmallDiam/750+1;
977         Line1[2].y = Line1[3].y = Line1[0].y +  92*SmallDiam/750;
978         Line1N = 4;
979         Line2N = 0;
980         break;
981
982     case DFCS_CAPTIONMAX:
983         edge = 47*SmallDiam/750;
984         Line1[0].x = Line1[5].x = myr.left +  57*SmallDiam/750+3;
985         Line1[0].y = Line1[1].y = myr.top  + 143*SmallDiam/750+1;
986         Line1[1].x = Line1[2].x = Line1[0].x + 562*SmallDiam/750;
987         Line1[5].y = Line1[4].y = Line1[0].y +  93*SmallDiam/750;
988         Line1[2].y = Line1[3].y = Line1[0].y + 513*SmallDiam/750;
989         Line1[3].x = Line1[4].x = Line1[1].x -  edge;
990
991         Line2[0].x = Line2[5].x = Line1[0].x;
992         Line2[3].x = Line2[4].x = Line1[1].x;
993         Line2[1].x = Line2[2].x = Line1[0].x + edge;
994         Line2[0].y = Line2[1].y = Line1[0].y;
995         Line2[4].y = Line2[5].y = Line1[2].y;
996         Line2[2].y = Line2[3].y = Line1[2].y - edge;
997         Line1N = 6;
998         Line2N = 6;
999         break;
1000
1001     case DFCS_CAPTIONRESTORE:
1002         /* FIXME: this one looks bad at small sizes < 15x15 :( */
1003         edge = 47*SmallDiam/750;
1004         move = 420*SmallDiam/750;
1005         Line1[0].x = Line1[9].x = myr.left + 198*SmallDiam/750+2;
1006         Line1[0].y = Line1[1].y = myr.top  + 169*SmallDiam/750+1;
1007         Line1[6].y = Line1[7].y = Line1[0].y + 93*SmallDiam/750;
1008         Line1[7].x = Line1[8].x = Line1[0].x + edge;
1009         Line1[1].x = Line1[2].x = Line1[0].x + move;
1010         Line1[5].x = Line1[6].x = Line1[1].x - edge;
1011         Line1[9].y = Line1[8].y = Line1[0].y + 187*SmallDiam/750;
1012         Line1[2].y = Line1[3].y = Line1[0].y + 327*SmallDiam/750;
1013         Line1[4].y = Line1[5].y = Line1[2].y - edge;
1014         Line1[3].x = Line1[4].x = Line1[2].x - 140*SmallDiam/750;
1015
1016         Line2[1].x = Line2[2].x = Line1[3].x;
1017         Line2[7].x = Line2[8].x = Line2[1].x - edge;
1018         Line2[0].x = Line2[9].x = Line2[3].x = Line2[4].x = Line2[1].x - move;
1019         Line2[5].x = Line2[6].x = Line2[0].x + edge;
1020         Line2[0].y = Line2[1].y = Line1[9].y;
1021         Line2[4].y = Line2[5].y = Line2[8].y = Line2[9].y = Line2[0].y + 93*SmallDiam/750;
1022         Line2[2].y = Line2[3].y = Line2[0].y + 327*SmallDiam/750;
1023         Line2[6].y = Line2[7].y = Line2[2].y - edge;
1024         Line1N = 10;
1025         Line2N = 10;
1026         break;
1027
1028     default:
1029         WARN("Invalid caption; flags=0x%04x\n", uFlags);
1030         return FALSE;
1031     }
1032
1033     /* Here the drawing takes place */
1034     if(uFlags & DFCS_INACTIVE)
1035     {
1036         /* If we have an inactive button, then you see a shadow */
1037         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1038         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1039         Polygon(dc, Line1, Line1N);
1040         if(Line2N > 0)
1041             Polygon(dc, Line2, Line2N);
1042         SelectObject(dc, hpsave);
1043         SelectObject(dc, hbsave);
1044     }
1045
1046     /* Correct for the shadow shift */
1047     if (!(uFlags & DFCS_PUSHED))
1048     {
1049         for(i = 0; i < Line1N; i++)
1050         {
1051             Line1[i].x--;
1052             Line1[i].y--;
1053         }
1054         for(i = 0; i < Line2N; i++)
1055         {
1056             Line2[i].x--;
1057             Line2[i].y--;
1058         }
1059     }
1060
1061     /* Make the final picture */
1062     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1063     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1064     hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
1065
1066     Polygon(dc, Line1, Line1N);
1067     if(Line2N > 0)
1068         Polygon(dc, Line2, Line2N);
1069     SelectObject(dc, hpsave);
1070     SelectObject(dc, hbsave);
1071
1072     return TRUE;
1073 }
1074
1075
1076 /************************************************************************
1077  *      UITOOLS_DrawFrameScroll
1078  *
1079  * Draw a scroll-bar control coming from DrawFrameControl()
1080  */
1081 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
1082 {
1083     POINT Line[4];
1084     RECT myr;
1085     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
1086     int i;
1087     HBRUSH hbsave, hb, hb2;
1088     HPEN hpsave, hp, hp2;
1089     int tri = 290*SmallDiam/1000 - 1;
1090     int d46, d93;
1091
1092     /*
1093      * This fixes a problem with really tiny "scroll" buttons. In particular
1094      * with the updown control. 
1095      * Making sure that the arrow is as least 3 pixels wide (or high).
1096      */
1097     if (tri == 0)
1098       tri = 1;
1099
1100     switch(uFlags & 0xff)
1101     {
1102     case DFCS_SCROLLCOMBOBOX:
1103     case DFCS_SCROLLDOWN:
1104         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1105         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1106         Line[0].x = Line[2].x - tri;
1107         Line[1].x = Line[2].x + tri;
1108         Line[0].y = Line[1].y = Line[2].y - tri;
1109         break;
1110
1111     case DFCS_SCROLLUP:
1112         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1113         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1114         Line[0].x = Line[2].x - tri;
1115         Line[1].x = Line[2].x + tri;
1116         Line[0].y = Line[1].y = Line[2].y + tri;
1117         break;
1118
1119     case DFCS_SCROLLLEFT:
1120         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1121         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1122         Line[0].y = Line[2].y - tri;
1123         Line[1].y = Line[2].y + tri;
1124         Line[0].x = Line[1].x = Line[2].x + tri;
1125         break;
1126
1127     case DFCS_SCROLLRIGHT:
1128         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1129         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1130         Line[0].y = Line[2].y - tri;
1131         Line[1].y = Line[2].y + tri;
1132         Line[0].x = Line[1].x = Line[2].x - tri;
1133         break;
1134
1135     case DFCS_SCROLLSIZEGRIP:
1136         /* This one breaks the flow... */
1137         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1138         hpsave = (HPEN)SelectObject(dc, GetStockObject(NULL_PEN));
1139         hbsave = (HBRUSH)SelectObject(dc, GetStockObject(NULL_BRUSH));
1140         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1141         {
1142             hp = hp2 = GetSysColorPen(COLOR_WINDOWFRAME);
1143             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1144         }
1145         else
1146         {
1147             hp  = GetSysColorPen(COLOR_BTNHIGHLIGHT);
1148             hp2 = GetSysColorPen(COLOR_BTNSHADOW);
1149             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1150             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1151         }
1152         Line[0].x = Line[1].x = r->right-1;
1153         Line[2].y = Line[3].y = r->bottom-1;
1154         d46 = 46*SmallDiam/750;
1155         d93 = 93*SmallDiam/750;
1156
1157         i = 586*SmallDiam/750;
1158         Line[0].y = r->bottom - i - 1;
1159         Line[3].x = r->right - i - 1;
1160         Line[1].y = Line[0].y + d46;
1161         Line[2].x = Line[3].x + d46;
1162         SelectObject(dc, hb);
1163         SelectObject(dc, hp);
1164         Polygon(dc, Line, 4);
1165
1166         Line[1].y++; Line[2].x++;
1167         Line[0].y = Line[1].y + d93;
1168         Line[3].x = Line[2].x + d93;
1169         SelectObject(dc, hb2);
1170         SelectObject(dc, hp2);
1171         Polygon(dc, Line, 4);
1172
1173         i = 398*SmallDiam/750;
1174         Line[0].y = r->bottom - i - 1;
1175         Line[3].x = r->right - i - 1;
1176         Line[1].y = Line[0].y + d46;
1177         Line[2].x = Line[3].x + d46;
1178         SelectObject(dc, hb);
1179         SelectObject(dc, hp);
1180         Polygon(dc, Line, 4);
1181
1182         Line[1].y++; Line[2].x++;
1183         Line[0].y = Line[1].y + d93;
1184         Line[3].x = Line[2].x + d93;
1185         SelectObject(dc, hb2);
1186         SelectObject(dc, hp2);
1187         Polygon(dc, Line, 4);
1188
1189         i = 210*SmallDiam/750;
1190         Line[0].y = r->bottom - i - 1;
1191         Line[3].x = r->right - i - 1;
1192         Line[1].y = Line[0].y + d46;
1193         Line[2].x = Line[3].x + d46;
1194         SelectObject(dc, hb);
1195         SelectObject(dc, hp);
1196         Polygon(dc, Line, 4);
1197
1198         Line[1].y++; Line[2].x++;
1199         Line[0].y = Line[1].y + d93;
1200         Line[3].x = Line[2].x + d93;
1201         SelectObject(dc, hb2);
1202         SelectObject(dc, hp2);
1203         Polygon(dc, Line, 4);
1204
1205         SelectObject(dc, hpsave);
1206         SelectObject(dc, hbsave);
1207         return TRUE;
1208
1209     default:
1210         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1211         return FALSE;
1212     }
1213
1214     /* Here do the real scroll-bar controls end up */
1215     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1216       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1217       /* want for the normal scroll-arrow button. */
1218       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1219     else
1220       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1221
1222     if(uFlags & DFCS_INACTIVE)
1223     {
1224         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1225         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1226         Polygon(dc, Line, 3);
1227         SelectObject(dc, hpsave);
1228         SelectObject(dc, hbsave);
1229     }
1230
1231     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1232       for(i = 0; i < 3; i++)
1233       {
1234         Line[i].x--;
1235         Line[i].y--;
1236       }
1237
1238     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1239     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1240     hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
1241     Polygon(dc, Line, 3);
1242     SelectObject(dc, hpsave);
1243     SelectObject(dc, hbsave);
1244
1245     return TRUE;
1246 }
1247
1248 /************************************************************************
1249  *      UITOOLS_DrawFrameMenu
1250  *
1251  * Draw a menu control coming from DrawFrameControl()
1252  */
1253 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1254 {
1255     POINT Points[6];
1256     RECT myr;
1257     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1258     int i;
1259     HBRUSH hbsave;
1260     HPEN hpsave;
1261     int xe, ye;
1262     int xc, yc;
1263     BOOL retval = TRUE;
1264
1265     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1266     /* use anything else. I think I tried all sys-colors to change things */
1267     /* without luck. It seems as if this behavior is inherited from the */
1268     /* win31 DFC() implementation... (you remember, B/W menus). */
1269
1270     FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
1271
1272     hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
1273     hpsave = (HPEN)SelectObject(dc, GetStockObject(BLACK_PEN));
1274
1275     switch(uFlags & 0xff)
1276     {
1277     case DFCS_MENUARROW:
1278         i = 187*SmallDiam/750;
1279         Points[2].x = myr.left + 468*SmallDiam/750;
1280         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1281         Points[0].y = Points[2].y - i;
1282         Points[1].y = Points[2].y + i;
1283         Points[0].x = Points[1].x = Points[2].x - i;
1284         Polygon(dc, Points, 3);
1285         break;
1286
1287     case DFCS_MENUBULLET:
1288         xe = myr.left;
1289         ye = myr.top  + SmallDiam - SmallDiam/2;
1290         xc = myr.left + SmallDiam - SmallDiam/2;
1291         yc = myr.top  + SmallDiam - SmallDiam/2;
1292         i = 234*SmallDiam/750;
1293         i = i < 1 ? 1 : i;
1294         myr.left   = xc - i+i/2;
1295         myr.right  = xc + i/2;
1296         myr.top    = yc - i+i/2;
1297         myr.bottom = yc + i/2;
1298         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1299         break;
1300
1301     case DFCS_MENUCHECK:
1302         Points[0].x = myr.left + 253*SmallDiam/1000;
1303         Points[0].y = myr.top  + 445*SmallDiam/1000;
1304         Points[1].x = myr.left + 409*SmallDiam/1000;
1305         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1306         Points[2].x = myr.left + 690*SmallDiam/1000;
1307         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1308         Points[3].x = Points[2].x;
1309         Points[3].y = Points[2].y + 3*SmallDiam/16;
1310         Points[4].x = Points[1].x;
1311         Points[4].y = Points[1].y + 3*SmallDiam/16;
1312         Points[5].x = Points[0].x;
1313         Points[5].y = Points[0].y + 3*SmallDiam/16;
1314         Polygon(dc, Points, 6);
1315         break;
1316
1317     default:
1318         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1319         retval = FALSE;
1320         break;
1321     }
1322
1323     SelectObject(dc, hpsave);
1324     SelectObject(dc, hbsave);
1325     return retval;
1326 }
1327
1328
1329 /**********************************************************************
1330  *          DrawFrameControl16  (USER.656)
1331  */
1332 BOOL16 WINAPI DrawFrameControl16( HDC16 hdc, LPRECT16 rc, UINT16 uType,
1333                                   UINT16 uState )
1334 {
1335     RECT rect32;
1336     BOOL ret;
1337
1338     CONV_RECT16TO32( rc, &rect32 );
1339     ret = DrawFrameControl( hdc, &rect32, uType, uState );
1340     CONV_RECT32TO16( &rect32, rc );
1341     return ret;
1342 }
1343
1344
1345 /**********************************************************************
1346  *          DrawFrameControl  (USER32.@)
1347  */
1348 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1349                                   UINT uState )
1350 {
1351     /* Win95 doesn't support drawing in other mapping modes */
1352     if(GetMapMode(hdc) != MM_TEXT)
1353         return FALSE;
1354         
1355     switch(uType)
1356     {
1357     case DFC_BUTTON:
1358       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1359     case DFC_CAPTION:
1360       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1361     case DFC_MENU:
1362       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1363     case DFC_SCROLL:
1364       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1365     default:
1366       WARN("(%x,%p,%d,%x), bad type!\n",
1367            hdc,rc,uType,uState );
1368     }
1369     return FALSE;
1370 }
1371