87b6c7a117b4e4c8f40d0ff6001550028f7a8656
[reactos.git] / reactos / lib / user32 / controls / scrollbar.c
1 /* $Id $
2 *
3 * ReactOS User32 Library
4 * - ScrollBar control
5 *
6 * Copyright 2001 Casper S. Hornstrup
7 * Copyright 2003 Thomas Weidenmueller
8 * Copyright 2003 Filip Navara
9 *
10 * Based on Wine code.
11 *
12 * Copyright 1993 Martin Ayotte
13 * Copyright 1994, 1996 Alexandre Julliard
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Library General Public
17 * License as published by the Free Software Foundation; either
18 * version 2 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Library General Public License for more details.
24 *
25 * You should have received a copy of the GNU Library General Public
26 * License along with this library; see the file COPYING.LIB.
27 * If not, write to the Free Software Foundation,
28 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 */
30
31 /* INCLUDES *******************************************************************/
32
33 #include <user32.h>
34 #define NDEBUG
35 #include <debug.h>
36
37
38 /* GLOBAL VARIABLES ***********************************************************/
39
40 /* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */
41 #define SCROLL_NOWHERE 0x00 /* Outside the scroll bar */
42 #define SCROLL_TOP_ARROW 0x01 /* Top or left arrow */
43 #define SCROLL_TOP_RECT 0x02 /* Rectangle between the top arrow and the thumb */
44 #define SCROLL_THUMB 0x03 /* Thumb rectangle */
45 #define SCROLL_BOTTOM_RECT 0x04 /* Rectangle between the thumb and the bottom arrow */
46 #define SCROLL_BOTTOM_ARROW 0x05 /* Bottom or right arrow */
47
48 #define SCROLL_FIRST_DELAY 200 /* Delay (in ms) before first repetition when
49 holding the button down */
50 #define SCROLL_REPEAT_DELAY 50 /* Delay (in ms) between scroll repetitions */
51
52 #define SCROLL_TIMER 0 /* Scroll timer id */
53
54 /* Minimum size of the rectangle between the arrows */
55 #define SCROLL_MIN_RECT 4
56
57 /* Minimum size of the thumb in pixels */
58 #define SCROLL_MIN_THUMB 6
59
60 /* Thumb-tracking info */
61 static HWND ScrollTrackingWin = 0;
62 static INT ScrollTrackingBar = 0;
63 static INT ScrollTrackingPos = 0;
64 static INT ScrollTrackingVal = 0;
65 static BOOL ScrollMovingThumb = FALSE;
66
67 static DWORD ScrollTrackHitTest = SCROLL_NOWHERE;
68 static BOOL ScrollTrackVertical;
69
70 HBRUSH DefWndControlColor(HDC hDC, UINT ctlType);
71
72 static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
73
74 UINT STDCALL SetSystemTimer(HWND,UINT_PTR,UINT,TIMERPROC);
75 BOOL STDCALL KillSystemTimer(HWND,UINT_PTR);
76
77 /*********************************************************************
78 * scrollbar class descriptor
79 */
80 const struct builtin_class_descr SCROLL_builtin_class =
81 {
82 L"ScrollBar", /* name */
83 CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style */
84 ScrollBarWndProc, /* procW */
85 NULL, /* procA (winproc is Unicode only) */
86 0, /* extra */
87 IDC_ARROW, /* cursor */
88 0 /* brush */
89 };
90
91 /* PRIVATE FUNCTIONS **********************************************************/
92
93
94 static void
95 IntDrawScrollInterior(HWND hWnd, HDC hDC, INT nBar, BOOL Vertical,
96 PSCROLLBARINFO ScrollBarInfo)
97 {
98 INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
99 INT ThumbTop = ScrollBarInfo->xyThumbTop;
100 RECT Rect;
101 HPEN hSavePen;
102 HBRUSH hSaveBrush, hBrush;
103 BOOL TopSelected = FALSE, BottomSelected = FALSE;
104
105 if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
106 TopSelected = TRUE;
107 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
108 BottomSelected = TRUE;
109
110 /*
111 * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
112 * The window-owned scrollbars need to call DefWndControlColor
113 * to correctly setup default scrollbar colors
114 */
115 if (nBar == SB_CTL)
116 {
117 hBrush = (HBRUSH)SendMessageW(GetParent(hWnd), WM_CTLCOLORSCROLLBAR, (WPARAM)hDC, (LPARAM)hWnd);
118 if (!hBrush)
119 hBrush = GetSysColorBrush(COLOR_SCROLLBAR);
120 }
121 else
122 {
123 hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
124 }
125
126 hSavePen = SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
127 hSaveBrush = SelectObject(hDC, hBrush);
128
129 /* Calculate the scroll rectangle */
130 if (Vertical)
131 {
132 Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
133 Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
134 Rect.left = ScrollBarInfo->rcScrollBar.left;
135 Rect.right = ScrollBarInfo->rcScrollBar.right;
136 }
137 else
138 {
139 Rect.top = ScrollBarInfo->rcScrollBar.top;
140 Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
141 Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
142 Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
143 }
144
145 /* Draw the scroll rectangles and thumb */
146 if (!ScrollBarInfo->xyThumbBottom)
147 {
148 PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
149 Rect.bottom - Rect.top, PATCOPY);
150
151 /* Cleanup and return */
152 SelectObject(hDC, hSavePen);
153 SelectObject(hDC, hSaveBrush);
154 return;
155 }
156
157 ThumbTop -= ScrollBarInfo->dxyLineButton;
158
159 if (ScrollBarInfo->dxyLineButton)
160 {
161 if (Vertical)
162 {
163 if (ThumbSize)
164 {
165 PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
166 ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
167 Rect.top += ThumbTop;
168 PatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
169 Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
170 Rect.bottom = Rect.top + ThumbSize;
171 }
172 else
173 {
174 if (ThumbTop)
175 {
176 PatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
177 Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
178 }
179 }
180 }
181 else
182 {
183 if (ThumbSize)
184 {
185 PatBlt(hDC, Rect.left, Rect.top, ThumbTop,
186 Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
187 Rect.left += ThumbTop;
188 PatBlt(hDC, Rect.left + ThumbSize, Rect.top,
189 Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
190 BottomSelected ? BLACKNESS : PATCOPY);
191 Rect.right = Rect.left + ThumbSize;
192 }
193 else
194 {
195 if (ThumbTop)
196 {
197 PatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
198 Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
199 }
200 }
201 }
202 }
203
204 /* Draw the thumb */
205 if (ThumbSize)
206 DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
207
208 /* Cleanup */
209 SelectObject(hDC, hSavePen);
210 SelectObject(hDC, hSaveBrush);
211 }
212
213 STATIC VOID FASTCALL
214 IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
215 {
216 RECT RectLT, RectRB;
217 INT ScrollDirFlagLT, ScrollDirFlagRB;
218
219 RectLT = RectRB = ScrollBarInfo->rcScrollBar;
220 if (Vertical)
221 {
222 ScrollDirFlagLT = DFCS_SCROLLUP;
223 ScrollDirFlagRB = DFCS_SCROLLDOWN;
224 RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
225 RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
226 }
227 else
228 {
229 ScrollDirFlagLT = DFCS_SCROLLLEFT;
230 ScrollDirFlagRB = DFCS_SCROLLRIGHT;
231 RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
232 RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
233 }
234
235 if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
236 {
237 ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
238 }
239 if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
240 {
241 ScrollDirFlagLT |= DFCS_INACTIVE;
242 }
243 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
244 {
245 ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
246 }
247 if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
248 {
249 ScrollDirFlagRB |= DFCS_INACTIVE;
250 }
251
252 DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
253 DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
254 }
255
256 STATIC VOID FASTCALL
257 IntScrollDrawMovingThumb(HDC Dc, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
258 {
259 INT Pos = ScrollTrackingPos;
260 INT MaxSize;
261 INT OldTop;
262
263 if (Vertical)
264 {
265 MaxSize = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->rcScrollBar.top;
266 }
267 else
268 {
269 MaxSize = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->rcScrollBar.left;
270 }
271
272 MaxSize -= ScrollBarInfo->dxyLineButton + ScrollBarInfo->xyThumbBottom
273 - ScrollBarInfo->xyThumbTop;
274
275 if (Pos < ScrollBarInfo->dxyLineButton)
276 {
277 Pos = ScrollBarInfo->dxyLineButton;
278 }
279 else if (MaxSize < Pos)
280 {
281 Pos = MaxSize;
282 }
283
284 OldTop = ScrollBarInfo->xyThumbTop;
285 ScrollBarInfo->xyThumbBottom = Pos + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
286 ScrollBarInfo->xyThumbTop = Pos;
287 IntDrawScrollInterior(ScrollTrackingWin, Dc, ScrollTrackingBar, Vertical, ScrollBarInfo);
288 ScrollBarInfo->xyThumbBottom = OldTop + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
289 ScrollBarInfo->xyThumbTop = OldTop;
290
291 ScrollMovingThumb = ! ScrollMovingThumb;
292 }
293
294 STATIC LONG FASTCALL
295 IntScrollGetObjectId(INT SBType)
296 {
297 if (SB_VERT == SBType)
298 {
299 return OBJID_VSCROLL;
300 }
301 if (SB_HORZ == SBType)
302 {
303 return OBJID_HSCROLL;
304 }
305
306 return OBJID_CLIENT;
307 }
308
309 STATIC BOOL FASTCALL
310 IntGetScrollBarInfo(HWND Wnd, INT Bar, PSCROLLBARINFO ScrollBarInfo)
311 {
312 ScrollBarInfo->cbSize = sizeof(SCROLLBARINFO);
313
314 return NtUserGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), ScrollBarInfo);
315 }
316
317 void
318 IntDrawScrollBar(HWND Wnd, HDC DC, INT Bar)
319 {
320 INT ThumbSize;
321 SCROLLBARINFO Info;
322 BOOL Vertical;
323
324 /*
325 * Get scroll bar info.
326 */
327 switch (Bar)
328 {
329 case SB_HORZ:
330 Vertical = FALSE;
331 break;
332
333 case SB_VERT:
334 Vertical = TRUE;
335 break;
336
337 case SB_CTL:
338 Vertical = (GetWindowLongW(Wnd, GWL_STYLE) & SBS_VERT) != 0;
339 break;
340
341 default:
342 return;
343 }
344 if (! IntGetScrollBarInfo(Wnd, Bar, &Info))
345 {
346 return;
347 }
348
349 if (IsRectEmpty(&Info.rcScrollBar))
350 {
351 return;
352 }
353
354 ThumbSize = Info.xyThumbBottom - Info.xyThumbTop;
355
356 /*
357 * Draw the arrows.
358 */
359 if (Info.dxyLineButton)
360 {
361 IntDrawScrollArrows(DC, &Info, Vertical);
362 }
363
364 /*
365 * Draw the interior.
366 */
367 IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);
368
369 /*
370 * If scroll bar has focus, reposition the caret.
371 */
372 if (Wnd == GetFocus() && SB_CTL == Bar)
373 {
374 if (Vertical)
375 {
376 SetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
377 }
378 else
379 {
380 SetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
381 }
382 }
383 }
384
385 STATIC BOOL FASTCALL
386 IntScrollPtInRectEx(LPRECT Rect, POINT Pt, BOOL Vertical)
387 {
388 RECT TempRect = *Rect;
389 if (Vertical)
390 {
391 TempRect.left -= Rect->right - Rect->left;
392 TempRect.right += Rect->right - Rect->left;
393 }
394 else
395 {
396 TempRect.top -= Rect->bottom - Rect->top;
397 TempRect.bottom += Rect->bottom - Rect->top;
398 }
399
400 return PtInRect(&TempRect, Pt);
401 }
402
403 STATIC DWORD FASTCALL
404 IntScrollHitTest(PSCROLLBARINFO ScrollBarInfo, BOOL Vertical, POINT Pt, BOOL Dragging)
405 {
406 INT ArrowSize, ThumbSize, ThumbPos;
407
408 if ((Dragging && ! IntScrollPtInRectEx(&ScrollBarInfo->rcScrollBar, Pt, Vertical)) ||
409 ! PtInRect(&ScrollBarInfo->rcScrollBar, Pt))
410 {
411 return SCROLL_NOWHERE;
412 }
413
414 ThumbPos = ScrollBarInfo->xyThumbTop;
415 ThumbSize = ScrollBarInfo->xyThumbBottom - ThumbPos;
416 ArrowSize = ScrollBarInfo->dxyLineButton;
417
418 if (Vertical)
419 {
420 if (Pt.y < ScrollBarInfo->rcScrollBar.top + ArrowSize)
421 {
422 return SCROLL_TOP_ARROW;
423 }
424 if (ScrollBarInfo->rcScrollBar.bottom - ArrowSize <= Pt.y)
425 {
426 return SCROLL_BOTTOM_ARROW;
427 }
428 if (0 == ThumbPos)
429 {
430 return SCROLL_TOP_RECT;
431 }
432 Pt.y -= ScrollBarInfo->rcScrollBar.top;
433 if (Pt.y < ThumbPos)
434 {
435 return SCROLL_TOP_RECT;
436 }
437 if (ThumbPos + ThumbSize <= Pt.y)
438 {
439 return SCROLL_BOTTOM_RECT;
440 }
441 }
442 else
443 {
444 if (Pt.x < ScrollBarInfo->rcScrollBar.left + ArrowSize)
445 {
446 return SCROLL_TOP_ARROW;
447 }
448 if (ScrollBarInfo->rcScrollBar.right - ArrowSize <= Pt.x)
449 {
450 return SCROLL_BOTTOM_ARROW;
451 }
452 if (0 == ThumbPos)
453 {
454 return SCROLL_TOP_RECT;
455 }
456 Pt.x -= ScrollBarInfo->rcScrollBar.left;
457 if (Pt.x < ThumbPos)
458 {
459 return SCROLL_TOP_RECT;
460 }
461 if (ThumbPos + ThumbSize <= Pt.x)
462 {
463 return SCROLL_BOTTOM_RECT;
464 }
465 }
466
467 return SCROLL_THUMB;
468 }
469
470
471 /***********************************************************************
472 * IntScrollGetScrollBarRect
473 *
474 * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
475 * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
476 * 'arrowSize' returns the width or height of an arrow (depending on
477 * the orientation of the scrollbar), 'thumbSize' returns the size of
478 * the thumb, and 'thumbPos' returns the position of the thumb
479 * relative to the left or to the top.
480 * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
481 */
482 STATIC BOOL FASTCALL
483 IntScrollGetScrollBarRect(HWND Wnd, INT Bar, RECT *Rect,
484 INT *ArrowSize, INT *ThumbSize,
485 INT *ThumbPos)
486 {
487 INT Pixels;
488 BOOL Vertical;
489 RECT ClientRect;
490 RECT WindowRect;
491 DWORD Style, ExStyle;
492
493 GetClientRect(Wnd, &ClientRect);
494 if (SB_HORZ == Bar || SB_VERT == Bar)
495 {
496 ClientToScreen(Wnd, (LPPOINT) &ClientRect.left);
497 ClientToScreen(Wnd, (LPPOINT) &ClientRect.right);
498 GetWindowRect(Wnd, &WindowRect);
499 }
500 Style = GetWindowLongW(Wnd, GWL_STYLE);
501
502 switch (Bar)
503 {
504 case SB_HORZ:
505 Rect->left = ClientRect.left - WindowRect.left;
506 Rect->top = ClientRect.bottom - WindowRect.top;
507 Rect->right = ClientRect.right - WindowRect.left;
508 Rect->bottom = Rect->top + GetSystemMetrics(SM_CYHSCROLL);
509 if (0 != (Style & WS_BORDER))
510 {
511 Rect->left--;
512 Rect->right++;
513 }
514 else if (0 != (Style & WS_VSCROLL))
515 {
516 Rect->right++;
517 }
518 Vertical = FALSE;
519 break;
520
521 case SB_VERT:
522 ExStyle = GetWindowLongW(Wnd, GWL_EXSTYLE);
523 if (0 != (ExStyle & WS_EX_LEFTSCROLLBAR))
524 {
525 Rect->left = ClientRect.left - WindowRect.left - GetSystemMetrics(SM_CXVSCROLL);
526 }
527 else
528 {
529 Rect->left = ClientRect.right - WindowRect.left;
530 }
531 Rect->top = ClientRect.top - WindowRect.top;
532 Rect->right = Rect->left + GetSystemMetrics(SM_CXVSCROLL);
533 Rect->bottom = ClientRect.bottom - WindowRect.top;
534 if (0 != (Style & WS_BORDER))
535 {
536 Rect->top--;
537 Rect->bottom++;
538 }
539 else if (0 != (Style & WS_HSCROLL))
540 {
541 Rect->bottom++;
542 }
543 Vertical = TRUE;
544 break;
545
546 case SB_CTL:
547 *Rect = ClientRect;
548 Vertical = (0 != (Style & SBS_VERT));
549 break;
550
551 default:
552 return FALSE;
553 }
554
555 if (Vertical)
556 {
557 Pixels = Rect->bottom - Rect->top;
558 }
559 else
560 {
561 Pixels = Rect->right - Rect->left;
562 }
563
564 if (Pixels <= 2 * GetSystemMetrics(SM_CXVSCROLL) + SCROLL_MIN_RECT)
565 {
566 if (SCROLL_MIN_RECT < Pixels)
567 {
568 *ArrowSize = (Pixels - SCROLL_MIN_RECT) / 2;
569 }
570 else
571 {
572 *ArrowSize = 0;
573 }
574 *ThumbPos = *ThumbSize = 0;
575 }
576 else
577 {
578 SCROLLINFO Info;
579
580 NtUserGetScrollInfo(Wnd, Bar, &Info);
581 *ArrowSize = GetSystemMetrics(SM_CXVSCROLL);
582 Pixels -= (2 * GetSystemMetrics(SM_CXVSCROLL));
583
584 if (0 != Info.nPage)
585 {
586 *ThumbSize = MulDiv(Pixels, Info.nPage, (Info.nMax - Info.nMin + 1));
587 if (*ThumbSize < SCROLL_MIN_THUMB)
588 {
589 *ThumbSize = SCROLL_MIN_THUMB;
590 }
591 }
592 else
593 {
594 *ThumbSize = GetSystemMetrics(SM_CXVSCROLL);
595 }
596
597 #if 0 /* FIXME */
598 if (((pixels -= *ThumbSize ) < 0) ||
599 ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
600 #else
601 if ((Pixels -= *ThumbSize ) < 0)
602 #endif
603 {
604 /* Rectangle too small or scrollbar disabled -> no thumb */
605 *ThumbPos = *ThumbSize = 0;
606 }
607 else
608 {
609 INT Max = Info.nMax - max(Info.nPage - 1, 0);
610 if (Max <= Info.nMin)
611 {
612 *ThumbPos = *ArrowSize;
613 }
614 else
615 {
616 *ThumbPos = *ArrowSize
617 + MulDiv(Pixels, (Info.nPos - Info.nMin),
618 (Max - Info.nMin));
619 }
620 }
621 }
622
623 return Vertical;
624 }
625
626 /***********************************************************************
627 * IntScrollGetThumbVal
628 *
629 * Compute the current scroll position based on the thumb position in pixels
630 * from the top of the scroll-bar.
631 */
632 STATIC UINT FASTCALL
633 IntScrollGetThumbVal(HWND Wnd, INT SBType, PSCROLLBARINFO ScrollBarInfo,
634 BOOL Vertical, INT Pos)
635 {
636 SCROLLINFO si;
637 INT Pixels = Vertical ? ScrollBarInfo->rcScrollBar.bottom
638 - ScrollBarInfo->rcScrollBar.top
639 : ScrollBarInfo->rcScrollBar.right
640 - ScrollBarInfo->rcScrollBar.left;
641
642 si.cbSize = sizeof(SCROLLINFO);
643 si.fMask = SIF_RANGE | SIF_PAGE;
644 NtUserGetScrollInfo(Wnd, SBType, &si);
645 if ((Pixels -= 2 * ScrollBarInfo->dxyLineButton) <= 0)
646 {
647 return si.nMin;
648 }
649
650 if ((Pixels -= (ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop)) <= 0)
651 {
652 return si.nMin;
653 }
654
655 Pos = Pos - ScrollBarInfo->dxyLineButton;
656 if (Pos < 0)
657 {
658 Pos = 0;
659 }
660 if (Pixels < Pos)
661 {
662 Pos = Pixels;
663 }
664
665 if (0 == si.nPage)
666 {
667 Pos *= si.nMax - si.nMin;
668 }
669 else
670 {
671 Pos *= si.nMax - si.nMin - si.nPage + 1;
672 }
673 return si.nMin + ((Pos + Pixels / 2) / Pixels);
674 }
675
676 /***********************************************************************
677 * IntScrollClipPos
678 */
679 STATIC POINT IntScrollClipPos(PRECT Rect, POINT Pt)
680 {
681 if (Pt.x < Rect->left)
682 {
683 Pt.x = Rect->left;
684 }
685 else if (Rect->right < Pt.x)
686 {
687 Pt.x = Rect->right;
688 }
689
690 if (Pt.y < Rect->top)
691 {
692 Pt.y = Rect->top;
693 }
694 else if (Rect->bottom < Pt.y)
695 {
696 Pt.y = Rect->bottom;
697 }
698
699 return Pt;
700 }
701
702 /***********************************************************************
703 * IntScrollDrawSizeGrip
704 *
705 * Draw the size grip.
706 */
707 STATIC void FASTCALL
708 IntScrollDrawSizeGrip(HWND Wnd, HDC Dc)
709 {
710 RECT Rect;
711
712 GetClientRect(Wnd, &Rect);
713 FillRect(Dc, &Rect, GetSysColorBrush(COLOR_SCROLLBAR));
714 Rect.left = max(Rect.left, Rect.right - GetSystemMetrics(SM_CXVSCROLL) - 1);
715 Rect.top = max(Rect.top, Rect.bottom - GetSystemMetrics(SM_CYHSCROLL) - 1);
716 DrawFrameControl(Dc, &Rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
717 }
718
719
720
721 /***********************************************************************
722 * IntScrollHandleKbdEvent
723 *
724 * Handle a keyboard event (only for SB_CTL scrollbars with focus).
725 */
726 STATIC void FASTCALL
727 IntScrollHandleKbdEvent(
728 HWND Wnd /* [in] Handle of window with scrollbar(s) */,
729 WPARAM wParam /* [in] Variable input including enable state */,
730 LPARAM lParam /* [in] Variable input including input point */)
731 {
732 DPRINT("Wnd=%p wParam=%d lParam=%ld\n", Wnd, wParam, lParam);
733
734 /* hide caret on first KEYDOWN to prevent flicker */
735 if (0 == (lParam & PFD_DOUBLEBUFFER_DONTCARE))
736 {
737 HideCaret(Wnd);
738 }
739
740 switch(wParam)
741 {
742 case VK_PRIOR:
743 wParam = SB_PAGEUP;
744 break;
745
746 case VK_NEXT:
747 wParam = SB_PAGEDOWN;
748 break;
749
750 case VK_HOME:
751 wParam = SB_TOP;
752 break;
753
754 case VK_END:
755 wParam = SB_BOTTOM;
756 break;
757
758 case VK_UP:
759 wParam = SB_LINEUP;
760 break;
761
762 case VK_DOWN:
763 wParam = SB_LINEDOWN;
764 break;
765
766 default:
767 return;
768 }
769
770 SendMessageW(GetParent(Wnd),
771 (0 != (GetWindowLongW(Wnd, GWL_STYLE ) & SBS_VERT) ?
772 WM_VSCROLL : WM_HSCROLL), wParam, (LPARAM) Wnd);
773 }
774
775 /***********************************************************************
776 * IntScrollHandleScrollEvent
777 *
778 * Handle a mouse or timer event for the scrollbar.
779 * 'Pt' is the location of the mouse event in drawing coordinates
780 */
781 STATIC VOID FASTCALL
782 IntScrollHandleScrollEvent(HWND Wnd, INT SBType, UINT Msg, POINT Pt)
783 {
784 static POINT PrevPt; /* Previous mouse position for timer events */
785 static UINT TrackThumbPos; /* Thumb position when tracking started. */
786 static INT LastClickPos; /* Position in the scroll-bar of the last
787 button-down event. */
788 static INT LastMousePos; /* Position in the scroll-bar of the last
789 mouse event. */
790
791 DWORD HitTest;
792 HWND WndOwner, WndCtl;
793 BOOL Vertical;
794 HDC Dc;
795 SCROLLBARINFO ScrollBarInfo;
796 SETSCROLLBARINFO NewInfo;
797
798 if (! IntGetScrollBarInfo(Wnd, SBType, &ScrollBarInfo))
799 {
800 return;
801 }
802 if (SCROLL_NOWHERE == ScrollTrackHitTest && WM_LBUTTONDOWN != Msg)
803 {
804 return;
805 }
806
807 NewInfo.nTrackPos = ScrollTrackingVal;
808 NewInfo.reserved = ScrollBarInfo.reserved;
809 memcpy(NewInfo.rgstate, ScrollBarInfo.rgstate, (CCHILDREN_SCROLLBAR + 1) * sizeof(DWORD));
810
811 if (SB_CTL == SBType
812 && 0 != (GetWindowLongW(Wnd, GWL_STYLE) & (SBS_SIZEGRIP | SBS_SIZEBOX)))
813 {
814 switch(Msg)
815 {
816 case WM_LBUTTONDOWN: /* Initialise mouse tracking */
817 HideCaret(Wnd); /* hide caret while holding down LBUTTON */
818 SetCapture(Wnd);
819 PrevPt = Pt;
820 ScrollTrackHitTest = HitTest = SCROLL_THUMB;
821 break;
822 case WM_MOUSEMOVE:
823 GetClientRect(GetParent(GetParent(Wnd)), &ScrollBarInfo.rcScrollBar);
824 PrevPt = Pt;
825 break;
826 case WM_LBUTTONUP:
827 ReleaseCapture();
828 ScrollTrackHitTest = HitTest = SCROLL_NOWHERE;
829 if (Wnd == GetFocus())
830 {
831 ShowCaret(Wnd);
832 }
833 break;
834 case WM_SYSTIMER:
835 Pt = PrevPt;
836 break;
837 }
838 return;
839 }
840
841 Dc = GetDCEx(Wnd, 0, DCX_CACHE | ((SB_CTL == SBType) ? 0 : DCX_WINDOW));
842 if (SB_VERT == SBType)
843 {
844 Vertical = TRUE;
845 }
846 else if (SB_HORZ == SBType)
847 {
848 Vertical = FALSE;
849 }
850 else
851 {
852 Vertical = (0 != (GetWindowLongW(Wnd, GWL_STYLE) & SBS_VERT));
853 }
854 WndOwner = (SB_CTL == SBType) ? GetParent(Wnd) : Wnd;
855 WndCtl = (SB_CTL == SBType) ? Wnd : NULL;
856
857 switch (Msg)
858 {
859 case WM_LBUTTONDOWN: /* Initialise mouse tracking */
860 HideCaret(Wnd); /* hide caret while holding down LBUTTON */
861 ScrollTrackVertical = Vertical;
862 ScrollTrackHitTest = HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, FALSE );
863 LastClickPos = Vertical ? (Pt.y - ScrollBarInfo.rcScrollBar.top)
864 : (Pt.x - ScrollBarInfo.rcScrollBar.left);
865 LastMousePos = LastClickPos;
866 TrackThumbPos = ScrollBarInfo.xyThumbTop;
867 PrevPt = Pt;
868 if (SB_CTL == SBType && 0 != (GetWindowLongW(Wnd, GWL_STYLE) & WS_TABSTOP))
869 {
870 SetFocus(Wnd);
871 }
872 SetCapture(Wnd);
873 ScrollBarInfo.rgstate[ScrollTrackHitTest] |= STATE_SYSTEM_PRESSED;
874 NewInfo.rgstate[ScrollTrackHitTest] = ScrollBarInfo.rgstate[ScrollTrackHitTest];
875 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
876 break;
877
878 case WM_MOUSEMOVE:
879 HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, TRUE);
880 PrevPt = Pt;
881 break;
882
883 case WM_LBUTTONUP:
884 HitTest = SCROLL_NOWHERE;
885 ReleaseCapture();
886 /* if scrollbar has focus, show back caret */
887 if (Wnd == GetFocus())
888 {
889 ShowCaret(Wnd);
890 }
891 ScrollBarInfo.rgstate[ScrollTrackHitTest] &= ~STATE_SYSTEM_PRESSED;
892 NewInfo.rgstate[ScrollTrackHitTest] = ScrollBarInfo.rgstate[ScrollTrackHitTest];
893 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
894 break;
895
896 case WM_SYSTIMER:
897 Pt = PrevPt;
898 HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, FALSE);
899 break;
900
901 default:
902 return; /* Should never happen */
903 }
904
905 switch (ScrollTrackHitTest)
906 {
907 case SCROLL_NOWHERE: /* No tracking in progress */
908 break;
909
910 case SCROLL_TOP_ARROW:
911 if (HitTest == ScrollTrackHitTest)
912 {
913 if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
914 {
915 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
916 SB_LINEUP, (LPARAM) WndCtl);
917 }
918 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
919 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
920 (TIMERPROC) NULL);
921 }
922 else
923 {
924 KillSystemTimer(Wnd, SCROLL_TIMER);
925 }
926 break;
927
928 case SCROLL_TOP_RECT:
929 if (HitTest == ScrollTrackHitTest)
930 {
931 if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
932 {
933 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
934 SB_PAGEUP, (LPARAM) WndCtl);
935 }
936 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
937 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
938 (TIMERPROC) NULL);
939 }
940 else
941 {
942 KillSystemTimer(Wnd, SCROLL_TIMER);
943 }
944 break;
945
946 case SCROLL_THUMB:
947 if (WM_LBUTTONDOWN == Msg)
948 {
949 ScrollTrackingWin = Wnd;
950 ScrollTrackingBar = SBType;
951 ScrollTrackingPos = TrackThumbPos + LastMousePos - LastClickPos;
952 ScrollTrackingVal = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo,
953 Vertical, ScrollTrackingPos);
954 NewInfo.nTrackPos = ScrollTrackingVal;
955 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
956 IntScrollDrawMovingThumb(Dc, &ScrollBarInfo, Vertical);
957 }
958 else if (WM_LBUTTONUP == Msg)
959 {
960 ScrollTrackingWin = 0;
961 ScrollTrackingVal = 0;
962 IntDrawScrollInterior(Wnd, Dc, SBType, Vertical, &ScrollBarInfo);
963 }
964 else /* WM_MOUSEMOVE */
965 {
966 UINT Pos;
967
968 if (! IntScrollPtInRectEx(&ScrollBarInfo.rcScrollBar, Pt, Vertical))
969 {
970 Pos = LastClickPos;
971 }
972 else
973 {
974 Pt = IntScrollClipPos(&ScrollBarInfo.rcScrollBar, Pt);
975 Pos = Vertical ? (Pt.y - ScrollBarInfo.rcScrollBar.top)
976 : (Pt.x - ScrollBarInfo.rcScrollBar.left);
977 }
978 if (Pos != LastMousePos || ! ScrollMovingThumb)
979 {
980 LastMousePos = Pos;
981 ScrollTrackingPos = TrackThumbPos + Pos - LastClickPos;
982 ScrollTrackingVal = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo,
983 Vertical, ScrollTrackingPos);
984 NewInfo.nTrackPos = ScrollTrackingVal;
985 NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
986 IntScrollDrawMovingThumb(Dc, &ScrollBarInfo, Vertical);
987 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
988 MAKEWPARAM(SB_THUMBTRACK, ScrollTrackingVal),
989 (LPARAM) WndCtl);
990 }
991 }
992 break;
993
994 case SCROLL_BOTTOM_RECT:
995 if (HitTest == ScrollTrackHitTest)
996 {
997 if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
998 {
999 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
1000 SB_PAGEDOWN, (LPARAM) WndCtl);
1001 }
1002 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
1003 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
1004 (TIMERPROC) NULL);
1005 }
1006 else
1007 {
1008 KillSystemTimer(Wnd, SCROLL_TIMER);
1009 }
1010 break;
1011
1012 case SCROLL_BOTTOM_ARROW:
1013 if (HitTest == ScrollTrackHitTest)
1014 {
1015 if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
1016 {
1017 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
1018 SB_LINEDOWN, (LPARAM) WndCtl);
1019 }
1020 SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
1021 SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
1022 (TIMERPROC) NULL);
1023 }
1024 else
1025 {
1026 KillSystemTimer(Wnd, SCROLL_TIMER);
1027 }
1028 break;
1029 }
1030
1031 if (WM_LBUTTONDOWN == Msg)
1032 {
1033 if (SCROLL_THUMB == HitTest)
1034 {
1035 UINT Val = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, Vertical,
1036 TrackThumbPos + LastMousePos - LastClickPos);
1037 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
1038 MAKEWPARAM(SB_THUMBTRACK, Val), (LPARAM) WndCtl);
1039 }
1040 }
1041
1042 if (WM_LBUTTONUP == Msg)
1043 {
1044 HitTest = ScrollTrackHitTest;
1045 ScrollTrackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
1046
1047 if (SCROLL_THUMB == HitTest)
1048 {
1049 UINT Val = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, Vertical,
1050 TrackThumbPos + LastMousePos - LastClickPos);
1051 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
1052 MAKEWPARAM(SB_THUMBPOSITION, Val), (LPARAM) WndCtl);
1053 }
1054 SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
1055 SB_ENDSCROLL, (LPARAM) WndCtl);
1056 }
1057
1058 ReleaseDC(Wnd, Dc);
1059 }
1060
1061
1062 /***********************************************************************
1063 * IntScrollCreateScrollBar
1064 *
1065 * Create a scroll bar
1066 */
1067 static void IntScrollCreateScrollBar(
1068 HWND Wnd /* [in] Handle of window with scrollbar(s) */,
1069 LPCREATESTRUCTW lpCreate /* [in] The style and place of the scroll bar */)
1070 {
1071 SCROLLINFO Info;
1072
1073 Info.cbSize = sizeof(SCROLLINFO);
1074 Info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
1075 Info.nMin = 0;
1076 Info.nMax = 100;
1077 Info.nPage = 0;
1078 Info.nPos = 0;
1079 Info.nTrackPos = 0;
1080 NtUserSetScrollInfo(Wnd, SB_CTL, &Info, FALSE);
1081
1082 DPRINT("hwnd=%p lpCreate=%p\n", Wnd, lpCreate);
1083
1084 #if 0 /* FIXME */
1085 if (lpCreate->style & WS_DISABLED)
1086 {
1087 info->flags = ESB_DISABLE_BOTH;
1088 TRACE("Created WS_DISABLED scrollbar\n");
1089 }
1090 #endif
1091
1092 if (0 != (lpCreate->style & (SBS_SIZEGRIP | SBS_SIZEBOX)))
1093 {
1094 if (0 != (lpCreate->style & SBS_SIZEBOXTOPLEFTALIGN))
1095 {
1096 MoveWindow(Wnd, lpCreate->x, lpCreate->y, GetSystemMetrics(SM_CXVSCROLL) + 1,
1097 GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE);
1098 }
1099 else if (0 != (lpCreate->style & SBS_SIZEBOXBOTTOMRIGHTALIGN))
1100 {
1101 MoveWindow(Wnd, lpCreate->x + lpCreate->cx - GetSystemMetrics(SM_CXVSCROLL) - 1,
1102 lpCreate->y + lpCreate->cy - GetSystemMetrics(SM_CYHSCROLL) - 1,
1103 GetSystemMetrics(SM_CXVSCROLL) + 1,
1104 GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE);
1105 }
1106 }
1107 else if (0 != (lpCreate->style & SBS_VERT))
1108 {
1109 if (0 != (lpCreate->style & SBS_LEFTALIGN))
1110 {
1111 MoveWindow(Wnd, lpCreate->x, lpCreate->y,
1112 GetSystemMetrics(SM_CXVSCROLL) + 1, lpCreate->cy, FALSE);
1113 }
1114 else if (0 != (lpCreate->style & SBS_RIGHTALIGN))
1115 {
1116 MoveWindow(Wnd,
1117 lpCreate->x + lpCreate->cx - GetSystemMetrics(SM_CXVSCROLL) - 1,
1118 lpCreate->y,
1119 GetSystemMetrics(SM_CXVSCROLL) + 1, lpCreate->cy, FALSE);
1120 }
1121 }
1122 else /* SBS_HORZ */
1123 {
1124 if (0 != (lpCreate->style & SBS_TOPALIGN))
1125 {
1126 MoveWindow(Wnd, lpCreate->x, lpCreate->y,
1127 lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE);
1128 }
1129 else if (0 != (lpCreate->style & SBS_BOTTOMALIGN))
1130 {
1131 MoveWindow(Wnd,
1132 lpCreate->x,
1133 lpCreate->y + lpCreate->cy - GetSystemMetrics(SM_CYHSCROLL) - 1,
1134 lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL) + 1, FALSE);
1135 }
1136 }
1137 }
1138
1139 STATIC INT FASTCALL
1140 IntScrollGetScrollPos(HWND Wnd, INT Bar)
1141 {
1142 SCROLLINFO ScrollInfo;
1143
1144 ScrollInfo.cbSize = sizeof(SCROLLINFO);
1145 ScrollInfo.fMask = SIF_POS;
1146 if (! NtUserGetScrollInfo(Wnd, Bar, &ScrollInfo))
1147 {
1148 return 0;
1149 }
1150
1151 return ScrollInfo.nPos;
1152 }
1153
1154 STATIC BOOL FASTCALL
1155 IntScrollGetScrollRange(HWND Wnd, int Bar, LPINT MinPos, LPINT MaxPos)
1156 {
1157 BOOL Result;
1158 SCROLLINFO ScrollInfo;
1159
1160 if (NULL == MinPos || NULL == MaxPos)
1161 {
1162 SetLastError(ERROR_INVALID_PARAMETER);
1163 return FALSE;
1164 }
1165
1166 ScrollInfo.cbSize = sizeof(SCROLLINFO);
1167 ScrollInfo.fMask = SIF_RANGE;
1168 Result = NtUserGetScrollInfo(Wnd, Bar, &ScrollInfo);
1169 if (Result)
1170 {
1171 *MinPos = ScrollInfo.nMin;
1172 *MaxPos = ScrollInfo.nMax;
1173 }
1174
1175 return Result;
1176 }
1177
1178 /* USER32 INTERNAL FUNCTIONS **************************************************/
1179
1180 /***********************************************************************
1181 * ScrollTrackScrollBar
1182 *
1183 * Track a mouse button press on a scroll-bar.
1184 * pt is in screen-coordinates for non-client scroll bars.
1185 */
1186 VOID FASTCALL
1187 ScrollTrackScrollBar(HWND Wnd, INT SBType, POINT Pt)
1188 {
1189 MSG Msg;
1190 RECT WindowRect;
1191 UINT XOffset, YOffset;
1192 POINT TopLeft;
1193
1194 if (SB_CTL != SBType)
1195 {
1196 NtUserGetWindowRect(Wnd, &WindowRect);
1197
1198 Pt.x -= WindowRect.left;
1199 Pt.y -= WindowRect.top;
1200
1201 TopLeft.x = WindowRect.left;
1202 TopLeft.y = WindowRect.top;
1203 ScreenToClient(Wnd, &TopLeft);
1204 XOffset = - TopLeft.x;
1205 YOffset = - TopLeft.y;
1206 }
1207 else
1208 {
1209 XOffset = 0;
1210 YOffset = 0;
1211 }
1212
1213 IntScrollHandleScrollEvent(Wnd, SBType, WM_LBUTTONDOWN, Pt);
1214
1215 do
1216 {
1217 if (! GetMessageW(&Msg, 0, 0, 0))
1218 {
1219 break;
1220 }
1221 if (CallMsgFilterW(&Msg, MSGF_SCROLLBAR))
1222 {
1223 continue;
1224 }
1225
1226 switch(Msg.message)
1227 {
1228 case WM_SYSTIMER:
1229 case WM_LBUTTONUP:
1230 case WM_MOUSEMOVE:
1231 Pt.x = LOWORD(Msg.lParam) + XOffset;
1232 Pt.y = HIWORD(Msg.lParam) + YOffset;
1233 IntScrollHandleScrollEvent(Wnd, SBType, Msg.message, Pt);
1234 break;
1235 default:
1236 TranslateMessage(&Msg);
1237 DispatchMessageW(&Msg);
1238 break;
1239 }
1240
1241 if (! IsWindow(Wnd))
1242 {
1243 ReleaseCapture();
1244 break;
1245 }
1246 }
1247 while (WM_LBUTTONUP != Msg.message);
1248 }
1249
1250
1251 /***********************************************************************
1252 * ScrollBarWndProc
1253 */
1254 static LRESULT WINAPI
1255 ScrollBarWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
1256 {
1257 if (! IsWindow(Wnd))
1258 {
1259 return 0;
1260 }
1261
1262 switch (Msg)
1263 {
1264 case WM_CREATE:
1265 IntScrollCreateScrollBar(Wnd, (LPCREATESTRUCTW) lParam);
1266 break;
1267
1268 //#if 0 /* FIXME */
1269 case WM_ENABLE:
1270 {
1271 // SCROLLBAR_INFO *infoPtr;
1272 // if ((infoPtr = SCROLL_GetScrollBarInfo( hwnd, SB_CTL )))
1273 // {
1274 // infoPtr->flags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
1275 // SCROLL_RefreshScrollBar(hwnd, SB_CTL, TRUE, TRUE);
1276 // }
1277 HDC hdc;
1278 DbgPrint("ScrollBarWndProc WM_ENABLE\n");
1279 NtUserEnableScrollBar(Wnd,SB_CTL,(wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH));
1280 /* Refresh Scrollbars. */
1281 hdc = GetDCEx( Wnd, 0, DCX_CACHE );
1282 if (!hdc) return 1;
1283 IntDrawScrollBar( Wnd, hdc, SB_CTL);
1284 ReleaseDC( Wnd, hdc );
1285 }
1286 return 0;
1287 //#endif
1288
1289 case WM_LBUTTONDBLCLK:
1290 case WM_LBUTTONDOWN:
1291 {
1292 POINT Pt;
1293
1294 Pt.x = (short)LOWORD(lParam);
1295 Pt.y = (short)HIWORD(lParam);
1296 ScrollTrackScrollBar(Wnd, SB_CTL, Pt);
1297 }
1298 break;
1299
1300 case WM_LBUTTONUP:
1301 case WM_MOUSEMOVE:
1302 case WM_SYSTIMER:
1303 {
1304 POINT Pt;
1305
1306 Pt.x = (short)LOWORD(lParam);
1307 Pt.y = (short)HIWORD(lParam);
1308 IntScrollHandleScrollEvent(Wnd, SB_CTL, Msg, Pt);
1309 }
1310 break;
1311
1312 case WM_KEYDOWN:
1313 IntScrollHandleKbdEvent(Wnd, wParam, lParam);
1314 break;
1315
1316 case WM_KEYUP:
1317 ShowCaret(Wnd);
1318 break;
1319
1320 case WM_SETFOCUS:
1321 {
1322 /* Create a caret when a ScrollBar get focus */
1323 RECT Rect;
1324 int ArrowSize, ThumbSize, ThumbPos, Vertical;
1325
1326 Vertical = IntScrollGetScrollBarRect(Wnd, SB_CTL, &Rect,
1327 &ArrowSize, &ThumbSize, &ThumbPos);
1328 if (! Vertical)
1329 {
1330 CreateCaret(Wnd, (HBITMAP) 1, ThumbSize - 2, Rect.bottom - Rect.top - 2);
1331 SetCaretPos(ThumbPos + 1, Rect.top + 1);
1332 }
1333 else
1334 {
1335 CreateCaret(Wnd, (HBITMAP) 1, Rect.right - Rect.left - 2, ThumbSize - 2);
1336 SetCaretPos(Rect.top + 1, ThumbPos + 1);
1337 }
1338 ShowCaret(Wnd);
1339 }
1340 break;
1341
1342 case WM_KILLFOCUS:
1343 {
1344 RECT Rect;
1345 int ArrowSize, ThumbSize, ThumbPos, Vertical;
1346
1347 Vertical = IntScrollGetScrollBarRect(Wnd, SB_CTL, &Rect,
1348 &ArrowSize, &ThumbSize, &ThumbPos);
1349 if (! Vertical)
1350 {
1351 Rect.left = ThumbPos + 1;
1352 Rect.right = Rect.left + ThumbSize;
1353 }
1354 else
1355 {
1356 Rect.top = ThumbPos + 1;
1357 Rect.bottom = Rect.top + ThumbSize;
1358 }
1359 HideCaret(Wnd);
1360 InvalidateRect(Wnd, &Rect, FALSE);
1361 DestroyCaret();
1362 }
1363 break;
1364
1365 case WM_ERASEBKGND:
1366 return 1;
1367
1368 case WM_GETDLGCODE:
1369 return DLGC_WANTARROWS; /* Windows returns this value */
1370
1371 case WM_PAINT:
1372 {
1373 PAINTSTRUCT Ps;
1374 HDC Dc;
1375
1376 Dc = (0 != wParam ? (HDC) wParam : BeginPaint(Wnd, &Ps));
1377
1378 if (GetWindowLongW(Wnd, GWL_STYLE) & SBS_SIZEGRIP)
1379 {
1380 IntScrollDrawSizeGrip(Wnd, Dc);
1381 }
1382 else if (0 != (GetWindowLongW(Wnd, GWL_STYLE) & SBS_SIZEBOX))
1383 {
1384 RECT Rect;
1385 GetClientRect(Wnd, &Rect);
1386 FillRect(Dc, &Rect, GetSysColorBrush(COLOR_SCROLLBAR));
1387 }
1388 else
1389 {
1390 IntDrawScrollBar(Wnd, Dc, SB_CTL/*, TRUE, TRUE*/);
1391 }
1392
1393 if (0 == wParam)
1394 {
1395 EndPaint(Wnd, &Ps);
1396 }
1397 }
1398 break;
1399
1400 case SBM_SETPOS:
1401 return SetScrollPos(Wnd, SB_CTL, wParam, (BOOL) lParam);
1402
1403 case SBM_GETPOS:
1404 return IntScrollGetScrollPos(Wnd, SB_CTL);
1405
1406 case SBM_SETRANGE:
1407 {
1408 INT OldPos = IntScrollGetScrollPos(Wnd, SB_CTL);
1409 SetScrollRange(Wnd, SB_CTL, wParam, lParam, FALSE);
1410 if (OldPos != IntScrollGetScrollPos(Wnd, SB_CTL))
1411 {
1412 return OldPos;
1413 }
1414 }
1415 return 0;
1416
1417 case SBM_GETRANGE:
1418 return IntScrollGetScrollRange(Wnd, SB_CTL, (LPINT) wParam, (LPINT) lParam);
1419
1420 case SBM_ENABLE_ARROWS:
1421 return EnableScrollBar(Wnd, SB_CTL, wParam);
1422
1423 case SBM_SETRANGEREDRAW:
1424 {
1425 INT OldPos = IntScrollGetScrollPos(Wnd, SB_CTL);
1426 SetScrollRange(Wnd, SB_CTL, wParam, lParam, TRUE);
1427 if (OldPos != IntScrollGetScrollPos(Wnd, SB_CTL))
1428 {
1429 return OldPos;
1430 }
1431 }
1432 return 0;
1433
1434 case SBM_SETSCROLLINFO:
1435 return NtUserSetScrollInfo(Wnd, SB_CTL, (SCROLLINFO *) lParam, wParam);
1436
1437 case SBM_GETSCROLLINFO:
1438 return NtUserGetScrollInfo(Wnd, SB_CTL, (SCROLLINFO *) lParam);
1439
1440 case 0x00e5:
1441 case 0x00e7:
1442 case 0x00e8:
1443 case 0x00eb:
1444 case 0x00ec:
1445 case 0x00ed:
1446 case 0x00ee:
1447 case 0x00ef:
1448 DPRINT("unknown Win32 msg %04x wp=%08x lp=%08lx\n",
1449 Msg, wParam, lParam );
1450 break;
1451
1452 default:
1453 if (WM_USER <= Msg)
1454 {
1455 DPRINT("unknown msg %04x wp=%04x lp=%08lx\n", Msg, wParam, lParam);
1456 }
1457 return DefWindowProcW(Wnd, Msg, wParam, lParam );
1458 }
1459
1460 return 0;
1461 }
1462
1463
1464 /* PUBLIC FUNCTIONS ***********************************************************/
1465
1466 /*
1467 * @implemented
1468 */
1469 BOOL STDCALL
1470 EnableScrollBar(HWND hWnd, UINT wSBflags, UINT wArrows)
1471 {
1472 return NtUserEnableScrollBar(hWnd, wSBflags, wArrows);
1473 }
1474
1475 /*
1476 * @implemented
1477 */
1478 BOOL STDCALL
1479 GetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
1480 {
1481 return NtUserGetScrollBarInfo(hWnd, idObject, psbi);
1482 }
1483
1484 /*
1485 * @implemented
1486 */
1487 BOOL STDCALL
1488 GetScrollInfo(HWND Wnd, INT SBType, LPSCROLLINFO Info)
1489 {
1490 if (SB_CTL == SBType)
1491 {
1492 return SendMessageW(Wnd, SBM_GETSCROLLINFO, 0, (LPARAM) Info);
1493 }
1494 else
1495 {
1496 return NtUserGetScrollInfo(Wnd, SBType, Info);
1497 }
1498 }
1499
1500 /*
1501 * @implemented
1502 */
1503 INT STDCALL
1504 GetScrollPos(HWND Wnd, INT Bar)
1505 {
1506 DPRINT("Wnd=%p Bar=%d\n", Wnd, Bar);
1507
1508 /* Refer SB_CTL requests to the window */
1509 if (SB_CTL == Bar)
1510 {
1511 return SendMessageW(Wnd, SBM_GETPOS, (WPARAM) 0, (LPARAM) 0);
1512 }
1513 else
1514 {
1515 return IntScrollGetScrollPos(Wnd, Bar);
1516 }
1517 }
1518
1519 /*
1520 * @implemented
1521 */
1522 BOOL STDCALL
1523 GetScrollRange(HWND Wnd, int Bar, LPINT MinPos, LPINT MaxPos)
1524 {
1525 DPRINT("Wnd=%x Bar=%d Min=%p Max=%p\n", Wnd, Bar, MinPos, MaxPos);
1526
1527 /* Refer SB_CTL requests to the window */
1528 if (SB_CTL == Bar)
1529 {
1530 return SendMessageW(Wnd, SBM_GETRANGE, (WPARAM) MinPos, (LPARAM) MaxPos);
1531 }
1532 else
1533 {
1534 return IntScrollGetScrollRange(Wnd, Bar, MinPos, MaxPos);
1535 }
1536 }
1537
1538 /*
1539 * @implemented
1540 */
1541 INT STDCALL
1542 SetScrollInfo(HWND Wnd, int SBType, LPCSCROLLINFO Info, BOOL bRedraw)
1543 {
1544 if (SB_CTL == SBType)
1545 {
1546 return SendMessageW(Wnd, SBM_SETSCROLLINFO, (WPARAM) bRedraw, (LPARAM) Info);
1547 }
1548 else
1549 {
1550 return NtUserSetScrollInfo(Wnd, SBType, Info, bRedraw);
1551 }
1552 }
1553
1554 /*
1555 * @implemented
1556 */
1557 INT STDCALL
1558 SetScrollPos(HWND hWnd, INT nBar, INT nPos, BOOL bRedraw)
1559 {
1560 INT Result = 0;
1561 SCROLLINFO ScrollInfo;
1562
1563 ScrollInfo.cbSize = sizeof(SCROLLINFO);
1564 ScrollInfo.fMask = SIF_POS;
1565
1566 /*
1567 * Call NtUserGetScrollInfo() to get the previous position that
1568 * we will later return.
1569 */
1570 if (NtUserGetScrollInfo(hWnd, nBar, &ScrollInfo))
1571 {
1572 Result = ScrollInfo.nPos;
1573 if (Result != nPos)
1574 {
1575 ScrollInfo.nPos = nPos;
1576 /* Finally set the new position */
1577 NtUserSetScrollInfo(hWnd, nBar, &ScrollInfo, bRedraw);
1578 }
1579 }
1580
1581 return Result;
1582 }
1583
1584 /*
1585 * @implemented
1586 */
1587 BOOL STDCALL
1588 SetScrollRange(HWND hWnd, INT nBar, INT nMinPos, INT nMaxPos, BOOL bRedraw)
1589 {
1590 SCROLLINFO ScrollInfo;
1591
1592 ScrollInfo.cbSize = sizeof(SCROLLINFO);
1593 ScrollInfo.fMask = SIF_RANGE;
1594 ScrollInfo.nMin = nMinPos;
1595 ScrollInfo.nMax = nMaxPos;
1596 NtUserSetScrollInfo(hWnd, nBar, &ScrollInfo, bRedraw);
1597
1598 return TRUE;
1599 }
1600
1601 /*
1602 * @implemented
1603 */
1604 BOOL STDCALL
1605 ShowScrollBar(HWND hWnd, INT wBar, BOOL bShow)
1606 {
1607 return NtUserShowScrollBar(hWnd, wBar, bShow);
1608 }