- Silence some debug messages
[reactos.git] / reactos / lib / 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 #define NDEBUG
33 #include <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 /* Ported from WINE20020904 */
721 /* Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
722 *
723 * Does a pretty good job in emulating MS behavior. Some quirks are
724 * however there because MS uses a TrueType font (Marlett) to draw
725 * the buttons.
726 */
727 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
728 {
729 RECT myr;
730 int i;
731 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
732 int BorderShrink = SmallDiam / 16;
733 HPEN hpsave;
734 HBRUSH hbsave;
735 int xc, yc;
736
737 if(BorderShrink < 1) BorderShrink = 1;
738
739 if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
740 {
741 FillRect(dc, r, (HBRUSH)GetStockObject(BLACK_BRUSH));
742 }
743
744 xc = myr.left + SmallDiam - SmallDiam/2;
745 yc = myr.top + SmallDiam - SmallDiam/2;
746
747 /* Define bounding box */
748 i = 14*SmallDiam/16;
749 myr.left = xc - i+i/2;
750 myr.right = xc + i/2;
751 myr.top = yc - i+i/2;
752 myr.bottom = yc + i/2;
753
754 if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
755 {
756 hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
757 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
758 SelectObject(dc, hbsave);
759 }
760 else
761 {
762 if(uFlags & (DFCS_FLAT|DFCS_MONO))
763 {
764 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_WINDOWFRAME));
765 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
766 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
767 SelectObject(dc, hbsave);
768 SelectObject(dc, hpsave);
769 }
770 else
771 {
772 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
773 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
774 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
775
776 SelectObject(dc, GetSysColorPen(COLOR_BTNSHADOW));
777 SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
778 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
779
780 myr.left += BorderShrink;
781 myr.right -= BorderShrink;
782 myr.top += BorderShrink;
783 myr.bottom -= BorderShrink;
784
785 SelectObject(dc, GetSysColorPen(COLOR_3DLIGHT));
786 SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
787 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
788
789 SelectObject(dc, GetSysColorPen(COLOR_3DDKSHADOW));
790 SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
791 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
792 SelectObject(dc, hbsave);
793 SelectObject(dc, hpsave);
794 }
795
796 i = 10*SmallDiam/16;
797 myr.left = xc - i+i/2;
798 myr.right = xc + i/2;
799 myr.top = yc - i+i/2;
800 myr.bottom = yc + i/2;
801 i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
802 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
803 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
804 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
805 SelectObject(dc, hbsave);
806 SelectObject(dc, hpsave);
807 }
808
809 if(uFlags & DFCS_CHECKED)
810 {
811 i = 6*SmallDiam/16;
812 i = i < 1 ? 1 : i;
813 myr.left = xc - i+i/2;
814 myr.right = xc + i/2;
815 myr.top = yc - i+i/2;
816 myr.bottom = yc + i/2;
817
818 i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
819 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
820 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
821 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
822 SelectObject(dc, hpsave);
823 SelectObject(dc, hbsave);
824 }
825
826 /* FIXME: M$ has a Polygon in the center at relative points: */
827 /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
828 /* 0.476, 0.525 */
829 /* 0.500, 0.500 */
830 /* 0.500, 0.499 */
831 /* when the button is unchecked. The reason for it is unknown. The */
832 /* color is COLOR_BTNHIGHLIGHT, although the Polygon gets painted at */
833 /* least 3 times (it looks like a clip-region when you see it happen). */
834 /* I do not really see a reason why this should be implemented. If you */
835 /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
836 /* font. */
837
838 return TRUE;
839 }
840
841 /* Ported from WINE20020904 */
842 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
843 {
844 switch(uState & 0xff)
845 {
846 case DFCS_BUTTONPUSH:
847 return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
848
849 case DFCS_BUTTONCHECK:
850 case DFCS_BUTTON3STATE:
851 return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
852
853 case DFCS_BUTTONRADIOIMAGE:
854 case DFCS_BUTTONRADIOMASK:
855 case DFCS_BUTTONRADIO:
856 return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
857
858 /*
859 default:
860 DbgPrint("Invalid button state=0x%04x\n", uState);
861 */
862 }
863
864 return FALSE;
865 }
866
867 /* Ported from WINE20020904 */
868 /* Draw caption buttons (win95), coming from DrawFrameControl() */
869 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
870 {
871 POINT Line1[10];
872 POINT Line2[10];
873 int Line1N;
874 int Line2N;
875 RECT myr;
876 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
877 int i;
878 HBRUSH hbsave;
879 HPEN hpsave;
880 HFONT hfsave, hf;
881 int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
882 int xc = (myr.left+myr.right)/2;
883 int yc = (myr.top+myr.bottom)/2;
884 int edge, move;
885 char str[2] = "?";
886 UINT alignsave;
887 int bksave;
888 COLORREF clrsave;
889 SIZE size;
890
891 if(uFlags & DFCS_PUSHED)
892 IntDrawRectEdge(dc,r,EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_SOFT);
893 else
894 IntDrawRectEdge(dc,r,BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RECT |
895 BF_SOFT | BF_MIDDLE);
896
897 switch(uFlags & 0xff)
898 {
899 case DFCS_CAPTIONCLOSE:
900 {
901 /* The "X" is made by drawing a series of lines.
902 * The number of lines drawn depends on the size
903 * of the bounding rect. e.g. For a 6x5 inside rect,
904 * two lines are drawn from top-left to bottom-right,
905 * and two lines from top-right to bottom-left.
906 *
907 * 0 1 2 3 4 5 0 1 2 3 4 5
908 * 1 * * * *
909 * 2 * * * *
910 * 3 * * * *
911 * 4 * * * *
912 *
913 * Drawing one line for every 6 pixels in width
914 * seems to provide the best proportions.
915 */
916
917 POINT start, oldPos;
918 INT width = myr.right - (++myr.left) - 5;
919 INT height = (--myr.bottom) - myr.top - 6;
920 INT numLines = (width / 6) + 1;
921
922 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
923
924 start.x = myr.left + 2;
925 start.y = myr.top + 2;
926
927 if (width < 6)
928 height = width;
929 else
930 start.y++;
931
932 if (uFlags & DFCS_PUSHED)
933 {
934 start.x++;
935 start.y++;
936 }
937
938 /* now use the width of each line */
939 width -= numLines - 1;
940
941 for (i = 0; i < numLines; i++)
942 {
943 MoveToEx(dc, start.x + i, start.y, &oldPos);
944 LineTo(dc, start.x + i + width, start.y + height);
945
946 MoveToEx(dc, start.x + i, start.y + height - 1, &oldPos);
947 LineTo(dc, start.x + i + width, start.y - 1);
948 }
949
950 SelectObject(dc, hpsave);
951 return TRUE;
952 }
953
954 case DFCS_CAPTIONHELP:
955 /* This one breaks the flow */
956 /* FIXME: We need the Marlett font in order to get this right. */
957
958 hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
959 ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
960 DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
961 alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
962 bksave = SetBkMode(dc, TRANSPARENT);
963 clrsave = GetTextColor(dc);
964 hfsave = (HFONT)SelectObject(dc, hf);
965 GetTextExtentPoint32A(dc, str, 1, &size);
966
967 if(uFlags & DFCS_INACTIVE)
968 {
969 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
970 TextOutA(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
971 }
972 SetTextColor(dc, GetSysColor(colorIdx));
973 TextOutA(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
974
975 SelectObject(dc, hfsave);
976 SetTextColor(dc, clrsave);
977 SetBkMode(dc, bksave);
978 SetTextAlign(dc, alignsave);
979 DeleteObject(hf);
980 return TRUE;
981
982 case DFCS_CAPTIONMIN:
983 /*
984 * If the button goes from x 0 -- w-1, the leftmost point of the
985 * minimize line always starts at x>=4.
986 */
987 {
988 const int width = myr.right - myr.left;
989 const int xInsetPixels = (width>=9 ? width - 9 : 0) / 8 + 4;
990 Line1[0].x = Line1[3].x = myr.left + xInsetPixels;
991 Line1[1].x = Line1[2].x = Line1[0].x + 372*SmallDiam/750;
992 Line1[0].y = Line1[1].y = myr.top + 563*SmallDiam/750+1;
993 Line1[2].y = Line1[3].y = Line1[0].y + 92*SmallDiam/750;
994 Line1N = 4;
995 Line2N = 0;
996 }
997 break;
998
999 case DFCS_CAPTIONMAX:
1000 edge = 47*SmallDiam/750;
1001 Line1[0].x = Line1[5].x = myr.left + 57*SmallDiam/750+3;
1002 Line1[0].y = Line1[1].y = myr.top + 143*SmallDiam/750+1;
1003 Line1[1].x = Line1[2].x = Line1[0].x + 562*SmallDiam/750;
1004 Line1[5].y = Line1[4].y = Line1[0].y + 93*SmallDiam/750;
1005 Line1[2].y = Line1[3].y = Line1[0].y + 513*SmallDiam/750;
1006 Line1[3].x = Line1[4].x = Line1[1].x - edge;
1007
1008 Line2[0].x = Line2[5].x = Line1[0].x;
1009 Line2[3].x = Line2[4].x = Line1[1].x;
1010 Line2[1].x = Line2[2].x = Line1[0].x + edge;
1011 Line2[0].y = Line2[1].y = Line1[0].y;
1012 Line2[4].y = Line2[5].y = Line1[2].y;
1013 Line2[2].y = Line2[3].y = Line1[2].y - edge;
1014 Line1N = 6;
1015 Line2N = 6;
1016 break;
1017
1018 case DFCS_CAPTIONRESTORE:
1019 /* FIXME: this one looks bad at small sizes < 15x15 :( */
1020 edge = 47*SmallDiam/750;
1021 move = 420*SmallDiam/750;
1022 Line1[0].x = Line1[9].x = myr.left + 198*SmallDiam/750+2;
1023 Line1[0].y = Line1[1].y = myr.top + 169*SmallDiam/750+1;
1024 Line1[6].y = Line1[7].y = Line1[0].y + 93*SmallDiam/750;
1025 Line1[7].x = Line1[8].x = Line1[0].x + edge;
1026 Line1[1].x = Line1[2].x = Line1[0].x + move;
1027 Line1[5].x = Line1[6].x = Line1[1].x - edge;
1028 Line1[9].y = Line1[8].y = Line1[0].y + 187*SmallDiam/750;
1029 Line1[2].y = Line1[3].y = Line1[0].y + 327*SmallDiam/750;
1030 Line1[4].y = Line1[5].y = Line1[2].y - edge;
1031 Line1[3].x = Line1[4].x = Line1[2].x - 140*SmallDiam/750;
1032
1033 Line2[1].x = Line2[2].x = Line1[3].x;
1034 Line2[7].x = Line2[8].x = Line2[1].x - edge;
1035 Line2[0].x = Line2[9].x = Line2[3].x = Line2[4].x = Line2[1].x - move;
1036 Line2[5].x = Line2[6].x = Line2[0].x + edge;
1037 Line2[0].y = Line2[1].y = Line1[9].y + 93*SmallDiam/750;
1038 Line2[4].y = Line2[5].y = Line2[8].y = Line2[9].y = Line2[0].y + 93*SmallDiam/750;
1039 Line2[2].y = Line2[3].y = Line2[0].y + 327*SmallDiam/750;
1040 Line2[6].y = Line2[7].y = Line2[2].y - edge;
1041 Line1N = 10;
1042 Line2N = 10;
1043 break;
1044
1045 default:
1046 return FALSE;
1047 }
1048
1049 /* Here the drawing takes place */
1050 if(uFlags & DFCS_INACTIVE)
1051 {
1052 /* If we have an inactive button, then you see a shadow */
1053 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1054 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1055 Polygon(dc, Line1, Line1N);
1056 if(Line2N > 0)
1057 Polygon(dc, Line2, Line2N);
1058 SelectObject(dc, hpsave);
1059 SelectObject(dc, hbsave);
1060 }
1061
1062 /* Correct for the shadow shift */
1063 if (!(uFlags & DFCS_PUSHED))
1064 {
1065 for(i = 0; i < Line1N; i++)
1066 {
1067 Line1[i].x--;
1068 Line1[i].y--;
1069 }
1070 for(i = 0; i < Line2N; i++)
1071 {
1072 Line2[i].x--;
1073 Line2[i].y--;
1074 }
1075 }
1076
1077 /* Make the final picture */
1078 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(colorIdx));
1079 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
1080
1081 Polygon(dc, Line1, Line1N);
1082 if(Line2N > 0)
1083 Polygon(dc, Line2, Line2N);
1084 SelectObject(dc, hpsave);
1085 SelectObject(dc, hbsave);
1086
1087 return TRUE;
1088 }
1089
1090 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
1091 {
1092 POINT Line[4];
1093 RECT myr;
1094 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
1095 int i;
1096 HBRUSH hbsave, hb, hb2;
1097 HPEN hpsave, hp, hp2;
1098 int tri = 290*SmallDiam/1000 - 1;
1099 int d46, d93;
1100
1101 /*
1102 * This fixes a problem with really tiny "scroll" buttons. In particular
1103 * with the updown control.
1104 * Making sure that the arrow is as least 3 pixels wide (or high).
1105 */
1106 if (tri == 0)
1107 tri = 1;
1108
1109 switch(uFlags & 0xff)
1110 {
1111 case DFCS_SCROLLCOMBOBOX:
1112 case DFCS_SCROLLDOWN:
1113 Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1114 Line[2].y = myr.top + 687*SmallDiam/1000 + 1;
1115 Line[0].x = Line[2].x - tri;
1116 Line[1].x = Line[2].x + tri;
1117 Line[0].y = Line[1].y = Line[2].y - tri;
1118 break;
1119
1120 case DFCS_SCROLLUP:
1121 Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1122 Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1123 Line[0].x = Line[2].x - tri;
1124 Line[1].x = Line[2].x + tri;
1125 Line[0].y = Line[1].y = Line[2].y + tri;
1126 break;
1127
1128 case DFCS_SCROLLLEFT:
1129 Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1130 Line[2].y = myr.top + 470*SmallDiam/1000 + 2;
1131 Line[0].y = Line[2].y - tri;
1132 Line[1].y = Line[2].y + tri;
1133 Line[0].x = Line[1].x = Line[2].x + tri;
1134 break;
1135
1136 case DFCS_SCROLLRIGHT:
1137 Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1138 Line[2].y = myr.top + 470*SmallDiam/1000 + 2;
1139 Line[0].y = Line[2].y - tri;
1140 Line[1].y = Line[2].y + tri;
1141 Line[0].x = Line[1].x = Line[2].x - tri;
1142 break;
1143
1144 case DFCS_SCROLLSIZEGRIP:
1145 /* This one breaks the flow... */
1146 IntDrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1147 hpsave = (HPEN)SelectObject(dc, GetStockObject(NULL_PEN));
1148 hbsave = (HBRUSH)SelectObject(dc, GetStockObject(NULL_BRUSH));
1149 if(uFlags & (DFCS_MONO|DFCS_FLAT))
1150 {
1151 hp = hp2 = GetSysColorPen(COLOR_WINDOWFRAME);
1152 hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1153 }
1154 else
1155 {
1156 hp = GetSysColorPen(COLOR_BTNHIGHLIGHT);
1157 hp2 = GetSysColorPen(COLOR_BTNSHADOW);
1158 hb = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1159 hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1160 }
1161 Line[0].x = Line[1].x = r->right-1;
1162 Line[2].y = Line[3].y = r->bottom-1;
1163 d46 = 46*SmallDiam/750;
1164 d93 = 93*SmallDiam/750;
1165
1166 i = 586*SmallDiam/750;
1167 Line[0].y = r->bottom - i - 1;
1168 Line[3].x = r->right - i - 1;
1169 Line[1].y = Line[0].y + d46;
1170 Line[2].x = Line[3].x + d46;
1171 SelectObject(dc, hb);
1172 SelectObject(dc, hp);
1173 Polygon(dc, Line, 4);
1174
1175 Line[1].y++; Line[2].x++;
1176 Line[0].y = Line[1].y + d93;
1177 Line[3].x = Line[2].x + d93;
1178 SelectObject(dc, hb2);
1179 SelectObject(dc, hp2);
1180 Polygon(dc, Line, 4);
1181
1182 i = 398*SmallDiam/750;
1183 Line[0].y = r->bottom - i - 1;
1184 Line[3].x = r->right - i - 1;
1185 Line[1].y = Line[0].y + d46;
1186 Line[2].x = Line[3].x + d46;
1187 SelectObject(dc, hb);
1188 SelectObject(dc, hp);
1189 Polygon(dc, Line, 4);
1190
1191 Line[1].y++; Line[2].x++;
1192 Line[0].y = Line[1].y + d93;
1193 Line[3].x = Line[2].x + d93;
1194 SelectObject(dc, hb2);
1195 SelectObject(dc, hp2);
1196 Polygon(dc, Line, 4);
1197
1198 i = 210*SmallDiam/750;
1199 Line[0].y = r->bottom - i - 1;
1200 Line[3].x = r->right - i - 1;
1201 Line[1].y = Line[0].y + d46;
1202 Line[2].x = Line[3].x + d46;
1203 SelectObject(dc, hb);
1204 SelectObject(dc, hp);
1205 Polygon(dc, Line, 4);
1206
1207 Line[1].y++; Line[2].x++;
1208 Line[0].y = Line[1].y + d93;
1209 Line[3].x = Line[2].x + d93;
1210 SelectObject(dc, hb2);
1211 SelectObject(dc, hp2);
1212 Polygon(dc, Line, 4);
1213
1214 SelectObject(dc, hpsave);
1215 SelectObject(dc, hbsave);
1216 return TRUE;
1217
1218 default:
1219 return FALSE;
1220 }
1221
1222 /* Here do the real scroll-bar controls end up */
1223 if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1224 /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1225 /* want for the normal scroll-arrow button. */
1226 IntDrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1227 else
1228 UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1229
1230 if(uFlags & DFCS_INACTIVE)
1231 {
1232 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1233 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1234 Polygon(dc, Line, 3);
1235 SelectObject(dc, hpsave);
1236 SelectObject(dc, hbsave);
1237 }
1238
1239 if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1240 for(i = 0; i < 3; i++)
1241 {
1242 Line[i].x--;
1243 Line[i].y--;
1244 }
1245
1246 i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1247 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1248 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
1249 Polygon(dc, Line, 3);
1250 SelectObject(dc, hpsave);
1251 SelectObject(dc, hbsave);
1252
1253 return TRUE;
1254 }
1255
1256 /* Ported from WINE20020904 */
1257 /* Draw a menu control coming from DrawFrameControl() */
1258 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1259 {
1260 POINT Points[6];
1261 RECT myr;
1262 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1263 int i;
1264 HBRUSH hbsave;
1265 HPEN hpsave;
1266 int xe, ye;
1267 int xc, yc;
1268 BOOL retval = TRUE;
1269
1270 /* Using black and white seems to be utterly wrong, but win95 doesn't */
1271 /* use anything else. I think I tried all sys-colors to change things */
1272 /* without luck. It seems as if this behavior is inherited from the */
1273 /* win31 DFC() implementation... (you remember, B/W menus). */
1274
1275 FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
1276
1277 hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
1278 hpsave = (HPEN)SelectObject(dc, GetStockObject(BLACK_PEN));
1279
1280 switch(uFlags & 0xff)
1281 {
1282 case DFCS_MENUARROW:
1283 i = 187*SmallDiam/750;
1284 Points[2].x = myr.left + 468*SmallDiam/750;
1285 Points[2].y = myr.top + 352*SmallDiam/750+1;
1286 Points[0].y = Points[2].y - i;
1287 Points[1].y = Points[2].y + i;
1288 Points[0].x = Points[1].x = Points[2].x - i;
1289 Polygon(dc, Points, 3);
1290 break;
1291
1292 case DFCS_MENUBULLET:
1293 xe = myr.left;
1294 ye = myr.top + SmallDiam - SmallDiam/2;
1295 xc = myr.left + SmallDiam - SmallDiam/2;
1296 yc = myr.top + SmallDiam - SmallDiam/2;
1297 i = 234*SmallDiam/750;
1298 i = i < 1 ? 1 : i;
1299 myr.left = xc - i+i/2;
1300 myr.right = xc + i/2;
1301 myr.top = yc - i+i/2;
1302 myr.bottom = yc + i/2;
1303 Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1304 break;
1305
1306 case DFCS_MENUCHECK:
1307 Points[0].x = myr.left + 253*SmallDiam/1000;
1308 Points[0].y = myr.top + 445*SmallDiam/1000;
1309 Points[1].x = myr.left + 409*SmallDiam/1000;
1310 Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1311 Points[2].x = myr.left + 690*SmallDiam/1000;
1312 Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1313 Points[3].x = Points[2].x;
1314 Points[3].y = Points[2].y + 3*SmallDiam/16;
1315 Points[4].x = Points[1].x;
1316 Points[4].y = Points[1].y + 3*SmallDiam/16;
1317 Points[5].x = Points[0].x;
1318 Points[5].y = Points[0].y + 3*SmallDiam/16;
1319 Polygon(dc, Points, 6);
1320 break;
1321
1322 default:
1323 /*
1324 DbgPrint("Invalid menu; flags=0x%04x\n", uFlags);
1325 */
1326 retval = FALSE;
1327 break;
1328 }
1329
1330 SelectObject(dc, hpsave);
1331 SelectObject(dc, hbsave);
1332 return retval;
1333 }
1334
1335
1336 BOOL
1337 STDCALL
1338 IntGrayString(
1339 HDC hDC,
1340 HBRUSH hBrush,
1341 GRAYSTRINGPROC lpOutputFunc,
1342 LPARAM lpData,
1343 int nCount,
1344 int X,
1345 int Y,
1346 int nWidth,
1347 int nHeight,
1348 BOOL unicode)
1349 {
1350 // AG: Mostly implemented, but probably won't work properly or return
1351 // correct error codes. I doubt it grays strings either... Untested!
1352
1353 BOOL success = FALSE;
1354 HDC MemDC = NULL;
1355 HBITMAP MemBMP = NULL,
1356 OldBMP = NULL;
1357 HBRUSH OldBrush = NULL;
1358 HFONT OldFont = NULL;
1359 RECT r;
1360 COLORREF ForeColor, BackColor;
1361
1362 ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
1363 BackColor = SetBkColor(hDC, RGB(255, 255, 255));
1364
1365
1366 if (! hBrush)
1367 {
1368 // The documentation is a little vague on what exactly should happen
1369 // here. Something about using the same brush for window text???
1370 hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
1371 }
1372
1373 if ((nCount == -1) && (! lpOutputFunc))
1374 return FALSE;
1375
1376 if (! nCount)
1377 {
1378 // TODO: calculate the length (easy enough)
1379
1380 if (unicode)
1381 nCount = lstrlenW((WCHAR*)lpData);
1382 else
1383 nCount = lstrlenA((CHAR*)lpData);
1384 }
1385
1386 if (! nWidth || ! nHeight)
1387 {
1388 SIZE s;
1389 // TODO: calculate the rect
1390
1391 if (unicode)
1392 success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
1393 else
1394 success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
1395
1396 if (! success) goto cleanup;
1397
1398 if (! nWidth) nWidth = s.cx;
1399 if (! nHeight) nHeight = s.cy;
1400 }
1401
1402 SetRect(&r, X, Y, X + nWidth, Y + nHeight);
1403
1404 MemDC = CreateCompatibleDC(hDC);
1405 if (! MemDC) goto cleanup;
1406 MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1407 if (! MemBMP) goto cleanup;
1408 OldBMP = SelectObject(MemDC, MemBMP);
1409 if (! OldBMP) goto cleanup;
1410 OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
1411 if (! OldFont) goto cleanup;
1412 OldBrush = SelectObject(MemDC, hBrush);
1413 if (! OldBrush) goto cleanup;
1414
1415 if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
1416
1417 SetTextColor(MemDC, RGB(255, 255, 255));
1418 SetBkColor(MemDC, RGB(0, 0, 0));
1419
1420 if (lpOutputFunc)
1421 {
1422 success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
1423
1424 if ((nCount == -1) && (! success))
1425 {
1426 // Don't gray (documented behaviour)
1427 success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
1428 goto cleanup;
1429 }
1430 }
1431 else
1432 {
1433 if (unicode)
1434 success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
1435 else
1436 success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
1437
1438 if (! success) goto cleanup;
1439
1440 PatBlt(MemDC, 0, 0, nWidth, nHeight, PATCOPY);
1441 // This is how WINE does it: (but we should have our own graying brush already)
1442 // hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1443 // PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
1444 // SelectObject(memdc, hbsave);
1445 }
1446
1447 if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
1448
1449 cleanup :
1450 SetTextColor(hDC, ForeColor);
1451 SetBkColor(hDC, BackColor);
1452
1453 if (MemDC)
1454 {
1455 if (OldFont) SelectObject(MemDC, OldFont);
1456 if (OldBrush) SelectObject(MemDC, OldBrush);
1457 if (OldBMP) SelectObject(MemDC, OldBMP);
1458 if (MemBMP) DeleteObject(MemBMP);
1459 DeleteDC(MemDC);
1460 }
1461
1462 return success;
1463 }
1464
1465 /**********************************************************************
1466 * PAINTING_DrawStateJam
1467 *
1468 * Jams in the requested type in the dc
1469 */
1470 static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
1471 DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1472 LPRECT rc, UINT dtflags, BOOL unicode )
1473 {
1474 HDC memdc;
1475 HBITMAP hbmsave;
1476 BOOL retval;
1477 INT cx = rc->right - rc->left;
1478 INT cy = rc->bottom - rc->top;
1479
1480 switch(opcode)
1481 {
1482 case DST_TEXT:
1483 case DST_PREFIXTEXT:
1484 if(unicode)
1485 return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1486 else
1487 return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1488
1489 case DST_ICON:
1490 return DrawIcon(hdc, rc->left, rc->top, (HICON)lp);
1491
1492 case DST_BITMAP:
1493 memdc = CreateCompatibleDC(hdc);
1494 if(!memdc) return FALSE;
1495 hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
1496 if(!hbmsave)
1497 {
1498 DeleteDC(memdc);
1499 return FALSE;
1500 }
1501 retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1502 SelectObject(memdc, hbmsave);
1503 DeleteDC(memdc);
1504 return retval;
1505
1506 case DST_COMPLEX:
1507 if(func) {
1508 BOOL bRet;
1509 /* DRAWSTATEPROC assumes that it draws at the center of coordinates */
1510
1511 OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1512 bRet = func(hdc, lp, wp, cx, cy);
1513 /* Restore origin */
1514 OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1515 return bRet;
1516 } else
1517 return FALSE;
1518 }
1519 return FALSE;
1520 }
1521
1522 static BOOL
1523 IntDrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1524 INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode)
1525 {
1526 HBITMAP hbm, hbmsave;
1527 HFONT hfsave;
1528 HBRUSH hbsave, hbrtmp = 0;
1529 HDC memdc;
1530 RECT rc;
1531 UINT dtflags = DT_NOCLIP;
1532 COLORREF fg, bg;
1533 UINT opcode = flags & 0xf;
1534 INT len = wp;
1535 BOOL retval, tmp;
1536
1537 if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len) /* The string is '\0' terminated */
1538 {
1539 if(unicode)
1540 len = lstrlenW((LPWSTR)lp);
1541 else
1542 len = lstrlenA((LPSTR)lp);
1543 }
1544
1545 /* Find out what size the image has if not given by caller */
1546 if(!cx || !cy)
1547 {
1548 SIZE s;
1549 ICONINFO ici;
1550 BITMAP bm;
1551
1552 switch(opcode)
1553 {
1554 case DST_TEXT:
1555 case DST_PREFIXTEXT:
1556 if(unicode)
1557 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1558 else
1559 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1560 if(!retval) return FALSE;
1561 break;
1562
1563 case DST_ICON:
1564 if(!GetIconInfo((HICON)lp, &ici))
1565 return FALSE;
1566 if(!GetObjectW(ici.hbmColor, sizeof(bm), &bm))
1567 return FALSE;
1568 s.cx = bm.bmWidth;
1569 s.cy = bm.bmHeight;
1570 break;
1571
1572 case DST_BITMAP:
1573 if(!GetObjectW((HBITMAP)lp, sizeof(bm), &bm))
1574 return FALSE;
1575 s.cx = bm.bmWidth;
1576 s.cy = bm.bmHeight;
1577 break;
1578
1579 case DST_COMPLEX: /* cx and cy must be set in this mode */
1580 return FALSE;
1581 }
1582
1583 if(!cx) cx = s.cx;
1584 if(!cy) cy = s.cy;
1585 }
1586
1587 rc.left = x;
1588 rc.top = y;
1589 rc.right = x + cx;
1590 rc.bottom = y + cy;
1591
1592 if(flags & DSS_RIGHT) /* This one is not documented in the win32.hlp file */
1593 dtflags |= DT_RIGHT;
1594 if(opcode == DST_TEXT)
1595 dtflags |= DT_NOPREFIX;
1596
1597 /* For DSS_NORMAL we just jam in the image and return */
1598 if((flags & 0x7ff0) == DSS_NORMAL)
1599 {
1600 return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1601 }
1602
1603 /* For all other states we need to convert the image to B/W in a local bitmap */
1604 /* before it is displayed */
1605 fg = SetTextColor(hdc, RGB(0, 0, 0));
1606 bg = SetBkColor(hdc, RGB(255, 255, 255));
1607 hbm = NULL; hbmsave = NULL;
1608 memdc = NULL; hbsave = NULL;
1609 retval = FALSE; /* assume failure */
1610
1611 /* From here on we must use "goto cleanup" when something goes wrong */
1612 hbm = CreateBitmap(cx, cy, 1, 1, NULL);
1613 if(!hbm) goto cleanup;
1614 memdc = CreateCompatibleDC(hdc);
1615 if(!memdc) goto cleanup;
1616 hbmsave = (HBITMAP)SelectObject(memdc, hbm);
1617 if(!hbmsave) goto cleanup;
1618 rc.left = rc.top = 0;
1619 rc.right = cx;
1620 rc.bottom = cy;
1621 if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
1622 SetBkColor(memdc, RGB(255, 255, 255));
1623 SetTextColor(memdc, RGB(0, 0, 0));
1624 hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1625
1626 /* DST_COMPLEX may draw text as well,
1627 * so we must be sure that correct font is selected
1628 */
1629 if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1630 tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1631 if(hfsave) SelectObject(memdc, hfsave);
1632 if(!tmp) goto cleanup;
1633
1634 /* This state cause the image to be dithered */
1635 if(flags & DSS_UNION)
1636 {
1637 #if 0
1638 hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1639 if(!hbsave) goto cleanup;
1640 tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1641 SelectObject(memdc, hbsave);
1642 if(!tmp) goto cleanup;
1643 #else
1644 UNIMPLEMENTED;
1645 #endif
1646 }
1647
1648 if (flags & DSS_DISABLED)
1649 hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1650 else if (flags & DSS_DEFAULT)
1651 hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1652
1653 /* Draw light or dark shadow */
1654 if (flags & (DSS_DISABLED|DSS_DEFAULT))
1655 {
1656 if(!hbrtmp) goto cleanup;
1657 hbsave = (HBRUSH)SelectObject(hdc, hbrtmp);
1658 if(!hbsave) goto cleanup;
1659 if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1660 SelectObject(hdc, hbsave);
1661 DeleteObject(hbrtmp);
1662 hbrtmp = 0;
1663 }
1664
1665 if (flags & DSS_DISABLED)
1666 {
1667 hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1668 if(!hbrtmp) goto cleanup;
1669 }
1670 else if (!hbr)
1671 {
1672 hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
1673 }
1674
1675 hbsave = (HBRUSH)SelectObject(hdc, hbr);
1676
1677 if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1678
1679 retval = TRUE; /* We succeeded */
1680
1681 cleanup:
1682 SetTextColor(hdc, fg);
1683 SetBkColor(hdc, bg);
1684
1685 if(hbsave) SelectObject(hdc, hbsave);
1686 if(hbmsave) SelectObject(memdc, hbmsave);
1687 if(hbrtmp) DeleteObject(hbrtmp);
1688 if(hbm) DeleteObject(hbm);
1689 if(memdc) DeleteDC(memdc);
1690
1691 return retval;
1692 }
1693
1694 /*
1695 * @implemented
1696 */
1697 BOOL STDCALL
1698 DrawFrameControl(HDC hDC, LPRECT rc, UINT uType, UINT uState)
1699 {
1700 if (GetMapMode(hDC) != MM_TEXT)
1701 return FALSE;
1702
1703 switch(uType)
1704 {
1705 case DFC_BUTTON:
1706 return UITOOLS95_DrawFrameButton(hDC, rc, uState);
1707 case DFC_CAPTION:
1708 return UITOOLS95_DrawFrameCaption(hDC, rc, uState);
1709 case DFC_MENU:
1710 return UITOOLS95_DrawFrameMenu(hDC, rc, uState);
1711 #if 0
1712 case DFC_POPUPMENU:
1713 UNIMPLEMENTED;
1714 break;
1715 #endif
1716 case DFC_SCROLL:
1717 return UITOOLS95_DrawFrameScroll(hDC, rc, uState);
1718 }
1719 return FALSE;
1720 }
1721
1722 /*
1723 * @implemented
1724 */
1725 BOOL STDCALL
1726 DrawEdge(HDC hDC, LPRECT rc, UINT edge, UINT flags)
1727 {
1728 if (flags & BF_DIAGONAL)
1729 return IntDrawDiagEdge(hDC, rc, edge, flags);
1730 else
1731 return IntDrawRectEdge(hDC, rc, edge, flags);
1732 }
1733
1734 /*
1735 * @implemented
1736 */
1737 BOOL STDCALL
1738 GrayStringA(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1739 int nCount, int X, int Y, int nWidth, int nHeight)
1740 {
1741 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1742 }
1743
1744 /*
1745 * @implemented
1746 */
1747 BOOL STDCALL
1748 GrayStringW(HDC hDC, HBRUSH hBrush, GRAYSTRINGPROC lpOutputFunc, LPARAM lpData,
1749 int nCount, int X, int Y, int nWidth, int nHeight)
1750 {
1751 return IntGrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1752 }
1753
1754 /*
1755 * @implemented
1756 */
1757 BOOL STDCALL
1758 InvertRect(HDC hDC, CONST RECT *lprc)
1759 {
1760 return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1761 lprc->bottom - lprc->top, DSTINVERT);
1762 }
1763
1764 /*
1765 * @implemented
1766 */
1767 INT STDCALL
1768 FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1769 {
1770 HBRUSH oldbrush;
1771 RECT r = *lprc;
1772
1773 if ((r.right <= r.left) || (r.bottom <= r.top)) return 0;
1774 if (!(oldbrush = SelectObject(hDC, hbr))) return 0;
1775
1776 PatBlt(hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY);
1777 PatBlt(hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY);
1778 PatBlt(hDC, r.left, r.top, r.right - r.left, 1, PATCOPY);
1779 PatBlt(hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY);
1780
1781 SelectObject(hDC, oldbrush);
1782 return TRUE;
1783 }
1784
1785 /*
1786 * @unimplemented
1787 */
1788 BOOL STDCALL
1789 FlashWindow(HWND hWnd, BOOL bInvert)
1790 {
1791 UNIMPLEMENTED;
1792 return FALSE;
1793 }
1794
1795 /*
1796 * @unimplemented
1797 */
1798 BOOL STDCALL
1799 FlashWindowEx(PFLASHWINFO pfwi)
1800 {
1801 UNIMPLEMENTED;
1802 return FALSE;
1803 }
1804
1805 /*
1806 * @implemented
1807 */
1808 INT STDCALL
1809 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1810 {
1811 HBRUSH prevhbr;
1812
1813 if (hbr <= (HBRUSH)(COLOR_MENUBAR + 1))
1814 {
1815 hbr = GetSysColorBrush((int)hbr - 1);
1816 }
1817 if ((prevhbr = NtGdiSelectObject(hDC, hbr)) == NULL)
1818 {
1819 return FALSE;
1820 }
1821 NtGdiPatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1822 lprc->bottom - lprc->top, PATCOPY);
1823 NtGdiSelectObject(hDC, prevhbr);
1824 return TRUE;
1825 }
1826
1827 /*
1828 * @unimplemented
1829 */
1830 BOOL STDCALL
1831 DrawAnimatedRects(HWND hWnd, int idAni, CONST RECT *lprcFrom,
1832 CONST RECT *lprcTo)
1833 {
1834 UNIMPLEMENTED;
1835 return FALSE;
1836 }
1837
1838 /*
1839 * @implemented
1840 */
1841 BOOL STDCALL
1842 DrawFocusRect(HDC hdc, CONST RECT *rect)
1843 {
1844 static HBRUSH hFocusRectBrush = NULL;
1845 HGDIOBJ OldObj;
1846 UINT cx, cy;
1847
1848 if(!hFocusRectBrush)
1849 {
1850 static HBITMAP hFocusPattern = NULL;
1851 const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
1852
1853 hFocusPattern = CreateBitmap(8, 8, 1, 1, Pattern);
1854 hFocusRectBrush = CreatePatternBrush(hFocusPattern);
1855 }
1856
1857 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &cx, 0);
1858 NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &cy, 0);
1859
1860 OldObj = SelectObject(hdc, hFocusRectBrush);
1861
1862 /* top */
1863 PatBlt(hdc, rect->left, rect->top, rect->right - rect->left, cy, PATINVERT);
1864 /* bottom */
1865 PatBlt(hdc, rect->left, rect->bottom - cy, rect->right - rect->left, cy, PATINVERT);
1866 /* left */
1867 PatBlt(hdc, rect->left, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1868 /* right */
1869 PatBlt(hdc, rect->right - cx, rect->top + cy, cx, rect->bottom - rect->top - (2 * cy), PATINVERT);
1870
1871 SelectObject(hdc, OldObj);
1872 return TRUE;
1873 }
1874
1875 /*
1876 * @implemented
1877 */
1878 BOOL STDCALL
1879 DrawStateA(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1880 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1881 {
1882 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
1883 }
1884
1885 /*
1886 * @implemented
1887 */
1888 BOOL STDCALL
1889 DrawStateW(HDC hDC, HBRUSH hBrush, DRAWSTATEPROC lpOutputFunc, LPARAM lData,
1890 WPARAM wData, int x, int y, int cx, int cy, UINT fuFlags)
1891 {
1892 return IntDrawState(hDC, hBrush, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
1893 }