滚动条界面

最近做UI的时候,需要更换滚动条的皮肤,主要来源于

http://www.codeproject.com/dialog/coolscroll.asp

 

但由于该类比较复杂,后来又在网上找了个DEMO,由于该DEMO,有些BUG,修改如下:

//
// Module Name  : UISkin scrollbar library version 1.0
// Copyright (C)  LiJun(Chinase) 2006
//
// Descrption   : Implement custom draw internal window of scrollbar 
//
// Email        : Notoldtree@126.com
//
// CREATE DATE  : 2006.10
//
// VERSION HISTORY :
//
// 2008.06
//
//
//
//

//#include "stdafx.h"
#include "internal.h"
#include "skinsb.h"

#define WIN32_LEAN_AND_MEAN


static TCHAR g_szPropSB[] = TEXT("PROP_SkinSB");

// The skin bitmap resourece array
static POINT ptArray[6][6] = {
 { {0,  0}, {19,  0}, {38,  0}, {57,  0}, {76,  0}, {95,  0} },
 { {0, 19}, {19, 19}, {38, 19}, {57, 19}, {76, 19}, {95, 19} },
 { {0, 38}, {19, 38}, {38, 38}, {57, 38}, {76, 38}, {95, 38} },
 { {0, 57}, {19, 57}, {38, 57}, {57, 57}, {76, 57}, {95, 57} },
 { {0, 76}, {19, 76}, {38, 76}, {57, 76}, {76, 76}, {95, 76} },
 { {0, 95}, {19, 95}, {38, 95}, {57, 95}, {76, 95}, {95, 95} }
};


// Public interfaces

//----------------------------------------------------------
// Name : SkinSB_Init()
// Desc : Initialize the skin scrollbar library
//----------------------------------------------------------
BOOL WINAPI SkinSB_Init(HWND hwnd, HBITMAP hBmp, BOOL bListBox)
{
 LPSB    psb;
 DWORD   dwStyle;

 if( !IsWindow(hwnd) ) {
  SetLastError(ERROR_INVALID_HANDLE);
  return FALSE;
 }

 if( SkinSB_IsValid(hwnd) )
  return FALSE;
 
 // Allocates memory
 psb = (LPSB)LocalAlloc(LPTR, sizeof(SB));
 if( psb == NULL )
  return FALSE;

 ZeroMemory(psb, sizeof(SB));

 // ListBox can not execute  ShowScrollBarD
 // add by Richard
 // 2009-2-25
 
 if (bListBox)
 {
  psb->fListBox = TRUE;
 }
 else
 {
  psb->fListBox = FALSE;
 }
 dwStyle = GetWindowLong(hwnd, GWL_STYLE);

 psb->Horz.cbSize = psb->Vert.cbSize = sizeof(SCROLLINFO);
 psb->Horz.fMask  = psb->Vert.fMask  = SIF_ALL;

 if( dwStyle & WS_HSCROLL )
  GetScrollInfo(hwnd, SB_HORZ, &psb->Horz);

 if( dwStyle & WS_VSCROLL )
  GetScrollInfo(hwnd, SB_VERT, &psb->Vert);
 
 // Is left scrollbar style
 if( GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LEFTSCROLLBAR )
  psb->fLeftScrollBar = TRUE;

 if( !hBmp ) {
  SetLastError(ERROR_INVALID_HANDLE);
  return FALSE;
 }

 psb->hBmp = hBmp;

 // Reaplace the window procedure
 psb->hwnd = hwnd;
 psb->pfnOldProc = (WNDPROC)(LONG_PTR)SetWindowLong(hwnd,
  GWL_WNDPROC, (LONG)(LONG_PTR)SkinSB_Proc);

 psb->fPreventStyleChange = FALSE;
 psb->fTracking = FALSE;

 // Whether richedit control
 TCHAR szClassName[255] = { 0 };
 GetClassName(hwnd, szClassName, sizeof(szClassName));
 if( _strcmpi(szClassName, TEXT("RichEdit20A")) == 0 ||
  _strcmpi(szClassName, TEXT("RichEdit20W")) == 0 ||
  _strcmpi(szClassName, TEXT("RICHEDIT")) == 0) { //Add By Qt
  psb->fRichEdit = TRUE;
 }
 
 // Set the window property
 if( !SetProp(hwnd, g_szPropSB, (HANDLE)psb) )
  return FALSE;

 // Redraw the window noclient
 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
            SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);

 return TRUE;
}

//---------------------------------------------------------
// Name : SkinSB_Uninit()
// Desc : Finalize the skin scrollbar library
//---------------------------------------------------------
BOOL WINAPI SkinSB_Uninit(HWND hwnd)
{
 LPSB        psb;
 SCROLLINFO  vsi;
 SCROLLINFO  hsi;
 BOOL        vValid, hValid;
 UINT        vFlags, hFlags;

 if( (psb = SkinSB_GetSB(hwnd)) == NULL )
  return FALSE; 
 
 vsi.cbSize = hsi.cbSize = sizeof(SCROLLINFO);
 vsi.fMask  = hsi.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
 
 vValid = SkinSB_GetScrollInfo(hwnd, SB_VERT, &vsi);
 vFlags = SkinSB_GetDisableFlags(psb, TRUE);
 hValid = SkinSB_GetScrollInfo(hwnd, SB_HORZ, &hsi);
 hFlags = SkinSB_GetDisableFlags(psb, FALSE);

 // Remove the subclass procedure
 SetWindowLong(hwnd, GWL_WNDPROC, (LONG)(LONG_PTR)psb->pfnOldProc);
 RemoveProp(hwnd, g_szPropSB);
 LocalFree((HLOCAL)psb);


 // Restore system scroll parameters
 if( vValid ) {
  SetScrollInfo(hwnd, SB_VERT, &vsi, TRUE);
  EnableScrollBar(hwnd, SB_VERT, vFlags);
 }

 if( hValid ) {
  SetScrollInfo(hwnd, SB_HORZ, &hsi, TRUE);
  EnableScrollBar(hwnd, SB_HORZ, hFlags);
 }

 return TRUE;
}

//---------------------------------------------------------
// Name : SkinSB_IsValid()
// Desc : Is initialized ??
//---------------------------------------------------------
BOOL WINAPI SkinSB_IsValid(HWND hwnd)
{
 return (SkinSB_GetSB(hwnd) != NULL);
}


//---------------------------------------------------------
// Name : SkinSB_GetScrollInfo()
// Desc : Overload API GetScrollInfo()
//---------------------------------------------------------
BOOL WINAPI SkinSB_GetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
{
 LPSB psb;
 LPSCROLLINFO psi;
 BOOL fCopied = FALSE;

 if( !lpsi || lpsi->cbSize != sizeof(SCROLLINFO) )
  return FALSE;

 // Is initialized ?
 if( (psb = SkinSB_GetSB(hwnd)) == NULL )
  return FALSE;

 // If be scrollbar control then call failed
 if( fnBar == SB_HORZ )
  psi = &psb->Horz;
 else if( fnBar == SB_VERT )
  psi = &psb->Vert;
 else if( fnBar == SB_CTL )
  return FALSE;

 if( lpsi->fMask & SIF_PAGE ) {
  lpsi->nPage = psi->nPage;
  fCopied = TRUE;
 }

 if( lpsi->fMask & SIF_POS ) {
  lpsi->nPos  = psi->nPos;
  fCopied = TRUE;
 }

 if( lpsi->fMask & SIF_TRACKPOS ) {
  lpsi->nTrackPos = psi->nTrackPos;
  fCopied = TRUE;
 }

 if( lpsi->fMask & SIF_RANGE ) {
  lpsi->nMin = psi->nMin;
  lpsi->nMax = psi->nMax;
  fCopied = TRUE;
 }

 return fCopied;
}

 


