Sync with trunk r43123
[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 * 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 RECT rc;
705 LOGFONTW lf;
706 HFONT hFont, hOldFont;
707 int SmallDiam, i;
708 TCHAR OutRight, OutLeft, InRight, InLeft, Center;
709
710 if (Radio)
711 {
712 OutRight = 'j'; // Outer right
713 OutLeft = 'k'; // Outer left
714 InRight = 'l'; // inner left
715 InLeft = 'm'; // inner right
716 Center = 'n'; // center
717 } else
718 {
719 OutRight = 'c'; // Outer right
720 OutLeft = 'd'; // Outer left
721 InRight = 'e'; // inner left
722 InLeft = 'f'; // inner right
723 Center = 'g'; // center
724 }
725
726 SmallDiam = UITOOLS_MakeSquareRect(r, &rc);
727
728 ZeroMemory(&lf, sizeof(LOGFONTW));
729 lf.lfHeight = SmallDiam;
730 lf.lfWidth = 0;
731 lf.lfWeight = FW_NORMAL;
732 lf.lfCharSet = DEFAULT_CHARSET;
733 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
734 hFont = CreateFontIndirect(&lf);
735 hOldFont = SelectObject(dc, hFont);
736
737 if(Radio && ((uFlags & 0xff) == DFCS_BUTTONRADIOMASK))
738 {
739 SetBkMode(dc, OPAQUE);
740 SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
741 TextOut(dc, rc.left, rc.top, &Center, 1);
742 SetBkMode(dc, TRANSPARENT);
743 SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
744 TextOut(dc, rc.left, rc.top, &OutRight, 1);
745 SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
746 TextOut(dc, rc.left, rc.top, &OutLeft, 1);
747 }
748 else
749 {
750 SetBkMode(dc, TRANSPARENT);
751
752 /* Center section, white for active, grey for inactive */
753 i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
754 SetTextColor(dc, GetSysColor(i));
755 TextOut(dc, rc.left, rc.top, &Center, 1);
756
757 if(uFlags & (DFCS_FLAT | DFCS_MONO))
758 {
759 SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
760 TextOut(dc, rc.left, rc.top, &OutRight, 1);
761 TextOut(dc, rc.left, rc.top, &OutLeft, 1);
762 TextOut(dc, rc.left, rc.top, &InRight, 1);
763 TextOut(dc, rc.left, rc.top, &InLeft, 1);
764 }
765 else
766 {
767 SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
768 TextOut(dc, rc.left, rc.top, &OutRight, 1);
769 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
770 TextOut(dc, rc.left, rc.top, &OutLeft, 1);
771 SetTextColor(dc, GetSysColor(COLOR_3DDKSHADOW));
772 TextOut(dc, rc.left, rc.top, &InRight, 1);
773 SetTextColor(dc, GetSysColor(COLOR_3DLIGHT));
774 TextOut(dc, rc.left, rc.top, &InLeft, 1);
775 }
776 }
777
778 if(uFlags & DFCS_CHECKED)
779 {
780 TCHAR Check = (Radio) ? 'i' : 'b';
781
782 SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
783 TextOut(dc, rc.left, rc.top, &Check, 1);
784 }
785
786 SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
787 SelectObject(dc, hOldFont);
788 DeleteObject(hFont);
789
790 return TRUE;
791 }
792
793 /* Ported from WINE20020904 */
794 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
795 {
796 switch(uState & 0xff)
797 {
798 case DFCS_BUTTONPUSH:
799 return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
800
801 case DFCS_BUTTONCHECK:
802 case DFCS_BUTTON3STATE:
803 return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, FALSE);
804
805 case DFCS_BUTTONRADIOIMAGE:
806 case DFCS_BUTTONRADIOMASK:
807 case DFCS_BUTTONRADIO:
808 return UITOOLS95_DFC_ButtonCheckRadio(hdc, rc, uState, TRUE);
809
810 /*
811 default:
812 DbgPrint("Invalid button state=0x%04x\n", uState);
813 */
814 }
815
816 return FALSE;
817 }
818
819 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
820 {
821 LOGFONTW lf;
822 HFONT hFont, hOldFont;
823 COLORREF clrsave;
824 RECT myr;
825 INT bkmode;
826 TCHAR Symbol;
827 switch(uFlags & 0xff)
828 {
829 case DFCS_CAPTIONCLOSE:
830 Symbol = 'r';
831 break;
832 case DFCS_CAPTIONHELP:
833 Symbol = 's';
834 break;
835 case DFCS_CAPTIONMIN:
836 Symbol = '0';
837 break;
838 case DFCS_CAPTIONMAX:
839 Symbol = '1';
840 break;
841 case DFCS_CAPTIONRESTORE:
842 Symbol = '2';
843 break;
844 default:
845 return FALSE;
846 }
847 IntDrawRectEdge(dc,r,(uFlags&DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, BF_RECT | BF_MIDDLE | BF_SOFT);
848 ZeroMemory(&lf, sizeof(LOGFONTW));
849 UITOOLS_MakeSquareRect(r, &myr);
850 myr.left += 1;
851 myr.top += 1;
852 myr.right -= 1;
853 myr.bottom -= 1;
854 if(uFlags & DFCS_PUSHED)
855 OffsetRect(&myr,1,1);
856 lf.lfHeight = myr.bottom - myr.top;
857 lf.lfWidth = 0;
858 lf.lfWeight = FW_NORMAL;
859 lf.lfCharSet = DEFAULT_CHARSET;
860 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
861 hFont = CreateFontIndirect(&lf);
862 /* save font and text color */
863 hOldFont = SelectObject(dc, hFont);
864 clrsave = GetTextColor(dc);
865 bkmode = GetBkMode(dc);
866 /* set color and drawing mode */
867 SetBkMode(dc, TRANSPARENT);
868 if(uFlags & DFCS_INACTIVE)
869 {
870 /* draw shadow */
871 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
872 TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
873 }
874 SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
875 /* draw selected symbol */
876 TextOut(dc, myr.left, myr.top, &Symbol, 1);
877 /* restore previous settings */
878 SetTextColor(dc, clrsave);
879 SelectObject(dc, hOldFont);
880 SetBkMode(dc, bkmode);
881 DeleteObject(hFont);
882 return TRUE;
883 }
884
885 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
886 {
887 LOGFONTW lf;
888 HFONT hFont, hOldFont;
889 COLORREF clrsave;
890 RECT myr;
891 INT bkmode;
892 TCHAR Symbol;
893 switch(uFlags & 0xff)
894 {
895 case DFCS_SCROLLCOMBOBOX:
896 case DFCS_SCROLLDOWN:
897 Symbol = '6';
898 break;
899
900 case DFCS_SCROLLUP:
901 Symbol = '5';
902 break;
903
904 case DFCS_SCROLLLEFT:
905 Symbol = '3';
906 break;
907
908 case DFCS_SCROLLRIGHT:
909 Symbol = '4';
910 break;
911
912 case DFCS_SCROLLSIZEGRIP:
913 case DFCS_SCROLLSIZEGRIPRIGHT:
914 ZeroMemory(&lf, sizeof(LOGFONTW));
915 UITOOLS_MakeSquareRect(r, &myr);
916 lf.lfHeight = myr.bottom - myr.top;
917 lf.lfWidth = 0;
918 lf.lfWeight = FW_NORMAL;
919 lf.lfCharSet = DEFAULT_CHARSET;
920 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
921 hFont = CreateFontIndirect(&lf);
922 /* save font and text color */
923 hOldFont = SelectObject(dc, hFont);
924 clrsave = GetTextColor(dc);
925 bkmode = GetBkMode(dc);
926 /* set color and drawing mode */
927 SetBkMode(dc, TRANSPARENT);
928 if (!(uFlags & (DFCS_MONO | DFCS_FLAT)))
929 {
930 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
931 /* draw selected symbol */
932 Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'o' : 'x';
933 TextOut(dc, myr.left, myr.top, &Symbol, 1);
934 SetTextColor(dc, GetSysColor(COLOR_BTNSHADOW));
935 } else
936 SetTextColor(dc, GetSysColor(COLOR_WINDOWFRAME));
937 /* draw selected symbol */
938 Symbol = ((uFlags & 0xff) == DFCS_SCROLLSIZEGRIP) ? 'p' : 'y';
939 TextOut(dc, myr.left, myr.top, &Symbol, 1);
940 /* restore previous settings */
941 SetTextColor(dc, clrsave);
942 SelectObject(dc, hOldFont);
943 SetBkMode(dc, bkmode);
944 DeleteObject(hFont);
945 return TRUE;
946 default:
947 return FALSE;
948 }
949 IntDrawRectEdge(dc, r, (uFlags & DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT);
950 ZeroMemory(&lf, sizeof(LOGFONTW));
951 UITOOLS_MakeSquareRect(r, &myr);
952 myr.left += 1;
953 myr.top += 1;
954 myr.right -= 1;
955 myr.bottom -= 1;
956 if(uFlags & DFCS_PUSHED)
957 OffsetRect(&myr,1,1);
958 lf.lfHeight = myr.bottom - myr.top;
959 lf.lfWidth = 0;
960 lf.lfWeight = FW_NORMAL;
961 lf.lfCharSet = DEFAULT_CHARSET;
962 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
963 hFont = CreateFontIndirect(&lf);
964 /* save font and text color */
965 hOldFont = SelectObject(dc, hFont);
966 clrsave = GetTextColor(dc);
967 bkmode = GetBkMode(dc);
968 /* set color and drawing mode */
969 SetBkMode(dc, TRANSPARENT);
970 if(uFlags & DFCS_INACTIVE)
971 {
972 /* draw shadow */
973 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
974 TextOut(dc, myr.left + 1, myr.top + 1, &Symbol, 1);
975 }
976 SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
977 /* draw selected symbol */
978 TextOut(dc, myr.left, myr.top, &Symbol, 1);
979 /* restore previous settings */
980 SetTextColor(dc, clrsave);
981 SelectObject(dc, hOldFont);
982 SetBkMode(dc, bkmode);
983 DeleteObject(hFont);
984 return TRUE;
985 }
986
987 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
988 {
989 LOGFONTW lf;
990 HFONT hFont, hOldFont;
991 TCHAR Symbol;
992 switch(uFlags & 0xff)
993 {
994 case DFCS_MENUARROW:
995 Symbol = '8';
996 break;
997
998 case DFCS_MENUARROWRIGHT:
999 Symbol = 'w'; // FIXME: needs to confirm
1000 break;
1001
1002 case DFCS_MENUBULLET:
1003 Symbol = 'h';
1004 break;
1005
1006 case DFCS_MENUCHECK:
1007 Symbol = 'a';
1008 break;
1009
1010 default:
1011 /*
1012 DbgPrint("Invalid menu; flags=0x%04x\n", uFlags);
1013 */
1014 return FALSE;
1015 }
1016 /* acquire ressources only if valid menu */
1017 ZeroMemory(&lf, sizeof(LOGFONTW));
1018 lf.lfHeight = r->bottom - r->top;
1019 lf.lfWidth = 0;
1020 lf.lfWeight = FW_NORMAL;
1021 lf.lfCharSet = DEFAULT_CHARSET;
1022 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
1023 hFont = CreateFontIndirect(&lf);
1024 /* save font */
1025 hOldFont = SelectObject(dc, hFont);
1026 // FIXME selecting color doesn't work
1027 #if 0
1028 if(uFlags & DFCS_INACTIVE)
1029 {
1030 /* draw shadow */
1031 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1032 TextOut(dc, r->left + 1, r->top + 1, &Symbol, 1);
1033 }
1034 SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
1035 #endif
1036 /* draw selected symbol */
1037 TextOut(dc, r->left, r->top, &Symbol, 1);
1038 /* restore previous settings */
1039 SelectObject(dc, hOldFont);
1040 DeleteObject(hFont);
1041 return TRUE;
1042 }
1043
1044 BOOL
1045 WINAPI
1046 IntGrayString(
1047 HDC hDC,
1048 HBRUSH hBrush,
1049 GRAYSTRINGPROC lpOutputFunc,
1050 LPARAM lpData,
1051 int nCount,
1052 int X,
1053 int Y,
1054 int nWidth,
1055 int nHeight,
1056 BOOL unicode)
1057 {
1058 // AG: Mostly implemented, but probably won't work properly or return
1059 // correct error codes. I doubt it grays strings either... Untested!
1060
1061 BOOL success = FALSE;
1062 HDC MemDC = NULL;
1063 HBITMAP MemBMP = NULL,
1064 OldBMP = NULL;
1065 HBRUSH OldBrush = NULL;
1066 HFONT OldFont = NULL;
1067 RECT r;
1068 COLORREF ForeColor, BackColor;
1069
1070 ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
1071 BackColor = SetBkColor(hDC, RGB(255, 255, 255));
1072
1073
1074 if (! hBrush)
1075 {
1076 // The documentation is a little vague on what exactly should happen
1077 // here. Something about using the same brush for window text???
1078 hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
1079 }
1080
1081 if ((nCount == -1) && (! lpOutputFunc))
1082 return FALSE;
1083
1084 if (! nCount)
1085 {
1086 // TODO: calculate the length (easy enough)
1087
1088 if (unicode)
1089 nCount = lstrlenW((WCHAR*)lpData);
1090 else
1091 nCount = lstrlenA((CHAR*)lpData);
1092 }
1093
1094 if (! nWidth || ! nHeight)
1095 {
1096 SIZE s;
1097 // TODO: calculate the rect
1098
1099 if (unicode)
1100 success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
1101 else
1102 success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
1103
1104 if (! success) goto cleanup;
1105
1106 if (! nWidth) nWidth = s.cx;
1107 if (! nHeight) nHeight = s.cy;
1108 }
1109
1110 SetRect(&r, X, Y, X + nWidth, Y + nHeight);
1111
1112 MemDC = CreateCompatibleDC(hDC);
1113 if (! MemDC) goto cleanup;
1114 MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1115 if (! MemBMP) goto cleanup;
1116 OldBMP = SelectObject(MemDC, MemBMP);
1117 if (! OldBMP) goto cleanup;
1118 OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
1119 if (! OldFont) goto cleanup;
1120 OldBrush = SelectObject(MemDC, hBrush);
1121 if (! OldBrush) goto cleanup;
1122
1123 if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
1124
1125 SetTextColor(MemDC, RGB(255, 255, 255));
1126 SetBkColor(MemDC, RGB(0, 0, 0));
1127
1128 if (lpOutputFunc)
1129 {
1130 success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
1131
1132 if ((nCount == -1) && (! success))
1133 {
1134 // Don't gray (documented behaviour)
1135 success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
1136 goto cleanup;
1137 }
1138 }
1139 else
1140 {
1141 if (unicode)
1142 success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
1143 else
1144 success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
1145
1146 if (! success) goto cleanup;
1147
1148 PatBlt(MemDC, 0, 0, nWidth, nHeight, PATCOPY);
1149 // This is how WINE does it: (but we should have our own graying brush already)
1150 // hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1151 // PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
1152 // SelectObject(memdc, hbsave);
1153 }
1154
1155 if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
1156
1157 cleanup:
1158 SetTextColor(hDC, ForeColor);
1159 SetBkColor(hDC, BackColor);
1160
1161 if (MemDC)
1162 {
1163 if (OldFont) SelectObject(MemDC, OldFont);
1164 if (OldBrush) SelectObject(MemDC, OldBrush);
1165 if (OldBMP) SelectObject(MemDC, OldBMP);
1166 if (MemBMP) DeleteObject(MemBMP);
1167 DeleteDC(MemDC);
1168 }
1169
1170 return success;
1171 }
1172
1173 /**********************************************************************
1174 * PAINTING_DrawStateJam
1175 *
1176 * Jams in the requested type in the dc
1177 */
1178 static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
1179 DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1180 LPRECT rc, UINT dtflags, BOOL unicode )
1181 {
1182 HDC memdc;
1183 HBITMAP hbmsave;
1184 BOOL retval;
1185 INT cx = rc->right - rc->left;
1186 INT cy = rc->bottom - rc->top;
1187
1188 switch(opcode)
1189 {
1190 case DST_TEXT:
1191 case DST_PREFIXTEXT:
1192 if(unicode)
1193 return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1194 else
1195 return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1196
1197 case DST_ICON:
1198 return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, cx, cy, 0, NULL, DI_NORMAL);
1199
1200 case DST_BITMAP:
1201 memdc = CreateCompatibleDC(hdc);
1202 if(!memdc)
1203 return FALSE;
1204 hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
1205 if(!hbmsave)
1206 {
1207 DeleteDC(memdc);
1208 return FALSE;
1209 }
1210 retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1211 SelectObject(memdc, hbmsave);
1212 DeleteDC(memdc);
1213 return retval;
1214
1215 case DST_COMPLEX:
1216 if(func)
1217 {
1218 BOOL bRet;
1219 /* DRAWSTATEPROC assumes that it draws at the center of coordinates */
1220
1221 OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1222 bRet = func(hdc, lp, wp, cx, cy);
1223 /* Restore origin */
1224 OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1225 return bRet;
1226 }
1227 else
1228 {
1229 return FALSE;
1230 }
1231 }
1232 return FALSE;
1233 }
1234
1235 static BOOL
1236 IntDrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1237 INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode)
1238 {
1239 HBITMAP hbm, hbmsave;
1240 HFONT hfsave;
1241 HBRUSH hbsave, hbrtmp = 0;
1242 HDC memdc;
1243 RECT rc;
1244 UINT dtflags = DT_NOCLIP;
1245 COLORREF fg, bg;
1246 UINT opcode = flags & 0xf;
1247 INT len = wp;
1248 BOOL retval, tmp;
1249
1250 if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len) /* The string is '\0' terminated */
1251 {
1252 if(unicode)
1253 len = lstrlenW((LPWSTR)lp);
1254 else
1255 len = lstrlenA((LPSTR)lp);
1256 }
1257
1258 /* Find out what size the image has if not given by caller */
1259 if(!cx || !cy)
1260 {
1261 SIZE s;
1262 ICONINFO ici;
1263 BITMAP bm;
1264
1265 switch(opcode)
1266 {
1267 case DST_TEXT:
1268 case DST_PREFIXTEXT:
1269 if(unicode)
1270 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1271 else
1272 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1273 if(!retval)
1274 return FALSE;
1275 break;
1276
1277 case DST_ICON:
1278 if(!GetIconInfo((HICON)lp, &ici))
1279 return FALSE;
1280 if(!GetObjectW(ici.hbmColor, sizeof(bm), &bm))
1281 return FALSE;
1282 s.cx = bm.bmWidth;
1283 s.cy = bm.bmHeight;
1284 break;
1285
1286 case DST_BITMAP:
1287 if(!GetObjectW((HBITMAP)lp, sizeof(bm), &bm))
1288 return FALSE;
1289 s.cx = bm.bmWidth;
1290 s.cy = bm.bmHeight;
1291 break;
1292
1293 case DST_COMPLEX: /* cx and cy must be set in this mode */
1294 return FALSE;
1295 }
1296
1297 if(!cx)
1298 cx = s.cx;
1299 if(!cy)
1300 cy = s.cy;
1301 }
1302
1303 rc.left = x;
1304 rc.top = y;
1305 rc.right = x + cx;
1306 rc.bottom = y + cy;
1307
1308 if(flags & DSS_RIGHT) /* This one is not documented in the win32.hlp file */
1309 dtflags |= DT_RIGHT;
1310 if(opcode == DST_TEXT)
1311 dtflags |= DT_NOPREFIX;
1312 else if(opcode == DST_PREFIXTEXT)
1313 {
1314 if (flags & DSS_HIDEPREFIX)
1315 dtflags |= DT_HIDEPREFIX;
1316 if (flags & DSS_PREFIXONLY)
1317 dtflags |= DT_PREFIXONLY;
1318 }
1319
1320 /* For DSS_NORMAL we just jam in the image and return */
1321 if((flags & 0x79f0) == DSS_NORMAL)
1322 {
1323 return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1324 }
1325
1326 /* For all other states we need to convert the image to B/W in a local bitmap */
1327 /* before it is displayed */
1328 fg = SetTextColor(hdc, RGB(0, 0, 0));
1329 bg = SetBkColor(hdc, RGB(255, 255, 255));
1330 hbm = NULL; hbmsave = NULL;
1331 memdc = NULL; hbsave = NULL;
1332 retval = FALSE; /* assume failure */
1333
1334 /* From here on we must use "goto cleanup" when something goes wrong */
1335 hbm = CreateBitmap(cx, cy, 1, 1, NULL);
1336 if(!hbm)
1337 goto cleanup;
1338 memdc = CreateCompatibleDC(hdc);
1339 if(!memdc)
1340 goto cleanup;
1341 hbmsave = (HBITMAP)SelectObject(memdc, hbm);
1342 if(!hbmsave)
1343 goto cleanup;
1344 rc.left = rc.top = 0;
1345 rc.right = cx;
1346 rc.bottom = cy;
1347 if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH)))
1348 goto cleanup;
1349 SetBkColor(memdc, RGB(255, 255, 255));
1350 SetTextColor(memdc, RGB(0, 0, 0));
1351 hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1352
1353 /* DST_COMPLEX may draw text as well,
1354 * so we must be sure that correct font is selected
1355 */
1356 if(!hfsave && (opcode <= DST_PREFIXTEXT))
1357 goto cleanup;
1358 tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1359 if(hfsave)
1360 SelectObject(memdc, hfsave);
1361 if(!tmp)
1362 goto cleanup;
1363
1364 /* This state cause the image to be dithered */
1365 if(flags & DSS_UNION)
1366 {
1367 #if 0
1368 hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1369 if(!hbsave)
1370 goto cleanup;
1371 tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1372 SelectObject(memdc, hbsave);
1373 if(!tmp)
1374 goto cleanup;
1375 #else
1376 UNIMPLEMENTED;
1377 #endif
1378 }
1379
1380 if (flags & DSS_DISABLED)
1381 hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1382 else if (flags & DSS_DEFAULT)
1383 hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1384
1385 /* Draw light or dark shadow */
1386 if (flags & (DSS_DISABLED|DSS_DEFAULT))
1387 {
1388 if(!hbrtmp)
1389 goto cleanup;
1390 hbsave = (HBRUSH)SelectObject(hdc, hbrtmp);
1391 if(!hbsave)
1392 goto cleanup;
1393 if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A))
1394 goto cleanup;
1395 SelectObject(hdc, hbsave);
1396 DeleteObject(hbrtmp);
1397 hbrtmp = 0;
1398 }
1399
1400 if (flags & DSS_DISABLED)
1401 {
1402 hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1403 if(!hbrtmp)
1404 goto cleanup;
1405 }
1406 else if (!hbr)
1407 {
1408 hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
1409 }
1410
1411 hbsave = (HBRUSH)SelectObject(hdc, hbr);
1412
1413 if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A))
1414 goto cleanup;
1415
1416 retval = TRUE; /* We succeeded */
1417
1418 cleanup:
1419 SetTextColor(hdc, fg);
1420 SetBkColor(hdc, bg);
1421
1422 if(hbsave)
1423 SelectObject(hdc, hbsave);
1424 if(hbmsave)
1425 SelectObject(memdc, hbmsave);
1426 if(hbrtmp)
1427 DeleteObject(hbrtmp);
1428 if(hbm)
1429 DeleteObject(hbm);
1430 if(memdc)
1431 DeleteDC(memdc);
1432
1433 return retval;
1434 }
1435
1436 /*
1437 * @implemented
1438 */
1439 BOOL WINAPI
1440 RealDrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1441 {
1442 if (GetMapMode(hDC) != MM_TEXT)
1443 return FALSE;
1444
1445 switch(uType)
1446 {
1447 case DFC_BUTTON:
1448 return UITOOLS95_DrawFrameButton(hDC, rc, uState);
1449 case DFC_CAPTION:
1450 return UITOOLS95_DrawFrameCaption(hDC, rc, uState);
1451 case DFC_MENU:
1452 return UITOOLS95_DrawFrameMenu(hDC, rc, uState);
1453 #if 0
1454 case DFC_POPUPMENU:
1455 UNIMPLEMENTED;
1456 break;
1457 #endif
1458 case DFC_SCROLL:
1459 return UITOOLS95_DrawFrameScroll(hDC, rc, uState);
1460 }
1461 return FALSE;
1462 }
1463
1464 BOOL WINAPI
1465 DrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1466 {
1467 BOOL Hook, Ret = FALSE;
1468
1469 LOADUSERAPIHOOK
1470
1471 Hook = BeginIfHookedUserApiHook();
1472
1473 /* Bypass SEH and go direct. */
1474 if (!Hook) return RealDrawFrameControl(hDC, rc, uType, uState);
1475
1476 _SEH2_TRY
1477 {
1478 Ret = guah.DrawFrameControl(hDC, rc, uType, uState);
1479 }
1480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1481 {
1482 }
1483 _SEH2_END;
1484
1485 EndUserApiHook();
1486
1487 return Ret;
1488 }
1489
1490 /*
1491 * @implemented
1492 */
1493 BOOL WINAPI
1494 DrawEdge(HDC hDC, LPRECT rc, UINT edge, UINT flags)
1495 {
1496 if (flags & BF_DIAGONAL)
1497 return IntDrawDiagEdge(hDC, rc, edge, flags);
1498 else
1499 return IntDrawRectEdge(hDC, rc, edge, flags);
1500 }
1501
1502 /*
1503 * @implemented
1504 */
1505 BOOL WINAPI
1506 GrayStringA(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1507 int nCount, int X, int Y, int nWidth, int nHeight)
1508 {
1509 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1510 }
1511
1512 /*
1513 * @implemented
1514 */
1515 BOOL WINAPI
1516 GrayStringW(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1517 int nCount, int X, int Y, int nWidth, int nHeight)
1518 {
1519 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1520 }
1521
1522 /*
1523 * @implemented
1524 */
1525 BOOL WINAPI
1526 InvertRect(HDC hDC, CONST RECT *lprc)
1527 {
1528 return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1529 lprc->bottom - lprc->top, DSTINVERT);
1530 }
1531
1532 /*
1533 * @implemented
1534 */
1535 INT WINAPI
1536 FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1537 {
1538 HBRUSH oldbrush;
1539 RECT r = *lprc;
1540
1541 if ((r.right <= r.left) || (r.bottom <= r.top)) return 0;
1542 if (!(oldbrush = SelectObject(hDC, hbr))) return 0;
1543
1544 PatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
1545 PatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
1546 PatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
1547 PatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
1548
1549 SelectObject(hDC, oldbrush);
1550 return TRUE;
1551 }
1552
1553 /*
1554 * @implemented
1555 */
1556 BOOL WINAPI
1557 FlashWindow(HWND hWnd, BOOL bInvert)
1558 {
1559 FLASHWINFO FlashWndInfo;
1560
1561 FlashWndInfo.cbSize = sizeof(FLASHWINFO);
1562 FlashWndInfo.hwnd = hWnd;
1563 FlashWndInfo.dwFlags = !bInvert ? 0 : (FLASHW_TRAY | FLASHW_CAPTION);
1564 FlashWndInfo.uCount = 1;
1565 FlashWndInfo.dwTimeout = 0;
1566
1567 return NtUserFlashWindowEx(&FlashWndInfo);
1568 }
1569
1570 /*
1571 * @implemented
1572 */
1573 INT WINAPI
1574 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1575 {
1576 HBRUSH prevhbr;
1577
1578 if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1))
1579 {
1580 hbr = GetSysColorBrush(PtrToUlong(hbr) - 1);
1581 }
1582 if ((prevhbr = SelectObject(hDC, hbr)) == NULL)
1583 {
1584 return FALSE;
1585 }
1586 PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1587 lprc->bottom - lprc->top, PATCOPY);
1588 SelectObject(hDC, prevhbr);
1589 return TRUE;
1590 }
1591
1592 /*
1593 * @implemented
1594 */
1595 BOOL WINAPI
1596 DrawFocusRect(HDC hdc, CONST RECT *rect)
1597 {
1598 static HBRUSH hFocusRectBrush = NULL;
1599 HGDIOBJ OldObj;
1600 UINT cx, cy;
1601
1602 if(!hFocusRectBrush)
1603 {
1604 static HBITMAP hFocusPattern = NULL;
1605 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
1606
1607 hFocusPattern = CreateBitmap(8, 8, 1, 1, Pattern);
1608 hFocusRectBrush = CreatePatternBrush(hFocusPattern);
1609 }
1610
1611 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &cx, 0);
1612 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &cy, 0);
1613
1614 OldObj = SelectObject(hdc, hFocusRectBrush);
1615
1616 /* top */
1617 PatBlt(hdc, rect->left, rect->top, rect->right - rect->left, cy, PATINVERT);
1618 /* bottom */
1619 PatBlt(hdc, rect->left, rect->bottom - cy, rect->right - rect->left, cy, PATINVERT);
1620 /* left */
1621 PatBlt(hdc, rect->left, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1622 /* right */
1623 PatBlt(hdc, rect->right - cx, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1624
1625 SelectObject(hdc, OldObj);
1626 return TRUE;
1627 }
1628
1629 /*
1630 * @implemented
1631 */
1632 BOOL WINAPI
1633 DrawStateA(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1634 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1635 {
1636 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
1637 }
1638
1639 /*
1640 * @implemented
1641 */
1642 BOOL WINAPI
1643 DrawStateW(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1644 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1645 {
1646 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
1647 }