// XTPReportDragDrop.cpp : implementation of the CXTPReportHeaderDropWnd class.
//
// This file is a part of the XTREME REPORTCONTROL MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPCustomHeap.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPSmartPtrInternalT.h"
#include "Common/XTPColorManager.h"


#include "XTPReportDefines.h"
#include "XTPReportHeader.h"
#include "XTPReportPaintManager.h"
#include "XTPReportDragDrop.h"
#include "XTPReportControl.h"
#include "XTPReportColumn.h"
#include "XTPReportColumns.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CXTPReportHeaderDragWnd

CXTPReportHeaderDragWnd::CXTPReportHeaderDragWnd()
{
	m_pHeader = NULL;
	m_pPaintManager = NULL;
	m_pColumn = NULL;
}

CXTPReportHeaderDragWnd::~CXTPReportHeaderDragWnd()
{
}


BEGIN_MESSAGE_MAP(CXTPReportHeaderDragWnd, CWnd)
	//{{AFX_MSG_MAP(CXTPReportHeaderDragWnd)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CXTPReportHeaderDragWnd message handlers

BOOL CXTPReportHeaderDragWnd::Create(CRect rect, CXTPReportHeader* pHeader, CXTPReportPaintManager* pPaintManager, CXTPReportColumn* pColumn)
{
	m_pHeader = pHeader;
	m_pPaintManager = pPaintManager;
	m_pColumn = pColumn;
	if (rect.Height() == 0)
		rect.bottom = rect.top + pPaintManager->GetHeaderHeight();

	DWORD dwStyle = WS_POPUP | WS_DISABLED;
	DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;

	BOOL bCreated = CreateEx(dwExStyle, AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), NULL, dwStyle,
		rect.left, rect.top, rect.Width(), rect.Height(),
		NULL, NULL, NULL);

	if (bCreated && m_pHeader && m_pHeader->GetControl() &&
		m_pHeader->GetControl()->m_bHScrollBarVisible )
	{
		SetTimer(1, 100, NULL);
	}
	return bCreated;
}


void CXTPReportHeaderDragWnd::OnPaint()
{
	CPaintDC dc(this);
	CXTPClientRect rc(this);
	CXTPBufferDC memDC(dc, rc);
	OnDraw(&memDC, rc);
}

BOOL CXTPReportHeaderDragWnd::OnEraseBkgnd(CDC* /*pDC*/)
{
	return TRUE;
}

void CXTPReportHeaderDragWnd::OnDraw(CDC* pDC, CRect rcClient)
{
	if (!m_pPaintManager)
		return;

	// draw background
	m_pPaintManager->FillHeaderControl(pDC, rcClient);
	// draw column header
	m_pPaintManager->DrawColumn(pDC, m_pColumn, m_pHeader, rcClient, TRUE);
}

void CXTPReportHeaderDragWnd::PostNcDestroy()
{
	CWnd::PostNcDestroy();
	delete this;
}

void CXTPReportHeaderDragWnd::OnTimer(UINT_PTR nIDEvent)
{
	UNREFERENCED_PARAMETER(nIDEvent);

	if (!m_pHeader || !m_pHeader->GetControl())
	{
		return;
	}
	CXTPReportControl* pControl = m_pHeader->GetControl();

	ASSERT(pControl->m_bHScrollBarVisible);

	CRect rcHeaderScreen = m_pHeader->m_rcHeader;
	pControl->ClientToScreen(&rcHeaderScreen);

	CRect rcControlScreen(0,0,0,0);
	CRect rcDragScreen(0,0,0,0);

	pControl->GetWindowRect(&rcControlScreen);
	GetWindowRect(&rcDragScreen);


	CPoint ptMouseScreen(0, 0);
	if (!GetCursorPos(&ptMouseScreen) ||
		ptMouseScreen.y < rcHeaderScreen.top || ptMouseScreen.y > rcHeaderScreen.bottom)
	{
		return;
	}

	BOOL bScrolled = FALSE;
	BOOL bLayoutRTL = pControl->GetExStyle() & WS_EX_LAYOUTRTL;

	int nDiffRight = bLayoutRTL ? rcControlScreen.left - rcDragScreen.left :
		rcDragScreen.right - rcControlScreen.right;

	//-----------------------------------------------------------------------
	CXTPReportColumn *pPrev = NULL, *pCurr = NULL, *pNext = NULL;
	int nScrollPos = 0, nScrollMax = 0;
	int nFreezOffset = 0;
	BOOL bFullColumnScrolling = pControl->IsFullColumnScrolling();
	if (bFullColumnScrolling)
		nFreezOffset = m_pHeader->GetFullColScrollInfo(pPrev, pCurr, pNext, nScrollPos, nScrollMax);
	//-----------------------------------------------------------------------

	if (nDiffRight > 0)
	{
		int nStep = max(min(7, nDiffRight/10), CXTPReportHeader::s_nMinAutoScrollStep);
		UINT uTimer = bFullColumnScrolling ? max(30, 800 - nDiffRight * 10) : max(10, 100 - nDiffRight);
		SCROLLINFO scrollInfo;

		BOOL bRes = pControl->GetScrollInfo(SB_HORZ, &scrollInfo);
		if (bRes)
		{
			if (!bFullColumnScrolling && scrollInfo.nPos < scrollInfo.nMax ||
				bFullColumnScrolling && nScrollPos < nScrollMax)
			{
				if (bFullColumnScrolling)
					pControl->SendMessage(WM_HSCROLL, SB_LINERIGHT);
				else
					pControl->SetScrollOffsetH(scrollInfo.nPos + nStep);

				KillTimer(1);
				SetTimer(1, uTimer, NULL);
				bScrolled = TRUE;
			}
		}
	}
	else
	{
		int nLeftBorderX = bLayoutRTL ? rcControlScreen.right : rcControlScreen.left;

		int nFreezCols = pControl->GetFreezeColumnsCount();
		if (nFreezCols && pControl->GetColumns())
		{
			CXTPReportColumn* pLastFCol = pControl->GetColumns()->GetVisibleAt(nFreezCols - 1);
			if (pLastFCol)
			{
				CRect rcLastFCol = pLastFCol->GetRect();
				pControl->ClientToScreen(&rcLastFCol);

				int nLastFCol_middleX = rcLastFCol.left + rcLastFCol.Width() / 2;
				if (rcDragScreen.left < rcLastFCol.right &&
					ptMouseScreen.x > nLastFCol_middleX )
				{
					nLeftBorderX = rcLastFCol.right;
				}
			}
		}

		int nDiffLeft = bLayoutRTL ? rcDragScreen.right - nLeftBorderX : nLeftBorderX - rcDragScreen.left;

		if (nDiffLeft > 0)
		{
			int nStep = max(min(7, nDiffLeft/10), CXTPReportHeader::s_nMinAutoScrollStep);
			UINT uTimer = bFullColumnScrolling ? max(30, 800 - nDiffLeft * 10) : max(10, 100 - nDiffLeft);
			SCROLLINFO scrollInfo;

			BOOL bRes = pControl->GetScrollInfo(SB_HORZ, &scrollInfo);
			if (bRes)
			{
				if (scrollInfo.nPos > scrollInfo.nMin)
				{
					if (bFullColumnScrolling)
						pControl->SendMessage(WM_HSCROLL, SB_LINELEFT);
					else
						pControl->SetScrollOffsetH(scrollInfo.nPos - nStep);

					SetTimer(1, uTimer, NULL);
					bScrolled = TRUE;
				}
			}
		}
	}

	//-------------------------------------------------------------------------
	if (bScrolled)
	{
		CPoint ptMouse = ptMouseScreen;
		pControl->ScreenToClient(&ptMouse);

		pControl->RedrawControl();
		pControl->UpdateWindow();

		m_pHeader->OnMouseMove(0, ptMouse);
	}
}

