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