1 /* 2 * Static control 3 * 4 * Copyright David W. Metcalfe, 1993 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 * Notes: 21 * - Windows XP introduced new behavior: The background of centered 22 * icons and bitmaps is painted differently. This is only done if 23 * a manifest is present. 24 * Because it has not yet been decided how to implement the two 25 * different modes in Wine, only the Windows XP mode is implemented. 26 * - Controls with SS_SIMPLE but without SS_NOPREFIX: 27 * The text should not be changed. Windows doesn't clear the 28 * client rectangle, so the new text must be larger than the old one. 29 * - The SS_RIGHTJUST style is currently not implemented by Windows 30 * (or it does something different than documented). 31 * 32 * TODO: 33 * - Animated cursors 34 */ 35 36 #include <stdarg.h> 37 38 #include "windef.h" 39 #include "winbase.h" 40 #include "wingdi.h" 41 #include "winuser.h" 42 #include "commctrl.h" 43 44 #include "wine/debug.h" 45 46 #include "comctl32.h" 47 48 WINE_DEFAULT_DEBUG_CHANNEL(static); 49 50 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style ); 51 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style ); 52 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style ); 53 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style ); 54 static void STATIC_PaintBitmapfn( HWND hwnd, HDC hdc, DWORD style ); 55 static void STATIC_PaintEnhMetafn( HWND hwnd, HDC hdc, DWORD style ); 56 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style ); 57 58 /* offsets for GetWindowLong for static private information */ 59 #define HFONT_GWL_OFFSET 0 60 #define HICON_GWL_OFFSET (sizeof(HFONT)) 61 #define STATIC_EXTRA_BYTES (HICON_GWL_OFFSET + sizeof(HICON)) 62 63 typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style ); 64 65 static const pfPaint staticPaintFunc[SS_TYPEMASK+1] = 66 { 67 STATIC_PaintTextfn, /* SS_LEFT */ 68 STATIC_PaintTextfn, /* SS_CENTER */ 69 STATIC_PaintTextfn, /* SS_RIGHT */ 70 STATIC_PaintIconfn, /* SS_ICON */ 71 STATIC_PaintRectfn, /* SS_BLACKRECT */ 72 STATIC_PaintRectfn, /* SS_GRAYRECT */ 73 STATIC_PaintRectfn, /* SS_WHITERECT */ 74 STATIC_PaintRectfn, /* SS_BLACKFRAME */ 75 STATIC_PaintRectfn, /* SS_GRAYFRAME */ 76 STATIC_PaintRectfn, /* SS_WHITEFRAME */ 77 NULL, /* SS_USERITEM */ 78 STATIC_PaintTextfn, /* SS_SIMPLE */ 79 STATIC_PaintTextfn, /* SS_LEFTNOWORDWRAP */ 80 STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */ 81 STATIC_PaintBitmapfn, /* SS_BITMAP */ 82 STATIC_PaintEnhMetafn, /* SS_ENHMETAFILE */ 83 STATIC_PaintEtchedfn, /* SS_ETCHEDHORZ */ 84 STATIC_PaintEtchedfn, /* SS_ETCHEDVERT */ 85 STATIC_PaintEtchedfn, /* SS_ETCHEDFRAME */ 86 }; 87 88 static BOOL get_icon_size( HICON handle, SIZE *size ) 89 { 90 ICONINFO info; 91 BITMAP bmp; 92 int ret; 93 94 if (!GetIconInfo(handle, &info)) 95 return FALSE; 96 97 ret = GetObjectW(info.hbmColor, sizeof(bmp), &bmp); 98 if (ret) 99 { 100 size->cx = bmp.bmWidth; 101 size->cy = bmp.bmHeight; 102 } 103 104 DeleteObject(info.hbmMask); 105 DeleteObject(info.hbmColor); 106 107 return !!ret; 108 } 109 110 /*********************************************************************** 111 * STATIC_SetIcon 112 * 113 * Set the icon for an SS_ICON control. 114 */ 115 static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style ) 116 { 117 HICON prevIcon; 118 SIZE size; 119 120 if ((style & SS_TYPEMASK) != SS_ICON) return 0; 121 if (hicon && !get_icon_size( hicon, &size )) 122 { 123 WARN("hicon != 0, but invalid\n"); 124 return 0; 125 } 126 prevIcon = (HICON)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hicon ); 127 if (hicon && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL)) 128 { 129 /* Windows currently doesn't implement SS_RIGHTJUST */ 130 /* 131 if ((style & SS_RIGHTJUST) != 0) 132 { 133 RECT wr; 134 GetWindowRect(hwnd, &wr); 135 SetWindowPos( hwnd, 0, wr.right - info->nWidth, wr.bottom - info->nHeight, 136 info->nWidth, info->nHeight, SWP_NOACTIVATE | SWP_NOZORDER ); 137 } 138 else */ 139 { 140 SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); 141 } 142 } 143 return prevIcon; 144 } 145 146 /*********************************************************************** 147 * STATIC_SetBitmap 148 * 149 * Set the bitmap for an SS_BITMAP control. 150 */ 151 static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style ) 152 { 153 HBITMAP hOldBitmap; 154 155 if ((style & SS_TYPEMASK) != SS_BITMAP) return 0; 156 if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP) 157 { 158 WARN("hBitmap != 0, but it's not a bitmap\n"); 159 return 0; 160 } 161 hOldBitmap = (HBITMAP)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hBitmap ); 162 if (hBitmap && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL)) 163 { 164 BITMAP bm; 165 GetObjectW(hBitmap, sizeof(bm), &bm); 166 /* Windows currently doesn't implement SS_RIGHTJUST */ 167 /* 168 if ((style & SS_RIGHTJUST) != 0) 169 { 170 RECT wr; 171 GetWindowRect(hwnd, &wr); 172 SetWindowPos( hwnd, 0, wr.right - bm.bmWidth, wr.bottom - bm.bmHeight, 173 bm.bmWidth, bm.bmHeight, SWP_NOACTIVATE | SWP_NOZORDER ); 174 } 175 else */ 176 { 177 SetWindowPos( hwnd, 0, 0, 0, bm.bmWidth, bm.bmHeight, 178 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER ); 179 } 180 } 181 return hOldBitmap; 182 } 183 184 /*********************************************************************** 185 * STATIC_SetEnhMetaFile 186 * 187 * Set the enhanced metafile for an SS_ENHMETAFILE control. 188 */ 189 static HENHMETAFILE STATIC_SetEnhMetaFile( HWND hwnd, HENHMETAFILE hEnhMetaFile, DWORD style ) 190 { 191 if ((style & SS_TYPEMASK) != SS_ENHMETAFILE) return 0; 192 if (hEnhMetaFile && GetObjectType(hEnhMetaFile) != OBJ_ENHMETAFILE) 193 { 194 WARN("hEnhMetaFile != 0, but it's not an enhanced metafile\n"); 195 return 0; 196 } 197 return (HENHMETAFILE)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hEnhMetaFile ); 198 } 199 200 /*********************************************************************** 201 * STATIC_GetImage 202 * 203 * Gets the bitmap for an SS_BITMAP control, the icon/cursor for an 204 * SS_ICON control or the enhanced metafile for an SS_ENHMETAFILE control. 205 */ 206 static HANDLE STATIC_GetImage( HWND hwnd, WPARAM wParam, DWORD style ) 207 { 208 switch (style & SS_TYPEMASK) 209 { 210 case SS_ICON: 211 if ((wParam != IMAGE_ICON) && 212 (wParam != IMAGE_CURSOR)) return NULL; 213 break; 214 case SS_BITMAP: 215 if (wParam != IMAGE_BITMAP) return NULL; 216 break; 217 case SS_ENHMETAFILE: 218 if (wParam != IMAGE_ENHMETAFILE) return NULL; 219 break; 220 default: 221 return NULL; 222 } 223 return (HANDLE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ); 224 } 225 226 /*********************************************************************** 227 * STATIC_LoadIconW 228 * 229 * Load the icon for an SS_ICON control. 230 */ 231 static HICON STATIC_LoadIconW( HINSTANCE hInstance, LPCWSTR name, DWORD style ) 232 { 233 HICON hicon = 0; 234 235 if (hInstance && ((ULONG_PTR)hInstance >> 16)) 236 { 237 if ((style & SS_REALSIZEIMAGE) != 0) 238 hicon = LoadImageW(hInstance, name, IMAGE_ICON, 0, 0, LR_SHARED); 239 else 240 { 241 hicon = LoadIconW( hInstance, name ); 242 if (!hicon) hicon = LoadCursorW( hInstance, name ); 243 } 244 } 245 if (!hicon) hicon = LoadIconW( 0, name ); 246 /* Windows doesn't try to load a standard cursor, 247 probably because most IDs for standard cursors conflict 248 with the IDs for standard icons anyway */ 249 return hicon; 250 } 251 252 /*********************************************************************** 253 * STATIC_TryPaintFcn 254 * 255 * Try to immediately paint the control. 256 */ 257 static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style) 258 { 259 LONG style = full_style & SS_TYPEMASK; 260 RECT rc; 261 262 GetClientRect( hwnd, &rc ); 263 if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style]) 264 { 265 HDC hdc; 266 HRGN hrgn; 267 268 hdc = GetDC( hwnd ); 269 hrgn = set_control_clipping( hdc, &rc ); 270 (staticPaintFunc[style])( hwnd, hdc, full_style ); 271 SelectClipRgn( hdc, hrgn ); 272 if (hrgn) DeleteObject( hrgn ); 273 ReleaseDC( hwnd, hdc ); 274 } 275 } 276 277 static HBRUSH STATIC_SendWmCtlColorStatic(HWND hwnd, HDC hdc) 278 { 279 HBRUSH hBrush; 280 HWND parent = GetParent(hwnd); 281 282 if (!parent) parent = hwnd; 283 hBrush = (HBRUSH) SendMessageW( parent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd ); 284 if (!hBrush) /* did the app forget to call DefWindowProc ? */ 285 { 286 /* FIXME: DefWindowProc should return different colors if a 287 manifest is present */ 288 hBrush = (HBRUSH)DefWindowProcW( parent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd); 289 } 290 return hBrush; 291 } 292 293 /*********************************************************************** 294 * hasTextStyle 295 * 296 * Tests if the control displays text. 297 */ 298 static BOOL hasTextStyle( DWORD style ) 299 { 300 switch (style & SS_TYPEMASK) 301 { 302 case SS_SIMPLE: 303 case SS_LEFT: 304 case SS_LEFTNOWORDWRAP: 305 case SS_CENTER: 306 case SS_RIGHT: 307 case SS_OWNERDRAW: 308 return TRUE; 309 } 310 311 return FALSE; 312 } 313 314 static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 315 { 316 LRESULT lResult = 0; 317 LONG full_style = GetWindowLongW( hwnd, GWL_STYLE ); 318 LONG style = full_style & SS_TYPEMASK; 319 320 if (!IsWindow( hwnd )) return 0; 321 322 switch (uMsg) 323 { 324 case WM_CREATE: 325 if (style < 0L || style > SS_TYPEMASK) 326 { 327 ERR("Unknown style 0x%02x\n", style ); 328 return -1; 329 } 330 break; 331 332 case WM_NCDESTROY: 333 if (style == SS_ICON) 334 { 335 /* 336 * FIXME 337 * DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) ); 338 * 339 * We don't want to do this yet because DestroyIcon32 is broken. If the icon 340 * had already been loaded by the application the last thing we want to do is 341 * GlobalFree16 the handle. 342 */ 343 break; 344 } 345 else 346 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 347 348 case WM_ERASEBKGND: 349 /* do all painting in WM_PAINT like Windows does */ 350 return 1; 351 352 case WM_PRINTCLIENT: 353 case WM_PAINT: 354 { 355 PAINTSTRUCT ps; 356 RECT rect; 357 HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps); 358 GetClientRect( hwnd, &rect ); 359 if (staticPaintFunc[style]) 360 { 361 HRGN hrgn = set_control_clipping( hdc, &rect ); 362 (staticPaintFunc[style])( hwnd, hdc, full_style ); 363 SelectClipRgn( hdc, hrgn ); 364 if (hrgn) DeleteObject( hrgn ); 365 } 366 if (!wParam) EndPaint(hwnd, &ps); 367 } 368 break; 369 370 case WM_ENABLE: 371 STATIC_TryPaintFcn( hwnd, full_style ); 372 if (full_style & SS_NOTIFY) 373 { 374 if (wParam) 375 SendMessageW( GetParent(hwnd), WM_COMMAND, 376 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_ENABLE ), (LPARAM)hwnd); 377 else 378 SendMessageW( GetParent(hwnd), WM_COMMAND, 379 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DISABLE ), (LPARAM)hwnd); 380 } 381 break; 382 383 case WM_SYSCOLORCHANGE: 384 COMCTL32_RefreshSysColors(); 385 STATIC_TryPaintFcn( hwnd, full_style ); 386 break; 387 388 case WM_NCCREATE: 389 { 390 CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam; 391 392 if (full_style & SS_SUNKEN) 393 SetWindowLongW( hwnd, GWL_EXSTYLE, 394 GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_STATICEDGE ); 395 396 switch (style) 397 { 398 case SS_ICON: 399 { 400 HICON hIcon; 401 402 hIcon = STATIC_LoadIconW(cs->hInstance, cs->lpszName, full_style); 403 STATIC_SetIcon(hwnd, hIcon, full_style); 404 } 405 break; 406 case SS_BITMAP: 407 if ((ULONG_PTR)cs->hInstance >> 16) 408 { 409 HBITMAP hBitmap; 410 hBitmap = LoadBitmapW(cs->hInstance, cs->lpszName); 411 STATIC_SetBitmap(hwnd, hBitmap, full_style); 412 } 413 break; 414 } 415 /* SS_ENHMETAFILE: Despite what MSDN says, Windows does not load 416 the enhanced metafile that was specified as the window text. */ 417 } 418 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 419 420 case WM_SETTEXT: 421 if (hasTextStyle( full_style )) 422 { 423 lResult = DefWindowProcW( hwnd, uMsg, wParam, lParam ); 424 STATIC_TryPaintFcn( hwnd, full_style ); 425 } 426 break; 427 428 case WM_SETFONT: 429 if (hasTextStyle( full_style )) 430 { 431 SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, wParam ); 432 if (LOWORD(lParam)) 433 RedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN ); 434 } 435 break; 436 437 case WM_GETFONT: 438 return GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET ); 439 440 case WM_NCHITTEST: 441 if (full_style & SS_NOTIFY) 442 return HTCLIENT; 443 else 444 return HTTRANSPARENT; 445 446 case WM_GETDLGCODE: 447 return DLGC_STATIC; 448 449 case WM_LBUTTONDOWN: 450 case WM_NCLBUTTONDOWN: 451 if (full_style & SS_NOTIFY) 452 SendMessageW( GetParent(hwnd), WM_COMMAND, 453 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_CLICKED ), (LPARAM)hwnd); 454 return 0; 455 456 case WM_LBUTTONDBLCLK: 457 case WM_NCLBUTTONDBLCLK: 458 if (full_style & SS_NOTIFY) 459 SendMessageW( GetParent(hwnd), WM_COMMAND, 460 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DBLCLK ), (LPARAM)hwnd); 461 return 0; 462 463 case STM_GETIMAGE: 464 return (LRESULT)STATIC_GetImage( hwnd, wParam, full_style ); 465 466 case STM_GETICON: 467 return (LRESULT)STATIC_GetImage( hwnd, IMAGE_ICON, full_style ); 468 469 case STM_SETIMAGE: 470 switch (wParam) 471 { 472 case IMAGE_BITMAP: 473 lResult = (LRESULT)STATIC_SetBitmap( hwnd, (HBITMAP)lParam, full_style ); 474 break; 475 case IMAGE_ENHMETAFILE: 476 lResult = (LRESULT)STATIC_SetEnhMetaFile( hwnd, (HENHMETAFILE)lParam, full_style ); 477 break; 478 case IMAGE_ICON: 479 case IMAGE_CURSOR: 480 lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)lParam, full_style ); 481 break; 482 default: 483 FIXME("STM_SETIMAGE: Unhandled type %lx\n", wParam); 484 break; 485 } 486 STATIC_TryPaintFcn( hwnd, full_style ); 487 break; 488 489 case STM_SETICON: 490 lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)wParam, full_style ); 491 STATIC_TryPaintFcn( hwnd, full_style ); 492 break; 493 494 default: 495 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 496 } 497 return lResult; 498 } 499 500 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style ) 501 { 502 DRAWITEMSTRUCT dis; 503 HFONT font, oldFont = NULL; 504 UINT id = (UINT)GetWindowLongPtrW( hwnd, GWLP_ID ); 505 506 dis.CtlType = ODT_STATIC; 507 dis.CtlID = id; 508 dis.itemID = 0; 509 dis.itemAction = ODA_DRAWENTIRE; 510 dis.itemState = IsWindowEnabled(hwnd) ? 0 : ODS_DISABLED; 511 dis.hwndItem = hwnd; 512 dis.hDC = hdc; 513 dis.itemData = 0; 514 GetClientRect( hwnd, &dis.rcItem ); 515 516 font = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET ); 517 if (font) oldFont = SelectObject( hdc, font ); 518 SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd ); 519 SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis ); 520 if (font) SelectObject( hdc, oldFont ); 521 } 522 523 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style ) 524 { 525 RECT rc; 526 HBRUSH hBrush; 527 HFONT hFont, hOldFont = NULL; 528 UINT format; 529 INT len, buf_size; 530 WCHAR *text; 531 532 GetClientRect( hwnd, &rc); 533 534 switch (style & SS_TYPEMASK) 535 { 536 case SS_LEFT: 537 format = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK; 538 break; 539 540 case SS_CENTER: 541 format = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK; 542 break; 543 544 case SS_RIGHT: 545 format = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK; 546 break; 547 548 case SS_SIMPLE: 549 format = DT_LEFT | DT_SINGLELINE; 550 break; 551 552 case SS_LEFTNOWORDWRAP: 553 format = DT_LEFT | DT_EXPANDTABS; 554 break; 555 556 default: 557 return; 558 } 559 560 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_RIGHT) 561 format = DT_RIGHT | (format & ~(DT_LEFT | DT_CENTER)); 562 563 if (style & SS_NOPREFIX) 564 format |= DT_NOPREFIX; 565 566 if ((style & SS_TYPEMASK) != SS_SIMPLE) 567 { 568 if (style & SS_CENTERIMAGE) 569 format |= DT_SINGLELINE | DT_VCENTER; 570 if (style & SS_EDITCONTROL) 571 format |= DT_EDITCONTROL; 572 if (style & SS_ENDELLIPSIS) 573 format |= DT_SINGLELINE | DT_END_ELLIPSIS; 574 if (style & SS_PATHELLIPSIS) 575 format |= DT_SINGLELINE | DT_PATH_ELLIPSIS; 576 if (style & SS_WORDELLIPSIS) 577 format |= DT_SINGLELINE | DT_WORD_ELLIPSIS; 578 } 579 580 if ((hFont = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET ))) 581 hOldFont = SelectObject( hdc, hFont ); 582 583 /* SS_SIMPLE controls: WM_CTLCOLORSTATIC is sent, but the returned 584 brush is not used */ 585 hBrush = STATIC_SendWmCtlColorStatic(hwnd, hdc); 586 587 if ((style & SS_TYPEMASK) != SS_SIMPLE) 588 { 589 FillRect( hdc, &rc, hBrush ); 590 if (!IsWindowEnabled(hwnd)) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); 591 } 592 593 buf_size = 256; 594 if (!(text = HeapAlloc( GetProcessHeap(), 0, buf_size * sizeof(WCHAR) ))) 595 goto no_TextOut; 596 597 while ((len = InternalGetWindowText( hwnd, text, buf_size )) == buf_size - 1) 598 { 599 buf_size *= 2; 600 if (!(text = HeapReAlloc( GetProcessHeap(), 0, text, buf_size * sizeof(WCHAR) ))) 601 goto no_TextOut; 602 } 603 604 if (!len) goto no_TextOut; 605 606 if (((style & SS_TYPEMASK) == SS_SIMPLE) && (style & SS_NOPREFIX)) 607 { 608 /* Windows uses the faster ExtTextOut() to draw the text and 609 to paint the whole client rectangle with the text background 610 color. Reference: "Static Controls" by Kyle Marsh, 1992 */ 611 ExtTextOutW( hdc, rc.left, rc.top, ETO_CLIPPED | ETO_OPAQUE, 612 &rc, text, len, NULL ); 613 } 614 else 615 { 616 DrawTextW( hdc, text, -1, &rc, format ); 617 } 618 619 no_TextOut: 620 HeapFree( GetProcessHeap(), 0, text ); 621 622 if (hFont) 623 SelectObject( hdc, hOldFont ); 624 } 625 626 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style ) 627 { 628 RECT rc; 629 HBRUSH hBrush; 630 631 GetClientRect( hwnd, &rc); 632 633 /* FIXME: send WM_CTLCOLORSTATIC */ 634 switch (style & SS_TYPEMASK) 635 { 636 case SS_BLACKRECT: 637 hBrush = CreateSolidBrush(comctl32_color.clr3dDkShadow); 638 FillRect( hdc, &rc, hBrush ); 639 break; 640 case SS_GRAYRECT: 641 hBrush = CreateSolidBrush(comctl32_color.clr3dShadow); 642 FillRect( hdc, &rc, hBrush ); 643 break; 644 case SS_WHITERECT: 645 hBrush = CreateSolidBrush(comctl32_color.clr3dHilight); 646 FillRect( hdc, &rc, hBrush ); 647 break; 648 case SS_BLACKFRAME: 649 hBrush = CreateSolidBrush(comctl32_color.clr3dDkShadow); 650 FrameRect( hdc, &rc, hBrush ); 651 break; 652 case SS_GRAYFRAME: 653 hBrush = CreateSolidBrush(comctl32_color.clr3dShadow); 654 FrameRect( hdc, &rc, hBrush ); 655 break; 656 case SS_WHITEFRAME: 657 hBrush = CreateSolidBrush(comctl32_color.clr3dHilight); 658 FrameRect( hdc, &rc, hBrush ); 659 break; 660 default: 661 return; 662 } 663 DeleteObject( hBrush ); 664 } 665 666 667 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style ) 668 { 669 RECT rc, iconRect; 670 HBRUSH hbrush; 671 HICON hIcon; 672 SIZE size; 673 674 GetClientRect( hwnd, &rc ); 675 hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc); 676 hIcon = (HICON)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ); 677 if (!hIcon || !get_icon_size( hIcon, &size )) 678 { 679 FillRect(hdc, &rc, hbrush); 680 } 681 else 682 { 683 if (style & SS_CENTERIMAGE) 684 { 685 iconRect.left = (rc.right - rc.left) / 2 - size.cx / 2; 686 iconRect.top = (rc.bottom - rc.top) / 2 - size.cy / 2; 687 iconRect.right = iconRect.left + size.cx; 688 iconRect.bottom = iconRect.top + size.cy; 689 } 690 else 691 iconRect = rc; 692 FillRect( hdc, &rc, hbrush ); 693 DrawIconEx( hdc, iconRect.left, iconRect.top, hIcon, iconRect.right - iconRect.left, 694 iconRect.bottom - iconRect.top, 0, NULL, DI_NORMAL ); 695 } 696 } 697 698 static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style ) 699 { 700 HDC hMemDC; 701 HBITMAP hBitmap, oldbitmap; 702 HBRUSH hbrush; 703 704 /* message is still sent, even if the returned brush is not used */ 705 hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc); 706 707 if ((hBitmap = (HBITMAP)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET )) 708 && (GetObjectType(hBitmap) == OBJ_BITMAP) 709 && (hMemDC = CreateCompatibleDC( hdc ))) 710 { 711 BITMAP bm; 712 RECT rcClient; 713 LOGBRUSH brush; 714 715 GetObjectW(hBitmap, sizeof(bm), &bm); 716 oldbitmap = SelectObject(hMemDC, hBitmap); 717 718 /* Set the background color for monochrome bitmaps 719 to the color of the background brush */ 720 if (GetObjectW( hbrush, sizeof(brush), &brush )) 721 { 722 if (brush.lbStyle == BS_SOLID) 723 SetBkColor(hdc, brush.lbColor); 724 } 725 GetClientRect(hwnd, &rcClient); 726 if (style & SS_CENTERIMAGE) 727 { 728 FillRect( hdc, &rcClient, hbrush ); 729 rcClient.left = (rcClient.right - rcClient.left)/2 - bm.bmWidth/2; 730 rcClient.top = (rcClient.bottom - rcClient.top)/2 - bm.bmHeight/2; 731 rcClient.right = rcClient.left + bm.bmWidth; 732 rcClient.bottom = rcClient.top + bm.bmHeight; 733 } 734 StretchBlt(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left, 735 rcClient.bottom - rcClient.top, hMemDC, 736 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); 737 SelectObject(hMemDC, oldbitmap); 738 DeleteDC(hMemDC); 739 } 740 } 741 742 static void STATIC_PaintEnhMetafn(HWND hwnd, HDC hdc, DWORD style ) 743 { 744 HENHMETAFILE hEnhMetaFile; 745 RECT rc; 746 HBRUSH hbrush; 747 748 GetClientRect(hwnd, &rc); 749 hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc); 750 FillRect(hdc, &rc, hbrush); 751 if ((hEnhMetaFile = (HENHMETAFILE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ))) 752 { 753 /* The control's current font is not selected into the 754 device context! */ 755 if (GetObjectType(hEnhMetaFile) == OBJ_ENHMETAFILE) 756 PlayEnhMetaFile(hdc, hEnhMetaFile, &rc); 757 } 758 } 759 760 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style ) 761 { 762 RECT rc; 763 764 /* FIXME: sometimes (not always) sends WM_CTLCOLORSTATIC */ 765 GetClientRect( hwnd, &rc ); 766 switch (style & SS_TYPEMASK) 767 { 768 case SS_ETCHEDHORZ: 769 DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOP | BF_BOTTOM); 770 break; 771 case SS_ETCHEDVERT: 772 DrawEdge(hdc, &rc, EDGE_ETCHED, BF_LEFT | BF_RIGHT); 773 break; 774 case SS_ETCHEDFRAME: 775 DrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT); 776 break; 777 } 778 } 779 780 void STATIC_Register(void) 781 { 782 WNDCLASSW wndClass; 783 784 memset(&wndClass, 0, sizeof(wndClass)); 785 wndClass.style = CS_DBLCLKS | CS_PARENTDC | CS_GLOBALCLASS; 786 wndClass.lpfnWndProc = STATIC_WindowProc; 787 wndClass.cbClsExtra = 0; 788 wndClass.cbWndExtra = STATIC_EXTRA_BYTES; 789 wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); 790 wndClass.hbrBackground = NULL; 791 wndClass.lpszClassName = WC_STATICW; 792 RegisterClassW(&wndClass); 793 } 794 795 #ifdef __REACTOS__ 796 void STATIC_Unregister(void) 797 { 798 UnregisterClassW(WC_STATICW, NULL); 799 } 800 #endif 801