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