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