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