⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scrollbar.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id $
 *
 * ReactOS User32 Library
 * - ScrollBar control
 *
 * Copyright 2001 Casper S. Hornstrup
 * Copyright 2003 Thomas Weidenmueller
 * Copyright 2003 Filip Navara
 *
 * Based on Wine code.
 *
 * Copyright 1993 Martin Ayotte
 * Copyright 1994, 1996 Alexandre Julliard
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; see the file COPYING.LIB.
 * If not, write to the Free Software Foundation,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* INCLUDES *******************************************************************/

#include <user32.h>

#include <wine/debug.h>


/* GLOBAL VARIABLES ***********************************************************/

/* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */
#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 */

#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 */

#define SCROLL_TIMER   0                /* Scroll timer id */

  /* Minimum size of the rectangle between the arrows */
#define SCROLL_MIN_RECT  4

  /* Minimum size of the thumb in pixels */
#define SCROLL_MIN_THUMB 6

 /* Thumb-tracking info */
static HWND ScrollTrackingWin = 0;
static INT  ScrollTrackingBar = 0;
static INT  ScrollTrackingPos = 0;
static INT  ScrollTrackingVal = 0;
static BOOL ScrollMovingThumb = FALSE;

static DWORD ScrollTrackHitTest = SCROLL_NOWHERE;
static BOOL ScrollTrackVertical;

HBRUSH DefWndControlColor(HDC hDC, UINT ctlType);

static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );

UINT STDCALL SetSystemTimer(HWND,UINT_PTR,UINT,TIMERPROC);
BOOL STDCALL KillSystemTimer(HWND,UINT_PTR);

/*********************************************************************
 * scrollbar class descriptor
 */
const struct builtin_class_descr SCROLL_builtin_class =
{
    L"ScrollBar",           /* name */
    CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style */
    ScrollBarWndProc,       /* procW */
    NULL,                   /* procA (winproc is Unicode only) */
    0,                      /* extra */
    IDC_ARROW,              /* cursor */
    0                       /* brush */
};

/* PRIVATE FUNCTIONS **********************************************************/


static void
IntDrawScrollInterior(HWND hWnd, HDC hDC, INT nBar, BOOL Vertical,
   PSCROLLBARINFO ScrollBarInfo)
{
   INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
   INT ThumbTop = ScrollBarInfo->xyThumbTop;
   RECT Rect;
   HPEN hSavePen;
   HBRUSH hSaveBrush, hBrush;
   BOOL TopSelected = FALSE, BottomSelected = FALSE;

   if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
      TopSelected = TRUE;
   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
      BottomSelected = TRUE;

   /*
    * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
    * The window-owned scrollbars need to call DefWndControlColor
    * to correctly setup default scrollbar colors
    */
   if (nBar == SB_CTL)
   {
      hBrush = (HBRUSH)SendMessageW(GetParent(hWnd), WM_CTLCOLORSCROLLBAR, (WPARAM)hDC, (LPARAM)hWnd);
      if (!hBrush)
         hBrush = GetSysColorBrush(COLOR_SCROLLBAR);
   }
   else
   {
      hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
   }

   hSavePen = SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
   hSaveBrush = SelectObject(hDC, hBrush);

   /* Calculate the scroll rectangle */
   if (Vertical)
   {
      Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
      Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
      Rect.left = ScrollBarInfo->rcScrollBar.left;
      Rect.right = ScrollBarInfo->rcScrollBar.right;
   }
   else
   {
      Rect.top = ScrollBarInfo->rcScrollBar.top;
      Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
      Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
      Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
   }

   /* Draw the scroll rectangles and thumb */
   if (!ScrollBarInfo->xyThumbBottom)
   {
      PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
         Rect.bottom - Rect.top, PATCOPY);

      /* Cleanup and return */
      SelectObject(hDC, hSavePen);
      SelectObject(hDC, hSaveBrush);
      return;
   }

   ThumbTop -= ScrollBarInfo->dxyLineButton;

   if (ScrollBarInfo->dxyLineButton)
   {
      if (Vertical)
      {
         if (ThumbSize)
         {
            PatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
                   ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
            Rect.top += ThumbTop;
            PatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
               Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
            Rect.bottom = Rect.top + ThumbSize;
         }
         else
         {
            if (ThumbTop)
            {
               PatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
                  Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
            }
         }
      }
      else
      {
         if (ThumbSize)
         {
            PatBlt(hDC, Rect.left, Rect.top, ThumbTop,
               Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
            Rect.left += ThumbTop;
            PatBlt(hDC, Rect.left + ThumbSize, Rect.top,
               Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
               BottomSelected ? BLACKNESS : PATCOPY);
            Rect.right = Rect.left + ThumbSize;
         }
         else
         {
            if (ThumbTop)
            {
               PatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
                  Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
            }
         }
      }
   }

   /* Draw the thumb */
   if (ThumbSize)
      DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);

   /* Cleanup */
   SelectObject(hDC, hSavePen);
   SelectObject(hDC, hSaveBrush);
}

