[uxtheme]
authorGiannis Adamopoulos <gadamopoulos@reactos.org>
Mon, 11 Jul 2011 22:29:33 +0000 (22:29 +0000)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Mon, 11 Jul 2011 22:29:33 +0000 (22:29 +0000)
- Implement drawing non client scrollbars. This code is heavily based on code from wine and modified properly to use themes

svn path=/branches/GSoC_2011/ThemesSupport/; revision=52645

dll/win32/uxtheme/CMakeLists.txt
dll/win32/uxtheme/ncscrollbar.c [new file with mode: 0644]
dll/win32/uxtheme/ncthm.h
dll/win32/uxtheme/nonclient.c

index 5c9b515..b2bde10 100644 (file)
@@ -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 (file)
index 0000000..87e76f9
--- /dev/null
@@ -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 <windows.h>
+#include "undocuser.h"
+#include "vfwmsgs.h"
+#include "uxtheme.h"
+#include <tmschema.h>
+#include <Windowsx.h>
+#include "ncthm.h"
+#include <assert.h>
+#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 );
+}
index 2928670..0707e9f 100644 (file)
@@ -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;
index 18b7c74..d86bb9b 100644 (file)
@@ -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? */