[USER32][WIN32K] Make antialiased disabled font readable. Patch by Katayama Hirofumi...
[reactos.git] / reactos / win32ss / user / user32 / windows / draw.c
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 /* INCLUDES *******************************************************************/
32
33 #include <user32.h>
34
35 #include <wine/debug.h>
36
37 WINE_DEFAULT_DEBUG_CHANNEL(user32);
38
39 /* GLOBALS *******************************************************************/
40
41 /* These tables are used in:
42 * UITOOLS_DrawDiagEdge()
43 * UITOOLS_DrawRectEdge()
44 */
45 static const signed char LTInnerNormal[] = {
46 -1, -1, -1, -1,
47 -1, COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
48 -1, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW, -1,
49 -1, -1, -1, -1
50 };
51
52 static const signed char LTOuterNormal[] = {
53 -1, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
54 COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
55 COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
56 -1, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1
57 };
58
59 static const signed char RBInnerNormal[] = {
60 -1, -1, -1, -1,
61 -1, COLOR_BTNSHADOW, COLOR_BTNSHADOW, -1,
62 -1, COLOR_3DLIGHT, COLOR_3DLIGHT, -1,
63 -1, -1, -1, -1
64 };
65
66 static const signed char RBOuterNormal[] = {
67 -1, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
68 COLOR_BTNSHADOW, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
69 COLOR_3DLIGHT, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
70 -1, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1
71 };
72
73 static const signed char LTInnerSoft[] = {
74 -1, -1, -1, -1,
75 -1, COLOR_3DLIGHT, COLOR_3DLIGHT, -1,
76 -1, COLOR_BTNSHADOW, COLOR_BTNSHADOW, -1,
77 -1, -1, -1, -1
78 };
79
80 static const signed char LTOuterSoft[] = {
81 -1, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
82 COLOR_3DLIGHT, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
83 COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
84 -1, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
85 };
86
87 #define RBInnerSoft RBInnerNormal /* These are the same */
88 #define RBOuterSoft RBOuterNormal
89
90 static const signed char LTRBOuterMono[] = {
91 -1, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
92 COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
93 COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
94 COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
95 };
96
97 static const signed char LTRBInnerMono[] = {
98 -1, -1, -1, -1,
99 -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
100 -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
101 -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
102 };
103
104 static const signed char LTRBOuterFlat[] = {
105 -1, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
106 COLOR_BTNFACE, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
107 COLOR_BTNFACE, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
108 COLOR_BTNFACE, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
109 };
110
111 static const signed char LTRBInnerFlat[] = {
112 -1, -1, -1, -1,
113 -1, COLOR_BTNFACE, COLOR_BTNFACE, COLOR_BTNFACE,
114 -1, COLOR_BTNFACE, COLOR_BTNFACE, COLOR_BTNFACE,
115 -1, COLOR_BTNFACE, COLOR_BTNFACE, COLOR_BTNFACE,
116 };
117 /* FUNCTIONS *****************************************************************/
118
119
120 HBRUSH WINAPI GetSysColorBrush(int nIndex);
121
122 /* Ported from WINE20020904 */
123 /* Same as DrawEdge invoked with BF_DIAGONAL */
124 static BOOL IntDrawDiagEdge(HDC hdc, LPRECT rc, UINT uType, UINT uFlags)
125 {
126 POINT Points[4];
127 signed char InnerI, OuterI;
128 HPEN InnerPen, OuterPen;
129 POINT SavePoint;
130 HPEN SavePen;
131 int spx, spy;
132 int epx, epy;
133 int Width = rc->right - rc->left;
134 int Height= rc->bottom - rc->top;
135 int SmallDiam = Width > Height ? Height : Width;
136 BOOL retval = !( ((uType & BDR_INNER) == BDR_INNER
137 || (uType & BDR_OUTER) == BDR_OUTER)
138 && !(uFlags & (BF_FLAT|BF_MONO)) );
139 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
140 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
141
142 /* Init some vars */
143 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
144 SavePen = (HPEN)SelectObject(hdc, InnerPen);
145 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
146
147 /* Determine the colors of the edges */
148 if(uFlags & BF_MONO)
149 {
150 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
151 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
152 }
153 else if(uFlags & BF_FLAT)
154 {
155 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
156 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
157 }
158 else if(uFlags & BF_SOFT)
159 {
160 if(uFlags & BF_BOTTOM)
161 {
162 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
163 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
164 }
165 else
166 {
167 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
168 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
169 }
170 }
171 else
172 {
173 if(uFlags & BF_BOTTOM)
174 {
175 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
176 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
177 }
178 else
179 {
180 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
181 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
182 }
183 }
184
185 if(InnerI != -1) InnerPen = GetStockObject(DC_PEN);
186 if(OuterI != -1) OuterPen = GetStockObject(DC_PEN);
187
188 MoveToEx(hdc, 0, 0, &SavePoint);
189
190 /* Don't ask me why, but this is what is visible... */
191 /* This must be possible to do much simpler, but I fail to */
192 /* see the logic in the MS implementation (sigh...). */
193 /* So, this might look a bit brute force here (and it is), but */
194 /* it gets the job done;) */
195
196 switch(uFlags & BF_RECT)
197 {
198 case 0:
199 case BF_LEFT:
200 case BF_BOTTOM:
201 case BF_BOTTOMLEFT:
202 /* Left bottom endpoint */
203 epx = rc->left-1;
204 spx = epx + SmallDiam;
205 epy = rc->bottom;
206 spy = epy - SmallDiam;
207 break;
208
209 case BF_TOPLEFT:
210 case BF_BOTTOMRIGHT:
211 /* Left top endpoint */
212 epx = rc->left-1;
213 spx = epx + SmallDiam;
214 epy = rc->top-1;
215 spy = epy + SmallDiam;
216 break;
217
218 case BF_TOP:
219 case BF_RIGHT:
220 case BF_TOPRIGHT:
221 case BF_RIGHT|BF_LEFT:
222 case BF_RIGHT|BF_LEFT|BF_TOP:
223 case BF_BOTTOM|BF_TOP:
224 case BF_BOTTOM|BF_TOP|BF_LEFT:
225 case BF_BOTTOMRIGHT|BF_LEFT:
226 case BF_BOTTOMRIGHT|BF_TOP:
227 case BF_RECT:
228 /* Right top endpoint */
229 spx = rc->left;
230 epx = spx + SmallDiam;
231 spy = rc->bottom-1;
232 epy = spy - SmallDiam;
233 break;
234 }
235
236 MoveToEx(hdc, spx, spy, NULL);
237 SelectObject(hdc, OuterPen);
238 SetDCPenColor(hdc, GetSysColor(OuterI));
239 LineTo(hdc, epx, epy);
240
241 SelectObject(hdc, InnerPen);
242 SetDCPenColor(hdc, GetSysColor(InnerI));
243
244 switch(uFlags & (BF_RECT|BF_DIAGONAL))
245 {
246 case BF_DIAGONAL_ENDBOTTOMLEFT:
247 case (BF_DIAGONAL|BF_BOTTOM):
248 case BF_DIAGONAL:
249 case (BF_DIAGONAL|BF_LEFT):
250 MoveToEx(hdc, spx-1, spy, NULL);
251 LineTo(hdc, epx, epy-1);
252 Points[0].x = spx-add;
253 Points[0].y = spy;
254 Points[1].x = rc->left;
255 Points[1].y = rc->top;
256 Points[2].x = epx+1;
257 Points[2].y = epy-1-add;
258 Points[3] = Points[2];
259 break;
260
261 case BF_DIAGONAL_ENDBOTTOMRIGHT:
262 MoveToEx(hdc, spx-1, spy, NULL);
263 LineTo(hdc, epx, epy+1);
264 Points[0].x = spx-add;
265 Points[0].y = spy;
266 Points[1].x = rc->left;
267 Points[1].y = rc->bottom-1;
268 Points[2].x = epx+1;
269 Points[2].y = epy+1+add;
270 Points[3] = Points[2];
271 break;
272
273 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
274 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
275 case BF_DIAGONAL_ENDTOPRIGHT:
276 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
277 MoveToEx(hdc, spx+1, spy, NULL);
278 LineTo(hdc, epx, epy+1);
279 Points[0].x = epx-1;
280 Points[0].y = epy+1+add;
281 Points[1].x = rc->right-1;
282 Points[1].y = rc->top+add;
283 Points[2].x = rc->right-1;
284 Points[2].y = rc->bottom-1;
285 Points[3].x = spx+add;
286 Points[3].y = spy;
287 break;
288
289 case BF_DIAGONAL_ENDTOPLEFT:
290 MoveToEx(hdc, spx, spy-1, NULL);
291 LineTo(hdc, epx+1, epy);
292 Points[0].x = epx+1+add;
293 Points[0].y = epy+1;
294 Points[1].x = rc->right-1;
295 Points[1].y = rc->top;
296 Points[2].x = rc->right-1;
297 Points[2].y = rc->bottom-1-add;
298 Points[3].x = spx;
299 Points[3].y = spy-add;
300 break;
301
302 case (BF_DIAGONAL|BF_TOP):
303 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
304 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
305 MoveToEx(hdc, spx+1, spy-1, NULL);
306 LineTo(hdc, epx, epy);
307 Points[0].x = epx-1;
308 Points[0].y = epy+1;
309 Points[1].x = rc->right-1;
310 Points[1].y = rc->top;
311 Points[2].x = rc->right-1;
312 Points[2].y = rc->bottom-1-add;
313 Points[3].x = spx+add;
314 Points[3].y = spy-add;
315 break;
316
317 case (BF_DIAGONAL|BF_RIGHT):
318 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
319 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
320 MoveToEx(hdc, spx, spy, NULL);
321 LineTo(hdc, epx-1, epy+1);
322 Points[0].x = spx;
323 Points[0].y = spy;
324 Points[1].x = rc->left;
325 Points[1].y = rc->top+add;
326 Points[2].x = epx-1-add;
327 Points[2].y = epy+1+add;
328 Points[3] = Points[2];
329 break;
330 }
331
332 /* Fill the interior if asked */
333 if((uFlags & BF_MIDDLE) && retval)
334 {
335 HBRUSH hbsave;
336 HPEN hpsave;
337 hbsave = (HBRUSH)SelectObject(hdc, GetStockObject(DC_BRUSH));
338 hpsave = (HPEN)SelectObject(hdc, GetStockObject(DC_PEN));
339 SetDCBrushColor(hdc, GetSysColor(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE));
340 SetDCPenColor(hdc, GetSysColor(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE));
341 Polygon(hdc, Points, 4);
342 SelectObject(hdc, hbsave);
343 SelectObject(hdc, hpsave);
344 }
345
346 /* Adjust rectangle if asked */
347 if(uFlags & BF_ADJUST)
348 {
349 if(uFlags & BF_LEFT) rc->left += add;
350 if(uFlags & BF_RIGHT) rc->right -= add;
351 if(uFlags & BF_TOP) rc->top += add;
352 if(uFlags & BF_BOTTOM) rc->bottom -= add;
353 }
354
355 /* Cleanup */
356 SelectObject(hdc, SavePen);
357 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
358
359 return retval;
360 }
361
362 /* Ported from WINE20020904 */
363 /* Same as DrawEdge invoked without BF_DIAGONAL
364 *
365 * 23-Nov-1997: Changed by Bertho Stultiens
366 * The width parameter sets the width of each outer and inner edge.
367 *
368 * Well, I started testing this and found out that there are a few things
369 * that weren't quite as win95. The following rewrite should reproduce
370 * win95 results completely.
371 * The colorselection is table-driven to avoid awfull if-statements.
372 * The table below show the color settings.
373 *
374 * Pen selection table for uFlags = 0
375 *
376 * uType | LTI | LTO | RBI | RBO
377 * ------+-------+-------+-------+-------
378 * 0000 | x | x | x | x
379 * 0001 | x | 22 | x | 21
380 * 0010 | x | 16 | x | 20
381 * 0011 | x | x | x | x
382 * ------+-------+-------+-------+-------
383 * 0100 | x | 20 | x | 16
384 * 0101 | 20 | 22 | 16 | 21
385 * 0110 | 20 | 16 | 16 | 20
386 * 0111 | x | x | x | x
387 * ------+-------+-------+-------+-------
388 * 1000 | x | 21 | x | 22
389 * 1001 | 21 | 22 | 22 | 21
390 * 1010 | 21 | 16 | 22 | 20
391 * 1011 | x | x | x | x
392 * ------+-------+-------+-------+-------
393 * 1100 | x | x | x | x
394 * 1101 | x | x (22)| x | x (21)
395 * 1110 | x | x (16)| x | x (20)
396 * 1111 | x | x | x | x
397 *
398 * Pen selection table for uFlags = BF_SOFT
399 *
400 * uType | LTI | LTO | RBI | RBO
401 * ------+-------+-------+-------+-------
402 * 0000 | x | x | x | x
403 * 0001 | x | 20 | x | 21
404 * 0010 | x | 21 | x | 20
405 * 0011 | x | x | x | x
406 * ------+-------+-------+-------+-------
407 * 0100 | x | 22 | x | 16
408 * 0101 | 22 | 20 | 16 | 21
409 * 0110 | 22 | 21 | 16 | 20
410 * 0111 | x | x | x | x
411 * ------+-------+-------+-------+-------
412 * 1000 | x | 16 | x | 22
413 * 1001 | 16 | 20 | 22 | 21
414 * 1010 | 16 | 21 | 22 | 20
415 * 1011 | x | x | x | x
416 * ------+-------+-------+-------+-------
417 * 1100 | x | x | x | x
418 * 1101 | x | x (20)| x | x (21)
419 * 1110 | x | x (21)| x | x (20)
420 * 1111 | x | x | x | x
421 *
422 * x = don't care; (n) = is what win95 actually uses
423 * LTI = left Top Inner line
424 * LTO = left Top Outer line
425 * RBI = Right Bottom Inner line
426 * RBO = Right Bottom Outer line
427 * 15 = COLOR_BTNFACE
428 * 16 = COLOR_BTNSHADOW
429 * 20 = COLOR_BTNHIGHLIGHT
430 * 21 = COLOR_3DDKSHADOW
431 * 22 = COLOR_3DLIGHT
432 */
433 static BOOL IntDrawRectEdge(HDC hdc, LPRECT rc, UINT uType, UINT uFlags, UINT width)
434 {
435 signed char LTInnerI, LTOuterI;
436 signed char RBInnerI, RBOuterI;
437 HBRUSH lti_brush, lto_brush, rbi_brush, rbo_brush;
438 RECT InnerRect = *rc, fill_rect;
439 int lbi_offset = 0, lti_offset = 0, rti_offset = 0, rbi_offset = 0;
440 BOOL retval = !( ((uType & BDR_INNER) == BDR_INNER
441 || (uType & BDR_OUTER) == BDR_OUTER)
442 && !(uFlags & (BF_FLAT|BF_MONO)) );
443
444 lti_brush = lto_brush = rbi_brush = rbo_brush = GetStockObject(NULL_BRUSH);
445
446 /* Determine the colors of the edges */
447 if(uFlags & BF_MONO)
448 {
449 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
450 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
451 }
452 else if(uFlags & BF_FLAT)
453 {
454 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
455 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
456
457 /* Bertho Stultiens states above that this function exactly matches win95
458 * In win98 BF_FLAT rectangles have an inner border same color as the
459 * middle (COLOR_BTNFACE). I believe it's the same for win95 but since
460 * I don't know I go with Bertho and just sets it for win98 until proven
461 * otherwise.
462 * Dennis Björklund, 10 June, 99
463 */
464 if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
465 }
466 else if(uFlags & BF_SOFT)
467 {
468 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
469 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
470 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
471 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
472 }
473 else
474 {
475 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
476 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
477 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
478 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
479 }
480
481 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) lbi_offset = width;
482 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) rti_offset = width;
483 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) rbi_offset = width;
484 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) lti_offset = width;
485
486 if(LTInnerI != -1) lti_brush = GetSysColorBrush(LTInnerI);
487 if(LTOuterI != -1) lto_brush = GetSysColorBrush(LTOuterI);
488 if(RBInnerI != -1) rbi_brush = GetSysColorBrush(RBInnerI);
489 if(RBOuterI != -1) rbo_brush = GetSysColorBrush(RBOuterI);
490
491 /* Draw the outer edge */
492 if(uFlags & BF_TOP)
493 {
494 fill_rect = InnerRect;
495 fill_rect.bottom = fill_rect.top + width;
496 FillRect( hdc, &fill_rect, lto_brush );
497 }
498 if(uFlags & BF_LEFT)
499 {
500 fill_rect = InnerRect;
501 fill_rect.right = fill_rect.left + width;
502 FillRect( hdc, &fill_rect, lto_brush );
503 }
504 if(uFlags & BF_BOTTOM)
505 {
506 fill_rect = InnerRect;
507 fill_rect.top = fill_rect.bottom - width;
508 FillRect( hdc, &fill_rect, rbo_brush );
509 }
510 if(uFlags & BF_RIGHT)
511 {
512 fill_rect = InnerRect;
513 fill_rect.left = fill_rect.right - width;
514 FillRect( hdc, &fill_rect, rbo_brush );
515 }
516
517 /* Draw the inner edge */
518 if(uFlags & BF_TOP)
519 {
520 SetRect( &fill_rect, InnerRect.left + lti_offset, InnerRect.top + width,
521 InnerRect.right - rti_offset, InnerRect.top + 2 * width );
522 FillRect( hdc, &fill_rect, lti_brush );
523 }
524 if(uFlags & BF_LEFT)
525 {
526 SetRect( &fill_rect, InnerRect.left + width, InnerRect.top + lti_offset,
527 InnerRect.left + 2 * width, InnerRect.bottom - lbi_offset );
528 FillRect( hdc, &fill_rect, lti_brush );
529 }
530 if(uFlags & BF_BOTTOM)
531 {
532 SetRect( &fill_rect, InnerRect.left + lbi_offset, InnerRect.bottom - 2 * width,
533 InnerRect.right - rbi_offset, InnerRect.bottom - width );
534 FillRect( hdc, &fill_rect, rbi_brush );
535 }
536 if(uFlags & BF_RIGHT)
537 {
538 SetRect( &fill_rect, InnerRect.right - 2 * width, InnerRect.top + rti_offset,
539 InnerRect.right - width, InnerRect.bottom - rbi_offset );
540 FillRect( hdc, &fill_rect, rbi_brush );
541 }
542
543 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
544 {
545 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0)
546 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? width : 0);
547
548 if(uFlags & BF_LEFT) InnerRect.left += add;
549 if(uFlags & BF_RIGHT) InnerRect.right -= add;
550 if(uFlags & BF_TOP) InnerRect.top += add;
551 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
552
553 if((uFlags & BF_MIDDLE) && retval)
554 {
555 FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
556 COLOR_WINDOW : COLOR_BTNFACE));
557 }
558
559 if(uFlags & BF_ADJUST)
560 *rc = InnerRect;
561 }
562
563 return retval;
564 }
565
566 /* Ported from WINE20020904 */
567 /* Utility to create a square rectangle and returning the width */
568 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
569 {
570 int Width = src->right - src->left;
571 int Height = src->bottom - src->top;
572 int SmallDiam = Width > Height ? Height : Width;
573
574 *dst = *src;
575
576 /* Make it a square box */
577 if(Width < Height) /* SmallDiam == Width */
578 {
579 dst->top += (Height-Width)/2;
580 dst->bottom = dst->top + SmallDiam;
581 }
582 else if(Width > Height) /* SmallDiam == Height */
583 {
584 dst->left += (Width-Height)/2;
585 dst->right = dst->left + SmallDiam;
586 }
587
588 return SmallDiam;
589 }
590
591 /* Ported from WINE20020904 */
592 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
593 {
594 if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
595 {
596 HBRUSH hbsave;
597 COLORREF bg;
598
599 FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
600 bg = SetBkColor(dc, RGB(255, 255, 255));
601 hbsave = (HBRUSH)SelectObject(dc, gpsi->hbrGray);
602 PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
603 SelectObject(dc, hbsave);
604 SetBkColor(dc, bg);
605 }
606 else
607 {
608 FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
609 }
610 }
611
612 /* Ported from WINE20020904 */
613 /* Draw a push button coming from DrawFrameControl()
614 *
615 * Does a pretty good job in emulating MS behavior. Some quirks are
616 * however there because MS uses a TrueType font (Marlett) to draw
617 * the buttons.
618 *
619 * FIXME: This looks a little bit strange, needs to be rewritten completely
620 * (several quirks with adjust, DFCS_CHECKED aso)
621 */
622 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
623 {
624 UINT edge;
625 RECT myr = *r;
626
627 if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
628 edge = EDGE_SUNKEN;
629 else
630 edge = EDGE_RAISED;
631
632 if(uFlags & DFCS_CHECKED)
633 {
634 if(uFlags & DFCS_MONO)
635 IntDrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST, 1);
636 else
637 IntDrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST, 1);
638
639 UITOOLS_DrawCheckedRect( dc, &myr );
640 }
641 else
642 {
643 if(uFlags & DFCS_MONO)
644 {
645 IntDrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST, 1);
646 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
647 }
648 else
649 {
650 IntDrawRectEdge(dc, r, edge, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT | BF_SOFT, 1);
651 }
652 }
653
654 /* Adjust rectangle if asked */
655 if(uFlags & DFCS_ADJUSTRECT)
656 InflateRect(r, -2, -2);
657
658 return TRUE;
659 }
660
661 static BOOL UITOOLS95_DFC_ButtonCheckRadio(HDC dc, LPRECT r, UINT uFlags, BOOL Radio)
662 {
663 LOGFONTW lf;
664 HFONT hFont, hOldFont;
665 int i;
666 TCHAR OutRight, OutLeft, InRight, InLeft, Center;
667 INT X, Y, Width, Height, Shorter;
668 INT BkMode = GetBkMode(dc);
669 COLORREF TextColor = GetTextColor(dc);
670
671 Width = r->right - r->left;
672 Height = r->bottom - r->top;
673 Shorter = (Width < Height) ? Width : Height;
674 X = r->left + (Width - Shorter) / 2;
675 Y = r->top + (Height - Shorter) / 2;
676
677 if (Radio)
678 {
679 OutRight = 'j'; // Outer right
680 OutLeft = 'k'; // Outer left
681 InRight = 'l'; // inner left
682 InLeft = 'm'; // inner right
683 Center = 'n'; // center
684 }
685 else
686 {
687 OutRight = 'c'; // Outer right
688 OutLeft = 'd'; // Outer left
689 InRight = 'e'; // inner left
690 InLeft = 'f'; // inner right
691 Center = 'g'; // center
692 }
693
694 ZeroMemory(&lf, sizeof(LOGFONTW));
695 lf.lfHeight = Shorter;
696 lf.lfCharSet = DEFAULT_CHARSET;
697 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
698 if (Radio && ((uFlags & 0xFF) == DFCS_BUTTONRADIOMASK))
699 {
700 lf.lfQuality = NONANTIALIASED_QUALITY;
701 }
702 hFont = CreateFontIndirect(&lf);
703 hOldFont = SelectObject(dc, hFont);
704
705 if (Radio && ((uFlags & 0xFF) == DFCS_BUTTONRADIOMASK))
706 {
707 #if 1
708 // FIXME: improve font rendering
709 RECT Rect;
710 HGDIOBJ hbrOld, hpenOld;
711 FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
712 SetRect(&Rect, X, Y, X + Shorter, Y + Shorter);
713 InflateRect(&Rect, -(Shorter * 8) / 54, -(Shorter * 8) / 54);
714 hbrOld = SelectObject(dc, GetStockObject(BLACK_BRUSH));
715 hpenOld = SelectObject(dc, GetStockObject(NULL_PEN));
716 Ellipse(dc, Rect.left, Rect.top, Rect.right, Rect.bottom);
717 SelectObject(dc, hbrOld);
718 SelectObject(dc, hpenOld);
719 #else
720 SetBkMode(dc, OPAQUE);
721 SetBkColor(dc, RGB(255, 255, 255));
722 SetTextColor(dc, RGB(0, 0, 0));
723 TextOut(dc, X, Y, &Center, 1);
724 SetBkMode(dc, TRANSPARENT);
725 TextOut(dc, X, Y, &OutRight, 1);
726 TextOut(dc, X, Y, &OutLeft, 1);
727 TextOut(dc, X, Y, &InRight, 1);
728 TextOut(dc, X, Y, &InLeft, 1);
729 #endif
730 }
731 else
732 {
733 SetBkMode(dc, TRANSPARENT);
734
735 /* Center section, white for active, grey for inactive */
736 if ((uFlags & (DFCS_INACTIVE | DFCS_PUSHED)))
737 i = COLOR_BTNFACE;
738 else
739 i = COLOR_WINDOW;
740 SetTextColor(dc, GetSysColor(i));
741 TextOut(dc, X, Y, &Center, 1);
742
743 if (uFlags & (DFCS_FLAT | DFCS_MONO))
744 {
745 SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
746 TextOut(dc, X, Y, &OutRight, 1);
747 TextOut(dc, X, Y, &OutLeft, 1);
748 TextOut(dc, X, Y, &InRight, 1);
749 TextOut(dc, X, Y, &InLeft, 1);
750 }
751 else
752 {
753 SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
754 TextOut(dc, X, Y, &OutRight, 1);
755 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
756 TextOut(dc, X, Y, &OutLeft, 1);
757 SetTextColor(dc, GetSysColor(COLOR_3DDKSHADOW));
758 TextOut(dc, X, Y, &InRight, 1);
759 SetTextColor(dc, GetSysColor(COLOR_3DLIGHT));
760 TextOut(dc, X, Y, &InLeft, 1);
761 }
762
763 if (uFlags & DFCS_CHECKED)
764 {
765 TCHAR Check = (Radio) ? 'i' : 'b';
766
767 SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
768 TextOut(dc, X, Y, &Check, 1);
769 }
770 }
771
772 SelectObject(dc, hOldFont);
773 DeleteObject(hFont);
774
775 SetTextColor(dc, TextColor);
776 SetBkMode(dc, BkMode);
777
778 return TRUE;
779 }
780
781 /* Ported from WINE20020904 */
782 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
783 {
784 switch(uState & 0xff)
785 {
786 case DFCS_BUTTONPUSH:
787 return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
788
789 case DFCS_BUTTONCHECK:
790 case DFCS_BUTTON3STATE:
791 return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, FALSE);
792
793 case DFCS_BUTTONRADIOIMAGE:
794 case DFCS_BUTTONRADIOMASK:
795 case DFCS_BUTTONRADIO:
796 return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, TRUE);
797
798 /*
799 default:
800 DbgPrint("Invalid button state=0x%04x\n", uState);
801 */
802 }
803
804 return FALSE;
805 }
806
807 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
808 {
809 LOGFONTW lf;
810 HFONT hFont, hOldFont;
811 COLORREF clrsave;
812 RECT myr;
813 INT bkmode;
814 TCHAR Symbol;
815 switch(uFlags & 0xff)
816 {
817 case DFCS_CAPTIONCLOSE:
818 Symbol = 'r';
819 break;
820 case DFCS_CAPTIONHELP:
821 Symbol = 's';
822 break;
823 case DFCS_CAPTIONMIN:
824 Symbol = '0';
825 break;
826 case DFCS_CAPTIONMAX:
827 Symbol = '1';
828 break;
829 case DFCS_CAPTIONRESTORE:
830 Symbol = '2';
831 break;
832 default:
833 WARN("Invalid caption; flags=0x%04x\n", uFlags);
834 return FALSE;
835 }
836 IntDrawRectEdge(dc,r,(uFlags&DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, BF_RECT | BF_MIDDLE | BF_SOFT, 1);
837 ZeroMemory(&lf, sizeof(LOGFONTW));
838 UITOOLS_MakeSquareRect(r, &myr);
839 myr.left += 1;
840 myr.top += 1;
841 myr.right -= 1;
842 myr.bottom -= 1;
843 if(uFlags & DFCS_PUSHED)
844 OffsetRect(&myr,1,1);
845 lf.lfHeight = myr.bottom - myr.top;
846 lf.lfWidth = 0;
847 lf.lfWeight = FW_NORMAL;
848 lf.lfCharSet = DEFAULT_CHARSET;
849 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
850 hFont = CreateFontIndirect(&lf);
851 /* save font and text color */
852 hOldFont = SelectObject(dc, hFont);
853 clrsave = GetTextColor(dc);
854 bkmode = GetBkMode(dc);
855 /* set color and drawing mode */
856 SetBkMode(dc, TRANSPARENT);
857 if(uFlags & DFCS_INACTIVE)
858 {
859 /* draw shadow */
860 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
861 TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
862 }
863 SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
864 /* draw selected symbol */
865 TextOut(dc, myr.left, myr.top, &Symbol, 1);
866 /* restore previous settings */
867 SetTextColor(dc, clrsave);
868 SelectObject(dc, hOldFont);
869 SetBkMode(dc, bkmode);
870 DeleteObject(hFont);
871 return TRUE;
872 }
873
874 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
875 {
876 LOGFONTW lf;
877 HFONT hFont, hOldFont;
878 COLORREF clrsave;
879 RECT myr;
880 INT bkmode;
881 TCHAR Symbol;
882 switch(uFlags & 0xff)
883 {
884 case DFCS_SCROLLCOMBOBOX:
885 case DFCS_SCROLLDOWN:
886 Symbol = '6';
887 break;
888
889 case DFCS_SCROLLUP:
890 Symbol = '5';
891 break;
892
893 case DFCS_SCROLLLEFT:
894 Symbol = '3';
895 break;
896
897 case DFCS_SCROLLRIGHT:
898 Symbol = '4';
899 break;
900
901 case DFCS_SCROLLSIZEGRIP:
902 case DFCS_SCROLLSIZEGRIPRIGHT:
903 ZeroMemory(&lf, sizeof(LOGFONTW));
904 UITOOLS_MakeSquareRect(r, &myr);
905 lf.lfHeight = myr.bottom - myr.top;
906 lf.lfWidth = 0;
907 lf.lfWeight = FW_NORMAL;
908 lf.lfCharSet = DEFAULT_CHARSET;
909 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
910 hFont = CreateFontIndirect(&lf);
911 /* save font and text color */
912 hOldFont = SelectObject(dc, hFont);
913 clrsave = GetTextColor(dc);
914 bkmode = GetBkMode(dc);
915 /* set color and drawing mode */
916 SetBkMode(dc, TRANSPARENT);
917 if (!(uFlags & (DFCS_MONO | DFCS_FLAT)))
918 {
919 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
920 /* draw selected symbol */
921 Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'o' : 'x';
922 TextOut(dc, myr.left, myr.top, &Symbol, 1);
923 SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
924 } else
925 SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
926 /* draw selected symbol */
927 Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'p' : 'y';
928 TextOut(dc, myr.left, myr.top, &Symbol, 1);
929 /* restore previous settings */
930 SetTextColor(dc, clrsave);
931 SelectObject(dc, hOldFont);
932 SetBkMode(dc, bkmode);
933 DeleteObject(hFont);
934 return TRUE;
935 default:
936 WARN("Invalid scroll; flags=0x%04x\n", uFlags);
937 return FALSE;
938 }
939 IntDrawRectEdge(dc, r, (uFlags & DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT, 1);
940 ZeroMemory(&lf, sizeof(LOGFONTW));
941 UITOOLS_MakeSquareRect(r, &myr);
942 myr.left += 1;
943 myr.top += 1;
944 myr.right -= 1;
945 myr.bottom -= 1;
946 if(uFlags & DFCS_PUSHED)
947 OffsetRect(&myr,1,1);
948 lf.lfHeight = myr.bottom - myr.top;
949 lf.lfWidth = 0;
950 lf.lfWeight = FW_NORMAL;
951 lf.lfCharSet = DEFAULT_CHARSET;
952 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
953 hFont = CreateFontIndirect(&lf);
954 /* save font and text color */
955 hOldFont = SelectObject(dc, hFont);
956 clrsave = GetTextColor(dc);
957 bkmode = GetBkMode(dc);
958 /* set color and drawing mode */
959 SetBkMode(dc, TRANSPARENT);
960 if(uFlags & DFCS_INACTIVE)
961 {
962 /* draw shadow */
963 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
964 TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
965 }
966 SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
967 /* draw selected symbol */
968 TextOut(dc, myr.left, myr.top, &Symbol, 1);
969 /* restore previous settings */
970 SetTextColor(dc, clrsave);
971 SelectObject(dc, hOldFont);
972 SetBkMode(dc, bkmode);
973 DeleteObject(hFont);
974 return TRUE;
975 }
976
977 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
978 {
979 LOGFONTW lf;
980 HFONT hFont, hOldFont;
981 TCHAR Symbol;
982 switch(uFlags & 0xff)
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 WARN("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 = r->bottom - r->top;
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 & 0xff) == DFCS_MENUARROWUP ||
1024 (uFlags & 0xff) == DFCS_MENUARROWDOWN )
1025 {
1026 #if 0
1027 if (uFlags & DFCS_INACTIVE)
1028 {
1029 /* draw shadow */
1030 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1031 TextOut(dc, r->left + 1, r->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, r->left, r->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 }
1462 _SEH2_END;
1463
1464 EndUserApiHook();
1465
1466 return Ret;
1467 }
1468
1469 /*
1470 * @implemented
1471 */
1472 BOOL WINAPI
1473 DrawEdge(HDC hDC, LPRECT rc, UINT edge, UINT flags)
1474 {
1475 if (flags & BF_DIAGONAL)
1476 return IntDrawDiagEdge(hDC, rc, edge, flags);
1477 else
1478 return IntDrawRectEdge(hDC, rc, edge, flags, 1);
1479 }
1480
1481 /*
1482 * @implemented
1483 */
1484 BOOL WINAPI
1485 GrayStringA(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1486 int nCount, int X, int Y, int nWidth, int nHeight)
1487 {
1488 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1489 }
1490
1491 /*
1492 * @implemented
1493 */
1494 BOOL WINAPI
1495 GrayStringW(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1496 int nCount, int X, int Y, int nWidth, int nHeight)
1497 {
1498 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1499 }
1500
1501 /*
1502 * @implemented
1503 */
1504 BOOL WINAPI
1505 InvertRect(HDC hDC, CONST RECT *lprc)
1506 {
1507 return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1508 lprc->bottom - lprc->top, DSTINVERT);
1509 }
1510
1511 /*
1512 * @implemented
1513 */
1514 INT WINAPI
1515 FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1516 {
1517 HBRUSH oldbrush;
1518 RECT r = *lprc;
1519
1520 if (IsRectEmpty(&r)) return 0;
1521 if (!(oldbrush = SelectObject(hDC, hbr))) return 0;
1522
1523 PatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
1524 PatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
1525 PatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
1526 PatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
1527
1528 SelectObject(hDC, oldbrush);
1529 return TRUE;
1530 }
1531
1532 /*
1533 * @implemented
1534 */
1535 BOOL WINAPI
1536 FlashWindow(HWND hWnd, BOOL bInvert)
1537 {
1538 FLASHWINFO FlashWndInfo;
1539
1540 FlashWndInfo.cbSize = sizeof(FLASHWINFO);
1541 FlashWndInfo.hwnd = hWnd;
1542 FlashWndInfo.dwFlags = !bInvert ? 0 : (FLASHW_TRAY | FLASHW_CAPTION);
1543 FlashWndInfo.uCount = 1;
1544 FlashWndInfo.dwTimeout = 0;
1545
1546 return NtUserFlashWindowEx(&FlashWndInfo);
1547 }
1548
1549 /*
1550 * @implemented
1551 */
1552 INT WINAPI
1553 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1554 {
1555 BOOL Ret;
1556 HBRUSH prevhbr = NULL;
1557
1558 /* Select brush if specified */
1559 if (hbr)
1560 {
1561 /* Handle system colors */
1562 if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1))
1563 hbr = GetSysColorBrush(PtrToUlong(hbr) - 1);
1564
1565 prevhbr = SelectObject(hDC, hbr);
1566 if (prevhbr == NULL)
1567 return (INT)FALSE;
1568 }
1569
1570 Ret = PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1571 lprc->bottom - lprc->top, PATCOPY);
1572
1573 /* Select old brush */
1574 if (prevhbr)
1575 SelectObject(hDC, prevhbr);
1576
1577 return (INT)Ret;
1578 }
1579
1580 /*
1581 * @implemented
1582 */
1583 BOOL WINAPI
1584 DrawFocusRect(HDC hdc, CONST RECT *rect)
1585 {
1586 HGDIOBJ OldObj;
1587 UINT cx, cy;
1588
1589 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &cx, 0);
1590 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &cy, 0);
1591
1592 OldObj = SelectObject(hdc, gpsi->hbrGray);
1593
1594 /* top */
1595 PatBlt(hdc, rect->left, rect->top, rect->right - rect->left, cy, PATINVERT);
1596 /* bottom */
1597 PatBlt(hdc, rect->left, rect->bottom - cy, rect->right - rect->left, cy, PATINVERT);
1598 /* left */
1599 PatBlt(hdc, rect->left, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1600 /* right */
1601 PatBlt(hdc, rect->right - cx, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1602
1603 SelectObject(hdc, OldObj);
1604 return TRUE;
1605 }
1606
1607 /*
1608 * @implemented
1609 */
1610 BOOL WINAPI
1611 DrawStateA(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1612 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1613 {
1614 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
1615 }
1616
1617 /*
1618 * @implemented
1619 */
1620 BOOL WINAPI
1621 DrawStateW(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1622 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1623 {
1624 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
1625 }