//---------------------------------------------------------
// Name : SkinSB_SetScrollInfo()
// Desc : Overload API SetScrollInfo()
//---------------------------------------------------------
int WINAPI SkinSB_SetScrollInfo(HWND hwnd, int fnBar, LPCSCROLLINFO psi, BOOL fRedraw)
{
 LPSB            psb;
 LPSCROLLINFO    mysi;
 int             nRet;
 DWORD           dwStyle;
 BOOL            fVert;
 UINT            wScroll;
 BOOL            fScroll;
 BOOL            fOldScroll;
 BOOL            bReturnOldPos;

 // if be scrollbar control the call failed
 if( fnBar == SB_CTL )
  return 0;

 if( (psb = SkinSB_GetSB(hwnd)) == NULL )
  return FALSE;

 if( fRedraw )
  fRedraw = IsWindowVisible(hwnd);

 fVert         = (fnBar == SB_VERT);
 bReturnOldPos = (psi->fMask & SIF_POS);
 dwStyle       = GetWindowLong(hwnd, GWL_STYLE);
 wScroll       = fVert ? WS_VSCROLL : WS_HSCROLL;

 fScroll = fOldScroll = (dwStyle & wScroll) ? TRUE : FALSE;
 
 // Don't do anything if we're setting position of a nonexistent scroll bar.
 if( !(psi->fMask & SIF_RANGE) && !fOldScroll )
  return 0;

 mysi = (fVert ? &psb->Vert : &psb->Horz);

 if( !SkinSB_SetSBParms(mysi, *psi, &fScroll, &nRet, bReturnOldPos) &&
  !(psi->fMask & SIF_DISABLENOSCROLL) ) {
  if( fOldScroll && fRedraw )
   goto redrawAfterSet;
  return nRet;
 }
 else
 {
  // ADD BY RICHARD
  // listbox can not exe SkinSB_ShowScrollBar,
  // Scroll bar in accordance with the contents of the distinction between state
  //
 // if (psb->fListBox)
  {
   if(    mysi->nPage >  (UINT)mysi->nMax
    || mysi->nPage == (UINT)mysi->nMax && mysi->nMax == 0
    || mysi->nMax  <= mysi->nMin)
   {
    fScroll = ((int)mysi->nPage <= (mysi->nMax - mysi->nMin));
    if( !fScroll ) {     
     psb->style |= wScroll;
     SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~wScroll);
     SkinSB_EnableArrows(psb, fnBar, fScroll ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
     
    }    
    if( fOldScroll ^ fScroll ) {
     SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
      SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
     return nRet;     
    }
   }
   else
   {
    
    fScroll = ((int)mysi->nPage <= (mysi->nMax - mysi->nMin));  
    if( fScroll ) {     
     psb->style |= wScroll;
     dwStyle       = GetWindowLong(hwnd, GWL_STYLE);
     SetWindowLong(hwnd, GWL_STYLE, dwStyle | wScroll );
     SkinSB_EnableArrows(psb, fnBar, fScroll ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
    }    
    if( fOldScroll ^ fScroll ) {
     SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
      SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
     return nRet;
    }
   }
   if( fScroll && fRedraw ) {
    
    if(dwStyle & wScroll) {
     HDC hDC = GetWindowDC(hwnd);
     SkinSB_DrawThumb(psb, hDC, fVert);
     ReleaseDC(hwnd, hDC);
    }
    else {
     if( SkinSB_IsScrollInfoActive(psi) )
      SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
      SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
    }
   }
   
   return mysi->nPos;
  }
 }

 if( fScroll )
  psb->style |= wScroll;
 else
  psb->style &= ~wScroll;
 
//  SetWindowLong(hwnd, GWL_STYLE, dwStyle | wScroll );
//
//  if( psi->fMask & SIF_DISABLENOSCROLL ) {
//   if( fOldScroll ) {
//    fScroll = ((int)mysi->nPage <= (mysi->nMax - mysi->nMin));
//    psb->style |= wScroll;
//    SetWindowLong(hwnd, GWL_STYLE, dwStyle | wScroll);
//    SkinSB_EnableArrows(psb, fnBar, fScroll ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
//   }
//  }
//  else if( fOldScroll ^ fScroll ) {
//   SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
//             SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
//   return nRet;
//  }

 if( fScroll && fRedraw ) {

redrawAfterSet:
  if(dwStyle & wScroll) {
   HDC hDC = GetWindowDC(hwnd);
   SkinSB_DrawThumb(psb, hDC, fVert);
   ReleaseDC(hwnd, hDC);
  }
  else {
   if( SkinSB_IsScrollInfoActive(psi) )
    SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
    SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
  }
 }

 return mysi->nPos; //lres;
}


//---------------------------------------------------------
// Name : SkinSB_GetScrollPos()
// Desc : Overload API GetScrollPos()
//---------------------------------------------------------
int WINAPI SkinSB_GetScrollPos(HWND hwnd, int nBar)
{
 LPSB psb;
 int nPos;
 if( !(psb = SkinSB_GetSB(hwnd)) )
  return FALSE;

 if( nBar == SB_HORZ )
  nPos = psb->Horz.nPos;
 else if( nBar == SB_VERT )
  nPos = psb->Vert.nPos;

 return nPos;
}


//---------------------------------------------------------
// Name : SkinSB_SetScrollPos()
// Desc : Overload API SetScrollPos()
//---------------------------------------------------------
int WINAPI SkinSB_SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL fRedraw)
{
 LPSB psb;
 LPSCROLLINFO psi;
 int nOldPos;

 if( (psb = SkinSB_GetSB(hwnd)) == NULL)
  return FALSE;

 if( nBar == SB_HORZ )
  psi = &psb->Horz;
 else if( nBar == SB_VERT )
  psi = &psb->Vert;
 else
  return FALSE;

 nOldPos = psi->nPos;
 psi->nPos = nPos;

 if( fRedraw ) {
  HDC hDC = GetWindowDC(hwnd);
  SkinSB_DrawScrollBar(psb, hDC, (nBar == SB_VERT) );
  ReleaseDC(hwnd, hDC);
 }

 return nOldPos;
}


