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