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