//---------------------------------------------------------
// Name : SkinSB_GetScrollRange()
// Desc : Overload API GetScrollRange()
//---------------------------------------------------------
BOOL WINAPI SkinSB_GetScrollRange(HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
{
 LPSB psb;
 LPSCROLLINFO psi;
 if( !lpMinPos || !lpMaxPos )
  return FALSE;

 if( (psb = SkinSB_GetSB(hwnd)) == NULL )
  return FALSE;

 if( nBar == SB_HORZ )
  psi = &psb->Horz;
 else if( nBar == SB_VERT )
  psi = &psb->Vert;

 *lpMinPos = psi->nMin;
 *lpMaxPos = psi->nMax;

 return TRUE;
}


//---------------------------------------------------------
// Name : SkinSB_SetScrollRange()
// Desc : Overload API SetScrollRange()
//---------------------------------------------------------
BOOL WINAPI SkinSB_SetScrollRange(HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw)
{
 LPSB psb;
 LPSCROLLINFO psi;

 if( !(psb = SkinSB_GetSB(hwnd)) )
  return FALSE;

 if( nBar == SB_HORZ )
  psi = &psb->Horz;
 else if( nBar == SB_VERT )
  psi = &psb->Vert;

 psi->nMin = nMinPos;
 psi->nMax = nMaxPos;

 if(nMinPos == 0 && nMaxPos == 0)
  SkinSB_ShowScrollBar(hwnd, nBar, FALSE);

 if( fRedraw ) {
  HDC hDC = GetWindowDC(hwnd);
  SkinSB_DrawScrollBar(psb, hDC, (nBar == SB_VERT) );
  ReleaseDC(hwnd, hDC);
 }

 return TRUE;
}


//---------------------------------------------------------
// Name : SkinSB_ShowScrollBar()
// Desc : Overload API ShowScrollBar()
//---------------------------------------------------------
BOOL WINAPI SkinSB_ShowScrollBar(HWND hwnd, int wBar, BOOL fShow)
{
 BOOL fChanged = FALSE;
 DWORD dwStyle, dwNew;

 switch( wBar )
 {
 case SB_CTL:
  ShowWindow(hwnd, fShow ? SW_SHOW : SW_HIDE);
  break;
 case SB_HORZ:
  dwNew = WS_HSCROLL;
  break;
 case SB_VERT:
  dwNew = WS_VSCROLL;
  break;
 case SB_BOTH:
  dwNew = WS_HSCROLL | WS_VSCROLL;
  break;
 }

 dwStyle = GetWindowLong(hwnd, GWL_STYLE);
 if( !fShow ) {
  if( dwStyle & dwNew ) {
   fChanged = TRUE;
   dwStyle &= ~dwNew;
  }
 }
 else {
  if( (dwStyle & dwNew) != dwNew ) {
   fChanged = TRUE;
   dwStyle |= dwNew;
  }
 }

 if( fChanged ) {
  SetWindowLong(hwnd, GWL_STYLE, dwStyle);
  SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
            SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
 }

 return TRUE;
}


//---------------------------------------------------------
// Name : SkinSB_EnableScrollBar()
// Desc : Overload API EnableScrollBar()
//---------------------------------------------------------
BOOL WINAPI SkinSB_EnableScrollBar(HWND hwnd, UINT wSBflags, UINT wArrows)
{
 LPSB psb;
 if( !(psb = SkinSB_GetSB(hwnd)) )
  return FALSE;

 if( wSBflags == SB_CTL )
  return FALSE;
 
 return SkinSB_EnableArrows(psb, wSBflags, wArrows);
}

// Internal Function


//---------------------------------------------------------
// Name : SkinSB_SetSBParms()
// Desc : Set scroll parameters
//---------------------------------------------------------
BOOL SkinSB_SetSBParms(LPSCROLLINFO psi, SCROLLINFO si, BOOL* pfScroll, int* plres, BOOL bOldPos)
{
 BOOL fChanged = FALSE;
 if( bOldPos )
  *plres = psi->nPos;

 if( si.fMask & SIF_RANGE ) {
  if( si.nMax < si.nMin )
   si.nMax = si.nMin;

  if( si.nMax != psi->nMax || si.nMin != psi->nMin ) {
   psi->nMax = si.nMax;
   psi->nMin = si.nMin;

   if( !(si.fMask & SIF_PAGE) ) {
    si.fMask |= SIF_PAGE;
    si.nPage = psi->nPage;
   }

   if( !(si.fMask & SIF_POS) ) {
    si.fMask |= SIF_POS;
    si.nPos  = psi->nPos;
   }

   fChanged = TRUE;
  }
 }

 if( si.fMask & SIF_PAGE ) {
  UINT nMaxPage = abs( psi->nMax - psi->nMin ) + 1;
  if( si.nPage > nMaxPage )
   si.nPage = nMaxPage;
  
  if( psi->nPage != si.nPage ) {
   psi->nPage = si.nPage;

   if( !(si.fMask & SIF_POS) ) {
    si.fMask |= SIF_POS;
    si.nPos  = psi->nPos;
   }

   fChanged = TRUE;
  }
 }

 if( si.fMask & SIF_POS ) {
  int nMaxPos = psi->nMax - ((psi->nPage) ? psi->nPage - 1 : 0);
  if( si.nPos < psi->nMin )
   si.nPos = psi->nMin;
  else if( si.nPos > nMaxPos )
   si.nPos = nMaxPos;

  if( psi->nPos != si.nPos ) {
   psi->nPos = si.nPos;
   fChanged = TRUE;
  }
 }

 if( si.fMask & SIF_TRACKPOS ) {
  if( psi->nTrackPos != si.nTrackPos ) {
   psi->nTrackPos = si.nTrackPos;
   fChanged = TRUE;
  }
 }

 if( !bOldPos )
  *plres = psi->nPos; // Return the new pos

 if( si.fMask & SIF_RANGE ) {
  if( *pfScroll = (psi->nMin != psi->nMax) )
   goto CheckPage;
 }
 else if( si.fMask & SIF_PAGE ) {
CheckPage:
  *pfScroll = ( (int)psi->nPage <= (psi->nMax - psi->nMin) );
 }

 return fChanged;
}


//---------------------------------------------------------
// Name : SkinSB_EnableArrows()
// Desc : Enable or Disable scrollbar arrows
//---------------------------------------------------------
BOOL SkinSB_EnableArrows(LPSB psb, int nBar, UINT wArrows)
{
 HDC hDC;
 UINT uOldFlags;
 BOOL bRetValue = FALSE;

 if( psb == NULL )
  return FALSE;

 uOldFlags = psb->flags;
 if( (hDC = GetWindowDC(psb->hwnd)) == NULL )
  return FALSE;

 // Enable or disable horizontal scrollbar
 if( nBar == SB_HORZ || nBar == SB_BOTH ) {
  if( wArrows == ESB_ENABLE_BOTH )
   psb->flags &= ~ESB_DISABLE_BOTH;
  else
   psb->flags |= wArrows;

  if( uOldFlags != psb->flags ) {
   bRetValue = TRUE;
   if( GetWindowLong(psb->hwnd, GWL_STYLE ) & WS_HSCROLL )
    SkinSB_DrawScrollBar(psb, hDC, FALSE);
  }
 }

 // Enable or disable vertical scrollbar
 if( nBar == SB_VERT || nBar == SB_BOTH ) {
  if( wArrows == ESB_ENABLE_BOTH )
   psb->flags &= ~(ESB_DISABLE_BOTH << 2);
  else
   psb->flags |= (wArrows << 2);

  if( uOldFlags != psb->flags ) {
   bRetValue = TRUE;
   if( GetWindowLong(psb->hwnd, GWL_STYLE ) & WS_VSCROLL )
    SkinSB_DrawScrollBar(psb, hDC, TRUE);
  }
 }

 ReleaseDC(psb->hwnd, hDC);

 return bRetValue;
}


//---------------------------------------------------------
// Name : SkinSB_GetDisableFlags()
// Desc : Get scrollbar disable flags
//---------------------------------------------------------
UINT SkinSB_GetDisableFlags(LPSB psb, BOOL fVert)
{
 return (fVert ? (psb->flags & 0x000c) >> 2 : psb->flags & 0x0003);
}


//---------------------------------------------------------
// Name : SkinSB_GetSB()
// Desc : Get the skin scrollbar data structure
//---------------------------------------------------------
LPSB SkinSB_GetSB(HWND hwnd)
{
 return (LPSB)GetProp(hwnd, g_szPropSB);;
}


//---------------------------------------------------------
// Name : SkinSB_IsScrollInfoActive()
// Desc : Check scroll information whether active
//---------------------------------------------------------
BOOL SkinSB_IsScrollInfoActive(LPCSCROLLINFO lpsi)
{
 if( lpsi->nPage > (UINT)lpsi->nMax || lpsi->nMax <= lpsi->nMin || lpsi->nMax == 0 )
  return FALSE;
 else
  return TRUE;
}


//----------------------------------------------------------
// Name : SkinSB_GetSizeBoxRect()
// Desc : Get the size box rect
//----------------------------------------------------------
BOOL SkinSB_GetSizeBoxRect(LPSB psb, LPRECT lprc)
{
 DWORD dwStyle;
 RECT  rect;

 SetRectEmpty(lprc);
 dwStyle = GetWindowLong(psb->hwnd, GWL_STYLE);
 if( (dwStyle & WS_HSCROLL) && (dwStyle & WS_VSCROLL) ) {
  GetClientRect(psb->hwnd, &rect);
  ClientToScreen(psb->hwnd, (LPPOINT)&rect);
  ClientToScreen(psb->hwnd, ((LPPOINT)&rect)+1);

  // calculate left scroll style of size box rect
  if( psb->fLeftScrollBar ) {
   lprc->left = rect.left - GetSystemMetrics(SM_CXVSCROLL);
   lprc->right = rect.left;
  }
  else {
   lprc->left = rect.right;
   lprc->right = rect.right + GetSystemMetrics(SM_CXVSCROLL);
  }

  lprc->top   = rect.bottom;
  lprc->bottom= rect.bottom + GetSystemMetrics(SM_CYHSCROLL);
  return TRUE;
 }

 return FALSE;
}


//----------------------------------------------------------
// Name : SkinSB_GetScrollBarRect()
// Desc : Get the scrollbar rect
//----------------------------------------------------------
BOOL SkinSB_GetScrollBarRect(LPSB psb, BOOL fVert, LPRECT lprc)
{
 RECT   rect;
 DWORD  dwStyle;

 if( !psb || !lprc )
  return FALSE;
 SetRectEmpty(lprc);
 GetClientRect(psb->hwnd, &rect);
 ClientToScreen(psb->hwnd, (LPPOINT)&rect);
 ClientToScreen(psb->hwnd, ((LPPOINT)&rect)+1);

 dwStyle = GetWindowLong(psb->hwnd, GWL_STYLE);

 if( fVert ) {
  if( psb->fLeftScrollBar ) {
   lprc->right = lprc->left = rect.left;
   if( dwStyle & WS_VSCROLL )
    lprc->left -= GetSystemMetrics(SM_CXVSCROLL);
  }
  else {
   lprc->right = lprc->left = rect.right;
   if( dwStyle & WS_VSCROLL )
    lprc->right += GetSystemMetrics(SM_CXVSCROLL);
  }
  lprc->top = rect.top;
  lprc->bottom = rect.bottom;
 }
 else {
  lprc->top = lprc->bottom = rect.bottom;
  if( dwStyle & WS_HSCROLL )
   lprc->bottom += GetSystemMetrics(SM_CYHSCROLL);
  lprc->left = rect.left;
  lprc->right = rect.right;
 }

 return TRUE;
}


//----------------------------------------------------------
// Name : SkinSB_GetThumbRect()
// Desc :
//----------------------------------------------------------

BOOL SkinSB_GetThumbRect(LPSB psb, LPRECT lprc, BOOL fVert)
{
 if( !psb || !lprc )
  return FALSE;
 SBCALC   sbc;
 RECT     rect;
 SkinSB_SBCalc(psb, &sbc, fVert);
 GetWindowRect(psb->hwnd, &rect);
 if( fVert )
  SetRect(lprc, sbc.pxLeft, sbc.pxThumbTop, sbc.pxRight, sbc.pxThumbBottom);
 else
  SetRect(lprc, sbc.pxThumbLeft, sbc.pxTop, sbc.pxThumbRight, sbc.pxBottom);

 OffsetRect(lprc, -rect.left, -rect.top);
 return TRUE;
}

//----------------------------------------------------------
// Name : SkinSB_GetGrooveRect()
// Desc :
//----------------------------------------------------------
BOOL SkinSB_GetGrooveRect(LPSB psb, LPRECT lprc, BOOL fVert)
{
 if( !psb || !lprc )
  return FALSE;
 SBCALC   sbc;
 RECT     rect;
 SkinSB_SBCalc(psb, &sbc, fVert);
 GetWindowRect(psb->hwnd, &rect);
 if( fVert )
  SetRect(lprc, sbc.pxLeft, sbc.pxUpArrow, sbc.pxRight, sbc.pxDownArrow);
 else
  SetRect(lprc, sbc.pxUpArrow, sbc.pxTop, sbc.pxDownArrow, sbc.pxBottom);
 OffsetRect(lprc, -rect.left, -rect.top);
 return TRUE;
}


//----------------------------------------------------------
// Name : SkinSB_DrawSizeBox()
// Desc : Draw the size box
//----------------------------------------------------------

BOOL SkinSB_DrawSizeBox(LPSB psb, HDC hDC)
{
 HDC     hMemDC;
 HBITMAP hOldBmp;

 RECT rect, rc;
 GetWindowRect(psb->hwnd, &rect);
 SkinSB_GetSizeBoxRect(psb, &rc);
 OffsetRect(&rc, -rect.left, -rect.top);

 hMemDC = CreateCompatibleDC(NULL);
 hOldBmp = (HBITMAP)SelectObject(hMemDC, psb->hBmp);

 BitBlt(hDC, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hMemDC, 38, 57, SRCCOPY);

 // Release GDI object
 SelectObject(hMemDC, hOldBmp);
 DeleteDC(hMemDC);

 return TRUE;
}


//----------------------------------------------------------
// Name : SkinSB_DrawGroove()
// Desc :
//----------------------------------------------------------
BOOL SkinSB_DrawGroove(LPSB psb, HDC hdc, LPRECT lprc, BOOL fVert)
{
 if( !hdc || !lprc || IsRectEmpty(lprc) )
  return FALSE;

 HDC      hbmpDC;
 HBITMAP  hOldBmp;
 POINT    pt;
 int      nMode;
 hbmpDC = CreateCompatibleDC(hdc);
 hOldBmp = (HBITMAP)SelectObject(hbmpDC, psb->hBmp);

 if( fVert )
  pt = ptArray[0][4];
 else
  pt = ptArray[3][4];

 nMode = SetStretchBltMode(hdc, HALFTONE);
 StretchBlt(hdc, lprc->left, lprc->top, lprc->right - lprc->left,
  lprc->bottom - lprc->top, hbmpDC, pt.x, pt.y, 16, 16, SRCCOPY);
 SetStretchBltMode(hdc, nMode);

 SelectObject(hbmpDC, hOldBmp);
 DeleteDC(hbmpDC);

 return TRUE;
}


//----------------------------------------------------------
// Name : SkinSB_DrawScrollBar()
// Desc : Draw the scrollbar
//----------------------------------------------------------
void SkinSB_DrawScrollBar(LPSB psb, HDC hDC, BOOL fVert)
{
 RECT rcGroove;

 SkinSB_GetGrooveRect(psb, &rcGroove, fVert);
 SkinSB_DrawGroove(psb, hDC, &rcGroove, fVert);

 if( fVert ) {
  // Draw the arrow
  SkinSB_DrawArrow(psb, hDC, fVert, HTSCROLL_LINEUP, 0);
  SkinSB_DrawArrow(psb, hDC, fVert, HTSCROLL_LINEDOWN, 0);
  
  // Draw the thumb
  if( !SkinSB_IsScrollInfoActive(&psb->Vert) )
   return ;
  SkinSB_DrawThumb(psb, hDC, fVert);
 }
 else {
  SkinSB_DrawArrow(psb, hDC, fVert, HTSCROLL_LINEUP, 0);
  SkinSB_DrawArrow(psb, hDC, fVert, HTSCROLL_LINEDOWN, 0);

  if( !SkinSB_IsScrollInfoActive(&psb->Horz) )
   return ;
  SkinSB_DrawThumb(psb, hDC, fVert);
 }
}


//----------------------------------------------------------
// Name : SkinSB_DrawArrow()
// Desc : Draw the scrollbar arrow button
//----------------------------------------------------------
BOOL SkinSB_DrawArrow(LPSB psb, HDC hdc, BOOL fVert, int nArrow, UINT uState)
{
 RECT       rect, rc;
 SBCALC     sbc;
 HDC        hMemDC;
 HBITMAP    hOldBmp;
 int        x, y;
 POINT      pt;

 GetWindowRect(psb->hwnd, &rect);
 SkinSB_SBCalc(psb, &sbc, fVert);

 if( uState == 0 )
  uState = SkinSB_GetState(psb, fVert, nArrow);

 hMemDC  = CreateCompatibleDC(hdc);
 hOldBmp = (HBITMAP)SelectObject(hMemDC, psb->hBmp);

 switch( nArrow )
 {
  // up or left arrow
 case HTSCROLL_LINEUP:
  if( fVert ) {
   x = 0; y = 0;
   SetRect(&rc, sbc.pxLeft, sbc.pxTop, sbc.pxRight, sbc.pxUpArrow);
  }
  else {
   x = 3; y = 0;
   SetRect(&rc, sbc.pxLeft, sbc.pxTop, sbc.pxUpArrow, sbc.pxBottom);
  }
  break;
  // right or down arrow
 case HTSCROLL_LINEDOWN:
  if( fVert ) {
   x = 0; y = 1;
   SetRect(&rc, sbc.pxLeft, sbc.pxDownArrow, sbc.pxRight, sbc.pxBottom);
  }
  else {
   x = 3; y = 1;
   SetRect(&rc, sbc.pxDownArrow, sbc.pxTop, sbc.pxRight, sbc.pxBottom);
  }
  break;
 }

 OffsetRect(&rc, -rect.left, -rect.top);

 switch( uState )
 {
 case SB_STATE_NORMAL:
  break;
 case SB_STATE_HOTTRACKED:
  x += 1;
  break;
 case SB_STATE_PRESSED:
  x += 2;
  break;
 case SB_STATE_DISABLED:
  break;
 }
 pt = ptArray[x][y];

 BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
  hMemDC, pt.x, pt.y, SRCCOPY);

 SelectObject(hMemDC, hOldBmp);
 DeleteDC(hMemDC);

 return TRUE;
 
}

