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