Release 941210
[wine/multimedia.git] / controls / scroll.c
blobe28347a416d3cb947416abfa09bf3485d465a70f
1 /*
2 * Interface code to SCROLLBAR widget
4 * Copyright Martin Ayotte, 1993
5 * Copyright Alexandre Julliard, 1994
7 * Small fixes and implemented SB_THUMBPOSITION
8 * by Peter Broadhurst, 940611
9 */
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include "windows.h"
16 #include "syscolor.h"
17 #include "sysmetrics.h"
18 #include "scroll.h"
19 #include "user.h"
20 #include "graphics.h"
21 #include "win.h"
22 #include "stddebug.h"
23 /* #define DEBUG_SCROLL */
24 #include "debug.h"
27 static HBITMAP hUpArrow = 0;
28 static HBITMAP hDnArrow = 0;
29 static HBITMAP hLfArrow = 0;
30 static HBITMAP hRgArrow = 0;
31 static HBITMAP hUpArrowD = 0;
32 static HBITMAP hDnArrowD = 0;
33 static HBITMAP hLfArrowD = 0;
34 static HBITMAP hRgArrowD = 0;
35 static HBITMAP hUpArrowI = 0;
36 static HBITMAP hDnArrowI = 0;
37 static HBITMAP hLfArrowI = 0;
38 static HBITMAP hRgArrowI = 0;
40 #define TOP_ARROW(flags,pressed) \
41 (((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow))
42 #define BOTTOM_ARROW(flags,pressed) \
43 (((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow))
44 #define LEFT_ARROW(flags,pressed) \
45 (((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow))
46 #define RIGHT_ARROW(flags,pressed) \
47 (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow))
50 /* Minimum size of the rectangle between the arrows */
51 #define SCROLL_MIN_RECT 4
53 /* Delay (in ms) before first repetition when holding the button down */
54 #define SCROLL_FIRST_DELAY 200
56 /* Delay (in ms) between scroll repetitions */
57 #define SCROLL_REPEAT_DELAY 100
59 /* Scroll timer id */
60 #define SCROLL_TIMER 0
62 /* Scroll-bar hit testing */
63 enum SCROLL_HITTEST
65 SCROLL_NOWHERE, /* Outside the scroll bar */
66 SCROLL_TOP_ARROW, /* Top or left arrow */
67 SCROLL_TOP_RECT, /* Rectangle between the top arrow and the thumb */
68 SCROLL_THUMB, /* Thumb rectangle */
69 SCROLL_BOTTOM_RECT, /* Rectangle between the thumb and the bottom arrow */
70 SCROLL_BOTTOM_ARROW /* Bottom or right arrow */
74 /***********************************************************************
75 * SCROLL_LoadBitmaps
77 static void SCROLL_LoadBitmaps(void)
79 hUpArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_UPARROW));
80 hDnArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_DNARROW));
81 hLfArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_LFARROW));
82 hRgArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_RGARROW));
83 hUpArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_UPARROWD));
84 hDnArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_DNARROWD));
85 hLfArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_LFARROWD));
86 hRgArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_RGARROWD));
87 hUpArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_UPARROWI));
88 hDnArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_DNARROWI));
89 hLfArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_LFARROWI));
90 hRgArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_RGARROWI));
94 /***********************************************************************
95 * SCROLL_GetScrollInfo
97 static SCROLLINFO *SCROLL_GetScrollInfo( HWND hwnd, int nBar )
99 HANDLE handle;
100 WND *wndPtr = WIN_FindWndPtr( hwnd );
102 switch(nBar)
104 case SB_HORZ: handle = wndPtr->hHScroll; break;
105 case SB_VERT: handle = wndPtr->hVScroll; break;
106 case SB_CTL: return (SCROLLINFO *)wndPtr->wExtra;
107 default: return NULL;
110 if (!handle) /* Create the info structure if needed */
112 if ((handle = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(SCROLLINFO) )))
114 SCROLLINFO *infoPtr = (SCROLLINFO *) USER_HEAP_ADDR( handle );
115 infoPtr->MinVal = infoPtr->CurVal = 0;
116 infoPtr->MaxVal = 100;
117 infoPtr->flags = ESB_ENABLE_BOTH;
118 if (nBar == SB_HORZ) wndPtr->hHScroll = handle;
119 else wndPtr->hVScroll = handle;
121 if (!hUpArrow) SCROLL_LoadBitmaps();
123 return (SCROLLINFO *) USER_HEAP_ADDR( handle );
127 /***********************************************************************
128 * SCROLL_GetScrollBarRect
130 * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
131 * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
132 * 'arrowSize' returns the width or height of an arrow (depending on the
133 * orientation of the scrollbar), and 'thumbPos' returns the position of
134 * the thumb relative to the left or to the top.
135 * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
137 static BOOL SCROLL_GetScrollBarRect( HWND hwnd, int nBar, RECT *lprect,
138 WORD *arrowSize, WORD *thumbPos )
140 int pixels;
141 BOOL vertical;
142 WND *wndPtr = WIN_FindWndPtr( hwnd );
144 switch(nBar)
146 case SB_HORZ:
147 lprect->left = wndPtr->rectClient.left - wndPtr->rectWindow.left - 1;
148 lprect->top = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
149 lprect->right = wndPtr->rectClient.right - wndPtr->rectWindow.left +1;
150 lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL + 1;
151 vertical = FALSE;
152 break;
154 case SB_VERT:
155 lprect->left = wndPtr->rectClient.right - wndPtr->rectWindow.left;
156 lprect->top = wndPtr->rectClient.top - wndPtr->rectWindow.top - 1;
157 lprect->right = lprect->left + SYSMETRICS_CXVSCROLL + 1;
158 lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top +1;
159 vertical = TRUE;
160 break;
162 case SB_CTL:
163 GetClientRect( hwnd, lprect );
164 vertical = ((wndPtr->dwStyle & SBS_VERT) != 0);
165 break;
168 if (vertical) pixels = lprect->bottom - lprect->top;
169 else pixels = lprect->right - lprect->left;
171 if (pixels > 2*SYSMETRICS_CXVSCROLL + SCROLL_MIN_RECT)
173 *arrowSize = SYSMETRICS_CXVSCROLL;
175 else if (pixels > SCROLL_MIN_RECT)
177 *arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
179 else *arrowSize = 0;
181 if ((pixels -= 3*SYSMETRICS_CXVSCROLL+1) > 0)
183 SCROLLINFO *info = SCROLL_GetScrollInfo( hwnd, nBar );
184 if ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
185 *thumbPos = 0;
186 else if (info->MinVal == info->MaxVal)
187 *thumbPos = *arrowSize;
188 else
189 *thumbPos = *arrowSize + pixels * (info->CurVal - info->MinVal) /
190 (info->MaxVal - info->MinVal);
192 else *thumbPos = 0;
193 return vertical;
197 /***********************************************************************
198 * SCROLL_GetThumbVal
200 * Compute the current scroll position based on the thumb position in pixels
201 * from the top of the scroll-bar.
203 static UINT SCROLL_GetThumbVal( SCROLLINFO *infoPtr, RECT *rect,
204 WORD arrowSize, BOOL vertical, WORD pos )
206 int pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
207 if ((pixels -= 3*SYSMETRICS_CXVSCROLL+1) <= 0) return infoPtr->MinVal;
208 pos = max( 0, pos - SYSMETRICS_CXVSCROLL );
209 if (pos > pixels) pos = pixels;
210 dprintf_scroll(stddeb,"GetThumbVal: pos=%d ret=%d\n", pos,
211 (infoPtr->MinVal
212 + (UINT)(((int)pos * (infoPtr->MaxVal-infoPtr->MinVal) + pixels/2)
213 / pixels)) );
214 return (infoPtr->MinVal
215 + (UINT)(((int)pos * (infoPtr->MaxVal-infoPtr->MinVal) + pixels/2)
216 / pixels));
220 /***********************************************************************
221 * SCROLL_HitTest
223 * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
225 static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, int nBar, POINT pt )
227 WORD arrowSize, thumbPos;
228 RECT rect;
230 BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
231 &arrowSize, &thumbPos );
232 if (!PtInRect( &rect, pt )) return SCROLL_NOWHERE;
234 if (vertical)
236 if (pt.y <= rect.top + arrowSize + 1) return SCROLL_TOP_ARROW;
237 if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
238 if (!thumbPos) return SCROLL_TOP_RECT;
239 pt.y -= rect.top;
240 if (pt.y < (INT)thumbPos) return SCROLL_TOP_RECT;
241 if (pt.y > thumbPos+SYSMETRICS_CYHSCROLL) return SCROLL_BOTTOM_RECT;
242 return SCROLL_THUMB;
244 else /* horizontal */
246 if (pt.x <= rect.left + arrowSize) return SCROLL_TOP_ARROW;
247 if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
248 if (!thumbPos) return SCROLL_TOP_RECT;
249 pt.x -= rect.left;
250 if (pt.x < (INT)thumbPos) return SCROLL_TOP_RECT;
251 if (pt.x > thumbPos+SYSMETRICS_CXVSCROLL) return SCROLL_BOTTOM_RECT;
252 return SCROLL_THUMB;
257 /***********************************************************************
258 * SCROLL_DrawArrows
260 * Draw the scroll bar arrows.
262 static void SCROLL_DrawArrows( HDC hdc, SCROLLINFO *infoPtr, RECT *rect,
263 WORD arrowSize, BOOL vertical,
264 BOOL top_pressed, BOOL bottom_pressed )
266 HDC hdcMem = CreateCompatibleDC( hdc );
267 HBITMAP hbmpPrev = SelectObject( hdcMem, vertical ?
268 TOP_ARROW(infoPtr->flags, top_pressed)
269 : LEFT_ARROW(infoPtr->flags, top_pressed));
270 StretchBlt( hdc, rect->left, rect->top,
271 vertical ? rect->right-rect->left : arrowSize+1,
272 vertical ? arrowSize+1 : rect->bottom-rect->top,
273 hdcMem, 0, 0,
274 SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
275 SRCCOPY );
277 SelectObject( hdcMem, vertical ?
278 BOTTOM_ARROW( infoPtr->flags, bottom_pressed )
279 : RIGHT_ARROW( infoPtr->flags, bottom_pressed ) );
280 if (vertical)
281 StretchBlt( hdc, rect->left, rect->bottom - arrowSize - 1,
282 rect->right - rect->left, arrowSize + 1,
283 hdcMem, 0, 0,
284 SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
285 SRCCOPY );
286 else
287 StretchBlt( hdc, rect->right - arrowSize - 1, rect->top,
288 arrowSize + 1, rect->bottom - rect->top,
289 hdcMem, 0, 0,
290 SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
291 SRCCOPY );
292 SelectObject( hdcMem, hbmpPrev );
293 DeleteDC( hdcMem );
297 /***********************************************************************
298 * SCROLL_DrawMovingThumb
300 * Draw the moving thumb rectangle.
302 static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical,
303 WORD arrowSize, WORD thumbPos )
305 RECT r = *rect;
306 if (vertical)
308 r.top += thumbPos;
309 if (r.top < rect->top + arrowSize) r.top = rect->top + arrowSize;
310 if (r.top + SYSMETRICS_CYHSCROLL >= rect->bottom - arrowSize)
311 r.top = rect->bottom - arrowSize - SYSMETRICS_CYHSCROLL - 1;
312 r.bottom = r.top + SYSMETRICS_CYHSCROLL + 1;
314 else
316 r.left += thumbPos;
317 if (r.left < rect->left + arrowSize) r.left = rect->left + arrowSize;
318 if (r.left + SYSMETRICS_CXVSCROLL >= rect->right - arrowSize)
319 r.left = rect->right - arrowSize - SYSMETRICS_CXVSCROLL - 1;
320 r.right = r.left + SYSMETRICS_CXVSCROLL + 1;
322 InflateRect( &r, -1, -1 );
323 DrawFocusRect( hdc, &r );
327 /***********************************************************************
328 * SCROLL_DrawInterior
330 * Draw the scroll bar interior (everything except the arrows).
332 static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, int nBar, RECT *rect,
333 WORD arrowSize, WORD thumbPos, WORD flags,
334 BOOL vertical, BOOL top_selected,
335 BOOL bottom_selected )
337 RECT r;
338 WND *wndPtr = WIN_FindWndPtr( hwnd );
339 if (((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL))
340 || ((nBar == SB_HORZ) && (!wndPtr->dwStyle & WS_HSCROLL))) return;
342 /* Select the correct brush and pen */
344 SelectObject( hdc, sysColorObjects.hpenWindowFrame );
345 if ((flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
347 /* This ought to be the color of the parent window */
348 SelectObject( hdc, sysColorObjects.hbrushWindow );
350 else
352 if (nBar == SB_CTL) /* Only scrollbar controls send WM_CTLCOLOR */
354 HBRUSH hbrush = SendMessage( GetParent(hwnd), WM_CTLCOLOR, hdc,
355 MAKELONG(hwnd, CTLCOLOR_SCROLLBAR) );
356 SelectObject( hdc, hbrush );
358 else SelectObject( hdc, sysColorObjects.hbrushScrollbar );
361 /* Calculate the scroll rectangle */
363 r = *rect;
364 if (vertical)
366 r.top += arrowSize;
367 r.bottom -= arrowSize;
369 else
371 r.left += arrowSize;
372 r.right -= arrowSize;
375 /* Draw the scroll bar frame */
377 MoveTo( hdc, r.left, r.top );
378 LineTo( hdc, r.right-1, r.top );
379 LineTo( hdc, r.right-1, r.bottom-1 );
380 LineTo( hdc, r.left, r.bottom-1 );
381 LineTo( hdc, r.left, r.top );
383 /* Draw the scroll rectangles and thumb */
385 if (!thumbPos) /* No thumb to draw */
387 PatBlt( hdc, r.left+1, r.top+1, r.right - r.left - 2,
388 r.bottom - r.top - 2, SRCCOPY );
389 return;
392 if (vertical)
394 PatBlt( hdc, r.left + 1, r.top + 1,
395 r.right - r.left - 2,
396 thumbPos - arrowSize,
397 top_selected ? NOTSRCCOPY : SRCCOPY );
398 r.top += thumbPos - arrowSize;
399 PatBlt( hdc, r.left + 1, r.top + SYSMETRICS_CYHSCROLL + 1,
400 r.right - r.left - 2,
401 r.bottom - r.top - SYSMETRICS_CYHSCROLL - 2,
402 bottom_selected ? NOTSRCCOPY : SRCCOPY );
403 r.bottom = r.top + SYSMETRICS_CYHSCROLL + 1;
405 else /* horizontal */
407 PatBlt( hdc, r.left + 1, r.top + 1,
408 thumbPos - arrowSize,
409 r.bottom - r.top - 2,
410 top_selected ? NOTSRCCOPY : SRCCOPY );
411 r.left += thumbPos - arrowSize;
412 PatBlt( hdc, r.left + SYSMETRICS_CYHSCROLL + 1, r.top + 1,
413 r.right - r.left - SYSMETRICS_CYHSCROLL - 2,
414 r.bottom - r.top - 2,
415 bottom_selected ? NOTSRCCOPY : SRCCOPY );
416 r.right = r.left + SYSMETRICS_CXVSCROLL + 1;
419 /* Draw the thumb */
421 SelectObject( hdc, sysColorObjects.hbrushBtnFace );
422 Rectangle( hdc, r.left, r.top, r.right, r.bottom );
423 InflateRect( &r, -1, -1 );
424 GRAPH_DrawReliefRect( hdc, &r, 1, 2, FALSE );
428 /***********************************************************************
429 * SCROLL_DrawScrollBar
431 * Redraw the whole scrollbar.
433 void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, int nBar )
435 WORD arrowSize, thumbPos;
436 RECT rect;
437 BOOL vertical;
439 SCROLLINFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
440 if (!infoPtr) return;
441 vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
442 &arrowSize, &thumbPos );
443 /* Draw the arrows */
445 if (arrowSize) SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize,
446 vertical, FALSE, FALSE );
448 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
449 infoPtr->flags, vertical, FALSE, FALSE );
453 /***********************************************************************
454 * SCROLL_RefreshScrollBar
456 * Repaint the scroll bar interior after a SetScrollRange() or
457 * SetScrollPos() call.
459 static void SCROLL_RefreshScrollBar( HWND hwnd, int nBar )
461 WORD arrowSize, thumbPos;
462 RECT rect;
463 BOOL vertical;
464 HDC hdc;
466 SCROLLINFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
467 if (!infoPtr) return;
468 vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
469 &arrowSize, &thumbPos );
470 hdc = (nBar == SB_CTL) ? GetDC(hwnd) : GetWindowDC(hwnd);
471 if (!hdc) return;
472 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
473 infoPtr->flags, vertical, FALSE, FALSE );
474 ReleaseDC( hwnd, hdc );
478 /***********************************************************************
479 * SCROLL_HandleKbdEvent
481 * Handle a keyboard event (only for SB_CTL scrollbars).
483 static void SCROLL_HandleKbdEvent( HWND hwnd, WORD wParam )
485 WND *wndPtr = WIN_FindWndPtr( hwnd );
486 WORD msg;
488 switch(wParam)
490 case VK_PRIOR: msg = SB_PAGEUP; break;
491 case VK_NEXT: msg = SB_PAGEDOWN; break;
492 case VK_HOME: msg = SB_TOP; break;
493 case VK_END: msg = SB_BOTTOM; break;
494 case VK_UP: msg = SB_LINEUP; break;
495 case VK_DOWN: msg = SB_LINEDOWN; break;
496 default:
497 return;
499 SendMessage( GetParent(hwnd),
500 (wndPtr->dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL,
501 msg, MAKELONG( 0, hwnd ));
505 /***********************************************************************
506 * SCROLL_HandleScrollEvent
508 * Handle a mouse or timer event for the scrollbar.
509 * 'pt' is the location of the mouse event in client (for SB_CTL) or
510 * windows coordinates.
512 void SCROLL_HandleScrollEvent( HWND hwnd, int nBar, WORD msg, POINT pt )
514 /* Previous mouse position for timer events */
515 static POINT prevPt;
516 /* Hit test code of the last button-down event */
517 static enum SCROLL_HITTEST trackHitTest;
518 /* Thumb position when tracking started. */
519 static UINT trackThumbPos;
520 /* Position in the scroll-bar of the last button-down event. */
521 static int lastClickPos;
522 /* Position in the scroll-bar of the last mouse event. */
523 static int lastMousePos;
525 enum SCROLL_HITTEST hittest;
526 HWND hwndOwner, hwndCtl;
527 BOOL vertical;
528 WORD arrowSize, thumbPos;
529 RECT rect;
530 HDC hdc;
532 SCROLLINFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
533 if (!infoPtr) return;
534 if ((trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) return;
536 hdc = (nBar == SB_CTL) ? GetDC(hwnd) : GetWindowDC(hwnd);
537 vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
538 &arrowSize, &thumbPos );
539 hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
540 hwndCtl = (nBar == SB_CTL) ? hwnd : 0;
542 switch(msg)
544 case WM_LBUTTONDOWN: /* Initialise mouse tracking */
545 trackHitTest = hittest = SCROLL_HitTest( hwnd, nBar, pt );
546 lastClickPos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
547 lastMousePos = lastClickPos;
548 trackThumbPos = thumbPos;
549 prevPt = pt;
550 SetCapture( hwnd );
551 if (nBar == SB_CTL) SetFocus( hwnd );
552 break;
554 case WM_MOUSEMOVE:
555 hittest = SCROLL_HitTest( hwnd, nBar, pt );
556 prevPt = pt;
557 break;
559 case WM_LBUTTONUP:
560 hittest = SCROLL_NOWHERE;
561 ReleaseCapture();
562 break;
564 case WM_SYSTIMER:
565 pt = prevPt;
566 hittest = SCROLL_HitTest( hwnd, nBar, pt );
567 break;
569 default:
570 return; /* Should never happen */
573 dprintf_scroll( stddeb, "ScrollBar Event: hwnd=%x bar=%d msg=%x pt=%d,%d hit=%d\n",
574 hwnd, nBar, msg, pt.x, pt.y, hittest );
576 switch(trackHitTest)
578 case SCROLL_NOWHERE: /* No tracking in progress */
579 break;
581 case SCROLL_TOP_ARROW:
582 SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
583 (hittest == trackHitTest), FALSE );
584 if (hittest == trackHitTest)
586 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
587 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
588 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
589 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
590 SB_LINEUP, MAKELONG( 0, hwndCtl ));
592 else KillSystemTimer( hwnd, SCROLL_TIMER );
593 break;
595 case SCROLL_TOP_RECT:
596 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
597 infoPtr->flags, vertical,
598 (hittest == trackHitTest), FALSE );
599 if (hittest == trackHitTest)
601 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
602 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
603 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
604 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
605 SB_PAGEUP, MAKELONG( 0, hwndCtl ));
607 else KillSystemTimer( hwnd, SCROLL_TIMER );
608 break;
610 case SCROLL_THUMB:
611 if (msg == WM_LBUTTONDOWN)
612 SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
613 trackThumbPos + lastMousePos - lastClickPos );
614 else if (msg == WM_LBUTTONUP)
615 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
616 infoPtr->flags, vertical, FALSE, FALSE );
617 else /* WM_MOUSEMOVE */
619 UINT pos, val;
621 if (!PtInRect( &rect, pt )) pos = lastClickPos;
622 else pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
623 if (pos != lastMousePos)
625 SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
626 trackThumbPos + lastMousePos - lastClickPos );
627 SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
628 trackThumbPos + pos - lastClickPos );
629 lastMousePos = pos;
630 val = SCROLL_GetThumbVal( infoPtr, &rect, vertical, arrowSize,
631 trackThumbPos + lastMousePos - lastClickPos );
632 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
633 SB_THUMBTRACK, MAKELONG( val, hwndCtl ));
636 break;
638 case SCROLL_BOTTOM_RECT:
639 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
640 infoPtr->flags, vertical,
641 FALSE, (hittest == trackHitTest) );
642 if (hittest == trackHitTest)
644 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
645 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
646 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
647 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
648 SB_PAGEDOWN, MAKELONG( 0, hwndCtl ));
650 else KillSystemTimer( hwnd, SCROLL_TIMER );
651 break;
653 case SCROLL_BOTTOM_ARROW:
654 SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
655 FALSE, (hittest == trackHitTest) );
656 if (hittest == trackHitTest)
658 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
659 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
660 if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
661 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
662 SB_LINEDOWN, MAKELONG( 0, hwndCtl ));
664 else KillSystemTimer( hwnd, SCROLL_TIMER );
665 break;
668 if (msg == WM_LBUTTONUP)
670 if (trackHitTest == SCROLL_THUMB)
672 UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical, arrowSize,
673 trackThumbPos + lastMousePos - lastClickPos );
674 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
675 SB_THUMBPOSITION, MAKELONG( val, hwndCtl ) );
677 else
678 SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
679 SB_ENDSCROLL, MAKELONG( 0, hwndCtl ) );
680 trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
683 ReleaseDC( hwnd, hdc );
687 /***********************************************************************
688 * ScrollBarWndProc
690 LONG ScrollBarWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam )
692 switch(message)
694 case WM_CREATE:
696 CREATESTRUCT *lpCreat = (CREATESTRUCT *)lParam;
697 if (lpCreat->style & SBS_SIZEBOX)
699 fprintf( stdnimp, "Unimplemented style SBS_SIZEBOX.\n" );
700 return -1;
703 if (lpCreat->style & SBS_VERT)
705 if (lpCreat->style & SBS_LEFTALIGN)
706 MoveWindow( hwnd, lpCreat->x, lpCreat->y,
707 SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE );
708 else if (lpCreat->style & SBS_RIGHTALIGN)
709 MoveWindow( hwnd,
710 lpCreat->x+lpCreat->cx-SYSMETRICS_CXVSCROLL-1,
711 lpCreat->y,
712 SYSMETRICS_CXVSCROLL + 1, lpCreat->cy, FALSE );
714 else /* SBS_HORZ */
716 if (lpCreat->style & SBS_TOPALIGN)
717 MoveWindow( hwnd, lpCreat->x, lpCreat->y,
718 lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
719 else if (lpCreat->style & SBS_BOTTOMALIGN)
720 MoveWindow( hwnd,
721 lpCreat->x,
722 lpCreat->y+lpCreat->cy-SYSMETRICS_CYHSCROLL-1,
723 lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
726 if (!hUpArrow) SCROLL_LoadBitmaps();
727 dprintf_scroll( stddeb, "ScrollBar creation, hwnd=%d\n", hwnd );
728 return 0;
730 case WM_LBUTTONDOWN:
731 case WM_LBUTTONUP:
732 case WM_MOUSEMOVE:
733 case WM_SYSTIMER:
734 SCROLL_HandleScrollEvent( hwnd, SB_CTL, message, MAKEPOINT(lParam) );
735 break;
737 case WM_KEYDOWN:
738 SCROLL_HandleKbdEvent( hwnd, wParam );
739 break;
741 case WM_ERASEBKGND:
742 break;
744 case WM_PAINT:
746 PAINTSTRUCT ps;
747 HDC hdc = BeginPaint( hwnd, &ps );
748 SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL );
749 EndPaint( hwnd, &ps );
751 break;
753 default:
754 return DefWindowProc( hwnd, message, wParam, lParam );
756 return 0;
760 /*************************************************************************
761 * SetScrollPos (USER.62)
763 int SetScrollPos( HWND hwnd, int nBar, int nPos, BOOL bRedraw )
765 SCROLLINFO *infoPtr;
766 INT oldPos;
768 if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
770 dprintf_scroll( stddeb,"SetScrollPos min=%d max=%d pos=%d\n",
771 infoPtr->MinVal, infoPtr->MaxVal, nPos );
773 if (nPos < infoPtr->MinVal) nPos = infoPtr->MinVal;
774 else if (nPos > infoPtr->MaxVal) nPos = infoPtr->MaxVal;
775 oldPos = infoPtr->CurVal;
776 infoPtr->CurVal = nPos;
777 if (bRedraw) SCROLL_RefreshScrollBar( hwnd, nBar );
778 return oldPos;
782 /*************************************************************************
783 * GetScrollPos (USER.63)
785 int GetScrollPos( HWND hwnd, int nBar )
787 SCROLLINFO *infoPtr;
789 if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
790 return infoPtr->CurVal;
794 /*************************************************************************
795 * SetScrollRange (USER.64)
797 void SetScrollRange(HWND hwnd, int nBar, int MinVal, int MaxVal, BOOL bRedraw)
799 SCROLLINFO *infoPtr;
801 if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return;
803 dprintf_scroll( stddeb,"SetScrollRange hwnd=%x bar=%d min=%d max=%d\n",
804 hwnd, nBar, MinVal, MaxVal );
806 /* Invalid range -> range is set to (0,0) */
807 if ((MinVal > MaxVal) || ((long)MaxVal - MinVal > 32767L))
808 MinVal = MaxVal = 0;
809 if (infoPtr->CurVal < MinVal) infoPtr->CurVal = MinVal;
810 else if (infoPtr->CurVal > MaxVal) infoPtr->CurVal = MaxVal;
811 infoPtr->MinVal = MinVal;
812 infoPtr->MaxVal = MaxVal;
814 /* Non-client scroll-bar is hidden if min==max */
815 if (nBar != SB_CTL) ShowScrollBar( hwnd, nBar, (MinVal != MaxVal) );
816 if (bRedraw) SCROLL_RefreshScrollBar( hwnd, nBar );
820 /*************************************************************************
821 * GetScrollRange (USER.65)
823 void GetScrollRange(HWND hwnd, int nBar, LPINT lpMin, LPINT lpMax)
825 SCROLLINFO *infoPtr;
827 if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return;
828 if (lpMin) *lpMin = infoPtr->MinVal;
829 if (lpMax) *lpMax = infoPtr->MaxVal;
833 /*************************************************************************
834 * ShowScrollBar (USER.267)
836 void ShowScrollBar( HWND hwnd, WORD wBar, BOOL fShow )
838 WND *wndPtr = WIN_FindWndPtr( hwnd );
840 if (!wndPtr) return;
841 dprintf_scroll( stddeb, "ShowScrollBar: hwnd=%x bar=%d on=%d\n", hwnd, wBar, fShow );
843 switch(wBar)
845 case SB_CTL:
846 ShowWindow( hwnd, fShow ? SW_SHOW : SW_HIDE );
847 return;
849 case SB_HORZ:
850 if (fShow)
852 if (wndPtr->dwStyle & WS_HSCROLL) return;
853 wndPtr->dwStyle |= WS_HSCROLL;
855 else /* hide it */
857 if (!(wndPtr->dwStyle & WS_HSCROLL)) return;
858 wndPtr->dwStyle &= ~WS_HSCROLL;
860 break;
862 case SB_VERT:
863 if (fShow)
865 if (wndPtr->dwStyle & WS_VSCROLL) return;
866 wndPtr->dwStyle |= WS_VSCROLL;
868 else /* hide it */
870 if (!(wndPtr->dwStyle & WS_VSCROLL)) return;
871 wndPtr->dwStyle &= ~WS_VSCROLL;
873 break;
875 case SB_BOTH:
876 if (fShow)
878 if ((wndPtr->dwStyle & WS_HSCROLL)
879 && (wndPtr->dwStyle & WS_VSCROLL)) return;
880 wndPtr->dwStyle |= WS_HSCROLL | WS_VSCROLL;
882 else /* hide it */
884 if (!(wndPtr->dwStyle & WS_HSCROLL)
885 && !(wndPtr->dwStyle & WS_HSCROLL)) return;
886 wndPtr->dwStyle &= ~(WS_HSCROLL | WS_VSCROLL);
888 break;
890 default:
891 return; /* Nothing to do! */
893 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
894 | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
895 /* FIXME: Hack until SetWindowPos works correctly */
896 InvalidateRect( hwnd, NULL, TRUE );
900 /*************************************************************************
901 * EnableScrollBar (USER.482)
903 BOOL EnableScrollBar( HWND hwnd, INT nBar, UINT flags )
905 SCROLLINFO *infoPtr;
906 HDC hdc;
908 if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE;
909 dprintf_scroll( stddeb, "EnableScrollBar: %x %d %d\n", hwnd, nBar, flags );
910 flags &= ESB_DISABLE_BOTH;
911 if (infoPtr->flags == flags) return FALSE;
912 infoPtr->flags = flags;
914 /* Redraw the whole scroll bar */
915 hdc = (nBar == SB_CTL) ? GetDC(hwnd) : GetWindowDC(hwnd);
916 SCROLL_DrawScrollBar( hwnd, hdc, nBar );
917 ReleaseDC( hwnd, hdc );
918 return TRUE;