//----------------------------------------------------------
// Name : SkinSB_DrawThumb()
// Desc : Draw the thumb
//----------------------------------------------------------
void SkinSB_DrawThumb(LPSB psb, HDC hdc, BOOL fVert)
{
 SBCALC    sbc;
 RECT      rc, rect;
 HDC       hSrcDC;
 HDC       memDC;
 HBITMAP   hOldBmp;
 HBITMAP   hMemBitmap, hOldBitmap;
 UINT      uState;
 int       cx, cy;
 POINT     pt, pt1;
 
 uState = SkinSB_GetState(psb, fVert, HTSCROLL_THUMB);

 SkinSB_SBCalc(psb, &sbc, fVert);
 GetWindowRect(psb->hwnd, &rect);

 // Chack scrollbar of size whether valid
 if( sbc.pxTop >= sbc.pxBottom || sbc.pxLeft >= sbc.pxRight )
  return ;

 // Draw the groove only
 if( (sbc.pxDownArrow - sbc.pxUpArrow) < (sbc.pxThumbBottom - sbc.pxThumbTop) ||
  uState == SB_STATE_DISABLED ) {
  SkinSB_GetGrooveRect(psb, &rc, fVert);
  SkinSB_DrawGroove(psb, hdc, &rc, fVert);
  return ;
 }

 // Padding the groove part
 if( sbc.pxUpArrow < sbc.pxThumbTop ) {
  if( fVert )
   SetRect(&rc, sbc.pxLeft, sbc.pxUpArrow,  sbc.pxRight, sbc.pxThumbTop);
  else
   SetRect(&rc, sbc.pxUpArrow, sbc.pxTop, sbc.pxThumbTop, sbc.pxBottom);
  OffsetRect(&rc, -rect.left, -rect.top);
  SkinSB_DrawGroove(psb, hdc, &rc, fVert);
 }

 if( sbc.pxThumbBottom < sbc.pxDownArrow ) {
  if( fVert )
   SetRect(&rc, sbc.pxLeft, sbc.pxThumbBottom, sbc.pxRight, sbc.pxDownArrow);
  else
   SetRect(&rc, sbc.pxThumbBottom, sbc.pxTop, sbc.pxDownArrow, sbc.pxBottom);
  OffsetRect(&rc, -rect.left, -rect.top);
  SkinSB_DrawGroove(psb, hdc, &rc, fVert);
 }

 // Draw the thumb use memory dc

 // Select scrollbar bitmap resource to dc
 hSrcDC   = CreateCompatibleDC(hdc);
 hOldBmp  = (HBITMAP)SelectObject(hSrcDC, psb->hBmp);

 // get the thumb rectangle
 SkinSB_GetThumbRect(psb, &rc, fVert);
 cx = rc.right - rc.left;
 cy = rc.bottom - rc.top;
 RECT rcMemDC = {0, 0, rc.right-rc.left, rc.bottom-rc.top};

 // create the memory dc
 memDC = CreateCompatibleDC(hdc);
 hMemBitmap = CreateCompatibleBitmap(hdc, cx, cy);
 hOldBitmap = (HBITMAP)SelectObject(memDC, hMemBitmap);
 SetBkColor(memDC, 0xFFFFFF);
 ExtTextOut(memDC, 0, 0, ETO_OPAQUE, &rcMemDC, NULL, 0, NULL);

 // Select state bitmap part
 switch( uState )
 {
 case SB_STATE_NORMAL:
  pt  = fVert ? ptArray[0][2] : ptArray[3][2];
  pt1 = fVert ? ptArray[0][3] : ptArray[3][3];
  break;
 case SB_STATE_HOTTRACKED:
  pt  = fVert ? ptArray[1][2] : ptArray[4][2];
  pt1 = fVert ? ptArray[1][3] : ptArray[4][3];
  break;
 case SB_STATE_PRESSED:
  pt  = fVert ? ptArray[2][2] : ptArray[5][2];
  pt1 = fVert ? ptArray[2][3] : ptArray[5][3];
  break;
 case SB_STATE_DISABLED:
  break;
 }

 if ( fVert ) {
  for( int i= 4; i < cy - 4; i += 8 )
   BitBlt(memDC, 0,  i, cx, 8, hSrcDC, pt.x, pt.y + 4, SRCCOPY);

  BitBlt(memDC, 0, 0, cx, 4, hSrcDC, pt.x, pt.y, SRCCOPY);
  BitBlt(memDC, 0, cy - 4, cx, 4, hSrcDC, pt.x, (pt.y + 16) - 4, SRCCOPY);
  if( cy > 16 + 8 ) {
   int y = (cy - 16) / 2;
   BitBlt(memDC, 0, y, cx, 16, hSrcDC, pt1.x, pt1.y, SRCCOPY);
  }
 }
 else {
  for( int i=4; i < cx - 4; i += 8 )
   BitBlt(memDC, i, 0, 8, cy, hSrcDC, pt.x + 4, pt.y, SRCCOPY);
  BitBlt(memDC, 0, 0, 4, cy, hSrcDC, pt.x, pt.y, SRCCOPY);
  BitBlt(memDC, cx - 4, 0, 4, cy, hSrcDC, (pt.x + 16) - 4, pt.y, SRCCOPY);
  if( cx > 16 + 8 ) {
   int x = (cx - 16) / 2;
   BitBlt(memDC, x, 0, 16, cy, hSrcDC, pt1.x, pt1.y, SRCCOPY);
  }
 }

 BitBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, memDC, 0,0, SRCCOPY);
 
 // Release the memory DC
 SelectObject(memDC, hOldBitmap);
 DeleteDC(memDC);
 DeleteObject(hMemBitmap);

 SelectObject(hSrcDC, hOldBmp);
 DeleteDC(hSrcDC);
}