/////////////////////////////////////////////////////////////////////////////
// CXTPReportHeaderDropWnd

CXTPReportHeaderDropWnd::CXTPReportHeaderDropWnd(COLORREF crColor)
	: m_clr(crColor)
{
	m_nHeight = 0;
}

CXTPReportHeaderDropWnd::~CXTPReportHeaderDropWnd()
{
}


BEGIN_MESSAGE_MAP(CXTPReportHeaderDropWnd, CWnd)
	//{{AFX_MSG_MAP(CXTPReportHeaderDropWnd)
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CXTPReportHeaderDropWnd message handlers

BOOL CXTPReportHeaderDropWnd::Create(CWnd* /*pParentWnd*/, int nHeight)
{
	m_nHeight = nHeight + 20;

	DWORD dwStyle = WS_POPUP | WS_DISABLED;
	DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST ;

	BOOL bResult = CreateEx(dwExStyle, AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), NULL, dwStyle,
		0, 0, 12, m_nHeight,
		NULL, NULL, NULL);

	CRgn rgn1, rgn2;
	POINT ptArrow[7];

	ptArrow[0].x = 8;   ptArrow[0].y = 0;
	ptArrow[1].x = 8;   ptArrow[1].y = 4;
	ptArrow[2].x = 11;  ptArrow[2].y = 4;
	ptArrow[3].x = 6;   ptArrow[3].y = 9;
	ptArrow[4].x = 1;   ptArrow[4].y = 4;
	ptArrow[5].x = 4;   ptArrow[5].y = 4;
	ptArrow[6].x = 4;   ptArrow[6].y = 0;
	rgn1.CreatePolygonRgn(ptArrow, 7, ALTERNATE);


	ptArrow[0].x = 4;   ptArrow[0].y = m_nHeight;
	ptArrow[1].x = 4;   ptArrow[1].y = m_nHeight-4;
	ptArrow[2].x = 0;   ptArrow[2].y = m_nHeight-4;
	ptArrow[3].x = 6;   ptArrow[3].y = m_nHeight-10;
	ptArrow[4].x = 12;  ptArrow[4].y = m_nHeight-4;
	ptArrow[5].x = 8;   ptArrow[5].y = m_nHeight-4;
	ptArrow[6].x = 8;   ptArrow[6].y = m_nHeight;
	rgn2.CreatePolygonRgn(ptArrow, 7, ALTERNATE);

	m_rgn.CreateRectRgn(0, 0, 12, nHeight);
	m_rgn.CombineRgn(&rgn1, &rgn2, RGN_OR);
	SetWindowRgn(m_rgn, FALSE);

	rgn1.DeleteObject();
	rgn2.DeleteObject();

	return bResult;
}


void CXTPReportHeaderDropWnd::PostNcDestroy()
{
	m_rgn.DeleteObject();

	CWnd::PostNcDestroy();
	delete this;
}

BOOL CXTPReportHeaderDropWnd::OnEraseBkgnd(CDC* pDC)
{
	pDC->FillSolidRect(0, 0, 12, m_nHeight, m_clr);
	return TRUE;
}

void CXTPReportHeaderDropWnd::SetWindowPos(int x, int y)
{
	CWnd::SetWindowPos(0, x - 6, y - (m_nHeight / 2), 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}