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