3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 09-05-2001 CSH Created
29 /* INCLUDES ******************************************************************/
34 // Needed for DrawState
42 /* GLOBALS *******************************************************************/
44 #define COLOR_MAX (28)
46 /* HPEN STDCALL W32kGetSysColorPen(int nIndex); */
48 static const WORD wPattern_AA55[8] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555,
49 0xaaaa, 0x5555, 0xaaaa, 0x5555 };
51 /* These tables are used in:
52 * UITOOLS_DrawDiagEdge()
53 * UITOOLS_DrawRectEdge()
55 static const signed char LTInnerNormal[] = {
57 -1, COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
58 -1, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW, -1,
62 static const signed char LTOuterNormal[] = {
63 -1, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
64 COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
65 COLOR_3DDKSHADOW, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1,
66 -1, COLOR_3DLIGHT, COLOR_BTNSHADOW, -1
69 static const signed char RBInnerNormal[] = {
71 -1, COLOR_BTNSHADOW, COLOR_BTNSHADOW, -1,
72 -1, COLOR_3DLIGHT, COLOR_3DLIGHT, -1,
76 static const signed char RBOuterNormal[] = {
77 -1, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
78 COLOR_BTNSHADOW, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
79 COLOR_3DLIGHT, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1,
80 -1, COLOR_3DDKSHADOW, COLOR_BTNHIGHLIGHT, -1
83 static const signed char LTInnerSoft[] = {
85 -1, COLOR_3DLIGHT, COLOR_3DLIGHT, -1,
86 -1, COLOR_BTNSHADOW, COLOR_BTNSHADOW, -1,
90 static const signed char LTOuterSoft[] = {
91 -1, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
92 COLOR_3DLIGHT, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
93 COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
94 -1, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
97 #define RBInnerSoft RBInnerNormal /* These are the same */
98 #define RBOuterSoft RBOuterNormal
100 static const signed char LTRBOuterMono[] = {
101 -1, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
102 COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
103 COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
104 COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
107 static const signed char LTRBInnerMono[] = {
109 -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
110 -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
111 -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
114 static const signed char LTRBOuterFlat[] = {
115 -1, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
116 COLOR_BTNFACE, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
117 COLOR_BTNFACE, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
118 COLOR_BTNFACE, COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
121 static const signed char LTRBInnerFlat[] = {
123 -1, COLOR_BTNFACE, COLOR_BTNFACE, COLOR_BTNFACE,
124 -1, COLOR_BTNFACE, COLOR_BTNFACE, COLOR_BTNFACE,
125 -1, COLOR_BTNFACE, COLOR_BTNFACE, COLOR_BTNFACE,
127 /* FUNCTIONS *****************************************************************/
130 HPEN STDCALL GetSysColorPen(int nIndex);
131 HBRUSH STDCALL GetSysColorBrush(int nIndex);
133 /* Ported from WINE20020904 */
134 /* Same as DrawEdge invoked with BF_DIAGONAL */
135 static BOOL UITOOLS95_DrawDiagEdge(HDC hdc, LPRECT rc,
136 UINT uType, UINT uFlags)
139 signed char InnerI, OuterI;
140 HPEN InnerPen, OuterPen;
145 int Width = rc->right - rc->left;
146 int Height= rc->bottom - rc->top;
147 int SmallDiam = Width > Height ? Height : Width;
148 BOOL retval = !( ((uType & BDR_INNER) == BDR_INNER
149 || (uType & BDR_OUTER) == BDR_OUTER)
150 && !(uFlags & (BF_FLAT|BF_MONO)) );
151 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
152 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
155 OuterPen = InnerPen = (HPEN)GetStockObject(NULL_PEN);
156 SavePen = (HPEN)SelectObject(hdc, InnerPen);
157 spx = spy = epx = epy = 0; /* Satisfy the compiler... */
159 /* Determine the colors of the edges */
162 InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
163 OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
165 else if(uFlags & BF_FLAT)
167 InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
168 OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
170 else if(uFlags & BF_SOFT)
172 if(uFlags & BF_BOTTOM)
174 InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
175 OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
179 InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
180 OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
185 if(uFlags & BF_BOTTOM)
187 InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
188 OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
192 InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
193 OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
197 if(InnerI != -1) InnerPen = GetSysColorPen(InnerI);
198 if(OuterI != -1) OuterPen = GetSysColorPen(OuterI);
200 MoveToEx(hdc, 0, 0, &SavePoint);
202 /* Don't ask me why, but this is what is visible... */
203 /* This must be possible to do much simpler, but I fail to */
204 /* see the logic in the MS implementation (sigh...). */
205 /* So, this might look a bit brute force here (and it is), but */
206 /* it gets the job done;) */
208 switch(uFlags & BF_RECT)
214 /* Left bottom endpoint */
216 spx = epx + SmallDiam;
218 spy = epy - SmallDiam;
223 /* Left top endpoint */
225 spx = epx + SmallDiam;
227 spy = epy + SmallDiam;
233 case BF_RIGHT|BF_LEFT:
234 case BF_RIGHT|BF_LEFT|BF_TOP:
235 case BF_BOTTOM|BF_TOP:
236 case BF_BOTTOM|BF_TOP|BF_LEFT:
237 case BF_BOTTOMRIGHT|BF_LEFT:
238 case BF_BOTTOMRIGHT|BF_TOP:
240 /* Right top endpoint */
242 epx = spx + SmallDiam;
244 epy = spy - SmallDiam;
248 MoveToEx(hdc, spx, spy, NULL);
249 SelectObject(hdc, OuterPen);
250 LineTo(hdc, epx, epy);
252 SelectObject(hdc, InnerPen);
254 switch(uFlags & (BF_RECT|BF_DIAGONAL))
256 case BF_DIAGONAL_ENDBOTTOMLEFT:
257 case (BF_DIAGONAL|BF_BOTTOM):
259 case (BF_DIAGONAL|BF_LEFT):
260 MoveToEx(hdc, spx-1, spy, NULL);
261 LineTo(hdc, epx, epy-1);
262 Points[0].x = spx-add;
264 Points[1].x = rc->left;
265 Points[1].y = rc->top;
267 Points[2].y = epy-1-add;
268 Points[3] = Points[2];
271 case BF_DIAGONAL_ENDBOTTOMRIGHT:
272 MoveToEx(hdc, spx-1, spy, NULL);
273 LineTo(hdc, epx, epy+1);
274 Points[0].x = spx-add;
276 Points[1].x = rc->left;
277 Points[1].y = rc->bottom-1;
279 Points[2].y = epy+1+add;
280 Points[3] = Points[2];
283 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
284 case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
285 case BF_DIAGONAL_ENDTOPRIGHT:
286 case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
287 MoveToEx(hdc, spx+1, spy, NULL);
288 LineTo(hdc, epx, epy+1);
290 Points[0].y = epy+1+add;
291 Points[1].x = rc->right-1;
292 Points[1].y = rc->top+add;
293 Points[2].x = rc->right-1;
294 Points[2].y = rc->bottom-1;
295 Points[3].x = spx+add;
299 case BF_DIAGONAL_ENDTOPLEFT:
300 MoveToEx(hdc, spx, spy-1, NULL);
301 LineTo(hdc, epx+1, epy);
302 Points[0].x = epx+1+add;
304 Points[1].x = rc->right-1;
305 Points[1].y = rc->top;
306 Points[2].x = rc->right-1;
307 Points[2].y = rc->bottom-1-add;
309 Points[3].y = spy-add;
312 case (BF_DIAGONAL|BF_TOP):
313 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
314 case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
315 MoveToEx(hdc, spx+1, spy-1, NULL);
316 LineTo(hdc, epx, epy);
319 Points[1].x = rc->right-1;
320 Points[1].y = rc->top;
321 Points[2].x = rc->right-1;
322 Points[2].y = rc->bottom-1-add;
323 Points[3].x = spx+add;
324 Points[3].y = spy-add;
327 case (BF_DIAGONAL|BF_RIGHT):
328 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
329 case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
330 MoveToEx(hdc, spx, spy, NULL);
331 LineTo(hdc, epx-1, epy+1);
334 Points[1].x = rc->left;
335 Points[1].y = rc->top+add;
336 Points[2].x = epx-1-add;
337 Points[2].y = epy+1+add;
338 Points[3] = Points[2];
342 /* Fill the interior if asked */
343 if((uFlags & BF_MIDDLE) && retval)
346 HBRUSH hb = GetSysColorBrush(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE);
348 HPEN hp = GetSysColorPen(uFlags & BF_MONO ? COLOR_WINDOW : COLOR_BTNFACE);
349 hbsave = (HBRUSH)SelectObject(hdc, hb);
350 hpsave = (HPEN)SelectObject(hdc, hp);
351 Polygon(hdc, Points, 4);
352 SelectObject(hdc, hbsave);
353 SelectObject(hdc, hpsave);
356 /* Adjust rectangle if asked */
357 if(uFlags & BF_ADJUST)
359 if(uFlags & BF_LEFT) rc->left += add;
360 if(uFlags & BF_RIGHT) rc->right -= add;
361 if(uFlags & BF_TOP) rc->top += add;
362 if(uFlags & BF_BOTTOM) rc->bottom -= add;
366 SelectObject(hdc, SavePen);
367 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
372 /* Ported from WINE20020904 */
373 /* Same as DrawEdge invoked without BF_DIAGONAL
375 * 23-Nov-1997: Changed by Bertho Stultiens
377 * Well, I started testing this and found out that there are a few things
378 * that weren't quite as win95. The following rewrite should reproduce
379 * win95 results completely.
380 * The colorselection is table-driven to avoid awfull if-statements.
381 * The table below show the color settings.
383 * Pen selection table for uFlags = 0
385 * uType | LTI | LTO | RBI | RBO
386 * ------+-------+-------+-------+-------
387 * 0000 | x | x | x | x
388 * 0001 | x | 22 | x | 21
389 * 0010 | x | 16 | x | 20
390 * 0011 | x | x | x | x
391 * ------+-------+-------+-------+-------
392 * 0100 | x | 20 | x | 16
393 * 0101 | 20 | 22 | 16 | 21
394 * 0110 | 20 | 16 | 16 | 20
395 * 0111 | x | x | x | x
396 * ------+-------+-------+-------+-------
397 * 1000 | x | 21 | x | 22
398 * 1001 | 21 | 22 | 22 | 21
399 * 1010 | 21 | 16 | 22 | 20
400 * 1011 | x | x | x | x
401 * ------+-------+-------+-------+-------
402 * 1100 | x | x | x | x
403 * 1101 | x | x (22)| x | x (21)
404 * 1110 | x | x (16)| x | x (20)
405 * 1111 | x | x | x | x
407 * Pen selection table for uFlags = BF_SOFT
409 * uType | LTI | LTO | RBI | RBO
410 * ------+-------+-------+-------+-------
411 * 0000 | x | x | x | x
412 * 0001 | x | 20 | x | 21
413 * 0010 | x | 21 | x | 20
414 * 0011 | x | x | x | x
415 * ------+-------+-------+-------+-------
416 * 0100 | x | 22 | x | 16
417 * 0101 | 22 | 20 | 16 | 21
418 * 0110 | 22 | 21 | 16 | 20
419 * 0111 | x | x | x | x
420 * ------+-------+-------+-------+-------
421 * 1000 | x | 16 | x | 22
422 * 1001 | 16 | 20 | 22 | 21
423 * 1010 | 16 | 21 | 22 | 20
424 * 1011 | x | x | x | x
425 * ------+-------+-------+-------+-------
426 * 1100 | x | x | x | x
427 * 1101 | x | x (20)| x | x (21)
428 * 1110 | x | x (21)| x | x (20)
429 * 1111 | x | x | x | x
431 * x = don't care; (n) = is what win95 actually uses
432 * LTI = left Top Inner line
433 * LTO = left Top Outer line
434 * RBI = Right Bottom Inner line
435 * RBO = Right Bottom Outer line
437 * 16 = COLOR_BTNSHADOW
438 * 20 = COLOR_BTNHIGHLIGHT
439 * 21 = COLOR_3DDKSHADOW
442 static BOOL UITOOLS95_DrawRectEdge(HDC hdc, LPRECT rc,
443 UINT uType, UINT uFlags)
445 signed char LTInnerI, LTOuterI;
446 signed char RBInnerI, RBOuterI;
447 HPEN LTInnerPen, LTOuterPen;
448 HPEN RBInnerPen, RBOuterPen;
449 RECT InnerRect = *rc;
456 BOOL retval = !( ((uType & BDR_INNER) == BDR_INNER
457 || (uType & BDR_OUTER) == BDR_OUTER)
458 && !(uFlags & (BF_FLAT|BF_MONO)) );
460 LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = (HPEN)GetStockObject(NULL_PEN);
461 SavePen = (HPEN)SelectObject(hdc, LTInnerPen);
463 /* Determine the colors of the edges */
466 LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
467 LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
469 else if(uFlags & BF_FLAT)
471 LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
472 LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
474 /* Bertho Stultiens states above that this function exactly matches win95
475 * In win98 BF_FLAT rectangles have an inner border same color as the
476 * middle (COLOR_BTNFACE). I believe it's the same for win95 but since
477 * I don't know I go with Bertho and just sets it for win98 until proven
479 * Dennis Björklund, 10 June, 99
481 /* if( TWEAK_WineLook == WIN98_LOOK && LTInnerI != -1 ) */
482 LTInnerI = RBInnerI = COLOR_BTNFACE;
484 else if(uFlags & BF_SOFT)
486 LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
487 LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
488 RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
489 RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
493 LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
494 LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
495 RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
496 RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
499 if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT) LBpenplus = 1;
500 if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT) RTpenplus = 1;
501 if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
502 if((uFlags & BF_TOPLEFT) == BF_TOPLEFT) LTpenplus = 1;
504 if(LTInnerI != -1) LTInnerPen = GetSysColorPen(LTInnerI);
505 if(LTOuterI != -1) LTOuterPen = GetSysColorPen(LTOuterI);
506 if(RBInnerI != -1) RBInnerPen = GetSysColorPen(RBInnerI);
507 if(RBOuterI != -1) RBOuterPen = GetSysColorPen(RBOuterI);
508 if((uFlags & BF_MIDDLE) && retval)
510 FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
511 COLOR_WINDOW : COLOR_BTNFACE));
513 MoveToEx(hdc, 0, 0, &SavePoint);
515 /* Draw the outer edge */
516 SelectObject(hdc, LTOuterPen);
519 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
520 LineTo(hdc, InnerRect.right, InnerRect.top);
524 MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
525 LineTo(hdc, InnerRect.left, InnerRect.bottom);
527 SelectObject(hdc, RBOuterPen);
528 if(uFlags & BF_BOTTOM)
530 MoveToEx(hdc, InnerRect.left, InnerRect.bottom-1, NULL);
531 LineTo(hdc, InnerRect.right, InnerRect.bottom-1);
533 if(uFlags & BF_RIGHT)
535 MoveToEx(hdc, InnerRect.right-1, InnerRect.top, NULL);
536 LineTo(hdc, InnerRect.right-1, InnerRect.bottom);
539 /* Draw the inner edge */
540 SelectObject(hdc, LTInnerPen);
543 MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
544 LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
548 MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
549 LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
551 SelectObject(hdc, RBInnerPen);
552 if(uFlags & BF_BOTTOM)
554 MoveToEx(hdc, InnerRect.left+LBpenplus, InnerRect.bottom-2, NULL);
555 LineTo(hdc, InnerRect.right-RBpenplus, InnerRect.bottom-2);
557 if(uFlags & BF_RIGHT)
559 MoveToEx(hdc, InnerRect.right-2, InnerRect.top+RTpenplus, NULL);
560 LineTo(hdc, InnerRect.right-2, InnerRect.bottom-RBpenplus);
563 if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
565 int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
566 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
568 if(uFlags & BF_LEFT) InnerRect.left += add;
569 if(uFlags & BF_RIGHT) InnerRect.right -= add;
570 if(uFlags & BF_TOP) InnerRect.top += add;
571 if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
573 if(uFlags & BF_ADJUST)
578 SelectObject(hdc, SavePen);
579 MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
583 /* Ported from WINE20020904 */
584 /* Utility to create a square rectangle and returning the width */
585 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
587 int Width = src->right - src->left;
588 int Height = src->bottom - src->top;
589 int SmallDiam = Width > Height ? Height : Width;
593 /* Make it a square box */
594 if(Width < Height) /* SmallDiam == Width */
596 dst->top += (Height-Width)/2;
597 dst->bottom = dst->top + SmallDiam;
599 else if(Width > Height) /* SmallDiam == Height */
601 dst->left += (Width-Height)/2;
602 dst->right = dst->left + SmallDiam;
608 /* Ported from WINE20020904 */
609 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
611 if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
613 HBITMAP hbm = CreateBitmap(8, 8, 1, 1, wPattern_AA55);
615 HBRUSH hb = CreatePatternBrush(hbm);
618 FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
619 bg = SetBkColor(dc, RGB(255, 255, 255));
620 hbsave = (HBRUSH)SelectObject(dc, hb);
621 PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
622 SelectObject(dc, hbsave);
629 FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
633 /* Ported from WINE20020904 */
634 /* Draw a push button coming from DrawFrameControl()
636 * Does a pretty good job in emulating MS behavior. Some quirks are
637 * however there because MS uses a TrueType font (Marlett) to draw
640 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
645 if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
650 if(uFlags & DFCS_CHECKED)
652 if(uFlags & DFCS_MONO)
653 UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
655 UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
657 UITOOLS_DrawCheckedRect( dc, &myr );
661 if(uFlags & DFCS_MONO)
663 UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
664 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
668 UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags&DFCS_FLAT) | BF_MIDDLE | BF_RECT);
672 /* Adjust rectangle if asked */
673 if(uFlags & DFCS_ADJUSTRECT)
684 /* Ported from WINE20020904 */
685 /* Draw a check/3state button coming from DrawFrameControl()
687 * Does a pretty good job in emulating MS behavior. Some quirks are
688 * however there because MS uses a TrueType font (Marlett) to draw
691 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
694 UINT flags = BF_RECT | BF_ADJUST;
695 UITOOLS_MakeSquareRect(r, &myr);
697 if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
698 else if(uFlags & DFCS_MONO) flags |= BF_MONO;
700 UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
702 if(uFlags & (DFCS_INACTIVE|DFCS_PUSHED))
703 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
704 else if( (uFlags & DFCS_BUTTON3STATE) && (uFlags & DFCS_CHECKED) )
705 UITOOLS_DrawCheckedRect( dc, &myr );
708 FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
711 if(uFlags & DFCS_CHECKED)
714 i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
715 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
717 /* draw 7 bars, with h=3w to form the check */
719 bar.top = myr.top + 2;
720 for (k = 0; k < 7; k++) {
721 bar.left = bar.left + 1;
722 bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
723 bar.bottom = bar.top + 3;
724 bar.right = bar.left + 1;
725 FillRect(dc, &bar, GetSysColorBrush(i));
731 /* Ported from WINE20020904 */
732 /* Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
734 * Does a pretty good job in emulating MS behavior. Some quirks are
735 * however there because MS uses a TrueType font (Marlett) to draw
738 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
742 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
743 int BorderShrink = SmallDiam / 16;
748 if(BorderShrink < 1) BorderShrink = 1;
750 if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
752 FillRect(dc, r, (HBRUSH)GetStockObject(BLACK_BRUSH));
755 xc = myr.left + SmallDiam - SmallDiam/2;
756 yc = myr.top + SmallDiam - SmallDiam/2;
758 /* Define bounding box */
760 myr.left = xc - i+i/2;
761 myr.right = xc + i/2;
762 myr.top = yc - i+i/2;
763 myr.bottom = yc + i/2;
765 if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
767 hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
768 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
769 SelectObject(dc, hbsave);
773 if(uFlags & (DFCS_FLAT|DFCS_MONO))
775 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_WINDOWFRAME));
776 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
777 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
778 SelectObject(dc, hbsave);
779 SelectObject(dc, hpsave);
783 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
784 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
785 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
787 SelectObject(dc, GetSysColorPen(COLOR_BTNSHADOW));
788 SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
789 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
791 myr.left += BorderShrink;
792 myr.right -= BorderShrink;
793 myr.top += BorderShrink;
794 myr.bottom -= BorderShrink;
796 SelectObject(dc, GetSysColorPen(COLOR_3DLIGHT));
797 SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
798 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
800 SelectObject(dc, GetSysColorPen(COLOR_3DDKSHADOW));
801 SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
802 Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
803 SelectObject(dc, hbsave);
804 SelectObject(dc, hpsave);
808 myr.left = xc - i+i/2;
809 myr.right = xc + i/2;
810 myr.top = yc - i+i/2;
811 myr.bottom = yc + i/2;
812 i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
813 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
814 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
815 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
816 SelectObject(dc, hbsave);
817 SelectObject(dc, hpsave);
820 if(uFlags & DFCS_CHECKED)
824 myr.left = xc - i+i/2;
825 myr.right = xc + i/2;
826 myr.top = yc - i+i/2;
827 myr.bottom = yc + i/2;
829 i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
830 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
831 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
832 Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
833 SelectObject(dc, hpsave);
834 SelectObject(dc, hbsave);
837 /* FIXME: M$ has a Polygon in the center at relative points: */
838 /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
842 /* when the button is unchecked. The reason for it is unknown. The */
843 /* color is COLOR_BTNHIGHLIGHT, although the Polygon gets painted at */
844 /* least 3 times (it looks like a clip-region when you see it happen). */
845 /* I do not really see a reason why this should be implemented. If you */
846 /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
852 /* Ported from WINE20020904 */
853 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
855 switch(uState & 0xff)
857 case DFCS_BUTTONPUSH:
858 return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
860 case DFCS_BUTTONCHECK:
861 case DFCS_BUTTON3STATE:
862 return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
864 case DFCS_BUTTONRADIOIMAGE:
865 case DFCS_BUTTONRADIOMASK:
866 case DFCS_BUTTONRADIO:
867 return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
870 DbgPrint("Invalid button state=0x%04x\n", uState);
876 /* Ported from WINE20020904 */
877 /* Draw caption buttons (win95), coming from DrawFrameControl() */
878 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
885 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
890 int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
891 int xc = (myr.left+myr.right)/2;
892 int yc = (myr.top+myr.bottom)/2;
900 if(uFlags & DFCS_PUSHED)
901 UITOOLS95_DrawRectEdge(dc,r,EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_SOFT);
903 UITOOLS95_DrawRectEdge(dc,r,BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RECT |
904 BF_SOFT | BF_MIDDLE);
906 switch(uFlags & 0xff)
908 case DFCS_CAPTIONCLOSE:
910 /* The "X" is made by drawing a series of lines.
911 * The number of lines drawn depends on the size
912 * of the bounding rect. e.g. For a 6x5 inside rect,
913 * two lines are drawn from top-left to bottom-right,
914 * and two lines from top-right to bottom-left.
916 * 0 1 2 3 4 5 0 1 2 3 4 5
922 * Drawing one line for every 6 pixels in width
923 * seems to provide the best proportions.
927 INT width = myr.right - myr.left - 5;
928 INT height = myr.bottom - myr.top - 6;
929 INT numLines = (width / 6) + 1;
931 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
933 start.x = myr.left + 2;
934 start.y = myr.top + 2;
941 if (uFlags & DFCS_PUSHED)
947 /* now use the width of each line */
948 width -= numLines - 1;
950 for (i = 0; i < numLines; i++)
952 MoveToEx(dc, start.x + i, start.y, &oldPos);
953 LineTo(dc, start.x + i + width, start.y + height);
955 MoveToEx(dc, start.x + i, start.y + height - 1, &oldPos);
956 LineTo(dc, start.x + i + width, start.y - 1);
959 SelectObject(dc, hpsave);
963 case DFCS_CAPTIONHELP:
964 /* This one breaks the flow */
965 /* FIXME: We need the Marlett font in order to get this right. */
967 hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
968 ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
969 DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
970 alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
971 bksave = SetBkMode(dc, TRANSPARENT);
972 clrsave = GetTextColor(dc);
973 hfsave = (HFONT)SelectObject(dc, hf);
974 GetTextExtentPoint32A(dc, str, 1, &size);
976 if(uFlags & DFCS_INACTIVE)
978 SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
979 TextOutA(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
981 SetTextColor(dc, GetSysColor(colorIdx));
982 TextOutA(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
984 SelectObject(dc, hfsave);
985 SetTextColor(dc, clrsave);
986 SetBkMode(dc, bksave);
987 SetTextAlign(dc, alignsave);
991 case DFCS_CAPTIONMIN:
992 Line1[0].x = Line1[3].x = myr.left + 96*SmallDiam/750+2;
993 Line1[1].x = Line1[2].x = Line1[0].x + 372*SmallDiam/750;
994 Line1[0].y = Line1[1].y = myr.top + 563*SmallDiam/750+1;
995 Line1[2].y = Line1[3].y = Line1[0].y + 92*SmallDiam/750;
1000 case DFCS_CAPTIONMAX:
1001 edge = 47*SmallDiam/750;
1002 Line1[0].x = Line1[5].x = myr.left + 57*SmallDiam/750+3;
1003 Line1[0].y = Line1[1].y = myr.top + 143*SmallDiam/750+1;
1004 Line1[1].x = Line1[2].x = Line1[0].x + 562*SmallDiam/750;
1005 Line1[5].y = Line1[4].y = Line1[0].y + 93*SmallDiam/750;
1006 Line1[2].y = Line1[3].y = Line1[0].y + 513*SmallDiam/750;
1007 Line1[3].x = Line1[4].x = Line1[1].x - edge;
1009 Line2[0].x = Line2[5].x = Line1[0].x;
1010 Line2[3].x = Line2[4].x = Line1[1].x;
1011 Line2[1].x = Line2[2].x = Line1[0].x + edge;
1012 Line2[0].y = Line2[1].y = Line1[0].y;
1013 Line2[4].y = Line2[5].y = Line1[2].y;
1014 Line2[2].y = Line2[3].y = Line1[2].y - edge;
1019 case DFCS_CAPTIONRESTORE:
1020 /* FIXME: this one looks bad at small sizes < 15x15 :( */
1021 edge = 47*SmallDiam/750;
1022 move = 420*SmallDiam/750;
1023 Line1[0].x = Line1[9].x = myr.left + 198*SmallDiam/750+2;
1024 Line1[0].y = Line1[1].y = myr.top + 169*SmallDiam/750+1;
1025 Line1[6].y = Line1[7].y = Line1[0].y + 93*SmallDiam/750;
1026 Line1[7].x = Line1[8].x = Line1[0].x + edge;
1027 Line1[1].x = Line1[2].x = Line1[0].x + move;
1028 Line1[5].x = Line1[6].x = Line1[1].x - edge;
1029 Line1[9].y = Line1[8].y = Line1[0].y + 187*SmallDiam/750;
1030 Line1[2].y = Line1[3].y = Line1[0].y + 327*SmallDiam/750;
1031 Line1[4].y = Line1[5].y = Line1[2].y - edge;
1032 Line1[3].x = Line1[4].x = Line1[2].x - 140*SmallDiam/750;
1034 Line2[1].x = Line2[2].x = Line1[3].x;
1035 Line2[7].x = Line2[8].x = Line2[1].x - edge;
1036 Line2[0].x = Line2[9].x = Line2[3].x = Line2[4].x = Line2[1].x - move;
1037 Line2[5].x = Line2[6].x = Line2[0].x + edge;
1038 Line2[0].y = Line2[1].y = Line1[9].y;
1039 Line2[4].y = Line2[5].y = Line2[8].y = Line2[9].y = Line2[0].y + 93*SmallDiam/750;
1040 Line2[2].y = Line2[3].y = Line2[0].y + 327*SmallDiam/750;
1041 Line2[6].y = Line2[7].y = Line2[2].y - edge;
1050 /* Here the drawing takes place */
1051 if(uFlags & DFCS_INACTIVE)
1053 /* If we have an inactive button, then you see a shadow */
1054 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1055 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1056 Polygon(dc, Line1, Line1N);
1058 Polygon(dc, Line2, Line2N);
1059 SelectObject(dc, hpsave);
1060 SelectObject(dc, hbsave);
1063 /* Correct for the shadow shift */
1064 if (!(uFlags & DFCS_PUSHED))
1066 for(i = 0; i < Line1N; i++)
1071 for(i = 0; i < Line2N; i++)
1078 /* Make the final picture */
1079 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(colorIdx));
1080 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
1082 Polygon(dc, Line1, Line1N);
1084 Polygon(dc, Line2, Line2N);
1085 SelectObject(dc, hpsave);
1086 SelectObject(dc, hbsave);
1091 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
1095 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
1097 HBRUSH hbsave, hb, hb2;
1098 HPEN hpsave, hp, hp2;
1099 int tri = 290*SmallDiam/1000 - 1;
1103 * This fixes a problem with really tiny "scroll" buttons. In particular
1104 * with the updown control.
1105 * Making sure that the arrow is as least 3 pixels wide (or high).
1110 switch(uFlags & 0xff)
1112 case DFCS_SCROLLCOMBOBOX:
1113 case DFCS_SCROLLDOWN:
1114 Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1115 Line[2].y = myr.top + 687*SmallDiam/1000 + 1;
1116 Line[0].x = Line[2].x - tri;
1117 Line[1].x = Line[2].x + tri;
1118 Line[0].y = Line[1].y = Line[2].y - tri;
1122 Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1123 Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1124 Line[0].x = Line[2].x - tri;
1125 Line[1].x = Line[2].x + tri;
1126 Line[0].y = Line[1].y = Line[2].y + tri;
1129 case DFCS_SCROLLLEFT:
1130 Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1131 Line[2].y = myr.top + 470*SmallDiam/1000 + 2;
1132 Line[0].y = Line[2].y - tri;
1133 Line[1].y = Line[2].y + tri;
1134 Line[0].x = Line[1].x = Line[2].x + tri;
1137 case DFCS_SCROLLRIGHT:
1138 Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1139 Line[2].y = myr.top + 470*SmallDiam/1000 + 2;
1140 Line[0].y = Line[2].y - tri;
1141 Line[1].y = Line[2].y + tri;
1142 Line[0].x = Line[1].x = Line[2].x - tri;
1145 case DFCS_SCROLLSIZEGRIP:
1146 /* This one breaks the flow... */
1147 UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1148 hpsave = (HPEN)SelectObject(dc, GetStockObject(NULL_PEN));
1149 hbsave = (HBRUSH)SelectObject(dc, GetStockObject(NULL_BRUSH));
1150 if(uFlags & (DFCS_MONO|DFCS_FLAT))
1152 hp = hp2 = GetSysColorPen(COLOR_WINDOWFRAME);
1153 hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1157 hp = GetSysColorPen(COLOR_BTNHIGHLIGHT);
1158 hp2 = GetSysColorPen(COLOR_BTNSHADOW);
1159 hb = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1160 hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1162 Line[0].x = Line[1].x = r->right-1;
1163 Line[2].y = Line[3].y = r->bottom-1;
1164 d46 = 46*SmallDiam/750;
1165 d93 = 93*SmallDiam/750;
1167 i = 586*SmallDiam/750;
1168 Line[0].y = r->bottom - i - 1;
1169 Line[3].x = r->right - i - 1;
1170 Line[1].y = Line[0].y + d46;
1171 Line[2].x = Line[3].x + d46;
1172 SelectObject(dc, hb);
1173 SelectObject(dc, hp);
1174 Polygon(dc, Line, 4);
1176 Line[1].y++; Line[2].x++;
1177 Line[0].y = Line[1].y + d93;
1178 Line[3].x = Line[2].x + d93;
1179 SelectObject(dc, hb2);
1180 SelectObject(dc, hp2);
1181 Polygon(dc, Line, 4);
1183 i = 398*SmallDiam/750;
1184 Line[0].y = r->bottom - i - 1;
1185 Line[3].x = r->right - i - 1;
1186 Line[1].y = Line[0].y + d46;
1187 Line[2].x = Line[3].x + d46;
1188 SelectObject(dc, hb);
1189 SelectObject(dc, hp);
1190 Polygon(dc, Line, 4);
1192 Line[1].y++; Line[2].x++;
1193 Line[0].y = Line[1].y + d93;
1194 Line[3].x = Line[2].x + d93;
1195 SelectObject(dc, hb2);
1196 SelectObject(dc, hp2);
1197 Polygon(dc, Line, 4);
1199 i = 210*SmallDiam/750;
1200 Line[0].y = r->bottom - i - 1;
1201 Line[3].x = r->right - i - 1;
1202 Line[1].y = Line[0].y + d46;
1203 Line[2].x = Line[3].x + d46;
1204 SelectObject(dc, hb);
1205 SelectObject(dc, hp);
1206 Polygon(dc, Line, 4);
1208 Line[1].y++; Line[2].x++;
1209 Line[0].y = Line[1].y + d93;
1210 Line[3].x = Line[2].x + d93;
1211 SelectObject(dc, hb2);
1212 SelectObject(dc, hp2);
1213 Polygon(dc, Line, 4);
1215 SelectObject(dc, hpsave);
1216 SelectObject(dc, hbsave);
1223 /* Here do the real scroll-bar controls end up */
1224 if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1225 /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1226 /* want for the normal scroll-arrow button. */
1227 UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1229 UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1231 if(uFlags & DFCS_INACTIVE)
1233 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1234 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
1235 Polygon(dc, Line, 3);
1236 SelectObject(dc, hpsave);
1237 SelectObject(dc, hbsave);
1240 if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1241 for(i = 0; i < 3; i++)
1247 i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1248 hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(i));
1249 hpsave = (HPEN)SelectObject(dc, GetSysColorPen(i));
1250 Polygon(dc, Line, 3);
1251 SelectObject(dc, hpsave);
1252 SelectObject(dc, hbsave);
1257 /* Ported from WINE20020904 */
1258 /* Draw a menu control coming from DrawFrameControl() */
1259 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1263 int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1271 /* Using black and white seems to be utterly wrong, but win95 doesn't */
1272 /* use anything else. I think I tried all sys-colors to change things */
1273 /* without luck. It seems as if this behavior is inherited from the */
1274 /* win31 DFC() implementation... (you remember, B/W menus). */
1276 FillRect(dc, r, (HBRUSH)GetStockObject(WHITE_BRUSH));
1278 hbsave = (HBRUSH)SelectObject(dc, GetStockObject(BLACK_BRUSH));
1279 hpsave = (HPEN)SelectObject(dc, GetStockObject(BLACK_PEN));
1281 switch(uFlags & 0xff)
1283 case DFCS_MENUARROW:
1284 i = 187*SmallDiam/750;
1285 Points[2].x = myr.left + 468*SmallDiam/750;
1286 Points[2].y = myr.top + 352*SmallDiam/750+1;
1287 Points[0].y = Points[2].y - i;
1288 Points[1].y = Points[2].y + i;
1289 Points[0].x = Points[1].x = Points[2].x - i;
1290 Polygon(dc, Points, 3);
1293 case DFCS_MENUBULLET:
1295 ye = myr.top + SmallDiam - SmallDiam/2;
1296 xc = myr.left + SmallDiam - SmallDiam/2;
1297 yc = myr.top + SmallDiam - SmallDiam/2;
1298 i = 234*SmallDiam/750;
1300 myr.left = xc - i+i/2;
1301 myr.right = xc + i/2;
1302 myr.top = yc - i+i/2;
1303 myr.bottom = yc + i/2;
1304 Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1307 case DFCS_MENUCHECK:
1308 Points[0].x = myr.left + 253*SmallDiam/1000;
1309 Points[0].y = myr.top + 445*SmallDiam/1000;
1310 Points[1].x = myr.left + 409*SmallDiam/1000;
1311 Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1312 Points[2].x = myr.left + 690*SmallDiam/1000;
1313 Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1314 Points[3].x = Points[2].x;
1315 Points[3].y = Points[2].y + 3*SmallDiam/16;
1316 Points[4].x = Points[1].x;
1317 Points[4].y = Points[1].y + 3*SmallDiam/16;
1318 Points[5].x = Points[0].x;
1319 Points[5].y = Points[0].y + 3*SmallDiam/16;
1320 Polygon(dc, Points, 6);
1324 DbgPrint("Invalid menu; flags=0x%04x\n", uFlags);
1329 SelectObject(dc, hpsave);
1330 SelectObject(dc, hbsave);
1334 /* Ported from WINE20020904 */
1335 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1338 /* Win95 doesn't support drawing in other mapping modes
1339 if(GetMapMode(hdc) != MM_TEXT)
1345 return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1347 return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1349 return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1355 return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1357 DbgPrint("(%p,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1361 /* Ported from WINE20020904 */
1362 BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
1364 if(flags & BF_DIAGONAL)
1365 return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
1367 return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
1373 INTERNAL_GrayString(
1376 GRAYSTRINGPROC lpOutputFunc,
1385 // AG: Mostly implemented, but probably won't work properly or return
1386 // correct error codes. I doubt it grays strings either... Untested!
1388 BOOL success = FALSE;
1390 HBITMAP MemBMP = NULL,
1392 HBRUSH OldBrush = NULL;
1393 HFONT OldFont = NULL;
1395 COLORREF ForeColor, BackColor;
1397 ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
1398 BackColor = SetBkColor(hDC, RGB(255, 255, 255));
1403 // The documentation is a little vague on what exactly should happen
1404 // here. Something about using the same brush for window text???
1405 hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
1408 if ((nCount == -1) && (! lpOutputFunc))
1413 // TODO: calculate the length (easy enough)
1416 nCount = lstrlenW((WCHAR*)lpData);
1418 nCount = strlen((CHAR*)lpData);
1421 if (! nWidth || ! nHeight)
1424 // TODO: calculate the rect
1427 success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
1429 success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
1431 if (! success) goto cleanup;
1433 if (! nWidth) nWidth = s.cx;
1434 if (! nHeight) nHeight = s.cy;
1437 SetRect(&r, X, Y, X + nWidth, Y + nHeight);
1439 MemDC = CreateCompatibleDC(hDC);
1440 if (! MemDC) goto cleanup;
1441 MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
1442 if (! MemBMP) goto cleanup;
1443 OldBMP = SelectObject(MemDC, MemBMP);
1444 if (! OldBMP) goto cleanup;
1445 OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
1446 if (! OldFont) goto cleanup;
1447 OldBrush = SelectObject(MemDC, hBrush);
1448 if (! OldBrush) goto cleanup;
1450 if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
1452 SetTextColor(MemDC, RGB(255, 255, 255));
1453 SetBkColor(MemDC, RGB(0, 0, 0));
1457 success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
1459 if ((nCount == -1) && (! success))
1461 // Don't gray (documented behaviour)
1462 success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
1469 success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
1471 success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
1473 if (! success) goto cleanup;
1475 PatBlt(MemDC, 0, 0, nWidth, nHeight, PATCOPY);
1476 // This is how WINE does it: (but we should have our own graying brush already)
1477 // hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1478 // PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
1479 // SelectObject(memdc, hbsave);
1482 if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
1485 SetTextColor(hDC, ForeColor);
1486 SetBkColor(hDC, BackColor);
1490 if (OldFont) SelectObject(MemDC, OldFont);
1491 if (OldBrush) SelectObject(MemDC, OldBrush);
1492 if (OldBMP) SelectObject(MemDC, OldBMP);
1493 if (MemBMP) DeleteObject(MemBMP);
1509 GRAYSTRINGPROC lpOutputFunc,
1517 return INTERNAL_GrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
1529 GRAYSTRINGPROC lpOutputFunc,
1537 return INTERNAL_GrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
1551 return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1552 lprc->bottom - lprc->top, DSTINVERT);
1568 CONST LPINT lpnTabStopPositions,
1588 CONST LPINT lpnTabStopPositions,
1608 if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
1609 if (!(oldbrush = SelectObject( hDC, hbr ))) return 0;
1611 PatBlt( hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY );
1612 PatBlt( hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY );
1613 PatBlt( hDC, r.left, r.top, r.right - r.left, 1, PATCOPY );
1614 PatBlt( hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY );
1616 SelectObject( hDC, oldbrush );
1652 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
1655 /*if (hbr <= (HBRUSH)(COLOR_MAX + 1))
1657 hbr = GetSysColorBrush((INT)hbr - 1);
1659 if ((prevhbr = SelectObject(hDC, hbr)) == NULL)
1663 PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
1664 lprc->bottom - lprc->top, PATCOPY);
1665 SelectObject(hDC, prevhbr);
1678 CONST RECT *lprcFrom,
1696 HPEN hOldPen, hNewPen;
1697 INT oldDrawMode, oldBkMode;
1699 hOldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH));
1700 hNewPen = CreatePen(PS_ALTERNATE, 1, GetSysColor(COLOR_WINDOWTEXT));
1701 hOldPen = SelectObject(hDC, hNewPen);
1702 oldDrawMode = SetROP2(hDC, R2_XORPEN);
1703 oldBkMode = SetBkMode(hDC, TRANSPARENT);
1705 Rectangle(hDC, lprc->left, lprc->top, lprc->right, lprc->bottom);
1707 SetBkMode(hDC, oldBkMode);
1708 SetROP2(hDC, oldDrawMode);
1709 SelectObject(hDC, hOldPen);
1710 DeleteObject(hNewPen);
1711 SelectObject(hDC, hOldBrush);
1718 // These are internal functions, based on the WINE sources. Currently they
1719 // are only implemented for DSS_NORMAL and DST_TEXT, although some handling
1720 // for DST_BITMAP has been included.
1722 WINBOOL INTERNAL_DrawStateDraw(HDC hdc, UINT type, DRAWSTATEPROC lpOutputFunc,
1723 LPARAM lData, WPARAM wData, LPRECT rc, UINT dtflags,
1728 BOOL retval = FALSE;
1729 INT cx = rc->right - rc->left;
1730 INT cy = rc->bottom - rc->top;
1732 // Is this supposed to happen?
1733 // if (((type == DST_TEXT) || (type == DST_PREFIXTEXT)) && (lpOutputFunc))
1734 // type = DST_COMPLEX;
1739 case DST_PREFIXTEXT :
1741 DbgPrint("Drawing DST_TEXT\n");
1743 return DrawTextW(hdc, (LPWSTR)lData, (INT)wData, rc, dtflags);
1745 return DrawTextA(hdc, (LPSTR)lData, (INT)wData, rc, dtflags);
1751 DbgPrint("Drawing DST_ICON\n");
1758 DbgPrint("Drawing DST_BITMAP\n");
1764 DbgPrint("Drawing DST_COMPLEX\n");
1765 // Call lpOutputFunc, if necessary
1768 // Something seems to be wrong with OffsetViewportOrgEx:
1769 OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1770 DbgPrint("Calling lpOutputFunc(0x%x, 0x%x, 0x%x, %d, %d)\n", hdc, lData, wData, cx, cy);
1771 retval = lpOutputFunc(hdc, lData, wData, cx, cy);
1772 OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1784 WINBOOL INTERNAL_DrawState(
1787 DRAWSTATEPROC lpOutputFunc,
1801 UINT dtflags = DT_NOCLIP; // Flags for DrawText
1802 BOOL retval = FALSE; // Return value
1804 COLORREF ForeColor, // Foreground color
1805 BackColor; // Background color
1807 HDC MemDC = NULL; // Memory DC
1808 HBITMAP MemBMP = NULL, // Memory bitmap (for MemDC)
1809 OldBMP = NULL; // Old memory bitmap (for MemDC)
1810 HFONT Font = NULL; // Old font (for MemDC)
1811 HBRUSH OldBrush = NULL, // Old brush (for MemDC)
1812 TempBrush = NULL; // Temporary brush (for MemDC)
1814 // AG: Experimental, unfinished, and most likely buggy! I haven't been
1815 // able to test this - my intention was to implement some things needed
1816 // by the button control.
1818 if ((! lpOutputFunc) && (fuFlags & DST_COMPLEX))
1821 type = fuFlags & 0xf; // DST_xxx
1822 state = fuFlags & 0x7ff0; // DSS_xxx
1823 len = wData; // Data length
1825 DbgPrint("Entered DrawState, fuFlags %d, type %d, state %d\n", fuFlags, type, state);
1827 if ((type == DST_TEXT || type == DST_PREFIXTEXT) && ! len)
1829 // The string is NULL-terminated
1831 len = lstrlenW((LPWSTR) lData);
1833 len = strlen((LPSTR) lData);
1836 // Identify the image size if not specified
1840 // CURSORICONINFO *ici;
1843 switch(type) // TODO
1846 case DST_PREFIXTEXT :
1850 DbgPrint("Calculating rect of DST_TEXT / DST_PREFIXTEXT\n");
1853 success = GetTextExtentPoint32W(hdc, (LPWSTR) lData, len, &s);
1855 success = GetTextExtentPoint32A(hdc, (LPSTR) lData, len, &s);
1857 if (!success) return FALSE;
1863 DbgPrint("Calculating rect of DST_ICON\n");
1870 DbgPrint("Calculating rect of DST_BITMAP\n");
1872 if (!GetObjectA((HBITMAP) lData, sizeof(bm), &bm))
1880 case DST_COMPLEX : // cx and cy must be set in this mode
1881 DbgPrint("Calculating rect of DST_COMPLEX - Not allowed!\n");
1885 if (! cx) cx = s.cx;
1886 if (! cy) cy = s.cy;
1889 // Flags for DrawText
1890 if (fuFlags & DSS_RIGHT) // Undocumented
1891 dtflags |= DT_RIGHT;
1892 if (type == DST_TEXT)
1893 dtflags |= DT_NOPREFIX;
1895 // No additional processing needed for DSS_NORMAL
1896 if (state == DSS_NORMAL)
1898 DbgPrint("DSS_NORMAL (no additional processing necessary)\n");
1899 SetRect(&rect, x, y, x + cx, y + cy);
1900 return INTERNAL_DrawStateDraw(hdc, type, lpOutputFunc, lData, wData, &rect, dtflags, unicode);
1903 // WARNING: FROM THIS POINT ON THE CODE IS VERY BUGGY
1905 // Set the rectangle to that of the memory DC
1906 SetRect(&rect, 0, 0, cx, cy);
1909 ForeColor = SetTextColor(hdc, RGB(0, 0, 0));
1910 BackColor = SetBkColor(hdc, RGB(255, 255, 255));
1912 // Create and initialize the memory DC
1913 MemDC = CreateCompatibleDC(hdc);
1914 if (! MemDC) goto cleanup;
1915 MemBMP = CreateBitmap(cx, cy, 1, 1, NULL);
1916 if (! MemBMP) goto cleanup;
1917 OldBMP = (HBITMAP) SelectObject(MemDC, MemBMP);
1918 if (! OldBMP) goto cleanup;
1920 DbgPrint("Created and inited MemDC\n");
1922 // Set up the default colors and font
1923 if (! FillRect(MemDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
1924 SetBkColor(MemDC, RGB(255, 255, 255));
1925 SetTextColor(MemDC, RGB(0, 0, 0));
1926 Font = (HFONT)SelectObject(MemDC, GetCurrentObject(hdc, OBJ_FONT));
1928 DbgPrint("Selected font and set colors\n");
1930 // Enable this line to use the current DC image to begin with (wrong?)
1931 // if (! BitBlt(MemDC, 0, 0, cx, cy, hdc, x, y, SRCCOPY)) goto cleanup;
1933 // DST_COMPLEX may draw text as well, so make sure font is selected
1934 if (! Font && (type <= DST_PREFIXTEXT)) // THIS FAILS
1938 BOOL TempResult = INTERNAL_DrawStateDraw(MemDC, type, lpOutputFunc, lData, wData, &rect, dtflags, unicode);
1939 if (Font) SelectObject(MemDC, Font);
1940 if (! TempResult) goto cleanup;
1943 DbgPrint("Done drawing\n");
1946 if (state & DSS_UNION)
1948 DbgPrint("DSS_UNION\n");
1949 // Dither the image (not implemented in ReactOS yet?)
1953 // Prepare shadow brush
1954 if (state & DSS_DISABLED)
1955 TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1956 // else if (state & DSS_DEFAULT)
1957 // TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1960 if (state & (DSS_DISABLED /*|DSS_DEFAULT*/))
1962 DbgPrint("DSS_DISABLED - Drawing shadow\n");
1963 if (! TempBrush) goto cleanup;
1964 OldBrush = (HBRUSH)SelectObject(hdc, TempBrush);
1965 if (! OldBrush) goto cleanup;
1966 if (! BitBlt(hdc, x + 1, y + 1, cx, cy, MemDC, 0, 0, 0x00B8074A)) goto cleanup;
1967 SelectObject(hdc, OldBrush);
1968 DeleteObject(TempBrush);
1972 if (state & DSS_DISABLED)
1974 DbgPrint("DSS_DISABLED - Creating shadow brush 2\n");
1975 hbr = TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1976 if (! TempBrush) goto cleanup;
1980 DbgPrint("Creating a brush\n");
1981 hbr = (HBRUSH) GetStockObject(BLACK_BRUSH);
1984 DbgPrint("Selecting new brush\n");
1985 OldBrush = (HBRUSH) SelectObject(hdc, hbr);
1987 // Copy to hdc from MemDC
1988 DbgPrint("Blitting\n");
1989 if (! BitBlt(hdc, x, y, cx, cy, MemDC, 0, 0, 0x00B8074A)) goto cleanup;
1995 DbgPrint("In cleanup : Font %x OldBrush %x OldBMP %x Tempbrush %x MemBMP %x MemDC %x\n",
1996 Font, OldBrush, OldBMP, TempBrush, MemBMP, MemDC);
1997 SetTextColor(hdc, ForeColor);
1998 SetBkColor(hdc, BackColor);
1999 if (OldBrush) SelectObject(MemDC, OldBrush);
2000 if (OldBMP) SelectObject(MemDC, OldBMP);
2001 if (TempBrush) DeleteObject(TempBrush);
2002 if (MemBMP) DeleteObject(MemBMP);
2003 if (MemDC) DeleteDC(MemDC);
2005 DbgPrint("Leaving DrawState() with retval %d\n", retval);
2019 DRAWSTATEPROC lpOutputFunc,
2028 return INTERNAL_DrawState(hdc, hbr, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
2040 DRAWSTATEPROC lpOutputFunc,
2049 return INTERNAL_DrawState(hdc, hbr, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);