xref: /reactos/dll/win32/uxtheme/ncscrollbar.c (revision 118869f6)
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