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