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
ScreenToWindow(HWND hWnd,POINT * pt)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
SCROLL_IsVertical(HWND hwnd,INT nBar)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
SCROLL_getObjectId(INT nBar)38 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 */
SCROLL_PtInRectEx(LPRECT lpRect,POINT pt,BOOL vertical)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 */
SCROLL_HitTest(HWND hwnd,SCROLLBARINFO * psbi,BOOL vertical,POINT pt,BOOL bDragging)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
SCROLL_ThemeDrawPart(PDRAW_CONTEXT pcontext,int iPartId,int iStateId,SCROLLBARINFO * psbi,int htCurrent,int htDown,int htHot,RECT * r)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 */
SCROLL_DrawArrows(PDRAW_CONTEXT pcontext,SCROLLBARINFO * psbi,BOOL vertical,int htDown,int htHot)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
SCROLL_DrawInterior(PDRAW_CONTEXT pcontext,SCROLLBARINFO * psbi,INT thumbPos,BOOL vertical,int htDown,int htHot)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
SCROLL_DrawMovingThumb(PWND_DATA pwndData,PDRAW_CONTEXT pcontext,SCROLLBARINFO * psbi,BOOL vertical)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
ThemeDrawScrollBarEx(PDRAW_CONTEXT pcontext,INT nBar,PSCROLLBARINFO psbi,POINT * pt)276 ThemeDrawScrollBarEx(PDRAW_CONTEXT pcontext, INT nBar, PSCROLLBARINFO psbi, POINT* pt)
277 {
278 SCROLLINFO si;
279 BOOL vertical;
280 enum SCROLL_HITTEST htHot = SCROLL_NOWHERE;
281 PWND_DATA pwndData;
282
283 if (!(pwndData = ThemeGetWndData(pcontext->hWnd)))
284 return;
285
286 if (pwndData->SCROLL_TrackingWin)
287 return;
288
289 /* Retrieve scrollbar info */
290 si.cbSize = sizeof(si);
291 si.fMask = SIF_ALL ;
292 GetScrollInfo(pcontext->hWnd, nBar, &si);
293 vertical = SCROLL_IsVertical(pcontext->hWnd, nBar);
294 if(psbi->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE &&
295 psbi->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE )
296 {
297 psbi->xyThumbTop = 0;
298 }
299
300 /* The scrollbar rect is in screen coordinates */
301 OffsetRect(&psbi->rcScrollBar, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top);
302
303 if(pt)
304 {
305 ScreenToWindow(pcontext->hWnd, pt);
306 htHot = SCROLL_HitTest(pcontext->hWnd, psbi, vertical, *pt, FALSE);
307 }
308
309 /* do not draw if the scrollbar rectangle is empty */
310 if(IsRectEmpty(&psbi->rcScrollBar)) return;
311
312 /* Draw the scrollbar */
313 SCROLL_DrawArrows( pcontext, psbi, vertical, 0, htHot );
314 SCROLL_DrawInterior( pcontext, psbi, psbi->xyThumbTop, vertical, 0, htHot );
315 }
316
317 void
ThemeDrawScrollBar(PDRAW_CONTEXT pcontext,INT nBar,POINT * pt)318 ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT nBar, POINT* pt)
319 {
320 SCROLLBARINFO sbi;
321
322 if (((nBar == SB_VERT) && !(pcontext->wi.dwStyle & WS_VSCROLL)) ||
323 ((nBar == SB_HORZ) && !(pcontext->wi.dwStyle & WS_HSCROLL)))
324 {
325 return;
326 }
327
328 sbi.cbSize = sizeof(sbi);
329 GetScrollBarInfo(pcontext->hWnd, SCROLL_getObjectId(nBar), &sbi);
330 ThemeDrawScrollBarEx(pcontext, nBar, &sbi, pt);
331 }
332
333
334 /***********************************************************************
335 * SCROLL_ClipPos
336 */
SCROLL_ClipPos(LPRECT lpRect,POINT pt)337 static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt )
338 {
339 if( pt.x < lpRect->left )
340 pt.x = lpRect->left;
341 else
342 if( pt.x > lpRect->right )
343 pt.x = lpRect->right;
344
345 if( pt.y < lpRect->top )
346 pt.y = lpRect->top;
347 else
348 if( pt.y > lpRect->bottom )
349 pt.y = lpRect->bottom;
350
351 return pt;
352 }
353
354
355
356 /***********************************************************************
357 * SCROLL_GetThumbVal
358 *
359 * Compute the current scroll position based on the thumb position in pixels
360 * from the top of the scroll-bar.
361 */
SCROLL_GetThumbVal(SCROLLINFO * psi,RECT * rect,BOOL vertical,INT pos)362 static UINT SCROLL_GetThumbVal( SCROLLINFO *psi, RECT *rect,
363 BOOL vertical, INT pos )
364 {
365 INT thumbSize;
366 INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
367 INT range;
368
369 if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
370 return psi->nMin;
371
372 if (psi->nPage)
373 {
374 thumbSize = MulDiv(pixels,psi->nPage,(psi->nMax-psi->nMin+1));
375 if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
376 }
377 else thumbSize = GetSystemMetrics(SM_CXVSCROLL);
378
379 if ((pixels -= thumbSize) <= 0) return psi->nMin;
380
381 pos = max( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) );
382 if (pos > pixels) pos = pixels;
383
384 if (!psi->nPage)
385 range = psi->nMax - psi->nMin;
386 else
387 range = psi->nMax - psi->nMin - psi->nPage + 1;
388
389 return psi->nMin + MulDiv(pos, range, pixels);
390 }
391
392 static void
SCROLL_HandleScrollEvent(PWND_DATA pwndData,HWND hwnd,INT nBar,UINT msg,POINT pt)393 SCROLL_HandleScrollEvent(PWND_DATA pwndData, HWND hwnd, INT nBar, UINT msg, POINT pt)
394 {
395 /* Previous mouse position for timer events */
396 static POINT prevPt;
397 /* Thumb position when tracking started. */
398 static UINT trackThumbPos;
399 /* Position in the scroll-bar of the last button-down event. */
400 static INT lastClickPos;
401 /* Position in the scroll-bar of the last mouse event. */
402 static INT lastMousePos;
403
404 enum SCROLL_HITTEST hittest;
405 HWND hwndOwner, hwndCtl;
406 BOOL vertical;
407 SCROLLINFO si;
408 SCROLLBARINFO sbi;
409 DRAW_CONTEXT context;
410
411 si.cbSize = sizeof(si);
412 sbi.cbSize = sizeof(sbi);
413 si.fMask = SIF_ALL;
414 GetScrollInfo(hwnd, nBar, &si);
415 GetScrollBarInfo(hwnd, SCROLL_getObjectId(nBar), &sbi);
416 vertical = SCROLL_IsVertical(hwnd, nBar);
417 if(sbi.rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE &&
418 sbi.rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE )
419 {
420 return;
421 }
422
423 if ((pwndData->SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN))
424 return;
425
426 ThemeInitDrawContext(&context, hwnd, 0);
427
428 /* The scrollbar rect is in screen coordinates */
429 OffsetRect(&sbi.rcScrollBar, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
430
431 hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
432 hwndCtl = (nBar == SB_CTL) ? hwnd : 0;
433
434 switch(msg)
435 {
436 case WM_LBUTTONDOWN: /* Initialise mouse tracking */
437 HideCaret(hwnd); /* hide caret while holding down LBUTTON */
438 pwndData->SCROLL_trackVertical = vertical;
439 pwndData->SCROLL_trackHitTest = hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE );
440 lastClickPos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left);
441 lastMousePos = lastClickPos;
442 trackThumbPos = sbi.xyThumbTop;
443 prevPt = pt;
444 SetCapture( hwnd );
445 break;
446
447 case WM_MOUSEMOVE:
448 hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, TRUE );
449 prevPt = pt;
450 break;
451
452 case WM_LBUTTONUP:
453 hittest = SCROLL_NOWHERE;
454 ReleaseCapture();
455 /* if scrollbar has focus, show back caret */
456 if (hwnd==GetFocus())
457 ShowCaret(hwnd);
458 break;
459
460 case WM_SYSTIMER:
461 pt = prevPt;
462 hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE );
463 break;
464
465 default:
466 return; /* Should never happen */
467 }
468
469 //TRACE("Event: hwnd=%p bar=%d msg=%s pt=%d,%d hit=%d\n",
470 // hwnd, nBar, SPY_GetMsgName(msg,hwnd), pt.x, pt.y, hittest );
471
472 switch(pwndData->SCROLL_trackHitTest)
473 {
474 case SCROLL_NOWHERE: /* No tracking in progress */
475 break;
476
477 case SCROLL_TOP_ARROW:
478 if (hittest == pwndData->SCROLL_trackHitTest)
479 {
480 SCROLL_DrawArrows( &context, &sbi, vertical, pwndData->SCROLL_trackHitTest, 0 );
481 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
482 {
483 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
484 SB_LINEUP, (LPARAM)hwndCtl );
485 }
486
487 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
488 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
489 }
490 else
491 {
492 SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 );
493 KillSystemTimer( hwnd, SCROLL_TIMER );
494 }
495
496 break;
497
498 case SCROLL_TOP_RECT:
499 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, pwndData->SCROLL_trackHitTest, 0);
500 if (hittest == pwndData->SCROLL_trackHitTest)
501 {
502 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
503 {
504 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
505 SB_PAGEUP, (LPARAM)hwndCtl );
506 }
507 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
508 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
509 }
510 else KillSystemTimer( hwnd, SCROLL_TIMER );
511 break;
512
513 case SCROLL_THUMB:
514 if (msg == WM_LBUTTONDOWN)
515 {
516 pwndData->SCROLL_TrackingWin = hwnd;
517 pwndData->SCROLL_TrackingBar = nBar;
518 pwndData->SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
519 pwndData->SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar,
520 vertical, pwndData->SCROLL_TrackingPos );
521 if (!pwndData->SCROLL_MovingThumb)
522 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
523 }
524 else if (msg == WM_LBUTTONUP)
525 {
526 if (pwndData->SCROLL_MovingThumb)
527 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
528
529 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, pwndData->SCROLL_trackHitTest );
530 }
531 else /* WM_MOUSEMOVE */
532 {
533 INT pos;
534
535 if (!SCROLL_PtInRectEx( &sbi.rcScrollBar, pt, vertical ))
536 pos = lastClickPos;
537 else
538 {
539 pt = SCROLL_ClipPos( &sbi.rcScrollBar, pt );
540 pos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left);
541 }
542 if ( (pos != lastMousePos) || (!pwndData->SCROLL_MovingThumb) )
543 {
544 if (pwndData->SCROLL_MovingThumb)
545 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
546 lastMousePos = pos;
547 pwndData->SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
548 pwndData->SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar,
549 vertical,
550 pwndData->SCROLL_TrackingPos );
551 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
552 MAKEWPARAM( SB_THUMBTRACK, pwndData->SCROLL_TrackingVal),
553 (LPARAM)hwndCtl );
554 if (!pwndData->SCROLL_MovingThumb)
555 SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
556 }
557 }
558 break;
559
560 case SCROLL_BOTTOM_RECT:
561 if (hittest == pwndData->SCROLL_trackHitTest)
562 {
563 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, pwndData->SCROLL_trackHitTest, 0 );
564 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
565 {
566 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
567 SB_PAGEDOWN, (LPARAM)hwndCtl );
568 }
569 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
570 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
571 }
572 else
573 {
574 SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, 0 );
575 KillSystemTimer( hwnd, SCROLL_TIMER );
576 }
577 break;
578
579 case SCROLL_BOTTOM_ARROW:
580 if (hittest == pwndData->SCROLL_trackHitTest)
581 {
582 SCROLL_DrawArrows( &context, &sbi, vertical, pwndData->SCROLL_trackHitTest, 0 );
583 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
584 {
585 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
586 SB_LINEDOWN, (LPARAM)hwndCtl );
587 }
588
589 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
590 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
591 }
592 else
593 {
594 SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 );
595 KillSystemTimer( hwnd, SCROLL_TIMER );
596 }
597 break;
598 }
599
600 if (msg == WM_LBUTTONDOWN)
601 {
602
603 if (hittest == SCROLL_THUMB)
604 {
605 UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical,
606 trackThumbPos + lastMousePos - lastClickPos );
607 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
608 MAKEWPARAM( SB_THUMBTRACK, val ), (LPARAM)hwndCtl );
609 }
610 }
611
612 if (msg == WM_LBUTTONUP)
613 {
614 hittest = pwndData->SCROLL_trackHitTest;
615 pwndData->SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
616
617 if (hittest == SCROLL_THUMB)
618 {
619 UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical,
620 trackThumbPos + lastMousePos - lastClickPos );
621 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
622 MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl );
623 }
624 /* SB_ENDSCROLL doesn't report thumb position */
625 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
626 SB_ENDSCROLL, (LPARAM)hwndCtl );
627
628 /* Terminate tracking */
629 pwndData->SCROLL_TrackingWin = 0;
630 }
631
632 ThemeCleanupDrawContext(&context);
633 }
634
635 static void
SCROLL_TrackScrollBar(HWND hwnd,INT scrollbar,POINT pt)636 SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt )
637 {
638 MSG msg;
639 PWND_DATA pwndData = ThemeGetWndData(hwnd);
640 if(!pwndData)
641 return;
642
643 ScreenToWindow(hwnd, &pt);
644
645 SCROLL_HandleScrollEvent(pwndData, hwnd, scrollbar, WM_LBUTTONDOWN, pt );
646
647 do
648 {
649 if (!GetMessageW( &msg, 0, 0, 0 )) break;
650 if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue;
651 if (msg.message == WM_LBUTTONUP ||
652 msg.message == WM_MOUSEMOVE ||
653 (msg.message == WM_SYSTIMER && msg.wParam == SCROLL_TIMER))
654 {
655 pt.x = GET_X_LPARAM(msg.lParam);
656 pt.y = GET_Y_LPARAM(msg.lParam);
657 ClientToScreen(hwnd, &pt);
658 ScreenToWindow(hwnd, &pt);
659 SCROLL_HandleScrollEvent(pwndData, hwnd, scrollbar, msg.message, pt );
660 }
661 else
662 {
663 TranslateMessage( &msg );
664 DispatchMessageW( &msg );
665 }
666 if (!IsWindow( hwnd ))
667 {
668 ReleaseCapture();
669 break;
670 }
671 } while (msg.message != WM_LBUTTONUP && GetCapture() == hwnd);
672 }
673
NC_TrackScrollBar(HWND hwnd,WPARAM wParam,POINT pt)674 void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
675 {
676 INT scrollbar;
677
678 if ((wParam & 0xfff0) == SC_HSCROLL)
679 {
680 if ((wParam & 0x0f) != HTHSCROLL) return;
681 scrollbar = SB_HORZ;
682 }
683 else /* SC_VSCROLL */
684 {
685 if ((wParam & 0x0f) != HTVSCROLL) return;
686 scrollbar = SB_VERT;
687 }
688 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
689 }
690