//----------------------------------------------------------
// Name : SkinSB_HitTest()
// Desc : HitTest scrollbar items
//----------------------------------------------------------
UINT SkinSB_HitTest(LPSB psb, BOOL fVert, POINT pt)
{
 SBCALC  sbc;
 UINT    disFlags;
 int     x;

 SkinSB_SBCalc(psb, &sbc, fVert);

 if( pt.x < sbc.pxLeft  || pt.y < sbc.pxTop ||
  pt.x > sbc.pxRight || pt.y > sbc.pxBottom )
  return HTSCROLL_NONE;

 disFlags = SkinSB_GetDisableFlags(psb, fVert);
 x = fVert ? pt.y : pt.x;

 if( x < sbc.pxUpArrow ) {
  if( disFlags & ESB_DISABLE_BOTH || disFlags & ESB_DISABLE_LTUP )
   return HTSCROLL_NONE;
  else
   return HTSCROLL_LINEUP;
 }
 else if( x > sbc.pxUpArrow && x < sbc.pxThumbTop ) {
  if( disFlags & ESB_DISABLE_BOTH || disFlags & ESB_DISABLE_LTUP )
   return HTSCROLL_NONE;
  else
   return HTSCROLL_PAGEUP;
 }
 else if( (x >= sbc.pxThumbTop && x <= sbc.pxThumbBottom) &&
  (sbc.pxThumbTop > 0 && sbc.pxThumbBottom > sbc.pxThumbTop) ) {
  return HTSCROLL_THUMB;
 }
 else if( x > sbc.pxThumbBottom && x < sbc.pxDownArrow ) {
  if( disFlags & ESB_DISABLE_BOTH || disFlags & ESB_DISABLE_RTDN )
   return HTSCROLL_NONE;
  else
   return HTSCROLL_PAGEDOWN;
 }
 else if( x >= sbc.pxDownArrow ) {
  if( disFlags & ESB_DISABLE_BOTH || disFlags & ESB_DISABLE_RTDN )
   return HTSCROLL_NONE;
  else
   return HTSCROLL_LINEDOWN;
 }

 return HTSCROLL_NONE;
}


