source: trunk/src/user32/scroll.cpp@ 5120

Last change on this file since 5120 was 4457, checked in by sandervl, 25 years ago

ShowScrollbar fix (SB_BOTH didn't enable the vertical scrollbar)

File size: 50.6 KB
Line 
1/* $Id: scroll.cpp,v 1.37 2000-10-08 18:45:36 sandervl Exp $ */
2/*
3 * Scrollbar control
4 *
5 * Copyright 1999 Christoph Bratschi
6 *
7 * Copyright 1993 Martin Ayotte
8 * Copyright 1994, 1996 Alexandre Julliard
9 *
10 * WINE version: 20000130
11 *
12 * Status: complete
13 * Version: 5.00
14 */
15
16#include <stdlib.h>
17#include <os2win.h>
18#include "controls.h"
19#include "scroll.h"
20#include "win32wbase.h"
21#include "oslibwin.h"
22#include "initterm.h"
23#include "pmframe.h"
24
25#define DBG_LOCALLOG DBG_scroll
26#include "dbglocal.h"
27
28#define SCROLL_MIN_RECT 4 /* Minimum size of the rectangle between the arrows */
29#define SCROLL_MIN_THUMB 6 /* Minimum size of the thumb in pixels */
30
31#define SCROLL_ARROW_THUMB_OVERLAP 0 /* Overlap between arrows and thumb */
32
33#define SCROLL_FIRST_DELAY 200 /* Delay (in ms) before first repetition when holding the button down */
34#define SCROLL_REPEAT_DELAY 50 /* Delay (in ms) between scroll repetitions */
35#define SCROLL_BLINK_DELAY 1000
36
37#define SCROLL_TIMER 0 /* Scroll timer id */
38#define BLINK_TIMER 1
39
40 /* Scroll-bar hit testing */
41enum SCROLL_HITTEST
42{
43 SCROLL_NOWHERE, /* Outside the scroll bar */
44 SCROLL_TOP_ARROW, /* Top or left arrow */
45 SCROLL_TOP_RECT, /* Rectangle between the top arrow and the thumb */
46 SCROLL_THUMB, /* Thumb rectangle */
47 SCROLL_BOTTOM_RECT, /* Rectangle between the thumb and the bottom arrow */
48 SCROLL_BOTTOM_ARROW /* Bottom or right arrow */
49};
50
51 /* What to do in SetScrollInfo() */
52#define SA_SSI_HIDE 0x0001
53#define SA_SSI_SHOW 0x0002
54#define SA_SSI_REPAINT_INTERIOR 0x0004
55#define SA_SSI_REPAINT_ARROWS 0x0008
56#define SA_SSI_MOVE_THUMB 0x0010
57#define SA_SSI_REFRESH 0x0020
58
59 /* Thumb-tracking info */
60static HWND SCROLL_TrackingWin = 0;
61static INT SCROLL_TrackingBar = 0;
62static INT SCROLL_TrackingPos = 0;
63static INT SCROLL_TrackingVal = 0;
64 /* Focus info */
65static HWND SCROLL_FocusWin = 0;
66static BOOL SCROLL_HasFocus = FALSE;
67static BOOL SCROLL_Highlighted = FALSE;
68static BOOL SCROLL_Scrolling = FALSE;
69
70 /* Hit test code of the last button-down event */
71static enum SCROLL_HITTEST SCROLL_trackHitTest;
72static enum SCROLL_HITTEST SCROLL_lastHitTest;
73static BOOL SCROLL_trackVertical;
74
75 /* Is the moving thumb being displayed? */
76static BOOL SCROLL_MovingThumb = FALSE;
77
78static SCROLLBAR_INFO *SCROLL_GetInfoPtr( HWND hwnd, INT nBar )
79{
80 Win32BaseWindow *win32wnd;
81
82 switch(nBar)
83 {
84 case SB_HORZ:
85 case SB_VERT:
86 win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
87 if (!win32wnd) return NULL;
88 return win32wnd->getScrollInfo(nBar);
89
90 case SB_CTL:
91 return (SCROLLBAR_INFO*)GetInfoPtr(hwnd);
92 }
93
94 return NULL;
95}
96
97/* Scrollbar Functions */
98
99/***********************************************************************
100 * SCROLL_GetScrollBarRect
101 *
102 * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
103 * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
104 * 'arrowSize' returns the width or height of an arrow (depending on
105 * the orientation of the scrollbar), 'thumbSize' returns the size of
106 * the thumb, and 'thumbPos' returns the position of the thumb
107 * relative to the left or to the top.
108 * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
109 */
110static BOOL SCROLL_GetScrollBarRect( HWND hwnd, INT nBar, RECT *lprect,
111 INT *arrowSize, INT *thumbSize,
112 INT *thumbPos )
113{
114 INT pixels;
115 BOOL vertical;
116 RECT rectClient;
117
118 switch(nBar)
119 {
120 case SB_HORZ:
121 {
122 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
123 RECT rectClient;
124
125 if (!win32wnd) return FALSE;
126 rectClient = *win32wnd->getClientRectPtr();
127 lprect->left = rectClient.left;
128 lprect->top = rectClient.bottom;
129 lprect->right = rectClient.right;
130 lprect->bottom = lprect->top+GetSystemMetrics(SM_CYHSCROLL);
131 if (win32wnd->getStyle() & WS_BORDER)
132 {
133 lprect->left--;
134 lprect->right++;
135 } else if (win32wnd->getStyle() & WS_VSCROLL)
136 lprect->right++;
137 vertical = FALSE;
138 break;
139 }
140
141 case SB_VERT:
142 {
143 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
144 RECT rectClient;
145
146 if (!win32wnd) return FALSE;
147 rectClient = *win32wnd->getClientRectPtr();
148 lprect->left = rectClient.right;
149 lprect->top = rectClient.top;
150 lprect->right = lprect->left+GetSystemMetrics(SM_CXVSCROLL);
151 lprect->bottom = rectClient.bottom;
152 if(win32wnd->getStyle() & WS_BORDER)
153 {
154 lprect->top--;
155 lprect->bottom++;
156 } else if (win32wnd->getStyle() & WS_HSCROLL)
157 lprect->bottom++;
158 vertical = TRUE;
159 break;
160 }
161
162 case SB_CTL:
163 {
164 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
165
166 GetClientRect( hwnd, lprect );
167 vertical = ((dwStyle & SBS_VERT) != 0);
168 break;
169 }
170
171 default:
172 return FALSE;
173 }
174
175 if (vertical) pixels = lprect->bottom - lprect->top;
176 else pixels = lprect->right - lprect->left;
177
178 if (pixels <= 2*GetSystemMetrics(SM_CXVSCROLL) + SCROLL_MIN_RECT)
179 {
180 if (pixels > SCROLL_MIN_RECT)
181 *arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
182 else
183 *arrowSize = 0;
184 *thumbPos = *thumbSize = 0;
185 }
186 else
187 {
188 SCROLLBAR_INFO *info = SCROLL_GetInfoPtr( hwnd, nBar );
189
190 *arrowSize = GetSystemMetrics(SM_CXVSCROLL);
191 pixels -= (2 * (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP));
192
193 if (info->Page)
194 {
195 *thumbSize = pixels * info->Page / (info->MaxVal-info->MinVal+1);
196 if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB;
197 }
198 else *thumbSize = GetSystemMetrics(SM_CXVSCROLL);
199
200 if (((pixels -= *thumbSize ) < 0) ||
201 ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
202 {
203 /* Rectangle too small or scrollbar disabled -> no thumb */
204 *thumbPos = *thumbSize = 0;
205 }
206 else
207 {
208 INT max = info->MaxVal - MAX( info->Page-1, 0 );
209 if (info->MinVal >= max)
210 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
211 else
212 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP
213 + pixels * (info->CurVal-info->MinVal) / (max - info->MinVal);
214 }
215 }
216 return vertical;
217}
218
219/***********************************************************************
220 * SCROLL_PtInRectEx
221 */
222static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
223{
224 RECT rect = *lpRect;
225
226 if (vertical)
227 {
228 INT w = lpRect->right-lpRect->left;
229
230 rect.left -= w;
231 rect.right += w;
232 rect.top -= w;
233 rect.bottom += w;
234 } else
235 {
236 INT h = lpRect->bottom-lpRect->top;
237
238 rect.top -= h;
239 rect.bottom += h;
240 rect.left -= h;
241 rect.right += h;
242 }
243
244 return PtInRect( &rect, pt );
245}
246
247/***********************************************************************
248 * SCROLL_HitTest
249 *
250 * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
251 */
252static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, INT nBar,
253 POINT pt, BOOL bDragging )
254{
255 INT arrowSize, thumbSize, thumbPos;
256 RECT rect;
257 SCROLLBAR_INFO *infoPtr = SCROLL_GetInfoPtr(hwnd,nBar);
258
259 if (!infoPtr) return SCROLL_NOWHERE;
260
261 BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
262 &arrowSize, &thumbSize, &thumbPos );
263
264 if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) ||
265 (!PtInRect( &rect, pt )) ) return SCROLL_NOWHERE;
266
267 if (vertical)
268 {
269 if (pt.y < rect.top + arrowSize) return (infoPtr->flags & ESB_DISABLE_LTUP) ? SCROLL_NOWHERE:SCROLL_TOP_ARROW;
270 if (pt.y >= rect.bottom - arrowSize) return (infoPtr->flags & ESB_DISABLE_RTDN) ? SCROLL_NOWHERE:SCROLL_BOTTOM_ARROW;
271 if (!thumbPos) return ((infoPtr->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) ? SCROLL_NOWHERE:SCROLL_TOP_RECT;
272 pt.y -= rect.top;
273 if (pt.y < thumbPos) return SCROLL_TOP_RECT;
274 if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
275 }
276 else /* horizontal */
277 {
278 if (pt.x < rect.left + arrowSize) return (infoPtr->flags & ESB_DISABLE_LTUP) ? SCROLL_NOWHERE:SCROLL_TOP_ARROW;
279 if (pt.x >= rect.right - arrowSize) return (infoPtr->flags & ESB_DISABLE_RTDN) ? SCROLL_NOWHERE:SCROLL_BOTTOM_ARROW;
280 if (!thumbPos) return ((infoPtr->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) ? SCROLL_NOWHERE:SCROLL_TOP_RECT;
281 pt.x -= rect.left;
282 if (pt.x < thumbPos) return SCROLL_TOP_RECT;
283 if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
284 }
285 return SCROLL_THUMB;
286}
287
288static void SCROLL_DrawTopArrow(HDC hdc,SCROLLBAR_INFO *infoPtr,RECT *rect,INT arrowSize,BOOL vertical,BOOL top_pressed)
289{
290 RECT r;
291
292 r = *rect;
293 if( vertical )
294 r.bottom = r.top + arrowSize;
295 else
296 r.right = r.left + arrowSize;
297
298 DrawFrameControl( hdc, &r, DFC_SCROLL,
299 (vertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT)
300 | (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
301 | (infoPtr->flags&ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0 ) );
302}
303
304static void SCROLL_DrawBottomArrow(HDC hdc,SCROLLBAR_INFO *infoPtr,RECT *rect,INT arrowSize,BOOL vertical,BOOL bottom_pressed)
305{
306 RECT r;
307
308 r = *rect;
309 if( vertical )
310 r.top = r.bottom-arrowSize;
311 else
312 r.left = r.right-arrowSize;
313
314 DrawFrameControl( hdc, &r, DFC_SCROLL,
315 (vertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT)
316 | (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
317 | (infoPtr->flags&ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) );
318}
319
320/***********************************************************************
321 * SCROLL_DrawArrows
322 *
323 * Draw the scroll bar arrows.
324 */
325static void SCROLL_DrawArrows( HDC hdc, SCROLLBAR_INFO *infoPtr,
326 RECT *rect, INT arrowSize, BOOL vertical,
327 BOOL top_pressed, BOOL bottom_pressed )
328{
329 SCROLL_DrawTopArrow(hdc,infoPtr,rect,arrowSize,vertical,top_pressed);
330 SCROLL_DrawBottomArrow(hdc,infoPtr,rect,arrowSize,vertical,bottom_pressed);
331}
332
333static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar,
334 RECT *rect, INT arrowSize,
335 INT thumbSize, INT thumbPos,
336 UINT flags, BOOL vertical,
337 BOOL top_selected, BOOL bottom_selected )
338{
339 RECT r;
340 HPEN hSavePen;
341 HBRUSH hSaveBrush,hBrush;
342
343 /* Select the correct brush and pen */
344
345 /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
346 * The window-owned scrollbars need to call DEFWND_ControlColor
347 * to correctly setup default scrollbar colors
348 */
349 if (nBar == SB_CTL) {
350 hBrush = (HBRUSH)SendMessageA( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
351 (WPARAM)hdc,(LPARAM)hwnd);
352 } else {
353 hBrush = (HBRUSH)SendMessageA( hwnd, WM_CTLCOLORSCROLLBAR,
354 (WPARAM)hdc,(LPARAM)hwnd);
355
356 }
357
358 hSavePen = SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
359 hSaveBrush = SelectObject( hdc, hBrush );
360
361 /* Calculate the scroll rectangle */
362
363 r = *rect;
364 if (vertical)
365 {
366 r.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
367 r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
368 }
369 else
370 {
371 r.left += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
372 r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
373 }
374
375 /* Draw the scroll rectangles and thumb */
376 if (!thumbPos) /* No thumb to draw */
377 {
378 PatBlt( hdc, r.left, r.top,
379 r.right - r.left, r.bottom - r.top,
380 PATCOPY );
381
382 /* cleanup and return */
383 SelectObject( hdc, hSavePen );
384 SelectObject( hdc, hSaveBrush );
385 return;
386 }
387
388 if (vertical)
389 {
390 PatBlt( hdc, r.left, r.top,
391 r.right - r.left,
392 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
393 top_selected ? 0x0f0000 : PATCOPY );
394 r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
395 PatBlt( hdc, r.left, r.top + thumbSize,
396 r.right - r.left,
397 r.bottom - r.top - thumbSize,
398 bottom_selected ? 0x0f0000 : PATCOPY );
399 r.bottom = r.top + thumbSize;
400 }
401 else /* horizontal */
402 {
403 PatBlt( hdc, r.left, r.top,
404 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
405 r.bottom - r.top,
406 top_selected ? 0x0f0000 : PATCOPY );
407 r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
408 PatBlt( hdc, r.left + thumbSize, r.top,
409 r.right - r.left - thumbSize,
410 r.bottom - r.top,
411 bottom_selected ? 0x0f0000 : PATCOPY );
412 r.right = r.left + thumbSize;
413 }
414
415 /* Draw the thumb */
416
417 DrawEdge(hdc,&r,EDGE_RAISED,BF_RECT | BF_ADJUST);
418 FillRect(hdc,&r,(SCROLL_FocusWin == hwnd && SCROLL_Highlighted && !SCROLL_Scrolling) ? GetSysColorBrush(COLOR_3DSHADOW):GetSysColorBrush(COLOR_BTNFACE));
419
420 /* cleanup */
421 SelectObject( hdc, hSavePen );
422 SelectObject( hdc, hSaveBrush );
423}
424
425/***********************************************************************
426 * SCROLL_DrawMovingThumb
427 *
428 * Draw the moving thumb rectangle.
429 */
430static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical,
431 INT arrowSize, INT thumbSize )
432{
433 INT pos = SCROLL_TrackingPos;
434 INT max_size;
435
436 if( vertical )
437 max_size = rect->bottom - rect->top;
438 else
439 max_size = rect->right - rect->left;
440
441 max_size -= (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) + thumbSize;
442
443 if( pos < (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) )
444 pos = (arrowSize-SCROLL_ARROW_THUMB_OVERLAP);
445 else if( pos > max_size )
446 pos = max_size;
447
448 SCROLL_DrawInterior( SCROLL_TrackingWin, hdc, SCROLL_TrackingBar,
449 rect, arrowSize, thumbSize, pos,
450 0, vertical, FALSE, FALSE );
451}
452
453/***********************************************************************
454 * SCROLL_ClipPos
455 */
456static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt )
457{
458 if( pt.x < lpRect->left )
459 pt.x = lpRect->left;
460 else
461 if( pt.x >= lpRect->right )
462 pt.x = lpRect->right-1;
463
464 if( pt.y < lpRect->top )
465 pt.y = lpRect->top;
466 else
467 if( pt.y >= lpRect->bottom )
468 pt.y = lpRect->bottom-1;
469
470 return pt;
471}
472
473/***********************************************************************
474 * SCROLL_GetThumbVal
475 *
476 * Compute the current scroll position based on the thumb position in pixels
477 * from the top of the scroll-bar.
478 */
479static UINT SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT *rect,
480 BOOL vertical, INT pos )
481{
482 INT thumbSize;
483 INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
484
485 if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
486 return infoPtr->MinVal;
487
488 if (infoPtr->Page)
489 {
490 thumbSize = pixels * infoPtr->Page/(infoPtr->MaxVal-infoPtr->MinVal+1);
491 if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
492 }
493 else thumbSize = GetSystemMetrics(SM_CXVSCROLL);
494
495 if ((pixels -= thumbSize) <= 0) return infoPtr->MinVal;
496
497 pos = MAX( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) );
498 if (pos > pixels) pos = pixels;
499
500 if (!infoPtr->Page) pos *= infoPtr->MaxVal - infoPtr->MinVal;
501 else pos *= infoPtr->MaxVal - infoPtr->MinVal - infoPtr->Page + 1;
502 return infoPtr->MinVal + ((pos + pixels / 2) / pixels);
503}
504
505void SCROLL_GetSizeBox(HWND hwnd,DWORD dwStyle,PRECT rect)
506{
507 RECT clientRect;
508 INT cx = GetSystemMetrics(SM_CXVSCROLL);
509 INT cy = GetSystemMetrics(SM_CYHSCROLL);
510
511 GetClientRect(hwnd,&clientRect);
512
513 if (dwStyle & SBS_SIZEBOXTOPLEFTALIGN)
514 {
515 rect->left = 0;
516 rect->right = cx;
517 rect->bottom = cy;
518 rect->top = 0;
519 } else
520 {
521 rect->left = clientRect.right-cx;
522 rect->right = clientRect.right;
523 rect->bottom = clientRect.bottom;
524 rect->top = clientRect.bottom-cy;
525 }
526}
527
528void SCROLL_DrawSizeBox(HDC hdc,RECT rect)
529{
530 POINT p1,p2;
531 HPEN penDark = GetSysColorPen(COLOR_3DSHADOW);
532 HPEN penWhite = GetSysColorPen(COLOR_3DHILIGHT);
533 HPEN oldPen = SelectObject(hdc,penDark);
534 INT x;
535
536 p1.x = rect.right-1;
537 p1.y = rect.bottom;
538 p2.x = rect.right;
539 p2.y = rect.bottom-1;
540 for (x = 0;x < 3;x++)
541 {
542 SelectObject(hdc,penDark);
543 MoveToEx(hdc,p1.x,p1.y,NULL);
544 LineTo(hdc,p2.x,p2.y);
545 p1.x--;
546 p2.y--;
547 MoveToEx(hdc,p1.x,p1.y,NULL);
548 LineTo(hdc,p2.x,p2.y);
549 SelectObject(hdc,penWhite);
550 p1.x--;
551 p2.y--;
552 MoveToEx(hdc,p1.x,p1.y,NULL);
553 LineTo(hdc,p2.x,p2.y);
554 p1.x -= 2;
555 p2.y -= 2;
556 }
557
558 SelectObject(hdc,oldPen);
559}
560
561/***********************************************************************
562 * SCROLL_DrawScrollBar
563 *
564 * Redraw the whole scrollbar.
565 */
566void SCROLL_DrawScrollBar(HWND hwnd,HDC hdc,INT nBar,BOOL arrows,BOOL interior)
567{
568 INT arrowSize, thumbSize, thumbPos;
569 RECT rect;
570 BOOL vertical;
571 SCROLLBAR_INFO *infoPtr = SCROLL_GetInfoPtr( hwnd, nBar );
572
573 if (!infoPtr) return;
574 if (nBar == SB_CTL)
575 {
576 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
577
578 if (dwStyle & (SBS_SIZEBOX | SBS_SIZEGRIP))
579 {
580 RECT rect;
581 HBRUSH hBrush;
582
583 hdc = GetDCEx(hwnd,0,DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
584 hBrush = GetSysColorBrush(COLOR_3DFACE);
585 GetClientRect(hwnd,&rect);
586 FillRect(hdc,&rect,hBrush);
587
588 if (dwStyle & SBS_SIZEGRIP)
589 {
590 SCROLL_GetSizeBox(hwnd,dwStyle,&rect);
591 SCROLL_DrawSizeBox(hdc,rect);
592 }
593
594 ReleaseDC(hwnd,hdc);
595
596 return;
597 }
598 }
599
600 vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
601 &arrowSize, &thumbSize, &thumbPos );
602
603 /* Draw the arrows */
604
605 if (arrows && arrowSize)
606 {
607 if( vertical == SCROLL_trackVertical && GetCapture() == hwnd )
608 SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
609 (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
610 (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) );
611 else
612 SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
613 FALSE, FALSE );
614 }
615
616 if (SCROLL_MovingThumb &&
617 (SCROLL_TrackingWin == hwnd) &&
618 (SCROLL_TrackingBar == nBar))
619 SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, thumbSize );
620 else if( interior )
621 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
622 thumbPos, infoPtr->flags, vertical, SCROLL_trackHitTest == SCROLL_TOP_RECT && SCROLL_lastHitTest == SCROLL_TOP_RECT,SCROLL_trackHitTest == SCROLL_BOTTOM_RECT && SCROLL_lastHitTest == SCROLL_BOTTOM_RECT);
623}
624
625/***********************************************************************
626 * SCROLL_RefreshScrollBar
627 *
628 * Repaint the scroll bar interior after a SetScrollRange() or
629 * SetScrollPos() call.
630 */
631static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar,
632 BOOL arrows, BOOL interior )
633{
634 HDC hdc = GetDCEx(hwnd,0,DCX_CACHE | ((nBar == SB_CTL) ? 0:DCX_WINDOW));
635
636 if (!hdc) return;
637
638 SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior );
639 ReleaseDC( hwnd, hdc );
640}
641
642/* Message Handler */
643
644LRESULT SCROLL_NCCreate(HWND hwnd,WPARAM wParam,LPARAM lParam)
645{
646 SCROLLBAR_INFO *infoPtr = (SCROLLBAR_INFO*)malloc(sizeof(SCROLLBAR_INFO));
647
648 infoPtr->MinVal = infoPtr->CurVal = infoPtr->Page = 0;
649 infoPtr->MaxVal = 100;
650 infoPtr->flags = ESB_ENABLE_BOTH;
651
652 SetInfoPtr(hwnd,(DWORD)infoPtr);
653
654 return TRUE;
655}
656
657LRESULT SCROLL_Create(HWND hwnd,WPARAM wParam,LPARAM lParam)
658{
659 CREATESTRUCTA *lpCreat = (CREATESTRUCTA *)lParam;
660
661 if (!(lpCreat->style & (SBS_SIZEBOX | SBS_SIZEGRIP)) && (lpCreat->style & (SBS_LEFTALIGN | SBS_RIGHTALIGN)))
662 {
663 if (lpCreat->style & SBS_VERT)
664 {
665 INT w,h;
666
667 w = GetSystemMetrics(SM_CXVSCROLL);
668 h = lpCreat->cy;
669
670 if (lpCreat->style & SBS_LEFTALIGN)
671 MoveWindow(hwnd,lpCreat->x,lpCreat->y,w,h,FALSE);
672 else if (lpCreat->style & SBS_RIGHTALIGN)
673 MoveWindow(hwnd,lpCreat->x+lpCreat->cx-w,lpCreat->y,w,h,FALSE);
674 } else /* SBS_HORZ */
675 {
676 INT w,h;
677
678 w = lpCreat->cx;
679 h = GetSystemMetrics(SM_CYHSCROLL);
680
681 if (lpCreat->style & SBS_TOPALIGN)
682 MoveWindow(hwnd,lpCreat->x,lpCreat->y,w,h,FALSE);
683 else if (lpCreat->style & SBS_BOTTOMALIGN)
684 MoveWindow(hwnd,lpCreat->x,lpCreat->y+lpCreat->cy-h,w,h,FALSE);
685 }
686 }
687
688 return 0;
689}
690
691static LRESULT SCROLL_Destroy(HWND hwnd,WPARAM wParam,LPARAM lParam)
692{
693 SCROLLBAR_INFO* infoPtr = (SCROLLBAR_INFO*)GetInfoPtr(hwnd);
694
695 free(infoPtr);
696
697 return 0;
698}
699
700/***********************************************************************
701 * SCROLL_HandleScrollEvent
702 *
703 * Handle a mouse or timer event for the scrollbar.
704 * 'pt' is the location of the mouse event in client (for SB_CTL) or
705 * windows coordinates.
706 */
707LRESULT SCROLL_HandleScrollEvent(HWND hwnd,WPARAM wParam,LPARAM lParam,INT nBar,UINT msg)
708{
709 static POINT prevPt; /* Previous mouse position for timer events */
710 static UINT trackThumbPos; /* Thumb position when tracking started. */
711 static BOOL thumbTrackSent;
712 static INT lastClickPos; /* Position in the scroll-bar of the last button-down event. */
713 static INT lastMousePos; /* Position in the scroll-bar of the last mouse event. */
714 static BOOL timerRunning;
715
716 enum SCROLL_HITTEST hittest;
717 HWND hwndOwner, hwndCtl;
718 BOOL vertical;
719 INT arrowSize, thumbSize, thumbPos;
720 RECT rect;
721 HDC hdc;
722 POINT pt;
723 LRESULT res = 0;
724
725 SCROLLBAR_INFO *infoPtr = SCROLL_GetInfoPtr(hwnd,nBar);
726 if (!infoPtr) return res;
727
728 if (nBar == SB_CTL)
729 {
730 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
731
732 if ((dwStyle & (SBS_SIZEBOX | SBS_SIZEGRIP)))
733 {
734 if (!(dwStyle & SBS_SIZEGRIP)) return res;
735
736 if (msg == WM_NCHITTEST)
737 {
738 if (dwStyle & SBS_SIZEGRIP)
739 {
740 RECT rect;
741
742 pt.x = (SHORT)LOWORD(lParam);
743 pt.y = (SHORT)HIWORD(lParam);
744 ScreenToClient(hwnd,&pt);
745 SCROLL_GetSizeBox(hwnd,dwStyle,&rect);
746 if (PtInRect(&rect,pt))
747 {
748 if (dwStyle & SBS_SIZEBOXTOPLEFTALIGN)
749 return HTTOPLEFT;
750 else
751 return HTBOTTOMRIGHT;
752 }
753 }
754 return DefWindowProcA(hwnd,WM_NCHITTEST,wParam,lParam);
755 } else if (msg == WM_LBUTTONDOWN)
756 {
757 return DefWindowProcA(hwnd,WM_LBUTTONDOWN,wParam,lParam);
758 }
759
760 return res;
761 }
762 }
763
764 if (msg == WM_NCHITTEST) return DefWindowProcA(hwnd,WM_NCHITTEST,wParam,lParam);
765
766 vertical = SCROLL_GetScrollBarRect(hwnd,nBar,&rect,&arrowSize,&thumbSize,&thumbPos);
767 hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd):hwnd;
768
769 hwndCtl = (nBar == SB_CTL) ? hwnd:0;
770
771 switch (msg)
772 {
773 case WM_LBUTTONDOWN: /* Initialise mouse tracking */
774 pt.x = (SHORT)LOWORD(lParam);
775 pt.y = (SHORT)HIWORD(lParam);
776 SCROLL_trackVertical = vertical;
777 SCROLL_trackHitTest = hittest = SCROLL_HitTest(hwnd,nBar,pt,FALSE);
778 if (SCROLL_trackHitTest == SCROLL_NOWHERE)
779 {
780 MessageBeep(MB_ICONEXCLAMATION);
781
782 return res;
783 }
784 SCROLL_Scrolling = TRUE;
785 timerRunning = FALSE;
786 if ((SCROLL_FocusWin == hwnd) && SCROLL_Highlighted)
787 {
788 hdc = GetDCEx(hwnd,0,DCX_CACHE | ((nBar == SB_CTL) ? 0:DCX_WINDOW));
789 SCROLL_DrawScrollBar(hwnd,hdc,nBar,FALSE,TRUE);
790 ReleaseDC(hwnd,hdc);
791 }
792 lastClickPos = vertical ? pt.y:pt.x;
793 lastMousePos = lastClickPos;
794 trackThumbPos = thumbPos;
795 prevPt = pt;
796 if (nBar == SB_CTL) SetFocus(hwnd);
797 SetCapture(hwnd);
798 break;
799
800 case WM_MOUSEMOVE:
801 if (SCROLL_Scrolling)
802 {
803 pt.x = (SHORT)LOWORD(lParam);
804 pt.y = (SHORT)HIWORD(lParam);
805 hittest = SCROLL_HitTest(hwnd,nBar,pt,TRUE);
806 prevPt = pt;
807 } else return res;
808 break;
809
810 case WM_LBUTTONUP:
811 if (SCROLL_Scrolling)
812 {
813 pt.x = (SHORT)LOWORD(lParam);
814 pt.y = (SHORT)HIWORD(lParam);
815 hittest = SCROLL_NOWHERE;
816 ReleaseCapture();
817 SCROLL_Scrolling = FALSE;
818 } else return res;
819 break;
820
821 case WM_CAPTURECHANGED:
822 if (SCROLL_Scrolling)
823 {
824 hittest = SCROLL_NOWHERE;
825 SCROLL_Scrolling = FALSE;
826 } else return res;
827 break;
828
829 case WM_SETFOCUS:
830 if (nBar == SB_CTL)
831 {
832 SCROLL_FocusWin = hwnd;
833 SCROLL_HasFocus = TRUE;
834 SCROLL_Highlighted = FALSE;
835 SetSystemTimer(hwnd,BLINK_TIMER,SCROLL_BLINK_DELAY,(TIMERPROC)0);
836 }
837 return res;
838
839 case WM_KILLFOCUS:
840 if (SCROLL_FocusWin == hwnd)
841 {
842 SCROLL_FocusWin = 0;
843 SCROLL_HasFocus = FALSE;
844 if (SCROLL_Highlighted)
845 {
846 SCROLL_Highlighted = FALSE;
847 hdc = GetDCEx(hwnd,0,DCX_CACHE | ((nBar == SB_CTL) ? 0:DCX_WINDOW));
848 SCROLL_DrawScrollBar(hwnd,hdc,nBar,FALSE,TRUE);
849 ReleaseDC(hwnd,hdc);
850 }
851 KillSystemTimer(hwnd,BLINK_TIMER);
852 }
853 return res;
854
855 case WM_SYSTIMER:
856 if (wParam == SCROLL_TIMER)
857 {
858 pt = prevPt;
859 hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
860 break;
861 } else if (wParam == BLINK_TIMER)
862 {
863 SCROLL_Highlighted = ~SCROLL_Highlighted;
864 if (!SCROLL_Scrolling)
865 {
866 hdc = GetDCEx(hwnd,0,DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
867 SCROLL_DrawScrollBar(hwnd,hdc,nBar,FALSE,TRUE);
868 ReleaseDC(hwnd,hdc);
869 }
870 return res;
871 } else return res;
872
873 default:
874 return res; /* Should never happen */
875 }
876
877 hdc = GetDCEx(hwnd,0,DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
878
879 switch(SCROLL_trackHitTest)
880 {
881 case SCROLL_NOWHERE: /* No tracking in progress */
882 break;
883
884 case SCROLL_TOP_ARROW:
885 if ((msg == WM_LBUTTONUP) || (msg == WM_CAPTURECHANGED))
886 KillSystemTimer(hwnd,SCROLL_TIMER);
887 else if ((msg == WM_LBUTTONDOWN) || (!timerRunning && msg == WM_SYSTIMER))
888 {
889 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
890 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
891 (TIMERPROC)0 );
892 if (msg != WM_LBUTTONDOWN) timerRunning = TRUE;
893 }
894
895 if ((msg == WM_LBUTTONDOWN) || (SCROLL_lastHitTest != hittest))
896 {
897 SCROLL_DrawTopArrow(hdc,infoPtr,&rect,arrowSize,vertical,(hittest == SCROLL_trackHitTest));
898 SCROLL_lastHitTest = hittest;
899 }
900 if ((hittest == SCROLL_trackHitTest) && ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)))
901 SendMessageA(hwndOwner,vertical ? WM_VSCROLL:WM_HSCROLL,SB_LINEUP,hwndCtl);
902
903 break;
904
905 case SCROLL_TOP_RECT:
906 if ((msg == WM_LBUTTONUP) || (msg == WM_CAPTURECHANGED))
907 KillSystemTimer(hwnd,SCROLL_TIMER);
908 else if ((msg == WM_LBUTTONDOWN) || (!timerRunning && (msg == WM_SYSTIMER)))
909 {
910 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
911 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
912 (TIMERPROC)0 );
913 if (msg != WM_LBUTTONDOWN) timerRunning = TRUE;
914 }
915
916 if ((msg == WM_LBUTTONDOWN) || (SCROLL_lastHitTest != hittest))
917 {
918 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
919 thumbPos, infoPtr->flags, vertical,
920 (hittest == SCROLL_trackHitTest), FALSE );
921 SCROLL_lastHitTest = hittest;
922 }
923
924 if ((hittest == SCROLL_trackHitTest) && ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)))
925 SendMessageA(hwndOwner,vertical ? WM_VSCROLL:WM_HSCROLL,SB_PAGEUP,hwndCtl);
926
927 break;
928
929 case SCROLL_THUMB:
930 if (msg == WM_LBUTTONDOWN)
931 {
932 SCROLL_TrackingWin = hwnd;
933 SCROLL_TrackingBar = nBar;
934 SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
935 SCROLL_TrackingVal = infoPtr->CurVal;
936 SCROLL_MovingThumb = TRUE;
937 thumbTrackSent = FALSE;
938 SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
939 } else if ((msg == WM_LBUTTONUP) || (msg == WM_CAPTURECHANGED))
940 {
941 UINT val;
942 INT oldPos = infoPtr->CurVal;
943
944 SCROLL_MovingThumb = FALSE;
945 SCROLL_TrackingWin = 0;
946 SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
947 val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
948 trackThumbPos + lastMousePos - lastClickPos );
949
950 if ((val != infoPtr->CurVal) || thumbTrackSent)
951 SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
952 MAKEWPARAM( SB_THUMBPOSITION, val ), hwndCtl );
953
954 if (oldPos == infoPtr->CurVal)
955 {
956 vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
957 &arrowSize, &thumbSize, &thumbPos );
958 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
959 thumbPos, infoPtr->flags, vertical,
960 FALSE, FALSE );
961 }
962
963 ReleaseDC(hwnd,hdc);
964 return res;
965 } else if (msg == WM_MOUSEMOVE)
966 {
967 UINT pos;
968
969 if (!SCROLL_PtInRectEx( &rect, pt, vertical )) pos = lastClickPos;
970 else
971 {
972 pt = SCROLL_ClipPos( &rect, pt );
973 pos = vertical ? pt.y:pt.x;
974 }
975 if (pos != lastMousePos)
976 {
977 lastMousePos = pos;
978 SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
979 SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
980 vertical,
981 SCROLL_TrackingPos );
982 SCROLL_DrawMovingThumb( hdc, &rect, vertical,
983 arrowSize, thumbSize );
984 SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
985 MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal),
986 hwndCtl );
987 thumbTrackSent = TRUE;
988 }
989 }
990 break;
991
992 case SCROLL_BOTTOM_RECT:
993 if ((msg == WM_LBUTTONUP) || (msg == WM_CAPTURECHANGED))
994 KillSystemTimer(hwnd,SCROLL_TIMER);
995 else if ((msg == WM_LBUTTONDOWN) || (!timerRunning && (msg == WM_SYSTIMER)))
996 {
997 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
998 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
999 (TIMERPROC)0 );
1000 if (msg != WM_LBUTTONDOWN) timerRunning = TRUE;
1001 }
1002
1003 if ((msg == WM_LBUTTONDOWN) || (SCROLL_lastHitTest != hittest))
1004 {
1005 SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
1006 thumbPos, infoPtr->flags, vertical,
1007 FALSE, (hittest == SCROLL_trackHitTest) );
1008 SCROLL_lastHitTest = hittest;
1009 }
1010
1011 if ((hittest == SCROLL_trackHitTest) && ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)))
1012 SendMessageA(hwndOwner,vertical ? WM_VSCROLL:WM_HSCROLL,SB_PAGEDOWN,hwndCtl);
1013
1014 break;
1015
1016 case SCROLL_BOTTOM_ARROW:
1017 if ((msg == WM_LBUTTONUP) || (msg == WM_CAPTURECHANGED))
1018 KillSystemTimer(hwnd,SCROLL_TIMER);
1019 else if ((msg == WM_LBUTTONDOWN) || (!timerRunning && (msg == WM_SYSTIMER)))
1020 {
1021 SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
1022 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
1023 (TIMERPROC)0 );
1024 if (msg != WM_LBUTTONDOWN) timerRunning = TRUE;
1025 }
1026
1027 if ((msg == WM_LBUTTONDOWN) || (SCROLL_lastHitTest != hittest))
1028 {
1029 SCROLL_DrawBottomArrow(hdc,infoPtr,&rect,arrowSize,vertical,(hittest == SCROLL_trackHitTest));
1030 SCROLL_lastHitTest = hittest;
1031 }
1032 if ((hittest == SCROLL_trackHitTest) && ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)))
1033 SendMessageA(hwndOwner,vertical ? WM_VSCROLL:WM_HSCROLL,SB_LINEDOWN,hwndCtl);
1034
1035 break;
1036 }
1037
1038 if ((msg == WM_LBUTTONUP) || (msg == WM_CAPTURECHANGED))
1039 {
1040 SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
1041
1042 SendMessageA(hwndOwner,vertical ? WM_VSCROLL:WM_HSCROLL,SB_ENDSCROLL,hwndCtl);
1043 }
1044
1045 ReleaseDC( hwnd, hdc );
1046
1047 return res;
1048}
1049
1050/***********************************************************************
1051 * SCROLL_HandleKbdEvent
1052 *
1053 * Handle a keyboard event (only for SB_CTL scrollbars).
1054 */
1055LRESULT SCROLL_KeyDown(HWND hwnd,WPARAM wParam,LPARAM lParam)
1056{
1057 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
1058 UINT msg;
1059
1060 if (dwStyle & (SBS_SIZEBOX | SBS_SIZEGRIP)) return 0;
1061
1062 switch(wParam)
1063 {
1064 case VK_PRIOR: msg = SB_PAGEUP; break;
1065 case VK_NEXT: msg = SB_PAGEDOWN; break;
1066 case VK_HOME: msg = SB_TOP; break;
1067 case VK_END: msg = SB_BOTTOM; break;
1068 case VK_UP: msg = SB_LINEUP; break;
1069 case VK_DOWN: msg = SB_LINEDOWN; break;
1070 default:
1071 return 0;
1072 }
1073 SendMessageA( GetParent(hwnd),
1074 (dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL,
1075 msg, hwnd );
1076
1077 return 0;
1078}
1079
1080LRESULT SCROLL_Paint(HWND hwnd,WPARAM wParam,LPARAM lParam,INT nBar)
1081{
1082 PAINTSTRUCT ps;
1083 HDC hdc = wParam ? (HDC)wParam:BeginPaint( hwnd, &ps );
1084
1085 SCROLL_DrawScrollBar( hwnd, hdc, nBar, TRUE, TRUE );
1086 if (!wParam) EndPaint( hwnd, &ps );
1087
1088 return 0;
1089}
1090
1091LRESULT SCROLL_SetRange(HWND hwnd,WPARAM wParam,LPARAM lParam,INT nBar,BOOL redraw)
1092{
1093 SCROLLBAR_INFO *infoPtr = SCROLL_GetInfoPtr(hwnd,nBar);
1094 INT oldPos = infoPtr->CurVal;
1095
1096 SetScrollRange(hwnd,nBar,wParam,lParam,redraw);
1097 return (oldPos != infoPtr->CurVal) ? infoPtr->CurVal:0;
1098}
1099
1100/* Window Procedures */
1101
1102/***********************************************************************
1103 * ScrollBarWndProc
1104 */
1105LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT message, WPARAM wParam,
1106 LPARAM lParam )
1107{
1108 switch(message)
1109 {
1110 case WM_NCCREATE:
1111 return SCROLL_NCCreate(hwnd,wParam,lParam);
1112
1113 case WM_CREATE:
1114 return SCROLL_Create(hwnd,wParam,lParam);
1115
1116 case WM_DESTROY:
1117 return SCROLL_Destroy(hwnd,wParam,lParam);
1118
1119 case WM_LBUTTONDOWN:
1120 case WM_LBUTTONUP:
1121 case WM_NCHITTEST:
1122 case WM_CAPTURECHANGED:
1123 case WM_MOUSEMOVE:
1124 case WM_SYSTIMER:
1125 case WM_SETFOCUS:
1126 case WM_KILLFOCUS:
1127 return SCROLL_HandleScrollEvent(hwnd,wParam,lParam,SB_CTL,message);
1128
1129 case WM_KEYDOWN:
1130 return SCROLL_KeyDown(hwnd,wParam,lParam);
1131
1132 case WM_ERASEBKGND:
1133 return 1;
1134
1135 case WM_GETDLGCODE:
1136 return DLGC_WANTARROWS; /* Windows returns this value */
1137
1138 case WM_PAINT:
1139 return SCROLL_Paint(hwnd,wParam,lParam,SB_CTL);
1140
1141 case SBM_SETPOS:
1142 return SetScrollPos( hwnd, SB_CTL, wParam, (BOOL)lParam );
1143
1144 case SBM_GETPOS:
1145 return GetScrollPos( hwnd, SB_CTL );
1146
1147 case SBM_SETRANGE:
1148 return SCROLL_SetRange(hwnd,wParam,lParam,SB_CTL,FALSE);
1149
1150 case SBM_GETRANGE:
1151 GetScrollRange( hwnd, SB_CTL, (LPINT)wParam, (LPINT)lParam );
1152 return 0;
1153
1154 case SBM_ENABLE_ARROWS:
1155 return EnableScrollBar( hwnd, SB_CTL, wParam );
1156
1157 case SBM_SETRANGEREDRAW:
1158 return SCROLL_SetRange(hwnd,wParam,lParam,SB_CTL,TRUE);
1159
1160 case SBM_SETSCROLLINFO:
1161 return SetScrollInfo(hwnd,SB_CTL,(SCROLLINFO*)lParam,wParam);
1162
1163 case SBM_GETSCROLLINFO:
1164 return GetScrollInfo( hwnd, SB_CTL, (SCROLLINFO *)lParam );
1165
1166 case 0x00e5:
1167 case 0x00e7:
1168 case 0x00e8:
1169 case 0x00eb:
1170 case 0x00ec:
1171 case 0x00ed:
1172 case 0x00ee:
1173 case 0x00ef:
1174 //ERR("unknown Win32 msg %04x wp=%08x lp=%08lx\n",
1175 // message, wParam, lParam );
1176 break;
1177
1178 default:
1179 return DefWindowProcA( hwnd, message, wParam, lParam );
1180 }
1181
1182 return 0;
1183}
1184
1185/* Scrollbar API */
1186
1187/*************************************************************************
1188 * SetScrollInfo (USER32.501)
1189 * SetScrollInfo32 can be used to set the position, upper bound,
1190 * lower bound, and page size of a scrollbar control.
1191 *
1192 * RETURNS
1193 * Scrollbar position
1194 *
1195 * NOTE
1196 * For 100 lines of text to be displayed in a window of 25 lines,
1197 * one would for instance use info->nMin=0, info->nMax=75
1198 * (corresponding to the 76 different positions of the window on
1199 * the text), and info->nPage=25.
1200 */
1201INT WINAPI SetScrollInfo(HWND hwnd,INT nBar,const SCROLLINFO *info,BOOL bRedraw)
1202{
1203 /* Update the scrollbar state and set action flags according to
1204 * what has to be done graphics wise. */
1205
1206 SCROLLBAR_INFO *infoPtr;
1207 UINT new_flags;
1208 INT action = 0;
1209
1210 dprintf(("USER32: SetScrollInfo %x %d",hwnd,nBar));
1211
1212 if (!(infoPtr = SCROLL_GetInfoPtr(hwnd,nBar))) return 0;
1213 if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0;
1214 if ((info->cbSize != sizeof(*info)) &&
1215 (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return 0;
1216
1217 /* Set the page size */
1218 if (info->fMask & SIF_PAGE)
1219 {
1220 if( infoPtr->Page != info->nPage )
1221 {
1222 infoPtr->Page = info->nPage;
1223 action |= SA_SSI_REPAINT_INTERIOR;
1224 }
1225 }
1226
1227 /* Set the scroll pos */
1228 if (info->fMask & SIF_POS)
1229 {
1230 //dsprintf(scroll, " pos=%d", info->nPos );
1231 if( infoPtr->CurVal != info->nPos )
1232 {
1233 infoPtr->CurVal = info->nPos;
1234 action |= SA_SSI_MOVE_THUMB;
1235 }
1236 }
1237
1238 /* Set the scroll range */
1239 if (info->fMask & SIF_RANGE)
1240 {
1241 /* Invalid range -> range is set to (0,0) */
1242 if ((info->nMin > info->nMax) ||
1243 ((UINT)(info->nMax - info->nMin) >= 0x80000000))
1244 {
1245 infoPtr->MinVal = 0;
1246 infoPtr->MaxVal = 0;
1247 }
1248 else
1249 {
1250 if( infoPtr->MinVal != info->nMin ||
1251 infoPtr->MaxVal != info->nMax )
1252 {
1253 action |= SA_SSI_REPAINT_INTERIOR;
1254 infoPtr->MinVal = info->nMin;
1255 infoPtr->MaxVal = info->nMax;
1256 }
1257 }
1258 }
1259
1260 /* Make sure the page size is valid */
1261
1262 if (infoPtr->Page < 0) infoPtr->Page = 0;
1263 else if (infoPtr->Page > infoPtr->MaxVal - infoPtr->MinVal + 1 )
1264 infoPtr->Page = infoPtr->MaxVal - infoPtr->MinVal + 1;
1265
1266 /* Make sure the pos is inside the range */
1267
1268 if (infoPtr->CurVal < infoPtr->MinVal)
1269 infoPtr->CurVal = infoPtr->MinVal;
1270 else if (infoPtr->CurVal > infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ))
1271 infoPtr->CurVal = infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 );
1272
1273 //TRACE(" new values: page=%d pos=%d min=%d max=%d\n",
1274 // infoPtr->Page, infoPtr->CurVal,
1275 // infoPtr->MinVal, infoPtr->MaxVal );
1276
1277 /* don't change the scrollbar state if SetScrollInfo
1278 * is just called with SIF_DISABLENOSCROLL
1279 */
1280 if(!(info->fMask & SIF_ALL)) goto done;
1281
1282 /* Check if the scrollbar should be hidden or disabled */
1283 if (info->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
1284 {
1285 new_flags = infoPtr->flags;
1286 if (infoPtr->MinVal >= infoPtr->MaxVal - MAX( infoPtr->Page-1, 0 ))
1287 {
1288 /* Hide or disable scroll-bar */
1289 if (info->fMask & SIF_DISABLENOSCROLL)
1290 {
1291 new_flags = ESB_DISABLE_BOTH;
1292 action |= SA_SSI_REFRESH;
1293 } else if (nBar != SB_CTL)
1294 {
1295 action = SA_SSI_HIDE;
1296 infoPtr->flags = 0;
1297 goto done;
1298 }
1299 } else /* Show and enable scroll-bar */
1300 {
1301 new_flags = 0;
1302 if (nBar != SB_CTL) action |= SA_SSI_SHOW;
1303 if (infoPtr->flags) action |= SA_SSI_REFRESH;
1304 }
1305
1306 if (infoPtr->flags != new_flags) /* check arrow flags */
1307 {
1308 infoPtr->flags = new_flags;
1309 action |= SA_SSI_REPAINT_ARROWS;
1310 }
1311 }
1312
1313done:
1314 /* Update scrollbar */
1315
1316 if( action & SA_SSI_HIDE )
1317 ShowScrollBar(hwnd,nBar,FALSE);
1318 else
1319 {
1320 if(action & SA_SSI_SHOW)
1321 ShowScrollBar(hwnd,nBar,TRUE);
1322
1323 if (bRedraw)
1324 {
1325 if (action & SA_SSI_REFRESH)
1326 SCROLL_RefreshScrollBar(hwnd,nBar,TRUE,TRUE);
1327 else
1328 {
1329 if (action & (SA_SSI_REPAINT_INTERIOR | SA_SSI_MOVE_THUMB))
1330 SCROLL_RefreshScrollBar(hwnd,nBar,FALSE,TRUE);
1331 if (action & SA_SSI_REPAINT_ARROWS)
1332 SCROLL_RefreshScrollBar(hwnd,nBar,TRUE,FALSE);
1333 }
1334 }
1335 }
1336
1337 /* Return current position */
1338
1339 return infoPtr->CurVal;
1340}
1341/*************************************************************************
1342 * GetScrollInfo (USER32.284)
1343 * GetScrollInfo32 can be used to retrieve the position, upper bound,
1344 * lower bound, and page size of a scrollbar control.
1345 *
1346 * RETURNS STD
1347 */
1348BOOL WINAPI GetScrollInfo(
1349 HWND hwnd /* [I] Handle of window */ ,
1350 INT nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */,
1351 LPSCROLLINFO info /* [IO] (info.fMask [I] specifies which values are to retrieve) */)
1352{
1353 SCROLLBAR_INFO *infoPtr;
1354
1355 dprintf(("USER32: GetScrollInfo"));
1356
1357 if (!(infoPtr = SCROLL_GetInfoPtr(hwnd,nBar))) return FALSE;
1358 if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return FALSE;
1359 if ((info->cbSize != sizeof(*info)) &&
1360 (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return FALSE;
1361
1362 if (info->fMask & SIF_PAGE) info->nPage = infoPtr->Page;
1363 if (info->fMask & SIF_POS) info->nPos = infoPtr->CurVal;
1364 if ((info->fMask & SIF_TRACKPOS) && (info->cbSize == sizeof(*info)))
1365 info->nTrackPos = (SCROLL_MovingThumb && SCROLL_TrackingWin == hwnd && SCROLL_TrackingBar == nBar) ? SCROLL_TrackingVal:infoPtr->CurVal;
1366
1367 if (info->fMask & SIF_RANGE)
1368 {
1369 info->nMin = infoPtr->MinVal;
1370 info->nMax = infoPtr->MaxVal;
1371 }
1372 return (info->fMask & SIF_ALL) != 0;
1373}
1374/*************************************************************************
1375 * SetScrollPos (USER32.502)
1376 *
1377 * RETURNS
1378 * Success: Scrollbar position
1379 * Failure: 0
1380 *
1381 * REMARKS
1382 * Note the ambiguity when 0 is returned. Use GetLastError
1383 * to make sure there was an error (and to know which one).
1384 */
1385INT WINAPI SetScrollPos(
1386 HWND hwnd /* [I] Handle of window whose scrollbar will be affected */,
1387 INT nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */,
1388 INT nPos /* [I] New value */,
1389 BOOL bRedraw /* [I] Should scrollbar be redrawn afterwards ? */ )
1390{
1391 SCROLLINFO info;
1392 SCROLLBAR_INFO *infoPtr;
1393 INT oldPos;
1394
1395 dprintf(("SetScrollPos %x %d %d %d", hwnd, nBar, nPos, bRedraw));
1396 if (!(infoPtr = SCROLL_GetInfoPtr(hwnd,nBar))) return 0;
1397 oldPos = infoPtr->CurVal;
1398 info.cbSize = sizeof(info);
1399 info.nPos = nPos;
1400 info.fMask = SIF_POS;
1401 SetScrollInfo( hwnd, nBar, &info, bRedraw );
1402 return oldPos;
1403}
1404/*************************************************************************
1405 * GetScrollPos (USER32.285)
1406 *
1407 * RETURNS
1408 * Success: Current position
1409 * Failure: 0
1410 *
1411 * REMARKS
1412 * Note the ambiguity when 0 is returned. Use GetLastError
1413 * to make sure there was an error (and to know which one).
1414 */
1415INT WINAPI GetScrollPos(
1416 HWND hwnd, /* [I] Handle of window */
1417 INT nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */)
1418{
1419 SCROLLBAR_INFO *infoPtr;
1420
1421 dprintf(("GetScrollPos %x %d", hwnd, nBar));
1422
1423 infoPtr = SCROLL_GetInfoPtr(hwnd,nBar);
1424 if (!infoPtr) return 0;
1425
1426 return infoPtr->CurVal;
1427}
1428
1429/*************************************************************************
1430 * SetScrollRange (USER32.503)
1431 *
1432 * RETURNS STD
1433 */
1434BOOL WINAPI SetScrollRange(
1435 HWND hwnd, /* [I] Handle of window whose scrollbar will be affected */
1436 INT nBar, /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */
1437 INT MinVal, /* [I] New minimum value */
1438 INT MaxVal, /* [I] New maximum value */
1439 BOOL bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
1440{
1441 SCROLLINFO info;
1442
1443 dprintf(("SetScrollRange %x %x %d %d %d", hwnd, nBar, MinVal, MaxVal, bRedraw));
1444 info.cbSize = sizeof(info);
1445 info.nMin = MinVal;
1446 info.nMax = MaxVal;
1447 info.fMask = SIF_RANGE;
1448 SetScrollInfo( hwnd, nBar, &info, bRedraw );
1449 return TRUE;
1450}
1451
1452/*************************************************************************
1453 * GetScrollRange (USER32.286)
1454 *
1455 * RETURNS STD
1456 */
1457BOOL WINAPI GetScrollRange(
1458 HWND hwnd, /* [I] Handle of window */
1459 INT nBar, /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */
1460 LPINT lpMin, /* [O] Where to store minimum value */
1461 LPINT lpMax /* [O] Where to store maximum value */)
1462{
1463 SCROLLBAR_INFO *infoPtr;
1464
1465 infoPtr = SCROLL_GetInfoPtr(hwnd,nBar);
1466 if (!infoPtr)
1467 {
1468 if (lpMin) lpMin = 0;
1469 if (lpMax) lpMax = 0;
1470 return FALSE;
1471 }
1472 if (lpMin) *lpMin = infoPtr->MinVal;
1473 if (lpMax) *lpMax = infoPtr->MaxVal;
1474 return TRUE;
1475}
1476
1477/*************************************************************************
1478 * ShowScrollBar (USER32.532)
1479 *
1480 * RETURNS STD
1481 */
1482BOOL WINAPI ShowScrollBar(
1483 HWND hwnd, /* [I] Handle of window whose scrollbar(s) will be affected */
1484 INT nBar, /* [I] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */
1485 BOOL fShow /* [I] TRUE = show, FALSE = hide */)
1486{
1487 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
1488 BOOL fShowH = (nBar == SB_HORZ) ? fShow : 0;
1489 BOOL fShowV = (nBar == SB_VERT) ? fShow : 0;
1490
1491 dprintf(("ShowScrollBar %04x %d %d\n", hwnd, nBar, fShow));
1492 if (!win32wnd) return FALSE;
1493
1494 //CB: does Win32 send a WM_STYLECHANGED message?
1495 switch(nBar)
1496 {
1497 case SB_CTL:
1498 ShowWindow(hwnd,fShow ? SW_SHOW:SW_HIDE);
1499 return TRUE;
1500
1501 case SB_BOTH:
1502 case SB_HORZ:
1503 if (fShow)
1504 {
1505 fShowH = !(win32wnd->getStyle() & WS_HSCROLL);
1506 win32wnd->setStyle(win32wnd->getStyle() | WS_HSCROLL);
1507 }
1508 else /* hide it */
1509 {
1510 fShowH = (win32wnd->getStyle() & WS_HSCROLL);
1511 win32wnd->setStyle(win32wnd->getStyle() & ~WS_HSCROLL);
1512 }
1513 if( nBar == SB_HORZ )
1514 {
1515 fShowV = FALSE;
1516 break;
1517 }
1518 /* fall through */
1519
1520 case SB_VERT:
1521 if (fShow)
1522 {
1523 fShowV = !(win32wnd->getStyle() & WS_VSCROLL);
1524 win32wnd->setStyle(win32wnd->getStyle() | WS_VSCROLL);
1525 }
1526 else /* hide it */
1527 {
1528 fShowV = (win32wnd->getStyle() & WS_VSCROLL);
1529 win32wnd->setStyle(win32wnd->getStyle() & ~WS_VSCROLL);
1530 }
1531 if ( nBar == SB_VERT )
1532 fShowH = FALSE;
1533 break;
1534
1535 default:
1536 return TRUE; /* Nothing to do! */
1537 }
1538
1539 if( fShowH || fShowV ) /* frame has been changed, let the window redraw itself */
1540 {
1541 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
1542 | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
1543 }
1544
1545 return TRUE;
1546}
1547
1548/*************************************************************************
1549 * EnableScrollBar (USER32.171)
1550 */
1551BOOL WINAPI EnableScrollBar( HWND hwnd, INT nBar, UINT flags)
1552{
1553 BOOL bFineWithMe;
1554 SCROLLBAR_INFO *infoPtr;
1555
1556 dprintf(("EnableScrollBar %04x %d %d\n", hwnd, nBar, flags));
1557
1558 flags &= ESB_DISABLE_BOTH;
1559
1560 if (nBar == SB_BOTH)
1561 {
1562 if (!(infoPtr = SCROLL_GetInfoPtr( hwnd, SB_VERT ))) return FALSE;
1563 if (!(bFineWithMe = (infoPtr->flags == flags)) )
1564 {
1565 infoPtr->flags = flags;
1566 SCROLL_RefreshScrollBar( hwnd, SB_VERT, TRUE, TRUE );
1567 }
1568 nBar = SB_HORZ;
1569 }
1570 else
1571 bFineWithMe = TRUE;
1572
1573 if (!(infoPtr = SCROLL_GetInfoPtr( hwnd, nBar ))) return FALSE;
1574 if (bFineWithMe && infoPtr->flags == flags) return FALSE;
1575 infoPtr->flags = flags;
1576
1577 SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1578 return TRUE;
1579}
1580
1581//CB: not listed in user32.exp -> don't know the id!
1582
1583BOOL WINAPI GetScrollBarInfo(HWND hwnd,LONG idObject,PSCROLLBARINFO psbi)
1584{
1585 if (!psbi || (psbi->cbSize != sizeof(SCROLLBARINFO)))
1586 {
1587 SetLastError(ERROR_INVALID_PARAMETER);
1588
1589 return FALSE;
1590 }
1591
1592 INT nBar,arrowSize;
1593
1594 switch (idObject)
1595 {
1596 case OBJID_CLIENT:
1597 nBar = SB_CTL;
1598 break;
1599
1600 case OBJID_HSCROLL:
1601 nBar = SB_HORZ;
1602 break;
1603
1604 case OBJID_VSCROLL:
1605 nBar = SB_VERT;
1606 break;
1607
1608 default:
1609 return FALSE;
1610 }
1611
1612 SCROLL_GetScrollBarRect(hwnd,nBar,&psbi->rcScrollBar,&arrowSize,&psbi->dxyLineButton,&psbi->xyThumbTop);
1613 psbi->xyThumbBottom = psbi->xyThumbTop+psbi->dxyLineButton;
1614 psbi->bogus = 0; //CB: undocumented!
1615 psbi->rgstate[0] = IsWindowVisible(hwnd) ? STATE_SYSTEM_INVISIBLE:0;
1616 psbi->rgstate[1] = psbi->rgstate[2] = psbi->rgstate[3] = psbi->rgstate[4] = psbi->rgstate[5] = psbi->rgstate[0]; //CB: todo
1617
1618 return TRUE;
1619}
1620//******************************************************************************
1621//******************************************************************************
1622BOOL SCROLLBAR_Register()
1623{
1624 WNDCLASSA wndClass;
1625
1626//SvL: Don't check this now
1627// if (GlobalFindAtomA(SCROLLBARCLASSNAME)) return FALSE;
1628
1629 ZeroMemory(&wndClass,sizeof(WNDCLASSA));
1630 wndClass.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW | CS_PARENTDC;
1631 wndClass.lpfnWndProc = (WNDPROC)ScrollBarWndProc;
1632 wndClass.cbClsExtra = 0;
1633 wndClass.cbWndExtra = sizeof(SCROLLBAR_INFO);
1634 wndClass.hCursor = LoadCursorA(0,IDC_ARROWA);
1635 wndClass.hbrBackground = (HBRUSH)0;
1636 wndClass.lpszClassName = SCROLLBARCLASSNAME;
1637
1638 return RegisterClassA(&wndClass);
1639}
1640//******************************************************************************
1641//******************************************************************************
1642BOOL SCROLLBAR_Unregister()
1643{
1644 if (GlobalFindAtomA(SCROLLBARCLASSNAME))
1645 return UnregisterClassA(SCROLLBARCLASSNAME,(HINSTANCE)NULL);
1646 else return FALSE;
1647}
1648//******************************************************************************
1649//******************************************************************************
1650
Note: See TracBrowser for help on using the repository browser.