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