static VOID FASTCALL
IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
{
  RECT RectLT, RectRB;
  INT ScrollDirFlagLT, ScrollDirFlagRB;

  RectLT = RectRB = ScrollBarInfo->rcScrollBar;
  if (Vertical)
    {
      ScrollDirFlagLT = DFCS_SCROLLUP;
      ScrollDirFlagRB = DFCS_SCROLLDOWN;
      RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
      RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
    }
   else
    {
      ScrollDirFlagLT = DFCS_SCROLLLEFT;
      ScrollDirFlagRB = DFCS_SCROLLRIGHT;
      RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
      RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
    }

   if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
     {
       ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
     }
   if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
     {
       ScrollDirFlagLT |= DFCS_INACTIVE;
     }
   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
     {
       ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
     }
   if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
     {
       ScrollDirFlagRB |= DFCS_INACTIVE;
     }

   DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
   DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
}

static VOID FASTCALL
IntScrollDrawMovingThumb(HDC Dc, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
{
  INT Pos = ScrollTrackingPos;
  INT MaxSize;
  INT OldTop;

  if (Vertical)
    {
      MaxSize = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->rcScrollBar.top;
    }
  else
    {
      MaxSize = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->rcScrollBar.left;
    }

  MaxSize -= ScrollBarInfo->dxyLineButton + ScrollBarInfo->xyThumbBottom
             - ScrollBarInfo->xyThumbTop;

  if (Pos < ScrollBarInfo->dxyLineButton)
    {
      Pos = ScrollBarInfo->dxyLineButton;
    }
  else if (MaxSize < Pos)
    {
      Pos = MaxSize;
    }

  OldTop = ScrollBarInfo->xyThumbTop;
  ScrollBarInfo->xyThumbBottom = Pos + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
  ScrollBarInfo->xyThumbTop = Pos;
  IntDrawScrollInterior(ScrollTrackingWin, Dc, ScrollTrackingBar, Vertical, ScrollBarInfo);
  ScrollBarInfo->xyThumbBottom = OldTop + ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
  ScrollBarInfo->xyThumbTop = OldTop;

  ScrollMovingThumb = ! ScrollMovingThumb;
}

static LONG FASTCALL
IntScrollGetObjectId(INT SBType)
{
  if (SB_VERT == SBType)
    {
      return OBJID_VSCROLL;
    }
  if (SB_HORZ == SBType)
    {
      return OBJID_HSCROLL;
    }

  return OBJID_CLIENT;
}

static BOOL FASTCALL
IntGetScrollBarInfo(HWND Wnd, INT Bar, PSCROLLBARINFO ScrollBarInfo)
{
  ScrollBarInfo->cbSize = sizeof(SCROLLBARINFO);

  return NtUserGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), ScrollBarInfo);
}

void
IntDrawScrollBar(HWND Wnd, HDC DC, INT Bar)
{
  INT ThumbSize;
  SCROLLBARINFO Info;
  BOOL Vertical;

  /*
   * Get scroll bar info.
   */
  switch (Bar)
    {
      case SB_HORZ:
        Vertical = FALSE;
        break;

      case SB_VERT:
        Vertical = TRUE;
        break;

      case SB_CTL:
        Vertical = (GetWindowLongW(Wnd, GWL_STYLE) & SBS_VERT) != 0;
        break;

      default:
        return;
    }
  if (! IntGetScrollBarInfo(Wnd, Bar, &Info))
    {
      return;
    }

  if (IsRectEmpty(&Info.rcScrollBar))
    {
      return;
    }

  ThumbSize = Info.xyThumbBottom - Info.xyThumbTop;

  /*
   * Draw the arrows.
   */
  if (Info.dxyLineButton)
    {
      IntDrawScrollArrows(DC, &Info, Vertical);
    }

  /*
   * Draw the interior.
   */
  IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);

  /*
   * If scroll bar has focus, reposition the caret.
   */
  if (Wnd == GetFocus() && SB_CTL == Bar)
    {
      if (Vertical)
        {
          SetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
        }
      else
        {
           SetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
        }
    }
}

static BOOL FASTCALL
IntScrollPtInRectEx(LPRECT Rect, POINT Pt, BOOL Vertical)
{
  RECT TempRect = *Rect;
  if (Vertical)
    {
      TempRect.left -= Rect->right - Rect->left;
      TempRect.right += Rect->right - Rect->left;
    }
   else
    {
      TempRect.top -= Rect->bottom - Rect->top;
      TempRect.bottom += Rect->bottom - Rect->top;
    }

   return PtInRect(&TempRect, Pt);
}

