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