//----------------------------------------------------------
// Name : SkinSB_SBCalc()
// Desc : Calc the scrollbar items position and size
//----------------------------------------------------------
void SkinSB_SBCalc(LPSB psb, LPSBCALC lpcalc, BOOL fVert)
{
 RECT         rcBar;             // the scrollbar rect
 int          nRange;            // the scroll range
 int          nWorkingsize;      // the scroll working size
 int          nArrowsize;        // the arrow button of size
 int          nThumbsize;        // the thumb of size 
 int          nStart;            // the thumb of start position
 int          nThumbpos;         // the thumn of current position
 SCROLLINFO*  psi;

 SkinSB_GetScrollBarRect(psb, fVert, &rcBar);

 lpcalc->pxLeft   = rcBar.left;
 lpcalc->pxTop    = rcBar.top;
 lpcalc->pxRight  = rcBar.right;
 lpcalc->pxBottom = rcBar.bottom;

 if( fVert ) {
  psi = &psb->Vert;
  nArrowsize   = GetSystemMetrics(SM_CYVSCROLL);
  nWorkingsize = (rcBar.bottom - rcBar.top) - nArrowsize * 2;
  nStart = rcBar.top + nArrowsize;
  
  lpcalc->pxUpArrow = rcBar.top + nArrowsize;
  lpcalc->pxDownArrow = rcBar.bottom - nArrowsize;
 }
 else {
  psi = &psb->Horz;
  nArrowsize   = GetSystemMetrics(SM_CXHSCROLL);
  nWorkingsize = (rcBar.right - rcBar.left) - nArrowsize * 2;
  nStart = rcBar.left + nArrowsize;

  lpcalc->pxUpArrow = rcBar.left + nArrowsize;
  lpcalc->pxDownArrow = rcBar.right - nArrowsize;
 }

 nRange = (psi->nMax - psi->nMin) + 1;
 if( nRange > 0 && SkinSB_IsScrollInfoActive(psi)) {
  nThumbsize = MulDiv(psi->nPage, nWorkingsize, nRange);
  if( nThumbsize < SB_MINTHUMB_SIZE )
   nThumbsize = SB_MINTHUMB_SIZE;
  int pagesize = max(1, psi->nPage);

  nThumbpos = MulDiv(psi->nPos - psi->nMin, nWorkingsize - nThumbsize, nRange - pagesize);
  
  if( nThumbpos < 0 )
   nThumbpos = 0;

  if( nThumbpos >= nWorkingsize - nThumbsize )
   nThumbpos =  nWorkingsize - nThumbsize;

  nThumbpos += nStart;
  lpcalc->pxThumbTop = nThumbpos;
  lpcalc->pxThumbBottom = nThumbpos + nThumbsize;
 }
 else {
  lpcalc->pxThumbTop = 0;
  lpcalc->pxThumbBottom = 0;
 } 
}

//---------------------------------------------------------
// Name : SkinSB_TrackThumb()
// Desc : Track the scroll thumb
//---------------------------------------------------------
BOOL SkinSB_TrackThumb(LPSB psb, BOOL fVert, POINT pt)
{
 SBCALC         sbclc;
 int            nPos;
 int            nThumbpos;
 int            nRange;
 int            nThumbsize;
 int            nWorksize;
 LPSCROLLINFO   psi;

 SkinSB_SBCalc(psb, &sbclc, fVert);
 
 if( fVert ) {
  psi = &psb->Vert;
  nThumbpos = pt.y -  psb->nOffsetPoint;
 }
 else {
  psi = &psb->Horz;
  nThumbpos = pt.x - psb->nOffsetPoint;
 }

 nPos       = 0;
 nThumbpos -= sbclc.pxUpArrow;
 nThumbsize = sbclc.pxThumbBottom - sbclc.pxThumbTop;
 nWorksize  = sbclc.pxDownArrow - sbclc.pxUpArrow;
 nRange     = (psi->nMax - psi->nMin) + 1;

 if( nThumbpos < 0 )
  nThumbpos = 0;
 if( nThumbpos > nWorksize - nThumbsize)
  nThumbpos = nWorksize - nThumbsize;

 if( nRange > 0 )
  nPos = MulDiv(nThumbpos, nRange - psi->nPage, nWorksize - nThumbsize);

 // Send the scroll message to window !!!
 if( psi->nPos != nPos ) {
  psi->nTrackPos = nPos;
  psb->nTrackPos = nPos;
  // NOTE: 2008-12-24
  // Not use the SB_THUMBTRACK flag that because of
  // the RichEdit cannot receving the WM_MOUSEMOVE message
  if( psb->fRichEdit ) {
   DoScrollMsg(psb->hwnd, /*SB_THUMBTRACK*/SB_THUMBPOSITION, nPos, fVert);
  }
  else {
   DoScrollMsg(psb->hwnd, SB_THUMBTRACK, nPos, fVert);
  }
 }

 return TRUE;
}

 

//---------------------------------------------------------
// Name : SkinSB_GetState()
// Desc :
//---------------------------------------------------------
UINT SkinSB_GetState(LPSB psb, BOOL fVert, UINT nHit)
{
 BOOL  fHotTracked;
 BOOL  fPressed;
 BOOL  fDisabled;
 UINT  disFlags;
 UINT  state;

 if( nHit == HTSCROLL_NONE )
  return 0;

 fHotTracked = fPressed = fDisabled = FALSE;

 disFlags = SkinSB_GetDisableFlags(psb, fVert);
 switch( nHit ) {
 case HTSCROLL_LINEUP:
  fDisabled = (disFlags & ESB_DISABLE_BOTH || disFlags & ESB_DISABLE_UP);
  break;
 case HTSCROLL_LINEDOWN:
  fDisabled = (disFlags & ESB_DISABLE_BOTH || disFlags & ESB_DISABLE_DOWN);
  break;
 case HTSCROLL_THUMB:
  fDisabled = (disFlags & ESB_DISABLE_BOTH);
  break;
 }

 if( nHit == psb->nLastCode && fVert == psb->fLastVert )
  fHotTracked = TRUE;

 if( !fDisabled && psb->fTracking && fHotTracked )
  fPressed = TRUE;

 if( fDisabled )
  state = SB_STATE_DISABLED;
 else if( fPressed )
  state = SB_STATE_PRESSED;
 else if( fHotTracked )
  state = SB_STATE_HOTTRACKED;
 else
  state = SB_STATE_NORMAL;
 
 return state;
}

//----------------------------------------------------------
// Name : SkinSB_Track()
// Desc :
//----------------------------------------------------------
void SkinSB_Track(LPSB psb, BOOL fVert, UINT nHit, POINT pt)
{
 UINT            disFlags;
 LPSCROLLINFO    psi;
 WORD            wSBCode;

 psi = fVert ? &psb->Vert : &psb->Horz;
 disFlags = SkinSB_GetDisableFlags(psb, fVert);

 switch( nHit )
 {
 case HTSCROLL_THUMB:
  SBCALC sbclc;
  SkinSB_SBCalc(psb, &sbclc, fVert);
  psi->nTrackPos    = psi->nPos;
  psb->nOffsetPoint = (fVert ? pt.y : pt.x) - sbclc.pxThumbTop;
  break;

 case HTSCROLL_LINEUP:
  wSBCode = SB_LINEUP;
  goto DoScroll;

 case HTSCROLL_LINEDOWN:
  wSBCode = SB_LINEDOWN;
  goto DoScroll;

 case HTSCROLL_PAGEDOWN:
  wSBCode = SB_PAGEDOWN;
  goto DoScroll;

 case HTSCROLL_PAGEUP:
  wSBCode = SB_PAGEUP;
DoScroll:
  psb->nScrollTimerMsg = MAKELONG(fVert ? WM_VSCROLL : WM_HSCROLL, wSBCode);
  DoScrollMsg(psb->hwnd, wSBCode, 0, fVert);
  SetTimer(psb->hwnd, SB_TIMER_DELAY, SB_SCROLL_DELAY, NULL);
  break;
 default:
  return;
 }

 psb->nTrackCode  = nHit;
 psb->fTrackVert  = fVert;
 psb->fTracking   = TRUE;

 SkinSB_HotTrack(psb, nHit, fVert, TRUE);
 SetCapture(psb->hwnd);

 //SkinSB_TrackLoop(psb);
}

/*
//----------------------------------------------------------
// Name : SkinSB_TrackLoop()
// Desc :
//----------------------------------------------------------
void SkinSB_TrackLoop(LPSB psb)
{
 HWND    hwnd;
 MSG     msg;
 int     cmd;
 //POINT   pt;

 if( !psb->fTracking )
  return;
 hwnd = psb->hwnd;
 while( GetCapture() == hwnd )
 {
  if( !GetMessage(&msg, hwnd, 0, 0) )
   break;

  if( !CallMsgFilter(&msg, MSGF_SCROLLBAR) )
  {
   cmd = msg.message;

   if( msg.hwnd == hwnd &&
    ((cmd >= WM_MOUSEFIRST && cmd <= WM_MOUSELAST) ||
    (cmd >= WM_KEYFIRST && cmd <= WM_KEYLAST))
    )
   {
    TRACE("message loop/n");
    SkinSB_Proc(hwnd, cmd, msg.wParam, msg.lParam);
   }
  }
  else
  {
   TranslateMessage(&msg);
            DispatchMessage(&msg);
  }
 }
}*/

