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