static DWORD FASTCALL
IntScrollHitTest(PSCROLLBARINFO ScrollBarInfo, BOOL Vertical, POINT Pt, BOOL Dragging)
{
  INT ArrowSize, ThumbSize, ThumbPos;

  if ((Dragging && ! IntScrollPtInRectEx(&ScrollBarInfo->rcScrollBar, Pt, Vertical)) ||
      ! PtInRect(&ScrollBarInfo->rcScrollBar, Pt))
    {
      return SCROLL_NOWHERE;
    }

  ThumbPos = ScrollBarInfo->xyThumbTop;
  ThumbSize = ScrollBarInfo->xyThumbBottom - ThumbPos;
  ArrowSize = ScrollBarInfo->dxyLineButton;

  if (Vertical)
    {
      if (Pt.y < ScrollBarInfo->rcScrollBar.top + ArrowSize)
        {
          return SCROLL_TOP_ARROW;
        }
      if (ScrollBarInfo->rcScrollBar.bottom - ArrowSize <= Pt.y)
        {
          return SCROLL_BOTTOM_ARROW;
        }
      if (0 == ThumbPos)
        {
          return SCROLL_TOP_RECT;
        }
      Pt.y -= ScrollBarInfo->rcScrollBar.top;
      if (Pt.y < ThumbPos)
        {
          return SCROLL_TOP_RECT;
        }
      if (ThumbPos + ThumbSize <= Pt.y)
        {
          return SCROLL_BOTTOM_RECT;
        }
    }
  else
    {
      if (Pt.x < ScrollBarInfo->rcScrollBar.left + ArrowSize)
        {
          return SCROLL_TOP_ARROW;
        }
      if (ScrollBarInfo->rcScrollBar.right - ArrowSize <= Pt.x)
        {
          return SCROLL_BOTTOM_ARROW;
        }
      if (0 == ThumbPos)
        {
          return SCROLL_TOP_RECT;
        }
      Pt.x -= ScrollBarInfo->rcScrollBar.left;
      if (Pt.x < ThumbPos)
        {
          return SCROLL_TOP_RECT;
        }
      if (ThumbPos + ThumbSize <= Pt.x)
        {
          return SCROLL_BOTTOM_RECT;
        }
    }

  return SCROLL_THUMB;
}


/***********************************************************************
 *           IntScrollGetScrollBarRect
 *
 * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
 * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
 * 'arrowSize' returns the width or height of an arrow (depending on
 * the orientation of the scrollbar), 'thumbSize' returns the size of
 * the thumb, and 'thumbPos' returns the position of the thumb
 * relative to the left or to the top.
 * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
 */
static BOOL FASTCALL
IntScrollGetScrollBarRect(HWND Wnd, INT Bar, RECT *Rect,
                          INT *ArrowSize, INT *ThumbSize,
                          INT *ThumbPos)
{
  INT Pixels;
  BOOL Vertical;
  RECT ClientRect;
  RECT WindowRect;
  DWORD Style, ExStyle;

  GetClientRect(Wnd, &ClientRect);
  if (SB_HORZ == Bar || SB_VERT == Bar)
    {
      ClientToScreen(Wnd, (LPPOINT) &ClientRect.left);
      ClientToScreen(Wnd, (LPPOINT) &ClientRect.right);
      GetWindowRect(Wnd, &WindowRect);
    }
  Style = GetWindowLongW(Wnd, GWL_STYLE);

  switch (Bar)
    {
      case SB_HORZ:
        Rect->left   = ClientRect.left - WindowRect.left;
        Rect->top    = ClientRect.bottom - WindowRect.top;
        Rect->right  = ClientRect.right - WindowRect.left;
        Rect->bottom = Rect->top + GetSystemMetrics(SM_CYHSCROLL);
	if (0 != (Style & WS_BORDER))
          {
            Rect->left--;
            Rect->right++;
	  }
        else if (0 != (Style & WS_VSCROLL))
          {
            Rect->right++;
          }
        Vertical = FALSE;
	break;

      case SB_VERT:
        ExStyle = GetWindowLongW(Wnd, GWL_EXSTYLE);
        if (0 != (ExStyle & WS_EX_LEFTSCROLLBAR))
          {
            Rect->left   = ClientRect.left - WindowRect.left - GetSystemMetrics(SM_CXVSCROLL);
          }
        else
          {
            Rect->left   = ClientRect.right - WindowRect.left;
          }
        Rect->top    = ClientRect.top - WindowRect.top;
        Rect->right  = Rect->left + GetSystemMetrics(SM_CXVSCROLL);
        Rect->bottom = ClientRect.bottom - WindowRect.top;
	if (0 != (Style & WS_BORDER))
          {
            Rect->top--;
            Rect->bottom++;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -