- continue "marletting"
[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 LOGFONT 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(LOGFONT));
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 LOGFONT 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(LOGFONT));
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 LOGFONT 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(LOGFONT));
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(LOGFONT));
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 LOGFONT 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(LOGFONT));
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 if(uFlags & DFCS_INACTIVE)
1027 {
1028 /* draw shadow */
1029 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
1030 TextOut(dc, r->left + 1, r->top + 1, &Symbol, 1);
1031 }
1032 SetTextColor(dc, GetSysColor((uFlags & DFCS_INACTIVE) ? COLOR_BTNSHADOW : COLOR_BTNTEXT));
1033 /* draw selected symbol */
1034 TextOut(dc, r->left, r->top, &Symbol, 1);
1035 /* restore previous settings */
1036 SelectObject(dc, hOldFont);
1037 DeleteObject(hFont);
1038 return TRUE;
1039 }
1040
1041 BOOL
1042 WINAPI
1043 IntGrayString(
1044 HDC hDC,
1045 HBRUSH hBrush,
1046 GRAYSTRINGPROC lpOutputFunc,
1047 LPARAM lpData,
1048 int nCount,
1049 int X,
1050 int Y,
1051 int nWidth,
1052 int nHeight,
1053 BOOL unicode)
1054 {
1055 // AG: Mostly implemented, but probably won't work properly or return
1056 // correct error codes. I doubt it grays strings either... Untested!
1057
1058 BOOL success = FALSE;
1059 HDC MemDC = NULL;
1060 HBITMAP MemBMP = NULL,
1061 OldBMP = NULL;
1062 HBRUSH OldBrush = NULL;
1063 HFONT OldFont = NULL;
1064 RECT r;
1065 COLORREF ForeColor, BackColor;
1066
1067 ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
1068 BackColor = SetBkColor(hDC, RGB(255, 255, 255));
1069
1070
1071 if (! hBrush)
1072 {
1073 // The documentation is a little vague on what exactly should happen
1074 // here. Something about using the same brush for window text???
1075 hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
1076 }
1077
1078 if ((nCount == -1) && (! lpOutputFunc))
1079 return FALSE;
1080
1081 if (! nCount)
1082 {
1083 // TODO: calculate the length (easy enough)
1084
1085 if (unicode)
1086 nCount = lstrlenW((WCHAR*)lpData);
1087 else
1088 nCount = lstrlenA((CHAR*)lpData);
1089 }
1090
1091 if (! nWidth || ! nHeight)
1092 {
1093 SIZE s;
1094 // TODO: calculate the rect
1095
1096 if (unicode)
1097 success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
1098 else
1099 success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
1100
1101 if (! success) goto cleanup;
1102
1103 if (! nWidth) nWidth = s.cx;
1104 if (! nHeight) nHeight = s.cy;
1105 }
1106
1107 SetRect(&r, X, Y, X + nWidth, Y + nHeight);
1108
1109 MemDC = CreateCompatibleDC(hDC);
1110 if (! MemDC) goto cleanup;
1111 MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1112 if (! MemBMP) goto cleanup;
1113 OldBMP = SelectObject(MemDC, MemBMP);
1114 if (! OldBMP) goto cleanup;
1115 OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
1116 if (! OldFont) goto cleanup;
1117 OldBrush = SelectObject(MemDC, hBrush);
1118 if (! OldBrush) goto cleanup;
1119
1120 if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
1121
1122 SetTextColor(MemDC, RGB(255, 255, 255));
1123 SetBkColor(MemDC, RGB(0, 0, 0));
1124
1125 if (lpOutputFunc)
1126 {
1127 success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
1128
1129 if ((nCount == -1) && (! success))
1130 {
1131 // Don't gray (documented behaviour)
1132 success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
1133 goto cleanup;
1134 }
1135 }
1136 else
1137 {
1138 if (unicode)
1139 success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
1140 else
1141 success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
1142
1143 if (! success) goto cleanup;
1144
1145 PatBlt(MemDC, 0, 0, nWidth, nHeight, PATCOPY);
1146 // This is how WINE does it: (but we should have our own graying brush already)
1147 // hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1148 // PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
1149 // SelectObject(memdc, hbsave);
1150 }
1151
1152 if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
1153
1154 cleanup:
1155 SetTextColor(hDC, ForeColor);
1156 SetBkColor(hDC, BackColor);
1157
1158 if (MemDC)
1159 {
1160 if (OldFont) SelectObject(MemDC, OldFont);
1161 if (OldBrush) SelectObject(MemDC, OldBrush);
1162 if (OldBMP) SelectObject(MemDC, OldBMP);
1163 if (MemBMP) DeleteObject(MemBMP);
1164 DeleteDC(MemDC);
1165 }
1166
1167 return success;
1168 }
1169
1170 /**********************************************************************
1171 * PAINTING_DrawStateJam
1172 *
1173 * Jams in the requested type in the dc
1174 */
1175 static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
1176 DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1177 LPRECT rc, UINT dtflags, BOOL unicode )
1178 {
1179 HDC memdc;
1180 HBITMAP hbmsave;
1181 BOOL retval;
1182 INT cx = rc->right - rc->left;
1183 INT cy = rc->bottom - rc->top;
1184
1185 switch(opcode)
1186 {
1187 case DST_TEXT:
1188 case DST_PREFIXTEXT:
1189 if(unicode)
1190 return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1191 else
1192 return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1193
1194 case DST_ICON:
1195 return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, cx, cy, 0, NULL, DI_NORMAL);
1196
1197 case DST_BITMAP:
1198 memdc = CreateCompatibleDC(hdc);
1199 if(!memdc)
1200 return FALSE;
1201 hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
1202 if(!hbmsave)
1203 {
1204 DeleteDC(memdc);
1205 return FALSE;
1206 }
1207 retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1208 SelectObject(memdc, hbmsave);
1209 DeleteDC(memdc);
1210 return retval;
1211
1212 case DST_COMPLEX:
1213 if(func)
1214 {
1215 BOOL bRet;
1216 /* DRAWSTATEPROC assumes that it draws at the center of coordinates */
1217
1218 OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1219 bRet = func(hdc, lp, wp, cx, cy);
1220 /* Restore origin */
1221 OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1222 return bRet;
1223 }
1224 else
1225 {
1226 return FALSE;
1227 }
1228 }
1229 return FALSE;
1230 }
1231
1232 static BOOL
1233 IntDrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1234 INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode)
1235 {
1236 HBITMAP hbm, hbmsave;
1237 HFONT hfsave;
1238 HBRUSH hbsave, hbrtmp = 0;
1239 HDC memdc;
1240 RECT rc;
1241 UINT dtflags = DT_NOCLIP;
1242 COLORREF fg, bg;
1243 UINT opcode = flags & 0xf;
1244 INT len = wp;
1245 BOOL retval, tmp;
1246
1247 if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len) /* The string is '\0' terminated */
1248 {
1249 if(unicode)
1250 len = lstrlenW((LPWSTR)lp);
1251 else
1252 len = lstrlenA((LPSTR)lp);
1253 }
1254
1255 /* Find out what size the image has if not given by caller */
1256 if(!cx || !cy)
1257 {
1258 SIZE s;
1259 ICONINFO ici;
1260 BITMAP bm;
1261
1262 switch(opcode)
1263 {
1264 case DST_TEXT:
1265 case DST_PREFIXTEXT:
1266 if(unicode)
1267 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1268 else
1269 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1270 if(!retval)
1271 return FALSE;
1272 break;
1273
1274 case DST_ICON:
1275 if(!GetIconInfo((HICON)lp, &ici))
1276 return FALSE;
1277 if(!GetObjectW(ici.hbmColor, sizeof(bm), &bm))
1278 return FALSE;
1279 s.cx = bm.bmWidth;
1280 s.cy = bm.bmHeight;
1281 break;
1282
1283 case DST_BITMAP:
1284 if(!GetObjectW((HBITMAP)lp, sizeof(bm), &bm))
1285 return FALSE;
1286 s.cx = bm.bmWidth;
1287 s.cy = bm.bmHeight;
1288 break;
1289
1290 case DST_COMPLEX: /* cx and cy must be set in this mode */
1291 return FALSE;
1292 }
1293
1294 if(!cx)
1295 cx = s.cx;
1296 if(!cy)
1297 cy = s.cy;
1298 }
1299
1300 rc.left = x;
1301 rc.top = y;
1302 rc.right = x + cx;
1303 rc.bottom = y + cy;
1304
1305 if(flags & DSS_RIGHT) /* This one is not documented in the win32.hlp file */
1306 dtflags |= DT_RIGHT;
1307 if(opcode == DST_TEXT)
1308 dtflags |= DT_NOPREFIX;
1309 else if(opcode == DST_PREFIXTEXT)
1310 {
1311 if (flags & DSS_HIDEPREFIX)
1312 dtflags |= DT_HIDEPREFIX;
1313 if (flags & DSS_PREFIXONLY)
1314 dtflags |= DT_PREFIXONLY;
1315 }
1316
1317 /* For DSS_NORMAL we just jam in the image and return */
1318 if((flags & 0x79f0) == DSS_NORMAL)
1319 {
1320 return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1321 }
1322
1323 /* For all other states we need to convert the image to B/W in a local bitmap */
1324 /* before it is displayed */
1325 fg = SetTextColor(hdc, RGB(0, 0, 0));
1326 bg = SetBkColor(hdc, RGB(255, 255, 255));
1327 hbm = NULL; hbmsave = NULL;
1328 memdc = NULL; hbsave = NULL;
1329 retval = FALSE; /* assume failure */
1330
1331 /* From here on we must use "goto cleanup" when something goes wrong */
1332 hbm = CreateBitmap(cx, cy, 1, 1, NULL);
1333 if(!hbm)
1334 goto cleanup;
1335 memdc = CreateCompatibleDC(hdc);
1336 if(!memdc)
1337 goto cleanup;
1338 hbmsave = (HBITMAP)SelectObject(memdc, hbm);
1339 if(!hbmsave)
1340 goto cleanup;
1341 rc.left = rc.top = 0;
1342 rc.right = cx;
1343 rc.bottom = cy;
1344 if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH)))
1345 goto cleanup;
1346 SetBkColor(memdc, RGB(255, 255, 255));
1347 SetTextColor(memdc, RGB(0, 0, 0));
1348 hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1349
1350 /* DST_COMPLEX may draw text as well,
1351 * so we must be sure that correct font is selected
1352 */
1353 if(!hfsave && (opcode <= DST_PREFIXTEXT))
1354 goto cleanup;
1355 tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1356 if(hfsave)
1357 SelectObject(memdc, hfsave);
1358 if(!tmp)
1359 goto cleanup;
1360
1361 /* This state cause the image to be dithered */
1362 if(flags & DSS_UNION)
1363 {
1364 #if 0
1365 hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1366 if(!hbsave)
1367 goto cleanup;
1368 tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1369 SelectObject(memdc, hbsave);
1370 if(!tmp)
1371 goto cleanup;
1372 #else
1373 UNIMPLEMENTED;
1374 #endif
1375 }
1376
1377 if (flags & DSS_DISABLED)
1378 hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1379 else if (flags & DSS_DEFAULT)
1380 hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1381
1382 /* Draw light or dark shadow */
1383 if (flags & (DSS_DISABLED|DSS_DEFAULT))
1384 {
1385 if(!hbrtmp)
1386 goto cleanup;
1387 hbsave = (HBRUSH)SelectObject(hdc, hbrtmp);
1388 if(!hbsave)
1389 goto cleanup;
1390 if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A))
1391 goto cleanup;
1392 SelectObject(hdc, hbsave);
1393 DeleteObject(hbrtmp);
1394 hbrtmp = 0;
1395 }
1396
1397 if (flags & DSS_DISABLED)
1398 {
1399 hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1400 if(!hbrtmp)
1401 goto cleanup;
1402 }
1403 else if (!hbr)
1404 {
1405 hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
1406 }
1407
1408 hbsave = (HBRUSH)SelectObject(hdc, hbr);
1409
1410 if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A))
1411 goto cleanup;
1412
1413 retval = TRUE; /* We succeeded */
1414
1415 cleanup:
1416 SetTextColor(hdc, fg);
1417 SetBkColor(hdc, bg);
1418
1419 if(hbsave)
1420 SelectObject(hdc, hbsave);
1421 if(hbmsave)
1422 SelectObject(memdc, hbmsave);
1423 if(hbrtmp)
1424 DeleteObject(hbrtmp);
1425 if(hbm)
1426 DeleteObject(hbm);
1427 if(memdc)
1428 DeleteDC(memdc);
1429
1430 return retval;
1431 }
1432
1433 /*
1434 * @implemented
1435 */
1436 BOOL WINAPI
1437 DrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1438 {
1439 if (GetMapMode(hDC) != MM_TEXT)
1440 return FALSE;
1441
1442 switch(uType)
1443 {
1444 case DFC_BUTTON:
1445 return UITOOLS95_DrawFrameButton(hDC, rc, uState);
1446 case DFC_CAPTION:
1447 return UITOOLS95_DrawFrameCaption(hDC, rc, uState);
1448 case DFC_MENU:
1449 return UITOOLS95_DrawFrameMenu(hDC, rc, uState);
1450 #if 0
1451 case DFC_POPUPMENU:
1452 UNIMPLEMENTED;
1453 break;
1454 #endif
1455 case DFC_SCROLL:
1456 return UITOOLS95_DrawFrameScroll(hDC, rc, uState);
1457 }
1458 return FALSE;
1459 }
1460
1461 /*
1462 * @implemented
1463 */
1464 BOOL WINAPI
1465 DrawEdge(HDC hDC, LPRECT rc, UINT edge, UINT flags)
1466 {
1467 if (flags & BF_DIAGONAL)
1468 return IntDrawDiagEdge(hDC, rc, edge, flags);
1469 else
1470 return IntDrawRectEdge(hDC, rc, edge, flags);
1471 }
1472
1473 /*
1474 * @implemented
1475 */
1476 BOOL WINAPI
1477 GrayStringA(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1478 int nCount, int X, int Y, int nWidth, int nHeight)
1479 {
1480 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1481 }
1482
1483 /*
1484 * @implemented
1485 */
1486 BOOL WINAPI
1487 GrayStringW(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1488 int nCount, int X, int Y, int nWidth, int nHeight)
1489 {
1490 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1491 }
1492
1493 /*
1494 * @implemented
1495 */
1496 BOOL WINAPI
1497 InvertRect(HDC hDC, CONST RECT *lprc)
1498 {
1499 return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1500 lprc->bottom - lprc->top, DSTINVERT);
1501 }
1502
1503 /*
1504 * @implemented
1505 */
1506 INT WINAPI
1507 FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1508 {
1509 HBRUSH oldbrush;
1510 RECT r = *lprc;
1511
1512 if ((r.right <= r.left) || (r.bottom <= r.top)) return 0;
1513 if (!(oldbrush = SelectObject(hDC, hbr))) return 0;
1514
1515 PatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
1516 PatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
1517 PatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
1518 PatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
1519
1520 SelectObject(hDC, oldbrush);
1521 return TRUE;
1522 }
1523
1524 /*
1525 * @implemented
1526 */
1527 BOOL WINAPI
1528 FlashWindow(HWND hWnd, BOOL bInvert)
1529 {
1530 FLASHWINFO FlashWndInfo;
1531
1532 FlashWndInfo.cbSize = sizeof(FLASHWINFO);
1533 FlashWndInfo.hwnd = hWnd;
1534 FlashWndInfo.dwFlags = !bInvert ? 0 : (FLASHW_TRAY | FLASHW_CAPTION);
1535 FlashWndInfo.uCount = 1;
1536 FlashWndInfo.dwTimeout = 0;
1537
1538 return NtUserFlashWindowEx(&FlashWndInfo);
1539 }
1540
1541 /*
1542 * @implemented
1543 */
1544 INT WINAPI
1545 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1546 {
1547 HBRUSH prevhbr;
1548
1549 if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1))
1550 {
1551 hbr = GetSysColorBrush((int)hbr - 1);
1552 }
1553 if ((prevhbr = SelectObject(hDC, hbr)) == NULL)
1554 {
1555 return FALSE;
1556 }
1557 PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1558 lprc->bottom - lprc->top, PATCOPY);
1559 SelectObject(hDC, prevhbr);
1560 return TRUE;
1561 }
1562
1563 /*
1564 * @implemented
1565 */
1566 BOOL WINAPI
1567 DrawFocusRect(HDC hdc, CONST RECT *rect)
1568 {
1569 static HBRUSH hFocusRectBrush = NULL;
1570 HGDIOBJ OldObj;
1571 UINT cx, cy;
1572
1573 if(!hFocusRectBrush)
1574 {
1575 static HBITMAP hFocusPattern = NULL;
1576 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
1577
1578 hFocusPattern = CreateBitmap(8, 8, 1, 1, Pattern);
1579 hFocusRectBrush = CreatePatternBrush(hFocusPattern);
1580 }
1581
1582 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &cx, 0);
1583 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &cy, 0);
1584
1585 OldObj = SelectObject(hdc, hFocusRectBrush);
1586
1587 /* top */
1588 PatBlt(hdc, rect->left, rect->top, rect->right - rect->left, cy, PATINVERT);
1589 /* bottom */
1590 PatBlt(hdc, rect->left, rect->bottom - cy, rect->right - rect->left, cy, PATINVERT);
1591 /* left */
1592 PatBlt(hdc, rect->left, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1593 /* right */
1594 PatBlt(hdc, rect->right - cx, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1595
1596 SelectObject(hdc, OldObj);
1597 return TRUE;
1598 }
1599
1600 /*
1601 * @implemented
1602 */
1603 BOOL WINAPI
1604 DrawStateA(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1605 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1606 {
1607 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
1608 }
1609
1610 /*
1611 * @implemented
1612 */
1613 BOOL WINAPI
1614 DrawStateW(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1615 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1616 {
1617 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
1618 }