// XTPSyntaxEditPaintManager.cpp : implementation of the CXTPSyntaxEditPaintManager class.
//
// This file is a part of the XTREME TOOLKIT PRO 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 SYNTAX EDIT 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 "Resource.h"
#include <math.h>

// common includes
#include "Common/XTPVC80Helpers.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPResourceManager.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPSmartPtrInternalT.h"


// syntax editor includes
#include "XTPSyntaxEditDefines.h"
#include "XTPSyntaxEditStruct.h"
#include "XTPSyntaxEditLineMarksManager.h"
#include "XTPSyntaxEditLexPtrs.h"
#include "XTPSyntaxEditTextIterator.h"
#include "XTPSyntaxEditLexParser.h"
#include "XTPSyntaxEditCtrl.h"
#include "XTPSyntaxEditPaintManager.h"
#include "XTPSyntaxEditBufferManager.h"
#include "XTPSyntaxEditDrawTextProcessor.h"
#include "XTPSyntaxEditSelection.h"


using namespace XTPSyntaxEditLexAnalyser;

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

//===========================================================================
// CXTPSyntaxEditPaintManager class
//===========================================================================
IMPLEMENT_DYNAMIC(CXTPSyntaxEditPaintManager, CCmdTarget)

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CXTPSyntaxEditPaintManager::CXTPSyntaxEditPaintManager()
{

	m_hCurLine = XTPResourceManager()->LoadCursor(XTP_IDC_EDIT_BACKARROW);
	m_hCurMove = XTPResourceManager()->LoadCursor(XTP_IDC_EDIT_MOVE);
	m_hCurCopy = XTPResourceManager()->LoadCursor(XTP_IDC_EDIT_COPY);
	m_hCurIBeam = AfxGetApp()->LoadStandardCursor(IDC_IBEAM);
	m_hCurArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
	m_hCurNO = AfxGetApp()->LoadStandardCursor(IDC_NO);

	// get non-client metrics info.
	NONCLIENTMETRICS ncm;
	ncm.cbSize = sizeof(NONCLIENTMETRICS);
	::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);

	// create the tooltip font.
	VERIFY(SetFontToolTip(&ncm.lfStatusFont));

	// construct default fonts.
	VERIFY(CreateFontIndirect(NULL, FALSE));

	// Initialize metrics
	RefreshMetrics();
	InitBitmaps();

	m_sLineNumberFormat = _T("%d");
	//m_sLineNumberFormat = _T("%02d");
	//m_sLineNumberFormat = _T("%2d"); //Good default for practical cases

}

CXTPSyntaxEditPaintManager::~CXTPSyntaxEditPaintManager()
{

}

void CXTPSyntaxEditPaintManager::InitBitmaps()
{
	// Check for already initialized bitmaps
	m_ilBookmark.DeleteImageList();

	// Load bookmarks bitmap
	CBitmap bmpBookMarks;       // Regular bookmark image

	if (XTPResourceManager()->LoadBitmap(& bmpBookMarks, XTP_IDB_EDIT_BOOKMARKS))
	{
		BITMAP info;
		bmpBookMarks.GetBitmap(&info);

		if (m_ilBookmark.Create(20, info.bmHeight,
			ILC_COLOR24|ILC_MASK, 0, 1))
		{
			m_ilBookmark.Add(&bmpBookMarks, RGB(0x00, 0xff, 0x00));
		}
	}
}

HCURSOR CXTPSyntaxEditPaintManager::SetMoveCursor(HCURSOR hCurMove)
{
	HCURSOR hCurMoveOld = m_hCurMove;
	m_hCurMove = hCurMove;
	return hCurMoveOld;
}

HCURSOR CXTPSyntaxEditPaintManager::SetCopyCursor(HCURSOR hCurCopy)
{
	HCURSOR hCurCopyOld = m_hCurCopy;
	m_hCurCopy = hCurCopy;
	return hCurCopyOld;
}

HCURSOR CXTPSyntaxEditPaintManager::SetLineSelCursor(HCURSOR hCur)
{
	HCURSOR hCurOld = m_hCurLine;
	m_hCurLine = hCur;
	return hCurOld;
}

AFX_STATIC void GetCustomValue(CWinApp* pWinApp, LPCTSTR lpszRegKey, CXTPPaintManagerColor& pmc)
{
	COLORREF color = pWinApp->GetProfileInt(XTP_EDIT_REG_SETTINGS,
		lpszRegKey, pmc.GetStandardColor());

	if (color != pmc.GetStandardColor())
	{
		pmc = color;
	}
}

void CXTPSyntaxEditPaintManager::RefreshMetrics()
{
	// Initialize default colors.
	m_clrValues.crText.SetStandardValue(::GetSysColor(COLOR_WINDOWTEXT));
	m_clrValues.crBack.SetStandardValue(::GetSysColor(COLOR_WINDOW));
	m_clrValues.crReadOnlyBack.SetStandardValue(::GetSysColor(COLOR_3DFACE));
	m_clrValues.crHiliteText.SetStandardValue(::GetSysColor(COLOR_HIGHLIGHTTEXT));
	m_clrValues.crHiliteBack.SetStandardValue(::GetSysColor(COLOR_HIGHLIGHT));
	m_clrValues.crInactiveHiliteText.SetStandardValue(::GetSysColor(COLOR_INACTIVECAPTIONTEXT));
	m_clrValues.crInactiveHiliteBack.SetStandardValue(::GetSysColor(COLOR_INACTIVECAPTION));
	m_clrValues.crLineNumberText.SetStandardValue(RGB(0x00, 0x82, 0x84));
	m_clrValues.crLineNumberBack.SetStandardValue(::GetSysColor(COLOR_WINDOW));

	// Restore user settings from registry.
	CWinApp* pWinApp = AfxGetApp();
	if (pWinApp != NULL)
	{
		GetCustomValue(pWinApp, XTP_EDIT_REG_TEXTCOLOR, m_clrValues.crText);
		GetCustomValue(pWinApp, XTP_EDIT_REG_BACKCOLOR, m_clrValues.crBack);
		GetCustomValue(pWinApp, XTP_EDIT_REG_SELTEXTCOLOR, m_clrValues.crHiliteText);
		GetCustomValue(pWinApp, XTP_EDIT_REG_SELBACKCOLOR, m_clrValues.crHiliteBack);
		GetCustomValue(pWinApp, XTP_EDIT_REG_INSELTEXTCOLOR, m_clrValues.crInactiveHiliteText);
		GetCustomValue(pWinApp, XTP_EDIT_REG_INSELBACKCOLOR, m_clrValues.crInactiveHiliteBack);
		GetCustomValue(pWinApp, XTP_EDIT_REG_LINENUMTEXTCOLOR, m_clrValues.crLineNumberText);
		GetCustomValue(pWinApp, XTP_EDIT_REG_LINENUMBACKCOLOR, m_clrValues.crLineNumberBack);

		UINT nSize = 0;
		LOGFONT *pLogFont;
		if (pWinApp->GetProfileBinary(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_LOGFONT, (LPBYTE*)&pLogFont, &nSize))
		{
			CreateFontIndirect(pLogFont);
			delete [] pLogFont;
		}
	}

	// Initialize gray pen.
	if (m_penGray.m_hObject)
		m_penGray.DeleteObject();
	m_penGray.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
}

//////////////////////////////////////////////////////////////////////////

CFont* CXTPSyntaxEditPaintManager::GetFont()
{
	return &m_font;
}

BOOL CXTPSyntaxEditPaintManager::CreateFontIndirect(LPLOGFONT pLogfont, BOOL bUpdateReg/*=FALSE*/)
{
	LOGFONT lfDefault;

// construct default fonts.
	if (!pLogfont)
	{
#ifdef XTP_FIXED
// change default font  "Courier New" => OEM_FIXED_FONT
		HFONT hFont = (HFONT)::GetStockObject(OEM_FIXED_FONT);
		CFont font;
		font.Attach(hFont);
		font.GetLogFont(&lfDefault);
		font.Detach();
#else
		::ZeroMemory(&lfDefault, sizeof(LOGFONT));

		lfDefault.lfCharSet = XTPResourceManager()->GetFontCharset();
		lfDefault.lfWeight = FW_NORMAL;
		lfDefault.lfHeight = -13;
		STRCPY_S(lfDefault.lfFaceName, LF_FACESIZE, _T("Courier New"));
#endif
		pLogfont = &lfDefault;
	}

	if (!SetFont(pLogfont))
		return FALSE;

	if (!SetFontText(pLogfont))
		return FALSE;

	if (!SetFontLineNumber(pLogfont))
		return FALSE;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileBinary(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_LOGFONT,
				reinterpret_cast<LPBYTE>(pLogfont), sizeof(LOGFONT)))
			{
				return TRUE;
			}
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetFont(LPLOGFONT pLogfont)
{
	if (m_font.m_hObject)
	{
		m_font.DeleteObject();
	}
	return m_font.CreateFontIndirect(pLogfont);
}

CFont* CXTPSyntaxEditPaintManager::GetFontText()
{
	return &m_fontText;
}

BOOL CXTPSyntaxEditPaintManager::SetFontText(LPLOGFONT pLogfont)
{
	if (m_fontText.m_hObject)
	{
		m_fontText.DeleteObject();
	}
	return m_fontText.CreateFontIndirect(pLogfont);
}

CFont* CXTPSyntaxEditPaintManager::GetFontLineNumber()
{
	return &m_fontLineNumber;
}

BOOL CXTPSyntaxEditPaintManager::SetFontLineNumber(LPLOGFONT pLogfont)
{
	if (m_fontLineNumber.m_hObject)
	{
		m_fontLineNumber.DeleteObject();
	}
	return m_fontLineNumber.CreateFontIndirect(pLogfont);
}

CFont* CXTPSyntaxEditPaintManager::GetFontToolTip()
{
	return &m_fontToolTip;
}

BOOL CXTPSyntaxEditPaintManager::SetFontToolTip(LPLOGFONT pLogfont)
{
	if (m_fontToolTip.m_hObject)
	{
		m_fontToolTip.DeleteObject();
	}
	return m_fontToolTip.CreateFontIndirect(pLogfont);
}

//////////////////////////////////////////////////////////////////////////

HCURSOR CXTPSyntaxEditPaintManager::GetCurLine()
{
	return m_hCurLine;
}

HCURSOR CXTPSyntaxEditPaintManager::GetCurMove()
{
	return m_hCurMove;
}

HCURSOR CXTPSyntaxEditPaintManager::GetCurCopy()
{
	return m_hCurCopy;
}

HCURSOR CXTPSyntaxEditPaintManager::GetCurNO()
{
	return m_hCurNO;
}

HCURSOR CXTPSyntaxEditPaintManager::GetCurIBeam()
{
	return m_hCurIBeam;
}

HCURSOR CXTPSyntaxEditPaintManager::GetCurArrow()
{
	return m_hCurArrow;
}

BOOL CXTPSyntaxEditPaintManager::SetTextColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crText = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_TEXTCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetBackColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crBack = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_BACKCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetReadOnlyBackColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crReadOnlyBack = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_READONLYBACKCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}


BOOL CXTPSyntaxEditPaintManager::SetHiliteTextColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crHiliteText = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_SELTEXTCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetHiliteBackColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crHiliteBack = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_SELBACKCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetInactiveHiliteTextColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crInactiveHiliteText = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_INSELTEXTCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetInactiveHiliteBackColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crInactiveHiliteBack = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_INSELBACKCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetLineNumberTextColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crLineNumberText = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_LINENUMTEXTCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditPaintManager::SetLineNumberBackColor(COLORREF color, BOOL bUpdateReg/*=FALSE*/)
{
	m_clrValues.crLineNumberBack = color;

	if (bUpdateReg)
	{
		CWinApp* pWinApp = AfxGetApp();
		if (pWinApp != NULL)
		{
			if (pWinApp->WriteProfileInt(XTP_EDIT_REG_SETTINGS, XTP_EDIT_REG_LINENUMBACKCOLOR, (int)color))
				return TRUE;
		}
		return FALSE;
	}

	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
CImageList* CXTPSyntaxEditPaintManager::GetBookmarks()
{
	return &m_ilBookmark;
}

//////////////////////////////////////////////////////////////////////////

BOOL CXTPSyntaxEditPaintManager::UpdateTextFont(CXTPSyntaxEditCtrl* pEditCtrl, const XTP_EDIT_FONTOPTIONS& lf)
{
	LOGFONT lfOpt;
	m_font.GetLogFont(&lfOpt);

	if (pEditCtrl && pEditCtrl->GetSyntaxColor())
	{
		if (lf.lfItalic != XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION)
		{
			lfOpt.lfItalic = lf.lfItalic;
		}
		if (lf.lfWeight != XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION)
		{
			lfOpt.lfWeight = lf.lfWeight;
		}
		if (lf.lfUnderline != XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION)
		{
			lfOpt.lfUnderline = lf.lfUnderline;
		}
	}

	return SetFontText(&lfOpt);
}

void CXTPSyntaxEditPaintManager::DrawLineNumber(CDC *pDC, const CRect& rcRect, int nTextRow, CXTPSyntaxEditCtrl* pEditCtrl)
{
	if (!pEditCtrl)
		return;

	if (nTextRow < 1)
		return;

	if (!pDC->IsPrinting())
	{
		COLORREF clrBk = m_clrValues.crLineNumberBack;
		if (m_clrValues.crLineNumberBack.IsStandardValue()
			&& pEditCtrl->IsReadOnly()
			&& !pEditCtrl->IsViewOnly())
			clrBk = m_clrValues.crReadOnlyBack;

		pDC->FillSolidRect(&rcRect, clrBk);
	}

	CXTPFontDC fontDC(pDC, GetFontLineNumber(), m_clrValues.crLineNumberText);

	CRect rcLineNum(rcRect);
	rcLineNum.right -= 2;

	if (nTextRow <= pEditCtrl->GetRowCount())
	{
		// Print line number
		CString strLineNum;
		CString sLineNumberFormat(m_sLineNumberFormat);
		if (!m_sLineNumberFormat.IsEmpty())
		{
			sLineNumberFormat.Replace(_T("%"), _T(""));
			sLineNumberFormat.Replace(_T("d"), _T(""));
			int N = _ttoi(sLineNumberFormat);
			if (N > 0 && nTextRow < pow(10.0, N))
				strLineNum.Format(m_sLineNumberFormat, nTextRow);
			else
				strLineNum.Format(_T("%d"), nTextRow);
		}
		else
			strLineNum.Format(_T("%d"), nTextRow);

		pDC->DrawText(strLineNum, &rcLineNum, DT_VCENTER|DT_RIGHT);
	}

	if (!pDC->IsPrinting())
		DrawLineNumbersBorder(pDC, rcLineNum, m_clrValues.crLineNumberText);
}

void CXTPSyntaxEditPaintManager::DrawLineNumbersBorder(CDC *pDC, const CRect& rcLineNum, const COLORREF clrBorder)
{
	for (int y = rcLineNum.top; y < rcLineNum.bottom; y++)
	{
		if (y % 2)
			pDC->SetPixelV(rcLineNum.right + 1, y, clrBorder);
	}
}

void CXTPSyntaxEditPaintManager::DrawLineNodeBackground(CDC *pDC, const CRect& rcNodeFull,
			DWORD dwType, int nTextRow, CXTPSyntaxEditCtrl* pEditCtrl)
{
	UNREFERENCED_PARAMETER(dwType); UNREFERENCED_PARAMETER(nTextRow);

	pDC->FillSolidRect(&rcNodeFull, m_clrValues.GetBackColorEx(pEditCtrl));
}

void CXTPSyntaxEditPaintManager::DrawLineNode(CDC *pDC, const CRect& rcNode, const CRect& rcNodeFull,
			DWORD dwType, int nTextRow, CXTPSyntaxEditCtrl* pEditCtrl)
{
	if (!pEditCtrl || !pEditCtrl->GetCollapsibleNodes())
		return;

	// fill node background
	DrawLineNodeBackground(pDC, rcNodeFull, dwType, nTextRow, pEditCtrl);

	// draw node picture
	if (dwType != XTP_EDIT_ROWNODE_NOTHING)
	{
		CXTPPenDC penGray(pDC, &m_penGray);

		if (dwType & XTP_EDIT_ROWNODE_NODEUP)
		{
			// draw up line
			CPoint ptEnd(rcNode.CenterPoint().x, rcNodeFull.top);
			pDC->MoveTo(ptEnd);
			ptEnd.y += rcNodeFull.Height() / 2;
			pDC->LineTo(ptEnd);
		}

		if (dwType & XTP_EDIT_ROWNODE_NODEDOWN)
		{
			// draw down line
			CPoint ptEnd(rcNode.CenterPoint().x, rcNodeFull.bottom);
			pDC->MoveTo(ptEnd);
			ptEnd.y -= rcNodeFull.Height() / 2 + 2;
			pDC->LineTo(ptEnd);
		}

		if (dwType & XTP_EDIT_ROWNODE_ENDMARK)
		{
			// draw down line
			CPoint ptEnd(rcNode.CenterPoint());
			pDC->MoveTo(ptEnd);
			ptEnd.x += rcNodeFull.Width() / 2;
			pDC->LineTo(ptEnd);
		}

		if (dwType & XTP_EDIT_ROWNODE_COLLAPSED ||
			dwType & XTP_EDIT_ROWNODE_EXPANDED)
		{
			// draw collapsed sign
			pDC->Rectangle(&rcNode);
			CPoint ptSign(rcNode.CenterPoint());
			ptSign.x -= 2;
			pDC->MoveTo(ptSign);
			ptSign.x += 5;
			pDC->LineTo(ptSign);
		}

		if (dwType & XTP_EDIT_ROWNODE_COLLAPSED)
		{
			// draw vertical line of the expanded sign
			CPoint ptSign(rcNode.CenterPoint());
			ptSign.y -= 2;
			pDC->MoveTo(ptSign);
			ptSign.y += 5;
			pDC->LineTo(ptSign);

		}
	}
}

void CXTPSyntaxEditPaintManager::DrawCollapsedTextMarks(CXTPSyntaxEditCtrl* pEditCtrl, CDC *pDC)
{
	COLORREF clrFrame = GetSysColor(COLOR_BTNSHADOW);
	COLORREF crText = GetSysColor(COLOR_BTNSHADOW);

	CXTPFontDC fontDC(pDC, GetFont());

	const XTP_EDIT_COLLAPSEDBLOCK* pCoDrawBlk = NULL;
	XTP_EDIT_LMPARAM LMCoParam;
	int nActualRow = 0;

	for (int i = 0; i < pEditCtrl->m_nCollapsedTextRowsCount; i++)
	{
		// get next collapsed row
		int nRow = pEditCtrl->m_arCollapsedTextRows[i];

		if (nRow <= nActualRow)
		{
			continue;
		}

		if (!pEditCtrl->HasRowMark(nRow, xtpEditLMT_Collapsed, &LMCoParam))
		{
			continue;
		}

		// get count of collapsed rows under this row
		int nHiddenRows = 0;
		if (!pEditCtrl->GetCollapsedBlockLen(nRow, nHiddenRows))
		{
			continue;
		}

		nActualRow = nRow + nHiddenRows;

		// get collapsed block pointer
		pCoDrawBlk = (XTP_EDIT_COLLAPSEDBLOCK*)LMCoParam.GetPtr();

		if (!pCoDrawBlk)
		{
			ASSERT(FALSE);
			continue;
		}

		CString strText = pCoDrawBlk->collBlock.strCollapsedText; // "[..]"
		CRect rcFrame(pCoDrawBlk->rcCollMark);
		rcFrame.InflateRect(0, 0, 0, 1);

		CRect rcText = pCoDrawBlk->rcCollMark;
		rcText.DeflateRect(1, 0, 1, 0);

		COLORREF clrBack = (pEditCtrl->IsReadOnly() && !pEditCtrl->IsViewOnly())
			? (COLORREF)m_clrValues.crReadOnlyBack
			: (COLORREF)m_clrValues.crBack;
		pDC->FillSolidRect(&rcText, clrBack);

		pDC->SetTextColor(crText);
		pDC->SetBkColor(clrBack);

		pDC->DrawText(strText, &rcText, 0);

		pDC->Draw3dRect(&rcFrame, clrFrame, clrFrame);
	}
}

void CXTPSyntaxEditPaintManager::DrawLineCalcSel(const XTP_EDIT_TEXTBLOCK& txtBlk,
									  int nSelStartX, int nSelEndX,
									  XTP_EDIT_TEXTBLOCK (&arTxtBlk)[4], BOOL (&bUseBlk)[4] )
{
	ASSERT(nSelStartX < nSelEndX);

	if (txtBlk.nPos < nSelStartX && txtBlk.nNextBlockPos-1 >= nSelStartX &&
		txtBlk.nNextBlockPos <= nSelEndX)
	{
		arTxtBlk[1] = arTxtBlk[2] = txtBlk;

		arTxtBlk[1].nNextBlockPos = nSelStartX;
		arTxtBlk[2].nPos = nSelStartX;

		bUseBlk[1] = bUseBlk[2] = TRUE;
	}
	else if (txtBlk.nPos >= nSelStartX && txtBlk.nPos < nSelEndX &&
		txtBlk.nNextBlockPos > nSelEndX)
	{
		arTxtBlk[2] = arTxtBlk[3] = txtBlk;

		arTxtBlk[2].nNextBlockPos = nSelEndX;
		arTxtBlk[3].nPos = nSelEndX;

		bUseBlk[2] = bUseBlk[3] = TRUE;
	}
	else if (txtBlk.nPos >= nSelStartX && txtBlk.nNextBlockPos <= nSelEndX)
	{
		arTxtBlk[2] = txtBlk;
		bUseBlk[2] = TRUE;
	}
	else if (txtBlk.nPos < nSelStartX && txtBlk.nNextBlockPos > nSelEndX)
	{
		arTxtBlk[1] = arTxtBlk[2] = arTxtBlk[3] = txtBlk;

		arTxtBlk[1].nNextBlockPos = nSelStartX;
		arTxtBlk[2].nPos = nSelStartX;
		arTxtBlk[2].nNextBlockPos = nSelEndX;
		arTxtBlk[3].nPos = nSelEndX;

		bUseBlk[1] = bUseBlk[2] = bUseBlk[3] = TRUE;
	}
	else
	{
		ASSERT(txtBlk.nPos >= nSelEndX || txtBlk.nNextBlockPos <= nSelStartX);

		arTxtBlk[1] = txtBlk;
		bUseBlk[1] = TRUE;
	}
}

void CXTPSyntaxEditPaintManager::DrawLineMark(CXTPSyntaxEditCtrl* pEditCtrl, XTP_EDIT_SENMBOOKMARK* pBookmark)
{
	enum { bookMark, bookMarkSel, breakpoint };

	POINT ptStart;
	ptStart.x = pBookmark->rcBookmark.left;
	ptStart.y = pBookmark->rcBookmark.top;

	SIZE szRect;
	szRect.cx = pBookmark->rcBookmark.right - pBookmark->rcBookmark.left;
	szRect.cy = pBookmark->rcBookmark.bottom - pBookmark->rcBookmark.top;

	CDC *pDC = CDC::FromHandle(pBookmark->hDC);

	IMAGEINFO bmpInfo;
	ZeroMemory(&bmpInfo, sizeof(bmpInfo));

	if (pEditCtrl->HasRowMark(pBookmark->nRow, xtpEditLMT_Bookmark))
	{
		int iImage = (pEditCtrl->GetCurrentDocumentRow() == pBookmark->nRow && pEditCtrl->HasFocus())? bookMarkSel: bookMark;
		if (GetBookmarks()->GetImageInfo(iImage, &bmpInfo))
		{
			CRect rcBmp(bmpInfo.rcImage);
			szRect.cx = min(szRect.cx, rcBmp.Width());
			szRect.cy = min(szRect.cy, rcBmp.Height());
		}

		IMAGELISTDRAWINDIRECT_S(GetBookmarks(), pDC, iImage, ptStart, szRect);
	}

	if (pEditCtrl->HasRowMark(pBookmark->nRow, xtpEditLMT_Breakpoint))
	{
		if (GetBookmarks()->GetImageInfo(breakpoint, &bmpInfo))
		{
			CRect rcBmp(bmpInfo.rcImage);
			szRect.cx = min(szRect.cx, rcBmp.Width());
			szRect.cy = min(szRect.cy, rcBmp.Height());
		}

		IMAGELISTDRAWINDIRECT_S(GetBookmarks(), pDC, breakpoint, ptStart, szRect);

		pEditCtrl->SetInternalRowBkColor(pBookmark->nRow, RGB(128, 0, 0));
		pEditCtrl->SetInternalRowColor(pBookmark->nRow, RGB(255, 255, 255));
	}
}

void CXTPSyntaxEditPaintManager::DrawLineMarks(CDC *pDC, const CRect& rcRect, int nTextRow, CXTPSyntaxEditCtrl* pEditCtrl)
{
	// NMHDR codes
	XTP_EDIT_SENMBOOKMARK bookmark;
	bookmark.nmhdr.code = XTP_EDIT_NM_DRAWBOOKMARK;
	bookmark.nmhdr.hwndFrom = pEditCtrl->GetSafeHwnd();
	bookmark.nmhdr.idFrom = 0;

	bookmark.hDC = pDC->GetSafeHdc();

	bookmark.rcBookmark = rcRect;
	bookmark.nRow = nTextRow;

	CRect rcLine = bookmark.rcBookmark;
	rcLine.left = rcLine.right-1;

	pDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
	pDC->SetTextColor(::GetSysColor(COLOR_BTNFACE));
	pDC->FillRect(&bookmark.rcBookmark, pDC->GetHalftoneBrush());
	pDC->FillSolidRect(rcLine, ::GetSysColor(COLOR_3DSHADOW));

	BOOL bHandled = FALSE;
	CWnd *pParent = pEditCtrl->GetParent();
	if (pParent)
	{
		bHandled = (BOOL)pParent->SendMessage(WM_NOTIFY, 0, (LPARAM)&bookmark);
	}

	if (!bHandled)
	{
		DrawLineMark(pEditCtrl, &bookmark);
	}
}



int CXTPSyntaxEditPaintManager::DrawLineTextEx(CDC *pDC, const CRect& rcTextLine, int nTextRow,
											  int nLine, CXTPSyntaxEditCtrl* pEditCtrl)
{
	int nRowHeight = 0;

	ASSERT(pDC && pEditCtrl);
	if (!pDC || !pEditCtrl)
		return nRowHeight;

	CXTPSyntaxEditDrawTextProcessor& drawTxtProc = pEditCtrl->GetDrawTextProcessor();

	drawTxtProc.ResetRowInfo(nLine);

	if (nTextRow <= 0)
		return nRowHeight;

	const CString& strText = pEditCtrl->GetLineText(nTextRow);
	int nTextLenC = (int)_tcsclen(strText);
	CString strDispText;

	drawTxtProc.ExpandChars(strText, strDispText, 0, pEditCtrl->IsEnabledWhiteSpace());
	drawTxtProc.SetRowTabPositions(nLine, strText);

	COLORREF crBreakText = pEditCtrl->GetRowColor(nTextRow);
	BOOL bBreakText = crBreakText != COLORREF_NULL;

	COLORREF crBreakBack = pEditCtrl->GetRowBkColor(nTextRow);
	BOOL bBreakBack  = crBreakBack != COLORREF_NULL;

	if (!bBreakBack)
		crBreakBack = m_clrValues.GetBackColorEx(pEditCtrl);

	if (!pDC->IsPrinting())
		pDC->FillSolidRect(&rcTextLine, crBreakBack);

	if (nTextRow > pEditCtrl->GetRowCount())
		return nRowHeight;

	pDC->SetBkMode(OPAQUE);
	pDC->SetTextColor(m_clrValues.crText);

	CXTPSyntaxEditTextBlockList blocks;

	pEditCtrl->GetRowColors(nTextRow, 0, -1, m_clrValues, &blocks);


	if (blocks.GetCount() == 0)
	{
		XTP_EDIT_TEXTBLOCK defBlk;
		defBlk.nPos = 0;
		defBlk.nNextBlockPos = nTextLenC;
		defBlk.clrBlock = m_clrValues;
		blocks.AddTail(defBlk);
	}

	// draw text

	//=======================================================================
	BOOL bCoBlkDrawn = FALSE;
	XTP_EDIT_COLLAPSEDBLOCK* pCoDrawBlk = NULL;
	XTP_EDIT_LMPARAM LMCoParam;
	if (pEditCtrl->HasRowMark(nTextRow, xtpEditLMT_Collapsed, &LMCoParam))
	{
		pCoDrawBlk = (XTP_EDIT_COLLAPSEDBLOCK*)LMCoParam.GetPtr();
		ASSERT(pCoDrawBlk);
	}

	//---------------------------------------------------------------
	BOOL bInfinitSelEnd = FALSE;
	int nSelStart = pEditCtrl->m_pSelection->GetSelStartForRow_str(nTextRow, nLine);
	int nSelEnd = pEditCtrl->m_pSelection->GetSelEndForRow_str(nTextRow, nLine, &bInfinitSelEnd);

	//---------------------------------------------------------------
	POSITION pos = blocks.GetHeadPosition();
	while (pos)
	{
		const XTP_EDIT_TEXTBLOCK& txtBlk = blocks.GetNext(pos);

		// draw [...] if needed
		if (pCoDrawBlk)
		{
			CRect rcCoBlk = rcTextLine;
			rcCoBlk.left += drawTxtProc.GetRowWidth(nLine) - drawTxtProc.GetScrollXOffset();
			rcCoBlk.left = max(rcCoBlk.left, rcTextLine.left);
			rcCoBlk.left = min(rcCoBlk.left, rcTextLine.right);

			bCoBlkDrawn = pEditCtrl->ProcessCollapsedTextEx(pDC, pCoDrawBlk, txtBlk, rcCoBlk);
			if (bCoBlkDrawn)
			{
				break;
			}
		}

		// define default colors.
		COLORREF crBack = m_clrValues.GetBackColorEx(pEditCtrl);
		COLORREF crText = m_clrValues.crText;
		COLORREF crHiliteBack = m_clrValues.crHiliteBack;
		COLORREF crHiliteText = m_clrValues.crHiliteText;
		//COLORREF crInactiveHiliteText = m_clrValues.crInactiveHiliteText;
		//COLORREF crInactiveHiliteBack = m_clrValues.crInactiveHiliteBack;

// if syntax coloring is enabled use defined colors.
//      if (pEditCtrl->GetSyntaxColor())
//      {
		crBack    = txtBlk.clrBlock.crBack;
		crText    = txtBlk.clrBlock.crText;
		crHiliteBack = txtBlk.clrBlock.crHiliteBack;
		crHiliteText = txtBlk.clrBlock.crHiliteText;
//      }

		if (bBreakBack)
			crBack = crBreakBack;

		if (bBreakText)
			crText = crBreakText;

		//--------------------------------------------------------------
		if (crBack == (COLORREF)m_clrValues.crBack)
			crBack = m_clrValues.GetBackColorEx(pEditCtrl);

		//if (crBack == m_clrValues.crBack.GetStandardColor())
//          crBack = m_clrValues.crBack;

//      if (crText == m_clrValues.crText.GetStandardColor())
//          crText = m_clrValues.crText;

		//--------------------------------------------------------------
		//if (!pEditCtrl->IsActive() || !pEditCtrl->m_bFocused)
		if (!pEditCtrl->IsActive())
		{
			if (crHiliteBack == m_clrValues.crHiliteBack.GetStandardColor())
				crHiliteBack = m_clrValues.crInactiveHiliteBack;

			if (crHiliteText == m_clrValues.crHiliteText.GetStandardColor())
				crHiliteText = m_clrValues.crInactiveHiliteText;
		}

		//--------------------------------------------------------------
		XTP_EDIT_TEXTBLOCK arTxtBlk[4];
		BOOL bUseBlk[4] = {FALSE, FALSE, FALSE, FALSE};

		if (pEditCtrl->m_pSelection->IsIntersectSel_str(nTextRow, txtBlk.nPos/* + 1*/, txtBlk.nNextBlockPos) &&
			!pDC->IsPrinting() && nTextLenC && nSelStart < nSelEnd)
		{
			DrawLineCalcSel(txtBlk, nSelStart, nSelEnd, arTxtBlk, bUseBlk);
		}
		else if (nTextLenC)
		{
			arTxtBlk[1] = txtBlk;
			bUseBlk[1] = TRUE;
		}

		//**************************************************
		for (int i = 1; i <= 3; i++)
		{
			if (!bUseBlk[i])
				continue;

			pDC->SetTextColor((i%2) ? crText : crHiliteText);
			pDC->SetBkColor((i%2) ? crBack : crHiliteBack);

			//pDC->SetTextColor((i%2) ? crText : ((pEditCtrl->GetFocus() == pEditCtrl) ? crHiliteText : crInactiveHiliteText));
			//pDC->SetBkColor((i%2) ? crBack : ((pEditCtrl->GetFocus() == pEditCtrl) ? crHiliteBack : crInactiveHiliteBack));

			int nOutStrPos = drawTxtProc.StrPosToDispPos(nLine, arTxtBlk[i].nPos);
			int nNextOutStrPos = drawTxtProc.StrPosToDispPos(nLine, arTxtBlk[i].nNextBlockPos);
			int nOutStrLen = nNextOutStrPos - nOutStrPos;
			//LPCTSTR pText = (LPCTSTR)strDispText + nOutStrPos;
#ifdef XTP_FIXED
// nOutStrPos : Display Length
			LPCTSTR pText = (LPCTSTR) strDispText + nOutStrPos;
#else
			LPCTSTR pText = _tcsninc((LPCTSTR)strDispText, nOutStrPos);
#endif
			UpdateTextFont(pEditCtrl, arTxtBlk[i].lf);
			CXTPFontDC fontDC(pDC, GetFontText());

			if (!pDC->IsPrinting())
			{
				drawTxtProc.DrawRowPart(pDC, nLine, pText, nOutStrLen);
			}
			else
			{
				int nOffsetY = rcTextLine.top - drawTxtProc.GetTextRect().top;
				nRowHeight = drawTxtProc.PrintRowPart(pDC, nTextRow, nOffsetY, 0,
													  pText, nOutStrLen, 0);//int *pnPrintedTextLen)
			}
		}

		if (!pDC->IsPrinting())
		{
			// draw selection for virtual space, after line text end)
			if (!pos && ((nSelStart < nSelEnd && nSelEnd > nTextLenC) || bInfinitSelEnd))
			{
				CRect rcSel = rcTextLine;
				rcSel.left += drawTxtProc.GetRowWidth(nLine) - drawTxtProc.GetScrollXOffset();

				if (!bInfinitSelEnd || nSelStart > nTextLenC)
				{
					if (nSelStart > nTextLenC)
						rcSel.left += drawTxtProc.GetSpaceWidth() * (nSelStart - nTextLenC);

					if (!bInfinitSelEnd)
						rcSel.right = rcSel.left + drawTxtProc.GetSpaceWidth() * abs(nSelEnd - max(nTextLenC, nSelStart));
				}

				rcSel.left = max(min(rcSel.left, rcTextLine.right), rcTextLine.left);
				rcSel.right = max(min(rcSel.right, rcTextLine.right), rcTextLine.left);

				pDC->FillSolidRect(rcSel, crHiliteBack);
			}
		}
	}

	//===========================================================================
	// draw [...] if needed and not yet
	if (pCoDrawBlk && !bCoBlkDrawn)
	{
		CRect rcCoBlk = rcTextLine;
		rcCoBlk.left += drawTxtProc.GetRowWidth(nLine) - drawTxtProc.GetScrollXOffset();
		rcCoBlk.left = max(rcCoBlk.left, rcTextLine.left);
		rcCoBlk.left = min(rcCoBlk.left, rcTextLine.right);

		pEditCtrl->ProcessCollapsedText(pDC, pCoDrawBlk, rcCoBlk);
	}

	pDC->SetTextColor(m_clrValues.crText);

	return nRowHeight;
}


int CXTPSyntaxEditPaintManager::PrintLineTextEx(CDC *pDC, const CRect& rcTextLine, int nTextRow,
												int nLine, CXTPSyntaxEditCtrl* pEditCtrl, int nFlags)
{
	ASSERT(pDC && pEditCtrl);
	if (!pDC || !pEditCtrl)
		return 0;

	CXTPSyntaxEditDrawTextProcessor& drawTxtProc = pEditCtrl->GetDrawTextProcessor();

	int nRowHeight = drawTxtProc.GetRowHeight();

	const CString& strText = pEditCtrl->GetLineText(nTextRow);
	int nTextLenC = (int)_tcsclen(strText);
	CString strDispText;
	drawTxtProc.ExpandChars(strText, strDispText, 0, pEditCtrl->IsEnabledWhiteSpace());

	drawTxtProc.ResetRowInfo(nLine);
	drawTxtProc.SetRowTabPositions(nLine, strText);

	COLORREF crBreakText = pEditCtrl->GetRowColor(nTextRow);
	BOOL bBreakText = crBreakText != COLORREF_NULL;

	COLORREF crBreakBack = pEditCtrl->GetRowBkColor(nTextRow);
	BOOL bBreakBack  = crBreakBack != COLORREF_NULL;

	CXTPSyntaxEditLexTextSchema* ptrTxtSch = pEditCtrl->m_pBuffer->GetLexParser()->GetTextSchema();

	if (!bBreakBack)
		crBreakBack = m_clrValues.crBack;

	if (nTextRow > pEditCtrl->GetRowCount())
		return 0;

	pDC->SetBkMode(OPAQUE);
	pDC->SetTextColor(m_clrValues.crText);

	CXTPSyntaxEditTextBlockList blocks;

	if (ptrTxtSch)
	{
		CXTPSyntaxEditLexTextBlock* pScreenSchFirstTB = pEditCtrl->GetOnScreenSch(nTextRow);
		if (pScreenSchFirstTB)
		{
			CXTPSyntaxEditTextIterator txtIter(pEditCtrl->GetEditBuffer());
			ptrTxtSch->GetRowColors(&txtIter, nTextRow, 0, -1,
									m_clrValues, &blocks,
									NULL, pScreenSchFirstTB);
		}
	}

	if (blocks.GetCount() == 0)
	{
		XTP_EDIT_TEXTBLOCK defBlk;
		defBlk.nPos = 0;
		defBlk.nNextBlockPos = nTextLenC;
		defBlk.clrBlock = m_clrValues;
		blocks.AddTail(defBlk);
	}

	// draw text

	//=======================================================================
	BOOL bCoBlkDrawn = FALSE;
	XTP_EDIT_COLLAPSEDBLOCK* pCoDrawBlk = NULL;
	XTP_EDIT_LMPARAM LMCoParam;
	if (pEditCtrl->HasRowMark(nTextRow, xtpEditLMT_Collapsed, &LMCoParam))
	{
		pCoDrawBlk = (XTP_EDIT_COLLAPSEDBLOCK*)LMCoParam.GetPtr();
		ASSERT(pCoDrawBlk);
	}

	//---------------------------------------------------------------
	POSITION pos = blocks.GetHeadPosition();
	while (pos)
	{
		const XTP_EDIT_TEXTBLOCK& txtBlk = blocks.GetNext(pos);

		// draw [...] if needed
		if (pCoDrawBlk)
		{
			CRect rcCoBlk = rcTextLine;
			rcCoBlk.left += drawTxtProc.GetRowWidth(nLine) - drawTxtProc.GetScrollXOffset();
			rcCoBlk.left = max(rcCoBlk.left, rcTextLine.left);
			rcCoBlk.left = min(rcCoBlk.left, rcTextLine.right);

			bCoBlkDrawn = pEditCtrl->ProcessCollapsedTextEx(pDC, pCoDrawBlk, txtBlk, rcCoBlk);
			if (bCoBlkDrawn)
			{
				break;
			}
		}

		// define default colors.
		COLORREF crBack    = m_clrValues.crBack.GetStandardColor();
		COLORREF crText    = m_clrValues.crText.GetStandardColor();

		// if syntax coloring is enabled use defined colors.
		if (pEditCtrl->GetSyntaxColor())
		{
			crBack = txtBlk.clrBlock.crBack;
			crText = txtBlk.clrBlock.crText;
		}

		if (bBreakBack)
			crBack = crBreakBack;

		if (bBreakText)
			crText = crBreakText;

		//--------------------------------------------------------------
		if (crBack == m_clrValues.crBack.GetStandardColor())
			crBack = m_clrValues.crBack;

		if (crText == m_clrValues.crText.GetStandardColor())
			crText = m_clrValues.crText;

		//**************************************************
		pDC->SetTextColor(crText);
		pDC->SetBkColor(crBack);

		int nOutStrPos = drawTxtProc.StrPosToDispPos(nLine, txtBlk.nPos);
		int nNextOutStrPos = drawTxtProc.StrPosToDispPos(nLine, txtBlk.nNextBlockPos);
		int nOutStrLen = nNextOutStrPos - nOutStrPos;
		//LPCTSTR pText = (LPCTSTR)strDispText + nOutStrPos;
		LPCTSTR pText = _tcsninc((LPCTSTR)strDispText, nOutStrPos);

		UpdateTextFont(pEditCtrl, txtBlk.lf);
		CXTPFontDC fontDC(pDC, GetFontText());

		int nPrintedTextLen = 0;
		int nOffsetY = rcTextLine.top - drawTxtProc.GetTextRect().top;
		nRowHeight = drawTxtProc.PrintRowPart(pDC, nTextRow, nOffsetY, nFlags,
												  pText, nOutStrLen, &nPrintedTextLen);

		if (nPrintedTextLen < nOutStrLen)
		{
			if ((nFlags & DT_SINGLELINE) == 0)
			{
				nRowHeight = -1;
				pDC->FillSolidRect(&rcTextLine, pDC->GetBkColor());
			}

			break;
		}
	}

	//===========================================================================
	// draw [...] if needed and not yet
	if (pCoDrawBlk && !bCoBlkDrawn)
	{
		CRect rcCoBlk = rcTextLine;
		rcCoBlk.left += drawTxtProc.GetRowWidth(nLine) - drawTxtProc.GetScrollXOffset();
		rcCoBlk.left = max(rcCoBlk.left, rcTextLine.left);
		rcCoBlk.left = min(rcCoBlk.left, rcTextLine.right);

		pEditCtrl->ProcessCollapsedText(pDC, pCoDrawBlk, rcCoBlk);
	}

	pDC->SetTextColor(m_clrValues.crText);

	return nRowHeight;
}