//----------------------------------------------------------
// Name : SkinSB_HotTrack()
// Desc : Hot scrollbar arrow and thumb items
//----------------------------------------------------------
BOOL SkinSB_HotTrack(LPSB psb, int nHitCode, BOOL fVert, BOOL fMouseDown)
{
 HDC   hDC;
 UINT  oldHit;
 BOOL    oldVert;

 // Save old hittest code
 oldHit = psb->nLastCode;
 oldVert = psb->fLastVert;

 psb->nLastCode = nHitCode;
 psb->fLastVert = fVert;

 if( (hDC = GetWindowDC(psb->hwnd)) == NULL )
  return FALSE;

 if( nHitCode != (int)oldHit || fVert != oldVert  || fMouseDown) {
  // Restore old hittest item state
  if( oldHit == HTSCROLL_LINEUP )
   SkinSB_DrawArrow(psb, hDC, oldVert, HTSCROLL_LINEUP, SB_STATE_NORMAL);
  else if( oldHit == HTSCROLL_LINEDOWN )
   SkinSB_DrawArrow(psb, hDC, oldVert, HTSCROLL_LINEDOWN, SB_STATE_NORMAL);
  else if( oldHit == HTSCROLL_THUMB )
   SkinSB_DrawThumb(psb, hDC, oldVert);
 

  // Draw new hittest item state
  if( nHitCode == HTSCROLL_LINEUP )
   SkinSB_DrawArrow(psb, hDC, fVert, HTSCROLL_LINEUP, fMouseDown ? SB_STATE_PRESSED : SB_STATE_HOTTRACKED);
  else if( nHitCode == HTSCROLL_LINEDOWN )
   SkinSB_DrawArrow(psb, hDC, fVert, HTSCROLL_LINEDOWN, fMouseDown ? SB_STATE_PRESSED : SB_STATE_HOTTRACKED);
  else if( nHitCode == HTSCROLL_THUMB)
   SkinSB_DrawThumb(psb, hDC, fVert);
 }

 ReleaseDC(psb->hwnd, hDC);
 
 return TRUE;
}

// Message handle

//----------------------------------------------------------
// Name : SkinSB_OnStyleChanged()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnStyleChanged(LPSB psb, int nStyleType, LPSTYLESTRUCT lpStyleStruct)
{
 if( psb->fPreventStyleChange )
  return 0;

 if( nStyleType == GWL_EXSTYLE ) {
  BOOL fOld = psb->fLeftScrollBar;
  if( lpStyleStruct->styleNew & WS_EX_LEFTSCROLLBAR )
   psb->fLeftScrollBar = TRUE;
  else
   psb->fLeftScrollBar = FALSE;

  if( fOld != psb->fLeftScrollBar )
   SetWindowPos(psb->hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
    SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
 }

 return CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_STYLECHANGED, nStyleType, (LPARAM)lpStyleStruct);
}

//----------------------------------------------------------
// Name : SkinSB_OnNcCalcSize()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnNcCalcSize(LPSB psb, BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
 LRESULT   lr;
 DWORD     dwStyle;
 RECT*     lprc, rect;
 
 lprc = &lpncsp->rgrc[0];
 rect = *lprc;

 dwStyle = GetWindowLong(psb->hwnd, GWL_STYLE);
 
 if( dwStyle & (WS_VSCROLL | WS_HSCROLL) ) {
  psb->fPreventStyleChange = TRUE;
  SetWindowLong(psb->hwnd, GWL_STYLE, dwStyle & ~(WS_VSCROLL|WS_HSCROLL));
 }

 lr = CallWindowProc(psb->pfnOldProc, psb->hwnd,
  WM_NCCALCSIZE, (WPARAM)bCalcValidRects, (LPARAM)lpncsp);

 if( dwStyle & (WS_VSCROLL | WS_HSCROLL) ) {
  SetWindowLong(psb->hwnd, GWL_STYLE, dwStyle);
  psb->fPreventStyleChange = FALSE;
 }

 if( (dwStyle & WS_HSCROLL) &&
  (lprc->bottom - lprc->top) > GetSystemMetrics(SM_CYHSCROLL) ) {
  lprc->bottom -= GetSystemMetrics(SM_CYHSCROLL);
 }

 if( (dwStyle & WS_VSCROLL) &&
  (lprc->right - lprc->left) > GetSystemMetrics(SM_CXVSCROLL) ) {
  if( psb->fLeftScrollBar )
   lprc->left += GetSystemMetrics(SM_CXVSCROLL);
  else
   lprc->right -= GetSystemMetrics(SM_CXVSCROLL);
 }
 return lr;
}

//----------------------------------------------------------
// Name : SkinSB_OnNcPaint()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnNcPaint(LPSB psb, HRGN hRgn)
{
 LRESULT  lr;
 DWORD    dwStyle;
 HDC      hDC;
 
 dwStyle = GetWindowLong(psb->hwnd, GWL_STYLE);
 if( dwStyle & (WS_VSCROLL | WS_HSCROLL) ) {
  psb->fPreventStyleChange = TRUE;
  SetWindowLong(psb->hwnd, GWL_STYLE, dwStyle & ~(WS_VSCROLL|WS_HSCROLL));
 }

 // draw frame border by system
 lr = CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_NCPAINT, (WPARAM)hRgn, 0);
 
 if( dwStyle & (WS_VSCROLL | WS_HSCROLL) ) {
  SetWindowLong(psb->hwnd, GWL_STYLE, dwStyle);
  psb->fPreventStyleChange = FALSE;
 }
 
 //hDC = GetDCEx(psb->hwnd, hRgn, DCX_WINDOW|DCX_INTERSECTRGN|DCX_CACHE );
 hDC = GetWindowDC(psb->hwnd);

 // draw the size box
 if( dwStyle & (WS_VSCROLL | WS_HSCROLL) )
  SkinSB_DrawSizeBox(psb, hDC);

 // Draw scrollbar
 if( dwStyle & WS_VSCROLL )
  SkinSB_DrawScrollBar(psb, hDC, TRUE);
 
 if( dwStyle & WS_HSCROLL )
  SkinSB_DrawScrollBar(psb, hDC, FALSE);

 ReleaseDC(psb->hwnd, hDC);

 return lr;
}

//----------------------------------------------------------
// Name : SkinSB_OnNcHitTest()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnNcHitTest(LPSB psb, WPARAM wParam, LPARAM lParam)
{
 POINT pt;
 RECT rcHorz, rcVert, rcSize;
 pt.x = GET_X_LPARAM(lParam);
 pt.y = GET_Y_LPARAM(lParam);

 SkinSB_GetScrollBarRect(psb, TRUE, &rcVert);
 SkinSB_GetScrollBarRect(psb, FALSE, &rcHorz);
 SkinSB_GetSizeBoxRect(psb, &rcSize);

 if( PtInRect(&rcVert, pt) )
  return HTVSCROLL;
 else if( PtInRect(&rcHorz, pt) )
  return HTHSCROLL;
 else if( PtInRect(&rcSize, pt) )
  return HTSIZE;

 return CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_NCHITTEST, wParam, lParam);
}


//----------------------------------------------------------
// Name : SkinSB_OnNcMouseMove()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnNcMouseMove(LPSB psb, WPARAM wParam, LPARAM lParam)
{
 if( wParam == HTHSCROLL || wParam == HTVSCROLL ) {
  POINT pt;
  BOOL  fVert;
  int   nHitCode;

  pt.x  = GET_X_LPARAM(lParam);
  pt.y  = GET_Y_LPARAM(lParam);
  fVert = ( wParam == HTVSCROLL );
  nHitCode  = SkinSB_HitTest(psb, fVert, pt);
  SkinSB_HotTrack(psb, nHitCode, fVert, FALSE);
 }
 else if( wParam == HTSIZE ) {
  SkinSB_HotTrack(psb, HTSCROLL_NONE, FALSE, FALSE);
 }

 return CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_NCMOUSEMOVE, wParam, lParam);
}

//---------------------------------------------------------
// Name : SkinSB_OnNcMouseLeave()
// Desc :
//---------------------------------------------------------
LRESULT SkinSB_OnNcMouseLeave(LPSB psb, WPARAM wParam, LPARAM lParam)
{
 psb->fMouseTracking = FALSE;
 if( psb->fTracking )
  return 0;

 SkinSB_HotTrack(psb, HTSCROLL_NONE, FALSE, FALSE);
 psb->nLastCode = HTSCROLL_NONE;

 return 0;
}

