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