Remove bitmaps that were only used for the 3.1 look.
[wine] / controls / scroll.c
1 /*
2  * Scrollbar control
3  *
4  * Copyright 1993 Martin Ayotte
5  * Copyright 1994, 1996 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "wine/winuser16.h"
28 #include "controls.h"
29 #include "win.h"
30 #include "wine/debug.h"
31 #include "user.h"
32 #include "message.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(scroll);
35
36 typedef struct
37 {
38     INT   curVal;   /* Current scroll-bar value */
39     INT   minVal;   /* Minimum scroll-bar value */
40     INT   maxVal;   /* Maximum scroll-bar value */
41     INT   page;     /* Page size of scroll bar (Win32) */
42     UINT  flags;    /* EnableScrollBar flags */
43 } SCROLLBAR_INFO, *LPSCROLLBAR_INFO;
44
45
46   /* Minimum size of the rectangle between the arrows */
47 #define SCROLL_MIN_RECT  4
48
49   /* Minimum size of the thumb in pixels */
50 #define SCROLL_MIN_THUMB 6
51
52   /* Overlap between arrows and thumb */
53 #define SCROLL_ARROW_THUMB_OVERLAP 0
54
55   /* Delay (in ms) before first repetition when holding the button down */
56 #define SCROLL_FIRST_DELAY   200
57
58   /* Delay (in ms) between scroll repetitions */
59 #define SCROLL_REPEAT_DELAY  50
60
61   /* Scroll timer id */
62 #define SCROLL_TIMER   0
63
64   /* Scroll-bar hit testing */
65 enum SCROLL_HITTEST
66 {
67     SCROLL_NOWHERE,      /* Outside the scroll bar */
68     SCROLL_TOP_ARROW,    /* Top or left arrow */
69     SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
70     SCROLL_THUMB,        /* Thumb rectangle */
71     SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
72     SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
73 };
74
75  /* What to do after SCROLL_SetScrollInfo() */
76 #define SA_SSI_HIDE             0x0001
77 #define SA_SSI_SHOW             0x0002
78 #define SA_SSI_REFRESH          0x0004
79 #define SA_SSI_REPAINT_ARROWS   0x0008
80
81  /* Thumb-tracking info */
82 static HWND SCROLL_TrackingWin = 0;
83 static INT  SCROLL_TrackingBar = 0;
84 static INT  SCROLL_TrackingPos = 0;
85 static INT  SCROLL_TrackingVal = 0;
86  /* Hit test code of the last button-down event */
87 static enum SCROLL_HITTEST SCROLL_trackHitTest;
88 static BOOL SCROLL_trackVertical;
89
90  /* Is the moving thumb being displayed? */
91 static BOOL SCROLL_MovingThumb = FALSE;
92
93  /* Local functions */
94 static BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar,
95                                     BOOL fShowH, BOOL fShowV );
96 static INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar,
97                                    const SCROLLINFO *info, INT *action );
98 static void SCROLL_DrawInterior_9x( HWND hwnd, HDC hdc, INT nBar,
99                                     RECT *rect, INT arrowSize,
100                                     INT thumbSize, INT thumbPos,
101                                     UINT flags, BOOL vertical,
102                                     BOOL top_selected, BOOL bottom_selected );
103 static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
104
105
106 /*********************************************************************
107  * scrollbar class descriptor
108  */
109 const struct builtin_class_descr SCROLL_builtin_class =
110 {
111     "ScrollBar",            /* name */
112     CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style  */
113     NULL,                   /* procA (winproc is Unicode only) */
114     ScrollBarWndProc,       /* procW */
115     sizeof(SCROLLBAR_INFO), /* extra */
116     IDC_ARROW,              /* cursor */
117     0                       /* brush */
118 };
119     
120 /***********************************************************************
121  *           SCROLL_ScrollInfoValid
122  *
123  *  Determine if the supplied SCROLLINFO struct is valid.
124  */
125 inline static BOOL SCROLL_ScrollInfoValid(
126 LPSCROLLINFO info /* [in] The SCROLLINFO struct to be tested */)
127 {
128     return !(info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)
129         || (info->cbSize != sizeof(*info)
130             && info->cbSize != sizeof(*info) - sizeof(info->nTrackPos)));
131 }
132
133
134 /***********************************************************************
135  *           SCROLL_GetScrollBarInfo
136  */
137 static SCROLLBAR_INFO *SCROLL_GetScrollBarInfo( HWND hwnd, INT nBar )
138 {
139     SCROLLBAR_INFO *infoPtr;
140     WND *wndPtr = WIN_FindWndPtr( hwnd );
141
142     if (!wndPtr) return NULL;
143     switch(nBar)
144     {
145         case SB_HORZ: infoPtr = (SCROLLBAR_INFO *)wndPtr->pHScroll; break;
146         case SB_VERT: infoPtr = (SCROLLBAR_INFO *)wndPtr->pVScroll; break;
147         case SB_CTL:  infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; break;
148         default:
149             WIN_ReleaseWndPtr( wndPtr );
150             return NULL;
151     }
152
153     if (!infoPtr)  /* Create the info structure if needed */
154     {
155         if ((infoPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(SCROLLBAR_INFO) )))
156         {
157             infoPtr->minVal = infoPtr->curVal = infoPtr->page = 0;
158             infoPtr->maxVal = 100;
159             infoPtr->flags  = ESB_ENABLE_BOTH;
160             if (nBar == SB_HORZ) wndPtr->pHScroll = infoPtr;
161             else wndPtr->pVScroll = infoPtr;
162         }
163     }
164     WIN_ReleaseWndPtr( wndPtr );
165     return infoPtr;
166 }
167
168
169 /***********************************************************************
170  *           SCROLL_GetScrollBarRect
171  *
172  * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
173  * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
174  * 'arrowSize' returns the width or height of an arrow (depending on
175  * the orientation of the scrollbar), 'thumbSize' returns the size of
176  * the thumb, and 'thumbPos' returns the position of the thumb
177  * relative to the left or to the top.
178  * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
179  */
180 static BOOL SCROLL_GetScrollBarRect( HWND hwnd, INT nBar, RECT *lprect,
181                                        INT *arrowSize, INT *thumbSize,
182                                        INT *thumbPos )
183 {
184     INT pixels;
185     BOOL vertical;
186     WND *wndPtr = WIN_FindWndPtr( hwnd );
187
188     switch(nBar)
189     {
190       case SB_HORZ:
191         lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left;
192         lprect->top    = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
193         lprect->right  = wndPtr->rectClient.right - wndPtr->rectWindow.left;
194         lprect->bottom = lprect->top + GetSystemMetrics(SM_CYHSCROLL);
195         if(wndPtr->dwStyle & WS_BORDER) {
196           lprect->left--;
197           lprect->right++;
198         } else if(wndPtr->dwStyle & WS_VSCROLL)
199           lprect->right++;
200         vertical = FALSE;
201         break;
202
203       case SB_VERT:
204         if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
205             lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left - GetSystemMetrics(SM_CXVSCROLL);
206         else
207             lprect->left   = wndPtr->rectClient.right - wndPtr->rectWindow.left;
208         lprect->top    = wndPtr->rectClient.top - wndPtr->rectWindow.top;
209         lprect->right  = lprect->left + GetSystemMetrics(SM_CXVSCROLL);
210         lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
211         if(wndPtr->dwStyle & WS_BORDER) {
212           lprect->top--;
213           lprect->bottom++;
214         } else if(wndPtr->dwStyle & WS_HSCROLL)
215           lprect->bottom++;
216         vertical = TRUE;
217         break;
218
219       case SB_CTL:
220         GetClientRect( hwnd, lprect );
221         vertical = ((wndPtr->dwStyle & SBS_VERT) != 0);
222         break;
223
224     default:
225         WIN_ReleaseWndPtr(wndPtr);
226         return FALSE;
227     }
228
229     if (vertical) pixels = lprect->bottom - lprect->top;
230     else pixels = lprect->right - lprect->left;
231
232     if (pixels <= 2*GetSystemMetrics(SM_CXVSCROLL) + SCROLL_MIN_RECT)
233     {
234         if (pixels > SCROLL_MIN_RECT)
235             *arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
236         else
237             *arrowSize = 0;
238         *thumbPos = *thumbSize = 0;
239     }
240     else
241     {
242         SCROLLBAR_INFO *info = SCROLL_GetScrollBarInfo( hwnd, nBar );
243
244         *arrowSize = GetSystemMetrics(SM_CXVSCROLL);
245         pixels -= (2 * (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP));
246
247         if (info->page)
248         {
249             *thumbSize = MulDiv(pixels,info->page,(info->maxVal-info->minVal+1));
250             if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB;
251         }
252         else *thumbSize = GetSystemMetrics(SM_CXVSCROLL);
253
254         if (((pixels -= *thumbSize ) < 0) ||
255             ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
256         {
257             /* Rectangle too small or scrollbar disabled -> no thumb */
258             *thumbPos = *thumbSize = 0;
259         }
260         else
261         {
262             INT max = info->maxVal - max( info->page-1, 0 );
263             if (info->minVal >= max)
264                 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
265             else
266                 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP
267                   + MulDiv(pixels, (info->curVal-info->minVal),(max - info->minVal));
268         }
269     }
270     WIN_ReleaseWndPtr(wndPtr);
271     return vertical;
272 }
273
274
275 /***********************************************************************
276  *           SCROLL_GetThumbVal
277  *
278  * Compute the current scroll position based on the thumb position in pixels
279  * from the top of the scroll-bar.
280  */
281 static UINT SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT *rect,
282                                   BOOL vertical, INT pos )
283 {
284     INT thumbSize;
285     INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
286
287     if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
288         return infoPtr->minVal;
289
290     if (infoPtr->page)
291     {
292         thumbSize = MulDiv(pixels,infoPtr->page,(infoPtr->maxVal-infoPtr->minVal+1));
293         if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
294     }
295     else thumbSize = GetSystemMetrics(SM_CXVSCROLL);
296
297     if ((pixels -= thumbSize) <= 0) return infoPtr->minVal;
298
299     pos = max( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) );
300     if (pos > pixels) pos = pixels;
301
302     if (!infoPtr->page) pos *= infoPtr->maxVal - infoPtr->minVal;
303     else pos *= infoPtr->maxVal - infoPtr->minVal - infoPtr->page + 1;
304     return infoPtr->minVal + ((pos + pixels / 2) / pixels);
305 }
306
307 /***********************************************************************
308  *           SCROLL_PtInRectEx
309  */
310 static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
311 {
312     RECT rect = *lpRect;
313
314     if (vertical)
315     {
316         rect.left -= lpRect->right - lpRect->left;
317         rect.right += lpRect->right - lpRect->left;
318     }
319     else
320     {
321         rect.top -= lpRect->bottom - lpRect->top;
322         rect.bottom += lpRect->bottom - lpRect->top;
323     }
324     return PtInRect( &rect, pt );
325 }
326
327 /***********************************************************************
328  *           SCROLL_ClipPos
329  */
330 static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt )
331 {
332     if( pt.x < lpRect->left )
333         pt.x = lpRect->left;
334     else
335     if( pt.x > lpRect->right )
336         pt.x = lpRect->right;
337
338     if( pt.y < lpRect->top )
339         pt.y = lpRect->top;
340     else
341     if( pt.y > lpRect->bottom )
342         pt.y = lpRect->bottom;
343
344     return pt;
345 }
346
347
348 /***********************************************************************
349  *           SCROLL_HitTest
350  *
351  * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
352  */
353 static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, INT nBar,
354                                            POINT pt, BOOL bDragging )
355 {
356     INT arrowSize, thumbSize, thumbPos;
357     RECT rect;
358
359     BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
360                                            &arrowSize, &thumbSize, &thumbPos );
361
362     if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) ||
363          (!PtInRect( &rect, pt )) ) return SCROLL_NOWHERE;
364
365     if (vertical)
366     {
367         if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW;
368         if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
369         if (!thumbPos) return SCROLL_TOP_RECT;
370         pt.y -= rect.top;
371         if (pt.y < thumbPos) return SCROLL_TOP_RECT;
372         if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
373     }
374     else  /* horizontal */
375     {
376         if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW;
377         if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
378         if (!thumbPos) return SCROLL_TOP_RECT;
379         pt.x -= rect.left;
380         if (pt.x < thumbPos) return SCROLL_TOP_RECT;
381         if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
382     }
383     return SCROLL_THUMB;
384 }
385
386
387 /***********************************************************************
388  *           SCROLL_DrawArrows
389  *
390  * Draw the scroll bar arrows.
391  */
392 static void SCROLL_DrawArrows( HDC hdc, SCROLLBAR_INFO *infoPtr,
393                                RECT *rect, INT arrowSize, BOOL vertical,
394                                BOOL top_pressed, BOOL bottom_pressed )
395 {
396   RECT r;
397
398   r = *rect;
399   if( vertical )
400     r.bottom = r.top + arrowSize;
401   else
402     r.right = r.left + arrowSize;
403
404   DrawFrameControl( hdc, &r, DFC_SCROLL,
405                     (vertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT)
406                     | (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
407                     | (infoPtr->flags&ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0 ) );
408
409   r = *rect;
410   if( vertical )
411     r.top = r.bottom-arrowSize;
412   else
413     r.left = r.right-arrowSize;
414
415   DrawFrameControl( hdc, &r, DFC_SCROLL,
416                     (vertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT)
417                     | (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
418                     | (infoPtr->flags&ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) );
419 }
420
421 static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical,
422                                     INT arrowSize, INT thumbSize )
423 {
424   INT pos = SCROLL_TrackingPos;
425   INT max_size;
426
427   if( vertical )
428     max_size = rect->bottom - rect->top;
429   else
430     max_size = rect->right - rect->left;
431
432   max_size -= (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) + thumbSize;
433
434   if( pos < (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) )
435     pos = (arrowSize-SCROLL_ARROW_THUMB_OVERLAP);
436   else if( pos > max_size )
437     pos = max_size;
438
439   SCROLL_DrawInterior_9x( SCROLL_TrackingWin, hdc, SCROLL_TrackingBar,
440                           rect, arrowSize, thumbSize, pos,
441                           0, vertical, FALSE, FALSE );
442
443   SCROLL_MovingThumb = !SCROLL_MovingThumb;
444 }
445
446 /***********************************************************************
447  *           SCROLL_DrawInterior
448  *
449  * Draw the scroll bar interior (everything except the arrows).
450  */
451 static void SCROLL_DrawInterior_9x( HWND hwnd, HDC hdc, INT nBar,
452                                     RECT *rect, INT arrowSize,
453                                     INT thumbSize, INT thumbPos,
454                                     UINT flags, BOOL vertical,
455                                     BOOL top_selected, BOOL bottom_selected )
456 {
457     RECT r;
458     HPEN hSavePen;
459     HBRUSH hSaveBrush,hBrush;
460
461     /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
462      * The window-owned scrollbars need to call DEFWND_ControlColor
463      * to correctly setup default scrollbar colors
464      */
465     if (nBar == SB_CTL)
466     {
467       hBrush = (HBRUSH)SendMessageA( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
468                                      (WPARAM)hdc,(LPARAM)hwnd);
469     }
470     else
471     {
472       hBrush = DEFWND_ControlColor( hdc, CTLCOLOR_SCROLLBAR );
473     }
474
475     hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
476     hSaveBrush = SelectObject( hdc, hBrush );
477
478     /* Calculate the scroll rectangle */
479     r = *rect;
480     if (vertical)
481     {
482         r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
483         r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
484     }
485     else
486     {
487         r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
488         r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
489     }
490
491     /* Draw the scroll rectangles and thumb */
492     if (!thumbPos)  /* No thumb to draw */
493     {
494         PatBlt( hdc, r.left, r.top,
495                      r.right - r.left, r.bottom - r.top,
496                      PATCOPY );
497
498         /* cleanup and return */
499         SelectObject( hdc, hSavePen );
500         SelectObject( hdc, hSaveBrush );
501         return;
502     }
503
504     if (vertical)
505     {
506         PatBlt( hdc, r.left, r.top,
507                   r.right - r.left,
508                   thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
509                   top_selected ? 0x0f0000 : PATCOPY );
510         r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
511         PatBlt( hdc, r.left, r.top + thumbSize,
512                   r.right - r.left,
513                   r.bottom - r.top - thumbSize,
514                   bottom_selected ? 0x0f0000 : PATCOPY );
515         r.bottom = r.top + thumbSize;
516     }
517     else  /* horizontal */
518     {
519         PatBlt( hdc, r.left, r.top,
520                   thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
521                   r.bottom - r.top,
522                   top_selected ? 0x0f0000 : PATCOPY );
523         r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
524         PatBlt( hdc, r.left + thumbSize, r.top,
525                   r.right - r.left - thumbSize,
526                   r.bottom - r.top,
527                   bottom_selected ? 0x0f0000 : PATCOPY );
528         r.right = r.left + thumbSize;
529     }
530
531     /* Draw the thumb */
532     DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT | BF_MIDDLE  );
533
534     /* cleanup */
535     SelectObject( hdc, hSavePen );
536     SelectObject( hdc, hSaveBrush );
537 }
538
539
540 static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar,
541                                  RECT *rect, INT arrowSize,
542                                  INT thumbSize, INT thumbPos,
543                                  UINT flags, BOOL vertical,
544                                  BOOL top_selected, BOOL bottom_selected )
545 {
546     RECT r;
547     HPEN hSavePen;
548     HBRUSH hSaveBrush,hBrush;
549     BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
550
551     if (Save_SCROLL_MovingThumb &&
552         (SCROLL_TrackingWin == hwnd) &&
553         (SCROLL_TrackingBar == nBar))
554         SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
555
556       /* Select the correct brush and pen */
557
558     /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
559      * The window-owned scrollbars need to call DEFWND_ControlColor
560      * to correctly setup default scrollbar colors
561      */
562     if (nBar == SB_CTL) {
563         hBrush = (HBRUSH)SendMessageA( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
564                                        (WPARAM)hdc,(LPARAM)hwnd);
565     } else {
566         hBrush = DEFWND_ControlColor( hdc, CTLCOLOR_SCROLLBAR );
567     }
568     hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
569     hSaveBrush = SelectObject( hdc, hBrush );
570
571       /* Calculate the scroll rectangle */
572
573     r = *rect;
574     if (vertical)
575     {
576         r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
577         r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
578     }
579     else
580     {
581         r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
582         r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
583     }
584
585       /* Draw the scroll bar frame */
586
587       /* Draw the scroll rectangles and thumb */
588
589     if (!thumbPos)  /* No thumb to draw */
590     {
591         PatBlt( hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, PATCOPY );
592
593         /* cleanup and return */
594         SelectObject( hdc, hSavePen );
595         SelectObject( hdc, hSaveBrush );
596         return;
597     }
598
599     if (vertical)
600     {
601         PatBlt( hdc, r.left, r.top, r.right - r.left,
602                 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
603                 top_selected ? 0x0f0000 : PATCOPY );
604         r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
605         PatBlt( hdc, r.left, r.top + thumbSize, r.right - r.left,
606                 r.bottom - r.top - thumbSize,
607                 bottom_selected ? 0x0f0000 : PATCOPY );
608         r.bottom = r.top + thumbSize;
609     }
610     else  /* horizontal */
611     {
612         PatBlt( hdc, r.left, r.top,
613                 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
614                 r.bottom - r.top, top_selected ? 0x0f0000 : PATCOPY );
615         r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
616         PatBlt( hdc, r.left + thumbSize, r.top, r.right - r.left - thumbSize,
617                 r.bottom - r.top, bottom_selected ? 0x0f0000 : PATCOPY );
618         r.right = r.left + thumbSize;
619     }
620
621       /* Draw the thumb */
622
623     SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) );
624     Rectangle( hdc, r.left+1, r.top+1, r.right-1, r.bottom-1 );
625     DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
626
627     if (Save_SCROLL_MovingThumb &&
628         (SCROLL_TrackingWin == hwnd) &&
629         (SCROLL_TrackingBar == nBar))
630         SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
631
632     /* cleanup */
633     SelectObject( hdc, hSavePen );
634     SelectObject( hdc, hSaveBrush );
635 }
636
637
638 /***********************************************************************
639  *           SCROLL_DrawScrollBar
640  *
641  * Redraw the whole scrollbar.
642  */
643 void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar,
644                            BOOL arrows, BOOL interior )
645 {
646     INT arrowSize, thumbSize, thumbPos;
647     RECT rect;
648     BOOL vertical;
649     WND *wndPtr = WIN_FindWndPtr( hwnd );
650     SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar );
651     BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
652
653     if (!wndPtr || !infoPtr ||
654         ((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) ||
655         ((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) goto END;
656     if (!WIN_IsWindowDrawable( hwnd, FALSE )) goto END;
657     hwnd = wndPtr->hwndSelf;  /* make it a full handle */
658
659     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
660                                         &arrowSize, &thumbSize, &thumbPos );
661
662     /* do not draw if the scrollbar rectangle is empty */
663     if(IsRectEmpty(&rect))
664       goto END;
665
666     if (Save_SCROLL_MovingThumb &&
667         (SCROLL_TrackingWin == hwnd) &&
668         (SCROLL_TrackingBar == nBar))
669         SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, thumbSize );
670
671       /* Draw the arrows */
672
673     if (arrows && arrowSize)
674     {
675         if( vertical == SCROLL_trackVertical && GetCapture() == hwnd )
676             SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
677                                (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
678                                (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) );
679         else
680             SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
681                                                                FALSE, FALSE );
682     }
683     if( interior )
684         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
685                          thumbPos, infoPtr->flags, vertical, FALSE, FALSE );
686
687     if (Save_SCROLL_MovingThumb &&
688         (SCROLL_TrackingWin == hwnd) &&
689         (SCROLL_TrackingBar == nBar))
690         SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, thumbSize );
691
692     /* if scroll bar has focus, reposition the caret */
693     if(hwnd==GetFocus() && (nBar==SB_CTL))
694     {
695         if (!vertical)
696         {
697             SetCaretPos(thumbPos+1, rect.top+1);
698         }
699         else
700         {
701             SetCaretPos(rect.top+1, thumbPos+1);
702         }
703     }
704
705 END:
706     WIN_ReleaseWndPtr(wndPtr);
707 }
708
709 /***********************************************************************
710  *           SCROLL_DrawSizeGrip
711  *
712  *  Draw the size grip.
713  */
714 static void SCROLL_DrawSizeGrip( HWND hwnd,  HDC hdc)
715 {
716     RECT rc;
717
718     GetClientRect( hwnd, &rc );
719     FillRect( hdc, &rc, GetSysColorBrush(COLOR_SCROLLBAR) );
720     rc.left = max( rc.left, rc.right - GetSystemMetrics(SM_CXVSCROLL) - 1 );
721     rc.top  = max( rc.top, rc.bottom - GetSystemMetrics(SM_CYHSCROLL) - 1 );
722     DrawFrameControl( hdc, &rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP );
723 }
724
725
726 /***********************************************************************
727  *           SCROLL_RefreshScrollBar
728  *
729  * Repaint the scroll bar interior after a SetScrollRange() or
730  * SetScrollPos() call.
731  */
732 static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar,
733                                      BOOL arrows, BOOL interior )
734 {
735     HDC hdc = GetDCEx( hwnd, 0,
736                            DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) );
737     if (!hdc) return;
738
739     SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior );
740     ReleaseDC( hwnd, hdc );
741 }
742
743
744 /***********************************************************************
745  *           SCROLL_HandleKbdEvent
746  *
747  * Handle a keyboard event (only for SB_CTL scrollbars with focus).
748  */
749 static void SCROLL_HandleKbdEvent(
750 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
751 WPARAM wParam /* [in] Variable input including enable state */,
752 LPARAM lParam /* [in] Variable input including input point */)
753 {
754     TRACE("hwnd=%p wParam=%d lParam=%ld\n", hwnd, wParam, lParam);
755
756     /* hide caret on first KEYDOWN to prevent flicker */
757     if ((lParam & PFD_DOUBLEBUFFER_DONTCARE) == 0)
758         HideCaret(hwnd);
759
760     switch(wParam)
761     {
762     case VK_PRIOR: wParam = SB_PAGEUP; break;
763     case VK_NEXT:  wParam = SB_PAGEDOWN; break;
764     case VK_HOME:  wParam = SB_TOP; break;
765     case VK_END:   wParam = SB_BOTTOM; break;
766     case VK_UP:    wParam = SB_LINEUP; break;
767     case VK_DOWN:  wParam = SB_LINEDOWN; break;
768     default: return;
769     }
770     SendMessageW(GetParent(hwnd),
771         ((GetWindowLongA( hwnd, GWL_STYLE ) & SBS_VERT) ?
772             WM_VSCROLL : WM_HSCROLL), wParam, (LPARAM)hwnd);
773 }
774
775
776 /***********************************************************************
777  *           SCROLL_HandleScrollEvent
778  *
779  * Handle a mouse or timer event for the scrollbar.
780  * 'pt' is the location of the mouse event in client (for SB_CTL) or
781  * windows coordinates.
782  */
783 static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
784 {
785       /* Previous mouse position for timer events */
786     static POINT prevPt;
787       /* Thumb position when tracking started. */
788     static UINT trackThumbPos;
789       /* Position in the scroll-bar of the last button-down event. */
790     static INT lastClickPos;
791       /* Position in the scroll-bar of the last mouse event. */
792     static INT lastMousePos;
793
794     enum SCROLL_HITTEST hittest;
795     HWND hwndOwner, hwndCtl;
796     BOOL vertical;
797     INT arrowSize, thumbSize, thumbPos;
798     RECT rect;
799     HDC hdc;
800
801     SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar );
802     if (!infoPtr) return;
803     if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN))
804                   return;
805
806     if (nBar == SB_CTL && (GetWindowLongW( hwnd, GWL_STYLE ) & (SBS_SIZEGRIP | SBS_SIZEBOX)))
807     {
808         switch(msg)
809         {
810             case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
811                 HideCaret(hwnd);  /* hide caret while holding down LBUTTON */
812                 SetCapture( hwnd );
813                 prevPt = pt;
814                 SCROLL_trackHitTest  = hittest = SCROLL_THUMB;
815                 break;
816             case WM_MOUSEMOVE:
817                 GetClientRect(GetParent(GetParent(hwnd)),&rect);
818                 prevPt = pt;
819                 break;
820             case WM_LBUTTONUP:
821                 ReleaseCapture();
822                 SCROLL_trackHitTest  = hittest = SCROLL_NOWHERE;
823                 if (hwnd==GetFocus()) ShowCaret(hwnd);
824                 break;
825             case WM_SYSTIMER:
826                 pt = prevPt;
827                 break;
828         }
829         return;
830     }
831
832     hdc = GetDCEx( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
833     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
834                                         &arrowSize, &thumbSize, &thumbPos );
835     hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
836     hwndCtl   = (nBar == SB_CTL) ? hwnd : 0;
837
838     switch(msg)
839     {
840       case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
841           HideCaret(hwnd);  /* hide caret while holding down LBUTTON */
842           SCROLL_trackVertical = vertical;
843           SCROLL_trackHitTest  = hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
844           lastClickPos  = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
845           lastMousePos  = lastClickPos;
846           trackThumbPos = thumbPos;
847           prevPt = pt;
848           if (nBar == SB_CTL && (GetWindowLongA(hwnd, GWL_STYLE) & WS_TABSTOP)) SetFocus( hwnd );
849           SetCapture( hwnd );
850           break;
851
852       case WM_MOUSEMOVE:
853           hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE );
854           prevPt = pt;
855           break;
856
857       case WM_LBUTTONUP:
858           hittest = SCROLL_NOWHERE;
859           ReleaseCapture();
860           /* if scrollbar has focus, show back caret */
861           if (hwnd==GetFocus()) ShowCaret(hwnd);
862           break;
863
864       case WM_SYSTIMER:
865           pt = prevPt;
866           hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
867           break;
868
869       default:
870           return;  /* Should never happen */
871     }
872
873     TRACE("Event: hwnd=%p bar=%d msg=%s pt=%ld,%ld hit=%d\n",
874           hwnd, nBar, SPY_GetMsgName(msg,hwnd), pt.x, pt.y, hittest );
875
876     switch(SCROLL_trackHitTest)
877     {
878     case SCROLL_NOWHERE:  /* No tracking in progress */
879         break;
880
881     case SCROLL_TOP_ARROW:
882         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
883                            (hittest == SCROLL_trackHitTest), FALSE );
884         if (hittest == SCROLL_trackHitTest)
885         {
886             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
887             {
888                 SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
889                                 SB_LINEUP, (LPARAM)hwndCtl );
890             }
891
892             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
893                             SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
894                             (TIMERPROC)0 );
895         }
896         else KillSystemTimer( hwnd, SCROLL_TIMER );
897         break;
898
899     case SCROLL_TOP_RECT:
900         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
901                              thumbPos, infoPtr->flags, vertical,
902                              (hittest == SCROLL_trackHitTest), FALSE );
903         if (hittest == SCROLL_trackHitTest)
904         {
905             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
906             {
907                 SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
908                                 SB_PAGEUP, (LPARAM)hwndCtl );
909             }
910             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
911                               SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
912                               (TIMERPROC)0 );
913         }
914         else KillSystemTimer( hwnd, SCROLL_TIMER );
915         break;
916
917     case SCROLL_THUMB:
918         if (msg == WM_LBUTTONDOWN)
919         {
920             SCROLL_TrackingWin = hwnd;
921             SCROLL_TrackingBar = nBar;
922             SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
923             SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
924                                                         vertical,
925                                                         SCROLL_TrackingPos );
926             if (!SCROLL_MovingThumb)
927                 SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
928         }
929         else if (msg == WM_LBUTTONUP)
930         {
931             if (SCROLL_MovingThumb)
932                 SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
933             SCROLL_TrackingWin = 0;
934             SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
935                                  thumbPos, infoPtr->flags, vertical,
936                                  FALSE, FALSE );
937         }
938         else  /* WM_MOUSEMOVE */
939         {
940             UINT pos;
941
942             if (!SCROLL_PtInRectEx( &rect, pt, vertical )) pos = lastClickPos;
943             else
944             {
945                 pt = SCROLL_ClipPos( &rect, pt );
946                 pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
947             }
948             if ( (pos != lastMousePos) || (!SCROLL_MovingThumb) )
949             {
950                 if (SCROLL_MovingThumb)
951                     SCROLL_DrawMovingThumb( hdc, &rect, vertical,
952                                         arrowSize, thumbSize );
953                 lastMousePos = pos;
954                 SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
955                 SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
956                                                          vertical,
957                                                          SCROLL_TrackingPos );
958                 SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
959                                 MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal),
960                                 (LPARAM)hwndCtl );
961                 if (!SCROLL_MovingThumb)
962                     SCROLL_DrawMovingThumb( hdc, &rect, vertical,
963                                         arrowSize, thumbSize );
964             }
965         }
966         break;
967
968     case SCROLL_BOTTOM_RECT:
969         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
970                              thumbPos, infoPtr->flags, vertical,
971                              FALSE, (hittest == SCROLL_trackHitTest) );
972         if (hittest == SCROLL_trackHitTest)
973         {
974             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
975             {
976                 SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
977                                 SB_PAGEDOWN, (LPARAM)hwndCtl );
978             }
979             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
980                               SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
981                               (TIMERPROC)0 );
982         }
983         else KillSystemTimer( hwnd, SCROLL_TIMER );
984         break;
985
986     case SCROLL_BOTTOM_ARROW:
987         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
988                            FALSE, (hittest == SCROLL_trackHitTest) );
989         if (hittest == SCROLL_trackHitTest)
990         {
991             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
992             {
993                 SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
994                                 SB_LINEDOWN, (LPARAM)hwndCtl );
995             }
996
997             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
998                             SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
999                             (TIMERPROC)0 );
1000         }
1001         else KillSystemTimer( hwnd, SCROLL_TIMER );
1002         break;
1003     }
1004
1005     if (msg == WM_LBUTTONDOWN)
1006     {
1007
1008         if (hittest == SCROLL_THUMB)
1009         {
1010             UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
1011                                  trackThumbPos + lastMousePos - lastClickPos );
1012             SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
1013                             MAKEWPARAM( SB_THUMBTRACK, val ), (LPARAM)hwndCtl );
1014         }
1015     }
1016
1017     if (msg == WM_LBUTTONUP)
1018     {
1019         hittest = SCROLL_trackHitTest;
1020         SCROLL_trackHitTest = SCROLL_NOWHERE;  /* Terminate tracking */
1021
1022         if (hittest == SCROLL_THUMB)
1023         {
1024             UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
1025                                  trackThumbPos + lastMousePos - lastClickPos );
1026             SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
1027                             MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl );
1028         }
1029         SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
1030                           SB_ENDSCROLL, (LPARAM)hwndCtl );
1031     }
1032
1033     ReleaseDC( hwnd, hdc );
1034 }
1035
1036
1037 /***********************************************************************
1038  *           SCROLL_TrackScrollBar
1039  *
1040  * Track a mouse button press on a scroll-bar.
1041  * pt is in screen-coordinates for non-client scroll bars.
1042  */
1043 void SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt )
1044 {
1045     MSG msg;
1046     INT xoffset = 0, yoffset = 0;
1047
1048     if (scrollbar != SB_CTL)
1049     {
1050         WND *wndPtr = WIN_GetPtr( hwnd );
1051         if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
1052         xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
1053         yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
1054         WIN_ReleasePtr( wndPtr );
1055         ScreenToClient( hwnd, &pt );
1056         pt.x += xoffset;
1057         pt.y += yoffset;
1058     }
1059
1060     SCROLL_HandleScrollEvent( hwnd, scrollbar, WM_LBUTTONDOWN, pt );
1061
1062     do
1063     {
1064         if (!GetMessageW( &msg, 0, 0, 0 )) break;
1065         if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue;
1066         switch(msg.message)
1067         {
1068         case WM_LBUTTONUP:
1069         case WM_MOUSEMOVE:
1070         case WM_SYSTIMER:
1071             pt.x = (short)LOWORD(msg.lParam) + xoffset;
1072             pt.y = (short)HIWORD(msg.lParam) + yoffset;
1073             SCROLL_HandleScrollEvent( hwnd, scrollbar, msg.message, pt );
1074             break;
1075         default:
1076             TranslateMessage( &msg );
1077             DispatchMessageW( &msg );
1078             break;
1079         }
1080         if (!IsWindow( hwnd ))
1081         {
1082             ReleaseCapture();
1083             break;
1084         }
1085     } while (msg.message != WM_LBUTTONUP);
1086 }
1087
1088
1089 /***********************************************************************
1090  *           SCROLL_CreateScrollBar
1091  *
1092  *  Create a scroll bar
1093  */
1094 static void SCROLL_CreateScrollBar(
1095 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1096 LPCREATESTRUCTW lpCreate /* [in] The style and place of the scroll bar */)
1097 {
1098     LPSCROLLBAR_INFO info = SCROLL_GetScrollBarInfo(hwnd, SB_CTL);
1099     if (!info) return;
1100
1101     TRACE("hwnd=%p lpCreate=%p\n", hwnd, lpCreate);
1102
1103     if (lpCreate->style & WS_DISABLED)
1104     {
1105         info->flags = ESB_DISABLE_BOTH;
1106         TRACE("Created WS_DISABLED scrollbar\n");
1107     }
1108
1109
1110     if (lpCreate->style & (SBS_SIZEGRIP | SBS_SIZEBOX))
1111     {
1112         if (lpCreate->style & SBS_SIZEBOXTOPLEFTALIGN)
1113             MoveWindow( hwnd, lpCreate->x, lpCreate->y, GetSystemMetrics(SM_CXVSCROLL)+1,
1114                         GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1115         else if(lpCreate->style & SBS_SIZEBOXBOTTOMRIGHTALIGN)
1116             MoveWindow( hwnd, lpCreate->x+lpCreate->cx-GetSystemMetrics(SM_CXVSCROLL)-1, 
1117                         lpCreate->y+lpCreate->cy-GetSystemMetrics(SM_CYHSCROLL)-1,
1118                         GetSystemMetrics(SM_CXVSCROLL)+1,
1119                         GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1120     }
1121     else if (lpCreate->style & SBS_VERT)
1122     {
1123         if (lpCreate->style & SBS_LEFTALIGN)
1124             MoveWindow( hwnd, lpCreate->x, lpCreate->y,
1125                         GetSystemMetrics(SM_CXVSCROLL)+1, lpCreate->cy, FALSE );
1126         else if (lpCreate->style & SBS_RIGHTALIGN)
1127             MoveWindow( hwnd,
1128                         lpCreate->x+lpCreate->cx-GetSystemMetrics(SM_CXVSCROLL)-1,
1129                         lpCreate->y,
1130                         GetSystemMetrics(SM_CXVSCROLL)+1, lpCreate->cy, FALSE );
1131     }
1132     else  /* SBS_HORZ */
1133     {
1134         if (lpCreate->style & SBS_TOPALIGN)
1135             MoveWindow( hwnd, lpCreate->x, lpCreate->y,
1136                         lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1137         else if (lpCreate->style & SBS_BOTTOMALIGN)
1138             MoveWindow( hwnd,
1139                         lpCreate->x,
1140                         lpCreate->y+lpCreate->cy-GetSystemMetrics(SM_CYHSCROLL)-1,
1141                         lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1142     }
1143 }
1144
1145
1146 /*************************************************************************
1147  *           SCROLL_GetScrollInfo
1148  *
1149  *  Internal helper for the API function
1150  */
1151 static BOOL SCROLL_GetScrollInfo(
1152 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1153 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1154 LPSCROLLINFO info /* [in/out] (fMask specifies which values to retrieve) */)
1155 {
1156     LPSCROLLBAR_INFO infoPtr;
1157
1158     /* handle invalid data structure */
1159     if (!SCROLL_ScrollInfoValid(info)
1160         || !(infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar)))
1161             return FALSE;
1162
1163     /* fill in the desired scroll info structure */
1164     if (info->fMask & SIF_PAGE) info->nPage = infoPtr->page;
1165     if (info->fMask & SIF_POS) info->nPos = infoPtr->curVal;
1166     if ((info->fMask & SIF_TRACKPOS) && (info->cbSize == sizeof(*info)))
1167         info->nTrackPos = (SCROLL_TrackingWin == WIN_GetFullHandle(hwnd)) ? SCROLL_TrackingVal : infoPtr->curVal;
1168     if (info->fMask & SIF_RANGE)
1169     {
1170         info->nMin = infoPtr->minVal;
1171         info->nMax = infoPtr->maxVal;
1172     }
1173
1174     return (info->fMask & SIF_ALL) != 0;
1175 }
1176
1177
1178 /*************************************************************************
1179  *           SCROLL_GetScrollPos
1180  *
1181  *  Internal helper for the API function
1182  */
1183 static INT SCROLL_GetScrollPos(
1184 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1185 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */)
1186 {
1187     LPSCROLLBAR_INFO infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar);
1188     return infoPtr ? infoPtr->curVal: 0;
1189 }
1190
1191
1192 /*************************************************************************
1193  *           SCROLL_GetScrollRange
1194  *
1195  *  Internal helper for the API function
1196  *
1197  * RETURNS STD
1198  */
1199 static BOOL SCROLL_GetScrollRange(
1200 HWND hwnd, /* [in] Handle of window */
1201 INT nBar, /* [in] One of SB_HORZ, SB_VERT, or SB_CTL  */
1202 LPINT lpMin, /* [out] Where to store minimum value */
1203 LPINT lpMax /* [out] Where to store maximum value */)
1204 {
1205     LPSCROLLBAR_INFO infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar);
1206
1207     if (lpMin) *lpMin = infoPtr ? infoPtr->minVal : 0;
1208     if (lpMax) *lpMax = infoPtr ? infoPtr->maxVal : 0;
1209
1210     return infoPtr ? TRUE : FALSE;
1211 }
1212
1213
1214
1215 /***********************************************************************
1216  *           ScrollBarWndProc
1217  */
1218 static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1219 {
1220     if (!IsWindow( hwnd )) return 0;
1221
1222     switch(message)
1223     {
1224     case WM_CREATE:
1225         SCROLL_CreateScrollBar(hwnd, (LPCREATESTRUCTW)lParam);
1226         break;
1227
1228     case WM_ENABLE:
1229         {
1230             SCROLLBAR_INFO *infoPtr;
1231             if ((infoPtr = SCROLL_GetScrollBarInfo( hwnd, SB_CTL )))
1232             {
1233                 infoPtr->flags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
1234                 SCROLL_RefreshScrollBar(hwnd, SB_CTL, TRUE, TRUE);
1235             }
1236         }
1237         return 0;
1238
1239     case WM_LBUTTONDBLCLK:
1240     case WM_LBUTTONDOWN:
1241         {
1242             POINT pt;
1243             pt.x = (short)LOWORD(lParam);
1244             pt.y = (short)HIWORD(lParam);
1245             SCROLL_TrackScrollBar( hwnd, SB_CTL, pt );
1246         }
1247         break;
1248     case WM_LBUTTONUP:
1249     case WM_MOUSEMOVE:
1250     case WM_SYSTIMER:
1251         {
1252             POINT pt;
1253             pt.x = (short)LOWORD(lParam);
1254             pt.y = (short)HIWORD(lParam);
1255             SCROLL_HandleScrollEvent( hwnd, SB_CTL, message, pt );
1256         }
1257         break;
1258
1259     case WM_KEYDOWN:
1260         SCROLL_HandleKbdEvent(hwnd, wParam, lParam);
1261         break;
1262
1263     case WM_KEYUP:
1264         ShowCaret(hwnd);
1265         break;
1266
1267     case WM_SETFOCUS:
1268         {
1269             /* Create a caret when a ScrollBar get focus */
1270             RECT rect;
1271             int arrowSize, thumbSize, thumbPos, vertical;
1272             vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,
1273                                                 &arrowSize, &thumbSize, &thumbPos );
1274             if (!vertical)
1275             {
1276                 CreateCaret(hwnd, (HBITMAP)1, thumbSize-2, rect.bottom-rect.top-2);
1277                 SetCaretPos(thumbPos+1, rect.top+1);
1278             }
1279             else
1280             {
1281                 CreateCaret(hwnd, (HBITMAP)1, rect.right-rect.left-2,thumbSize-2);
1282                 SetCaretPos(rect.top+1, thumbPos+1);
1283             }
1284             ShowCaret(hwnd);
1285         }
1286         break;
1287
1288     case WM_KILLFOCUS:
1289         {
1290             RECT rect;
1291             int arrowSize, thumbSize, thumbPos, vertical;
1292             vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,&arrowSize, &thumbSize, &thumbPos );
1293             if (!vertical){
1294                 rect.left=thumbPos+1;
1295                 rect.right=rect.left+thumbSize;
1296             }
1297             else
1298             {
1299                 rect.top=thumbPos+1;
1300                 rect.bottom=rect.top+thumbSize;
1301             }
1302             HideCaret(hwnd);
1303             InvalidateRect(hwnd,&rect,0);
1304             DestroyCaret();
1305         }
1306         break;
1307
1308     case WM_ERASEBKGND:
1309          return 1;
1310
1311     case WM_GETDLGCODE:
1312          return DLGC_WANTARROWS; /* Windows returns this value */
1313
1314     case WM_PAINT:
1315         {
1316             PAINTSTRUCT ps;
1317             HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
1318             if (GetWindowLongW( hwnd, GWL_STYLE ) & SBS_SIZEGRIP)
1319             {
1320                 SCROLL_DrawSizeGrip( hwnd, hdc);
1321             }
1322             else if (GetWindowLongW( hwnd, GWL_STYLE ) & SBS_SIZEBOX)
1323             {
1324                 RECT rc;
1325                 GetClientRect( hwnd, &rc );
1326                 FillRect( hdc, &rc, GetSysColorBrush(COLOR_SCROLLBAR) );
1327             }
1328             else
1329                 SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, TRUE, TRUE );
1330             if (!wParam) EndPaint(hwnd, &ps);
1331         }
1332         break;
1333
1334     case SBM_SETPOS16:
1335     case SBM_SETPOS:
1336         return SetScrollPos( hwnd, SB_CTL, wParam, (BOOL)lParam );
1337
1338     case SBM_GETPOS16:
1339     case SBM_GETPOS:
1340        return SCROLL_GetScrollPos(hwnd, SB_CTL);
1341
1342     case SBM_SETRANGE16:
1343         SetScrollRange( hwnd, SB_CTL, LOWORD(lParam), HIWORD(lParam),
1344                           wParam  /* FIXME: Is this correct? */ );
1345         return 0;
1346
1347     case SBM_SETRANGE:
1348         {
1349             INT oldPos = SCROLL_GetScrollPos( hwnd, SB_CTL );
1350             SetScrollRange( hwnd, SB_CTL, wParam, lParam, FALSE );
1351             if (oldPos != SCROLL_GetScrollPos( hwnd, SB_CTL )) return oldPos;
1352         }
1353         return 0;
1354
1355     case SBM_GETRANGE16:
1356         FIXME("don't know how to handle SBM_GETRANGE16 (wp=%04x,lp=%08lx)\n", wParam, lParam );
1357         return 0;
1358
1359     case SBM_GETRANGE:
1360         return SCROLL_GetScrollRange(hwnd, SB_CTL, (LPINT)wParam, (LPINT)lParam);
1361
1362     case SBM_ENABLE_ARROWS16:
1363     case SBM_ENABLE_ARROWS:
1364         return EnableScrollBar( hwnd, SB_CTL, wParam );
1365
1366     case SBM_SETRANGEREDRAW:
1367         {
1368             INT oldPos = SCROLL_GetScrollPos( hwnd, SB_CTL );
1369             SetScrollRange( hwnd, SB_CTL, wParam, lParam, TRUE );
1370             if (oldPos != SCROLL_GetScrollPos( hwnd, SB_CTL )) return oldPos;
1371         }
1372         return 0;
1373
1374     case SBM_SETSCROLLINFO:
1375         return SetScrollInfo( hwnd, SB_CTL, (SCROLLINFO *)lParam, wParam );
1376
1377     case SBM_GETSCROLLINFO:
1378         return SCROLL_GetScrollInfo(hwnd, SB_CTL, (SCROLLINFO *)lParam);
1379
1380     case 0x00e5:
1381     case 0x00e7:
1382     case 0x00e8:
1383     case 0x00eb:
1384     case 0x00ec:
1385     case 0x00ed:
1386     case 0x00ee:
1387     case 0x00ef:
1388         ERR("unknown Win32 msg %04x wp=%08x lp=%08lx\n",
1389                     message, wParam, lParam );
1390         break;
1391
1392     default:
1393         if (message >= WM_USER)
1394             WARN("unknown msg %04x wp=%04x lp=%08lx\n",
1395                          message, wParam, lParam );
1396         return DefWindowProcW( hwnd, message, wParam, lParam );
1397     }
1398     return 0;
1399 }
1400
1401
1402 /*************************************************************************
1403  *           SetScrollInfo   (USER32.@)
1404  * SetScrollInfo can be used to set the position, upper bound,
1405  * lower bound, and page size of a scrollbar control.
1406  *
1407  * RETURNS
1408  *    Scrollbar position
1409  *
1410  * NOTE
1411  *    For 100 lines of text to be displayed in a window of 25 lines,
1412  *  one would for instance use info->nMin=0, info->nMax=75
1413  *  (corresponding to the 76 different positions of the window on
1414  *  the text), and info->nPage=25.
1415  */
1416 INT WINAPI SetScrollInfo(
1417 HWND hwnd /* [in] Handle of window whose scrollbar will be affected */,
1418 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1419 const SCROLLINFO *info /* [in] Specifies what to change and new values */,
1420 BOOL bRedraw /* [in] Should scrollbar be redrawn afterwards ? */)
1421 {
1422     INT action;
1423     INT retVal = SCROLL_SetScrollInfo( hwnd, nBar, info, &action );
1424
1425     if( action & SA_SSI_HIDE )
1426         SCROLL_ShowScrollBar( hwnd, nBar, FALSE, FALSE );
1427     else
1428     {
1429         if( action & SA_SSI_SHOW )
1430             if( SCROLL_ShowScrollBar( hwnd, nBar, TRUE, TRUE ) )
1431                 return retVal; /* SetWindowPos() already did the painting */
1432
1433         if( bRedraw )
1434             SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1435         else if( action & SA_SSI_REPAINT_ARROWS )
1436             SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, FALSE );
1437     }
1438     return retVal;
1439 }
1440
1441 INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar,
1442                             const SCROLLINFO *info, INT *action  )
1443 {
1444     /* Update the scrollbar state and set action flags according to
1445      * what has to be done graphics wise. */
1446
1447     SCROLLBAR_INFO *infoPtr;
1448     UINT new_flags;
1449     BOOL bChangeParams = FALSE; /* don't show/hide scrollbar if params don't change */
1450
1451    *action = 0;
1452
1453     if (!(infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar))) return 0;
1454     if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0;
1455     if ((info->cbSize != sizeof(*info)) &&
1456         (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return 0;
1457
1458     if (TRACE_ON(scroll))
1459     {
1460         TRACE("hwnd=%p bar=%d", hwnd, nBar);
1461         if (info->fMask & SIF_PAGE) TRACE( " page=%d", info->nPage );
1462         if (info->fMask & SIF_POS) TRACE( " pos=%d", info->nPos );
1463         if (info->fMask & SIF_RANGE) TRACE( " min=%d max=%d", info->nMin, info->nMax );
1464         TRACE("\n");
1465     }
1466
1467     /* Set the page size */
1468
1469     if (info->fMask & SIF_PAGE)
1470     {
1471         if( infoPtr->page != info->nPage )
1472         {
1473             infoPtr->page = info->nPage;
1474            *action |= SA_SSI_REFRESH;
1475            bChangeParams = TRUE;
1476         }
1477     }
1478
1479     /* Set the scroll pos */
1480
1481     if (info->fMask & SIF_POS)
1482     {
1483         if( infoPtr->curVal != info->nPos )
1484         {
1485             infoPtr->curVal = info->nPos;
1486            *action |= SA_SSI_REFRESH;
1487         }
1488     }
1489
1490     /* Set the scroll range */
1491
1492     if (info->fMask & SIF_RANGE)
1493     {
1494         /* Invalid range -> range is set to (0,0) */
1495         if ((info->nMin > info->nMax) ||
1496             ((UINT)(info->nMax - info->nMin) >= 0x80000000))
1497         {
1498             infoPtr->minVal = 0;
1499             infoPtr->maxVal = 0;
1500             bChangeParams = TRUE;
1501         }
1502         else
1503         {
1504             if( infoPtr->minVal != info->nMin ||
1505                 infoPtr->maxVal != info->nMax )
1506             {
1507                 *action |= SA_SSI_REFRESH;
1508                 infoPtr->minVal = info->nMin;
1509                 infoPtr->maxVal = info->nMax;
1510                 bChangeParams = TRUE;
1511             }
1512         }
1513     }
1514
1515     /* Make sure the page size is valid */
1516
1517     if (infoPtr->page < 0) infoPtr->page = 0;
1518     else if (infoPtr->page > infoPtr->maxVal - infoPtr->minVal + 1 )
1519         infoPtr->page = infoPtr->maxVal - infoPtr->minVal + 1;
1520
1521     /* Make sure the pos is inside the range */
1522
1523     if (infoPtr->curVal < infoPtr->minVal)
1524         infoPtr->curVal = infoPtr->minVal;
1525     else if (infoPtr->curVal > infoPtr->maxVal - max( infoPtr->page-1, 0 ))
1526         infoPtr->curVal = infoPtr->maxVal - max( infoPtr->page-1, 0 );
1527
1528     TRACE("    new values: page=%d pos=%d min=%d max=%d\n",
1529                  infoPtr->page, infoPtr->curVal,
1530                  infoPtr->minVal, infoPtr->maxVal );
1531
1532     /* don't change the scrollbar state if SetScrollInfo
1533      * is just called with SIF_DISABLENOSCROLL
1534      */
1535     if(!(info->fMask & SIF_ALL)) goto done;
1536
1537     /* Check if the scrollbar should be hidden or disabled */
1538
1539     if (info->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
1540     {
1541         new_flags = infoPtr->flags;
1542         if (infoPtr->minVal >= infoPtr->maxVal - max( infoPtr->page-1, 0 ))
1543         {
1544             /* Hide or disable scroll-bar */
1545             if (info->fMask & SIF_DISABLENOSCROLL)
1546             {
1547                 new_flags = ESB_DISABLE_BOTH;
1548                *action |= SA_SSI_REFRESH;
1549             }
1550             else if ((nBar != SB_CTL) && bChangeParams)
1551             {
1552                 *action = SA_SSI_HIDE;
1553                 goto done;
1554             }
1555         }
1556         else  /* Show and enable scroll-bar */
1557         {
1558             new_flags = 0;
1559             if ((nBar != SB_CTL) && bChangeParams)
1560                 *action |= SA_SSI_SHOW;
1561         }
1562
1563         if (infoPtr->flags != new_flags) /* check arrow flags */
1564         {
1565             infoPtr->flags = new_flags;
1566            *action |= SA_SSI_REPAINT_ARROWS;
1567         }
1568     }
1569
1570 done:
1571     /* Return current position */
1572
1573     return infoPtr->curVal;
1574 }
1575
1576
1577 /*************************************************************************
1578  *           GetScrollInfo   (USER32.@)
1579  *
1580  * GetScrollInfo can be used to retrieve the position, upper bound,
1581  * lower bound, and page size of a scrollbar control.
1582  *
1583  * RETURNS STD
1584  */
1585 BOOL WINAPI GetScrollInfo(
1586 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1587 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1588 LPSCROLLINFO info /* [in/out] (fMask specifies which values to retrieve) */)
1589 {
1590     TRACE("hwnd=%p nBar=%d info=%p\n", hwnd, nBar, info);
1591
1592     /* Refer SB_CTL requests to the window */
1593     if (nBar == SB_CTL)
1594         return SendMessageA(hwnd, SBM_GETSCROLLINFO, (WPARAM)0, (LPARAM)info);
1595     else
1596         return SCROLL_GetScrollInfo(hwnd, nBar, info);
1597 }
1598
1599
1600 /*************************************************************************
1601  *           SetScrollPos   (USER32.@)
1602  *
1603  * RETURNS
1604  *    Success: Scrollbar position
1605  *    Failure: 0
1606  *
1607  * REMARKS
1608  *    Note the ambiguity when 0 is returned.  Use GetLastError
1609  *    to make sure there was an error (and to know which one).
1610  */
1611 INT WINAPI SetScrollPos(
1612 HWND hwnd /* [in] Handle of window whose scrollbar will be affected */,
1613 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1614 INT nPos /* [in] New value */,
1615 BOOL bRedraw /* [in] Should scrollbar be redrawn afterwards ? */ )
1616 {
1617     SCROLLINFO info;
1618     SCROLLBAR_INFO *infoPtr;
1619     INT oldPos;
1620
1621     if (!(infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar ))) return 0;
1622     oldPos      = infoPtr->curVal;
1623     info.cbSize = sizeof(info);
1624     info.nPos   = nPos;
1625     info.fMask  = SIF_POS;
1626     SetScrollInfo( hwnd, nBar, &info, bRedraw );
1627     return oldPos;
1628 }
1629
1630
1631 /*************************************************************************
1632  *           GetScrollPos   (USER32.@)
1633  *
1634  * RETURNS
1635  *    Success: Current position
1636  *    Failure: 0
1637  *
1638  * REMARKS
1639  *    There is ambiguity when 0 is returned.  Use GetLastError
1640  *    to make sure there was an error (and to know which one).
1641  */
1642 INT WINAPI GetScrollPos(
1643 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1644 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */)
1645 {
1646     TRACE("hwnd=%p nBar=%d\n", hwnd, nBar);
1647
1648     /* Refer SB_CTL requests to the window */
1649     if (nBar == SB_CTL)
1650         return SendMessageA(hwnd, SBM_GETPOS, (WPARAM)0, (LPARAM)0);
1651     else
1652         return SCROLL_GetScrollPos(hwnd, nBar);
1653 }
1654
1655
1656 /*************************************************************************
1657  *           SetScrollRange   (USER32.@)
1658  *
1659  * RETURNS STD
1660  */
1661 BOOL WINAPI SetScrollRange(
1662 HWND hwnd, /* [in] Handle of window whose scrollbar will be affected */
1663 INT nBar, /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */
1664 INT minVal, /* [in] New minimum value */
1665 INT maxVal, /* [in] New maximum value */
1666 BOOL bRedraw /* [in] Should scrollbar be redrawn afterwards ? */)
1667 {
1668     SCROLLINFO info;
1669
1670     info.cbSize = sizeof(info);
1671     info.nMin   = minVal;
1672     info.nMax   = maxVal;
1673     info.fMask  = SIF_RANGE;
1674     SetScrollInfo( hwnd, nBar, &info, bRedraw );
1675     return TRUE;
1676 }
1677
1678
1679 /*************************************************************************
1680  *           SCROLL_SetNCSbState
1681  *
1682  * Updates both scrollbars at the same time. Used by MDI CalcChildScroll().
1683  */
1684 INT SCROLL_SetNCSbState(HWND hwnd, int vMin, int vMax, int vPos,
1685                         int hMin, int hMax, int hPos)
1686 {
1687     INT vA, hA;
1688     SCROLLINFO vInfo, hInfo;
1689
1690     vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO);
1691     vInfo.nMin   = vMin;
1692     vInfo.nMax   = vMax;
1693     vInfo.nPos   = vPos;
1694     hInfo.nMin   = hMin;
1695     hInfo.nMax   = hMax;
1696     hInfo.nPos   = hPos;
1697     vInfo.fMask  = hInfo.fMask = SIF_RANGE | SIF_POS;
1698
1699     SCROLL_SetScrollInfo( hwnd, SB_VERT, &vInfo, &vA );
1700     SCROLL_SetScrollInfo( hwnd, SB_HORZ, &hInfo, &hA );
1701
1702     if( !SCROLL_ShowScrollBar( hwnd, SB_BOTH,
1703                               (hA & SA_SSI_SHOW),(vA & SA_SSI_SHOW) ) )
1704     {
1705         /* SetWindowPos() wasn't called, just redraw the scrollbars if needed */
1706         if( vA & SA_SSI_REFRESH )
1707             SCROLL_RefreshScrollBar( hwnd, SB_VERT, FALSE, TRUE );
1708
1709         if( hA & SA_SSI_REFRESH )
1710             SCROLL_RefreshScrollBar( hwnd, SB_HORZ, FALSE, TRUE );
1711     }
1712     return 0;
1713 }
1714
1715
1716 /*************************************************************************
1717  *           GetScrollRange   (USER32.@)
1718  *
1719  * RETURNS STD
1720  */
1721 BOOL WINAPI GetScrollRange(
1722 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1723 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL  */,
1724 LPINT lpMin /* [out] Where to store minimum value */,
1725 LPINT lpMax /* [out] Where to store maximum value */)
1726 {
1727     TRACE("hwnd=%p nBar=%d lpMin=%p lpMax=%p\n", hwnd, nBar, lpMin, lpMax);
1728
1729     /* Refer SB_CTL requests to the window */
1730     if (nBar == SB_CTL)
1731         return SendMessageA(hwnd, SBM_GETRANGE, (WPARAM)lpMin, (LPARAM)lpMax);
1732     else
1733         return SCROLL_GetScrollRange(hwnd, nBar, lpMin, lpMax);
1734 }
1735
1736
1737 /*************************************************************************
1738  *           SCROLL_ShowScrollBar()
1739  *
1740  * Back-end for ShowScrollBar(). Returns FALSE if no action was taken.
1741  */
1742 BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar,
1743                              BOOL fShowH, BOOL fShowV )
1744 {
1745     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1746
1747     TRACE("hwnd=%p bar=%d horz=%d, vert=%d\n", hwnd, nBar, fShowH, fShowV );
1748
1749     switch(nBar)
1750     {
1751     case SB_CTL:
1752         ShowWindow( hwnd, fShowH ? SW_SHOW : SW_HIDE );
1753         return TRUE;
1754
1755     case SB_BOTH:
1756     case SB_HORZ:
1757         if (fShowH)
1758         {
1759             fShowH = !(style & WS_HSCROLL);
1760             style |= WS_HSCROLL;
1761         }
1762         else  /* hide it */
1763         {
1764             fShowH = (style & WS_HSCROLL);
1765             style &= ~WS_HSCROLL;
1766         }
1767         if( nBar == SB_HORZ ) {
1768             fShowV = FALSE;
1769             break;
1770         }
1771         /* fall through */
1772
1773     case SB_VERT:
1774         if (fShowV)
1775         {
1776             fShowV = !(style & WS_VSCROLL);
1777             style |= WS_VSCROLL;
1778         }
1779         else  /* hide it */
1780         {
1781             fShowV = (style & WS_VSCROLL);
1782             style &= ~WS_VSCROLL;
1783         }
1784         if ( nBar == SB_VERT )
1785            fShowH = FALSE;
1786         break;
1787
1788     default:
1789         return FALSE;  /* Nothing to do! */
1790     }
1791
1792     if( fShowH || fShowV ) /* frame has been changed, let the window redraw itself */
1793     {
1794         WIN_SetStyle( hwnd, style );
1795         SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
1796                     | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
1797         return TRUE;
1798     }
1799     return FALSE; /* no frame changes */
1800 }
1801
1802
1803 /*************************************************************************
1804  *           ShowScrollBar   (USER32.@)
1805  *
1806  * RETURNS STD
1807  */
1808 BOOL WINAPI ShowScrollBar(
1809 HWND hwnd, /* [in] Handle of window whose scrollbar(s) will be affected   */
1810 INT nBar, /* [in] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */
1811 BOOL fShow /* [in] TRUE = show, FALSE = hide  */)
1812 {
1813     SCROLL_ShowScrollBar( hwnd, nBar, (nBar == SB_VERT) ? 0 : fShow,
1814                                       (nBar == SB_HORZ) ? 0 : fShow );
1815     return TRUE;
1816 }
1817
1818
1819 /*************************************************************************
1820  *           EnableScrollBar   (USER32.@)
1821  */
1822 BOOL WINAPI EnableScrollBar( HWND hwnd, INT nBar, UINT flags )
1823 {
1824     BOOL bFineWithMe;
1825     SCROLLBAR_INFO *infoPtr;
1826
1827     TRACE("%p %d %d\n", hwnd, nBar, flags );
1828
1829     flags &= ESB_DISABLE_BOTH;
1830
1831     if (nBar == SB_BOTH)
1832     {
1833         if (!(infoPtr = SCROLL_GetScrollBarInfo( hwnd, SB_VERT ))) return FALSE;
1834         if (!(bFineWithMe = (infoPtr->flags == flags)) )
1835         {
1836             infoPtr->flags = flags;
1837             SCROLL_RefreshScrollBar( hwnd, SB_VERT, TRUE, TRUE );
1838         }
1839         nBar = SB_HORZ;
1840     }
1841     else
1842         bFineWithMe = TRUE;
1843
1844     if (!(infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar ))) return FALSE;
1845     if (bFineWithMe && infoPtr->flags == flags) return FALSE;
1846     infoPtr->flags = flags;
1847
1848     SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1849     return TRUE;
1850 }