//----------------------------------------------------------
// Name : SkinSB_OnNcLButtonDown()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnNcLButtonDown(LPSB psb, WPARAM wParam, LPARAM lParam)
{
 if( wParam == HTHSCROLL || wParam == HTVSCROLL ) {
  POINT    pt;
  BOOL     fVert;
  int      nHitCode;
  LPSCROLLINFO    psi;

  pt.x  = GET_X_LPARAM(lParam);
  pt.y  = GET_Y_LPARAM(lParam);
  fVert = (wParam == HTVSCROLL);
  
  psi = (fVert ? &psb->Vert : &psb->Horz);
  nHitCode = SkinSB_HitTest(psb, fVert, pt);
  psb->nLastCode = nHitCode;
  psb->fLastVert = fVert;
  SkinSB_Track(psb, fVert, nHitCode, pt);
  return 0;

 }
 return CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_NCLBUTTONDOWN, wParam, lParam);
}

//----------------------------------------------------------
// Name : SkinSB_OnMouseMove()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnMouseMove(LPSB psb, WPARAM wParam, LPARAM lParam)
{
 DWORD    dwPos;
 POINT    pt;
 UINT      nHitCode, nHitTest;
 dwPos =  GetMessagePos();
 pt.x  =  GET_X_LPARAM(dwPos);
 pt.y  =  GET_Y_LPARAM(dwPos);

 // Mouse left button down
 if( psb->fTracking && wParam & MK_LBUTTON ) {
  if( psb->nTrackCode == HTSCROLL_THUMB ) {
   SkinSB_TrackThumb(psb, psb->fTrackVert, pt);
   return 0;
  }

  nHitTest = (UINT)SkinSB_OnNcHitTest(psb, 0, dwPos);

  if( nHitTest == HTHSCROLL || nHitTest == HTVSCROLL ) {
   BOOL fVert = (nHitTest == HTVSCROLL);
   nHitCode = SkinSB_HitTest(psb, fVert, pt);

   if( (int)nHitCode != psb->nTrackCode || fVert != psb->fTrackVert) {
    // Unallowed hot-track other hittest item
    SkinSB_HotTrack(psb, HTSCROLL_NONE, FALSE, FALSE);
   }
   else {
    SkinSB_HotTrack(psb, psb->nTrackCode, psb->fTrackVert, TRUE);
   }
  }
  else {
   SkinSB_HotTrack(psb, HTSCROLL_NONE, FALSE, FALSE);
  }
  return 0;
 }

 return CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_MOUSEMOVE, wParam, lParam);
}

//----------------------------------------------------------
// Name : SkinSB_OnLButtonUp()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnLButtonUp(LPSB psb, WPARAM wParam, LPARAM lParam)
{
 if( psb->nTrackCode != HTSCROLL_NONE && psb->fTracking) {
  // Release mouse capture
  ReleaseCapture();

  // End scroll
  switch( psb->nTrackCode )
  {
  case HTSCROLL_LINEUP:
  case HTSCROLL_LINEDOWN:
  case HTSCROLL_PAGEUP:
  case HTSCROLL_PAGEDOWN:
   KillTimer(psb->hwnd, SB_TIMER_SCROLL);
   DoScrollMsg(psb->hwnd, SB_ENDSCROLL, 0, psb->fTrackVert);
   break;

  case HTSCROLL_THUMB:
   if( psb->fTracking ) {
    DWORD  dwPos;
    POINT  pt;
    dwPos = GetMessagePos();
    pt.x = GET_X_LPARAM(dwPos);
    pt.y = GET_Y_LPARAM(dwPos);
    DoScrollMsg(psb->hwnd, SB_THUMBPOSITION, psb->nTrackPos, psb->fTrackVert);
    DoScrollMsg(psb->hwnd, SB_ENDSCROLL, 0, psb->fTrackVert);
    psb->nLastCode = SkinSB_HitTest(psb, psb->fTrackVert, pt);
   }
   break;
  }
  
  // Clean the track parameters
  psb->nOffsetPoint    = 0;
  psb->nScrollTimerMsg = MAKELONG(WM_NULL, 0);
  psb->nTrackCode      = HTSCROLL_NONE;
  psb->fTracking       = FALSE;
  psb->nTrackPos       = 0;

  HDC hdc = GetWindowDC(psb->hwnd);
  SkinSB_DrawThumb(psb, hdc, psb->fTrackVert);
  ReleaseDC(psb->hwnd, hdc);
  return 0;
 }
 return CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_LBUTTONUP, wParam, lParam);
}

//----------------------------------------------------------
// Name : SkinSB_OnTimer()
// Desc :
//----------------------------------------------------------
LRESULT SkinSB_OnTimer(LPSB psb, WPARAM wParam, LPARAM lParam)
{
 
 if(wParam == SB_TIMER_SCROLL) {
  // if mouse left button released then close scroll timer
  if( psb->nTrackCode == HTSCROLL_NONE ) {
   KillTimer(psb->hwnd, SB_TIMER_SCROLL);
   return 0;
  }

  // Timer send scroll message
  if( (UINT)psb->nTrackCode == psb->nLastCode && psb->fTrackVert == psb->fLastVert )
   DoScrollMsg(psb->hwnd, HIWORD(psb->nScrollTimerMsg), 0, psb->fTrackVert);

  return 0;
 }
 else if(wParam == SB_TIMER_DELAY) {
  KillTimer(psb->hwnd, SB_TIMER_DELAY);
  SetTimer(psb->hwnd, SB_TIMER_SCROLL, SB_SCROLL_INTERVAL, 0);
  return 0;
 }
 return CallWindowProc(psb->pfnOldProc, psb->hwnd, WM_TIMER, wParam, lParam);
}


//----------------------------------------------------------
// Name : SkinSB_Proc()
// Desc :
//----------------------------------------------------------
LRESULT CALLBACK SkinSB_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 LPSB psb = SkinSB_GetSB(hwnd);
 if( psb == NULL)
 {
  return FALSE;
 }

 if( psb && uMsg == WM_NCMOUSEMOVE ) {
  if(!psb->fMouseTracking && !psb->fTracking) {
   TRACKMOUSEEVENT tme;
   tme.cbSize = sizeof(tme);
   tme.hwndTrack = psb->hwnd;
   tme.dwFlags = TME_LEAVE|TME_NONCLIENT;
   tme.dwHoverTime = 0;
   psb->fMouseTracking = _TrackMouseEvent(&tme);
  }
 }

 switch( uMsg )
 {
 case WM_NCPAINT:
  return SkinSB_OnNcPaint(psb, (HRGN)wParam);

 case WM_NCCALCSIZE:
  return SkinSB_OnNcCalcSize(psb, (BOOL)wParam, (NCCALCSIZE_PARAMS*)lParam);

 case WM_NCHITTEST:
  return SkinSB_OnNcHitTest(psb, wParam, lParam);

 case WM_STYLECHANGED:
  return SkinSB_OnStyleChanged(psb, (int)wParam, (LPSTYLESTRUCT)lParam);

 case WM_NCLBUTTONDOWN:
  return SkinSB_OnNcLButtonDown(psb, wParam, lParam);

 case WM_NCMOUSEMOVE:
  return SkinSB_OnNcMouseMove(psb, wParam, lParam);

 case WM_MOUSEMOVE:
  return SkinSB_OnMouseMove(psb, wParam, lParam);

 case WM_LBUTTONUP:
  return SkinSB_OnLButtonUp(psb, wParam, lParam);

 case WM_NCMOUSELEAVE:  
  return SkinSB_OnNcMouseLeave(psb, wParam, lParam);

    case WM_NCLBUTTONDBLCLK:
 case WM_NCRBUTTONDBLCLK:
  return 0;

 case WM_TIMER:
  return SkinSB_OnTimer(psb, wParam, lParam);

 case WM_NCDESTROY:
  LRESULT lr = CallWindowProc(psb->pfnOldProc, hwnd, uMsg, wParam, lParam);
  SkinSB_Uninit(hwnd);
  return lr;
 }
 return CallWindowProc(psb->pfnOldProc, hwnd, uMsg, wParam, lParam);
}

 

基本解决了LISTBOX拖动后,显示无效的问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值