Release 980628
[wine] / controls / scroll.c
1 /*              
2  * Scrollbar control
3  *
4  * Copyright 1993 Martin Ayotte
5  * Copyright 1994, 1996 Alexandre Julliard
6  */
7
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include "windows.h"
12 #include "sysmetrics.h"
13 #include "scroll.h"
14 #include "graphics.h"
15 #include "heap.h"
16 #include "win.h"
17 #include "debug.h"
18
19
20 static HBITMAP32 hUpArrow = 0;
21 static HBITMAP32 hDnArrow = 0;
22 static HBITMAP32 hLfArrow = 0;
23 static HBITMAP32 hRgArrow = 0;
24 static HBITMAP32 hUpArrowD = 0;
25 static HBITMAP32 hDnArrowD = 0;
26 static HBITMAP32 hLfArrowD = 0;
27 static HBITMAP32 hRgArrowD = 0;
28 static HBITMAP32 hUpArrowI = 0;
29 static HBITMAP32 hDnArrowI = 0;
30 static HBITMAP32 hLfArrowI = 0;
31 static HBITMAP32 hRgArrowI = 0;
32
33 #define TOP_ARROW(flags,pressed) \
34    (((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow))
35 #define BOTTOM_ARROW(flags,pressed) \
36    (((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow))
37 #define LEFT_ARROW(flags,pressed) \
38    (((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow))
39 #define RIGHT_ARROW(flags,pressed) \
40    (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow))
41
42
43   /* Minimum size of the rectangle between the arrows */
44 #define SCROLL_MIN_RECT  4  
45
46   /* Minimum size of the thumb in pixels */
47 #define SCROLL_MIN_THUMB 6
48
49   /* Overlap between arrows and thumb */
50 #define SCROLL_ARROW_THUMB_OVERLAP 1
51
52   /* Delay (in ms) before first repetition when holding the button down */
53 #define SCROLL_FIRST_DELAY   200
54
55   /* Delay (in ms) between scroll repetitions */
56 #define SCROLL_REPEAT_DELAY  50
57
58   /* Scroll timer id */
59 #define SCROLL_TIMER   0
60
61   /* Scroll-bar hit testing */
62 enum SCROLL_HITTEST
63 {
64     SCROLL_NOWHERE,      /* Outside the scroll bar */
65     SCROLL_TOP_ARROW,    /* Top or left arrow */
66     SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
67     SCROLL_THUMB,        /* Thumb rectangle */
68     SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
69     SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
70 };
71
72  /* Thumb-tracking info */
73 static HWND32 SCROLL_TrackingWin = 0;
74 static INT32  SCROLL_TrackingBar = 0;
75 static INT32  SCROLL_TrackingPos = 0;
76 static INT32  SCROLL_TrackingVal = 0;
77
78 /* Is the moving thumb being displayed? */
79 static BOOL32 SCROLL_MovingThumb = FALSE;
80
81 /***********************************************************************
82  *           SCROLL_LoadBitmaps
83  */
84 static void SCROLL_LoadBitmaps(void)
85 {
86     hUpArrow  = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_UPARROW) );
87     hDnArrow  = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_DNARROW) );
88     hLfArrow  = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_LFARROW) );
89     hRgArrow  = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_RGARROW) );
90     hUpArrowD = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_UPARROWD) );
91     hDnArrowD = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_DNARROWD) );
92     hLfArrowD = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_LFARROWD) );
93     hRgArrowD = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_RGARROWD) );
94     hUpArrowI = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_UPARROWI) );
95     hDnArrowI = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_DNARROWI) );
96     hLfArrowI = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_LFARROWI) );
97     hRgArrowI = LoadBitmap32A( 0, MAKEINTRESOURCE32A(OBM_RGARROWI) );
98 }
99
100
101 /***********************************************************************
102  *           SCROLL_GetPtrScrollInfo
103  */
104 static SCROLLBAR_INFO *SCROLL_GetPtrScrollInfo( WND* wndPtr, INT32 nBar )
105 {
106     SCROLLBAR_INFO *infoPtr;
107
108     if (!wndPtr) return NULL;
109     switch(nBar)
110     {
111         case SB_HORZ: infoPtr = (SCROLLBAR_INFO *)wndPtr->pHScroll; break;
112         case SB_VERT: infoPtr = (SCROLLBAR_INFO *)wndPtr->pVScroll; break;
113         case SB_CTL:  infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; break;
114         default:      return NULL;
115     }
116
117     if (!infoPtr)  /* Create the info structure if needed */
118     {
119         if ((infoPtr = HeapAlloc( SystemHeap, 0, sizeof(SCROLLBAR_INFO) )))
120         {
121             infoPtr->MinVal = infoPtr->CurVal = infoPtr->Page = 0;
122             infoPtr->MaxVal = 100;
123             infoPtr->flags  = ESB_ENABLE_BOTH;
124             if (nBar == SB_HORZ) wndPtr->pHScroll = infoPtr;
125             else wndPtr->pVScroll = infoPtr;
126         }
127         if (!hUpArrow) SCROLL_LoadBitmaps();
128     }
129     return infoPtr;
130 }
131
132
133 /***********************************************************************
134  *           SCROLL_GetScrollInfo
135  */
136 static SCROLLBAR_INFO *SCROLL_GetScrollInfo( HWND32 hwnd, INT32 nBar )
137 {
138    WND *wndPtr = WIN_FindWndPtr( hwnd );
139    return SCROLL_GetPtrScrollInfo( wndPtr, nBar );
140 }
141
142
143 /***********************************************************************
144  *           SCROLL_GetScrollBarRect
145  *
146  * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
147  * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
148  * 'arrowSize' returns the width or height of an arrow (depending on
149  * the orientation of the scrollbar), 'thumbSize' returns the size of
150  * the thumb, and 'thumbPos' returns the position of the thumb
151  * relative to the left or to the top.
152  * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
153  */
154 static BOOL32 SCROLL_GetScrollBarRect( HWND32 hwnd, INT32 nBar, RECT32 *lprect,
155                                        INT32 *arrowSize, INT32 *thumbSize,
156                                        INT32 *thumbPos )
157 {
158     INT32 pixels;
159     BOOL32 vertical;
160     WND *wndPtr = WIN_FindWndPtr( hwnd );
161
162     switch(nBar)
163     {
164       case SB_HORZ:
165         lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left;
166         lprect->top    = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
167         lprect->right  = wndPtr->rectClient.right - wndPtr->rectWindow.left;
168         lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL;
169         if(wndPtr->dwStyle & WS_BORDER) {
170           lprect->left--;
171           lprect->right++;
172         } else if(wndPtr->dwStyle & WS_VSCROLL)
173           lprect->right++;
174         vertical = FALSE;
175         break;
176
177       case SB_VERT:
178         lprect->left   = wndPtr->rectClient.right - wndPtr->rectWindow.left;
179         lprect->top    = wndPtr->rectClient.top - wndPtr->rectWindow.top;
180         lprect->right  = lprect->left + SYSMETRICS_CXVSCROLL;
181         lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
182         if(wndPtr->dwStyle & WS_BORDER) {
183           lprect->top--;
184           lprect->bottom++;
185         } else if(wndPtr->dwStyle & WS_HSCROLL)
186           lprect->bottom++;
187         vertical = TRUE;
188         break;
189
190       case SB_CTL:
191         GetClientRect32( hwnd, lprect );
192         vertical = ((wndPtr->dwStyle & SBS_VERT) != 0);
193         break;
194
195     default:
196         return FALSE;
197     }
198
199     if (vertical) pixels = lprect->bottom - lprect->top;
200     else pixels = lprect->right - lprect->left;
201
202     if (pixels <= 2*SYSMETRICS_CXVSCROLL + SCROLL_MIN_RECT)
203     {
204         if (pixels > SCROLL_MIN_RECT)
205             *arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
206         else
207             *arrowSize = 0;
208         *thumbPos = *thumbSize = 0;
209     }
210     else
211     {
212         SCROLLBAR_INFO *info = SCROLL_GetPtrScrollInfo( wndPtr, nBar );
213
214         *arrowSize = SYSMETRICS_CXVSCROLL;
215         pixels -= (2 * (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP));
216
217         if (info->Page)
218         {
219             *thumbSize = pixels * info->Page / (info->MaxVal-info->MinVal+1);
220             if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB;
221         }
222         else *thumbSize = SYSMETRICS_CXVSCROLL;
223
224         if (((pixels -= *thumbSize ) < 0) ||
225             ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
226         {
227             /* Rectangle too small or scrollbar disabled -> no thumb */
228             *thumbPos = *thumbSize = 0;
229         }
230         else
231         {
232             INT32 max = info->MaxVal - MAX( info->Page-1, 0 );
233             if (info->MinVal >= max)
234                 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
235             else
236                 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP
237                  + pixels * (info->CurVal-info->MinVal) / (max - info->MinVal);
238         }
239     }
240     return vertical;
241 }
242
243
244 /***********************************************************************
245  *           SCROLL_GetThumbVal
246  *
247  * Compute the current scroll position based on the thumb position in pixels
248  * from the top of the scroll-bar.
249  */
250 static UINT32 SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT32 *rect,
251                                   BOOL32 vertical, INT32 pos )
252 {
253     INT32 thumbSize;
254     INT32 pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
255
256     if ((pixels -= 2*(SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
257         return infoPtr->MinVal;
258
259     if (infoPtr->Page)
260     {
261         thumbSize = pixels * infoPtr->Page/(infoPtr->MaxVal-infoPtr->MinVal+1);
262         if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
263     }
264     else thumbSize = SYSMETRICS_CXVSCROLL;
265
266     if ((pixels -= thumbSize) <= 0) return infoPtr->MinVal;
267
268     pos = MAX( 0, pos - (SYSMETRICS_CXVSCROLL - SCROLL_ARROW_THUMB_OVERLAP) );
269     if (pos > pixels) pos = pixels;
270
271     if (!infoPtr->Page) pos *= infoPtr->MaxVal - infoPtr->MinVal;
272     else pos *= infoPtr->MaxVal - infoPtr->MinVal - infoPtr->Page + 1;
273     return infoPtr->MinVal + ((pos + pixels / 2) / pixels);
274 }
275
276
277 /***********************************************************************
278  *           SCROLL_HitTest
279  *
280  * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
281  */
282 static enum SCROLL_HITTEST SCROLL_HitTest( HWND32 hwnd, INT32 nBar,
283                                            POINT32 pt )
284 {
285     INT32 arrowSize, thumbSize, thumbPos;
286     RECT32 rect;
287
288     BOOL32 vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
289                                            &arrowSize, &thumbSize, &thumbPos );
290     if (!PtInRect32( &rect, pt )) return SCROLL_NOWHERE;
291
292     if (vertical)
293     {
294         if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW;
295         if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
296         if (!thumbPos) return SCROLL_TOP_RECT;
297         pt.y -= rect.top;
298         if (pt.y < thumbPos) return SCROLL_TOP_RECT;
299         if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
300         return SCROLL_THUMB;
301     }
302     else  /* horizontal */
303     {
304         if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW;
305         if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
306         if (!thumbPos) return SCROLL_TOP_RECT;
307         pt.x -= rect.left;
308         if (pt.x < thumbPos) return SCROLL_TOP_RECT;
309         if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
310         return SCROLL_THUMB;
311     }
312 }
313
314
315 /***********************************************************************
316  *           SCROLL_DrawArrows
317  *
318  * Draw the scroll bar arrows.
319  */
320 static void SCROLL_DrawArrows( HDC32 hdc, SCROLLBAR_INFO *infoPtr,
321                                RECT32 *rect, INT32 arrowSize, BOOL32 vertical,
322                                BOOL32 top_pressed, BOOL32 bottom_pressed )
323 {
324     HDC32 hdcMem = CreateCompatibleDC32( hdc );
325     HBITMAP32 hbmpPrev = SelectObject32( hdcMem, vertical ?
326                                     TOP_ARROW(infoPtr->flags, top_pressed)
327                                     : LEFT_ARROW(infoPtr->flags, top_pressed));
328     SetStretchBltMode32( hdc, STRETCH_DELETESCANS );
329     StretchBlt32( hdc, rect->left, rect->top,
330                   vertical ? rect->right-rect->left : arrowSize,
331                   vertical ? arrowSize : rect->bottom-rect->top,
332                   hdcMem, 0, 0,
333                   SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
334                   SRCCOPY );
335
336     SelectObject32( hdcMem, vertical ?
337                     BOTTOM_ARROW( infoPtr->flags, bottom_pressed )
338                     : RIGHT_ARROW( infoPtr->flags, bottom_pressed ) );
339     if (vertical)
340         StretchBlt32( hdc, rect->left, rect->bottom - arrowSize,
341                       rect->right - rect->left, arrowSize,
342                       hdcMem, 0, 0,
343                       SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
344                       SRCCOPY );
345     else
346         StretchBlt32( hdc, rect->right - arrowSize, rect->top,
347                       arrowSize, rect->bottom - rect->top,
348                       hdcMem, 0, 0,
349                       SYSMETRICS_CXVSCROLL, SYSMETRICS_CYHSCROLL,
350                       SRCCOPY );
351     SelectObject32( hdcMem, hbmpPrev );
352     DeleteDC32( hdcMem );
353 }
354
355
356 /***********************************************************************
357  *           SCROLL_DrawMovingThumb
358  *
359  * Draw the moving thumb rectangle.
360  */
361 static void SCROLL_DrawMovingThumb( HDC32 hdc, RECT32 *rect, BOOL32 vertical,
362                                     INT32 arrowSize, INT32 thumbSize )
363 {
364     RECT32 r = *rect;
365     if (vertical)
366     {
367         r.top += SCROLL_TrackingPos;
368         if (r.top < rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
369             r.top = rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
370         if (r.top + thumbSize >
371                        rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
372             r.top = rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
373                                                                   - thumbSize;
374         r.bottom = r.top + thumbSize;
375     }
376     else
377     {
378         r.left += SCROLL_TrackingPos;
379         if (r.left < rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
380             r.left = rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
381         if (r.left + thumbSize >
382                        rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
383             r.left = rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) 
384                                                                   - thumbSize;
385         r.right = r.left + thumbSize;
386     }
387     DrawFocusRect32( hdc, &r );
388     SCROLL_MovingThumb = !SCROLL_MovingThumb;
389 }
390
391
392 /***********************************************************************
393  *           SCROLL_DrawInterior
394  *
395  * Draw the scroll bar interior (everything except the arrows).
396  */
397 static void SCROLL_DrawInterior( HWND32 hwnd, HDC32 hdc, INT32 nBar, 
398                                  RECT32 *rect, INT32 arrowSize,
399                                  INT32 thumbSize, INT32 thumbPos,
400                                  UINT32 flags, BOOL32 vertical,
401                                  BOOL32 top_selected, BOOL32 bottom_selected )
402 {
403     RECT32 r;
404
405       /* Select the correct brush and pen */
406
407     SelectObject32( hdc, GetSysColorPen32(COLOR_WINDOWFRAME) );
408     if ((flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
409     {
410           /* This ought to be the color of the parent window */
411         SelectObject32( hdc, GetSysColorBrush32(COLOR_WINDOW) );
412     }
413     else
414     {
415         if (nBar == SB_CTL)  /* Only scrollbar controls send WM_CTLCOLOR */
416         {
417             HBRUSH32 hbrush = SendMessage32A(GetParent32(hwnd),
418                                              WM_CTLCOLORSCROLLBAR, hdc, hwnd );
419             SelectObject32( hdc, hbrush );
420         }
421         else SelectObject32( hdc, GetSysColorBrush32(COLOR_SCROLLBAR) );
422     }
423
424       /* Calculate the scroll rectangle */
425
426     r = *rect;
427     if (vertical)
428     {
429         r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
430         r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
431     }
432     else
433     {
434         r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
435         r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
436     }
437
438       /* Draw the scroll bar frame */
439
440     GRAPH_DrawRectangle( hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, 0);
441
442       /* Draw the scroll rectangles and thumb */
443
444     if (!thumbPos)  /* No thumb to draw */
445     {
446         PatBlt32( hdc, r.left+1, r.top+1, r.right - r.left - 2,
447                   r.bottom - r.top - 2, PATCOPY );
448         return;
449     }
450
451     if (vertical)
452     {
453         PatBlt32( hdc, r.left + 1, r.top + 1,
454                   r.right - r.left - 2,
455                   thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1,
456                   top_selected ? 0x0f0000 : PATCOPY );
457         r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
458         PatBlt32( hdc, r.left + 1, r.top + thumbSize,
459                   r.right - r.left - 2,
460                   r.bottom - r.top - thumbSize - 1,
461                   bottom_selected ? 0x0f0000 : PATCOPY );
462         r.bottom = r.top + thumbSize;
463     }
464     else  /* horizontal */
465     {
466         PatBlt32( hdc, r.left + 1, r.top + 1,
467                   thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - 1,
468                   r.bottom - r.top - 2,
469                   top_selected ? 0x0f0000 : PATCOPY );
470         r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
471         PatBlt32( hdc, r.left + thumbSize, r.top + 1,
472                   r.right - r.left - thumbSize - 1,
473                   r.bottom - r.top - 2,
474                   bottom_selected ? 0x0f0000 : PATCOPY );
475         r.right = r.left + thumbSize;
476     }
477
478       /* Draw the thumb */
479
480     SelectObject32( hdc, GetSysColorBrush32(COLOR_BTNFACE) );
481     Rectangle32( hdc, r.left, r.top, r.right, r.bottom );
482     InflateRect32( &r, -1, -1 );
483     GRAPH_DrawReliefRect( hdc, &r, 1, 2, FALSE );
484     if (SCROLL_MovingThumb &&
485         (SCROLL_TrackingWin == hwnd) &&
486         (SCROLL_TrackingBar == nBar))
487     {
488         SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
489         SCROLL_MovingThumb = TRUE;
490     }
491 }
492
493
494 /***********************************************************************
495  *           SCROLL_DrawScrollBar
496  *
497  * Redraw the whole scrollbar.
498  */
499 void SCROLL_DrawScrollBar( HWND32 hwnd, HDC32 hdc, INT32 nBar, BOOL32 arrows )
500 {
501     INT32 arrowSize, thumbSize, thumbPos;
502     RECT32 rect;
503     BOOL32 vertical;
504     WND *wndPtr = WIN_FindWndPtr( hwnd );
505     SCROLLBAR_INFO *infoPtr = SCROLL_GetPtrScrollInfo( wndPtr, nBar );
506
507     if (!wndPtr || !infoPtr ||
508         ((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) ||
509         ((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) return;
510
511     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
512                                         &arrowSize, &thumbSize, &thumbPos );
513
514       /* Draw the arrows */
515
516     if (arrows && arrowSize) SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize,
517                                                 vertical, FALSE, FALSE );
518     
519     SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
520                          thumbPos, infoPtr->flags, vertical, FALSE, FALSE );
521 }
522
523
524 /***********************************************************************
525  *           SCROLL_RefreshScrollBar
526  *
527  * Repaint the scroll bar interior after a SetScrollRange() or
528  * SetScrollPos() call.
529  */
530 static void SCROLL_RefreshScrollBar( HWND32 hwnd, INT32 nBar, BOOL32 arrows )
531 {
532     HDC32 hdc = GetDCEx32( hwnd, 0,
533                            DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) );
534     if (!hdc) return;
535     SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows );
536     ReleaseDC32( hwnd, hdc );
537 }
538
539
540 /***********************************************************************
541  *           SCROLL_HandleKbdEvent
542  *
543  * Handle a keyboard event (only for SB_CTL scrollbars).
544  */
545 static void SCROLL_HandleKbdEvent( HWND32 hwnd, WPARAM32 wParam )
546 {
547     WND *wndPtr = WIN_FindWndPtr( hwnd );
548     WPARAM32 msg;
549     
550     switch(wParam)
551     {
552     case VK_PRIOR: msg = SB_PAGEUP; break;
553     case VK_NEXT:  msg = SB_PAGEDOWN; break;
554     case VK_HOME:  msg = SB_TOP; break;
555     case VK_END:   msg = SB_BOTTOM; break;
556     case VK_UP:    msg = SB_LINEUP; break;
557     case VK_DOWN:  msg = SB_LINEDOWN; break;
558     default:
559         return;
560     }
561     SendMessage32A( GetParent32(hwnd),
562                     (wndPtr->dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL,
563                     msg, hwnd );
564 }
565
566
567 /***********************************************************************
568  *           SCROLL_HandleScrollEvent
569  *
570  * Handle a mouse or timer event for the scrollbar.
571  * 'pt' is the location of the mouse event in client (for SB_CTL) or
572  * windows coordinates.
573  */
574 void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
575 {
576       /* Previous mouse position for timer events */
577     static POINT32 prevPt;
578       /* Hit test code of the last button-down event */
579     static enum SCROLL_HITTEST trackHitTest;
580       /* Thumb position when tracking started. */
581     static UINT32 trackThumbPos;
582       /* Position in the scroll-bar of the last button-down event. */
583     static INT32 lastClickPos;
584       /* Position in the scroll-bar of the last mouse event. */
585     static INT32 lastMousePos;
586
587     enum SCROLL_HITTEST hittest;
588     HWND32 hwndOwner, hwndCtl;
589     BOOL32 vertical;
590     INT32 arrowSize, thumbSize, thumbPos;
591     RECT32 rect;
592     HDC32 hdc;
593
594     SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
595     if (!infoPtr) return;
596     if ((trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) return;
597
598     hdc = GetDCEx32( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
599     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
600                                         &arrowSize, &thumbSize, &thumbPos );
601     hwndOwner = (nBar == SB_CTL) ? GetParent32(hwnd) : hwnd;
602     hwndCtl   = (nBar == SB_CTL) ? hwnd : 0;
603
604     switch(msg)
605     {
606       case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
607           trackHitTest  = hittest = SCROLL_HitTest( hwnd, nBar, pt );
608           lastClickPos  = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
609           lastMousePos  = lastClickPos;
610           trackThumbPos = thumbPos;
611           prevPt = pt;
612           SetCapture32( hwnd );
613           if (nBar == SB_CTL) SetFocus32( hwnd );
614           break;
615
616       case WM_MOUSEMOVE:
617           hittest = SCROLL_HitTest( hwnd, nBar, pt );
618           prevPt = pt;
619           break;
620
621       case WM_LBUTTONUP:
622           hittest = SCROLL_NOWHERE;
623           ReleaseCapture();
624           break;
625
626       case WM_SYSTIMER:
627           pt = prevPt;
628           hittest = SCROLL_HitTest( hwnd, nBar, pt );
629           break;
630
631       default:
632           return;  /* Should never happen */
633     }
634
635     TRACE(scroll, "Event: hwnd=%04x bar=%d msg=%x pt=%d,%d hit=%d\n",
636                  hwnd, nBar, msg, pt.x, pt.y, hittest );
637
638     switch(trackHitTest)
639     {
640     case SCROLL_NOWHERE:  /* No tracking in progress */
641         break;
642
643     case SCROLL_TOP_ARROW:
644         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
645                            (hittest == trackHitTest), FALSE );
646         if (hittest == trackHitTest)
647         {
648             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
649             {
650                 SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
651                                 SB_LINEUP, hwndCtl );
652                 SetSystemTimer32( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
653                                   SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
654                                   (TIMERPROC32)0 );
655             }
656         }
657         else KillSystemTimer32( hwnd, SCROLL_TIMER );
658         break;
659
660     case SCROLL_TOP_RECT:
661         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
662                              thumbPos, infoPtr->flags, vertical,
663                              (hittest == trackHitTest), FALSE );
664         if (hittest == trackHitTest)
665         {
666             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
667             {
668                 SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
669                                 SB_PAGEUP, hwndCtl );
670                 SetSystemTimer32( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
671                                   SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
672                                   (TIMERPROC32)0 );
673             }
674         }
675         else KillSystemTimer32( hwnd, SCROLL_TIMER );
676         break;
677
678     case SCROLL_THUMB:
679         if (msg == WM_LBUTTONDOWN)
680         {
681             SCROLL_TrackingWin = hwnd;
682             SCROLL_TrackingBar = nBar;
683             SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
684             SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
685         }
686         else if (msg == WM_LBUTTONUP)
687         {
688             SCROLL_TrackingWin = 0;
689             SCROLL_MovingThumb = FALSE;
690             SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
691                                  thumbPos, infoPtr->flags, vertical,
692                                  FALSE, FALSE );
693         }
694         else  /* WM_MOUSEMOVE */
695         {
696             UINT32 pos;
697
698             if (!PtInRect32( &rect, pt )) pos = lastClickPos;
699             else pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
700             if (pos != lastMousePos)
701             {
702                 SCROLL_DrawMovingThumb( hdc, &rect, vertical,
703                                         arrowSize, thumbSize );
704                 lastMousePos = pos;
705                 SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
706                 SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
707                                                          vertical,
708                                                          SCROLL_TrackingPos );
709                 SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
710                                 MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal),
711                                 hwndCtl );
712                 SCROLL_DrawMovingThumb( hdc, &rect, vertical,
713                                         arrowSize, thumbSize );
714             }
715         }
716         break;
717         
718     case SCROLL_BOTTOM_RECT:
719         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
720                              thumbPos, infoPtr->flags, vertical,
721                              FALSE, (hittest == trackHitTest) );
722         if (hittest == trackHitTest)
723         {
724             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
725             {
726                 SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
727                                 SB_PAGEDOWN, hwndCtl );
728                 SetSystemTimer32( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
729                                   SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
730                                   (TIMERPROC32)0 );
731             }
732         }
733         else KillSystemTimer32( hwnd, SCROLL_TIMER );
734         break;
735         
736     case SCROLL_BOTTOM_ARROW:
737         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
738                            FALSE, (hittest == trackHitTest) );
739         if (hittest == trackHitTest)
740         {
741             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
742             {
743                 SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
744                                 SB_LINEDOWN, hwndCtl );
745                 SetSystemTimer32( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
746                                   SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
747                                   (TIMERPROC32)0 );
748             }
749         }
750         else KillSystemTimer32( hwnd, SCROLL_TIMER );
751         break;
752     }
753
754     if (msg == WM_LBUTTONUP)
755     {
756         if (trackHitTest == SCROLL_THUMB)
757         {
758             UINT32 val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
759                                  trackThumbPos + lastMousePos - lastClickPos );
760             SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
761                             MAKEWPARAM( SB_THUMBPOSITION, val ), hwndCtl );
762         }
763         else
764             SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
765                             SB_ENDSCROLL, hwndCtl );
766         trackHitTest = SCROLL_NOWHERE;  /* Terminate tracking */
767     }
768
769     ReleaseDC32( hwnd, hdc );
770 }
771
772
773 /***********************************************************************
774  *           ScrollBarWndProc
775  */
776 LRESULT WINAPI ScrollBarWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
777                                  LPARAM lParam )
778 {
779     switch(message)
780     {
781     case WM_CREATE:
782         {
783             CREATESTRUCT32A *lpCreat = (CREATESTRUCT32A *)lParam;
784             if (lpCreat->style & SBS_SIZEBOX)
785             {
786                 FIXME(scroll, "Unimplemented style SBS_SIZEBOX.\n" );
787                 return 0;
788             }
789             
790             if (lpCreat->style & SBS_VERT)
791             {
792                 if (lpCreat->style & SBS_LEFTALIGN)
793                     MoveWindow32( hwnd, lpCreat->x, lpCreat->y,
794                                   SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE );
795                 else if (lpCreat->style & SBS_RIGHTALIGN)
796                     MoveWindow32( hwnd, 
797                                   lpCreat->x+lpCreat->cx-SYSMETRICS_CXVSCROLL-1,
798                                   lpCreat->y,
799                                   SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE );
800             }
801             else  /* SBS_HORZ */
802             {
803                 if (lpCreat->style & SBS_TOPALIGN)
804                     MoveWindow32( hwnd, lpCreat->x, lpCreat->y,
805                                   lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
806                 else if (lpCreat->style & SBS_BOTTOMALIGN)
807                     MoveWindow32( hwnd, 
808                                   lpCreat->x,
809                                   lpCreat->y+lpCreat->cy-SYSMETRICS_CYHSCROLL-1,
810                                   lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
811             }
812         }
813         if (!hUpArrow) SCROLL_LoadBitmaps();
814         TRACE(scroll, "ScrollBar creation, hwnd=%04x\n", hwnd );
815         return 0;
816         
817     case WM_LBUTTONDOWN:
818     case WM_LBUTTONUP:
819     case WM_MOUSEMOVE:
820     case WM_SYSTIMER:
821         {
822             POINT32 pt;
823             CONV_POINT16TO32( (POINT16 *)&lParam, &pt );
824             SCROLL_HandleScrollEvent( hwnd, SB_CTL, message, pt );
825         }
826         break;
827
828     case WM_KEYDOWN:
829         SCROLL_HandleKbdEvent( hwnd, wParam );
830         break;
831
832     case WM_ERASEBKGND:
833          return 1;
834
835     case WM_GETDLGCODE:
836          return DLGC_WANTARROWS; /* Windows returns this value */
837
838     case WM_PAINT:
839         {
840             PAINTSTRUCT32 ps;
841             HDC32 hdc = BeginPaint32( hwnd, &ps );
842             SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, TRUE );
843             EndPaint32( hwnd, &ps );
844         }
845         break;
846
847     case SBM_SETPOS16:
848     case SBM_SETPOS32:
849         return SetScrollPos32( hwnd, SB_CTL, wParam, (BOOL32)lParam );
850
851     case SBM_GETPOS16:
852     case SBM_GETPOS32:
853         return GetScrollPos32( hwnd, SB_CTL );
854
855     case SBM_SETRANGE16:
856         SetScrollRange32( hwnd, SB_CTL, LOWORD(lParam), HIWORD(lParam),
857                           wParam  /* FIXME: Is this correct? */ );
858         return 0;
859
860     case SBM_SETRANGE32:
861         SetScrollRange32( hwnd, SB_CTL, wParam, lParam, FALSE );
862         return 0;  /* FIXME: return previous position */
863
864     case SBM_GETRANGE16:
865         FIXME(scroll, "don't know how to handle SBM_GETRANGE16 (wp=%04x,lp=%08lx)\n", wParam, lParam );
866         return 0;
867
868     case SBM_GETRANGE32:
869         GetScrollRange32( hwnd, SB_CTL, (LPINT32)wParam, (LPINT32)lParam );
870         return 0;
871
872     case SBM_ENABLE_ARROWS16:
873     case SBM_ENABLE_ARROWS32:
874         return EnableScrollBar32( hwnd, SB_CTL, wParam );
875
876     case SBM_SETRANGEREDRAW32:
877         SetScrollRange32( hwnd, SB_CTL, wParam, lParam, TRUE );
878         return 0;  /* FIXME: return previous position */
879         
880     case SBM_SETSCROLLINFO32:
881         return SetScrollInfo32( hwnd, SB_CTL, (SCROLLINFO *)lParam, wParam );
882
883     case SBM_GETSCROLLINFO32:
884         return GetScrollInfo32( hwnd, SB_CTL, (SCROLLINFO *)lParam );
885
886     case 0x00e5:
887     case 0x00e7:
888     case 0x00e8:
889     case 0x00eb:
890     case 0x00ec:
891     case 0x00ed:
892     case 0x00ee:
893     case 0x00ef:
894         ERR(scroll, "unknown Win32 msg %04x wp=%08x lp=%08lx\n",
895                     message, wParam, lParam );
896         break;
897
898     default:
899         if (message >= WM_USER)
900             WARN(scroll, "unknown msg %04x wp=%04x lp=%08lx\n",
901                          message, wParam, lParam );
902         return DefWindowProc32A( hwnd, message, wParam, lParam );
903     }
904     return 0;
905 }
906
907
908 /*************************************************************************
909  *           SetScrollInfo16   (USER.475)
910  */
911 INT16 WINAPI SetScrollInfo16( HWND16 hwnd, INT16 nBar, const SCROLLINFO *info,
912                               BOOL16 bRedraw )
913 {
914     return (INT16)SetScrollInfo32( hwnd, nBar, info, bRedraw );
915 }
916
917
918 /*************************************************************************
919  *           SetScrollInfo32   (USER32.501)
920  * SetScrollInfo32 can be used to set the position, upper bound, 
921  * lower bound, and page size of a scrollbar control.
922  *
923  * RETURNS
924  *    Scrollbar position
925  *
926  * NOTE
927  *    For 100 lines of text to be displayed in a window of 25 lines,
928  *  one would for instance use info->nMin=0, info->nMax=75
929  *  (corresponding to the 76 different positions of the window on
930  *  the text), and info->nPage=25.
931  */
932 INT32 WINAPI SetScrollInfo32( 
933 HWND32 hwnd /* [I] Handle of window whose scrollbar will be affected */, 
934 INT32 nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */, 
935 const SCROLLINFO *info /* [I] Specifies what to change and new values */,
936 BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
937 {
938     SCROLLBAR_INFO *infoPtr;
939     UINT32 new_flags;
940     BOOL32 repaint_arrows = FALSE;
941     dbg_decl_str(scroll, 256);
942
943     if (!(infoPtr = SCROLL_GetScrollInfo(hwnd, nBar))) return 0;
944     if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0;
945     if ((info->cbSize != sizeof(*info)) &&
946         (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return 0;
947
948     /* Set the page size */
949
950     if (info->fMask & SIF_PAGE)
951     {
952         dsprintf(scroll, " page=%d", info->nPage );
953         infoPtr->Page = info->nPage;
954     }
955
956     /* Set the scroll pos */
957
958     if (info->fMask & SIF_POS)
959     {
960         dsprintf(scroll, " pos=%d", info->nPos );
961         infoPtr->CurVal = info->nPos;
962     }
963
964     /* Set the scroll range */
965
966     if (info->fMask & SIF_RANGE)
967     {
968         dsprintf(scroll, " min=%d max=%d", info->nMin, info->nMax );
969
970         /* Invalid range -> range is set to (0,0) */
971         if ((info->nMin > info->nMax) ||
972             ((UINT32)(info->nMax - info->nMin) >= 0x80000000))
973         {
974             infoPtr->MinVal = 0;
975             infoPtr->MaxVal = 0;
976         }
977         else
978         {
979             infoPtr->MinVal = info->nMin;
980             infoPtr->MaxVal = info->nMax;
981         }
982     }
983
984     TRACE(scroll, "hwnd=%04x bar=%d %s\n", 
985                     hwnd, nBar, dbg_str(scroll));
986
987     /* Make sure the page size is valid */
988
989     if (infoPtr->Page < 0) infoPtr->Page = 0;
990     else if (infoPtr->Page > infoPtr->MaxVal - infoPtr->MinVal + 1 )
991         infoPtr->Page = infoPtr->MaxVal - infoPtr->MinVal + 1;
992
993     /* Make sure the pos is inside the range */
994
995     if (infoPtr->CurVal < infoPtr->MinVal)
996         infoPtr->CurVal = infoPtr->MinVal;
997     else if (infoPtr->CurVal > infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ))
998         infoPtr->CurVal = infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 );
999
1000     TRACE(scroll, "    new values: page=%d pos=%d min=%d max=%d\n",
1001                  infoPtr->Page, infoPtr->CurVal,
1002                  infoPtr->MinVal, infoPtr->MaxVal );
1003
1004     /* Check if the scrollbar should be hidden or disabled */
1005
1006     if (info->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
1007     {
1008         new_flags = infoPtr->flags;
1009         if (infoPtr->MinVal >= infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ))
1010         {
1011             /* Hide or disable scroll-bar */
1012             if (info->fMask & SIF_DISABLENOSCROLL)
1013                 new_flags = ESB_DISABLE_BOTH;
1014             else if (nBar != SB_CTL)
1015             {
1016                 ShowScrollBar32( hwnd, nBar, FALSE );
1017                 bRedraw = FALSE;  /* No need to repaint anything */
1018             }
1019         }
1020         else  /* Show and enable scroll-bar */
1021         {
1022             new_flags = 0;
1023             if (nBar != SB_CTL) ShowScrollBar32( hwnd, nBar, TRUE );
1024         }
1025
1026         if (infoPtr->flags != new_flags)
1027         {
1028             infoPtr->flags = new_flags;
1029             repaint_arrows = TRUE;
1030         }
1031     }
1032
1033     if (bRedraw || repaint_arrows)
1034         SCROLL_RefreshScrollBar( hwnd, nBar, repaint_arrows );
1035
1036     /* Return current position */
1037
1038     return infoPtr->CurVal;
1039 }
1040
1041
1042 /*************************************************************************
1043  *           GetScrollInfo16   (USER.476)
1044  */
1045 BOOL16 WINAPI GetScrollInfo16( HWND16 hwnd, INT16 nBar, LPSCROLLINFO info )
1046 {
1047     return GetScrollInfo32( hwnd, nBar, info );
1048 }
1049
1050
1051 /*************************************************************************
1052  *           GetScrollInfo32   (USER32.284)
1053  * GetScrollInfo32 can be used to retrieve the position, upper bound, 
1054  * lower bound, and page size of a scrollbar control.
1055  *
1056  * RETURNS STD
1057  */
1058 BOOL32 WINAPI GetScrollInfo32( 
1059   HWND32 hwnd /* [I] Handle of window */ , 
1060   INT32 nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */, 
1061   LPSCROLLINFO info /* [IO] (info.fMask [I] specifies which values are to retrieve) */)
1062 {
1063     SCROLLBAR_INFO *infoPtr;
1064
1065     if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE;
1066     if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return FALSE;
1067     if ((info->cbSize != sizeof(*info)) &&
1068         (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return FALSE;
1069
1070     if (info->fMask & SIF_PAGE) info->nPage = infoPtr->Page;
1071     if (info->fMask & SIF_POS) info->nPos = infoPtr->CurVal;
1072     if ((info->fMask & SIF_TRACKPOS) && (info->cbSize == sizeof(*info)))
1073         info->nTrackPos = (SCROLL_TrackingWin==hwnd) ? SCROLL_TrackingVal : 0;
1074     if (info->fMask & SIF_RANGE)
1075     {
1076         info->nMin = infoPtr->MinVal;
1077         info->nMax = infoPtr->MaxVal;
1078     }
1079     return (info->fMask & SIF_ALL) != 0;
1080 }
1081
1082
1083 /*************************************************************************
1084  *           SetScrollPos16   (USER.62)
1085  */
1086 INT16 WINAPI SetScrollPos16( HWND16 hwnd, INT16 nBar, INT16 nPos,
1087                              BOOL16 bRedraw )
1088 {
1089     return (INT16)SetScrollPos32( hwnd, nBar, nPos, bRedraw );
1090 }
1091
1092
1093 /*************************************************************************
1094  *           SetScrollPos32   (USER32.502)
1095  *
1096  * RETURNS
1097  *    Success: Scrollbar position
1098  *    Failure: 0
1099  *
1100  * REMARKS
1101  *    Note the ambiguity when 0 is returned.  Use GetLastError
1102  *    to make sure there was an error (and to know which one).
1103  */
1104 INT32 WINAPI SetScrollPos32( 
1105 HWND32 hwnd /* [I] Handle of window whose scrollbar will be affected */,
1106 INT32 nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */,
1107 INT32 nPos /* [I] New value */,
1108 BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */ )
1109 {
1110     SCROLLINFO info;
1111     SCROLLBAR_INFO *infoPtr;
1112     INT32 oldPos;
1113
1114     if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
1115     oldPos      = infoPtr->CurVal;
1116     info.cbSize = sizeof(info);
1117     info.nPos   = nPos;
1118     info.fMask  = SIF_POS;
1119     SetScrollInfo32( hwnd, nBar, &info, bRedraw );
1120     return oldPos;
1121 }
1122
1123
1124 /*************************************************************************
1125  *           GetScrollPos16   (USER.63)
1126  */
1127 INT16 WINAPI GetScrollPos16( HWND16 hwnd, INT16 nBar )
1128 {
1129     return (INT16)GetScrollPos32( hwnd, nBar );
1130 }
1131
1132
1133 /*************************************************************************
1134  *           GetScrollPos32   (USER32.285)
1135  *
1136  * RETURNS
1137  *    Success: Current position
1138  *    Failure: 0   
1139  *
1140  * REMARKS
1141  *    Note the ambiguity when 0 is returned.  Use GetLastError
1142  *    to make sure there was an error (and to know which one).
1143  */
1144 INT32 WINAPI GetScrollPos32( 
1145 HWND32 hwnd, /* [I] Handle of window */
1146 INT32 nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */)
1147 {
1148     SCROLLBAR_INFO *infoPtr;
1149
1150     if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
1151     return infoPtr->CurVal;
1152 }
1153
1154
1155 /*************************************************************************
1156  *           SetScrollRange16   (USER.64)
1157  */
1158 void WINAPI SetScrollRange16( HWND16 hwnd, INT16 nBar,
1159                               INT16 MinVal, INT16 MaxVal, BOOL16 bRedraw )
1160 {
1161     /* Invalid range -> range is set to (0,0) */
1162     if ((INT32)MaxVal - (INT32)MinVal > 0x7fff) MinVal = MaxVal = 0;
1163     SetScrollRange32( hwnd, nBar, MinVal, MaxVal, bRedraw );
1164 }
1165
1166
1167 /*************************************************************************
1168  *           SetScrollRange32   (USER32.503)
1169  *
1170  * RETURNS STD
1171  */
1172 BOOL32 WINAPI SetScrollRange32( 
1173 HWND32 hwnd, /* [I] Handle of window whose scrollbar will be affected */
1174 INT32 nBar, /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */
1175 INT32 MinVal, /* [I] New minimum value */
1176 INT32 MaxVal, /* [I] New maximum value */
1177 BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
1178 {
1179     SCROLLINFO info;
1180
1181     info.cbSize = sizeof(info);
1182     info.nMin   = MinVal;
1183     info.nMax   = MaxVal;
1184     info.fMask  = SIF_RANGE;
1185     SetScrollInfo32( hwnd, nBar, &info, bRedraw );
1186     return TRUE;
1187 }
1188
1189
1190 /*************************************************************************
1191  *           SCROLL_SetNCSbState
1192  *
1193  * This is for CalcChildScroll in windows/mdi.c
1194  */
1195 DWORD SCROLL_SetNCSbState(WND* wndPtr, int vMin, int vMax, int vPos,
1196                                        int hMin, int hMax, int hPos)
1197 {
1198   SCROLLBAR_INFO  *infoPtr = SCROLL_GetPtrScrollInfo(wndPtr, SB_VERT);
1199  
1200   wndPtr->dwStyle |= (WS_VSCROLL | WS_HSCROLL);
1201
1202   if( vMin >= vMax ) 
1203     { vMin = vMax;
1204       wndPtr->dwStyle &= ~WS_VSCROLL; }
1205   if( vPos > vMax ) vPos = vMax; else if( vPos < vMin ) vPos = vMin;
1206   infoPtr->MinVal = vMin;
1207   infoPtr->MaxVal = vMax;
1208   infoPtr->CurVal = vPos;
1209
1210   infoPtr = SCROLL_GetPtrScrollInfo(wndPtr, SB_HORZ);
1211
1212   if( hMin >= hMax )
1213     { hMin = hMax;
1214       wndPtr->dwStyle &= ~WS_HSCROLL; }
1215   if( hPos > hMax ) hPos = hMax; else if( hPos < hMin ) hPos = hMin;
1216   infoPtr->MinVal = hMin;
1217   infoPtr->MaxVal = hMax;
1218   infoPtr->CurVal = hPos;
1219
1220   return wndPtr->dwStyle & (WS_VSCROLL | WS_HSCROLL);
1221 }
1222
1223
1224 /*************************************************************************
1225  *           GetScrollRange16   (USER.65)
1226  */
1227 BOOL16 WINAPI GetScrollRange16( HWND16 hwnd, INT16 nBar,
1228                                 LPINT16 lpMin, LPINT16 lpMax)
1229 {
1230     INT32 min, max;
1231     BOOL16 ret = GetScrollRange32( hwnd, nBar, &min, &max );
1232     if (lpMin) *lpMin = min;
1233     if (lpMax) *lpMax = max;
1234     return ret;
1235 }
1236
1237
1238 /*************************************************************************
1239  *           GetScrollRange32   (USER32.286)
1240  *
1241  * RETURNS STD
1242  */
1243 BOOL32 WINAPI GetScrollRange32( 
1244 HWND32 hwnd, /* [I] Handle of window */
1245 INT32 nBar, /* [I] One of SB_HORZ, SB_VERT, or SB_CTL  */
1246 LPINT32 lpMin, /* [O] Where to store minimum value */
1247 LPINT32 lpMax /* [O] Where to store maximum value */)
1248 {
1249     SCROLLBAR_INFO *infoPtr;
1250
1251     if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar )))
1252     {
1253         if (lpMin) lpMin = 0;
1254         if (lpMax) lpMax = 0;
1255         return FALSE;
1256     }
1257     if (lpMin) *lpMin = infoPtr->MinVal;
1258     if (lpMax) *lpMax = infoPtr->MaxVal;
1259     return TRUE;
1260 }
1261
1262
1263 /*************************************************************************
1264  *           ShowScrollBar16   (USER.267)
1265  */
1266 void WINAPI ShowScrollBar16( HWND16 hwnd, INT16 nBar, BOOL16 fShow )
1267 {
1268     ShowScrollBar32( hwnd, nBar, fShow );
1269 }
1270
1271
1272 /*************************************************************************
1273  *           ShowScrollBar32   (USER32.532)
1274  *
1275  * RETURNS STD
1276  */
1277 BOOL32 WINAPI ShowScrollBar32( 
1278 HWND32 hwnd, /* [I] Handle of window whose scrollbar(s) will be affected   */
1279 INT32 nBar, /* [I] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */
1280 BOOL32 fShow /* [I] TRUE = show, FALSE = hide  */)
1281 {
1282     WND *wndPtr = WIN_FindWndPtr( hwnd );
1283
1284     if (!wndPtr) return FALSE;
1285     TRACE(scroll, "hwnd=%04x bar=%d on=%d\n",
1286                     hwnd, nBar, fShow );
1287
1288     switch(nBar)
1289     {
1290     case SB_CTL:
1291         ShowWindow32( hwnd, fShow ? SW_SHOW : SW_HIDE );
1292         return TRUE;
1293
1294     case SB_HORZ:
1295         if (fShow)
1296         {
1297             if (wndPtr->dwStyle & WS_HSCROLL) return TRUE;
1298             wndPtr->dwStyle |= WS_HSCROLL;
1299         }
1300         else  /* hide it */
1301         {
1302             if (!(wndPtr->dwStyle & WS_HSCROLL)) return TRUE;
1303             wndPtr->dwStyle &= ~WS_HSCROLL;
1304         }
1305         break;
1306
1307     case SB_VERT:
1308         if (fShow)
1309         {
1310             if (wndPtr->dwStyle & WS_VSCROLL) return TRUE;
1311             wndPtr->dwStyle |= WS_VSCROLL;
1312         }
1313         else  /* hide it */
1314         {
1315             if (!(wndPtr->dwStyle & WS_VSCROLL)) return TRUE;
1316             wndPtr->dwStyle &= ~WS_VSCROLL;
1317         }
1318         break;
1319
1320     case SB_BOTH:
1321         if (fShow)
1322         {
1323             if ((wndPtr->dwStyle & WS_HSCROLL)
1324                 && (wndPtr->dwStyle & WS_VSCROLL)) return TRUE;
1325             wndPtr->dwStyle |= WS_HSCROLL | WS_VSCROLL;
1326         }
1327         else  /* hide it */
1328         {
1329             if (!(wndPtr->dwStyle & WS_HSCROLL)
1330                 && !(wndPtr->dwStyle & WS_VSCROLL)) return TRUE;
1331             wndPtr->dwStyle &= ~(WS_HSCROLL | WS_VSCROLL);
1332         }
1333         break;
1334
1335     default:
1336         return TRUE;  /* Nothing to do! */
1337     }
1338     SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
1339                     | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
1340     return TRUE;
1341 }
1342
1343
1344 /*************************************************************************
1345  *           EnableScrollBar16   (USER.482)
1346  */
1347 BOOL16 WINAPI EnableScrollBar16( HWND16 hwnd, INT16 nBar, UINT16 flags )
1348 {
1349     return EnableScrollBar32( hwnd, nBar, flags );
1350 }
1351
1352
1353 /*************************************************************************
1354  *           EnableScrollBar32   (USER32.171)
1355  */
1356 BOOL32 WINAPI EnableScrollBar32( HWND32 hwnd, INT32 nBar, UINT32 flags )
1357 {
1358     SCROLLBAR_INFO *infoPtr;
1359
1360     if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE;
1361     TRACE(scroll, "%04x %d %d\n",
1362                     hwnd, nBar, flags );
1363     flags &= ESB_DISABLE_BOTH;
1364     if (infoPtr->flags == flags) return FALSE;
1365     infoPtr->flags = flags;
1366
1367     /* Redraw the whole scroll bar */
1368     SCROLL_RefreshScrollBar( hwnd, nBar, TRUE );
1369     return TRUE;
1370 }