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