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