2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/scrollbar.c
25 * PROGRAMER: Jason Filby (jasonfilby@yahoo.com)
27 * 16-11-2002 Jason Filby Created
29 /* INCLUDES ******************************************************************/
31 #include <ddk/ntddk.h>
32 #include <win32k/win32k.h>
33 #include <include/object.h>
34 #include <include/window.h>
35 #include <include/class.h>
36 #include <include/error.h>
37 #include <include/winsta.h>
38 #include <include/winpos.h>
39 #include <include/rect.h>
40 #include <include/scroll.h>
45 #define SCROLL_MIN_RECT 4 /* Minimum size of the rectangle between the arrows */
46 #define SCROLL_ARROW_THUMB_OVERLAP 0 /* Overlap between arrows and thumb */
48 #define SBRG_SCROLLBAR 0 /* the scrollbar itself */
49 #define SBRG_TOPRIGHTBTN 1 /* the top or right button */
50 #define SBRG_PAGEUPRIGHT 2 /* the page up or page right region */
51 #define SBRG_SCROLLBOX 3 /* the scroll box */
52 #define SBRG_PAGEDOWNLEFT 4 /* the page down or page left region */
53 #define SBRG_BOTTOMLEFTBTN 5 /* the bottom or left button */
55 /***********************************************************************
56 * MulDiv (copied from kernel32)
63 #if SIZEOF_LONG_LONG >= 8
66 if (!nDivisor) return -1;
68 /* We want to deal with a positive divisor to simplify the logic. */
71 nMultiplicand = - nMultiplicand;
75 /* If the result is positive, we "add" to round. else, we subtract to round. */
76 if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) ||
77 ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
78 ret = (((long long)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
80 ret = (((long long)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
82 if ((ret > 2147483647) || (ret < -2147483647)) return -1;
85 if (!nDivisor) return -1;
87 /* We want to deal with a positive divisor to simplify the logic. */
90 nMultiplicand = - nMultiplicand;
94 /* If the result is positive, we "add" to round. else, we subtract to round. */
95 if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) ||
96 ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
97 return ((nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
99 return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
105 /* FUNCTIONS *****************************************************************/
107 /* Ported from WINE20020904 */
108 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
109 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
110 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
111 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
114 IntGetScrollBarRect (PWINDOW_OBJECT Window, INT nBar, PRECT lprect)
117 RECT ClientRect = Window->ClientRect;
118 RECT WindowRect = Window->WindowRect;
123 lprect->left = ClientRect.left - WindowRect.left + 1;
124 lprect->top = ClientRect.bottom - WindowRect.top;
125 lprect->right = ClientRect.right - WindowRect.left - 1;
126 lprect->bottom = lprect->top + NtUserGetSystemMetrics (SM_CYHSCROLL);
127 if (Window->Style & WS_BORDER)
136 lprect->left = (ClientRect.right - WindowRect.left);
137 lprect->top = (ClientRect.top - WindowRect.top) + 1;
138 lprect->right = (lprect->left + NtUserGetSystemMetrics (SM_CXVSCROLL));
139 lprect->bottom = (ClientRect.bottom - WindowRect.top) - 1;
140 if (Window->Style & WS_BORDER)
145 else if (Window->Style & WS_HSCROLL)
151 IntGetClientRect (Window, lprect);
152 vertical = ((Window->Style & SBS_VERT) != 0);
156 IntReleaseWindowObject(Window);
163 #define MINTRACKTHUMB (8)
165 IntCalculateThumb(PWINDOW_OBJECT Window, LONG idObject, PSCROLLBARINFO psbi, LPSCROLLINFO psi)
167 INT Thumb, ThumbBox, ThumbPos, cxy, mx;
171 Thumb = NtUserGetSystemMetrics(SM_CXHSCROLL);
172 cxy = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
175 Thumb = NtUserGetSystemMetrics(SM_CYVSCROLL);
176 cxy = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
186 /* calculate Thumb */
187 if(cxy <= (2 * Thumb))
190 psbi->xyThumbTop = 0;
191 psbi->xyThumbBottom = 0;
196 ThumbBox = psi->nPage ? MINTRACKTHUMB : NtUserGetSystemMetrics(SM_CXHTHUMB);
202 ThumbBox = max(IntMulDiv(cxy, psi->nPage, psi->nMax - psi->nMin + 1), ThumbBox);
207 mx = psi->nMax - max(psi->nPage - 1, 0);
209 ThumbPos = Thumb + IntMulDiv(cxy, psi->nPos - psi->nMin, psi->nMax - psi->nMin + 1);
212 psbi->xyThumbTop = ThumbPos;
213 psbi->xyThumbBottom = ThumbPos + ThumbBox;
217 psbi->xyThumbTop = 0;
218 psbi->xyThumbBottom = 0;
221 psbi->dxyLineButton = Thumb;
227 IntCreateScrollBar(PWINDOW_OBJECT Window, LONG idObject)
234 psbi = ExAllocatePool(PagedPool, sizeof(SCROLLBARINFO) + sizeof(SCROLLINFO));
238 psi = (LPSCROLLINFO)((PSCROLLBARINFO)(psbi + 1));
240 psi->cbSize = sizeof(LPSCROLLINFO);
247 Result = WinPosGetNonClientSize(Window->Self,
249 &Window->ClientRect);
251 psbi->cbSize = sizeof(SCROLLBARINFO);
253 for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
254 psbi->rgstate[i] = 0;
259 //psbi->dxyLineButton = NtUserGetSystemMetrics(SM_CXHSCROLL);
260 Window->pHScroll = psbi;
263 //psbi->dxyLineButton = NtUserGetSystemMetrics(SM_CYVSCROLL);
264 Window->pVScroll = psbi;
267 /* FIXME - set psbi->dxyLineButton */
268 Window->wExtra = psbi;
275 IntGetScrollBarRect(Window, idObject, &(psbi->rcScrollBar));
276 IntCalculateThumb(Window, idObject, psbi, psi);
282 IntDestroyScrollBar(PWINDOW_OBJECT Window, LONG idObject)
289 ExFreePool(Window->pHScroll);
290 Window->pHScroll = NULL;
297 ExFreePool(Window->pVScroll);
298 Window->pVScroll = NULL;
305 ExFreePool(Window->wExtra);
306 Window->wExtra = NULL;
314 #define CHANGERGSTATE(item, status) \
315 if(Info->rgstate[(item)] != (status)) \
317 Info->rgstate[(item)] = (status);
321 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows)
326 case ESB_DISABLE_BOTH:
327 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
328 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
330 case ESB_DISABLE_RTDN:
333 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
337 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
340 case ESB_DISABLE_LTUP:
343 CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
347 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
350 case ESB_ENABLE_BOTH:
351 CHANGERGSTATE(SBRG_TOPRIGHTBTN, 0);
352 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, 0);
361 NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
363 PWINDOW_OBJECT Window;
368 if(!psbi || (psbi->cbSize != sizeof(SCROLLBARINFO)))
370 SetLastWin32Error(ERROR_INVALID_PARAMETER);
374 Window = IntGetWindowObject(hWnd);
378 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
388 sbi = Window->pHScroll;
396 sbi = Window->pVScroll;
404 sbi = Window->wExtra;
409 IntReleaseWindowObject(Window);
410 SetLastWin32Error(ERROR_INVALID_PARAMETER);
414 psi = (LPSCROLLINFO)((PSCROLLBARINFO)(sbi + 1));
416 IntGetScrollBarRect(Window, Bar, &(sbi->rcScrollBar));
417 IntCalculateThumb(Window, Bar, sbi, psi);
419 memcpy(psbi, sbi, sizeof(SCROLLBARINFO));
421 IntReleaseWindowObject(Window);
428 NtUserGetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
430 PWINDOW_OBJECT Window;
433 PSCROLLBARINFO Info = NULL;
435 if(!lpsi || ((lpsi->cbSize != sizeof(SCROLLINFO)) &&
436 (lpsi->cbSize != sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos))))
438 SetLastWin32Error(ERROR_INVALID_PARAMETER);
442 Window = IntGetWindowObject(hwnd);
446 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
453 Info = Window->pHScroll;
458 Info = Window->pVScroll;
463 Info = Window->wExtra;
468 IntReleaseWindowObject(Window);
472 psi = (LPSCROLLINFO)((PSCROLLBARINFO)(Info + 1));
474 if(lpsi->fMask == SIF_ALL)
475 Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
481 lpsi->nPage = psi->nPage;
486 lpsi->nPos = psi->nPos;
491 lpsi->nMin = psi->nMin;
492 lpsi->nMax = psi->nMax;
495 IntReleaseWindowObject(Window);
502 NtUserEnableScrollBar(
507 PWINDOW_OBJECT Window;
508 PSCROLLBARINFO InfoV = NULL, InfoH = NULL;
511 Window = IntGetWindowObject(hWnd);
515 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
522 InfoV = Window->pVScroll;
525 InfoH = Window->pHScroll;
528 InfoV = Window->pVScroll;
531 InfoV = Window->wExtra;
534 IntReleaseWindowObject(Window);
539 Chg = IntEnableScrollBar(FALSE, InfoV, wArrows);
542 Chg = (IntEnableScrollBar(TRUE, InfoH, wArrows) || Chg);
544 //if(Chg && (Window->Style & WS_VISIBLE))
545 /* FIXME - repaint scrollbars */
547 IntReleaseWindowObject(Window);
557 CONST RECT *lprcScroll,
558 CONST RECT *lprcClip ,
576 PWINDOW_OBJECT Window;
577 PSCROLLBARINFO Info = NULL;
583 if(!lpsi || ((lpsi->cbSize != sizeof(SCROLLINFO)) &&
584 (lpsi->cbSize != sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos))))
586 SetLastWin32Error(ERROR_INVALID_PARAMETER);
590 Window = IntGetWindowObject(hwnd);
594 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
601 Info = Window->pHScroll;
606 Info = Window->pVScroll;
611 Info = Window->wExtra;
616 IntReleaseWindowObject(Window);
620 psi = (LPSCROLLINFO)((PSCROLLBARINFO)(Info + 1));
622 if(lpsi->fMask == SIF_ALL)
623 Mask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
627 if(Mask & SIF_DISABLENOSCROLL)
632 if((Mask & SIF_RANGE) && ((psi->nMin != lpsi->nMin) || (psi->nMax != lpsi->nMax)))
634 /* Invalid range -> range is set to (0,0) */
635 if((lpsi->nMin > lpsi->nMax) ||
636 ((UINT)(lpsi->nMax - lpsi->nMin) >= 0x80000000))
644 if(psi->nMin != lpsi->nMin ||
645 psi->nMax != lpsi->nMax )
647 //*action |= SA_SSI_REFRESH;
648 psi->nMin = lpsi->nMin;
649 psi->nMax = lpsi->nMax;
655 if((Mask & SIF_PAGE) && (psi->nPage != lpsi->nPage))
657 psi->nPage = lpsi->nPage;
659 if(psi->nPage < 0) psi->nPage = 0;
660 else if(psi->nPage > psi->nMax - psi->nMin + 1)
661 psi->nPage = psi->nMax - psi->nMin + 1;
664 if((Mask & SIF_POS) && (psi->nPos != lpsi->nPos))
666 psi->nPos = lpsi->nPos;
668 if(psi->nPos < psi->nMin)
669 psi->nPos = psi->nMin;
670 else if(psi->nPos > psi->nMax - max(psi->nPage - 1, 0))
671 psi->nPos = psi->nMax - max(psi->nPage - 1, 0);
674 /* FIXME check assigned values */
676 if(fRedraw && Chg && (Window->Style & WS_VISIBLE))
683 IntReleaseWindowObject(Window);
687 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
690 NtUserShowScrollBar(HWND hWnd, int wBar, DWORD bShow)
692 BOOL fShowV = (wBar == SB_VERT) ? 0 : bShow;
693 BOOL fShowH = (wBar == SB_HORZ) ? 0 : bShow;
694 PWINDOW_OBJECT Window = IntGetWindowObject(hWnd);
697 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
704 WinPosShowWindow (hWnd, fShowH ? SW_SHOW : SW_HIDE);
711 fShowH = !(Window->Style & WS_HSCROLL);
712 Window->Style |= WS_HSCROLL;
716 fShowH = (Window->Style & WS_HSCROLL);
717 Window->Style &= ~WS_HSCROLL;
729 fShowV = !(Window->Style & WS_VSCROLL);
730 Window->Style |= WS_VSCROLL;
734 fShowV = (Window->Style & WS_VSCROLL);
735 Window->Style &= ~WS_VSCROLL;
742 return FALSE; /* Nothing to do! */
745 if (fShowH || fShowV) /* frame has been changed, let the window redraw itself */
747 WinPosSetWindowPos (hWnd, 0, 0, 0, 0, 0,
748 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
751 return FALSE; /* no frame changes */