update for HEAD-2003091401
[reactos.git] / lib / user32 / controls / scrollbar.c
index 5ee30a4..935871a 100644 (file)
@@ -5,6 +5,7 @@
  * PURPOSE:          Windows
  * FILE:             subsys/win32k/ntuser/window.c
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *                   Thomas Weidenmueller (w3seek@users.sourceforge.net)
  * REVISION HISTORY:
  *       06-06-2001  CSH  Created
  */
@@ -13,6 +14,9 @@
 #include <windows.h>
 #include <user32.h>
 #include <debug.h>
+#include <draw.h>
+#include <stdlib.h>
+#include <string.h>
 
 /* GLOBAL VARIABLES **********************************************************/
 /*
@@ -38,7 +42,6 @@ static HBITMAP hRgArrowI;
 #define RIGHT_ARROW(flags,pressed) \
    (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow))
 
-#define SCROLL_ARROW_THUMB_OVERLAP 0     /* Overlap between arrows and thumb */
 #define SCROLL_MIN_THUMB 6               /* Minimum size of the thumb in pixels */
 #define SCROLL_FIRST_DELAY   200         /* Delay (in ms) before first repetition when holding the button down */
 #define SCROLL_REPEAT_DELAY  50          /* Delay (in ms) between scroll repetitions */
@@ -50,16 +53,13 @@ static HBITMAP hRgArrowI;
 #define SA_SSI_REFRESH         0x0004
 #define SA_SSI_REPAINT_ARROWS  0x0008
 
-  /* 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 */
-};
+/* Scroll-bar hit testing */
+#define SCROLL_NOWHERE  0x00    /* Outside the scroll bar */
+#define SCROLL_TOP_ARROW    0x01    /* Top or left arrow */
+#define SCROLL_TOP_RECT 0x02    /* Rectangle between the top arrow and the thumb */
+#define SCROLL_THUMB    0x03    /* Thumb rectangle */
+#define SCROLL_BOTTOM_RECT  0x04    /* Rectangle between the thumb and the bottom arrow */
+#define SCROLL_BOTTOM_ARROW 0x05    /* Bottom or right arrow */
 
 static BOOL SCROLL_MovingThumb = FALSE; /* Is the moving thumb being displayed? */
 
@@ -68,24 +68,12 @@ static HWND SCROLL_TrackingWin = 0;
 static INT SCROLL_TrackingBar = 0;
 static INT SCROLL_TrackingPos = 0;
 /* static INT  SCROLL_TrackingVal = 0; */
-static enum SCROLL_HITTEST SCROLL_trackHitTest; /* Hit test code of the last button-down event */
+static DWORD SCROLL_trackHitTest; /* Hit test code of the last button-down event */
 static BOOL SCROLL_trackVertical;
 
-/* FUNCTIONS
-*****************************************************************/
+/* INTERNAL FUNCTIONS *********************************************************/
 
 HBRUSH DefWndControlColor (HDC hDC, UINT ctlType);
-HPEN STDCALL GetSysColorPen (int nIndex);
-
-
-
-WINBOOL STDCALL
-GetScrollBarInfo (HWND hwnd, LONG idObject, PSCROLLBARINFO psbi)
-{
-  int ret = NtUserGetScrollBarInfo (hwnd, idObject, psbi);
-
-  return ret;
-}
 
 /* Ported from WINE20020904 */
 /* Draw the scroll bar interior (everything except the arrows). */
