// myscroll.cpp

#include "myscroll.h"

namespace mylib
{

CMyScrollWin::CMyScrollWin()
{
	m_ptOffset.x = 0;
	m_ptOffset.y = 0;
	m_szDraw.cx = 0;
	m_szDraw.cy = 0;
	m_xScrollUnit = 20;
	m_yScrollUnit = 20;
}

CMyScrollWin::~CMyScrollWin()
{
}

void
CMyScrollWin::SetDrawSize(const POINT& ptOffset, const SIZE& sz)
{
	m_ptOffset = ptOffset;
	m_szDraw = sz;
	SetScrollParam();
}

int
CMyScrollWin::SetScrollInfo(int fnBar, SCROLLINFO* lpsi, BOOL fRedraw)
{
	return ::SetScrollInfo(m_hWnd, fnBar, lpsi, fRedraw);
}

BOOL
CMyScrollWin::GetScrollInfo(int fnBar, SCROLLINFO* lpsi)
{
	return ::GetScrollInfo(m_hWnd, fnBar, lpsi);
}

int
CMyScrollWin::Scroll(int dx, int dy, const RECT* prcScroll, const RECT* prcClip,
		HRGN hrgnUpdate, RECT* prcUpdate, UINT flags)
{
	return ::ScrollWindowEx(m_hWnd, dx, dy, prcScroll, prcClip,
		hrgnUpdate, prcUpdate, flags);
}

BOOL
CMyScrollWin::SetScrollParam()
{
	RECT rc;
	SCROLLINFO sci;
	SIZE sz;
	int xofs, yofs;

	if( m_hWnd == NULL )
		return FALSE;
	GetClientRect( &rc );
	sci.cbSize = sizeof( SCROLLINFO );
	sci.fMask = (SIF_PAGE | SIF_RANGE | SIF_POS | SIF_DISABLENOSCROLL);

	xofs = m_ptOffset.x;
	yofs = m_ptOffset.y;
	sz = m_szDraw;
	sci.nMin = 0;
	sci.nMax = sz.cx;
	sci.nPage = rc.right - rc.left;
	sci.nPos = xofs;
	sci.nTrackPos = xofs;
	SetScrollInfo( SB_HORZ, &sci, TRUE );
	sci.nMin = 0;
	sci.nMax = sz.cy;
	sci.nPage = rc.bottom - rc.top;
	sci.nPos = yofs;
	sci.nTrackPos = yofs;
	SetScrollInfo( SB_VERT, &sci, TRUE );
	return TRUE;
}

BOOL
CMyScrollWin::DeltaScroll(int nBarFlag, int zDelta)
{
	int nRange;
	int nNewPos;
	int nDelta;
	int xofs, yofs;
	int dx, dy;
	SCROLLINFO si;
	RECT rc;

	if( m_hWnd == NULL )
		return FALSE;
	if( zDelta == 0 )
		return FALSE;
	GetClientRect( &rc );
	xofs = m_ptOffset.x;
	yofs = m_ptOffset.y;

	si.cbSize = sizeof( SCROLLINFO );
	si.fMask = (SIF_POS | SIF_TRACKPOS | SIF_RANGE | SIF_PAGE);
	si.nMax = 0;
	si.nMin = 0;
	si.nPage = 0;
	si.nPos = 0;
	si.nTrackPos = 0;
	if( !GetScrollInfo( nBarFlag, &si ) )
		return FALSE;

	nRange = si.nMax - (si.nPage - 1);

	if( nBarFlag == SB_VERT )
		nNewPos = yofs - zDelta;
	else
		nNewPos = xofs - zDelta;

	if( nNewPos < 0 )
		nNewPos = 0;
	if( nNewPos > nRange )
		nNewPos = nRange;
	if( nNewPos == si.nPos )
		return TRUE;
	nDelta = si.nPos - nNewPos;
	if( nBarFlag == SB_VERT )
	{
		yofs = si.nTrackPos = si.nPos = nNewPos;
		dx = 0;
		dy = nDelta;
	}
	else
	{
		xofs = si.nTrackPos = si.nPos = nNewPos;
		dx = nDelta;
		dy = 0;
	}
	m_ptOffset.x = xofs;
	m_ptOffset.y = yofs;
	si.fMask = (SIF_POS | SIF_DISABLENOSCROLL);
	SetScrollInfo( nBarFlag, &si, TRUE );
	Scroll( dx, dy, NULL, &rc,
		NULL, NULL, (SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN));
	return TRUE;
}

BOOL
CMyScrollWin::Create(LPCTSTR szTitle, DWORD dwStyle,
		int x, int y, int nWidth, int nHeight,
		HWND hWndParent, HMENU hMenu)
{
	return CMyWin::Create(szTitle, (dwStyle | WS_HSCROLL | WS_VSCROLL),
		x, y, nWidth, nHeight, hWndParent, hMenu);
}

BOOL
CMyScrollWin::OnSize(UINT nType, int cx, int cy)
{
	SetScrollParam();
	return CMyWin::OnSize(nType, cx, cy);
}

BOOL
CMyScrollWin::OnMouseWheel(int fwKeys, int zDelta, int xPos, int yPos)
{
	return DeltaScroll( SB_VERT, zDelta );
}

BOOL
CMyScrollWin::OnHScroll(int nScrollCode, int nPos, HWND hwndScrollBar)
{
	int nRange;
	int nNewPos;
	int nBarFlag;
	int nDelta;
	int xofs, yofs;
	SCROLLINFO si;
	RECT rc;

	if( m_hWnd == NULL )
		return FALSE;
	GetClientRect( &rc );

	xofs = m_ptOffset.x;
	yofs = m_ptOffset.y;

	nBarFlag = SB_HORZ;

	si.cbSize = sizeof( SCROLLINFO );
	si.fMask = (SIF_POS | SIF_TRACKPOS | SIF_RANGE | SIF_PAGE);
	si.nMax = 0;
	si.nMin = 0;
	si.nPage = 0;
	si.nPos = 0;
	si.nTrackPos = 0;
	if( !GetScrollInfo( nBarFlag, &si ) )
		return FALSE;

	nRange = si.nMax - (si.nPage - 1);

	if( (nScrollCode == SB_THUMBPOSITION) ||
		(nScrollCode == SB_THUMBTRACK) )
		nNewPos = si.nTrackPos;
	else if(nScrollCode == SB_LINELEFT)
		nNewPos = xofs - m_xScrollUnit;
	else if(nScrollCode == SB_LINERIGHT)
		nNewPos = xofs + m_xScrollUnit;
	else
		return FALSE;
	if( nNewPos < 0 )
		nNewPos = 0;
	if( nNewPos > nRange )
		nNewPos = nRange;
	if( nNewPos == si.nPos )
		return TRUE;
	nDelta = si.nPos - nNewPos;
	xofs = si.nTrackPos = si.nPos = nNewPos;
	m_ptOffset.x = xofs;
	m_ptOffset.y = yofs;
	si.fMask = (SIF_POS | SIF_DISABLENOSCROLL);
	SetScrollInfo( nBarFlag, &si, TRUE );
	Scroll( nDelta, 0, NULL, &rc,
		NULL, NULL, (SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN));
	return TRUE;
}

BOOL
CMyScrollWin::OnVScroll(int nScrollCode, int nPos, HWND hwndScrollBar)
{
	int nRange;
	int nNewPos;
	int nBarFlag;
	int nDelta;
	int xofs, yofs;
	SCROLLINFO si;
	RECT rc;

	if( m_hWnd == NULL )
		return FALSE;
	GetClientRect( &rc );
	xofs = m_ptOffset.x;
	yofs = m_ptOffset.y;

	nBarFlag = SB_VERT;

	si.cbSize = sizeof( SCROLLINFO );
	si.fMask = (SIF_POS | SIF_TRACKPOS | SIF_RANGE | SIF_PAGE);
	si.nMax = 0;
	si.nMin = 0;
	si.nPage = 0;
	si.nPos = 0;
	si.nTrackPos = 0;
	if( !GetScrollInfo( nBarFlag, &si ) )
		return FALSE;

	nRange = si.nMax - (si.nPage - 1);

	if( (nScrollCode == SB_THUMBPOSITION) ||
		(nScrollCode == SB_THUMBTRACK) )
		nNewPos = si.nTrackPos;
	else if(nScrollCode == SB_LINEUP)
		nNewPos = yofs - m_yScrollUnit;
	else if(nScrollCode == SB_LINEDOWN)
		nNewPos = yofs + m_yScrollUnit;
	else
		return FALSE;
	if( nNewPos < 0 )
		nNewPos = 0;
	if( nNewPos > nRange )
		nNewPos = nRange;
	if( nNewPos == si.nPos )
		return TRUE;
	nDelta = si.nPos - nNewPos;
	yofs = si.nTrackPos = si.nPos = nNewPos;
	m_ptOffset.x = xofs;
	m_ptOffset.y = yofs;
	si.fMask = (SIF_POS | SIF_DISABLENOSCROLL);
	SetScrollInfo( nBarFlag, &si, TRUE );
	Scroll( 0, nDelta, NULL, &rc,
		NULL, NULL, (SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN));
	return TRUE;
}

}	// namespace mylib
