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