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