reactos/dll/win32/uxtheme/ncscrollbar.c
2024-02-13 21:20:49 +01:00

689 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;
}
}
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
ThemeDrawScrollBarEx(PDRAW_CONTEXT pcontext, INT nBar, PSCROLLBARINFO psbi, POINT* pt)
{
SCROLLINFO si;
BOOL vertical;
enum SCROLL_HITTEST htHot = SCROLL_NOWHERE;
PWND_DATA pwndData;
if (!(pwndData = ThemeGetWndData(pcontext->hWnd)))
return;
if (pwndData->SCROLL_TrackingWin)
return;
/* Retrieve scrollbar info */
si.cbSize = sizeof(si);
si.fMask = SIF_ALL ;
GetScrollInfo(pcontext->hWnd, nBar, &si);
vertical = SCROLL_IsVertical(pcontext->hWnd, nBar);
if(psbi->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE &&
psbi->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE )
{
psbi->xyThumbTop = 0;
}
/* The scrollbar rect is in screen coordinates */
OffsetRect(&psbi->rcScrollBar, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top);
if(pt)
{
ScreenToWindow(pcontext->hWnd, pt);
htHot = SCROLL_HitTest(pcontext->hWnd, psbi, vertical, *pt, FALSE);
}
/* do not draw if the scrollbar rectangle is empty */
if(IsRectEmpty(&psbi->rcScrollBar)) return;
/* Draw the scrollbar */
SCROLL_DrawArrows( pcontext, psbi, vertical, 0, htHot );
SCROLL_DrawInterior( pcontext, psbi, psbi->xyThumbTop, vertical, 0, htHot );
}
void
ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT nBar, POINT* pt)
{
SCROLLBARINFO sbi;
if (((nBar == SB_VERT) && !(pcontext->wi.dwStyle & WS_VSCROLL)) ||
((nBar == SB_HORZ) && !(pcontext->wi.dwStyle & WS_HSCROLL)))
{
return;
}
sbi.cbSize = sizeof(sbi);
GetScrollBarInfo(pcontext->hWnd, SCROLL_getObjectId(nBar), &sbi);
ThemeDrawScrollBarEx(pcontext, nBar, &sbi, pt);
}
/***********************************************************************
* 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 );
}