📄 scrollbar.c
字号:
}
else if (0 != (Style & WS_HSCROLL))
{
Rect->bottom++;
}
Vertical = TRUE;
break;
case SB_CTL:
*Rect = ClientRect;
Vertical = (0 != (Style & SBS_VERT));
break;
default:
return FALSE;
}
if (Vertical)
{
Pixels = Rect->bottom - Rect->top;
}
else
{
Pixels = Rect->right - Rect->left;
}
if (Pixels <= 2 * GetSystemMetrics(SM_CXVSCROLL) + SCROLL_MIN_RECT)
{
if (SCROLL_MIN_RECT < Pixels)
{
*ArrowSize = (Pixels - SCROLL_MIN_RECT) / 2;
}
else
{
*ArrowSize = 0;
}
*ThumbPos = *ThumbSize = 0;
}
else
{
SCROLLINFO Info;
NtUserGetScrollInfo(Wnd, Bar, &Info);
*ArrowSize = GetSystemMetrics(SM_CXVSCROLL);
Pixels -= (2 * GetSystemMetrics(SM_CXVSCROLL));
if (0 != Info.nPage)
{
*ThumbSize = MulDiv(Pixels, Info.nPage, (Info.nMax - Info.nMin + 1));
if (*ThumbSize < SCROLL_MIN_THUMB)
{
*ThumbSize = SCROLL_MIN_THUMB;
}
}
else
{
*ThumbSize = GetSystemMetrics(SM_CXVSCROLL);
}
#if 0 /* FIXME */
if (((pixels -= *ThumbSize ) < 0) ||
((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
#else
if ((Pixels -= *ThumbSize ) < 0)
#endif
{
/* Rectangle too small or scrollbar disabled -> no thumb */
*ThumbPos = *ThumbSize = 0;
}
else
{
INT Max = Info.nMax - max(Info.nPage - 1, 0);
if (Max <= Info.nMin)
{
*ThumbPos = *ArrowSize;
}
else
{
*ThumbPos = *ArrowSize
+ MulDiv(Pixels, (Info.nPos - Info.nMin),
(Max - Info.nMin));
}
}
}
return Vertical;
}
/***********************************************************************
* IntScrollGetThumbVal
*
* Compute the current scroll position based on the thumb position in pixels
* from the top of the scroll-bar.
*/
static UINT FASTCALL
IntScrollGetThumbVal(HWND Wnd, INT SBType, PSCROLLBARINFO ScrollBarInfo,
BOOL Vertical, INT Pos)
{
SCROLLINFO si;
INT Pixels = Vertical ? ScrollBarInfo->rcScrollBar.bottom
- ScrollBarInfo->rcScrollBar.top
: ScrollBarInfo->rcScrollBar.right
- ScrollBarInfo->rcScrollBar.left;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE | SIF_PAGE;
NtUserGetScrollInfo(Wnd, SBType, &si);
if ((Pixels -= 2 * ScrollBarInfo->dxyLineButton) <= 0)
{
return si.nMin;
}
if ((Pixels -= (ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop)) <= 0)
{
return si.nMin;
}
Pos = Pos - ScrollBarInfo->dxyLineButton;
if (Pos < 0)
{
Pos = 0;
}
if (Pixels < Pos)
{
Pos = Pixels;
}
if (0 == si.nPage)
{
Pos *= si.nMax - si.nMin;
}
else
{
Pos *= si.nMax - si.nMin - si.nPage + 1;
}
return si.nMin + ((Pos + Pixels / 2) / Pixels);
}
/***********************************************************************
* IntScrollClipPos
*/
static POINT IntScrollClipPos(PRECT Rect, POINT Pt)
{
if (Pt.x < Rect->left)
{
Pt.x = Rect->left;
}
else if (Rect->right < Pt.x)
{
Pt.x = Rect->right;
}
if (Pt.y < Rect->top)
{
Pt.y = Rect->top;
}
else if (Rect->bottom < Pt.y)
{
Pt.y = Rect->bottom;
}
return Pt;
}
/***********************************************************************
* IntScrollDrawSizeGrip
*
* Draw the size grip.
*/
static void FASTCALL
IntScrollDrawSizeGrip(HWND Wnd, HDC Dc)
{
RECT Rect;
GetClientRect(Wnd, &Rect);
FillRect(Dc, &Rect, GetSysColorBrush(COLOR_SCROLLBAR));
Rect.left = max(Rect.left, Rect.right - GetSystemMetrics(SM_CXVSCROLL) - 1);
Rect.top = max(Rect.top, Rect.bottom - GetSystemMetrics(SM_CYHSCROLL) - 1);
DrawFrameControl(Dc, &Rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
}
/***********************************************************************
* IntScrollHandleKbdEvent
*
* Handle a keyboard event (only for SB_CTL scrollbars with focus).
*/
static void FASTCALL
IntScrollHandleKbdEvent(
HWND Wnd /* [in] Handle of window with scrollbar(s) */,
WPARAM wParam /* [in] Variable input including enable state */,
LPARAM lParam /* [in] Variable input including input point */)
{
DPRINT("Wnd=%p wParam=%d lParam=%ld\n", Wnd, wParam, lParam);
/* hide caret on first KEYDOWN to prevent flicker */
if (0 == (lParam & PFD_DOUBLEBUFFER_DONTCARE))
{
HideCaret(Wnd);
}
switch(wParam)
{
case VK_PRIOR:
wParam = SB_PAGEUP;
break;
case VK_NEXT:
wParam = SB_PAGEDOWN;
break;
case VK_HOME:
wParam = SB_TOP;
break;
case VK_END:
wParam = SB_BOTTOM;
break;
case VK_UP:
wParam = SB_LINEUP;
break;
case VK_DOWN:
wParam = SB_LINEDOWN;
break;
default:
return;
}
SendMessageW(GetParent(Wnd),
(0 != (GetWindowLongW(Wnd, GWL_STYLE ) & SBS_VERT) ?
WM_VSCROLL : WM_HSCROLL), wParam, (LPARAM) Wnd);
}
/***********************************************************************
* IntScrollHandleScrollEvent
*
* Handle a mouse or timer event for the scrollbar.
* 'Pt' is the location of the mouse event in drawing coordinates
*/
static VOID FASTCALL
IntScrollHandleScrollEvent(HWND Wnd, INT SBType, UINT Msg, POINT Pt)
{
static POINT PrevPt; /* Previous mouse position for timer events */
static UINT TrackThumbPos; /* Thumb position when tracking started. */
static INT LastClickPos; /* Position in the scroll-bar of the last
button-down event. */
static INT LastMousePos; /* Position in the scroll-bar of the last
mouse event. */
DWORD HitTest;
HWND WndOwner, WndCtl;
BOOL Vertical;
HDC Dc;
SCROLLBARINFO ScrollBarInfo;
SETSCROLLBARINFO NewInfo;
if (! IntGetScrollBarInfo(Wnd, SBType, &ScrollBarInfo))
{
return;
}
if (SCROLL_NOWHERE == ScrollTrackHitTest && WM_LBUTTONDOWN != Msg)
{
return;
}
NewInfo.nTrackPos = ScrollTrackingVal;
NewInfo.reserved = ScrollBarInfo.reserved;
memcpy(NewInfo.rgstate, ScrollBarInfo.rgstate, (CCHILDREN_SCROLLBAR + 1) * sizeof(DWORD));
if (SB_CTL == SBType
&& 0 != (GetWindowLongW(Wnd, GWL_STYLE) & (SBS_SIZEGRIP | SBS_SIZEBOX)))
{
switch(Msg)
{
case WM_LBUTTONDOWN: /* Initialise mouse tracking */
HideCaret(Wnd); /* hide caret while holding down LBUTTON */
SetCapture(Wnd);
PrevPt = Pt;
ScrollTrackHitTest = HitTest = SCROLL_THUMB;
break;
case WM_MOUSEMOVE:
GetClientRect(GetParent(GetParent(Wnd)), &ScrollBarInfo.rcScrollBar);
PrevPt = Pt;
break;
case WM_LBUTTONUP:
ReleaseCapture();
ScrollTrackHitTest = HitTest = SCROLL_NOWHERE;
if (Wnd == GetFocus())
{
ShowCaret(Wnd);
}
break;
case WM_SYSTIMER:
Pt = PrevPt;
break;
}
return;
}
Dc = GetDCEx(Wnd, 0, DCX_CACHE | ((SB_CTL == SBType) ? 0 : DCX_WINDOW));
if (SB_VERT == SBType)
{
Vertical = TRUE;
}
else if (SB_HORZ == SBType)
{
Vertical = FALSE;
}
else
{
Vertical = (0 != (GetWindowLongW(Wnd, GWL_STYLE) & SBS_VERT));
}
WndOwner = (SB_CTL == SBType) ? GetParent(Wnd) : Wnd;
WndCtl = (SB_CTL == SBType) ? Wnd : NULL;
switch (Msg)
{
case WM_LBUTTONDOWN: /* Initialise mouse tracking */
HideCaret(Wnd); /* hide caret while holding down LBUTTON */
ScrollTrackVertical = Vertical;
ScrollTrackHitTest = HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, FALSE );
LastClickPos = Vertical ? (Pt.y - ScrollBarInfo.rcScrollBar.top)
: (Pt.x - ScrollBarInfo.rcScrollBar.left);
LastMousePos = LastClickPos;
TrackThumbPos = ScrollBarInfo.xyThumbTop;
PrevPt = Pt;
if (SB_CTL == SBType && 0 != (GetWindowLongW(Wnd, GWL_STYLE) & WS_TABSTOP))
{
SetFocus(Wnd);
}
SetCapture(Wnd);
ScrollBarInfo.rgstate[ScrollTrackHitTest] |= STATE_SYSTEM_PRESSED;
NewInfo.rgstate[ScrollTrackHitTest] = ScrollBarInfo.rgstate[ScrollTrackHitTest];
NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
break;
case WM_MOUSEMOVE:
HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, TRUE);
PrevPt = Pt;
break;
case WM_LBUTTONUP:
HitTest = SCROLL_NOWHERE;
ReleaseCapture();
/* if scrollbar has focus, show back caret */
if (Wnd == GetFocus())
{
ShowCaret(Wnd);
}
ScrollBarInfo.rgstate[ScrollTrackHitTest] &= ~STATE_SYSTEM_PRESSED;
NewInfo.rgstate[ScrollTrackHitTest] = ScrollBarInfo.rgstate[ScrollTrackHitTest];
NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
break;
case WM_SYSTIMER:
Pt = PrevPt;
HitTest = IntScrollHitTest(&ScrollBarInfo, Vertical, Pt, FALSE);
break;
default:
return; /* Should never happen */
}
switch (ScrollTrackHitTest)
{
case SCROLL_NOWHERE: /* No tracking in progress */
break;
case SCROLL_TOP_ARROW:
if (HitTest == ScrollTrackHitTest)
{
if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
{
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
SB_LINEUP, (LPARAM) WndCtl);
}
SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(TIMERPROC) NULL);
}
else
{
KillSystemTimer(Wnd, SCROLL_TIMER);
}
break;
case SCROLL_TOP_RECT:
if (HitTest == ScrollTrackHitTest)
{
if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
{
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
SB_PAGEUP, (LPARAM) WndCtl);
}
SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(TIMERPROC) NULL);
}
else
{
KillSystemTimer(Wnd, SCROLL_TIMER);
}
break;
case SCROLL_THUMB:
if (WM_LBUTTONDOWN == Msg)
{
ScrollTrackingWin = Wnd;
ScrollTrackingBar = SBType;
ScrollTrackingPos = TrackThumbPos + LastMousePos - LastClickPos;
ScrollTrackingVal = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo,
Vertical, ScrollTrackingPos);
NewInfo.nTrackPos = ScrollTrackingVal;
NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
IntScrollDrawMovingThumb(Dc, &ScrollBarInfo, Vertical);
}
else if (WM_LBUTTONUP == Msg)
{
ScrollTrackingWin = 0;
ScrollTrackingVal = 0;
IntDrawScrollInterior(Wnd, Dc, SBType, Vertical, &ScrollBarInfo);
}
else /* WM_MOUSEMOVE */
{
UINT Pos;
if (! IntScrollPtInRectEx(&ScrollBarInfo.rcScrollBar, Pt, Vertical))
{
Pos = LastClickPos;
}
else
{
Pt = IntScrollClipPos(&ScrollBarInfo.rcScrollBar, Pt);
Pos = Vertical ? (Pt.y - ScrollBarInfo.rcScrollBar.top)
: (Pt.x - ScrollBarInfo.rcScrollBar.left);
}
if (Pos != LastMousePos || ! ScrollMovingThumb)
{
LastMousePos = Pos;
ScrollTrackingPos = TrackThumbPos + Pos - LastClickPos;
ScrollTrackingVal = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo,
Vertical, ScrollTrackingPos);
NewInfo.nTrackPos = ScrollTrackingVal;
NtUserSetScrollBarInfo(Wnd, IntScrollGetObjectId(SBType), &NewInfo);
IntScrollDrawMovingThumb(Dc, &ScrollBarInfo, Vertical);
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
MAKEWPARAM(SB_THUMBTRACK, ScrollTrackingVal),
(LPARAM) WndCtl);
}
}
break;
case SCROLL_BOTTOM_RECT:
if (HitTest == ScrollTrackHitTest)
{
if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
{
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
SB_PAGEDOWN, (LPARAM) WndCtl);
}
SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(TIMERPROC) NULL);
}
else
{
KillSystemTimer(Wnd, SCROLL_TIMER);
}
break;
case SCROLL_BOTTOM_ARROW:
if (HitTest == ScrollTrackHitTest)
{
if ((WM_LBUTTONDOWN == Msg) || (WM_SYSTIMER == Msg))
{
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
SB_LINEDOWN, (LPARAM) WndCtl);
}
SetSystemTimer(Wnd, SCROLL_TIMER, (WM_LBUTTONDOWN == Msg) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(TIMERPROC) NULL);
}
else
{
KillSystemTimer(Wnd, SCROLL_TIMER);
}
break;
}
if (WM_LBUTTONDOWN == Msg)
{
if (SCROLL_THUMB == HitTest)
{
UINT Val = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, Vertical,
TrackThumbPos + LastMousePos - LastClickPos);
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
MAKEWPARAM(SB_THUMBTRACK, Val), (LPARAM) WndCtl);
}
}
if (WM_LBUTTONUP == Msg)
{
HitTest = ScrollTrackHitTest;
ScrollTrackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
if (SCROLL_THUMB == HitTest)
{
UINT Val = IntScrollGetThumbVal(Wnd, SBType, &ScrollBarInfo, Vertical,
TrackThumbPos + LastMousePos - LastClickPos);
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
MAKEWPARAM(SB_THUMBPOSITION, Val), (LPARAM) WndCtl);
}
SendMessageW(WndOwner, Vertical ? WM_VSCROLL : WM_HSCROLL,
SB_ENDSCROLL, (LPARAM) WndCtl);
}
ReleaseDC(Wnd, Dc);
}
/***********************************************************************
* IntScrollCreateScrollBar
*
* Create a scroll bar
*/
static void IntScrollCreateScrollBar(
HWND Wnd /* [in] Handle of window with scrollbar(s) */,
LPCREATESTRUCTW lpCreate /* [in] The style and place of the scroll bar */)
{
SCROLLINFO Info;
Info.cbSize = sizeof(SCROLLINFO);
Info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -