xref: /reactos/win32ss/user/user32/windows/draw.c (revision 019f21ee)
1 /*
2  * ReactOS User32 Library
3  * - Various drawing functions
4  *
5  * Copyright 2001 Casper S. Hournstroup
6  * Copyright 2003 Andrew Greenwood
7  * Copyright 2003 Filip Navara
8  * Copyright 2009 Matthias Kupfer
9  * Copyright 2017 Katayama Hirofumi MZ
10  *
11  * Based on Wine code.
12  *
13  * Copyright 1993, 1994 Alexandre Julliard
14  * Copyright 2002 Bill Medland
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  */
30 
31 #include <user32.h>
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(user32);
34 
35 /* GLOBALS *******************************************************************/
36 
37 /* These tables are used in:
38  * UITOOLS_DrawDiagEdge()
39  * UITOOLS_DrawRectEdge()
40  */
41 static const signed char LTInnerNormal[] = {
42             -1,           -1,                 -1,                 -1,
43             -1,           COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
44             -1,           COLOR_3DDKSHADOW,   COLOR_3DDKSHADOW,   -1,
45             -1,           -1,                 -1,                 -1
46 };
47 
48 static const signed char LTOuterNormal[] = {
49             -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
50             COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
51             COLOR_3DDKSHADOW,   COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
52             -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1
53 };
54 
55 static const signed char RBInnerNormal[] = {
56             -1,           -1,                -1,              -1,
57             -1,           COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
58             -1,           COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
59             -1,           -1,                -1,              -1
60 };
61 
62 static const signed char RBOuterNormal[] = {
63             -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
64             COLOR_BTNSHADOW, COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
65             COLOR_3DLIGHT,   COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
66             -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1
67 };
68 
69 static const signed char LTInnerSoft[] = {
70             -1,                  -1,                -1,              -1,
71             -1,                  COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
72             -1,                  COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
73             -1,                  -1,                -1,              -1
74 };
75 
76 static const signed char LTOuterSoft[] = {
77             -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
78             COLOR_3DLIGHT,   COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
79             COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
80             -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
81 };
82 
83 #define RBInnerSoft RBInnerNormal   /* These are the same */
84 #define RBOuterSoft RBOuterNormal
85 
86 static const signed char LTRBOuterMono[] = {
87             -1,           COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
88             COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
89             COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
90             COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
91 };
92 
93 static const signed char LTRBInnerMono[] = {
94             -1, -1,           -1,           -1,
95             -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
96             -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
97             -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
98 };
99 
100 static const signed char LTRBOuterFlat[] = {
101             -1,                COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
102             COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
103             COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
104             COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
105 };
106 
107 static const signed char LTRBInnerFlat[] = {
108             -1, -1,              -1,              -1,
109             -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
110             -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
111             -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
112 };
113 /* FUNCTIONS *****************************************************************/
114 
115 
116 HBRUSH WINAPI GetSysColorBrush(int nIndex);
117 
118 /* Ported from WINE20020904 */
119 /* Same as DrawEdge invoked with BF_DIAGONAL */
120 static BOOL IntDrawDiagEdge(HDC hdc, LPRECT rc, UINT uType, UINT uFlags)
121 {
122     POINT Points[4];
123     signed char InnerI, OuterI;
124     HPEN InnerPen, OuterPen;
125     POINT SavePoint;
126     HPEN SavePen;
127     int spx, spy;
128     int epx, epy;
129     int Width = rc->right - rc->left;
130     int Height= rc->bottom - rc->top;
131     int SmallDiam = Width > Height ? Height : Width;
132     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
133                         || (uType & BDR_OUTER) == BDR_OUTER)
134                        && !(uFlags & (BF_FLAT|BF_MONO)) );
135     int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
136             + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
137 
138     /* Init some vars */
139     OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
140     SavePen = (HPEN)SelectObject(hdc, InnerPen);
141     spx = spy = epx = epy = 0; /* Satisfy the compiler... */
142 
143     /* Determine the colors of the edges */
144     if(uFlags & BF_MONO)
145     {
146         InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
147         OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
148     }
149     else if(uFlags & BF_FLAT)
150     {
151         InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
152         OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
153     }
154     else if(uFlags & BF_SOFT)
155     {
156         if(uFlags & BF_BOTTOM)
157         {
158             InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
159             OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
160         }
161         else
162         {
163             InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
164             OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
165         }
166     }
167     else
168     {
169         if(uFlags & BF_BOTTOM)
170         {
171             InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
172             OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
173         }
174         else
175         {
176             InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
177             OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
178         }
179     }
180 
181     if(InnerI != -1) InnerPen = GetStockObject(DC_PEN);
182     if(OuterI != -1) OuterPen = GetStockObject(DC_PEN);
183 
184     MoveToEx(hdc, 0, 0, &SavePoint);
185 
186     /* Don't ask me why, but this is what is visible... */
187     /* This must be possible to do much simpler, but I fail to */
188     /* see the logic in the MS implementation (sigh...). */
189     /* So, this might look a bit brute force here (and it is), but */
190     /* it gets the job done;) */
191 
192     switch(uFlags & BF_RECT)
193     {
194         case 0:
195         case BF_LEFT:
196         case BF_BOTTOM:
197         case BF_BOTTOMLEFT:
198             /* Left bottom endpoint */
199             epx = rc->left-1;
200             spx = epx + SmallDiam;
201             epy = rc->bottom;
202             spy = epy - SmallDiam;
203             break;
204 
205         case BF_TOPLEFT:
206         case BF_BOTTOMRIGHT:
207             /* Left top endpoint */
208             epx = rc->left-1;
209             spx = epx + SmallDiam;
210             epy = rc->top-1;
211             spy = epy + SmallDiam;
212             break;
213 
214         case BF_TOP:
215         case BF_RIGHT:
216         case BF_TOPRIGHT:
217         case BF_RIGHT|BF_LEFT:
218         case BF_RIGHT|BF_LEFT|BF_TOP:
219         case BF_BOTTOM|BF_TOP:
220         case BF_BOTTOM|BF_TOP|BF_LEFT:
221         case BF_BOTTOMRIGHT|BF_LEFT:
222         case BF_BOTTOMRIGHT|BF_TOP:
223         case BF_RECT:
224             /* Right top endpoint */
225             spx = rc->left;
226             epx = spx + SmallDiam;
227             spy = rc->bottom-1;
228             epy = spy - SmallDiam;
229             break;
230     }
231 
232     MoveToEx(hdc, spx, spy, NULL);
233     SelectObject(hdc, OuterPen);
234     SetDCPenColor(hdc, GetSysColor(OuterI));
235     LineTo(hdc, epx, epy);
236 
237     SelectObject(hdc, InnerPen);
238     SetDCPenColor(hdc, GetSysColor(InnerI));
239 
240     switch(uFlags & (BF_RECT|BF_DIAGONAL))
241     {
242         case BF_DIAGONAL_ENDBOTTOMLEFT:
243         case (BF_DIAGONAL|BF_BOTTOM):
244         case BF_DIAGONAL:
245         case (BF_DIAGONAL|BF_LEFT):
246             MoveToEx(hdc, spx-1, spy, NULL);
247             LineTo(hdc, epx, epy-1);
248             Points[0].x = spx-add;
249             Points[0].y = spy;
250             Points[1].x = rc->left;
251             Points[1].y = rc->top;
252             Points[2].x = epx+1;
253             Points[2].y = epy-1-add;
254             Points[3] = Points[2];
255             break;
256 
257         case BF_DIAGONAL_ENDBOTTOMRIGHT:
258             MoveToEx(hdc, spx-1, spy, NULL);
259             LineTo(hdc, epx, epy+1);
260             Points[0].x = spx-add;
261             Points[0].y = spy;
262             Points[1].x = rc->left;
263             Points[1].y = rc->bottom-1;
264             Points[2].x = epx+1;
265             Points[2].y = epy+1+add;
266             Points[3] = Points[2];
267             break;
268 
269         case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
270         case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
271         case BF_DIAGONAL_ENDTOPRIGHT:
272         case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
273             MoveToEx(hdc, spx+1, spy, NULL);
274             LineTo(hdc, epx, epy+1);
275             Points[0].x = epx-1;
276             Points[0].y = epy+1+add;
277             Points[1].x = rc->right-1;
278             Points[1].y = rc->top+add;
279             Points[2].x = rc->right-1;
280             Points[2].y = rc->bottom-1;
281             Points[3].x = spx+add;
282             Points[3].y = spy;
283             break;
284 
285         case BF_DIAGONAL_ENDTOPLEFT:
286             MoveToEx(hdc, spx, spy-1, NULL);
287             LineTo(hdc, epx+1, epy);
288             Points[0].x = epx+1+add;
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;
295             Points[3].y = spy-add;
296             break;
297 
298         case (BF_DIAGONAL|BF_TOP):
299         case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
300         case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
301             MoveToEx(hdc, spx+1, spy-1, NULL);
302             LineTo(hdc, epx, epy);
303             Points[0].x = epx-1;
304             Points[0].y = epy+1;
305             Points[1].x = rc->right-1;
306             Points[1].y = rc->top;
307             Points[2].x = rc->right-1;
308             Points[2].y = rc->bottom-1-add;
309             Points[3].x = spx+add;
310             Points[3].y = spy-add;
311             break;
312 
313         case (BF_DIAGONAL|BF_RIGHT):
314         case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
315         case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
316             MoveToEx(hdc, spx, spy, NULL);
317             LineTo(hdc, epx-1, epy+1);
318             Points[0].x = spx;
319             Points[0].y = spy;
320             Points[1].x = rc->left;
321             Points[1].y = rc->top+add;
322             Points[2].x = epx-1-add;
323             Points[2].y = epy+1+add;
324             Points[3] = Points[2];
325             break;
326     }
327 
328     /* Fill the interior if asked */
329     if((uFlags & BF_MIDDLE) && retval)
330     {
331         HBRUSH hbsave;
332         HPEN hpsave;
333         hbsave = (HBRUSH)SelectObject(hdc, GetStockObject(DC_BRUSH));
334         hpsave = (HPEN)SelectObject(hdc, GetStockObject(DC_PEN));
335         SetDCBrushColor(hdc, GetSysColor(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE));
336         SetDCPenColor(hdc, GetSysColor(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE));
337         Polygon(hdc, Points, 4);
338         SelectObject(hdc, hbsave);
339         SelectObject(hdc, hpsave);
340     }
341 
342     /* Adjust rectangle if asked */
343     if(uFlags & BF_ADJUST)
344     {
345         if(uFlags & BF_LEFT)   rc->left   += add;
346         if(uFlags & BF_RIGHT)  rc->right  -= add;
347         if(uFlags & BF_TOP)    rc->top    += add;
348         if(uFlags & BF_BOTTOM) rc->bottom -= add;
349     }
350 
351     /* Cleanup */
352     SelectObject(hdc, SavePen);
353     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
354 
355     return retval;
356 }
357 
358 /* Ported from WINE20020904 */
359 /* Same as DrawEdge invoked without BF_DIAGONAL
360  *
361  * 23-Nov-1997: Changed by Bertho Stultiens
362  * The width parameter sets the width of each outer and inner edge.
363  *
364  * Well, I started testing this and found out that there are a few things
365  * that weren't quite as win95. The following rewrite should reproduce
366  * win95 results completely.
367  * The colorselection is table-driven to avoid awfull if-statements.
368  * The table below show the color settings.
369  *
370  * Pen selection table for uFlags = 0
371  *
372  * uType |  LTI  |  LTO  |  RBI  |  RBO
373  * ------+-------+-------+-------+-------
374  *  0000 |   x   |   x   |   x   |   x
375  *  0001 |   x   |  22   |   x   |  21
376  *  0010 |   x   |  16   |   x   |  20
377  *  0011 |   x   |   x   |   x   |   x
378  * ------+-------+-------+-------+-------
379  *  0100 |   x   |  20   |   x   |  16
380  *  0101 |  20   |  22   |  16   |  21
381  *  0110 |  20   |  16   |  16   |  20
382  *  0111 |   x   |   x   |   x   |   x
383  * ------+-------+-------+-------+-------
384  *  1000 |   x   |  21   |   x   |  22
385  *  1001 |  21   |  22   |  22   |  21
386  *  1010 |  21   |  16   |  22   |  20
387  *  1011 |   x   |   x   |   x   |   x
388  * ------+-------+-------+-------+-------
389  *  1100 |   x   |   x   |   x   |   x
390  *  1101 |   x   | x (22)|   x   | x (21)
391  *  1110 |   x   | x (16)|   x   | x (20)
392  *  1111 |   x   |   x   |   x   |   x
393  *
394  * Pen selection table for uFlags = BF_SOFT
395  *
396  * uType |  LTI  |  LTO  |  RBI  |  RBO
397  * ------+-------+-------+-------+-------
398  *  0000 |   x   |   x   |   x   |   x
399  *  0001 |   x   |  20   |   x   |  21
400  *  0010 |   x   |  21   |   x   |  20
401  *  0011 |   x   |   x   |   x   |   x
402  * ------+-------+-------+-------+-------
403  *  0100 |   x   |  22   |   x   |  16
404  *  0101 |  22   |  20   |  16   |  21
405  *  0110 |  22   |  21   |  16   |  20
406  *  0111 |   x   |   x   |   x   |   x
407  * ------+-------+-------+-------+-------
408  *  1000 |   x   |  16   |   x   |  22
409  *  1001 |  16   |  20   |  22   |  21
410  *  1010 |  16   |  21   |  22   |  20
411  *  1011 |   x   |   x   |   x   |   x
412  * ------+-------+-------+-------+-------
413  *  1100 |   x   |   x   |   x   |   x
414  *  1101 |   x   | x (20)|   x   | x (21)
415  *  1110 |   x   | x (21)|   x   | x (20)
416  *  1111 |   x   |   x   |   x   |   x
417  *
418  * x = don't care; (n) = is what win95 actually uses
419  * LTI = left Top Inner line
420  * LTO = left Top Outer line
421  * RBI = Right Bottom Inner line
422  * RBO = Right Bottom Outer line
423  * 15 = COLOR_BTNFACE
424  * 16 = COLOR_BTNSHADOW
425  * 20 = COLOR_BTNHIGHLIGHT
426  * 21 = COLOR_3DDKSHADOW
427  * 22 = COLOR_3DLIGHT
428  */
429 static BOOL IntDrawRectEdge(HDC hdc, LPRECT rc, UINT uType, UINT uFlags, UINT width)
430 {
431     signed char LTInnerI, LTOuterI;
432     signed char RBInnerI, RBOuterI;
433     HBRUSH lti_brush, lto_brush, rbi_brush, rbo_brush;
434     RECT InnerRect = *rc, fill_rect;
435     int lbi_offset = 0, lti_offset = 0, rti_offset = 0, rbi_offset = 0;
436     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
437                        || (uType & BDR_OUTER) == BDR_OUTER)
438                       && !(uFlags & (BF_FLAT|BF_MONO)) );
439 
440     lti_brush = lto_brush = rbi_brush = rbo_brush = GetStockObject(NULL_BRUSH);
441 
442     /* Determine the colors of the edges */
443     if(uFlags & BF_MONO)
444     {
445         LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
446         LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
447     }
448     else if(uFlags & BF_FLAT)
449     {
450         LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
451         LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
452 
453         /* Bertho Stultiens states above that this function exactly matches win95
454          * In win98 BF_FLAT rectangles have an inner border same color as the
455         * middle (COLOR_BTNFACE). I believe it's the same for win95 but since
456         * I don't know I go with Bertho and just sets it for win98 until proven
457         * otherwise.
458         *                                          Dennis Björklund, 10 June, 99
459         */
460 	if( LTInnerI != -1 ) 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)   lbi_offset = width;
478     if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT)       rti_offset = width;
479     if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) rbi_offset = width;
480     if((uFlags & BF_TOPLEFT) == BF_TOPLEFT)         lti_offset = width;
481 
482     if(LTInnerI != -1) lti_brush = GetSysColorBrush(LTInnerI);
483     if(LTOuterI != -1) lto_brush = GetSysColorBrush(LTOuterI);
484     if(RBInnerI != -1) rbi_brush = GetSysColorBrush(RBInnerI);
485     if(RBOuterI != -1) rbo_brush = GetSysColorBrush(RBOuterI);
486 
487     /* Draw the outer edge */
488     if(uFlags & BF_TOP)
489     {
490         fill_rect = InnerRect;
491         fill_rect.bottom = fill_rect.top + width;
492         FillRect( hdc, &fill_rect, lto_brush );
493     }
494     if(uFlags & BF_LEFT)
495     {
496         fill_rect = InnerRect;
497         fill_rect.right = fill_rect.left + width;
498         FillRect( hdc, &fill_rect, lto_brush );
499     }
500     if(uFlags & BF_BOTTOM)
501     {
502         fill_rect = InnerRect;
503         fill_rect.top = fill_rect.bottom - width;
504         FillRect( hdc, &fill_rect, rbo_brush );
505     }
506     if(uFlags & BF_RIGHT)
507     {
508         fill_rect = InnerRect;
509         fill_rect.left = fill_rect.right - width;
510         FillRect( hdc, &fill_rect, rbo_brush );
511     }
512 
513     /* Draw the inner edge */
514     if(uFlags & BF_TOP)
515     {
516         SetRect( &fill_rect, InnerRect.left + lti_offset, InnerRect.top + width,
517                  InnerRect.right - rti_offset, InnerRect.top + 2 * width );
518         FillRect( hdc, &fill_rect, lti_brush );
519     }
520     if(uFlags & BF_LEFT)
521     {
522         SetRect( &fill_rect, InnerRect.left + width, InnerRect.top + lti_offset,
523                  InnerRect.left + 2 * width, InnerRect.bottom - lbi_offset );
524         FillRect( hdc, &fill_rect, lti_brush );
525     }
526     if(uFlags & BF_BOTTOM)
527     {
528         SetRect( &fill_rect, InnerRect.left + lbi_offset, InnerRect.bottom - 2 * width,
529                  InnerRect.right - rbi_offset, InnerRect.bottom - width );
530         FillRect( hdc, &fill_rect, rbi_brush );
531     }
532     if(uFlags & BF_RIGHT)
533     {
534         SetRect( &fill_rect, InnerRect.right - 2 * width, InnerRect.top + rti_offset,
535                  InnerRect.right - width, InnerRect.bottom - rbi_offset );
536         FillRect( hdc, &fill_rect, rbi_brush );
537     }
538 
539     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
540     {
541         int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0)
542                 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0);
543 
544         if(uFlags & BF_LEFT)   InnerRect.left   += add;
545         if(uFlags & BF_RIGHT)  InnerRect.right  -= add;
546         if(uFlags & BF_TOP)    InnerRect.top    += add;
547         if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
548 
549         if((uFlags & BF_MIDDLE) && retval)
550 	{
551             FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
552 						       COLOR_WINDOW : COLOR_BTNFACE));
553 	}
554 
555 	if(uFlags & BF_ADJUST)
556 	    *rc = InnerRect;
557     }
558 
559     return retval;
560 }
561 
562 /* Ported from WINE20020904 */
563 /* Utility to create a square rectangle and returning the width */
564 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
565 {
566     int Width  = src->right - src->left;
567     int Height = src->bottom - src->top;
568     int SmallDiam = Width > Height ? Height : Width;
569 
570     *dst = *src;
571 
572     /* Make it a square box */
573     if(Width < Height)      /* SmallDiam == Width */
574     {
575         dst->top += (Height-Width)/2;
576         dst->bottom = dst->top + SmallDiam;
577     }
578     else if(Width > Height) /* SmallDiam == Height */
579     {
580         dst->left += (Width-Height)/2;
581         dst->right = dst->left + SmallDiam;
582     }
583 
584     return SmallDiam;
585 }
586 
587 /* Ported from WINE20020904 */
588 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
589 {
590     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
591     {
592         HBRUSH hbsave;
593         COLORREF bg;
594 
595         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
596         bg = SetBkColor(dc, RGB(255, 255, 255));
597         hbsave = (HBRUSH)SelectObject(dc, gpsi->hbrGray);
598         PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
599         SelectObject(dc, hbsave);
600         SetBkColor(dc, bg);
601     }
602     else
603     {
604         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
605     }
606 }
607 
608 /* Ported from WINE20020904 */
609 /* Draw a push button coming from DrawFrameControl()
610  *
611  * Does a pretty good job in emulating MS behavior. Some quirks are
612  * however there because MS uses a TrueType font (Marlett) to draw
613  * the buttons.
614  *
615  * FIXME: This looks a little bit strange, needs to be rewritten completely
616  * (several quirks with adjust, DFCS_CHECKED aso)
617  */
618 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
619 {
620     UINT edge;
621     RECT myr = *r;
622 
623     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
624         edge = EDGE_SUNKEN;
625     else
626         edge = EDGE_RAISED;
627 
628     if(uFlags & DFCS_CHECKED)
629     {
630         if(uFlags & DFCS_MONO)
631             IntDrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST, 1);
632         else
633             IntDrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST, 1);
634 
635         UITOOLS_DrawCheckedRect( dc, &myr );
636     }
637     else
638     {
639         if(uFlags & DFCS_MONO)
640         {
641             IntDrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST, 1);
642             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
643         }
644         else
645         {
646             IntDrawRectEdge(dc, r, edge, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT | BF_SOFT, 1);
647         }
648     }
649 
650     /* Adjust rectangle if asked */
651     if(uFlags & DFCS_ADJUSTRECT)
652         InflateRect(r, -2, -2);
653 
654     return TRUE;
655 }
656 
657 static BOOL UITOOLS95_DFC_ButtonCheckRadio(HDC dc, LPRECT r, UINT uFlags, BOOL Radio)
658 {
659     LOGFONTW lf;
660     HFONT hFont, hOldFont;
661     int i;
662     TCHAR OutRight, OutLeft, InRight, InLeft, Center;
663     INT X, Y, Width, Height, Shorter;
664     INT BkMode = GetBkMode(dc);
665     COLORREF TextColor = GetTextColor(dc);
666 
667     Width = r->right - r->left;
668     Height = r->bottom - r->top;
669     Shorter = (Width < Height) ? Width : Height;
670     X = r->left + (Width - Shorter) / 2;
671     Y = r->top + (Height - Shorter) / 2;
672 
673     if (Radio)
674     {
675         OutRight = 'j'; // Outer right
676         OutLeft  = 'k'; // Outer left
677         InRight  = 'l'; // inner left
678         InLeft   = 'm'; // inner right
679         Center   = 'n'; // center
680     }
681     else
682     {
683         OutRight = 'c'; // Outer right
684         OutLeft  = 'd'; // Outer left
685         InRight  = 'e'; // inner left
686         InLeft   = 'f'; // inner right
687         Center   = 'g'; // center
688     }
689 
690     ZeroMemory(&lf, sizeof(LOGFONTW));
691     lf.lfHeight = Shorter;
692     lf.lfCharSet = DEFAULT_CHARSET;
693     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
694     if (Radio && ((uFlags & 0xFF) == DFCS_BUTTONRADIOMASK))
695     {
696         lf.lfQuality = NONANTIALIASED_QUALITY;
697     }
698     hFont = CreateFontIndirect(&lf);
699     hOldFont = SelectObject(dc, hFont);
700 
701     if (Radio && ((uFlags & 0xFF) == DFCS_BUTTONRADIOMASK))
702     {
703 #if 1
704         // FIXME: improve font rendering
705         RECT Rect;
706         HGDIOBJ hbrOld, hpenOld;
707         FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
708         SetRect(&Rect, X, Y, X + Shorter, Y + Shorter);
709         InflateRect(&Rect, -(Shorter * 8) / 54, -(Shorter * 8) / 54);
710         hbrOld = SelectObject(dc, GetStockObject(BLACK_BRUSH));
711         hpenOld = SelectObject(dc, GetStockObject(NULL_PEN));
712         Ellipse(dc, Rect.left, Rect.top, Rect.right, Rect.bottom);
713         SelectObject(dc, hbrOld);
714         SelectObject(dc, hpenOld);
715 #else
716         SetBkMode(dc, OPAQUE);
717         SetBkColor(dc, RGB(255, 255, 255));
718         SetTextColor(dc, RGB(0, 0, 0));
719         TextOut(dc, X, Y, &Center, 1);
720         SetBkMode(dc, TRANSPARENT);
721         TextOut(dc, X, Y, &OutRight, 1);
722         TextOut(dc, X, Y, &OutLeft, 1);
723         TextOut(dc, X, Y, &InRight, 1);
724         TextOut(dc, X, Y, &InLeft, 1);
725 #endif
726     }
727     else
728     {
729         SetBkMode(dc, TRANSPARENT);
730 
731         /* Center section, white for active, grey for inactive */
732         if ((uFlags & (DFCS_INACTIVE | DFCS_PUSHED)))
733             i = COLOR_BTNFACE;
734         else
735             i = COLOR_WINDOW;
736         SetTextColor(dc, GetSysColor(i));
737         TextOut(dc, X, Y, &Center, 1);
738 
739         if (uFlags & (DFCS_FLAT | DFCS_MONO))
740         {
741             SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
742             TextOut(dc, X, Y, &OutRight, 1);
743             TextOut(dc, X, Y, &OutLeft, 1);
744             TextOut(dc, X, Y, &InRight, 1);
745             TextOut(dc, X, Y, &InLeft, 1);
746         }
747         else
748         {
749             SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
750             TextOut(dc, X, Y, &OutRight, 1);
751             SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
752             TextOut(dc, X, Y, &OutLeft, 1);
753             SetTextColor(dc, GetSysColor(COLOR_3DDKSHADOW));
754             TextOut(dc, X, Y, &InRight, 1);
755             SetTextColor(dc, GetSysColor(COLOR_3DLIGHT));
756             TextOut(dc, X, Y, &InLeft, 1);
757         }
758 
759         if (uFlags & DFCS_CHECKED)
760         {
761             TCHAR Check = (Radio) ? 'i' : 'b';
762 
763             SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
764             TextOut(dc, X, Y, &Check, 1);
765         }
766     }
767 
768     SelectObject(dc, hOldFont);
769     DeleteObject(hFont);
770 
771     SetTextColor(dc, TextColor);
772     SetBkMode(dc, BkMode);
773 
774     return TRUE;
775 }
776 
777 /* Ported from WINE20020904 */
778 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
779 {
780     switch(uState & 0x1f)
781     {
782         case DFCS_BUTTONPUSH:
783             return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
784 
785         case DFCS_BUTTONCHECK:
786         case DFCS_BUTTON3STATE:
787             return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, FALSE);
788 
789         case DFCS_BUTTONRADIOIMAGE:
790         case DFCS_BUTTONRADIOMASK:
791         case DFCS_BUTTONRADIO:
792             return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, TRUE);
793 
794 
795         default:
796             ERR("Invalid button state=0x%04x\n", uState);
797 
798     }
799 
800     return FALSE;
801 }
802 
803 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
804 {
805     LOGFONTW lf;
806     HFONT hFont, hOldFont;
807     COLORREF clrsave;
808     RECT myr;
809     INT bkmode;
810     TCHAR Symbol;
811     switch(uFlags & 0xf)
812     {
813         case DFCS_CAPTIONCLOSE:
814 		Symbol = 'r';
815 		break;
816         case DFCS_CAPTIONHELP:
817 		Symbol = 's';
818 		break;
819         case DFCS_CAPTIONMIN:
820 		Symbol = '0';
821 		break;
822         case DFCS_CAPTIONMAX:
823 		Symbol = '1';
824 		break;
825         case DFCS_CAPTIONRESTORE:
826 		Symbol = '2';
827 		break;
828         default:
829              ERR("Invalid caption; flags=0x%04x\n", uFlags);
830              return FALSE;
831     }
832     IntDrawRectEdge(dc,r,(uFlags&DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, BF_RECT | BF_MIDDLE | BF_SOFT, 1);
833     ZeroMemory(&lf, sizeof(LOGFONTW));
834     UITOOLS_MakeSquareRect(r, &myr);
835     myr.left += 1;
836     myr.top += 1;
837     myr.right -= 1;
838     myr.bottom -= 1;
839     if(uFlags & DFCS_PUSHED)
840        OffsetRect(&myr,1,1);
841     lf.lfHeight = myr.bottom - myr.top;
842     lf.lfWidth = 0;
843     lf.lfWeight = FW_NORMAL;
844     lf.lfCharSet = DEFAULT_CHARSET;
845     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
846     hFont = CreateFontIndirect(&lf);
847     /* save font and text color */
848     hOldFont = SelectObject(dc, hFont);
849     clrsave = GetTextColor(dc);
850     bkmode = GetBkMode(dc);
851     /* set color and drawing mode */
852     SetBkMode(dc, TRANSPARENT);
853     if(uFlags & DFCS_INACTIVE)
854     {
855         /* draw shadow */
856         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
857         TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
858     }
859     SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
860     /* draw selected symbol */
861     TextOut(dc, myr.left, myr.top, &Symbol, 1);
862     /* restore previous settings */
863     SetTextColor(dc, clrsave);
864     SelectObject(dc, hOldFont);
865     SetBkMode(dc, bkmode);
866     DeleteObject(hFont);
867     return TRUE;
868 }
869 
870 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
871 {
872     LOGFONTW lf;
873     HFONT hFont, hOldFont;
874     COLORREF clrsave;
875     RECT myr;
876     INT bkmode;
877     TCHAR Symbol;
878     switch(uFlags & 0x1f)
879     {
880         case DFCS_SCROLLCOMBOBOX:
881         case DFCS_SCROLLDOWN:
882 		Symbol = '6';
883 		break;
884 
885 	case DFCS_SCROLLUP:
886 		Symbol = '5';
887 		break;
888 
889 	case DFCS_SCROLLLEFT:
890 		Symbol = '3';
891 		break;
892 
893 	case DFCS_SCROLLRIGHT:
894 		Symbol = '4';
895 		break;
896 
897 	case DFCS_SCROLLSIZEGRIP:
898 	case DFCS_SCROLLSIZEGRIPRIGHT:
899 		ZeroMemory(&lf, sizeof(LOGFONTW));
900 		UITOOLS_MakeSquareRect(r, &myr);
901 		lf.lfHeight = myr.bottom - myr.top;
902 		lf.lfWidth = 0;
903 		lf.lfWeight = FW_NORMAL;
904 		lf.lfCharSet = DEFAULT_CHARSET;
905 		lstrcpy(lf.lfFaceName, TEXT("Marlett"));
906 		hFont = CreateFontIndirect(&lf);
907 		/* save font and text color */
908 		hOldFont = SelectObject(dc, hFont);
909 		clrsave = GetTextColor(dc);
910 		bkmode = GetBkMode(dc);
911 		/* set color and drawing mode */
912 		SetBkMode(dc, TRANSPARENT);
913 		if (!(uFlags & (DFCS_MONO | DFCS_FLAT)))
914 		{
915 			SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
916 			/* draw selected symbol */
917 			Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'o' : 'x';
918 			TextOut(dc, myr.left, myr.top, &Symbol, 1);
919 			SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
920 		} else
921 			SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
922 		/* draw selected symbol */
923 		Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'p' : 'y';
924 		TextOut(dc, myr.left, myr.top, &Symbol, 1);
925 		/* restore previous settings */
926 		SetTextColor(dc, clrsave);
927 		SelectObject(dc, hOldFont);
928 		SetBkMode(dc, bkmode);
929 		DeleteObject(hFont);
930             return TRUE;
931 	default:
932 	    ERR("Invalid scroll; flags=0x%04x\n", uFlags);
933             return FALSE;
934     }
935     IntDrawRectEdge(dc, r, (uFlags & DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT, 1);
936     ZeroMemory(&lf, sizeof(LOGFONTW));
937     UITOOLS_MakeSquareRect(r, &myr);
938     myr.left += 1;
939     myr.top += 1;
940     myr.right -= 1;
941     myr.bottom -= 1;
942     if(uFlags & DFCS_PUSHED)
943        OffsetRect(&myr,1,1);
944     lf.lfHeight = myr.bottom - myr.top;
945     lf.lfWidth = 0;
946     lf.lfWeight = FW_NORMAL;
947     lf.lfCharSet = DEFAULT_CHARSET;
948     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
949     hFont = CreateFontIndirect(&lf);
950     /* save font and text color */
951     hOldFont = SelectObject(dc, hFont);
952     clrsave = GetTextColor(dc);
953     bkmode = GetBkMode(dc);
954     /* set color and drawing mode */
955     SetBkMode(dc, TRANSPARENT);
956     if(uFlags & DFCS_INACTIVE)
957     {
958         /* draw shadow */
959         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
960         TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
961     }
962     SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
963     /* draw selected symbol */
964     TextOut(dc, myr.left, myr.top, &Symbol, 1);
965     /* restore previous settings */
966     SetTextColor(dc, clrsave);
967     SelectObject(dc, hOldFont);
968     SetBkMode(dc, bkmode);
969     DeleteObject(hFont);
970     return TRUE;
971 }
972 
973 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
974 {
975     // TODO: DFCS_TRANSPARENT upon DFCS_MENUARROWUP or DFCS_MENUARROWDOWN
976     LOGFONTW lf;
977     HFONT hFont, hOldFont;
978     TCHAR Symbol;
979     RECT myr;
980     INT cxy;
981     cxy = UITOOLS_MakeSquareRect(r, &myr);
982     switch(uFlags & 0x1f)
983     {
984         case DFCS_MENUARROWUP:
985             Symbol = '5';
986             break;
987 
988         case DFCS_MENUARROWDOWN:
989             Symbol = '6';
990             break;
991 
992         case DFCS_MENUARROW:
993             Symbol = '8';
994             break;
995 
996         case DFCS_MENUARROWRIGHT:
997 	    Symbol = 'w'; // FIXME: needs to confirm
998 	    break;
999 
1000         case DFCS_MENUBULLET:
1001             Symbol = 'h';
1002             break;
1003 
1004         case DFCS_MENUCHECK:
1005             Symbol = 'a';
1006             break;
1007 
1008         default:
1009             ERR("Invalid menu; flags=0x%04x\n", uFlags);
1010             return FALSE;
1011     }
1012     /* acquire ressources only if valid menu */
1013     ZeroMemory(&lf, sizeof(LOGFONTW));
1014     lf.lfHeight = cxy;
1015     lf.lfWidth = 0;
1016     lf.lfWeight = FW_NORMAL;
1017     lf.lfCharSet = DEFAULT_CHARSET;
1018     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
1019     hFont = CreateFontIndirect(&lf);
1020     /* save font */
1021     hOldFont = SelectObject(dc, hFont);
1022 
1023     if ((uFlags & 0x1f) == DFCS_MENUARROWUP ||
1024         (uFlags & 0x1f) == DFCS_MENUARROWDOWN )
1025     {
1026 #if 0
1027        if (uFlags & DFCS_INACTIVE)
1028        {
1029            /* draw shadow */
1030            SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1031            TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
1032        }
1033 #endif
1034        SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
1035     }
1036     /* draw selected symbol */
1037     TextOut(dc, myr.left, myr.top, &Symbol, 1);
1038     /* restore previous settings */
1039     SelectObject(dc, hOldFont);
1040     DeleteObject(hFont);
1041     return TRUE;
1042 }
1043 
1044 BOOL
1045 WINAPI
1046 IntGrayString(
1047     HDC hDC,
1048     HBRUSH hBrush,
1049     GRAYSTRINGPROC lpOutputFunc,
1050     LPARAM lpData,
1051     int nCount,
1052     int X,
1053     int Y,
1054     int nWidth,
1055     int nHeight,
1056     BOOL unicode)
1057 {
1058     // AG: Mostly implemented, but probably won't work properly or return
1059     // correct error codes. I doubt it grays strings either... Untested!
1060 
1061     BOOL    success = FALSE;
1062     HBRUSH  hbsave;
1063     HDC     MemDC = NULL;
1064     HBITMAP MemBMP = NULL, OldBMP = NULL;
1065     HBRUSH  OldBrush = NULL;
1066     HFONT   OldFont = NULL;
1067     RECT    r;
1068     COLORREF ForeColor, BackColor;
1069 
1070     ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
1071     BackColor = SetBkColor(hDC, RGB(255, 255, 255));
1072 
1073     if (! hBrush)
1074     {
1075         // The documentation is a little vague on what exactly should happen
1076         // here. Something about using the same brush for window text???
1077         hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
1078     }
1079 
1080     if ((nCount == -1) && (! lpOutputFunc))
1081         return FALSE;
1082 
1083     if (! nCount)
1084     {
1085         // TODO: calculate the length (easy enough)
1086 
1087         if (unicode)
1088             nCount = lstrlenW((WCHAR*)lpData);
1089         else
1090             nCount = lstrlenA((CHAR*)lpData);
1091     }
1092 
1093     if (! nWidth || ! nHeight)
1094     {
1095         SIZE s;
1096         // TODO: calculate the rect
1097 
1098         if (unicode)
1099             success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
1100         else
1101             success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
1102 
1103         if (! success) goto cleanup;
1104 
1105         if (! nWidth)   nWidth = s.cx;
1106         if (! nHeight)  nHeight = s.cy;
1107     }
1108 
1109     SetRect(&r, X, Y, X + nWidth, Y + nHeight);
1110 
1111     MemDC = CreateCompatibleDC(hDC);
1112     if (! MemDC) goto cleanup;
1113     MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1114     if (! MemBMP) goto cleanup;
1115     OldBMP = SelectObject(MemDC, MemBMP);
1116     if (! OldBMP) goto cleanup;
1117     OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
1118     if (! OldFont) goto cleanup;
1119     OldBrush = SelectObject(MemDC, hBrush);
1120     if (! OldBrush) goto cleanup;
1121 
1122     if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
1123 
1124     SetTextColor(MemDC, RGB(255, 255, 255));
1125     SetBkColor(MemDC, RGB(0, 0, 0));
1126 
1127     if (lpOutputFunc)
1128     {
1129         success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
1130 
1131         if ((nCount == -1) && (! success))
1132         {
1133             // Don't gray (documented behaviour)
1134             success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
1135             goto cleanup;
1136         }
1137     }
1138     else
1139     {
1140         if (unicode)
1141             success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
1142         else
1143             success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
1144 
1145         if (! success) goto cleanup;
1146 
1147         hbsave = (HBRUSH)SelectObject(MemDC, gpsi->hbrGray);
1148         PatBlt(MemDC, 0, 0, nWidth, nHeight, 0x000A0329);
1149         SelectObject(MemDC, hbsave);
1150     }
1151 
1152     if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
1153 
1154 cleanup:
1155     SetTextColor(hDC, ForeColor);
1156     SetBkColor(hDC, BackColor);
1157 
1158     if (MemDC)
1159     {
1160         if (OldFont) SelectObject(MemDC, OldFont);
1161         if (OldBrush) SelectObject(MemDC, OldBrush);
1162         if (OldBMP) SelectObject(MemDC, OldBMP);
1163         if (MemBMP) DeleteObject(MemBMP);
1164         DeleteDC(MemDC);
1165     }
1166 
1167     return success;
1168 }
1169 
1170 /**********************************************************************
1171  *          PAINTING_DrawStateJam
1172  *
1173  * Jams in the requested type in the dc
1174  */
1175 static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
1176                                   DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1177                                   LPRECT rc, UINT dtflags, BOOL unicode )
1178 {
1179     HDC memdc;
1180     HBITMAP hbmsave;
1181     BOOL retval;
1182     INT cx = rc->right - rc->left;
1183     INT cy = rc->bottom - rc->top;
1184 
1185     switch(opcode)
1186     {
1187         case DST_TEXT:
1188         case DST_PREFIXTEXT:
1189             if(unicode)
1190                 return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1191             else
1192                 return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1193 
1194         case DST_ICON:
1195             return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, cx, cy, 0, NULL, DI_NORMAL);
1196 
1197         case DST_BITMAP:
1198             memdc = CreateCompatibleDC(hdc);
1199             if(!memdc)
1200                 return FALSE;
1201             hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
1202             if(!hbmsave)
1203             {
1204                 DeleteDC(memdc);
1205                 return FALSE;
1206             }
1207             retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1208             SelectObject(memdc, hbmsave);
1209             DeleteDC(memdc);
1210             return retval;
1211 
1212         case DST_COMPLEX:
1213             if(func)
1214             {
1215                 BOOL bRet;
1216                 /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */
1217 
1218                 OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1219                 bRet = func(hdc, lp, wp, cx, cy);
1220                 /* Restore origin */
1221                 OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1222                 return bRet;
1223             }
1224             else
1225             {
1226                 return FALSE;
1227             }
1228     }
1229     return FALSE;
1230 }
1231 
1232 static BOOL
1233 IntDrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1234              INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode)
1235 {
1236     HBITMAP hbm, hbmsave;
1237     HFONT hfsave;
1238     HBRUSH hbsave, hbrtmp = 0;
1239     HDC memdc;
1240     RECT rc;
1241     UINT dtflags = DT_NOCLIP;
1242     COLORREF fg, bg;
1243     UINT opcode = flags & 0xf;
1244     INT len = wp;
1245     BOOL retval, tmp;
1246     LOGFONTW lf;
1247     HFONT hFontOriginal, hNaaFont = NULL;
1248 
1249     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1250     {
1251         if(unicode)
1252             len = lstrlenW((LPWSTR)lp);
1253         else
1254             len = lstrlenA((LPSTR)lp);
1255     }
1256 
1257     hFontOriginal = GetCurrentObject(hdc, OBJ_FONT);
1258     if (flags & (DSS_MONO | DSS_DISABLED))
1259     {
1260         /* Create a non-antialiased font */
1261         GetObjectW(hFontOriginal, sizeof(lf), &lf);
1262         lf.lfQuality = NONANTIALIASED_QUALITY;
1263         hNaaFont = CreateFontIndirectW(&lf);
1264     }
1265 
1266     /* Find out what size the image has if not given by caller */
1267     if(!cx || !cy)
1268     {
1269         SIZE s;
1270         BITMAP bm;
1271 
1272         switch(opcode)
1273         {
1274             case DST_TEXT:
1275             case DST_PREFIXTEXT:
1276                 if(unicode)
1277                     retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1278                 else
1279                     retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1280                 if(!retval)
1281                     return FALSE;
1282                 break;
1283 
1284             case DST_ICON:
1285                 if(!get_icon_size((HICON)lp, &s))
1286                     return FALSE;
1287                 break;
1288 
1289             case DST_BITMAP:
1290                 if(!GetObjectW((HBITMAP)lp, sizeof(bm), &bm))
1291                     return FALSE;
1292                 s.cx = bm.bmWidth;
1293                 s.cy = bm.bmHeight;
1294                 break;
1295 
1296             case DST_COMPLEX: /* cx and cy must be set in this mode */
1297                 return FALSE;
1298 
1299             default:
1300                 ERR("Invalid opcode: %u\n", opcode);
1301                 return FALSE;
1302         }
1303 
1304         if(!cx) cx = s.cx;
1305         if(!cy) cy = s.cy;
1306     }
1307 
1308     SetRect(&rc, x, y, x + cx, y + cy);
1309 
1310     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1311         dtflags |= DT_RIGHT;
1312     if(opcode == DST_TEXT)
1313         dtflags |= DT_NOPREFIX;
1314     else if(opcode == DST_PREFIXTEXT)
1315     {
1316         if (flags & DSS_HIDEPREFIX)
1317             dtflags |= DT_HIDEPREFIX;
1318         if (flags & DSS_PREFIXONLY)
1319             dtflags |= DT_PREFIXONLY;
1320     }
1321 
1322     /* For DSS_NORMAL we just jam in the image and return */
1323     if((flags & 0x79f0) == DSS_NORMAL)
1324     {
1325         return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1326     }
1327 
1328     /* For all other states we need to convert the image to B/W in a local bitmap */
1329     /* before it is displayed */
1330     fg = SetTextColor(hdc, RGB(0, 0, 0));
1331     bg = SetBkColor(hdc, RGB(255, 255, 255));
1332     hbm = NULL; hbmsave = NULL;
1333     memdc = NULL; hbsave = NULL;
1334     retval = FALSE; /* assume failure */
1335 
1336     /* From here on we must use "goto cleanup" when something goes wrong */
1337     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1338     if(!hbm) goto cleanup;
1339     memdc   = CreateCompatibleDC(hdc);
1340     if(!memdc) goto cleanup;
1341     hbmsave = (HBITMAP)SelectObject(memdc, hbm);
1342     if(!hbmsave) goto cleanup;
1343     SetRect(&rc, 0, 0, cx, cy);
1344     if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
1345     SetBkColor(memdc, RGB(255, 255, 255));
1346     SetTextColor(memdc, RGB(0, 0, 0));
1347     if (hNaaFont)
1348         hfsave  = (HFONT)SelectObject(memdc, hNaaFont);
1349     else
1350         hfsave  = (HFONT)SelectObject(memdc, hFontOriginal);
1351     SetLayout( memdc, GetLayout( hdc ));
1352 
1353     /* DST_COMPLEX may draw text as well,
1354      * so we must be sure that correct font is selected
1355      */
1356     if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1357     tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1358     if(hfsave) SelectObject(memdc, hfsave);
1359     if (hNaaFont) DeleteObject(hNaaFont);
1360     if(!tmp) goto cleanup;
1361 
1362     /* This state cause the image to be dithered */
1363     if(flags & DSS_UNION)
1364     {
1365         hbsave = (HBRUSH)SelectObject(memdc, gpsi->hbrGray);
1366         if(!hbsave) goto cleanup;
1367         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1368         SelectObject(memdc, hbsave);
1369         if(!tmp) goto cleanup;
1370     }
1371 
1372     if (flags & DSS_DISABLED)
1373         hbrtmp = GetSysColorBrush(COLOR_3DHILIGHT);
1374     else if (flags & DSS_DEFAULT)
1375         hbrtmp = GetSysColorBrush(COLOR_3DSHADOW);
1376 
1377     /* Draw light or dark shadow */
1378     if (flags & (DSS_DISABLED|DSS_DEFAULT))
1379     {
1380         if(!hbrtmp) goto cleanup;
1381         hbsave = (HBRUSH)SelectObject(hdc, hbrtmp);
1382         if(!hbsave) goto cleanup;
1383         if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1384         SelectObject(hdc, hbsave);
1385     }
1386 
1387     if (flags & DSS_DISABLED)
1388     {
1389         hbr = hbrtmp = GetSysColorBrush(COLOR_3DSHADOW);
1390         if(!hbrtmp) goto cleanup;
1391     }
1392     else if (!hbr)
1393     {
1394         hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
1395     }
1396 
1397     hbsave = (HBRUSH)SelectObject(hdc, hbr);
1398 
1399     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1400 
1401     retval = TRUE; /* We succeeded */
1402 
1403 cleanup:
1404     SetTextColor(hdc, fg);
1405     SetBkColor(hdc, bg);
1406 
1407     if(hbsave) SelectObject(hdc, hbsave);
1408     if(hbmsave) SelectObject(memdc, hbmsave);
1409     if(hbm) DeleteObject(hbm);
1410     if(memdc) DeleteDC(memdc);
1411 
1412     return retval;
1413 }
1414 
1415 /*
1416  * @implemented
1417  */
1418 BOOL WINAPI
1419 RealDrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1420 {
1421     if (GetMapMode(hDC) != MM_TEXT)
1422         return FALSE;
1423 
1424     switch(uType)
1425     {
1426         case DFC_BUTTON:
1427             return UITOOLS95_DrawFrameButton(hDC, rc, uState);
1428         case DFC_CAPTION:
1429             return UITOOLS95_DrawFrameCaption(hDC, rc, uState);
1430         case DFC_MENU:
1431             return UITOOLS95_DrawFrameMenu(hDC, rc, uState);
1432 #if 0
1433         case DFC_POPUPMENU:
1434             UNIMPLEMENTED;
1435             break;
1436 #endif
1437         case DFC_SCROLL:
1438             return UITOOLS95_DrawFrameScroll(hDC, rc, uState);
1439     }
1440     return FALSE;
1441 }
1442 
1443 BOOL WINAPI
1444 DrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1445 {
1446    BOOL Hook, Ret = FALSE;
1447 
1448    LoadUserApiHook();
1449 
1450    Hook = BeginIfHookedUserApiHook();
1451 
1452    /* Bypass SEH and go direct. */
1453    if (!Hook) return RealDrawFrameControl(hDC, rc, uType, uState);
1454 
1455    _SEH2_TRY
1456    {
1457       Ret = guah.DrawFrameControl(hDC, rc, uType, uState);
1458    }
1459    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1460    {
1461        ERR("Got exception in hooked DrawFrameControl!\n");
1462    }
1463    _SEH2_END;
1464 
1465    EndUserApiHook();
1466 
1467    return Ret;
1468 }
1469 
1470 /*
1471  * @implemented
1472  */
1473 BOOL WINAPI
1474 DrawEdge(HDC hDC, LPRECT rc, UINT edge, UINT flags)
1475 {
1476     if (flags & BF_DIAGONAL)
1477         return IntDrawDiagEdge(hDC, rc, edge, flags);
1478     else
1479         return IntDrawRectEdge(hDC, rc, edge, flags, 1);
1480 }
1481 
1482 /*
1483  * @implemented
1484  */
1485 BOOL WINAPI
1486 GrayStringA(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1487             int nCount, int X, int Y, int nWidth, int nHeight)
1488 {
1489     return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1490 }
1491 
1492 /*
1493  * @implemented
1494  */
1495 BOOL WINAPI
1496 GrayStringW(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1497             int nCount, int X, int Y, int nWidth, int nHeight)
1498 {
1499     return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1500 }
1501 
1502 /*
1503  * @implemented
1504  */
1505 BOOL WINAPI
1506 InvertRect(HDC hDC, CONST RECT *lprc)
1507 {
1508     return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1509                   lprc->bottom - lprc->top, DSTINVERT);
1510 }
1511 
1512 /*
1513  * @implemented
1514  */
1515 INT WINAPI
1516 FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1517 {
1518     HBRUSH oldbrush;
1519     RECT r = *lprc;
1520 
1521     if (IsRectEmpty(&r)) return 0;
1522     if (!(oldbrush = SelectObject(hDC, hbr))) return 0;
1523 
1524     PatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
1525     PatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
1526     PatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
1527     PatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
1528 
1529     SelectObject(hDC, oldbrush);
1530     return TRUE;
1531 }
1532 
1533 /*
1534  * @implemented
1535  */
1536 BOOL WINAPI
1537 FlashWindow(HWND hWnd, BOOL bInvert)
1538 {
1539     FLASHWINFO FlashWndInfo;
1540 
1541     FlashWndInfo.cbSize = sizeof(FLASHWINFO);
1542     FlashWndInfo.hwnd = hWnd;
1543     FlashWndInfo.dwFlags = !bInvert ? 0 : (FLASHW_TRAY | FLASHW_CAPTION);
1544     FlashWndInfo.uCount = 1;
1545     FlashWndInfo.dwTimeout = 0;
1546 
1547     return NtUserFlashWindowEx(&FlashWndInfo);
1548 }
1549 
1550 /*
1551  * @implemented
1552  */
1553 INT WINAPI
1554 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1555 {
1556     BOOL Ret;
1557     HBRUSH prevhbr = NULL;
1558 
1559     /* Select brush if specified */
1560     if (hbr)
1561     {
1562         /* Handle system colors */
1563         if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1))
1564             hbr = GetSysColorBrush(PtrToUlong(hbr) - 1);
1565 
1566         prevhbr = SelectObject(hDC, hbr);
1567         if (prevhbr == NULL)
1568             return (INT)FALSE;
1569     }
1570 
1571     Ret = PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1572                  lprc->bottom - lprc->top, PATCOPY);
1573 
1574     /* Select old brush */
1575     if (prevhbr)
1576         SelectObject(hDC, prevhbr);
1577 
1578     return (INT)Ret;
1579 }
1580 
1581 /*
1582  * @implemented
1583  */
1584 BOOL WINAPI
1585 DrawFocusRect(HDC hdc, CONST RECT *rect)
1586 {
1587     HGDIOBJ OldObj;
1588     UINT cx, cy;
1589 
1590     NtUserSystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &cx, 0);
1591     NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &cy, 0);
1592 
1593     OldObj = SelectObject(hdc, gpsi->hbrGray);
1594 
1595     /* top */
1596     PatBlt(hdc, rect->left, rect->top, rect->right - rect->left, cy, PATINVERT);
1597     /* bottom */
1598     PatBlt(hdc, rect->left, rect->bottom - cy, rect->right - rect->left, cy, PATINVERT);
1599     /* left */
1600     PatBlt(hdc, rect->left, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1601     /* right */
1602     PatBlt(hdc, rect->right - cx, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1603 
1604     SelectObject(hdc, OldObj);
1605     return TRUE;
1606 }
1607 
1608 /*
1609  * @implemented
1610  */
1611 BOOL WINAPI
1612 DrawStateA(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1613            WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1614 {
1615     return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
1616 }
1617 
1618 /*
1619  * @implemented
1620  */
1621 BOOL WINAPI
1622 DrawStateW(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1623            WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1624 {
1625     return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
1626 }
1627