📄 scrollbar.c
字号:
/* $Id $
*
* ReactOS User32 Library
* - ScrollBar control
*
* Copyright 2001 Casper S. Hornstrup
* Copyright 2003 Thomas Weidenmueller
* Copyright 2003 Filip Navara
*
* Based on Wine code.
*
* 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 Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; see the file COPYING.LIB.
* If not, write to the Free Software Foundation,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* INCLUDES *******************************************************************/
#include <user32.h>
#include <wine/debug.h>
/* GLOBAL VARIABLES ***********************************************************/
/* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */
#define SCROLL_NOWHERE 0x00 /* Outside the scroll bar */
#define SCROLL_TOP_ARROW 0x01 /* Top or left arrow */
#define SCROLL_TOP_RECT 0x02 /* Rectangle between the top arrow and the thumb */
#define SCROLL_THUMB 0x03 /* Thumb rectangle */
#define SCROLL_BOTTOM_RECT 0x04 /* Rectangle between the thumb and the bottom arrow */
#define SCROLL_BOTTOM_ARROW 0x05 /* Bottom or right arrow */
#define SCROLL_FIRST_DELAY 200 /* Delay (in ms) before first repetition when
holding the button down */
#define SCROLL_REPEAT_DELAY 50 /* Delay (in ms) between scroll repetitions */
#define SCROLL_TIMER 0 /* Scroll timer id */
/* Minimum size of the rectangle between the arrows */
#define SCROLL_MIN_RECT 4
/* Minimum size of the thumb in pixels */
#define SCROLL_MIN_THUMB 6
/* Thumb-tracking info */
static HWND ScrollTrackingWin = 0;
static INT ScrollTrackingBar = 0;
static INT ScrollTrackingPos = 0;
static INT ScrollTrackingVal = 0;
static BOOL ScrollMovingThumb = FALSE;
static DWORD ScrollTrackHitTest = SCROLL_NOWHERE;
static BOOL ScrollTrackVertical;
HBRUSH DefWndControlColor(HDC hDC, UINT ctlType);
static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
UINT STDCALL SetSystemTimer(HWND,UINT_PTR,UINT,TIMERPROC);
BOOL STDCALL KillSystemTimer(HWND,UINT_PTR);
/*********************************************************************
* scrollbar class descriptor
*/
const struct builtin_class_descr SCROLL_builtin_class =
{
L"ScrollBar", /* name */
CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style */
ScrollBarWndProc, /* procW */
NULL, /* procA (winproc is Unicode only) */
0, /* extra */
IDC_ARROW, /* cursor */
0 /* brush */
};
/* PRIVATE FUNCTIONS **********************************************************/
static void
IntDrawScrollInterior(HWND hWnd, HDC hDC, INT nBar, BOOL Vertical,
PSCROLLBARINFO ScrollBarInfo)
{
INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
INT ThumbTop = ScrollBarInfo->xyThumbTop;
RECT Rect;
HPEN hSavePen;
HBRUSH hSaveBrush, hBrush;
BOOL TopSelected = FALSE, BottomSelected = FALSE;
if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
TopSelected = TRUE;
if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
BottomSelected = TRUE;
/*
* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
* The window-owned scrollbars need to call DefWndControlColor
* to correctly setup default scrollbar colors
*/
if (nBar == SB_CTL)
{
hBrush = (HBRUSH)SendMessageW(GetParent(hWnd), WM_CTLCOLORSCROLLBAR, (WPARAM)hDC, (LPARAM)hWnd);
if (!hBrush)
hBrush = GetSysColorBrush(COLOR_SCROLLBAR);
}
else
{
hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
}
hSavePen = SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
hSaveBrush = SelectObject(hDC, hBrush);
/* Calculate the scroll rectangle */
if (Vertical)
{
Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
Rect.left = ScrollBarInfo->rcScrollBar.left;
Rect.right = ScrollBarInfo->rcScrollBar.right;
}
else
{
Rect.top = ScrollBarInfo->rcScrollBar.top;
Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
}
/* Draw the scroll rectangles and thumb */
if (!ScrollBarInfo->xyThumbBottom)
{
PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
Rect.bottom - Rect.top, PATCOPY);
/* Cleanup and return */
SelectObject(hDC, hSavePen);
SelectObject(hDC, hSaveBrush);
return;
}
ThumbTop -= ScrollBarInfo->dxyLineButton;
if (ScrollBarInfo->dxyLineButton)
{
if (Vertical)
{
if (ThumbSize)
{
PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
Rect.top += ThumbTop;
PatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
Rect.bottom = Rect.top + ThumbSize;
}
else
{
if (ThumbTop)
{
PatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
}
}
}
else
{
if (ThumbSize)
{
PatBlt(hDC, Rect.left, Rect.top, ThumbTop,
Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
Rect.left += ThumbTop;
PatBlt(hDC, Rect.left + ThumbSize, Rect.top,
Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
BottomSelected ? BLACKNESS : PATCOPY);
Rect.right = Rect.left + ThumbSize;
}
else
{
if (ThumbTop)
{
PatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
}
}
}
}
/* Draw the thumb */
if (ThumbSize)
DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
/* Cleanup */
SelectObject(hDC, hSavePen);
SelectObject(hDC, hSaveBrush);
}
static VOID FASTCALL
IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
{
RECT RectLT, RectRB;
INT ScrollDirFlagLT, ScrollDirFlagRB;
RectLT = RectRB = ScrollBarInfo->rcScrollBar;
if (Vertical)
{
ScrollDirFlagLT = DFCS_SCROLLUP;
ScrollDirFlagRB = DFCS_SCROLLDOWN;
RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
}
else
{
ScrollDirFlagLT = DFCS_SCROLLLEFT;
ScrollDirFlagRB = DFCS_SCROLLRIGHT;
RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
}
if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
{
ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
}
if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
{
ScrollDirFlagLT |= DFCS_INACTIVE;
}
if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
{
ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
}
if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
{
ScrollDirFlagRB |= DFCS_INACTIVE;
}
DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
}
static VOID FASTCALL
IntScrollDrawMovingThumb(HDC Dc, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
{
INT Pos = ScrollTrackingPos;
INT MaxSize;
INT OldTop;
if (Vertical)
{
MaxSize = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->rcScrollBar.top;
}
else
{
MaxSize = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->rcScrollBar.left;
}
MaxSize -= ScrollBarInfo->dxyLineButton + ScrollBarInfo->xyThumbBottom
- ScrollBarInfo->xyThumbTop;
if (Pos < ScrollBarInfo->dxyLineButton)
{
Pos = ScrollBarInfo->dxyLineButton;
}
else if (MaxSize < Pos)
{
Pos = MaxSize;
}
OldTop = ScrollBarInfo->xyThumbTop;
ScrollBarInfo->xyThumbBottom = Pos + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
ScrollBarInfo->xyThumbTop = Pos;
IntDrawScrollInterior(ScrollTrackingWin, Dc, ScrollTrackingBar, Vertical, ScrollBarInfo);
ScrollBarInfo->xyThumbBottom = OldTop + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
ScrollBarInfo->xyThumbTop = OldTop;
ScrollMovingThumb = ! ScrollMovingThumb;
}
static LONG FASTCALL
IntScrollGetObjectId(INT SBType)
{
if (SB_VERT == SBType)
{
return OBJID_VSCROLL;
}
if (SB_HORZ == SBType)
{
return OBJID_HSCROLL;
}
return OBJID_CLIENT;
}
static BOOL FASTCALL
IntGetScrollBarInfo(HWND Wnd, INT Bar, PSCROLLBARINFO ScrollBarInfo)
{
ScrollBarInfo->cbSize = sizeof(SCROLLBARINFO);
return NtUserGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), ScrollBarInfo);
}
void
IntDrawScrollBar(HWND Wnd, HDC DC, INT Bar)
{
INT ThumbSize;
SCROLLBARINFO Info;
BOOL Vertical;
/*
* Get scroll bar info.
*/
switch (Bar)
{
case SB_HORZ:
Vertical = FALSE;
break;
case SB_VERT:
Vertical = TRUE;
break;
case SB_CTL:
Vertical = (GetWindowLongW(Wnd, GWL_STYLE) & SBS_VERT) != 0;
break;
default:
return;
}
if (! IntGetScrollBarInfo(Wnd, Bar, &Info))
{
return;
}
if (IsRectEmpty(&Info.rcScrollBar))
{
return;
}
ThumbSize = Info.xyThumbBottom - Info.xyThumbTop;
/*
* Draw the arrows.
*/
if (Info.dxyLineButton)
{
IntDrawScrollArrows(DC, &Info, Vertical);
}
/*
* Draw the interior.
*/
IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);
/*
* If scroll bar has focus, reposition the caret.
*/
if (Wnd == GetFocus() && SB_CTL == Bar)
{
if (Vertical)
{
SetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
}
else
{
SetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
}
}
}
static BOOL FASTCALL
IntScrollPtInRectEx(LPRECT Rect, POINT Pt, BOOL Vertical)
{
RECT TempRect = *Rect;
if (Vertical)
{
TempRect.left -= Rect->right - Rect->left;
TempRect.right += Rect->right - Rect->left;
}
else
{
TempRect.top -= Rect->bottom - Rect->top;
TempRect.bottom += Rect->bottom - Rect->top;
}
return PtInRect(&TempRect, Pt);
}
static DWORD FASTCALL
IntScrollHitTest(PSCROLLBARINFO ScrollBarInfo, BOOL Vertical, POINT Pt, BOOL Dragging)
{
INT ArrowSize, ThumbSize, ThumbPos;
if ((Dragging && ! IntScrollPtInRectEx(&ScrollBarInfo->rcScrollBar, Pt, Vertical)) ||
! PtInRect(&ScrollBarInfo->rcScrollBar, Pt))
{
return SCROLL_NOWHERE;
}
ThumbPos = ScrollBarInfo->xyThumbTop;
ThumbSize = ScrollBarInfo->xyThumbBottom - ThumbPos;
ArrowSize = ScrollBarInfo->dxyLineButton;
if (Vertical)
{
if (Pt.y < ScrollBarInfo->rcScrollBar.top + ArrowSize)
{
return SCROLL_TOP_ARROW;
}
if (ScrollBarInfo->rcScrollBar.bottom - ArrowSize <= Pt.y)
{
return SCROLL_BOTTOM_ARROW;
}
if (0 == ThumbPos)
{
return SCROLL_TOP_RECT;
}
Pt.y -= ScrollBarInfo->rcScrollBar.top;
if (Pt.y < ThumbPos)
{
return SCROLL_TOP_RECT;
}
if (ThumbPos + ThumbSize <= Pt.y)
{
return SCROLL_BOTTOM_RECT;
}
}
else
{
if (Pt.x < ScrollBarInfo->rcScrollBar.left + ArrowSize)
{
return SCROLL_TOP_ARROW;
}
if (ScrollBarInfo->rcScrollBar.right - ArrowSize <= Pt.x)
{
return SCROLL_BOTTOM_ARROW;
}
if (0 == ThumbPos)
{
return SCROLL_TOP_RECT;
}
Pt.x -= ScrollBarInfo->rcScrollBar.left;
if (Pt.x < ThumbPos)
{
return SCROLL_TOP_RECT;
}
if (ThumbPos + ThumbSize <= Pt.x)
{
return SCROLL_BOTTOM_RECT;
}
}
return SCROLL_THUMB;
}
/***********************************************************************
* IntScrollGetScrollBarRect
*
* Compute the scroll bar rectangle, in drawing coordinates (i.e. client
* coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
* 'arrowSize' returns the width or height of an arrow (depending on
* the orientation of the scrollbar), 'thumbSize' returns the size of
* the thumb, and 'thumbPos' returns the position of the thumb
* relative to the left or to the top.
* Return TRUE if the scrollbar is vertical, FALSE if horizontal.
*/
static BOOL FASTCALL
IntScrollGetScrollBarRect(HWND Wnd, INT Bar, RECT *Rect,
INT *ArrowSize, INT *ThumbSize,
INT *ThumbPos)
{
INT Pixels;
BOOL Vertical;
RECT ClientRect;
RECT WindowRect;
DWORD Style, ExStyle;
GetClientRect(Wnd, &ClientRect);
if (SB_HORZ == Bar || SB_VERT == Bar)
{
ClientToScreen(Wnd, (LPPOINT) &ClientRect.left);
ClientToScreen(Wnd, (LPPOINT) &ClientRect.right);
GetWindowRect(Wnd, &WindowRect);
}
Style = GetWindowLongW(Wnd, GWL_STYLE);
switch (Bar)
{
case SB_HORZ:
Rect->left = ClientRect.left - WindowRect.left;
Rect->top = ClientRect.bottom - WindowRect.top;
Rect->right = ClientRect.right - WindowRect.left;
Rect->bottom = Rect->top + GetSystemMetrics(SM_CYHSCROLL);
if (0 != (Style & WS_BORDER))
{
Rect->left--;
Rect->right++;
}
else if (0 != (Style & WS_VSCROLL))
{
Rect->right++;
}
Vertical = FALSE;
break;
case SB_VERT:
ExStyle = GetWindowLongW(Wnd, GWL_EXSTYLE);
if (0 != (ExStyle & WS_EX_LEFTSCROLLBAR))
{
Rect->left = ClientRect.left - WindowRect.left - GetSystemMetrics(SM_CXVSCROLL);
}
else
{
Rect->left = ClientRect.right - WindowRect.left;
}
Rect->top = ClientRect.top - WindowRect.top;
Rect->right = Rect->left + GetSystemMetrics(SM_CXVSCROLL);
Rect->bottom = ClientRect.bottom - WindowRect.top;
if (0 != (Style & WS_BORDER))
{
Rect->top--;
Rect->bottom++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -