xref: /reactos/win32ss/user/user32/windows/draw.c (revision 50cf16b3)
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 & 0xff)
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             DbgPrint("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 & 0xff)
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              WARN("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 & 0xff)
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 	    WARN("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     LOGFONTW lf;
976     HFONT hFont, hOldFont;
977     TCHAR Symbol;
978     switch(uFlags & 0xff)
979     {
980         case DFCS_MENUARROWUP:
981             Symbol = '5';
982             break;
983 
984         case DFCS_MENUARROWDOWN:
985             Symbol = '6';
986             break;
987 
988         case DFCS_MENUARROW:
989             Symbol = '8';
990             break;
991 
992         case DFCS_MENUARROWRIGHT:
993 	    Symbol = 'w'; // FIXME: needs to confirm
994 	    break;
995 
996         case DFCS_MENUBULLET:
997             Symbol = 'h';
998             break;
999 
1000         case DFCS_MENUCHECK:
1001             Symbol = 'a';
1002             break;
1003 
1004         default:
1005             WARN("Invalid menu; flags=0x%04x\n", uFlags);
1006             return FALSE;
1007     }
1008     /* acquire ressources only if valid menu */
1009     ZeroMemory(&lf, sizeof(LOGFONTW));
1010     lf.lfHeight = r->bottom - r->top;
1011     lf.lfWidth = 0;
1012     lf.lfWeight = FW_NORMAL;
1013     lf.lfCharSet = DEFAULT_CHARSET;
1014     lstrcpy(lf.lfFaceName, TEXT("Marlett"));
1015     hFont = CreateFontIndirect(&lf);
1016     /* save font */
1017     hOldFont = SelectObject(dc, hFont);
1018 
1019     if ((uFlags & 0xff) == DFCS_MENUARROWUP ||
1020         (uFlags & 0xff) == DFCS_MENUARROWDOWN )
1021     {
1022 #if 0
1023        if (uFlags & DFCS_INACTIVE)
1024        {
1025            /* draw shadow */
1026            SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1027            TextOut(dc, r->left + 1, r->top + 1, &Symbol, 1);
1028        }
1029 #endif
1030        SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
1031     }
1032     /* draw selected symbol */
1033     TextOut(dc, r->left, r->top, &Symbol, 1);
1034     /* restore previous settings */
1035     SelectObject(dc, hOldFont);
1036     DeleteObject(hFont);
1037     return TRUE;
1038 }
1039 
1040 BOOL
1041 WINAPI
1042 IntGrayString(
1043     HDC hDC,
1044     HBRUSH hBrush,
1045     GRAYSTRINGPROC lpOutputFunc,
1046     LPARAM lpData,
1047     int nCount,
1048     int X,
1049     int Y,
1050     int nWidth,
1051     int nHeight,
1052     BOOL unicode)
1053 {
1054     // AG: Mostly implemented, but probably won't work properly or return
1055     // correct error codes. I doubt it grays strings either... Untested!
1056 
1057     BOOL    success = FALSE;
1058     HBRUSH  hbsave;
1059     HDC     MemDC = NULL;
1060     HBITMAP MemBMP = NULL, OldBMP = NULL;
1061     HBRUSH  OldBrush = NULL;
1062     HFONT   OldFont = NULL;
1063     RECT    r;
1064     COLORREF ForeColor, BackColor;
1065 
1066     ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
1067     BackColor = SetBkColor(hDC, RGB(255, 255, 255));
1068 
1069     if (! hBrush)
1070     {
1071         // The documentation is a little vague on what exactly should happen
1072         // here. Something about using the same brush for window text???
1073         hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
1074     }
1075 
1076     if ((nCount == -1) && (! lpOutputFunc))
1077         return FALSE;
1078 
1079     if (! nCount)
1080     {
1081         // TODO: calculate the length (easy enough)
1082 
1083         if (unicode)
1084             nCount = lstrlenW((WCHAR*)lpData);
1085         else
1086             nCount = lstrlenA((CHAR*)lpData);
1087     }
1088 
1089     if (! nWidth || ! nHeight)
1090     {
1091         SIZE s;
1092         // TODO: calculate the rect
1093 
1094         if (unicode)
1095             success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
1096         else
1097             success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
1098 
1099         if (! success) goto cleanup;
1100 
1101         if (! nWidth)   nWidth = s.cx;
1102         if (! nHeight)  nHeight = s.cy;
1103     }
1104 
1105     SetRect(&r, X, Y, X + nWidth, Y + nHeight);
1106 
1107     MemDC = CreateCompatibleDC(hDC);
1108     if (! MemDC) goto cleanup;
1109     MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1110     if (! MemBMP) goto cleanup;
1111     OldBMP = SelectObject(MemDC, MemBMP);
1112     if (! OldBMP) goto cleanup;
1113     OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
1114     if (! OldFont) goto cleanup;
1115     OldBrush = SelectObject(MemDC, hBrush);
1116     if (! OldBrush) goto cleanup;
1117 
1118     if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
1119 
1120     SetTextColor(MemDC, RGB(255, 255, 255));
1121     SetBkColor(MemDC, RGB(0, 0, 0));
1122 
1123     if (lpOutputFunc)
1124     {
1125         success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
1126 
1127         if ((nCount == -1) && (! success))
1128         {
1129             // Don't gray (documented behaviour)
1130             success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
1131             goto cleanup;
1132         }
1133     }
1134     else
1135     {
1136         if (unicode)
1137             success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
1138         else
1139             success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
1140 
1141         if (! success) goto cleanup;
1142 
1143         hbsave = (HBRUSH)SelectObject(MemDC, gpsi->hbrGray);
1144         PatBlt(MemDC, 0, 0, nWidth, nHeight, 0x000A0329);
1145         SelectObject(MemDC, hbsave);
1146     }
1147 
1148     if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
1149 
1150 cleanup:
1151     SetTextColor(hDC, ForeColor);
1152     SetBkColor(hDC, BackColor);
1153 
1154     if (MemDC)
1155     {
1156         if (OldFont) SelectObject(MemDC, OldFont);
1157         if (OldBrush) SelectObject(MemDC, OldBrush);
1158         if (OldBMP) SelectObject(MemDC, OldBMP);
1159         if (MemBMP) DeleteObject(MemBMP);
1160         DeleteDC(MemDC);
1161     }
1162 
1163     return success;
1164 }
1165 
1166 /**********************************************************************
1167  *          PAINTING_DrawStateJam
1168  *
1169  * Jams in the requested type in the dc
1170  */
1171 static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
1172                                   DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1173                                   LPRECT rc, UINT dtflags, BOOL unicode )
1174 {
1175     HDC memdc;
1176     HBITMAP hbmsave;
1177     BOOL retval;
1178     INT cx = rc->right - rc->left;
1179     INT cy = rc->bottom - rc->top;
1180 
1181     switch(opcode)
1182     {
1183         case DST_TEXT:
1184         case DST_PREFIXTEXT:
1185             if(unicode)
1186                 return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1187             else
1188                 return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1189 
1190         case DST_ICON:
1191             return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, cx, cy, 0, NULL, DI_NORMAL);
1192 
1193         case DST_BITMAP:
1194             memdc = CreateCompatibleDC(hdc);
1195             if(!memdc)
1196                 return FALSE;
1197             hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
1198             if(!hbmsave)
1199             {
1200                 DeleteDC(memdc);
1201                 return FALSE;
1202             }
1203             retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1204             SelectObject(memdc, hbmsave);
1205             DeleteDC(memdc);
1206             return retval;
1207 
1208         case DST_COMPLEX:
1209             if(func)
1210             {
1211                 BOOL bRet;
1212                 /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */
1213 
1214                 OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1215                 bRet = func(hdc, lp, wp, cx, cy);
1216                 /* Restore origin */
1217                 OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1218                 return bRet;
1219             }
1220             else
1221             {
1222                 return FALSE;
1223             }
1224     }
1225     return FALSE;
1226 }
1227 
1228 static BOOL
1229 IntDrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1230              INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode)
1231 {
1232     HBITMAP hbm, hbmsave;
1233     HFONT hfsave;
1234     HBRUSH hbsave, hbrtmp = 0;
1235     HDC memdc;
1236     RECT rc;
1237     UINT dtflags = DT_NOCLIP;
1238     COLORREF fg, bg;
1239     UINT opcode = flags & 0xf;
1240     INT len = wp;
1241     BOOL retval, tmp;
1242     LOGFONTW lf;
1243     HFONT hFontOriginal, hNaaFont = NULL;
1244 
1245     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1246     {
1247         if(unicode)
1248             len = lstrlenW((LPWSTR)lp);
1249         else
1250             len = lstrlenA((LPSTR)lp);
1251     }
1252 
1253     hFontOriginal = GetCurrentObject(hdc, OBJ_FONT);
1254     if (flags & (DSS_MONO | DSS_DISABLED))
1255     {
1256         /* Create a non-antialiased font */
1257         GetObjectW(hFontOriginal, sizeof(lf), &lf);
1258         lf.lfQuality = NONANTIALIASED_QUALITY;
1259         hNaaFont = CreateFontIndirectW(&lf);
1260     }
1261 
1262     /* Find out what size the image has if not given by caller */
1263     if(!cx || !cy)
1264     {
1265         SIZE s;
1266         BITMAP bm;
1267 
1268         switch(opcode)
1269         {
1270             case DST_TEXT:
1271             case DST_PREFIXTEXT:
1272                 if(unicode)
1273                     retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1274                 else
1275                     retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1276                 if(!retval)
1277                     return FALSE;
1278                 break;
1279 
1280             case DST_ICON:
1281                 if(!get_icon_size((HICON)lp, &s))
1282                     return FALSE;
1283                 break;
1284 
1285             case DST_BITMAP:
1286                 if(!GetObjectW((HBITMAP)lp, sizeof(bm), &bm))
1287                     return FALSE;
1288                 s.cx = bm.bmWidth;
1289                 s.cy = bm.bmHeight;
1290                 break;
1291 
1292             case DST_COMPLEX: /* cx and cy must be set in this mode */
1293                 return FALSE;
1294 
1295             default:
1296                 ERR("Invalid opcode: %u\n", opcode);
1297                 return FALSE;
1298         }
1299 
1300         if(!cx) cx = s.cx;
1301         if(!cy) cy = s.cy;
1302     }
1303 
1304     SetRect(&rc, x, y, x + cx, y + cy);
1305 
1306     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1307         dtflags |= DT_RIGHT;
1308     if(opcode == DST_TEXT)
1309         dtflags |= DT_NOPREFIX;
1310     else if(opcode == DST_PREFIXTEXT)
1311     {
1312         if (flags & DSS_HIDEPREFIX)
1313             dtflags |= DT_HIDEPREFIX;
1314         if (flags & DSS_PREFIXONLY)
1315             dtflags |= DT_PREFIXONLY;
1316     }
1317 
1318     /* For DSS_NORMAL we just jam in the image and return */
1319     if((flags & 0x79f0) == DSS_NORMAL)
1320     {
1321         return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1322     }
1323 
1324     /* For all other states we need to convert the image to B/W in a local bitmap */
1325     /* before it is displayed */
1326     fg = SetTextColor(hdc, RGB(0, 0, 0));
1327     bg = SetBkColor(hdc, RGB(255, 255, 255));
1328     hbm = NULL; hbmsave = NULL;
1329     memdc = NULL; hbsave = NULL;
1330     retval = FALSE; /* assume failure */
1331 
1332     /* From here on we must use "goto cleanup" when something goes wrong */
1333     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1334     if(!hbm) goto cleanup;
1335     memdc   = CreateCompatibleDC(hdc);
1336     if(!memdc) goto cleanup;
1337     hbmsave = (HBITMAP)SelectObject(memdc, hbm);
1338     if(!hbmsave) goto cleanup;
1339     SetRect(&rc, 0, 0, cx, cy);
1340     if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
1341     SetBkColor(memdc, RGB(255, 255, 255));
1342     SetTextColor(memdc, RGB(0, 0, 0));
1343     if (hNaaFont)
1344         hfsave  = (HFONT)SelectObject(memdc, hNaaFont);
1345     else
1346         hfsave  = (HFONT)SelectObject(memdc, hFontOriginal);
1347     SetLayout( memdc, GetLayout( hdc ));
1348 
1349     /* DST_COMPLEX may draw text as well,
1350      * so we must be sure that correct font is selected
1351      */
1352     if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1353     tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1354     if(hfsave) SelectObject(memdc, hfsave);
1355     if (hNaaFont) DeleteObject(hNaaFont);
1356     if(!tmp) goto cleanup;
1357 
1358     /* This state cause the image to be dithered */
1359     if(flags & DSS_UNION)
1360     {
1361         hbsave = (HBRUSH)SelectObject(memdc, gpsi->hbrGray);
1362         if(!hbsave) goto cleanup;
1363         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1364         SelectObject(memdc, hbsave);
1365         if(!tmp) goto cleanup;
1366     }
1367 
1368     if (flags & DSS_DISABLED)
1369         hbrtmp = GetSysColorBrush(COLOR_3DHILIGHT);
1370     else if (flags & DSS_DEFAULT)
1371         hbrtmp = GetSysColorBrush(COLOR_3DSHADOW);
1372 
1373     /* Draw light or dark shadow */
1374     if (flags & (DSS_DISABLED|DSS_DEFAULT))
1375     {
1376         if(!hbrtmp) goto cleanup;
1377         hbsave = (HBRUSH)SelectObject(hdc, hbrtmp);
1378         if(!hbsave) goto cleanup;
1379         if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1380         SelectObject(hdc, hbsave);
1381     }
1382 
1383     if (flags & DSS_DISABLED)
1384     {
1385         hbr = hbrtmp = GetSysColorBrush(COLOR_3DSHADOW);
1386         if(!hbrtmp) goto cleanup;
1387     }
1388     else if (!hbr)
1389     {
1390         hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
1391     }
1392 
1393     hbsave = (HBRUSH)SelectObject(hdc, hbr);
1394 
1395     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1396 
1397     retval = TRUE; /* We succeeded */
1398 
1399 cleanup:
1400     SetTextColor(hdc, fg);
1401     SetBkColor(hdc, bg);
1402 
1403     if(hbsave) SelectObject(hdc, hbsave);
1404     if(hbmsave) SelectObject(memdc, hbmsave);
1405     if(hbm) DeleteObject(hbm);
1406     if(memdc) DeleteDC(memdc);
1407 
1408     return retval;
1409 }
1410 
1411 /*
1412  * @implemented
1413  */
1414 BOOL WINAPI
1415 RealDrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1416 {
1417     if (GetMapMode(hDC) != MM_TEXT)
1418         return FALSE;
1419 
1420     switch(uType)
1421     {
1422         case DFC_BUTTON:
1423             return UITOOLS95_DrawFrameButton(hDC, rc, uState);
1424         case DFC_CAPTION:
1425             return UITOOLS95_DrawFrameCaption(hDC, rc, uState);
1426         case DFC_MENU:
1427             return UITOOLS95_DrawFrameMenu(hDC, rc, uState);
1428 #if 0
1429         case DFC_POPUPMENU:
1430             UNIMPLEMENTED;
1431             break;
1432 #endif
1433         case DFC_SCROLL:
1434             return UITOOLS95_DrawFrameScroll(hDC, rc, uState);
1435     }
1436     return FALSE;
1437 }
1438 
1439 BOOL WINAPI
1440 DrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1441 {
1442    BOOL Hook, Ret = FALSE;
1443 
1444    LoadUserApiHook();
1445 
1446    Hook = BeginIfHookedUserApiHook();
1447 
1448    /* Bypass SEH and go direct. */
1449    if (!Hook) return RealDrawFrameControl(hDC, rc, uType, uState);
1450 
1451    _SEH2_TRY
1452    {
1453       Ret = guah.DrawFrameControl(hDC, rc, uType, uState);
1454    }
1455    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1456    {
1457        ERR("Got exception in hooked DrawFrameControl!\n");
1458    }
1459    _SEH2_END;
1460 
1461    EndUserApiHook();
1462 
1463    return Ret;
1464 }
1465 
1466 /*
1467  * @implemented
1468  */
1469 BOOL WINAPI
1470 DrawEdge(HDC hDC, LPRECT rc, UINT edge, UINT flags)
1471 {
1472     if (flags & BF_DIAGONAL)
1473         return IntDrawDiagEdge(hDC, rc, edge, flags);
1474     else
1475         return IntDrawRectEdge(hDC, rc, edge, flags, 1);
1476 }
1477 
1478 /*
1479  * @implemented
1480  */
1481 BOOL WINAPI
1482 GrayStringA(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1483             int nCount, int X, int Y, int nWidth, int nHeight)
1484 {
1485     return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1486 }
1487 
1488 /*
1489  * @implemented
1490  */
1491 BOOL WINAPI
1492 GrayStringW(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1493             int nCount, int X, int Y, int nWidth, int nHeight)
1494 {
1495     return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1496 }
1497 
1498 /*
1499  * @implemented
1500  */
1501 BOOL WINAPI
1502 InvertRect(HDC hDC, CONST RECT *lprc)
1503 {
1504     return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1505                   lprc->bottom - lprc->top, DSTINVERT);
1506 }
1507 
1508 /*
1509  * @implemented
1510  */
1511 INT WINAPI
1512 FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1513 {
1514     HBRUSH oldbrush;
1515     RECT r = *lprc;
1516 
1517     if (IsRectEmpty(&r)) return 0;
1518     if (!(oldbrush = SelectObject(hDC, hbr))) return 0;
1519 
1520     PatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
1521     PatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
1522     PatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
1523     PatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
1524 
1525     SelectObject(hDC, oldbrush);
1526     return TRUE;
1527 }
1528 
1529 /*
1530  * @implemented
1531  */
1532 BOOL WINAPI
1533 FlashWindow(HWND hWnd, BOOL bInvert)
1534 {
1535     FLASHWINFO FlashWndInfo;
1536 
1537     FlashWndInfo.cbSize = sizeof(FLASHWINFO);
1538     FlashWndInfo.hwnd = hWnd;
1539     FlashWndInfo.dwFlags = !bInvert ? 0 : (FLASHW_TRAY | FLASHW_CAPTION);
1540     FlashWndInfo.uCount = 1;
1541     FlashWndInfo.dwTimeout = 0;
1542 
1543     return NtUserFlashWindowEx(&FlashWndInfo);
1544 }
1545 
1546 /*
1547  * @implemented
1548  */
1549 INT WINAPI
1550 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1551 {
1552     BOOL Ret;
1553     HBRUSH prevhbr = NULL;
1554 
1555     /* Select brush if specified */
1556     if (hbr)
1557     {
1558         /* Handle system colors */
1559         if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1))
1560             hbr = GetSysColorBrush(PtrToUlong(hbr) - 1);
1561 
1562         prevhbr = SelectObject(hDC, hbr);
1563         if (prevhbr == NULL)
1564             return (INT)FALSE;
1565     }
1566 
1567     Ret = PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1568                  lprc->bottom - lprc->top, PATCOPY);
1569 
1570     /* Select old brush */
1571     if (prevhbr)
1572         SelectObject(hDC, prevhbr);
1573 
1574     return (INT)Ret;
1575 }
1576 
1577 /*
1578  * @implemented
1579  */
1580 BOOL WINAPI
1581 DrawFocusRect(HDC hdc, CONST RECT *rect)
1582 {
1583     HGDIOBJ OldObj;
1584     UINT cx, cy;
1585 
1586     NtUserSystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &cx, 0);
1587     NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &cy, 0);
1588 
1589     OldObj = SelectObject(hdc, gpsi->hbrGray);
1590 
1591     /* top */
1592     PatBlt(hdc, rect->left, rect->top, rect->right - rect->left, cy, PATINVERT);
1593     /* bottom */
1594     PatBlt(hdc, rect->left, rect->bottom - cy, rect->right - rect->left, cy, PATINVERT);
1595     /* left */
1596     PatBlt(hdc, rect->left, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1597     /* right */
1598     PatBlt(hdc, rect->right - cx, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1599 
1600     SelectObject(hdc, OldObj);
1601     return TRUE;
1602 }
1603 
1604 /*
1605  * @implemented
1606  */
1607 BOOL WINAPI
1608 DrawStateA(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1609            WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1610 {
1611     return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
1612 }
1613 
1614 /*
1615  * @implemented
1616  */
1617 BOOL WINAPI
1618 DrawStateW(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1619            WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1620 {
1621     return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
1622 }
1623