1 /* 2 * ReactOS User32 Library 3 * - ScrollBar control 4 * 5 * Copyright 2001 Casper S. Hornstrup 6 * Copyright 2003 Thomas Weidenmueller 7 * Copyright 2003 Filip Navara 8 * 9 * Based on Wine code. 10 * 11 * Copyright 1993 Martin Ayotte 12 * Copyright 1994, 1996 Alexandre Julliard 13 * 14 * This library is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU Lesser General Public 16 * License as published by the Free Software Foundation; either 17 * version 2.1 of the License, or (at your option) any later version. 18 * 19 * This library is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * Lesser General Public License for more details. 23 * 24 * You should have received a copy of the GNU Lesser General Public 25 * License along with this library; if not, write to the Free Software 26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27 */ 28 29 #include <user32.h> 30 31 WINE_DEFAULT_DEBUG_CHANNEL(scrollbar); 32 33 /* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */ 34 #define SCROLL_NOWHERE 0x00 /* Outside the scroll bar */ 35 #define SCROLL_TOP_ARROW 0x01 /* Top or left arrow */ 36 #define SCROLL_TOP_RECT 0x02 /* Rectangle between the top arrow and the thumb */ 37 #define SCROLL_THUMB 0x03 /* Thumb rectangle */ 38 #define SCROLL_BOTTOM_RECT 0x04 /* Rectangle between the thumb and the bottom arrow */ 39 #define SCROLL_BOTTOM_ARROW 0x05 /* Bottom or right arrow */ 40 41 #define SCROLL_FIRST_DELAY 200 /* Delay (in ms) before first repetition when 42 holding the button down */ 43 #define SCROLL_REPEAT_DELAY 50 /* Delay (in ms) between scroll repetitions */ 44 45 #define SCROLL_TIMER 0 /* Scroll timer id */ 46 47 /* Minimum size of the rectangle between the arrows */ 48 #define SCROLL_MIN_RECT 4 49 50 /* Minimum size of the thumb in pixels */ 51 #define SCROLL_MIN_THUMB 6 52 53 /* Overlap between arrows and thumb */ 54 #define SCROLL_ARROW_THUMB_OVERLAP 0 55 56 /* Thumb-tracking info */ 57 static HWND ScrollTrackingWin = 0; 58 static INT ScrollTrackingBar = 0; 59 static INT ScrollTrackingPos = 0; 60 static INT ScrollTrackingVal = 0; 61 /* Hit test code of the last button-down event */ 62 static DWORD ScrollTrackHitTest = SCROLL_NOWHERE; 63 static BOOL ScrollTrackVertical; 64 65 /* Is the moving thumb being displayed? */ 66 static BOOL ScrollMovingThumb = FALSE; 67 68 HBRUSH DefWndControlColor(HDC hDC, UINT ctlType); 69 70 UINT_PTR WINAPI SetSystemTimer(HWND,UINT_PTR,UINT,TIMERPROC); 71 BOOL WINAPI KillSystemTimer(HWND,UINT_PTR); 72 73 /********************************************************************* 74 * scrollbar class descriptor 75 */ 76 const struct builtin_class_descr SCROLL_builtin_class = 77 { 78 L"ScrollBar", /* name */ 79 CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style */ 80 ScrollBarWndProcA, /* procA */ 81 ScrollBarWndProcW, /* procW */ 82 sizeof(SBWND)-sizeof(WND), /* extra */ 83 IDC_ARROW, /* cursor */ 84 0 /* brush */ 85 }; 86 87 /* PRIVATE FUNCTIONS **********************************************************/ 88 89 static PSBDATA 90 IntGetSBData(PWND pwnd, INT Bar) 91 { 92 PSBWND pSBWnd; 93 PSBINFO pSBInfo; 94 95 pSBInfo = DesktopPtrToUser(pwnd->pSBInfo); 96 switch (Bar) 97 { 98 case SB_HORZ: 99 return &pSBInfo->Horz; 100 case SB_VERT: 101 return &pSBInfo->Vert; 102 case SB_CTL: 103 if ( pwnd->cbwndExtra < (sizeof(SBWND)-sizeof(WND)) ) 104 { 105 ERR("IntGetSBData Wrong Extra bytes for CTL Scrollbar!\n"); 106 return 0; 107 } 108 pSBWnd = (PSBWND)pwnd; 109 return (PSBDATA)&pSBWnd->SBCalc; 110 default: 111 ERR("IntGetSBData Bad Bar!\n"); 112 } 113 return NULL; 114 } 115 116 static void 117 IntDrawScrollInterior(HWND hWnd, HDC hDC, INT nBar, BOOL Vertical, 118 PSCROLLBARINFO ScrollBarInfo) 119 { 120 INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop; 121 INT ThumbTop = ScrollBarInfo->xyThumbTop; 122 RECT Rect; 123 HBRUSH hSaveBrush, hBrush; 124 BOOL TopSelected = FALSE, BottomSelected = FALSE; 125 126 if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED) 127 TopSelected = TRUE; 128 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED) 129 BottomSelected = TRUE; 130 131 /* 132 * Only scrollbar controls send WM_CTLCOLORSCROLLBAR. 133 * The window-owned scrollbars need to call DefWndControlColor 134 * to correctly setup default scrollbar colors 135 */ 136 if (nBar == SB_CTL) 137 { 138 hBrush = GetControlBrush( hWnd, hDC, WM_CTLCOLORSCROLLBAR); 139 if (!hBrush) 140 hBrush = GetSysColorBrush(COLOR_SCROLLBAR); 141 } 142 else 143 { 144 hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR); 145 } 146 147 hSaveBrush = SelectObject(hDC, hBrush); 148 149 /* Calculate the scroll rectangle */ 150 if (Vertical) 151 { 152 Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton; 153 Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton; 154 Rect.left = ScrollBarInfo->rcScrollBar.left; 155 Rect.right = ScrollBarInfo->rcScrollBar.right; 156 } 157 else 158 { 159 Rect.top = ScrollBarInfo->rcScrollBar.top; 160 Rect.bottom = ScrollBarInfo->rcScrollBar.bottom; 161 Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton; 162 Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton; 163 } 164 165 /* Draw the scroll rectangles and thumb */ 166 if (!ScrollBarInfo->xyThumbBottom) 167 { 168 PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left, 169 Rect.bottom - Rect.top, PATCOPY); 170 171 /* Cleanup and return */ 172 SelectObject(hDC, hSaveBrush); 173 return; 174 } 175 176 ThumbTop -= ScrollBarInfo->dxyLineButton; 177 178 if (ScrollBarInfo->dxyLineButton) 179 { 180 if (Vertical) 181 { 182 if (ThumbSize) 183 { 184 PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left, 185 ThumbTop, TopSelected ? BLACKNESS : PATCOPY); 186 Rect.top += ThumbTop; 187 PatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left, 188 Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY); 189 Rect.bottom = Rect.top + ThumbSize; 190 } 191 else 192 { 193 if (ThumbTop) 194 { 195 PatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton, 196 Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY); 197 } 198 } 199 } 200 else 201 { 202 if (ThumbSize) 203 { 204 PatBlt(hDC, Rect.left, Rect.top, ThumbTop, 205 Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY); 206 Rect.left += ThumbTop; 207 PatBlt(hDC, Rect.left + ThumbSize, Rect.top, 208 Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top, 209 BottomSelected ? BLACKNESS : PATCOPY); 210 Rect.right = Rect.left + ThumbSize; 211 } 212 else 213 { 214 if (ThumbTop) 215 { 216 PatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top, 217 Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY); 218 } 219 } 220 } 221 } 222 223 /* Draw the thumb */ 224 if (ThumbSize) 225 DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE); 226 227 /* Cleanup */ 228 SelectObject(hDC, hSaveBrush); 229 } 230 231 static VOID FASTCALL 232 IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical) 233 { 234 RECT RectLT, RectRB; 235 INT ScrollDirFlagLT, ScrollDirFlagRB; 236 237 RectLT = RectRB = ScrollBarInfo->rcScrollBar; 238 if (Vertical) 239 { 240 ScrollDirFlagLT = DFCS_SCROLLUP; 241 ScrollDirFlagRB = DFCS_SCROLLDOWN; 242 RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton; 243 RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton; 244 } 245 else 246 { 247 ScrollDirFlagLT = DFCS_SCROLLLEFT; 248 ScrollDirFlagRB = DFCS_SCROLLRIGHT; 249 RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton; 250 RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton; 251 } 252 253 if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED) 254 { 255 ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT; 256 } 257 if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE) 258 { 259 ScrollDirFlagLT |= DFCS_INACTIVE; 260 } 261 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED) 262 { 263 ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT; 264 } 265 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE) 266 { 267 ScrollDirFlagRB |= DFCS_INACTIVE; 268 } 269 270 DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT); 271 DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB); 272 } 273 274 static VOID FASTCALL 275 IntScrollDrawMovingThumb(HDC Dc, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical) 276 { 277 INT Pos = ScrollTrackingPos; 278 INT MaxSize; 279 INT OldTop; 280 281 if (Vertical) 282 MaxSize = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->rcScrollBar.top; 283 else 284 MaxSize = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->rcScrollBar.left; 285 286 MaxSize -= ScrollBarInfo->dxyLineButton + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop; 287 288 if (Pos < ScrollBarInfo->dxyLineButton) 289 Pos = ScrollBarInfo->dxyLineButton; 290 else if (MaxSize < Pos) 291 Pos = MaxSize; 292 293 OldTop = ScrollBarInfo->xyThumbTop; 294 ScrollBarInfo->xyThumbBottom = Pos + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop; 295 ScrollBarInfo->xyThumbTop = Pos; 296 IntDrawScrollInterior(ScrollTrackingWin, Dc, ScrollTrackingBar, Vertical, ScrollBarInfo); 297 ScrollBarInfo->xyThumbBottom = OldTop + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop; 298 ScrollBarInfo->xyThumbTop = OldTop; 299 300 ScrollMovingThumb = !ScrollMovingThumb; 301 } 302 303 static LONG FASTCALL 304 IntScrollGetObjectId(INT SBType) 305 { 306 if (SBType == SB_VERT) 307 return OBJID_VSCROLL; 308 if (SBType == SB_HORZ) 309 return OBJID_HSCROLL; 310 return OBJID_CLIENT; 311 } 312 313 static BOOL FASTCALL 314 IntGetScrollBarInfo(HWND Wnd, INT Bar, PSCROLLBARINFO ScrollBarInfo) 315 { 316 ScrollBarInfo->cbSize = sizeof(SCROLLBARINFO); 317 318 return NtUserGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), ScrollBarInfo); 319 } 320 321 void 322 IntDrawScrollBar(HWND Wnd, HDC DC, INT Bar) 323 { 324 //PSBWND pSBWnd; 325 //INT ThumbSize; 326 SCROLLBARINFO Info; 327 BOOL Vertical; 328 329 /* 330 * Get scroll bar info. 331 */ 332 switch (Bar) 333 { 334 case SB_HORZ: 335 Vertical = FALSE; 336 break; 337 338 case SB_VERT: 339 Vertical = TRUE; 340 break; 341 342 case SB_CTL: 343 Vertical = (GetWindowLongPtrW(Wnd, GWL_STYLE) & SBS_VERT) != 0; 344 break; 345 346 default: 347 return; 348 } 349 if (!IntGetScrollBarInfo(Wnd, Bar, &Info)) 350 { 351 return; 352 } 353 354 if (IsRectEmpty(&Info.rcScrollBar)) 355 { 356 return; 357 } 358 359 //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop; 360 361 /* 362 * Draw the arrows. 363 */ 364 if (Info.dxyLineButton) 365 { 366 IntDrawScrollArrows(DC, &Info, Vertical); 367 } 368 369 /* 370 * Draw the interior. 371 */ 372 IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info); 373 374 /* 375 * If scroll bar has focus, reposition the caret. 376 */ 377 if (Wnd == GetFocus() && SB_CTL == Bar) 378 { 379 if (Vertical) 380 { 381 SetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1); 382 } 383 else 384 { 385 SetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1); 386 } 387 } 388 } 389 390 static BOOL FASTCALL 391 IntScrollPtInRectEx(LPRECT Rect, POINT Pt, BOOL Vertical) 392 { 393 RECT TempRect = *Rect; 394 int scrollbarWidth; 395 396 /* Pad hit rect to allow mouse to be dragged outside of scrollbar and 397 * still be considered in the scrollbar. */ 398 if (Vertical) 399 { 400 scrollbarWidth = Rect->right - Rect->left; 401 TempRect.left -= scrollbarWidth*8; 402 TempRect.right += scrollbarWidth*8; 403 TempRect.top -= scrollbarWidth*2; 404 TempRect.bottom += scrollbarWidth*2; 405 } 406 else 407 { 408 scrollbarWidth = Rect->bottom - Rect->top; 409 TempRect.left -= scrollbarWidth*2; 410 TempRect.right += scrollbarWidth*2; 411 TempRect.top -= scrollbarWidth*8; 412 TempRect.bottom += scrollbarWidth*8; 413 } 414 415 return PtInRect(&TempRect, Pt); 416 } 417 418 static DWORD FASTCALL 419 IntScrollHitTest(PSCROLLBARINFO ScrollBarInfo, BOOL Vertical, POINT Pt, BOOL Dragging) 420 { 421 INT ArrowSize, ThumbSize, ThumbPos; 422 423 if ((Dragging && ! IntScrollPtInRectEx(&ScrollBarInfo->rcScrollBar, Pt, Vertical)) || 424 ! PtInRect(&ScrollBarInfo->rcScrollBar, Pt)) return SCROLL_NOWHERE; 425 426 ThumbPos = ScrollBarInfo->xyThumbTop; 427 ThumbSize = ScrollBarInfo->xyThumbBottom - ThumbPos; 428 ArrowSize = ScrollBarInfo->dxyLineButton; 429 430 if (Vertical) 431 { 432 if (Pt.y < ScrollBarInfo->rcScrollBar.top + ArrowSize) return SCROLL_TOP_ARROW; 433 if (Pt.y >= ScrollBarInfo->rcScrollBar.bottom - ArrowSize) return SCROLL_BOTTOM_ARROW; 434 if (!ThumbPos) return SCROLL_TOP_RECT; 435 Pt.y -= ScrollBarInfo->rcScrollBar.top; 436 if (Pt.y < ThumbPos) return SCROLL_TOP_RECT; 437 if (Pt.y >= ThumbPos + ThumbSize) return SCROLL_BOTTOM_RECT; 438 } 439 else 440 { 441 if (Pt.x < ScrollBarInfo->rcScrollBar.left + ArrowSize) return SCROLL_TOP_ARROW; 442 if (Pt.x >= ScrollBarInfo->rcScrollBar.right - ArrowSize) return SCROLL_BOTTOM_ARROW; 443 if (!ThumbPos) return SCROLL_TOP_RECT; 444 Pt.x -= ScrollBarInfo->rcScrollBar.left; 445 if (Pt.x < ThumbPos) return SCROLL_TOP_RECT; 446 if (Pt.x >= ThumbPos + ThumbSize) return SCROLL_BOTTOM_RECT; 447 } 448 449 return SCROLL_THUMB; 450 } 451 452 453 /*********************************************************************** 454 * IntScrollGetScrollBarRect 455 * 456 * Compute the scroll bar rectangle, in drawing coordinates (i.e. client 457 * coords for SB_CTL, window coords for SB_VERT and SB_HORZ). 458 * 'arrowSize' returns the width or height of an arrow (depending on 459 * the orientation of the scrollbar), 'thumbSize' returns the size of 460 * the thumb, and 'thumbPos' returns the position of the thumb 461 * relative to the left or to the top. 462 * Return TRUE if the scrollbar is vertical, FALSE if horizontal. 463 */ 464 static BOOL FASTCALL 465 IntScrollGetScrollBarRect(HWND Wnd, INT Bar, RECT *Rect, 466 INT *ArrowSize, INT *ThumbSize, 467 INT *ThumbPos) 468 { 469 INT Pixels; 470 BOOL Vertical; 471 PWND pWnd; 472 PSBINFO pSBInfo; 473 PSBDATA pSBData; 474 PSBWND pSBWnd; 475 476 pWnd = ValidateHwnd( Wnd ); 477 if (!pWnd) return FALSE; 478 pSBInfo = DesktopPtrToUser(pWnd->pSBInfo); 479 480 *Rect = pWnd->rcClient; 481 OffsetRect( Rect, -pWnd->rcWindow.left, -pWnd->rcWindow.top ); 482 if (pWnd->ExStyle & WS_EX_LAYOUTRTL) 483 mirror_rect( &pWnd->rcWindow, Rect ); 484 485 switch (Bar) 486 { 487 case SB_HORZ: 488 // WIN_GetRectangles( Wnd, COORDS_WINDOW, NULL, Rect ); 489 Rect->top = Rect->bottom; 490 Rect->bottom += GetSystemMetrics(SM_CYHSCROLL); 491 if (pWnd->style & WS_BORDER) 492 { 493 Rect->left--; 494 Rect->right++; 495 } 496 else if (pWnd->style & WS_VSCROLL) 497 { 498 Rect->right++; 499 } 500 Vertical = FALSE; 501 pSBData = &pSBInfo->Horz; 502 break; 503 504 case SB_VERT: 505 // WIN_GetRectangles( Wnd, COORDS_WINDOW, NULL, Rect ); 506 if (pWnd->ExStyle & WS_EX_LEFTSCROLLBAR) 507 { 508 Rect->right = Rect->left; 509 Rect->left -= GetSystemMetrics(SM_CXVSCROLL); 510 } 511 else 512 { 513 Rect->left = Rect->right; 514 Rect->right += GetSystemMetrics(SM_CXVSCROLL); 515 } 516 if (pWnd->style & WS_BORDER) 517 { 518 Rect->top--; 519 Rect->bottom++; 520 } 521 else if (pWnd->style & WS_HSCROLL) 522 { 523 Rect->bottom++; 524 } 525 Vertical = TRUE; 526 pSBData = &pSBInfo->Vert; 527 break; 528 529 case SB_CTL: 530 GetClientRect( Wnd, Rect ); 531 Vertical = (pWnd->style & SBS_VERT); 532 pSBWnd = (PSBWND)pWnd; 533 pSBData = (PSBDATA)&pSBWnd->SBCalc; 534 break; 535 536 default: 537 return FALSE; 538 } 539 540 if (Vertical) Pixels = Rect->bottom - Rect->top; 541 else Pixels = Rect->right - Rect->left; 542 543 if (Pixels <= 2 * GetSystemMetrics(SM_CXVSCROLL) + SCROLL_MIN_RECT) 544 { 545 if (SCROLL_MIN_RECT < Pixels) 546 *ArrowSize = (Pixels - SCROLL_MIN_RECT) / 2; 547 else 548 *ArrowSize = 0; 549 *ThumbPos = *ThumbSize = 0; 550 } 551 else 552 { 553 *ArrowSize = GetSystemMetrics(SM_CXVSCROLL); 554 Pixels -= (2 * (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)); 555 if (pSBData->page) 556 { 557 *ThumbSize = MulDiv(Pixels, pSBData->page, (pSBData->posMax - pSBData->posMin + 1)); 558 if (*ThumbSize < SCROLL_MIN_THUMB) *ThumbSize = SCROLL_MIN_THUMB; 559 } 560 else *ThumbSize = GetSystemMetrics(SM_CXVSCROLL); 561 562 if (((Pixels -= *ThumbSize ) < 0) || 563 (( pSBInfo->WSBflags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)) 564 { 565 /* Rectangle too small or scrollbar disabled -> no thumb */ 566 *ThumbPos = *ThumbSize = 0; 567 } 568 else 569 { 570 INT Max = pSBData->posMax - max(pSBData->page - 1, 0); 571 if (pSBData->posMin >= Max) 572 *ThumbPos = *ArrowSize - SCROLL_ARROW_THUMB_OVERLAP; 573 else 574 *ThumbPos = *ArrowSize - SCROLL_ARROW_THUMB_OVERLAP 575 + MulDiv(Pixels, (pSBData->pos - pSBData->posMin),(Max - pSBData->posMin)); 576 } 577 } 578 return Vertical; 579 } 580 581 /*********************************************************************** 582 * IntScrollGetThumbVal 583 * 584 * Compute the current scroll position based on the thumb position in pixels 585 * from the top of the scroll-bar. 586 */ 587 static UINT FASTCALL 588 IntScrollGetThumbVal(HWND Wnd, INT SBType, PSCROLLBARINFO ScrollBarInfo, 589 BOOL Vertical, INT Pos) 590 { 591 PWND pWnd; 592 PSBDATA pSBData; 593 INT Pixels = Vertical ? ScrollBarInfo->rcScrollBar.bottom 594 - ScrollBarInfo->rcScrollBar.top 595 : ScrollBarInfo->rcScrollBar.right 596 - ScrollBarInfo->rcScrollBar.left; 597 598 pWnd = ValidateHwnd( Wnd ); 599 if (!pWnd) return FALSE; 600 601 pSBData = IntGetSBData(pWnd, SBType); 602 603 if ((Pixels -= 2 * ScrollBarInfo->dxyLineButton) <= 0) 604 { 605 return pSBData->posMin; 606 } 607 608 if ((Pixels -= (ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop)) <= 0) 609 { 610 return pSBData->posMin; 611 } 612 613 Pos = Pos - ScrollBarInfo->dxyLineButton; 614 if (Pos < 0) 615 { 616 Pos = 0; 617 } 618 if (Pos > Pixels) Pos = Pixels; 619 620 if (!pSBData->page) 621 Pos *= pSBData->posMax - pSBData->posMin; 622 else 623 Pos *= pSBData->posMax - pSBData->posMin - pSBData->page + 1; 624 625 return pSBData->posMin + ((Pos + Pixels / 2) / Pixels); 626 } 627 628 /*********************************************************************** 629 * IntScrollClipPos 630 */ 631 static POINT IntScrollClipPos(PRECT lpRect, POINT pt) 632 { 633 if( pt.x < lpRect->left ) 634 pt.x = lpRect->left; 635 else 636 if( pt.x > lpRect->right ) 637 pt.x = lpRect->right; 638 639 if( pt.y < lpRect->top ) 640 pt.y = lpRect->top; 641 else 642 if( pt.y > lpRect->bottom ) 643 pt.y = lpRect->bottom; 644 645 return pt; 646 } 647 648 /*********************************************************************** 649 * IntScrollDrawSizeGrip 650 * 651 * Draw the size grip. 652 */ 653 static void FASTCALL 654 IntScrollDrawSizeGrip(HWND Wnd, HDC Dc) 655 { 656 RECT Rect; 657 658 GetClientRect(Wnd, &Rect); 659 FillRect(Dc, &Rect, GetSysColorBrush(COLOR_SCROLLBAR)); 660 Rect.left = max(Rect.left, Rect.right - GetSystemMetrics(SM_CXVSCROLL) - 1); 661 Rect.top = max(Rect.top, Rect.bottom - GetSystemMetrics(SM_CYHSCROLL) - 1); 662 DrawFrameControl(Dc, &Rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); 663 } 664 665 /*********************************************************************** 666 * SCROLL_RefreshScrollBar 667 * 668 * Repaint the scroll bar interior after a SetScrollRange() or 669 * SetScrollPos() call. 670 */ 671 static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar, 672 BOOL arrows, BOOL interior ) 673 { 674 HDC hdc = GetDCEx( hwnd, 0, 675 DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) ); 676 if (!hdc) return; 677 678 IntDrawScrollBar( hwnd, hdc, nBar);//, arrows, interior ); 679 ReleaseDC( hwnd, hdc ); 680 } 681 682 683 /*********************************************************************** 684 * IntScrollHandleKbdEvent 685 * 686 * Handle a keyboard event (only for SB_CTL scrollbars with focus). 687 */ 688 static void FASTCALL 689 IntScrollHandleKbdEvent( 690 HWND Wnd /* [in] Handle of window with scrollbar(s) */, 691 WPARAM wParam /* [in] Variable input including enable state */, 692 LPARAM lParam /* [in] Variable input including input point */) 693 { 694 TRACE("Wnd=%p wParam=%ld lParam=%ld\n", Wnd, wParam, lParam); 695 696 /* hide caret on first KEYDOWN to prevent flicker */ 697 if (0 == (lParam & PFD_DOUBLEBUFFER_DONTCARE)) 698 { 699 HideCaret(Wnd); 700 } 701 702 switch(wParam) 703 { 704 case VK_PRIOR: 705 wParam = SB_PAGEUP; 706 break; 707 708 case VK_NEXT: 709 wParam = SB_PAGEDOWN; 710 break; 711 712 case VK_HOME: 713 wParam = SB_TOP; 714 break; 715 716 case VK_END: 717 wParam = SB_BOTTOM; 718 break; 719 720 case VK_UP: 721 wParam = SB_LINEUP; 722 break; 723 724 case VK_DOWN: 725 wParam = SB_LINEDOWN; 726 break; 727 728 default: 729 return; 730 } 731 732 SendMessageW(GetParent(Wnd), 733 (0 != (GetWindowLongPtrW(Wnd, GWL_STYLE ) & SBS_VERT) ? 734 WM_VSCROLL : WM_HSCROLL), wParam, (LPARAM) Wnd); 735 } 736 737 /*********************************************************************** 738 * IntScrollHandleScrollEvent 739 * 740 * Handle a mouse or timer event for the scrollbar. 741 * 'Pt' is the location of the mouse event in drawing coordinates 742 */ 743 static VOID FASTCALL 744 IntScrollHandleScrollEvent(HWND Wnd, INT SBType, UINT Msg, POINT Pt) 745 { 746 static POINT PrevPt; /* Previous mouse position for timer events */ 747 static UINT TrackThumbPos; /* Thumb position when tracking started. */ 748 static INT LastClickPos; /* Position in the scroll-bar of the last 749 button-down event. */ 750 static INT LastMousePos; /* Position in the scroll-bar of the last 751 mouse event. */ 752 753 DWORD HitTest; 754 HWND WndOwner, WndCtl; 755 BOOL Vertical; 756 HDC Dc; 757 SCROLLBARINFO ScrollBarInfo; 758 SETSCROLLBARINFO NewInfo; 759 760 if (! IntGetScrollBarInfo(Wnd, SBType, &ScrollBarInfo)) 761 { 762 return; 763 } 764 if ((ScrollTrackHitTest == SCROLL_NOWHERE) && (Msg != WM_LBUTTONDOWN)) 765 { 766 //// ReactOS : Justin Case something goes wrong. 767 if (Wnd == GetCapture()) 768 { 769 ReleaseCapture(); 770 } 771 //// 772 return; 773 } 774 775 NewInfo.nTrackPos = ScrollTrackingVal; 776 NewInfo.reserved = ScrollBarInfo.reserved; 777 memcpy(NewInfo.rgstate, ScrollBarInfo.rgstate, (CCHILDREN_SCROLLBAR + 1) * sizeof(DWORD)); 778 779 if (SBType == SB_CTL && (GetWindowLongPtrW(Wnd, GWL_STYLE) & (SBS_SIZEGRIP | SBS_SIZEBOX))) 780 { 781 switch(Msg) 782 { 783 case WM_LBUTTONDOWN: /* Initialise mouse tracking */ 784 HideCaret(Wnd); /* hide caret while holding down LBUTTON */ 785 SetCapture(Wnd); 786 PrevPt = Pt; 787 ScrollTrackHitTest = HitTest = SCROLL_THUMB; 788 break; 789 case WM_MOUSEMOVE: 790 GetClientRect(GetParent(GetParent(Wnd)), &ScrollBarInfo.rcScrollBar); 791 PrevPt = Pt; 792 break; 793 case WM_LBUTTONUP: 794 ReleaseCapture(); 795 ScrollTrackHitTest = HitTest = SCROLL_NOWHERE; 796 if (Wnd == GetFocus()) ShowCaret(Wnd); 797 break; 798 case WM_SYSTIMER: 799 Pt = PrevPt; 800 break; 801 } 802 return; 803 } 804 805 Dc = GetDCEx(Wnd, 0, DCX_CACHE | ((SB_CTL == SBType) ? 0 : DCX_WINDOW)); 806 if (SB_VERT == SBType) 807 { 808 Vertical = TRUE; 809 } 810 else if (SB_HORZ == SBType) 811 { 812 Vertical = FALSE; 813 } 814 else 815 { 816 Vertical = (0 != (GetWindowLongPtrW(Wnd, GWL_STYLE) & SBS_VERT)); 817 } 818 WndOwner = (SB_CTL == SBType) ? GetParent(Wnd) : Wnd; 819 WndCtl = (SB_CTL == SBType) ? Wnd : NULL; 820 821 switch (Msg) 822 { 823 case WM_LBUTTONDOWN: /* Initialise mouse tracking */ 824 HideCaret(Wnd); /* hide caret while holding down LBUTTON */ 825 ScrollTrackVertical = Vertical; 826 ScrollTrackHitTest = HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, FALSE ); 827 LastClickPos = Vertical ? (Pt.y - ScrollBarInfo.rcScrollBar.top) 828 : (Pt.x - ScrollBarInfo.rcScrollBar.left); 829 LastMousePos = LastClickPos; 830 TrackThumbPos = ScrollBarInfo.xyThumbTop; 831 PrevPt = Pt; 832 if (SBType == SB_CTL && (GetWindowLongPtrW(Wnd, GWL_STYLE) & WS_TABSTOP)) SetFocus(Wnd); 833 SetCapture(Wnd); 834 /* Don't update scrollbar if disabled. */ 835 if (ScrollBarInfo.rgstate[ScrollTrackHitTest] != STATE_SYSTEM_UNAVAILABLE) 836 { 837 ScrollBarInfo.rgstate[ScrollTrackHitTest] |= STATE_SYSTEM_PRESSED; 838 NewInfo.rgstate[ScrollTrackHitTest] = ScrollBarInfo.rgstate[ScrollTrackHitTest]; 839 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo); 840 } 841 break; 842 843 case WM_MOUSEMOVE: 844 HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, TRUE); 845 PrevPt = Pt; 846 break; 847 848 case WM_LBUTTONUP: 849 HitTest = SCROLL_NOWHERE; 850 ReleaseCapture(); 851 /* if scrollbar has focus, show back caret */ 852 if (Wnd == GetFocus()) ShowCaret(Wnd); 853 /* Don't update scrollbar if disabled. */ 854 if (ScrollBarInfo.rgstate[ScrollTrackHitTest] != STATE_SYSTEM_UNAVAILABLE) 855 { 856 ScrollBarInfo.rgstate[ScrollTrackHitTest] &= ~STATE_SYSTEM_PRESSED; 857 NewInfo.rgstate[ScrollTrackHitTest] = ScrollBarInfo.rgstate[ScrollTrackHitTest]; 858 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo); 859 860 IntDrawScrollInterior(Wnd,Dc,SBType,Vertical,&ScrollBarInfo); 861 IntDrawScrollArrows(Dc, &ScrollBarInfo, Vertical); 862 } 863 break; 864 865 case WM_SYSTIMER: 866 Pt = PrevPt; 867 HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, FALSE); 868 break; 869 870 default: 871 return; /* Should never happen */ 872 } 873 874 TRACE("Event: hwnd=%p bar=%d msg=%s pt=%d,%d hit=%d\n", 875 Wnd, SBType, SPY_GetMsgName(Msg,Wnd), Pt.x, Pt.y, HitTest ); 876 877 switch (ScrollTrackHitTest) 878 { 879 case SCROLL_NOWHERE: /* No tracking in progress */ 880 break; 881 882 case SCROLL_TOP_ARROW: 883 if (HitTest == ScrollTrackHitTest) 884 { 885 if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg)) 886 { 887 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 888 SB_LINEUP, (LPARAM) WndCtl); 889 } 890 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ? 891 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, 892 (TIMERPROC) NULL); 893 } 894 else 895 { 896 KillSystemTimer(Wnd, SCROLL_TIMER); 897 } 898 break; 899 900 case SCROLL_TOP_RECT: 901 if (HitTest == ScrollTrackHitTest) 902 { 903 if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg)) 904 { 905 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 906 SB_PAGEUP, (LPARAM) WndCtl); 907 } 908 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ? 909 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, 910 (TIMERPROC) NULL); 911 } 912 else 913 { 914 KillSystemTimer(Wnd, SCROLL_TIMER); 915 } 916 break; 917 918 case SCROLL_THUMB: 919 if (Msg == WM_LBUTTONDOWN) 920 { 921 ScrollTrackingWin = Wnd; 922 ScrollTrackingBar = SBType; 923 ScrollTrackingPos = TrackThumbPos + LastMousePos - LastClickPos; 924 ScrollTrackingVal = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, 925 Vertical, ScrollTrackingPos); 926 NewInfo.nTrackPos = ScrollTrackingVal; 927 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo); 928 IntScrollDrawMovingThumb(Dc, &ScrollBarInfo, Vertical); 929 } 930 else if (Msg == WM_LBUTTONUP) 931 { 932 ScrollTrackingWin = 0; 933 ScrollTrackingVal = 0; 934 IntDrawScrollInterior(Wnd, Dc, SBType, Vertical, &ScrollBarInfo); 935 } 936 else /* WM_MOUSEMOVE */ 937 { 938 UINT Pos; 939 940 if (! IntScrollPtInRectEx(&ScrollBarInfo.rcScrollBar, Pt, Vertical)) 941 { 942 Pos = LastClickPos; 943 } 944 else 945 { 946 Pt = IntScrollClipPos(&ScrollBarInfo.rcScrollBar, Pt); 947 Pos = Vertical ? (Pt.y - ScrollBarInfo.rcScrollBar.top) 948 : (Pt.x - ScrollBarInfo.rcScrollBar.left); 949 } 950 if (Pos != LastMousePos || ! ScrollMovingThumb) 951 { 952 LastMousePos = Pos; 953 ScrollTrackingPos = TrackThumbPos + Pos - LastClickPos; 954 ScrollTrackingVal = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, 955 Vertical, ScrollTrackingPos); 956 NewInfo.nTrackPos = ScrollTrackingVal; 957 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo); 958 IntScrollDrawMovingThumb(Dc, &ScrollBarInfo, Vertical); 959 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 960 MAKEWPARAM(SB_THUMBTRACK, ScrollTrackingVal), 961 (LPARAM) WndCtl); 962 } 963 } 964 break; 965 966 case SCROLL_BOTTOM_RECT: 967 if (HitTest == ScrollTrackHitTest) 968 { 969 if ((Msg == WM_LBUTTONDOWN) || (Msg == WM_SYSTIMER)) 970 { 971 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 972 SB_PAGEDOWN, (LPARAM) WndCtl); 973 } 974 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ? 975 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, 976 (TIMERPROC) NULL); 977 } 978 else 979 { 980 KillSystemTimer(Wnd, SCROLL_TIMER); 981 } 982 break; 983 984 case SCROLL_BOTTOM_ARROW: 985 if (HitTest == ScrollTrackHitTest) 986 { 987 if ((Msg == WM_LBUTTONDOWN) || (Msg == WM_SYSTIMER)) 988 { 989 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 990 SB_LINEDOWN, (LPARAM) WndCtl); 991 } 992 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ? 993 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, 994 (TIMERPROC) NULL); 995 } 996 else KillSystemTimer(Wnd, SCROLL_TIMER); 997 break; 998 } 999 1000 if (Msg == WM_LBUTTONDOWN) 1001 { 1002 if (SCROLL_THUMB == HitTest) 1003 { 1004 UINT Val = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, Vertical, 1005 TrackThumbPos + LastMousePos - LastClickPos); 1006 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 1007 MAKEWPARAM(SB_THUMBTRACK, Val), (LPARAM) WndCtl); 1008 } 1009 } 1010 1011 if (Msg == WM_LBUTTONUP) 1012 { 1013 HitTest = ScrollTrackHitTest; 1014 ScrollTrackHitTest = SCROLL_NOWHERE; /* Terminate tracking */ 1015 1016 if (SCROLL_THUMB == HitTest) 1017 { 1018 UINT Val = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, Vertical, 1019 TrackThumbPos + LastMousePos - LastClickPos); 1020 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 1021 MAKEWPARAM(SB_THUMBPOSITION, Val), (LPARAM) WndCtl); 1022 } 1023 /* SB_ENDSCROLL doesn't report thumb position */ 1024 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL, 1025 SB_ENDSCROLL, (LPARAM) WndCtl); 1026 1027 /* Terminate tracking */ 1028 ScrollTrackingWin = 0; 1029 } 1030 1031 ReleaseDC(Wnd, Dc); 1032 } 1033 1034 1035 /*********************************************************************** 1036 * IntScrollCreateScrollBar 1037 * 1038 * Create a scroll bar 1039 */ 1040 static void IntScrollCreateScrollBar( 1041 HWND Wnd /* [in] Handle of window with scrollbar(s) */, 1042 LPCREATESTRUCTW lpCreate /* [in] The style and place of the scroll bar */) 1043 { 1044 SCROLLINFO Info; 1045 1046 Info.cbSize = sizeof(SCROLLINFO); 1047 Info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; 1048 Info.nMin = 0; 1049 Info.nMax = 0; 1050 Info.nPage = 0; 1051 Info.nPos = 0; 1052 Info.nTrackPos = 0; 1053 NtUserSetScrollInfo(Wnd, SB_CTL, &Info, FALSE); 1054 1055 TRACE("hwnd=%p lpCreate=%p\n", Wnd, lpCreate); 1056 1057 #if 0 /* FIXME */ 1058 if (lpCreate->style & WS_DISABLED) 1059 { 1060 // info->flags = ESB_DISABLE_BOTH; 1061 //NtUserEnableScrollBar(Wnd,SB_CTL,(wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH)); 1062 NtUserMessageCall( Wnd, WM_ENABLE, FALSE, 0, 0, FNID_SCROLLBAR, FALSE); 1063 ERR("Created WS_DISABLED scrollbar\n"); 1064 } 1065 #endif 1066 if (0 != (lpCreate->style & (SBS_SIZEGRIP | SBS_SIZEBOX))) 1067 { 1068 if (0 != (lpCreate->style & SBS_SIZEBOXTOPLEFTALIGN)) 1069 { 1070 MoveWindow(Wnd, lpCreate->x, lpCreate->y, GetSystemMetrics(SM_CXVSCROLL) + 1, 1071 GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE); 1072 } 1073 else if (0 != (lpCreate->style & SBS_SIZEBOXBOTTOMRIGHTALIGN)) 1074 { 1075 MoveWindow(Wnd, lpCreate->x + lpCreate->cx - GetSystemMetrics(SM_CXVSCROLL) - 1, 1076 lpCreate->y + lpCreate->cy - GetSystemMetrics(SM_CYHSCROLL) - 1, 1077 GetSystemMetrics(SM_CXVSCROLL) + 1, 1078 GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE); 1079 } 1080 } 1081 else if (0 != (lpCreate->style & SBS_VERT)) 1082 { 1083 if (0 != (lpCreate->style & SBS_LEFTALIGN)) 1084 { 1085 MoveWindow(Wnd, lpCreate->x, lpCreate->y, 1086 GetSystemMetrics(SM_CXVSCROLL) + 1, lpCreate->cy, FALSE); 1087 } 1088 else if (0 != (lpCreate->style & SBS_RIGHTALIGN)) 1089 { 1090 MoveWindow(Wnd, 1091 lpCreate->x + lpCreate->cx - GetSystemMetrics(SM_CXVSCROLL) - 1, 1092 lpCreate->y, 1093 GetSystemMetrics(SM_CXVSCROLL) + 1, lpCreate->cy, FALSE); 1094 } 1095 } 1096 else /* SBS_HORZ */ 1097 { 1098 if (0 != (lpCreate->style & SBS_TOPALIGN)) 1099 { 1100 MoveWindow(Wnd, lpCreate->x, lpCreate->y, 1101 lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE); 1102 } 1103 else if (0 != (lpCreate->style & SBS_BOTTOMALIGN)) 1104 { 1105 MoveWindow(Wnd, 1106 lpCreate->x, 1107 lpCreate->y + lpCreate->cy - GetSystemMetrics(SM_CYHSCROLL) - 1, 1108 lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE); 1109 } 1110 } 1111 } 1112 1113 /* USER32 INTERNAL FUNCTIONS **************************************************/ 1114 1115 /*********************************************************************** 1116 * ScrollTrackScrollBar 1117 * 1118 * Track a mouse button press on a scroll-bar. 1119 * pt is in screen-coordinates for non-client scroll bars. 1120 */ 1121 VOID FASTCALL 1122 ScrollTrackScrollBar(HWND Wnd, INT SBType, POINT Pt) 1123 { 1124 MSG Msg; 1125 UINT XOffset = 0, YOffset = 0; 1126 1127 if (SBType != SB_CTL) 1128 { // Used with CMD mouse tracking. 1129 PWND pwnd = ValidateHwnd(Wnd); 1130 if (!pwnd) return; 1131 XOffset = pwnd->rcClient.left - pwnd->rcWindow.left; 1132 YOffset = pwnd->rcClient.top - pwnd->rcWindow.top; 1133 // RECT rect; 1134 // WIN_GetRectangles( Wnd, COORDS_CLIENT, &rect, NULL ); 1135 ScreenToClient(Wnd, &Pt); 1136 // Pt.x -= rect.left; 1137 // Pt.y -= rect.top; 1138 Pt.x += XOffset; 1139 Pt.y += YOffset; 1140 } 1141 1142 IntScrollHandleScrollEvent(Wnd, SBType, WM_LBUTTONDOWN, Pt); 1143 1144 do 1145 { 1146 if (!GetMessageW(&Msg, 0, 0, 0)) break; 1147 if (CallMsgFilterW(&Msg, MSGF_SCROLLBAR)) continue; 1148 if ( Msg.message == WM_LBUTTONUP || 1149 Msg.message == WM_MOUSEMOVE || 1150 (Msg.message == WM_SYSTIMER && Msg.wParam == SCROLL_TIMER)) 1151 { 1152 Pt.x = LOWORD(Msg.lParam) + XOffset; 1153 Pt.y = HIWORD(Msg.lParam) + YOffset; 1154 IntScrollHandleScrollEvent(Wnd, SBType, Msg.message, Pt); 1155 } 1156 else 1157 { 1158 TranslateMessage(&Msg); 1159 DispatchMessageW(&Msg); 1160 } 1161 if (!IsWindow(Wnd)) 1162 { 1163 ReleaseCapture(); 1164 break; 1165 } 1166 } while (Msg.message != WM_LBUTTONUP && GetCapture() == Wnd); 1167 } 1168 1169 1170 static DWORD FASTCALL 1171 IntSetScrollInfo(HWND Wnd, LPCSCROLLINFO Info, BOOL bRedraw) 1172 { 1173 DWORD Ret = NtUserSetScrollInfo(Wnd, SB_CTL, Info, bRedraw); 1174 if (Ret) IntNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, Wnd, OBJID_CLIENT, CHILDID_SELF, WEF_SETBYWNDPTI); 1175 return Ret; 1176 } 1177 1178 1179 /*********************************************************************** 1180 * ScrollBarWndProc 1181 */ 1182 LRESULT WINAPI 1183 ScrollBarWndProc_common(WNDPROC DefWindowProc, HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL unicode ) 1184 { 1185 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed. 1186 PWND pWnd; 1187 PSBWND pSBWnd; 1188 SCROLLINFO ScrollInfo; 1189 1190 pWnd = ValidateHwnd(Wnd); 1191 if (pWnd) 1192 { 1193 if (!pWnd->fnid) 1194 { 1195 TRACE("ScrollBar CTL size %d\n", (sizeof(SBWND)-sizeof(WND))); 1196 if ( pWnd->cbwndExtra < (sizeof(SBWND)-sizeof(WND)) ) 1197 { 1198 ERR("Wrong Extra bytes for Scrollbar!\n"); 1199 return 0; 1200 } 1201 1202 if (Msg != WM_CREATE) 1203 { 1204 return DefWindowProc(Wnd, Msg, wParam, lParam); 1205 } 1206 NtUserSetWindowFNID(Wnd, FNID_SCROLLBAR); 1207 } 1208 else 1209 { 1210 if (pWnd->fnid != FNID_SCROLLBAR) 1211 { 1212 ERR("Wrong window class for Scrollbar!\n"); 1213 return 0; 1214 } 1215 } 1216 } 1217 #endif 1218 1219 if (! IsWindow(Wnd)) 1220 { 1221 return 0; 1222 } 1223 1224 // Must be a scroll bar control! 1225 pSBWnd = (PSBWND)pWnd; 1226 1227 switch (Msg) 1228 { 1229 case WM_CREATE: 1230 IntScrollCreateScrollBar(Wnd, (LPCREATESTRUCTW) lParam); 1231 break; 1232 1233 case WM_ENABLE: 1234 { 1235 return SendMessageW( Wnd, SBM_ENABLE_ARROWS, wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH, 0); 1236 } 1237 1238 case WM_LBUTTONDBLCLK: 1239 case WM_LBUTTONDOWN: 1240 if (GetWindowLongW( Wnd, GWL_STYLE ) & SBS_SIZEGRIP) 1241 { 1242 SendMessageW( GetParent(Wnd), WM_SYSCOMMAND, 1243 SC_SIZE + ((GetWindowLongW( Wnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) ? 1244 WMSZ_BOTTOMLEFT : WMSZ_BOTTOMRIGHT), lParam ); 1245 } 1246 else 1247 { 1248 POINT Pt; 1249 Pt.x = (short)LOWORD(lParam); 1250 Pt.y = (short)HIWORD(lParam); 1251 ScrollTrackScrollBar(Wnd, SB_CTL, Pt); 1252 } 1253 break; 1254 1255 case WM_LBUTTONUP: 1256 case WM_MOUSEMOVE: 1257 case WM_SYSTIMER: 1258 { 1259 POINT Pt; 1260 Pt.x = (short)LOWORD(lParam); 1261 Pt.y = (short)HIWORD(lParam); 1262 IntScrollHandleScrollEvent(Wnd, SB_CTL, Msg, Pt); 1263 } 1264 break; 1265 1266 case WM_KEYDOWN: 1267 IntScrollHandleKbdEvent(Wnd, wParam, lParam); 1268 break; 1269 1270 case WM_KEYUP: 1271 ShowCaret(Wnd); 1272 break; 1273 1274 case WM_SETFOCUS: 1275 { 1276 /* Create a caret when a ScrollBar get focus */ 1277 RECT Rect; 1278 int ArrowSize, ThumbSize, ThumbPos, Vertical; 1279 1280 Vertical = IntScrollGetScrollBarRect(Wnd, SB_CTL, &Rect, 1281 &ArrowSize, &ThumbSize, &ThumbPos); 1282 if (! Vertical) 1283 { 1284 CreateCaret(Wnd, (HBITMAP) 1, ThumbSize - 2, Rect.bottom - Rect.top - 2); 1285 SetCaretPos(ThumbPos + 1, Rect.top + 1); 1286 } 1287 else 1288 { 1289 CreateCaret(Wnd, (HBITMAP) 1, Rect.right - Rect.left - 2, ThumbSize - 2); 1290 SetCaretPos(Rect.top + 1, ThumbPos + 1); 1291 } 1292 ShowCaret(Wnd); 1293 } 1294 break; 1295 1296 case WM_KILLFOCUS: 1297 { 1298 RECT Rect; 1299 int ArrowSize, ThumbSize, ThumbPos, Vertical; 1300 1301 Vertical = IntScrollGetScrollBarRect(Wnd, SB_CTL, &Rect, 1302 &ArrowSize, &ThumbSize, &ThumbPos); 1303 if (! Vertical) 1304 { 1305 Rect.left = ThumbPos + 1; 1306 Rect.right = Rect.left + ThumbSize; 1307 } 1308 else 1309 { 1310 Rect.top = ThumbPos + 1; 1311 Rect.bottom = Rect.top + ThumbSize; 1312 } 1313 HideCaret(Wnd); 1314 InvalidateRect(Wnd, &Rect, FALSE); 1315 DestroyCaret(); 1316 } 1317 break; 1318 1319 case WM_ERASEBKGND: 1320 return 1; 1321 1322 case WM_GETDLGCODE: 1323 return DLGC_WANTARROWS; /* Windows returns this value */ 1324 1325 case WM_PAINT: 1326 { 1327 PAINTSTRUCT Ps; 1328 HDC Dc; 1329 1330 Dc = (0 != wParam ? (HDC) wParam : BeginPaint(Wnd, &Ps)); 1331 1332 if (GetWindowLongPtrW(Wnd, GWL_STYLE) & SBS_SIZEGRIP) 1333 { 1334 IntScrollDrawSizeGrip(Wnd, Dc); 1335 } 1336 else if (0 != (GetWindowLongPtrW(Wnd, GWL_STYLE) & SBS_SIZEBOX)) 1337 { 1338 RECT Rect; 1339 GetClientRect(Wnd, &Rect); 1340 FillRect(Dc, &Rect, GetSysColorBrush(COLOR_SCROLLBAR)); 1341 } 1342 else 1343 { 1344 IntDrawScrollBar(Wnd, Dc, SB_CTL/*, TRUE, TRUE*/); 1345 } 1346 1347 if (0 == wParam) 1348 { 1349 EndPaint(Wnd, &Ps); 1350 } 1351 } 1352 break; 1353 1354 case SBM_GETPOS: 1355 return pSBWnd->SBCalc.pos; 1356 1357 case SBM_GETRANGE: 1358 *(LPINT)wParam = pSBWnd->SBCalc.posMin; 1359 *(LPINT)lParam = pSBWnd->SBCalc.posMax; 1360 // This message does not return a value. 1361 return 0; 1362 1363 case SBM_ENABLE_ARROWS: 1364 return EnableScrollBar( Wnd, SB_CTL, wParam ); 1365 1366 case SBM_SETPOS: 1367 { 1368 ScrollInfo.cbSize = sizeof(SCROLLINFO); 1369 ScrollInfo.fMask = SIF_POS|SIF_PREVIOUSPOS; 1370 ScrollInfo.nPos = wParam; 1371 return IntSetScrollInfo(Wnd, &ScrollInfo, lParam); 1372 } 1373 1374 case SBM_SETRANGEREDRAW: 1375 case SBM_SETRANGE: 1376 { 1377 ScrollInfo.cbSize = sizeof(SCROLLINFO); 1378 ScrollInfo.fMask = SIF_RANGE|SIF_PREVIOUSPOS; 1379 ScrollInfo.nMin = wParam; 1380 ScrollInfo.nMax = lParam; 1381 return IntSetScrollInfo(Wnd, &ScrollInfo, Msg == SBM_SETRANGEREDRAW ? TRUE : FALSE); 1382 } 1383 1384 case SBM_SETSCROLLINFO: 1385 return IntSetScrollInfo(Wnd, (LPCSCROLLINFO)lParam, wParam); 1386 1387 case SBM_GETSCROLLINFO: 1388 { 1389 PSBDATA pSBData = (PSBDATA)&pSBWnd->SBCalc; 1390 DWORD ret = NtUserSBGetParms(Wnd, SB_CTL, pSBData, (SCROLLINFO *) lParam); 1391 if (!ret) 1392 { 1393 ERR("SBM_GETSCROLLINFO No ScrollInfo\n"); 1394 } 1395 return ret; 1396 } 1397 case SBM_GETSCROLLBARINFO: 1398 ((PSCROLLBARINFO)lParam)->cbSize = sizeof(SCROLLBARINFO); 1399 return NtUserGetScrollBarInfo(Wnd, OBJID_CLIENT, (PSCROLLBARINFO)lParam); 1400 1401 case 0x00e5: 1402 case 0x00e7: 1403 case 0x00e8: 1404 case 0x00ec: 1405 case 0x00ed: 1406 case 0x00ee: 1407 case 0x00ef: 1408 WARN("unknown Win32 msg %04x wp=%08lx lp=%08lx\n", 1409 Msg, wParam, lParam ); 1410 break; 1411 1412 default: 1413 if (WM_USER <= Msg) 1414 { 1415 WARN("unknown msg %04x wp=%04lx lp=%08lx\n", Msg, wParam, lParam); 1416 } 1417 if (unicode) 1418 return DefWindowProcW( Wnd, Msg, wParam, lParam ); 1419 else 1420 return DefWindowProcA( Wnd, Msg, wParam, lParam ); 1421 } 1422 1423 return 0; 1424 } 1425 1426 LRESULT WINAPI 1427 ScrollBarWndProcW(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) 1428 { 1429 return ScrollBarWndProc_common(DefWindowProcW, Wnd, Msg, wParam, lParam, TRUE); 1430 } 1431 1432 LRESULT WINAPI 1433 ScrollBarWndProcA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) 1434 { 1435 return ScrollBarWndProc_common(DefWindowProcA, Wnd, Msg, wParam, lParam, FALSE); 1436 } 1437 1438 1439 /* PUBLIC FUNCTIONS ***********************************************************/ 1440 1441 /* 1442 * @implemented 1443 */ 1444 BOOL 1445 WINAPI 1446 DECLSPEC_HOTPATCH 1447 EnableScrollBar( HWND hwnd, UINT nBar, UINT flags ) 1448 { 1449 BOOL Hook, Ret = FALSE; 1450 1451 LoadUserApiHook(); 1452 1453 Hook = BeginIfHookedUserApiHook(); 1454 1455 /* Bypass SEH and go direct. */ 1456 if (!Hook) 1457 { 1458 Ret = NtUserEnableScrollBar(hwnd, nBar, flags); 1459 if (!Ret) return Ret; 1460 SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE ); 1461 return Ret; 1462 } 1463 _SEH2_TRY 1464 { 1465 Ret = guah.EnableScrollBar(hwnd, nBar, flags); 1466 } 1467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1468 { 1469 ERR("Got exception in hooked EnableScrollBar!\n"); 1470 } 1471 _SEH2_END; 1472 1473 EndUserApiHook(); 1474 1475 return Ret; 1476 } 1477 1478 BOOL WINAPI 1479 RealGetScrollInfo(HWND Wnd, INT SBType, LPSCROLLINFO Info) 1480 { 1481 PWND pWnd; 1482 PSBDATA pSBData; 1483 1484 if (SB_CTL == SBType) 1485 { 1486 return SendMessageW(Wnd, SBM_GETSCROLLINFO, 0, (LPARAM) Info); 1487 } 1488 1489 pWnd = ValidateHwnd(Wnd); 1490 if (!pWnd) return FALSE; 1491 1492 if (SBType < SB_HORZ || SBType > SB_VERT) 1493 { 1494 SetLastError(ERROR_INVALID_PARAMETER); 1495 return FALSE; 1496 } 1497 if (!pWnd->pSBInfo) 1498 { 1499 SetLastError(ERROR_NO_SCROLLBARS); 1500 return FALSE; 1501 } 1502 pSBData = IntGetSBData(pWnd, SBType); 1503 return NtUserSBGetParms(Wnd, SBType, pSBData, Info); 1504 } 1505 1506 /* 1507 * @implemented 1508 */ 1509 BOOL WINAPI GetScrollBarInfo( _In_ HWND hwnd, _In_ LONG idObject, _Inout_ LPSCROLLBARINFO info) 1510 { 1511 BOOL Ret; 1512 PWND pWnd = ValidateHwnd(hwnd); 1513 TRACE("hwnd=%p idObject=%d info=%p\n", hwnd, idObject, info); 1514 if (!pWnd) return FALSE; 1515 Ret = NtUserGetScrollBarInfo(hwnd, idObject, info); // This will be fixed once SB is server side. 1516 /* rcScrollBar needs to be in screen coordinates */ 1517 OffsetRect( &(info->rcScrollBar), pWnd->rcWindow.left, pWnd->rcWindow.top ); 1518 return Ret; 1519 } 1520 1521 /* 1522 * @implemented 1523 */ 1524 BOOL 1525 WINAPI 1526 DECLSPEC_HOTPATCH 1527 GetScrollInfo(HWND Wnd, INT SBType, LPSCROLLINFO Info) 1528 { 1529 BOOL Hook, Ret = FALSE; 1530 1531 LoadUserApiHook(); 1532 1533 Hook = BeginIfHookedUserApiHook(); 1534 1535 /* Bypass SEH and go direct. */ 1536 if (!Hook) return RealGetScrollInfo(Wnd, SBType, Info); 1537 1538 _SEH2_TRY 1539 { 1540 Ret = guah.GetScrollInfo(Wnd, SBType, Info); 1541 } 1542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1543 { 1544 ERR("Got exception in hooked GetScrollInfo!\n"); 1545 } 1546 _SEH2_END; 1547 1548 EndUserApiHook(); 1549 1550 return Ret; 1551 } 1552 1553 /* 1554 * @implemented 1555 */ 1556 INT 1557 WINAPI 1558 DECLSPEC_HOTPATCH 1559 GetScrollPos(HWND Wnd, INT Bar) 1560 { 1561 PWND pwnd; 1562 PSBDATA pSBData; 1563 1564 TRACE("Wnd=%p Bar=%d\n", Wnd, Bar); 1565 1566 /* Refer SB_CTL requests to the window */ 1567 if (SB_CTL == Bar) 1568 { 1569 return SendMessageW(Wnd, SBM_GETPOS, (WPARAM) 0, (LPARAM) 0); 1570 } 1571 else if (Bar == SB_HORZ || Bar == SB_VERT ) 1572 { 1573 pwnd = ValidateHwnd(Wnd); 1574 if (!pwnd) return 0; 1575 1576 if (pwnd->pSBInfo) 1577 { 1578 pSBData = IntGetSBData(pwnd, Bar); 1579 return pSBData->pos; 1580 } 1581 1582 SetLastError(ERROR_NO_SCROLLBARS); 1583 TRACE("GetScrollPos No Scroll Info\n"); 1584 return 0; 1585 } 1586 SetLastError(ERROR_INVALID_PARAMETER); 1587 return 0; 1588 } 1589 1590 /* 1591 * @implemented 1592 */ 1593 BOOL 1594 WINAPI 1595 DECLSPEC_HOTPATCH 1596 GetScrollRange(HWND Wnd, int Bar, LPINT MinPos, LPINT MaxPos) 1597 { 1598 PWND pwnd; 1599 PSBDATA pSBData; 1600 1601 TRACE("Wnd=%x Bar=%d Min=%p Max=%p\n", Wnd, Bar, MinPos, MaxPos); 1602 1603 /* Refer SB_CTL requests to the window */ 1604 if (SB_CTL == Bar) 1605 { 1606 return SendMessageW(Wnd, SBM_GETRANGE, (WPARAM) MinPos, (LPARAM) MaxPos); 1607 } 1608 else if (Bar == SB_HORZ || Bar == SB_VERT ) 1609 { 1610 pwnd = ValidateHwnd(Wnd); 1611 if (!pwnd) return FALSE; 1612 1613 if (pwnd->pSBInfo) 1614 { 1615 pSBData = IntGetSBData(pwnd, Bar); 1616 *MinPos = pSBData->posMin; 1617 *MaxPos = pSBData->posMax; 1618 } 1619 else 1620 { 1621 SetLastError(ERROR_NO_SCROLLBARS); 1622 *MinPos = 0; 1623 *MaxPos = 0; 1624 } 1625 return TRUE; 1626 } 1627 SetLastError(ERROR_INVALID_PARAMETER); 1628 return FALSE; 1629 } 1630 1631 INT WINAPI 1632 RealSetScrollInfo(HWND Wnd, int SBType, LPCSCROLLINFO Info, BOOL bRedraw) 1633 { 1634 if (SB_CTL == SBType) 1635 { 1636 return SendMessageW(Wnd, SBM_SETSCROLLINFO, (WPARAM) bRedraw, (LPARAM) Info); 1637 } 1638 else 1639 { 1640 return NtUserSetScrollInfo(Wnd, SBType, Info, bRedraw); 1641 } 1642 } 1643 1644 /* 1645 * @implemented 1646 */ 1647 INT 1648 WINAPI 1649 DECLSPEC_HOTPATCH 1650 SetScrollInfo(HWND Wnd, int SBType, LPCSCROLLINFO Info, BOOL bRedraw) 1651 { 1652 BOOL Hook; 1653 INT Ret = 0; 1654 1655 LoadUserApiHook(); 1656 1657 Hook = BeginIfHookedUserApiHook(); 1658 1659 /* Bypass SEH and go direct. */ 1660 if (!Hook) return RealSetScrollInfo(Wnd, SBType, Info, bRedraw); 1661 1662 _SEH2_TRY 1663 { 1664 Ret = guah.SetScrollInfo(Wnd, SBType, Info, bRedraw); 1665 } 1666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1667 { 1668 ERR("Got exception in hooked SetScrollInfo!\n"); 1669 } 1670 _SEH2_END; 1671 1672 EndUserApiHook(); 1673 1674 return Ret; 1675 1676 } 1677 1678 /* 1679 * @implemented 1680 */ 1681 INT 1682 WINAPI 1683 DECLSPEC_HOTPATCH 1684 SetScrollPos(HWND hWnd, INT nBar, INT nPos, BOOL bRedraw) 1685 { 1686 SCROLLINFO ScrollInfo; 1687 1688 ScrollInfo.cbSize = sizeof(SCROLLINFO); 1689 ScrollInfo.fMask = SIF_POS|SIF_PREVIOUSPOS; 1690 ScrollInfo.nPos = nPos; 1691 1692 return RealSetScrollInfo(hWnd, nBar, &ScrollInfo, bRedraw); 1693 } 1694 1695 /* 1696 * @implemented 1697 */ 1698 BOOL 1699 WINAPI 1700 DECLSPEC_HOTPATCH 1701 SetScrollRange(HWND hWnd, INT nBar, INT nMinPos, INT nMaxPos, BOOL bRedraw) 1702 { 1703 PWND pWnd; 1704 SCROLLINFO ScrollInfo; 1705 1706 pWnd = ValidateHwnd(hWnd); 1707 if ( !pWnd ) return FALSE; 1708 1709 if (((LONGLONG)nMaxPos - nMinPos) > MAXLONG) 1710 { 1711 SetLastError(ERROR_INVALID_SCROLLBAR_RANGE); 1712 return FALSE; 1713 } 1714 1715 ScrollInfo.cbSize = sizeof(SCROLLINFO); 1716 ScrollInfo.fMask = SIF_RANGE; 1717 ScrollInfo.nMin = nMinPos; 1718 ScrollInfo.nMax = nMaxPos; 1719 SetScrollInfo(hWnd, nBar, &ScrollInfo, bRedraw); // do not bypass themes. 1720 return TRUE; 1721 } 1722