@@ -94,15 +82,16 @@ SCROLL_DrawInterior (HWND hwnd, HDC hdc, INT nBar, BOOL vertical, INT
 arrowSize, PSCROLLBARINFO psbi)
 {
   INT thumbSize = psbi->xyThumbBottom - psbi->xyThumbTop;
+  RECT rc;
   HPEN hSavePen;
   HBRUSH hSaveBrush, hBrush;
   BOOLEAN top_selected = FALSE, bottom_selected = FALSE;
 DbgPrint("[SCROLL_DrawInterior:%d]\n", nBar);
-  if(psbi->rgstate[2] & STATE_SYSTEM_PRESSED)
+  if(psbi->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
   {
     top_selected = TRUE;
   }
-  if(psbi->rgstate[4] & STATE_SYSTEM_PRESSED)
+  if(psbi->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
   {
     bottom_selected = TRUE;
   }
@@ -114,6 +103,8 @@ DbgPrint("[SCROLL_DrawInterior:%d]\n", nBar);
   if ( nBar == SB_CTL )
   {
     hBrush = (HBRUSH) NtUserSendMessage (GetParent (hwnd), WM_CTLCOLORSCROLLBAR, (WPARAM) hdc, (LPARAM) hwnd);
+    if(!hBrush)
+      hBrush = GetSysColorBrush(COLOR_SCROLLBAR);
   }
   else
   {
@@ -128,23 +119,27 @@ DbgPrint("[SCROLL_DrawInterior:%d]\n", nBar);
   /* Calculate the scroll rectangle */
   if (vertical)
   {
-    psbi->rcScrollBar.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-    psbi->rcScrollBar.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+    rc.top = psbi->rcScrollBar.top + arrowSize;
+    rc.bottom = psbi->rcScrollBar.bottom - arrowSize;
+    rc.left = psbi->rcScrollBar.left;
+    rc.right = psbi->rcScrollBar.right;
   }
   else
   {
-    psbi->rcScrollBar.left += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-    psbi->rcScrollBar.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+    rc.top = psbi->rcScrollBar.top;
+    rc.bottom = psbi->rcScrollBar.bottom;
+    rc.left = psbi->rcScrollBar.left + arrowSize;
+    rc.right = psbi->rcScrollBar.right - arrowSize;
   }
 
   /* Draw the scroll rectangles and thumb */
-  if (!psbi->dxyLineButton)            /* No thumb to draw */
+  if (!psbi->xyThumbBottom)            /* No thumb to draw */
   {
     PatBlt (hdc,
-            psbi->rcScrollBar.left,
-            psbi->rcScrollBar.top,
-            psbi->rcScrollBar.right - psbi->rcScrollBar.left,
-            psbi->rcScrollBar.bottom - psbi->rcScrollBar.top,
+            rc.left,
+            rc.top,
+            rc.right - rc.left,
+            rc.bottom - rc.top,
             PATCOPY);
 
     /* cleanup and return */
@@ -152,44 +147,46 @@ DbgPrint("[SCROLL_DrawInterior:%d]\n", nBar);
     SelectObject (hdc, hSaveBrush);
     return;
   }
+  
+  psbi->xyThumbTop -= arrowSize;
 
   if (vertical)
   {
     PatBlt (hdc,
-            psbi->rcScrollBar.left,
-            psbi->rcScrollBar.top,
-            psbi->rcScrollBar.right - psbi->rcScrollBar.left,
-            psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
+            rc.left,
+            rc.top,
+            rc.right - rc.left,
+            psbi->dxyLineButton,
             top_selected ? 0x0f0000 : PATCOPY);
-    psbi->rcScrollBar.top += psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+    rc.top += psbi->xyThumbTop;
     PatBlt (hdc,
-            psbi->rcScrollBar.left,
-            psbi->rcScrollBar.top + thumbSize,
-            psbi->rcScrollBar.right - psbi->rcScrollBar.left,
-            psbi->rcScrollBar.bottom - psbi->rcScrollBar.top - thumbSize,
+            rc.left,
+            rc.top + thumbSize,
+            rc.right - rc.left,
+            rc.bottom - rc.top - thumbSize,
             bottom_selected ? 0x0f0000 : PATCOPY);
-    psbi->rcScrollBar.bottom = psbi->rcScrollBar.top + thumbSize;
+    rc.bottom = rc.top + thumbSize;
   }
   else
   {
     PatBlt (hdc,
-            psbi->rcScrollBar.left,
-            psbi->rcScrollBar.top,
-            psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
-            psbi->rcScrollBar.bottom - psbi->rcScrollBar.top,
+            rc.left,
+            rc.top,
+            psbi->xyThumbTop,
+            rc.bottom - rc.top,
             top_selected ? 0x0f0000 : PATCOPY);
-    psbi->rcScrollBar.left += psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+    rc.left += psbi->xyThumbTop;
     PatBlt (hdc,
-            psbi->rcScrollBar.left + thumbSize,
-            psbi->rcScrollBar.top,
-            psbi->rcScrollBar.right - psbi->rcScrollBar.left - thumbSize,
-            psbi->rcScrollBar.bottom - psbi->rcScrollBar.top,
+            rc.left + thumbSize,
+            rc.top,
+            rc.right - rc.left - thumbSize,
+            rc.bottom - rc.top,
             bottom_selected ? 0x0f0000 : PATCOPY);
-    psbi->rcScrollBar.right = psbi->rcScrollBar.left + thumbSize;
+    rc.right = rc.left + thumbSize;
   }
 
   /* Draw the thumb */
-  DrawEdge (hdc, &psbi->rcScrollBar, EDGE_RAISED, BF_RECT | BF_MIDDLE);
+  DrawEdge (hdc, &rc, EDGE_RAISED, BF_RECT | BF_MIDDLE);
 
   /* cleanup */
   SelectObject (hdc, hSavePen);
@@ -208,10 +205,10 @@ SCROLL_DrawMovingThumb (HDC hdc, RECT * rect, BOOL vertical, int arrowSize, int
   else
     max_size = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
 
-  max_size -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + thumbSize;
+  max_size -= arrowSize + thumbSize;
 
-  if (pos < (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
-    pos = (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
+  if (pos < arrowSize)
+    pos = arrowSize;
   else if (pos > max_size)
     pos = max_size;
 
@@ -269,20 +266,20 @@ SCROLL_DrawScrollBar (HWND hwnd, HDC hdc, INT nBar,
   BOOL vertical;
 
   info.cbSize = sizeof(SCROLLBARINFO);
-  GetScrollBarInfo (hwnd, nBar, &info);
-
-  thumbSize = info.xyThumbBottom - info.xyThumbTop;
 
   switch ( nBar )
   {
   case SB_HORZ:
     vertical = FALSE;
+    NtUserGetScrollBarInfo (hwnd, OBJID_HSCROLL, &info);
     break;
   case SB_VERT:
     vertical = TRUE;
+    NtUserGetScrollBarInfo (hwnd, OBJID_VSCROLL, &info);
     break;
   case SB_CTL:
-    vertical = (GetWindowLong(hwnd,GWL_STYLE)&SBS_VERT) != 0;
+    vertical = (GetWindowLongW(hwnd,GWL_STYLE)&SBS_VERT) != 0;
+    NtUserGetScrollBarInfo (hwnd, OBJID_CLIENT, &info);
     break;
 #ifdef DBG
   default:
@@ -290,6 +287,8 @@ SCROLL_DrawScrollBar (HWND hwnd, HDC hdc, INT nBar,
     break;
 #endif /* DBG */
   }
+  
+  thumbSize = info.xyThumbBottom - info.xyThumbTop;
 
   if (vertical)
     arrowSize = GetSystemMetrics(SM_CXVSCROLL);
@@ -343,53 +342,262 @@ END:;
 /*    WIN_ReleaseWndPtr(wndPtr); */
 }
 
+static BOOL 
+SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
+{
+  RECT rect = *lpRect;
+
+  if (vertical)
+  {
+    rect.left -= lpRect->right - lpRect->left;
+    rect.right += lpRect->right - lpRect->left;
+  }
+  else
+  {
+    rect.top -= lpRect->bottom - lpRect->top;
+    rect.bottom += lpRect->bottom - lpRect->top;
+  }
+  return PtInRect( &rect, pt );
+}
+
+DWORD
+SCROLL_HitTest( HWND hwnd, INT nBar, POINT pt, BOOL bDragging )
+{
+  SCROLLBARINFO sbi;
+  RECT wndrect;
+  INT arrowSize, thumbSize, thumbPos;
+  BOOL vertical = (nBar == SB_VERT); /* FIXME - ((Window->Style & SBS_VERT) != 0) */
+  
+  NtUserGetWindowRect(hwnd, &wndrect);
+  
+  sbi.cbSize = sizeof(SCROLLBARINFO);
+  NtUserGetScrollBarInfo(hwnd, vertical ? OBJID_VSCROLL : OBJID_HSCROLL, &sbi);
+  
+  OffsetRect(&sbi.rcScrollBar, wndrect.left, wndrect.top);
+
+  if ( (bDragging && !SCROLL_PtInRectEx( &sbi.rcScrollBar, pt, vertical )) ||
+       (!PtInRect( &sbi.rcScrollBar, pt )) ) return SCROLL_NOWHERE;
+
+  thumbPos = sbi.xyThumbTop;
+  thumbSize = sbi.xyThumbBottom - thumbPos;
+  arrowSize = sbi.dxyLineButton;
+
+  if (vertical) 
+  {
+    if (pt.y < sbi.rcScrollBar.top + arrowSize) return SCROLL_TOP_ARROW;
+    if (pt.y >= sbi.rcScrollBar.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
+    if (!thumbPos) return SCROLL_TOP_RECT;
+      pt.y -= sbi.rcScrollBar.top;
+    if (pt.y < thumbPos) return SCROLL_TOP_RECT;
+    if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
+  }
+  else  /* horizontal */
+  {
+    if (pt.x < sbi.rcScrollBar.left + arrowSize) return SCROLL_TOP_ARROW;
+    if (pt.x >= sbi.rcScrollBar.right - arrowSize) return SCROLL_BOTTOM_ARROW;
+    if (!thumbPos) return SCROLL_TOP_RECT;
+    pt.x -= sbi.rcScrollBar.left;
+    if (pt.x < thumbPos) return SCROLL_TOP_RECT;
+    if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
+  }
+  return SCROLL_THUMB;
+}
+
+
+/* FUNCTIONS ******************************************************************/
+
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+EnableScrollBar(HWND hWnd, UINT wSBflags, UINT wArrows)
+{
+  return NtUserEnableScrollBar(hWnd, wSBflags, wArrows);
+}
+
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+GetScrollBarInfo(HWND hwnd, LONG idObject, PSCROLLBARINFO psbi)
+{
+  SCROLLBARINFO sbi;
+  WINBOOL ret;
+  
+  if(!psbi)
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+  }
+  
+  RtlCopyMemory(&sbi, psbi, sizeof(SCROLLBARINFO));
+  ret = NtUserGetScrollBarInfo (hwnd, idObject, psbi);
+  if(ret)
+  {
+    RtlCopyMemory(psbi, &sbi, sizeof(SCROLLBARINFO));
+  }
+
+  return ret;
+}
+
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 GetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+  WINBOOL res;
+  SCROLLINFO si;
+  
+  if(!lpsi || 
+     ((lpsi->cbSize != sizeof(SCROLLINFO)) && (lpsi->cbSize != sizeof(SCROLLINFO) - sizeof(si.nTrackPos))))
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return 0;
+  }
+  
+  RtlZeroMemory(&si, sizeof(SCROLLINFO));
+  si.cbSize = lpsi->cbSize;
+  si.fMask = lpsi->fMask;
+  
+  res = (WINBOOL)NtUserGetScrollInfo(hwnd, fnBar, &si);
+  
+  if(res)
+  {
+    RtlCopyMemory(lpsi, &si, lpsi->cbSize);
+  }
+  
+  return res;
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 GetScrollPos (HWND hWnd, int nBar)
 {
-  UNIMPLEMENTED;
-  return 0;
+  SCROLLINFO si;
+  BOOL ret;
+  int res = 0;
+  
+  si.cbSize = sizeof(SCROLLINFO);
+  si.fMask = SIF_POS;
+  ret = NtUserGetScrollInfo(hWnd, nBar, &si);
+  if(ret)
+    res = si.nPos;
+  return res;  
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 GetScrollRange (HWND hWnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+  WINBOOL ret;
+  SCROLLINFO si;
+  
+  if(!lpMinPos || !lpMaxPos)
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+  }
+  
+  si.cbSize = sizeof(SCROLLINFO);
+  si.fMask = SIF_RANGE;
+  ret = NtUserGetScrollInfo(hWnd, nBar, &si);
+  if(ret)
+  {
+    *lpMinPos = si.nMin;
+    *lpMaxPos = si.nMax;
+  }
+  
+  return ret;
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 SetScrollInfo (HWND hwnd, int fnBar, LPCSCROLLINFO lpsi, WINBOOL fRedraw)
 {
-  UNIMPLEMENTED;
-  return 0;
+  SCROLLINFO si;
+  
+  if(!lpsi || 
+     ((lpsi->cbSize != sizeof(SCROLLINFO)) && (lpsi->cbSize != sizeof(SCROLLINFO) - sizeof(si.nTrackPos))))
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return 0;
+  }
+  RtlCopyMemory(&si, lpsi, lpsi->cbSize);
+  return (int)NtUserSetScrollInfo(hwnd, fnBar, &si, fRedraw);
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 SetScrollPos (HWND hWnd, int nBar, int nPos, WINBOOL bRedraw)
 {
-  UNIMPLEMENTED;
-  return 0;
+  int Res = 0;
+  BOOL ret;
+  SCROLLINFO si;
+  
+  si.cbSize = sizeof(SCROLLINFO);
+  si.fMask = SIF_POS;
+  
+  /* call NtUserGetScrollInfo() because we need to return the previous position */
+  ret = NtUserGetScrollInfo(hWnd, nBar, &si);
+  
+  if(ret)
+  {
+    Res = si.nPos;
+    
+    if(Res != nPos)
+    {
+      si.nPos = nPos;
+      /* finally set the new position */
+      NtUserSetScrollInfo(hWnd, nBar, &si, bRedraw);
+    }
+  }
+  
+  return Res;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 SetScrollRange (HWND hWnd,
                int nBar, int nMinPos, int nMaxPos, WINBOOL bRedraw)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+  SCROLLINFO si;
+  
+  si.cbSize = sizeof(SCROLLINFO);
+  si.fMask = SIF_RANGE;
+  si.nMin = nMinPos;
+  si.nMax = nMaxPos;
+  
+  NtUserSetScrollInfo(hWnd, nBar, &si, bRedraw);
+  /* FIXME - check if called successfully */
+  
+  return TRUE;
 }
 
-/* Ported from WINE20020904 */
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 ShowScrollBar (HWND hWnd, int wBar, WINBOOL bShow)
 {
-  NtUserShowScrollBar (hWnd, wBar, bShow);
-  return TRUE;
+  return (WINBOOL)NtUserShowScrollBar (hWnd, wBar, bShow);
 }