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