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