mirror of
https://github.com/reactos/reactos.git
synced 2024-10-30 11:35:58 +00:00
fc6c07c385
- After inspecting a theme file with different upper or lower tracks it seems that windows use what is called LowerTrackHorz and LowerTrackVert in the upper track and UpperTrackHorz and UpperTrackVert are used in the lower track. CORE-13513
681 lines
22 KiB
C
681 lines
22 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS uxtheme.dll
|
|
* FILE: dll/win32/uxtheme/ncscrollbar.c
|
|
* PURPOSE: uxtheme scrollbar support
|
|
* PROGRAMMER: Giannis Adamopoulos
|
|
* This file is heavily based on code from the wine project:
|
|
* Copyright 1993 Martin Ayotte
|
|
* Copyright 1994, 1996 Alexandre Julliard
|
|
*/
|
|
|
|
#include "uxthemep.h"
|
|
|
|
#include <assert.h>
|
|
|
|
static void ScreenToWindow( HWND hWnd, POINT* pt)
|
|
{
|
|
RECT rcWnd;
|
|
GetWindowRect(hWnd, &rcWnd);
|
|
pt->x -= rcWnd.left;
|
|
pt->y -= rcWnd.top;
|
|
}
|
|
|
|
static BOOL SCROLL_IsVertical(HWND hwnd, INT nBar)
|
|
{
|
|
switch(nBar)
|
|
{
|
|
case SB_HORZ:
|
|
return FALSE;
|
|
case SB_VERT:
|
|
return TRUE;
|
|
default:
|
|
assert(FALSE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static LONG SCROLL_getObjectId(INT nBar)
|
|
{
|
|
switch(nBar)
|
|
{
|
|
case SB_HORZ:
|
|
return OBJID_HSCROLL;
|
|
case SB_VERT:
|
|
return OBJID_VSCROLL;
|
|
default:
|
|
assert(FALSE);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SCROLL_PtInRectEx
|
|
*/
|
|
static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
|
|
{
|
|
RECT rect = *lpRect;
|
|
int scrollbarWidth;
|
|
|
|
/* Pad hit rect to allow mouse to be dragged outside of scrollbar and
|
|
* still be considered in the scrollbar. */
|
|
if (vertical)
|
|
{
|
|
scrollbarWidth = lpRect->right - lpRect->left;
|
|
rect.left -= scrollbarWidth*8;
|
|
rect.right += scrollbarWidth*8;
|
|
rect.top -= scrollbarWidth*2;
|
|
rect.bottom += scrollbarWidth*2;
|
|
}
|
|
else
|
|
{
|
|
scrollbarWidth = lpRect->bottom - lpRect->top;
|
|
rect.left -= scrollbarWidth*2;
|
|
rect.right += scrollbarWidth*2;
|
|
rect.top -= scrollbarWidth*8;
|
|
rect.bottom += scrollbarWidth*8;
|
|
}
|
|
return PtInRect( &rect, pt );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SCROLL_HitTest
|
|
*
|
|
* Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
|
|
*/
|
|
static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, SCROLLBARINFO* psbi, BOOL vertical,
|
|
POINT pt, BOOL bDragging )
|
|
{
|
|
if ( (bDragging && !SCROLL_PtInRectEx( &psbi->rcScrollBar, pt, vertical )) ||
|
|
(!PtInRect( &psbi->rcScrollBar, pt )) )
|
|
{
|
|
return SCROLL_NOWHERE;
|
|
}
|
|
|
|
if (vertical)
|
|
{
|
|
if (pt.y < psbi->rcScrollBar.top + psbi->dxyLineButton)
|
|
return SCROLL_TOP_ARROW;
|
|
if (pt.y >= psbi->rcScrollBar.bottom - psbi->dxyLineButton)
|
|
return SCROLL_BOTTOM_ARROW;
|
|
if (!psbi->xyThumbTop)
|
|
return SCROLL_TOP_RECT;
|
|
pt.y -= psbi->rcScrollBar.top;
|
|
if (pt.y < psbi->xyThumbTop)
|
|
return SCROLL_TOP_RECT;
|
|
if (pt.y >= psbi->xyThumbBottom)
|
|
return SCROLL_BOTTOM_RECT;
|
|
}
|
|
else /* horizontal */
|
|
{
|
|
if (pt.x < psbi->rcScrollBar.left + psbi->dxyLineButton)
|
|
return SCROLL_TOP_ARROW;
|
|
if (pt.x >= psbi->rcScrollBar.right - psbi->dxyLineButton)
|
|
return SCROLL_BOTTOM_ARROW;
|
|
if (!psbi->xyThumbTop)
|
|
return SCROLL_TOP_RECT;
|
|
pt.x -= psbi->rcScrollBar.left;
|
|
if (pt.x < psbi->xyThumbTop)
|
|
return SCROLL_TOP_RECT;
|
|
if (pt.x >= psbi->xyThumbBottom)
|
|
return SCROLL_BOTTOM_RECT;
|
|
}
|
|
return SCROLL_THUMB;
|
|
}
|
|
|
|
static void SCROLL_ThemeDrawPart(PDRAW_CONTEXT pcontext, int iPartId,int iStateId, SCROLLBARINFO* psbi, int htCurrent, int htDown, int htHot, RECT* r)
|
|
{
|
|
if (r->right <= r->left || r->bottom <= r->top)
|
|
return;
|
|
|
|
if(psbi->rgstate[htCurrent] & STATE_SYSTEM_UNAVAILABLE)
|
|
iStateId += BUTTON_DISABLED - BUTTON_NORMAL;
|
|
else if (htHot == htCurrent)
|
|
iStateId += BUTTON_HOT - BUTTON_NORMAL;
|
|
else if (htDown == htCurrent)
|
|
iStateId += BUTTON_PRESSED - BUTTON_NORMAL;
|
|
|
|
DrawThemeBackground(pcontext->scrolltheme, pcontext->hDC, iPartId, iStateId, r, NULL);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SCROLL_DrawArrows
|
|
*
|
|
* Draw the scroll bar arrows.
|
|
*/
|
|
static void SCROLL_DrawArrows( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi,
|
|
BOOL vertical, int htDown, int htHot )
|
|
{
|
|
RECT r;
|
|
int iStateId;
|
|
|
|
r = psbi->rcScrollBar;
|
|
if( vertical )
|
|
{
|
|
r.bottom = r.top + psbi->dxyLineButton;
|
|
iStateId = ABS_UPNORMAL;
|
|
}
|
|
else
|
|
{
|
|
r.right = r.left + psbi->dxyLineButton;
|
|
iStateId = ABS_LEFTNORMAL;
|
|
}
|
|
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_ARROWBTN, iStateId, psbi, SCROLL_TOP_ARROW, htDown, htHot, &r);
|
|
|
|
r = psbi->rcScrollBar;
|
|
if( vertical )
|
|
{
|
|
r.top = r.bottom - psbi->dxyLineButton;
|
|
iStateId = ABS_DOWNNORMAL;
|
|
}
|
|
else
|
|
{
|
|
iStateId = ABS_RIGHTNORMAL;
|
|
r.left = r.right - psbi->dxyLineButton;
|
|
}
|
|
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_ARROWBTN, iStateId, psbi, SCROLL_BOTTOM_ARROW, htDown, htHot, &r);
|
|
}
|
|
|
|
static void SCROLL_DrawInterior( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi,
|
|
INT thumbPos, BOOL vertical,
|
|
int htDown, int htHot )
|
|
{
|
|
RECT r, rcPart;
|
|
|
|
/* thumbPos is relative to the edge of the scrollbar */
|
|
|
|
r = psbi->rcScrollBar;
|
|
if (vertical)
|
|
{
|
|
if (thumbPos)
|
|
thumbPos += pcontext->wi.rcClient.top - pcontext->wi.rcWindow.top;
|
|
r.top += psbi->dxyLineButton;
|
|
r.bottom -= (psbi->dxyLineButton);
|
|
}
|
|
else
|
|
{
|
|
if (thumbPos)
|
|
thumbPos += pcontext->wi.rcClient.left - pcontext->wi.rcWindow.left;
|
|
r.left += psbi->dxyLineButton;
|
|
r.right -= psbi->dxyLineButton;
|
|
}
|
|
|
|
if (r.right <= r.left || r.bottom <= r.top)
|
|
return;
|
|
|
|
/* Draw the scroll rectangles and thumb */
|
|
|
|
if (!thumbPos) /* No thumb to draw */
|
|
{
|
|
rcPart = r;
|
|
SCROLL_ThemeDrawPart(pcontext, vertical ? SBP_UPPERTRACKVERT: SBP_UPPERTRACKHORZ , BUTTON_NORMAL, psbi, SCROLL_THUMB, 0, 0, &rcPart);
|
|
return;
|
|
}
|
|
|
|
/* Some themes have different bitmaps for the upper and lower tracks
|
|
It seems that windows use the bitmap for the lower track in the upper track */
|
|
if (vertical)
|
|
{
|
|
rcPart = r;
|
|
rcPart.bottom = thumbPos;
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKVERT, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart);
|
|
r.top = rcPart.bottom;
|
|
|
|
rcPart = r;
|
|
rcPart.top += psbi->xyThumbBottom - psbi->xyThumbTop;
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKVERT, BUTTON_NORMAL, psbi, SCROLL_BOTTOM_RECT, htDown, htHot, &rcPart);
|
|
r.bottom = rcPart.top;
|
|
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_THUMBBTNVERT, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_GRIPPERVERT, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
|
|
}
|
|
else /* horizontal */
|
|
{
|
|
rcPart = r;
|
|
rcPart.right = thumbPos;
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKHORZ, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart);
|
|
r.left = rcPart.right;
|
|
|
|
rcPart = r;
|
|
rcPart.left += psbi->xyThumbBottom - psbi->xyThumbTop;
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKHORZ, BUTTON_NORMAL, psbi, SCROLL_BOTTOM_RECT, htDown, htHot, &rcPart);
|
|
r.right = rcPart.left;
|
|
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_THUMBBTNHORZ, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
|
|
SCROLL_ThemeDrawPart(pcontext, SBP_GRIPPERHORZ, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
|
|
}
|
|
}
|
|
|
|
static void SCROLL_DrawMovingThumb(PWND_DATA pwndData, PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi, BOOL vertical)
|
|
{
|
|
INT pos = pwndData->SCROLL_TrackingPos;
|
|
INT max_size;
|
|
|
|
if( vertical )
|
|
max_size = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
|
|
else
|
|
max_size = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
|
|
|
|
max_size -= psbi->xyThumbBottom - psbi->xyThumbTop + psbi->dxyLineButton;
|
|
|
|
if( pos < (psbi->dxyLineButton) )
|
|
pos = (psbi->dxyLineButton);
|
|
else if( pos > max_size )
|
|
pos = max_size;
|
|
|
|
SCROLL_DrawInterior(pcontext, psbi, pos, vertical, SCROLL_THUMB, 0);
|
|
|
|
pwndData->SCROLL_MovingThumb = !pwndData->SCROLL_MovingThumb;
|
|
}
|
|
|
|
|
|
void
|
|
ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT nBar, POINT* pt)
|
|
{
|
|
SCROLLINFO si;
|
|
SCROLLBARINFO sbi;
|
|
BOOL vertical;
|
|
enum SCROLL_HITTEST htHot = SCROLL_NOWHERE;
|
|
PWND_DATA pwndData;
|
|
|
|
if (((nBar == SB_VERT) && !(pcontext->wi.dwStyle & WS_VSCROLL)) ||
|
|
((nBar == SB_HORZ) && !(pcontext->wi.dwStyle & WS_HSCROLL))) return;
|
|
|
|
if (!(pwndData = ThemeGetWndData(pcontext->hWnd)))
|
|
return;
|
|
|
|
if (pwndData->SCROLL_TrackingWin)
|
|
return;
|
|
|
|
/* Retrieve scrollbar info */
|
|
sbi.cbSize = sizeof(sbi);
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_ALL ;
|
|
GetScrollInfo(pcontext->hWnd, nBar, &si);
|
|
GetScrollBarInfo(pcontext->hWnd, SCROLL_getObjectId(nBar), &sbi);
|
|
vertical = SCROLL_IsVertical(pcontext->hWnd, nBar);
|
|
if(sbi.rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE &&
|
|
sbi.rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE )
|
|
{
|
|
sbi.xyThumbTop = 0;
|
|
}
|
|
|
|
/* The scrollbar rect is in screen coordinates */
|
|
OffsetRect(&sbi.rcScrollBar, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top);
|
|
|
|
if(pt)
|
|
{
|
|
ScreenToWindow(pcontext->hWnd, pt);
|
|
htHot = SCROLL_HitTest(pcontext->hWnd, &sbi, vertical, *pt, FALSE);
|
|
}
|
|
|
|
/* do not draw if the scrollbar rectangle is empty */
|
|
if(IsRectEmpty(&sbi.rcScrollBar)) return;
|
|
|
|
/* Draw the scrollbar */
|
|
SCROLL_DrawArrows( pcontext, &sbi, vertical, 0, htHot );
|
|
SCROLL_DrawInterior( pcontext, &sbi, sbi.xyThumbTop, vertical, 0, htHot );
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
* SCROLL_ClipPos
|
|
*/
|
|
static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt )
|
|
{
|
|
if( pt.x < lpRect->left )
|
|
pt.x = lpRect->left;
|
|
else
|
|
if( pt.x > lpRect->right )
|
|
pt.x = lpRect->right;
|
|
|
|
if( pt.y < lpRect->top )
|
|
pt.y = lpRect->top;
|
|
else
|
|
if( pt.y > lpRect->bottom )
|
|
pt.y = lpRect->bottom;
|
|
|
|
return pt;
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
* SCROLL_GetThumbVal
|
|
*
|
|
* Compute the current scroll position based on the thumb position in pixels
|
|
* from the top of the scroll-bar.
|
|
*/
|
|
static UINT SCROLL_GetThumbVal( SCROLLINFO *psi, RECT *rect,
|
|
BOOL vertical, INT pos )
|
|
{
|
|
INT thumbSize;
|
|
INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
|
|
INT range;
|
|
|
|
if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
|
|
return psi->nMin;
|
|
|
|
if (psi->nPage)
|
|
{
|
|
thumbSize = MulDiv(pixels,psi->nPage,(psi->nMax-psi->nMin+1));
|
|
if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
|
|
}
|
|
else thumbSize = GetSystemMetrics(SM_CXVSCROLL);
|
|
|
|
if ((pixels -= thumbSize) <= 0) return psi->nMin;
|
|
|
|
pos = max( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) );
|
|
if (pos > pixels) pos = pixels;
|
|
|
|
if (!psi->nPage)
|
|
range = psi->nMax - psi->nMin;
|
|
else
|
|
range = psi->nMax - psi->nMin - psi->nPage + 1;
|
|
|
|
return psi->nMin + MulDiv(pos, range, pixels);
|
|
}
|
|
|
|
static void
|
|
SCROLL_HandleScrollEvent(PWND_DATA pwndData, HWND hwnd, INT nBar, UINT msg, POINT pt)
|
|
{
|
|
/* Previous mouse position for timer events */
|
|
static POINT prevPt;
|
|
/* Thumb position when tracking started. */
|
|
static UINT trackThumbPos;
|
|
/* Position in the scroll-bar of the last button-down event. */
|
|
static INT lastClickPos;
|
|
/* Position in the scroll-bar of the last mouse event. */
|
|
static INT lastMousePos;
|
|
|
|
enum SCROLL_HITTEST hittest;
|
|
HWND hwndOwner, hwndCtl;
|
|
BOOL vertical;
|
|
SCROLLINFO si;
|
|
SCROLLBARINFO sbi;
|
|
DRAW_CONTEXT context;
|
|
|
|
si.cbSize = sizeof(si);
|
|
sbi.cbSize = sizeof(sbi);
|
|
si.fMask = SIF_ALL;
|
|
GetScrollInfo(hwnd, nBar, &si);
|
|
GetScrollBarInfo(hwnd, SCROLL_getObjectId(nBar), &sbi);
|
|
vertical = SCROLL_IsVertical(hwnd, nBar);
|
|
if(sbi.rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE &&
|
|
sbi.rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((pwndData->SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN))
|
|
return;
|
|
|
|
ThemeInitDrawContext(&context, hwnd, 0);
|
|
|
|
/* The scrollbar rect is in screen coordinates */
|
|
OffsetRect(&sbi.rcScrollBar, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
|
|
|
|
hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
|
|
hwndCtl = (nBar == SB_CTL) ? hwnd : 0;
|
|
|
|
switch(msg)
|
|
{
|
|
case WM_LBUTTONDOWN: /* Initialise mouse tracking */
|
|
HideCaret(hwnd); /* hide caret while holding down LBUTTON */
|
|
pwndData->SCROLL_trackVertical = vertical;
|
|
pwndData->SCROLL_trackHitTest = hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE );
|
|
lastClickPos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left);
|
|
lastMousePos = lastClickPos;
|
|
trackThumbPos = sbi.xyThumbTop;
|
|
prevPt = pt;
|
|
SetCapture( hwnd );
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, TRUE );
|
|
prevPt = pt;
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
hittest = SCROLL_NOWHERE;
|
|
ReleaseCapture();
|
|
/* if scrollbar has focus, show back caret */
|
|
if (hwnd==GetFocus())
|
|
ShowCaret(hwnd);
|
|
break;
|
|
|
|
case WM_SYSTIMER:
|
|
pt = prevPt;
|
|
hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE );
|
|
break;
|
|
|
|
default:
|
|
return; /* Should never happen */
|
|
}
|
|
|
|
//TRACE("Event: hwnd=%p bar=%d msg=%s pt=%d,%d hit=%d\n",
|
|
// hwnd, nBar, SPY_GetMsgName(msg,hwnd), pt.x, pt.y, hittest );
|
|
|
|
switch(pwndData->SCROLL_trackHitTest)
|
|
{
|
|
case SCROLL_NOWHERE: /* No tracking in progress */
|
|
break;
|
|
|
|
case SCROLL_TOP_ARROW:
|
|
if (hittest == pwndData->SCROLL_trackHitTest)
|
|
{
|
|
SCROLL_DrawArrows( &context, &sbi, vertical, pwndData->SCROLL_trackHitTest, 0 );
|
|
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
|
|
{
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
SB_LINEUP, (LPARAM)hwndCtl );
|
|
}
|
|
|
|
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
|
|
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
|
|
}
|
|
else
|
|
{
|
|
SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 );
|
|
KillSystemTimer( hwnd, SCROLL_TIMER );
|
|
}
|
|
|
|
break;
|
|
|
|
case SCROLL_TOP_RECT:
|
|
SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, pwndData->SCROLL_trackHitTest, 0);
|
|
if (hittest == pwndData->SCROLL_trackHitTest)
|
|
{
|
|
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
|
|
{
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
SB_PAGEUP, (LPARAM)hwndCtl );
|
|
}
|
|
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
|
|
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
|
|
}
|
|
else KillSystemTimer( hwnd, SCROLL_TIMER );
|
|
break;
|
|
|
|
case SCROLL_THUMB:
|
|
if (msg == WM_LBUTTONDOWN)
|
|
{
|
|
pwndData->SCROLL_TrackingWin = hwnd;
|
|
pwndData->SCROLL_TrackingBar = nBar;
|
|
pwndData->SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
|
|
pwndData->SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar,
|
|
vertical, pwndData->SCROLL_TrackingPos );
|
|
if (!pwndData->SCROLL_MovingThumb)
|
|
SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
|
|
}
|
|
else if (msg == WM_LBUTTONUP)
|
|
{
|
|
if (pwndData->SCROLL_MovingThumb)
|
|
SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
|
|
|
|
SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, pwndData->SCROLL_trackHitTest );
|
|
}
|
|
else /* WM_MOUSEMOVE */
|
|
{
|
|
INT pos;
|
|
|
|
if (!SCROLL_PtInRectEx( &sbi.rcScrollBar, pt, vertical ))
|
|
pos = lastClickPos;
|
|
else
|
|
{
|
|
pt = SCROLL_ClipPos( &sbi.rcScrollBar, pt );
|
|
pos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left);
|
|
}
|
|
if ( (pos != lastMousePos) || (!pwndData->SCROLL_MovingThumb) )
|
|
{
|
|
if (pwndData->SCROLL_MovingThumb)
|
|
SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
|
|
lastMousePos = pos;
|
|
pwndData->SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
|
|
pwndData->SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar,
|
|
vertical,
|
|
pwndData->SCROLL_TrackingPos );
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
MAKEWPARAM( SB_THUMBTRACK, pwndData->SCROLL_TrackingVal),
|
|
(LPARAM)hwndCtl );
|
|
if (!pwndData->SCROLL_MovingThumb)
|
|
SCROLL_DrawMovingThumb(pwndData, &context, &sbi, vertical);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SCROLL_BOTTOM_RECT:
|
|
if (hittest == pwndData->SCROLL_trackHitTest)
|
|
{
|
|
SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, pwndData->SCROLL_trackHitTest, 0 );
|
|
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
|
|
{
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
SB_PAGEDOWN, (LPARAM)hwndCtl );
|
|
}
|
|
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
|
|
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
|
|
}
|
|
else
|
|
{
|
|
SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, 0 );
|
|
KillSystemTimer( hwnd, SCROLL_TIMER );
|
|
}
|
|
break;
|
|
|
|
case SCROLL_BOTTOM_ARROW:
|
|
if (hittest == pwndData->SCROLL_trackHitTest)
|
|
{
|
|
SCROLL_DrawArrows( &context, &sbi, vertical, pwndData->SCROLL_trackHitTest, 0 );
|
|
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
|
|
{
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
SB_LINEDOWN, (LPARAM)hwndCtl );
|
|
}
|
|
|
|
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
|
|
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
|
|
}
|
|
else
|
|
{
|
|
SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 );
|
|
KillSystemTimer( hwnd, SCROLL_TIMER );
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (msg == WM_LBUTTONDOWN)
|
|
{
|
|
|
|
if (hittest == SCROLL_THUMB)
|
|
{
|
|
UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical,
|
|
trackThumbPos + lastMousePos - lastClickPos );
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
MAKEWPARAM( SB_THUMBTRACK, val ), (LPARAM)hwndCtl );
|
|
}
|
|
}
|
|
|
|
if (msg == WM_LBUTTONUP)
|
|
{
|
|
hittest = pwndData->SCROLL_trackHitTest;
|
|
pwndData->SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
|
|
|
|
if (hittest == SCROLL_THUMB)
|
|
{
|
|
UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical,
|
|
trackThumbPos + lastMousePos - lastClickPos );
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl );
|
|
}
|
|
/* SB_ENDSCROLL doesn't report thumb position */
|
|
SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
|
|
SB_ENDSCROLL, (LPARAM)hwndCtl );
|
|
|
|
/* Terminate tracking */
|
|
pwndData->SCROLL_TrackingWin = 0;
|
|
}
|
|
|
|
ThemeCleanupDrawContext(&context);
|
|
}
|
|
|
|
static void
|
|
SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt )
|
|
{
|
|
MSG msg;
|
|
PWND_DATA pwndData = ThemeGetWndData(hwnd);
|
|
if(!pwndData)
|
|
return;
|
|
|
|
ScreenToWindow(hwnd, &pt);
|
|
|
|
SCROLL_HandleScrollEvent(pwndData, hwnd, scrollbar, WM_LBUTTONDOWN, pt );
|
|
|
|
do
|
|
{
|
|
if (!GetMessageW( &msg, 0, 0, 0 )) break;
|
|
if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue;
|
|
if (msg.message == WM_LBUTTONUP ||
|
|
msg.message == WM_MOUSEMOVE ||
|
|
(msg.message == WM_SYSTIMER && msg.wParam == SCROLL_TIMER))
|
|
{
|
|
pt.x = GET_X_LPARAM(msg.lParam);
|
|
pt.y = GET_Y_LPARAM(msg.lParam);
|
|
ClientToScreen(hwnd, &pt);
|
|
ScreenToWindow(hwnd, &pt);
|
|
SCROLL_HandleScrollEvent(pwndData, hwnd, scrollbar, msg.message, pt );
|
|
}
|
|
else
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessageW( &msg );
|
|
}
|
|
if (!IsWindow( hwnd ))
|
|
{
|
|
ReleaseCapture();
|
|
break;
|
|
}
|
|
} while (msg.message != WM_LBUTTONUP && GetCapture() == hwnd);
|
|
}
|
|
|
|
void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
|
|
{
|
|
INT scrollbar;
|
|
|
|
if ((wParam & 0xfff0) == SC_HSCROLL)
|
|
{
|
|
if ((wParam & 0x0f) != HTHSCROLL) return;
|
|
scrollbar = SB_HORZ;
|
|
}
|
|
else /* SC_VSCROLL */
|
|
{
|
|
if ((wParam & 0x0f) != HTVSCROLL) return;
|
|
scrollbar = SB_VERT;
|
|
}
|
|
SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
|
|
}
|