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