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