1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS uxtheme.dll 4 * FILE: dll/win32/uxtheme/ncscrollbar.c 5 * PURPOSE: uxtheme scrollbar support 6 * PROGRAMMER: Giannis Adamopoulos 7 * This file is heavily based on code from the wine project: 8 * Copyright 1993 Martin Ayotte 9 * Copyright 1994, 1996 Alexandre Julliard 10 */ 11 12 #include "uxthemep.h" 13 14 #include <assert.h> 15 16 static void ScreenToWindow( HWND hWnd, POINT* pt) 17 { 18 RECT rcWnd; 19 GetWindowRect(hWnd, &rcWnd); 20 pt->x -= rcWnd.left; 21 pt->y -= rcWnd.top; 22 } 23 24 static BOOL SCROLL_IsVertical(HWND hwnd, INT nBar) 25 { 26 switch(nBar) 27 { 28 case SB_HORZ: 29 return FALSE; 30 case SB_VERT: 31 return TRUE; 32 default: 33 assert(FALSE); 34 return FALSE; 35 } 36 } 37 38 static LONG SCROLL_getObjectId(INT nBar) 39 { 40 switch(nBar) 41 { 42 case SB_HORZ: 43 return OBJID_HSCROLL; 44 case SB_VERT: 45 return OBJID_VSCROLL; 46 default: 47 assert(FALSE); 48 return 0; 49 } 50 } 51 52 /*********************************************************************** 53 * SCROLL_PtInRectEx 54 */ 55 static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical ) 56 { 57 RECT rect = *lpRect; 58 int scrollbarWidth; 59 60 /* Pad hit rect to allow mouse to be dragged outside of scrollbar and 61 * still be considered in the scrollbar. */ 62 if (vertical) 63 { 64 scrollbarWidth = lpRect->right - lpRect->left; 65 rect.left -= scrollbarWidth*8; 66 rect.right += scrollbarWidth*8; 67 rect.top -= scrollbarWidth*2; 68 rect.bottom += scrollbarWidth*2; 69 } 70 else 71 { 72 scrollbarWidth = lpRect->bottom - lpRect->top; 73 rect.left -= scrollbarWidth*2; 74 rect.right += scrollbarWidth*2; 75 rect.top -= scrollbarWidth*8; 76 rect.bottom += scrollbarWidth*8; 77 } 78 return PtInRect( &rect, pt ); 79 } 80 81 82 /*********************************************************************** 83 * SCROLL_HitTest 84 * 85 * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!). 86 */ 87 static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, SCROLLBARINFO* psbi, BOOL vertical, 88 POINT pt, BOOL bDragging ) 89 { 90 if ( (bDragging && !SCROLL_PtInRectEx( &psbi->rcScrollBar, pt, vertical )) || 91 (!PtInRect( &psbi->rcScrollBar, pt )) ) 92 { 93 return SCROLL_NOWHERE; 94 } 95 96 if (vertical) 97 { 98 if (pt.y < psbi->rcScrollBar.top + psbi->dxyLineButton) 99 return SCROLL_TOP_ARROW; 100 if (pt.y >= psbi->rcScrollBar.bottom - psbi->dxyLineButton) 101 return SCROLL_BOTTOM_ARROW; 102 if (!psbi->xyThumbTop) 103 return SCROLL_TOP_RECT; 104 pt.y -= psbi->rcScrollBar.top; 105 if (pt.y < psbi->xyThumbTop) 106 return SCROLL_TOP_RECT; 107 if (pt.y >= psbi->xyThumbBottom) 108 return SCROLL_BOTTOM_RECT; 109 } 110 else /* horizontal */ 111 { 112 if (pt.x < psbi->rcScrollBar.left + psbi->dxyLineButton) 113 return SCROLL_TOP_ARROW; 114 if (pt.x >= psbi->rcScrollBar.right - psbi->dxyLineButton) 115 return SCROLL_BOTTOM_ARROW; 116 if (!psbi->xyThumbTop) 117 return SCROLL_TOP_RECT; 118 pt.x -= psbi->rcScrollBar.left; 119 if (pt.x < psbi->xyThumbTop) 120 return SCROLL_TOP_RECT; 121 if (pt.x >= psbi->xyThumbBottom) 122 return SCROLL_BOTTOM_RECT; 123 } 124 return SCROLL_THUMB; 125 } 126 127 static void SCROLL_ThemeDrawPart(PDRAW_CONTEXT pcontext, int iPartId,int iStateId, SCROLLBARINFO* psbi, int htCurrent, int htDown, int htHot, RECT* r) 128 { 129 if (r->right <= r->left || r->bottom <= r->top) 130 return; 131 132 if(psbi->rgstate[htCurrent] & STATE_SYSTEM_UNAVAILABLE) 133 iStateId += BUTTON_DISABLED - BUTTON_NORMAL; 134 else if (htHot == htCurrent) 135 iStateId += BUTTON_HOT - BUTTON_NORMAL; 136 else if (htDown == htCurrent) 137 iStateId += BUTTON_PRESSED - BUTTON_NORMAL; 138 139 DrawThemeBackground(pcontext->scrolltheme, pcontext->hDC, iPartId, iStateId, r, NULL); 140 } 141 142 /*********************************************************************** 143 * SCROLL_DrawArrows 144 * 145 * Draw the scroll bar arrows. 146 */ 147 static void SCROLL_DrawArrows( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi, 148 BOOL vertical, int htDown, int htHot ) 149 { 150 RECT r; 151 int iStateId; 152 153 r = psbi->rcScrollBar; 154 if( vertical ) 155 { 156 r.bottom = r.top + psbi->dxyLineButton; 157 iStateId = ABS_UPNORMAL; 158 } 159 else 160 { 161 r.right = r.left + psbi->dxyLineButton; 162 iStateId = ABS_LEFTNORMAL; 163 } 164 165 SCROLL_ThemeDrawPart(pcontext, SBP_ARROWBTN, iStateId, psbi, SCROLL_TOP_ARROW, htDown, htHot, &r); 166 167 r = psbi->rcScrollBar; 168 if( vertical ) 169 { 170 r.top = r.bottom - psbi->dxyLineButton; 171 iStateId = ABS_DOWNNORMAL; 172 } 173 else 174 { 175 iStateId = ABS_RIGHTNORMAL; 176 r.left = r.right - psbi->dxyLineButton; 177 } 178 179 SCROLL_ThemeDrawPart(pcontext, SBP_ARROWBTN, iStateId, psbi, SCROLL_BOTTOM_ARROW, htDown, htHot, &r); 180 } 181 182 static void SCROLL_DrawInterior( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi, 183 INT thumbPos, BOOL vertical, 184 int htDown, int htHot ) 185 { 186 RECT r, rcPart; 187 188 /* thumbPos is relative to the edge of the scrollbar */ 189 190 r = psbi->rcScrollBar; 191 if (vertical) 192 { 193 if (thumbPos) 194 thumbPos += pcontext->wi.rcClient.top - pcontext->wi.rcWindow.top; 195 r.top += psbi->dxyLineButton; 196 r.bottom -= (psbi->dxyLineButton); 197 } 198 else 199 { 200 if (thumbPos) 201 thumbPos += pcontext->wi.rcClient.left - pcontext->wi.rcWindow.left; 202 r.left += psbi->dxyLineButton; 203 r.right -= psbi->dxyLineButton; 204 } 205 206 if (r.right <= r.left || r.bottom <= r.top) 207 return; 208 209 /* Draw the scroll rectangles and thumb */ 210 211 if (!thumbPos) /* No thumb to draw */ 212 { 213 rcPart = r; 214 SCROLL_ThemeDrawPart(pcontext, vertical ? SBP_UPPERTRACKVERT: SBP_UPPERTRACKHORZ , BUTTON_NORMAL, psbi, SCROLL_THUMB, 0, 0, &rcPart); 215 return; 216 } 217 218 /* Some themes have different bitmaps for the upper and lower tracks 219 It seems that windows use the bitmap for the lower track in the upper track */ 220 if (vertical) 221 { 222 rcPart = r; 223 rcPart.bottom = thumbPos; 224 SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKVERT, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart); 225 r.top = rcPart.bottom; 226 227 rcPart = r; 228 rcPart.top += psbi->xyThumbBottom - psbi->xyThumbTop; 229 SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKVERT, BUTTON_NORMAL, psbi, SCROLL_BOTTOM_RECT, htDown, htHot, &rcPart); 230 r.bottom = rcPart.top; 231 232 SCROLL_ThemeDrawPart(pcontext, SBP_THUMBBTNVERT, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r); 233 SCROLL_ThemeDrawPart(pcontext, SBP_GRIPPERVERT, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r); 234 } 235 else /* horizontal */ 236 { 237 rcPart = r; 238 rcPart.right = thumbPos; 239 SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKHORZ, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart); 240 r.left = rcPart.right; 241 242 rcPart = r; 243 rcPart.left += psbi->xyThumbBottom - psbi->xyThumbTop; 244 SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKHORZ, BUTTON_NORMAL, psbi, SCROLL_BOTTOM_RECT, htDown, htHot, &rcPart); 245 r.right = rcPart.left; 246 247 SCROLL_ThemeDrawPart(pcontext, SBP_THUMBBTNHORZ, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r); 248 SCROLL_ThemeDrawPart(pcontext, SBP_GRIPPERHORZ, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r); 249 } 250 } 251 252 static void SCROLL_DrawMovingThumb(PWND_DATA pwndData, PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi, BOOL vertical) 253 { 254 INT pos = pwndData->SCROLL_TrackingPos; 255 INT max_size; 256 257 if( vertical ) 258 max_size = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top; 259 else 260 max_size = psbi->rcScrollBar.right - psbi->rcScrollBar.left; 261 262 max_size -= psbi->xyThumbBottom - psbi->xyThumbTop + psbi->dxyLineButton; 263 264 if( pos < (psbi->dxyLineButton) ) 265 pos = (psbi->dxyLineButton); 266 else if( pos > max_size ) 267 pos = max_size; 268 269 SCROLL_DrawInterior(pcontext, psbi, pos, vertical, SCROLL_THUMB, 0); 270 271 pwndData->SCROLL_MovingThumb = !pwndData->SCROLL_MovingThumb; 272 } 273 274 275 void 276 ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT nBar, POINT* pt) 277 { 278 SCROLLINFO si; 279 SCROLLBARINFO sbi; 280 BOOL vertical; 281 enum SCROLL_HITTEST htHot = SCROLL_NOWHERE; 282 PWND_DATA pwndData; 283 284 if (((nBar == SB_VERT) && !(pcontext->wi.dwStyle & WS_VSCROLL)) || 285 ((nBar == SB_HORZ) && !(pcontext->wi.dwStyle & WS_HSCROLL))) return; 286 287 if (!(pwndData = ThemeGetWndData(pcontext->hWnd))) 288 return; 289 290 if (pwndData->SCROLL_TrackingWin) 291 return; 292 293 /* Retrieve scrollbar info */ 294 sbi.cbSize = sizeof(sbi); 295 si.cbSize = sizeof(si); 296 si.fMask = SIF_ALL ; 297 GetScrollInfo(pcontext->hWnd, nBar, &si); 298 GetScrollBarInfo(pcontext->hWnd, SCROLL_getObjectId(nBar), &sbi); 299 vertical = SCROLL_IsVertical(pcontext->hWnd, nBar); 300 if(sbi.rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE && 301 sbi.rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE ) 302 { 303 sbi.xyThumbTop = 0; 304 } 305 306 /* The scrollbar rect is in screen coordinates */ 307 OffsetRect(&sbi.rcScrollBar, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top); 308 309 if(pt) 310 { 311 ScreenToWindow(pcontext->hWnd, pt); 312 htHot = SCROLL_HitTest(pcontext->hWnd, &sbi, vertical, *pt, FALSE); 313 } 314 315 /* do not draw if the scrollbar rectangle is empty */ 316 if(IsRectEmpty(&sbi.rcScrollBar)) return; 317 318 /* Draw the scrollbar */ 319 SCROLL_DrawArrows( pcontext, &sbi, vertical, 0, htHot ); 320 SCROLL_DrawInterior( pcontext, &sbi, sbi.xyThumbTop, vertical, 0, htHot ); 321 } 322 323 324 325 /*********************************************************************** 326 * SCROLL_ClipPos 327 */ 328 static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt ) 329 { 330 if( pt.x < lpRect->left ) 331 pt.x = lpRect->left; 332 else 333 if( pt.x > lpRect->right ) 334 pt.x = lpRect->right; 335 336 if( pt.y < lpRect->top ) 337 pt.y = lpRect->top; 338 else 339 if( pt.y > lpRect->bottom ) 340 pt.y = lpRect->bottom; 341 342 return pt; 343 } 344 345 346 347 /*********************************************************************** 348 * SCROLL_GetThumbVal 349 * 350 * Compute the current scroll position based on the thumb position in pixels 351 * from the top of the scroll-bar. 352 */ 353 static UINT SCROLL_GetThumbVal( SCROLLINFO *psi, RECT *rect, 354 BOOL vertical, INT pos ) 355 { 356 INT thumbSize; 357 INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left; 358 INT range; 359 360 if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0) 361 return psi->nMin; 362 363 if (psi->nPage) 364 { 365 thumbSize = MulDiv(pixels,psi->nPage,(psi->nMax-psi->nMin+1)); 366 if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB; 367 } 368 else thumbSize = GetSystemMetrics(SM_CXVSCROLL); 369 370 if ((pixels -= thumbSize) <= 0) return psi->nMin; 371 372 pos = max( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) ); 373 if (pos > pixels) pos = pixels; 374 375 if (!psi->nPage) 376 range = psi->nMax - psi->nMin; 377 else 378 range = psi->nMax - psi->nMin - psi->nPage + 1; 379 380 return psi->nMin + MulDiv(pos, range, pixels); 381 } 382 383 static void 384 SCROLL_HandleScrollEvent(PWND_DATA pwndData, HWND hwnd, INT nBar, UINT msg, POINT pt) 385 { 386 /* Previous mouse position for timer events */ 387 static POINT prevPt; 388 /* Thumb position when tracking started. */ 389 static UINT trackThumbPos; 390 /* Position in the scroll-bar of the last button-down event. */ 391 static INT lastClickPos; 392 /* Position in the scroll-bar of the last mouse event. */ 393 static INT lastMousePos; 394 395 enum SCROLL_HITTEST hittest; 396 HWND hwndOwner, hwndCtl; 397 BOOL vertical; 398 SCROLLINFO si; 399 SCROLLBARINFO sbi; 400 DRAW_CONTEXT context; 401 402 si.cbSize = sizeof(si); 403 sbi.cbSize = sizeof(sbi); 404 si.fMask = SIF_ALL; 405 GetScrollInfo(hwnd, nBar, &si); 406 GetScrollBarInfo(hwnd, SCROLL_getObjectId(nBar), &sbi); 407 vertical = SCROLL_IsVertical(hwnd, nBar); 408 if(sbi.rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE && 409 sbi.rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE ) 410 { 411 return; 412 } 413 414 if ((pwndData->SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) 415 return; 416 417 ThemeInitDrawContext(&context, hwnd, 0); 418 419 /* The scrollbar rect is in screen coordinates */ 420 OffsetRect(&sbi.rcScrollBar, -context.wi.rcWindow.left, -context.wi.rcWindow.top); 421 422 hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd; 423 hwndCtl = (nBar == SB_CTL) ? hwnd : 0; 424 425 switch(msg) 426 { 427 case WM_LBUTTONDOWN: /* Initialise mouse tracking */ 428 HideCaret(hwnd); /* hide caret while holding down LBUTTON */ 429 pwndData->SCROLL_trackVertical = vertical; 430 pwndData->SCROLL_trackHitTest = hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE ); 431 lastClickPos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left); 432 lastMousePos = lastClickPos; 433 trackThumbPos = sbi.xyThumbTop; 434 prevPt = pt; 435 SetCapture( hwnd ); 436 break; 437 438 case WM_MOUSEMOVE: 439 hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, TRUE ); 440 prevPt = pt; 441 break; 442 443 case WM_LBUTTONUP: 444 hittest = SCROLL_NOWHERE; 445 ReleaseCapture(); 446 /* if scrollbar has focus, show back caret */ 447 if (hwnd==GetFocus()) 448 ShowCaret(hwnd); 449 break; 450 451 case WM_SYSTIMER: 452 pt = prevPt; 453 hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE ); 454 break; 455 456 default: 457 return; /* Should never happen */ 458 } 459 460 //TRACE("Event: hwnd=%p bar=%d msg=%s pt=%d,%d hit=%d\n", 461 // hwnd, nBar, SPY_GetMsgName(msg,hwnd), pt.x, pt.y, hittest ); 462 463 switch(pwndData->SCROLL_trackHitTest) 464 { 465 case SCROLL_NOWHERE: /* No tracking in progress */ 466 break; 467 468 case SCROLL_TOP_ARROW: 469 if (hittest == pwndData->SCROLL_trackHitTest) 470 { 471 SCROLL_DrawArrows( &context, &sbi, vertical, pwndData->SCROLL_trackHitTest, 0 ); 472 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) 473 { 474 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 475 SB_LINEUP, (LPARAM)hwndCtl ); 476 } 477 478 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? 479 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL ); 480 } 481 else 482 { 483 SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 ); 484 KillSystemTimer( hwnd, SCROLL_TIMER ); 485 } 486 487 break; 488 489 case SCROLL_TOP_RECT: 490 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, pwndData->SCROLL_trackHitTest, 0); 491 if (hittest == pwndData->SCROLL_trackHitTest) 492 { 493 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) 494 { 495 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 496 SB_PAGEUP, (LPARAM)hwndCtl ); 497 } 498 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? 499 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL ); 500 } 501 else KillSystemTimer( hwnd, SCROLL_TIMER ); 502 break; 503 504 case SCROLL_THUMB: 505 if (msg == WM_LBUTTONDOWN) 506 { 507 pwndData->SCROLL_TrackingWin = hwnd; 508 pwndData->SCROLL_TrackingBar = nBar; 509 pwndData->SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos; 510 pwndData->SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, 511 vertical, pwndData->SCROLL_TrackingPos ); 512 if (!pwndData->SCROLL_MovingThumb) 513 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical); 514 } 515 else if (msg == WM_LBUTTONUP) 516 { 517 if (pwndData->SCROLL_MovingThumb) 518 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical); 519 520 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, pwndData->SCROLL_trackHitTest ); 521 } 522 else /* WM_MOUSEMOVE */ 523 { 524 INT pos; 525 526 if (!SCROLL_PtInRectEx( &sbi.rcScrollBar, pt, vertical )) 527 pos = lastClickPos; 528 else 529 { 530 pt = SCROLL_ClipPos( &sbi.rcScrollBar, pt ); 531 pos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left); 532 } 533 if ( (pos != lastMousePos) || (!pwndData->SCROLL_MovingThumb) ) 534 { 535 if (pwndData->SCROLL_MovingThumb) 536 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical); 537 lastMousePos = pos; 538 pwndData->SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos; 539 pwndData->SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, 540 vertical, 541 pwndData->SCROLL_TrackingPos ); 542 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 543 MAKEWPARAM( SB_THUMBTRACK, pwndData->SCROLL_TrackingVal), 544 (LPARAM)hwndCtl ); 545 if (!pwndData->SCROLL_MovingThumb) 546 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical); 547 } 548 } 549 break; 550 551 case SCROLL_BOTTOM_RECT: 552 if (hittest == pwndData->SCROLL_trackHitTest) 553 { 554 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, pwndData->SCROLL_trackHitTest, 0 ); 555 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) 556 { 557 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 558 SB_PAGEDOWN, (LPARAM)hwndCtl ); 559 } 560 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? 561 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL ); 562 } 563 else 564 { 565 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, 0 ); 566 KillSystemTimer( hwnd, SCROLL_TIMER ); 567 } 568 break; 569 570 case SCROLL_BOTTOM_ARROW: 571 if (hittest == pwndData->SCROLL_trackHitTest) 572 { 573 SCROLL_DrawArrows( &context, &sbi, vertical, pwndData->SCROLL_trackHitTest, 0 ); 574 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) 575 { 576 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 577 SB_LINEDOWN, (LPARAM)hwndCtl ); 578 } 579 580 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ? 581 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL ); 582 } 583 else 584 { 585 SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 ); 586 KillSystemTimer( hwnd, SCROLL_TIMER ); 587 } 588 break; 589 } 590 591 if (msg == WM_LBUTTONDOWN) 592 { 593 594 if (hittest == SCROLL_THUMB) 595 { 596 UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical, 597 trackThumbPos + lastMousePos - lastClickPos ); 598 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 599 MAKEWPARAM( SB_THUMBTRACK, val ), (LPARAM)hwndCtl ); 600 } 601 } 602 603 if (msg == WM_LBUTTONUP) 604 { 605 hittest = pwndData->SCROLL_trackHitTest; 606 pwndData->SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */ 607 608 if (hittest == SCROLL_THUMB) 609 { 610 UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical, 611 trackThumbPos + lastMousePos - lastClickPos ); 612 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 613 MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl ); 614 } 615 /* SB_ENDSCROLL doesn't report thumb position */ 616 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, 617 SB_ENDSCROLL, (LPARAM)hwndCtl ); 618 619 /* Terminate tracking */ 620 pwndData->SCROLL_TrackingWin = 0; 621 } 622 623 ThemeCleanupDrawContext(&context); 624 } 625 626 static void 627 SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt ) 628 { 629 MSG msg; 630 PWND_DATA pwndData = ThemeGetWndData(hwnd); 631 if(!pwndData) 632 return; 633 634 ScreenToWindow(hwnd, &pt); 635 636 SCROLL_HandleScrollEvent(pwndData, hwnd, scrollbar, WM_LBUTTONDOWN, pt ); 637 638 do 639 { 640 if (!GetMessageW( &msg, 0, 0, 0 )) break; 641 if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue; 642 if (msg.message == WM_LBUTTONUP || 643 msg.message == WM_MOUSEMOVE || 644 (msg.message == WM_SYSTIMER && msg.wParam == SCROLL_TIMER)) 645 { 646 pt.x = GET_X_LPARAM(msg.lParam); 647 pt.y = GET_Y_LPARAM(msg.lParam); 648 ClientToScreen(hwnd, &pt); 649 ScreenToWindow(hwnd, &pt); 650 SCROLL_HandleScrollEvent(pwndData, hwnd, scrollbar, msg.message, pt ); 651 } 652 else 653 { 654 TranslateMessage( &msg ); 655 DispatchMessageW( &msg ); 656 } 657 if (!IsWindow( hwnd )) 658 { 659 ReleaseCapture(); 660 break; 661 } 662 } while (msg.message != WM_LBUTTONUP && GetCapture() == hwnd); 663 } 664 665 void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt ) 666 { 667 INT scrollbar; 668 669 if ((wParam & 0xfff0) == SC_HSCROLL) 670 { 671 if ((wParam & 0x0f) != HTHSCROLL) return; 672 scrollbar = SB_HORZ; 673 } 674 else /* SC_VSCROLL */ 675 { 676 if ((wParam & 0x0f) != HTVSCROLL) return; 677 scrollbar = SB_VERT; 678 } 679 SCROLL_TrackScrollBar( hwnd, scrollbar, pt ); 680 } 681