diff --git a/dll/win32/uxtheme/CMakeLists.txt b/dll/win32/uxtheme/CMakeLists.txt index 5c9b5152abe..b2bde10c33f 100644 --- a/dll/win32/uxtheme/CMakeLists.txt +++ b/dll/win32/uxtheme/CMakeLists.txt @@ -11,6 +11,7 @@ list(APPEND SOURCE main.c metric.c msstyles.c + ncscrollbar.c nonclient.c property.c stylemap.c diff --git a/dll/win32/uxtheme/ncscrollbar.c b/dll/win32/uxtheme/ncscrollbar.c new file mode 100644 index 00000000000..87e76f9310f --- /dev/null +++ b/dll/win32/uxtheme/ncscrollbar.c @@ -0,0 +1,676 @@ +/* + * 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 +#include "undocuser.h" +#include "vfwmsgs.h" +#include "uxtheme.h" +#include +#include +#include "ncthm.h" +#include +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(uxtheme); + +static BOOL SCROLL_trackVertical; +static enum SCROLL_HITTEST SCROLL_trackHitTest; +/* Is the moving thumb being displayed? */ +static HWND SCROLL_TrackingWin = 0; +static INT SCROLL_TrackingBar = 0; +static INT SCROLL_TrackingPos = 0; +static INT SCROLL_TrackingVal = 0; + +void static 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->xyThumbTop + psbi->dxyLineButton) + 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->xyThumbTop + psbi->dxyLineButton) + 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(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; + + r = psbi->rcScrollBar; + if (vertical) + { + r.top += psbi->dxyLineButton; + r.bottom -= (psbi->dxyLineButton); + } + else + { + r.left += psbi->dxyLineButton; + r.right -= psbi->dxyLineButton; + } + + /* 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; + } + + if (vertical) + { + rcPart = r; + rcPart.bottom = rcPart.top + thumbPos - psbi->dxyLineButton; + SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKVERT, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart); + r.top = rcPart.bottom; + + rcPart = r; + rcPart.top += psbi->dxyLineButton; + SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKVERT, 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 = rcPart.left + thumbPos - psbi->dxyLineButton; + SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKHORZ, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart); + r.left = rcPart.right; + + rcPart = r; + rcPart.left += psbi->dxyLineButton; + SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKHORZ, 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( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi, BOOL vertical) +{ + INT pos = 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->dxyLineButton -SCROLL_ARROW_THUMB_OVERLAP) + psbi->dxyLineButton; + + if( pos < (psbi->dxyLineButton-SCROLL_ARROW_THUMB_OVERLAP) ) + pos = (psbi->dxyLineButton-SCROLL_ARROW_THUMB_OVERLAP); + else if( pos > max_size ) + pos = max_size; + + SCROLL_DrawInterior(pcontext, psbi, pos, vertical, SCROLL_THUMB, 0); + + SCROLL_MovingThumb = !SCROLL_MovingThumb; +} + + +void +ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT nBar, POINT* pt) +{ + BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb; + SCROLLINFO si; + SCROLLBARINFO sbi; + BOOL vertical; + enum SCROLL_HITTEST htHot = SCROLL_NOWHERE; + + /* 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; + } + +#ifndef ROS_SUCKS + /* The scrollbar rect is in screen coordinates */ +// OffsetRect(&sbi.rcScrollBar, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top); +#endif + + if(pt) + { + ScreenToWindow(pcontext->hWnd, pt); + htHot = SCROLL_HitTest(pcontext->hWnd, &sbi, vertical, *pt, FALSE); + } + + if (((nBar == SB_VERT) && !(pcontext->wi.dwStyle & WS_VSCROLL)) || + ((nBar == SB_HORZ) && !(pcontext->wi.dwStyle & WS_HSCROLL))) return; + + /* 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( 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; + } + ThemeInitDrawContext(&context, hwnd, 0); + +#ifndef ROS_SUCKS + /* The scrollbar rect is in screen coordinates */ +// OffsetRect(&sbi.rcScrollBar, -context.wi.rcWindow.left, -context.wi.rcWindow.top); +#endif + + if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) + return; + + 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 */ + SCROLL_trackVertical = vertical; + 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(SCROLL_trackHitTest) + { + case SCROLL_NOWHERE: /* No tracking in progress */ + break; + + case SCROLL_TOP_ARROW: + if (hittest == SCROLL_trackHitTest) + { + SCROLL_DrawArrows( &context, &sbi, vertical, 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, SCROLL_trackHitTest, 0); + if (hittest == 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) + { + SCROLL_TrackingWin = hwnd; + SCROLL_TrackingBar = nBar; + SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos; + SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, + vertical, SCROLL_TrackingPos ); + if (!SCROLL_MovingThumb) + SCROLL_DrawMovingThumb(&context, &sbi, vertical); + } + else if (msg == WM_LBUTTONUP) + { + if (SCROLL_MovingThumb) + SCROLL_DrawMovingThumb(&context, &sbi, vertical); + + SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, 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) || (!SCROLL_MovingThumb) ) + { + if (SCROLL_MovingThumb) + SCROLL_DrawMovingThumb( &context, &sbi, vertical); + lastMousePos = pos; + SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos; + SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, + vertical, + SCROLL_TrackingPos ); + SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL, + MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal), + (LPARAM)hwndCtl ); + if (!SCROLL_MovingThumb) + SCROLL_DrawMovingThumb( &context, &sbi, vertical); + } + } + break; + + case SCROLL_BOTTOM_RECT: + if (hittest == SCROLL_trackHitTest) + { + SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 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 == SCROLL_trackHitTest) + { + SCROLL_DrawArrows( &context, &sbi, vertical, 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 = SCROLL_trackHitTest; + 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 */ + SCROLL_TrackingWin = 0; + } + + ThemeCleanupDrawContext(&context); +} + +static void +SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt ) +{ + MSG msg; + + ScreenToWindow(hwnd, &pt); + + SCROLL_HandleScrollEvent( 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( 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 ); +} diff --git a/dll/win32/uxtheme/ncthm.h b/dll/win32/uxtheme/ncthm.h index 2928670191e..0707e9f7b2f 100644 --- a/dll/win32/uxtheme/ncthm.h +++ b/dll/win32/uxtheme/ncthm.h @@ -4,6 +4,7 @@ typedef struct _DRAW_CONTEXT HWND hWnd; HDC hDC; HTHEME theme; + HTHEME scrolltheme; HTHEME hPrevTheme; WINDOWINFO wi; BOOL Active; /* wi.dwWindowStatus isn't correct for mdi child windows */ @@ -36,6 +37,17 @@ typedef enum { BUTTON_INACTIVE } THEME_BUTTON_STATES; + /* Scroll-bar hit testing */ +enum SCROLL_HITTEST +{ + SCROLL_NOWHERE, /* Outside the scroll bar */ + SCROLL_TOP_ARROW, /* Top or left arrow */ + SCROLL_TOP_RECT, /* Rectangle between the top arrow and the thumb */ + SCROLL_THUMB, /* Thumb rectangle */ + SCROLL_BOTTOM_RECT, /* Rectangle between the thumb and the bottom arrow */ + SCROLL_BOTTOM_ARROW /* Bottom or right arrow */ +}; + #define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \ ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE)) || \ ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \ @@ -48,4 +60,36 @@ typedef enum { #define MENU_BAR_ITEMS_SPACE (12) +#define SCROLL_TIMER 0 /* Scroll timer id */ + + /* Overlap between arrows and thumb */ +#define SCROLL_ARROW_THUMB_OVERLAP 0 + + /* Delay (in ms) before first repetition when holding the button down */ +#define SCROLL_FIRST_DELAY 200 + + /* Delay (in ms) between scroll repetitions */ +#define SCROLL_REPEAT_DELAY 50 + +/* Minimum size of the thumb in pixels */ +#define SCROLL_MIN_THUMB 6 + +/* Minimum size of the rectangle between the arrows */ +#define SCROLL_MIN_RECT 4 + +void +ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT Bar, POINT* pt); + +VOID +NC_TrackScrollBar(HWND Wnd, WPARAM wParam, POINT Pt); + +void +ThemeInitDrawContext(PDRAW_CONTEXT pcontext, + HWND hWnd, + HRGN hRgn); + +void +ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext); + + extern ATOM atWindowTheme; diff --git a/dll/win32/uxtheme/nonclient.c b/dll/win32/uxtheme/nonclient.c index 18b7c7418ff..d86bb9bda14 100644 --- a/dll/win32/uxtheme/nonclient.c +++ b/dll/win32/uxtheme/nonclient.c @@ -156,7 +156,7 @@ HRESULT WINAPI ThemeDrawCaptionText(HTHEME hTheme, HDC hdc, int iPartId, int iSt return S_OK; } -static void +void ThemeInitDrawContext(PDRAW_CONTEXT pcontext, HWND hWnd, HRGN hRgn) @@ -167,6 +167,7 @@ ThemeInitDrawContext(PDRAW_CONTEXT pcontext, pcontext->Active = IsWindowActive(hWnd, pcontext->wi.dwExStyle); pcontext->hPrevTheme = GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWindowTheme)); pcontext->theme = OpenThemeData(pcontext->hWnd, L"WINDOW"); + pcontext->scrolltheme = OpenThemeData(pcontext->hWnd, L"SCROLLBAR"); pcontext->CaptionHeight = pcontext->wi.cyWindowBorders; pcontext->CaptionHeight += GetSystemMetrics(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION ); @@ -180,12 +181,13 @@ ThemeInitDrawContext(PDRAW_CONTEXT pcontext, pcontext->hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN); } -static void +void ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext) { ReleaseDC(pcontext->hWnd ,pcontext->hDC); CloseThemeData (pcontext->theme); + CloseThemeData (pcontext->scrolltheme); SetPropW(pcontext->hWnd, (LPCWSTR)MAKEINTATOM(atWindowTheme), pcontext->hPrevTheme); @@ -628,12 +630,6 @@ ThemeDrawMenuBar(PDRAW_CONTEXT pcontext, PRECT prcCurrent) FillRect(pcontext->hDC, &Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU)); } -static void -ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT Bar) -{ - -} - static void ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent) { @@ -662,10 +658,10 @@ ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent) ThemeDrawMenuBar(pcontext, prcCurrent); if(pcontext->wi.dwStyle & WS_HSCROLL) - ThemeDrawScrollBar(pcontext, OBJID_VSCROLL); + ThemeDrawScrollBar(pcontext, SB_HORZ , NULL); if(pcontext->wi.dwStyle & WS_VSCROLL) - ThemeDrawScrollBar(pcontext, OBJID_HSCROLL); + ThemeDrawScrollBar(pcontext, SB_VERT, NULL); } /* @@ -690,7 +686,7 @@ ThemeHandleNCPaint(HWND hWnd, HRGN hRgn) } static LRESULT -ThemeHandleNcMouseMove(HWND hWnd, DWORD ht) +ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt) { DRAW_CONTEXT context; TRACKMOUSEEVENT tme; @@ -708,6 +704,13 @@ ThemeHandleNcMouseMove(HWND hWnd, DWORD ht) ThemeInitDrawContext(&context, hWnd, 0); ThemeDrawCaptionButtons(&context, ht, 0); + + if(context.wi.dwStyle & WS_HSCROLL) + ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL); + + if(context.wi.dwStyle & WS_VSCROLL) + ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL); + ThemeCleanupDrawContext(&context); return 0; @@ -720,6 +723,13 @@ ThemeHandleNcMouseLeave(HWND hWnd) ThemeInitDrawContext(&context, hWnd, 0); ThemeDrawCaptionButtons(&context, 0, 0); + + if(context.wi.dwStyle & WS_HSCROLL) + ThemeDrawScrollBar(&context, SB_HORZ, NULL); + + if(context.wi.dwStyle & WS_VSCROLL) + ThemeDrawScrollBar(&context, SB_VERT, NULL); + ThemeCleanupDrawContext(&context); return 0; @@ -1021,7 +1031,12 @@ ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndPr ThemeHandleNCPaint(hWnd, (HRGN)1); return TRUE; case WM_NCMOUSEMOVE: - return ThemeHandleNcMouseMove(hWnd, wParam); + { + POINT Point; + Point.x = GET_X_LPARAM(lParam); + Point.y = GET_Y_LPARAM(lParam); + return ThemeHandleNcMouseMove(hWnd, wParam, &Point); + } case WM_NCMOUSELEAVE: return ThemeHandleNcMouseLeave(hWnd); case WM_NCLBUTTONDOWN: @@ -1044,6 +1059,21 @@ ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndPr Point.y = GET_Y_LPARAM(lParam); return DefWndNCHitTest(hWnd, Point); } + case WM_SYSCOMMAND: + { + if((wParam & 0xfff0) == SC_VSCROLL || + (wParam & 0xfff0) == SC_HSCROLL) + { + POINT Pt; + Pt.x = (short)LOWORD(lParam); + Pt.y = (short)HIWORD(lParam); + NC_TrackScrollBar(hWnd, wParam, Pt); + } + else + { + return DefWndProc(hWnd, Msg, wParam, lParam); + } + } case WM_NCUAHDRAWCAPTION: case WM_NCUAHDRAWFRAME: /* FIXME: how should these be handled? */