mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-02 19:13:38 +00:00
458 lines
14 KiB
C
458 lines
14 KiB
C
/*
|
|
* Scrollbar control
|
|
*
|
|
* Copyright 1993 Martin Ayotte
|
|
* Copyright 1994, 1996 Alexandre Julliard
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "user_private.h"
|
|
#include "controls.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(scroll);
|
|
|
|
|
|
/* Overlap between arrows and thumb */
|
|
#define SCROLL_ARROW_THUMB_OVERLAP 0
|
|
|
|
|
|
/***********************************************************************
|
|
* SCROLL_DrawArrows
|
|
*
|
|
* Draw the scroll bar arrows.
|
|
*/
|
|
static void SCROLL_DrawArrows( HDC hdc, UINT flags,
|
|
RECT *rect, INT arrowSize, BOOL vertical,
|
|
BOOL top_pressed, BOOL bottom_pressed )
|
|
{
|
|
RECT r;
|
|
|
|
r = *rect;
|
|
if( vertical )
|
|
r.bottom = r.top + arrowSize;
|
|
else
|
|
r.right = r.left + arrowSize;
|
|
|
|
DrawFrameControl( hdc, &r, DFC_SCROLL,
|
|
(vertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT)
|
|
| (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
|
|
| (flags & ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0 ) );
|
|
|
|
r = *rect;
|
|
if( vertical )
|
|
r.top = r.bottom-arrowSize;
|
|
else
|
|
r.left = r.right-arrowSize;
|
|
|
|
DrawFrameControl( hdc, &r, DFC_SCROLL,
|
|
(vertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT)
|
|
| (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
|
|
| (flags & ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SCROLL_DrawInterior
|
|
*
|
|
* Draw the scroll bar interior (everything except the arrows).
|
|
*/
|
|
static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar,
|
|
RECT *rect, INT arrowSize,
|
|
INT thumbSize, INT thumbPos, BOOL vertical,
|
|
BOOL top_selected, BOOL bottom_selected )
|
|
{
|
|
RECT r;
|
|
HPEN hSavePen;
|
|
HBRUSH hSaveBrush,hBrush;
|
|
|
|
if (nBar == SB_CTL)
|
|
{
|
|
hBrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
|
|
(WPARAM)hdc,(LPARAM)hwnd);
|
|
}
|
|
else
|
|
{
|
|
COLORREF bk = GetSysColor( COLOR_3DHILIGHT );
|
|
SetTextColor( hdc, GetSysColor( COLOR_3DFACE ));
|
|
SetBkColor( hdc, bk );
|
|
|
|
/* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
|
|
* we better use 0x55aa bitmap brush to make scrollbar's background
|
|
* look different from the window background.
|
|
*/
|
|
if (bk == GetSysColor( COLOR_WINDOW ))
|
|
hBrush = SYSCOLOR_Get55AABrush();
|
|
else
|
|
{
|
|
hBrush = GetSysColorBrush( COLOR_SCROLLBAR );
|
|
UnrealizeObject( hBrush );
|
|
}
|
|
}
|
|
|
|
hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
|
|
hSaveBrush = SelectObject( hdc, hBrush );
|
|
|
|
/* Calculate the scroll rectangle */
|
|
|
|
r = *rect;
|
|
if (vertical)
|
|
{
|
|
r.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
|
|
r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
|
|
}
|
|
else
|
|
{
|
|
r.left += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
|
|
r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
|
|
}
|
|
|
|
/* Draw the scroll bar frame */
|
|
|
|
/* Draw the scroll rectangles and thumb */
|
|
|
|
if (!thumbPos) /* No thumb to draw */
|
|
{
|
|
PatBlt( hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, PATCOPY );
|
|
|
|
/* cleanup and return */
|
|
SelectObject( hdc, hSavePen );
|
|
SelectObject( hdc, hSaveBrush );
|
|
return;
|
|
}
|
|
|
|
if (vertical)
|
|
{
|
|
PatBlt( hdc, r.left, r.top, r.right - r.left,
|
|
thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
|
|
top_selected ? 0x0f0000 : PATCOPY );
|
|
r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
|
|
PatBlt( hdc, r.left, r.top + thumbSize, r.right - r.left,
|
|
r.bottom - r.top - thumbSize,
|
|
bottom_selected ? 0x0f0000 : PATCOPY );
|
|
r.bottom = r.top + thumbSize;
|
|
}
|
|
else /* horizontal */
|
|
{
|
|
PatBlt( hdc, r.left, r.top,
|
|
thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
|
|
r.bottom - r.top, top_selected ? 0x0f0000 : PATCOPY );
|
|
r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
|
|
PatBlt( hdc, r.left + thumbSize, r.top, r.right - r.left - thumbSize,
|
|
r.bottom - r.top, bottom_selected ? 0x0f0000 : PATCOPY );
|
|
r.right = r.left + thumbSize;
|
|
}
|
|
|
|
/* Draw the thumb */
|
|
|
|
SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) );
|
|
Rectangle( hdc, r.left+1, r.top+1, r.right-1, r.bottom-1 );
|
|
DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
|
|
|
|
/* cleanup */
|
|
SelectObject( hdc, hSavePen );
|
|
SelectObject( hdc, hSaveBrush );
|
|
}
|
|
|
|
void WINAPI USER_ScrollBarDraw( HWND hwnd, HDC hdc, INT nBar, enum SCROLL_HITTEST hit_test,
|
|
const struct SCROLL_TRACKING_INFO *tracking_info, BOOL arrows,
|
|
BOOL interior, RECT *rect, UINT enable_flags, INT arrowSize,
|
|
INT thumbPos, INT thumbSize, BOOL vertical )
|
|
{
|
|
if (nBar == SB_CTL)
|
|
{
|
|
DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
|
|
|
|
if (style & SBS_SIZEGRIP)
|
|
{
|
|
RECT rc = *rect;
|
|
|
|
FillRect( hdc, &rc, GetSysColorBrush( COLOR_BTNFACE ) );
|
|
rc.left = max( rc.left, rc.right - GetSystemMetrics( SM_CXVSCROLL ) - 1 );
|
|
rc.top = max( rc.top, rc.bottom - GetSystemMetrics( SM_CYHSCROLL ) - 1 );
|
|
DrawFrameControl( hdc, &rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP );
|
|
return;
|
|
}
|
|
|
|
if (style & SBS_SIZEBOX)
|
|
{
|
|
FillRect( hdc, rect, GetSysColorBrush( COLOR_BTNFACE ) );
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Draw the arrows */
|
|
if (arrows && arrowSize)
|
|
{
|
|
if (vertical == tracking_info->vertical && GetCapture() == hwnd)
|
|
SCROLL_DrawArrows( hdc, enable_flags, rect, arrowSize, vertical,
|
|
hit_test == tracking_info->hit_test && hit_test == SCROLL_TOP_ARROW,
|
|
hit_test == tracking_info->hit_test && hit_test == SCROLL_BOTTOM_ARROW );
|
|
else
|
|
SCROLL_DrawArrows( hdc, enable_flags, rect, arrowSize, vertical, FALSE, FALSE );
|
|
}
|
|
|
|
if (interior)
|
|
{
|
|
if (vertical == tracking_info->vertical && GetCapture() == hwnd)
|
|
{
|
|
SCROLL_DrawInterior( hwnd, hdc, nBar, rect, arrowSize, thumbSize, thumbPos, vertical,
|
|
hit_test == tracking_info->hit_test && hit_test == SCROLL_TOP_RECT,
|
|
hit_test == tracking_info->hit_test && hit_test == SCROLL_BOTTOM_RECT );
|
|
}
|
|
else
|
|
{
|
|
SCROLL_DrawInterior( hwnd, hdc, nBar, rect, arrowSize, thumbSize, thumbPos,
|
|
vertical, FALSE, FALSE );
|
|
}
|
|
}
|
|
|
|
/* if scroll bar has focus, reposition the caret */
|
|
if(hwnd==GetFocus() && (nBar==SB_CTL))
|
|
{
|
|
if (!vertical)
|
|
{
|
|
SetCaretPos(thumbPos + 1, rect->top + 1);
|
|
}
|
|
else
|
|
{
|
|
SetCaretPos(rect->top + 1, thumbPos + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL unicode )
|
|
{
|
|
switch(message)
|
|
{
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
case WM_ENABLE:
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONUP:
|
|
case WM_NCMOUSEMOVE:
|
|
case WM_NCMOUSELEAVE:
|
|
case WM_MOUSEMOVE:
|
|
case WM_MOUSELEAVE:
|
|
case WM_SYSTIMER:
|
|
case WM_SETFOCUS:
|
|
case WM_KILLFOCUS:
|
|
case WM_CREATE:
|
|
case WM_ERASEBKGND:
|
|
case WM_GETDLGCODE:
|
|
case WM_PAINT:
|
|
case SBM_SETRANGEREDRAW:
|
|
case SBM_SETRANGE:
|
|
case SBM_GETSCROLLINFO:
|
|
case SBM_GETSCROLLBARINFO:
|
|
case SBM_SETSCROLLINFO:
|
|
case WM_SETCURSOR:
|
|
case SBM_SETPOS:
|
|
case SBM_GETPOS:
|
|
case SBM_GETRANGE:
|
|
case SBM_ENABLE_ARROWS:
|
|
case 0x00e5:
|
|
case 0x00e7:
|
|
case 0x00e8:
|
|
case 0x00ec:
|
|
case 0x00ed:
|
|
case 0x00ee:
|
|
case 0x00ef:
|
|
return NtUserMessageCall( hwnd, message, wParam, lParam, 0, NtUserScrollBarWndProc, !unicode );
|
|
|
|
default:
|
|
if (message >= WM_USER)
|
|
WARN("unknown msg %04x wp=%04Ix lp=%08Ix\n",
|
|
message, wParam, lParam );
|
|
if (unicode)
|
|
return DefWindowProcW( hwnd, message, wParam, lParam );
|
|
else
|
|
return DefWindowProcA( hwnd, message, wParam, lParam );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ScrollBarWndProc_common
|
|
*/
|
|
LRESULT ScrollBarWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode )
|
|
{
|
|
return user_api->pScrollBarWndProc( hwnd, msg, wParam, lParam, unicode );
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* GetScrollInfo (USER32.@)
|
|
*
|
|
* GetScrollInfo can be used to retrieve the position, upper bound,
|
|
* lower bound, and page size of a scrollbar control.
|
|
*
|
|
* PARAMS
|
|
* hwnd [I] Handle of window with scrollbar(s)
|
|
* nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
|
|
* info [IO] fMask specifies which values to retrieve
|
|
*
|
|
* RETURNS
|
|
* TRUE if SCROLLINFO is filled
|
|
* ( if nBar is SB_CTL, GetScrollInfo returns TRUE even if nothing
|
|
* is filled)
|
|
*/
|
|
BOOL WINAPI DECLSPEC_HOTPATCH GetScrollInfo(HWND hwnd, INT nBar, LPSCROLLINFO info)
|
|
{
|
|
TRACE("hwnd=%p nBar=%d info=%p\n", hwnd, nBar, info);
|
|
|
|
/* Refer SB_CTL requests to the window */
|
|
if (nBar == SB_CTL)
|
|
{
|
|
SendMessageW(hwnd, SBM_GETSCROLLINFO, 0, (LPARAM)info);
|
|
return TRUE;
|
|
}
|
|
return NtUserGetScrollInfo( hwnd, nBar, info );
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* SetScrollPos (USER32.@)
|
|
*
|
|
* Sets the current position of the scroll thumb.
|
|
*
|
|
* PARAMS
|
|
* hwnd [I] Handle of window with scrollbar(s)
|
|
* nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
|
|
* nPos [I] New value
|
|
* bRedraw [I] Should scrollbar be redrawn afterwards?
|
|
*
|
|
* RETURNS
|
|
* Success: Scrollbar position
|
|
* Failure: 0
|
|
*
|
|
* REMARKS
|
|
* Note the ambiguity when 0 is returned. Use GetLastError
|
|
* to make sure there was an error (and to know which one).
|
|
*/
|
|
int WINAPI DECLSPEC_HOTPATCH SetScrollPos( HWND hwnd, int bar, int pos, BOOL redraw )
|
|
{
|
|
SCROLLINFO info;
|
|
|
|
info.cbSize = sizeof(info);
|
|
info.nPos = pos;
|
|
info.fMask = SIF_POS | SIF_RETURNPREV;
|
|
return NtUserSetScrollInfo( hwnd, bar, &info, redraw );
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* GetScrollPos (USER32.@)
|
|
*
|
|
* Gets the current position of the scroll thumb.
|
|
*
|
|
* PARAMS
|
|
* hwnd [I] Handle of window with scrollbar(s)
|
|
* nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
|
|
*
|
|
* RETURNS
|
|
* Success: Current position
|
|
* Failure: 0
|
|
*
|
|
* REMARKS
|
|
* There is ambiguity when 0 is returned. Use GetLastError
|
|
* to make sure there was an error (and to know which one).
|
|
*/
|
|
int WINAPI DECLSPEC_HOTPATCH GetScrollPos( HWND hwnd, int bar )
|
|
{
|
|
SCROLLINFO info;
|
|
|
|
TRACE( "hwnd=%p bar=%d\n", hwnd, bar );
|
|
|
|
/* Refer SB_CTL requests to the window */
|
|
if (bar == SB_CTL)
|
|
return SendMessageW( hwnd, SBM_GETPOS, 0, 0 );
|
|
|
|
info.cbSize = sizeof(info);
|
|
info.fMask = SIF_POS;
|
|
return GetScrollInfo( hwnd, bar, &info ) ? info.nPos : 0;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* SetScrollRange (USER32.@)
|
|
* The SetScrollRange function sets the minimum and maximum scroll box positions
|
|
* If nMinPos and nMaxPos is the same value, the scroll bar will hide
|
|
*
|
|
* Sets the range of the scroll bar.
|
|
*
|
|
* PARAMS
|
|
* hwnd [I] Handle of window with scrollbar(s)
|
|
* nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
|
|
* minVal [I] New minimum value
|
|
* maxVal [I] New Maximum value
|
|
* bRedraw [I] Should scrollbar be redrawn afterwards?
|
|
*
|
|
* RETURNS
|
|
* Success: TRUE
|
|
* Failure: FALSE
|
|
*/
|
|
BOOL WINAPI DECLSPEC_HOTPATCH SetScrollRange(HWND hwnd, INT nBar, INT minVal, INT maxVal, BOOL bRedraw)
|
|
{
|
|
SCROLLINFO info;
|
|
|
|
TRACE("hwnd=%p nBar=%d min=%d max=%d, bRedraw=%d\n", hwnd, nBar, minVal, maxVal, bRedraw);
|
|
|
|
info.cbSize = sizeof(info);
|
|
info.fMask = SIF_RANGE;
|
|
info.nMin = minVal;
|
|
info.nMax = maxVal;
|
|
NtUserSetScrollInfo( hwnd, nBar, &info, bRedraw );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* GetScrollRange (USER32.@)
|
|
*
|
|
* Gets the range of the scroll bar.
|
|
*
|
|
* PARAMS
|
|
* hwnd [I] Handle of window with scrollbar(s)
|
|
* nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
|
|
* lpMin [O] Where to store minimum value
|
|
* lpMax [O] Where to store maximum value
|
|
*
|
|
* RETURNS
|
|
* TRUE if values is filled
|
|
*/
|
|
BOOL WINAPI DECLSPEC_HOTPATCH GetScrollRange( HWND hwnd, int bar, int *min, int *max )
|
|
{
|
|
SCROLLINFO info;
|
|
|
|
TRACE( "hwnd=%p nBar=%d lpMin=%p lpMax=%p\n", hwnd, bar, min, max );
|
|
|
|
/* Refer SB_CTL requests to the window */
|
|
if (bar == SB_CTL)
|
|
{
|
|
SendMessageW( hwnd, SBM_GETRANGE, (WPARAM)min, (LPARAM)max );
|
|
return TRUE;
|
|
}
|
|
|
|
info.cbSize = sizeof(info);
|
|
info.fMask = SIF_RANGE;
|
|
info.nMin = info.nMax = 0;
|
|
GetScrollInfo( hwnd, bar, &info );
|
|
if (min) *min = info.nMin;
|
|
if (max) *max = info.nMax;
|
|
return TRUE;
|
|
}
|