// aplRichEditCtrl.cpp : implementation file
//

#include "stdafx.h"
#include <afxrich.h>

#include "apl_gui.h"

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

/*Для выравнивания по ширене нужно только TO_ADVANCEDTYPOGRAPHY, но пусть все будет*/
#define EM_SETTYPOGRAPHYOPTIONS (WM_USER + 202)

#define TO_ADVANCEDTYPOGRAPHY 1
#define TO_SIMPLELINEBREAK 2
#define TO_DISABLECUSTOMTEXTOUT 4
#define TO_ADVANCEDLAYOUT 8

/////////////////////////////////////////////////////////////////////////////
// CaplRichEditCtrl
#define PARAFORMAT_MASK PFM_LINESPACING|PFM_ALIGNMENT|PFM_BORDER|PFM_NUMBERING|PFM_NUMBERINGSTART|PFM_NUMBERINGSTYLE|PFM_NUMBERINGTAB|PFM_OFFSET|PFM_OFFSETINDENT|PFM_RIGHTINDENT|PFM_SHADING|PFM_SPACEAFTER|PFM_SPACEBEFORE|PFM_STARTINDENT|PFM_STYLE|PFM_TABSTOPS
#define FONTSIZES 4,5,6,8,9,10,11,12,14,16,18,20,22,24,26,28,32,36,54,72,144
#define FONTSIZESCOUNT 21

CaplRichEditCtrl::CaplRichEditCtrl()
{
//	m_pRitchEditCallBack= NULL;
}

CaplRichEditCtrl::~CaplRichEditCtrl()
{
/*	if(m_pRitchEditCallBack)
	{
		m_pRitchEditCallBack->Release();
		m_pRitchEditCallBack= NULL;
	}*/
}

BEGIN_MESSAGE_MAP(CaplRichEditCtrl, CRichEditCtrl)
	//{{AFX_MSG_MAP(CaplRichEditCtrl)
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CaplRichEditCtrl message handlers

CString CaplRichEditCtrl::GetRTF(UINT flags /* = APL_RC_ALL*/)
{
	// Return the RTF string of the text in the control.
	
	// Stream out here.
	EDITSTREAM es;
	es.dwError = 0;
	es.pfnCallback = CBStreamOut;		// Set the callback

	CString sRTF = _T("");

	es.dwCookie = (DWORD) &sRTF;	// so sRTF receives the string
	
	StreamOut(flags, es);			// Call CRichEditCtrl::StreamOut to get the string.
	///

	return sRTF;

}

void CaplRichEditCtrl::SetRTF(CString sRTF, UINT flags /* = APL_RC_ALL*/)
{
	::SendMessage(m_hWnd, EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY);

	// Put the RTF string sRTF into the rich edit control.
	// Read the text in
	EDITSTREAM es;
	es.dwError = 0;
	es.pfnCallback = CBStreamIn;
	es.dwCookie = (DWORD) &sRTF;
	StreamIn(flags, es);	// Do it.	
}

/*
	Callback function to stream an RTF string into the rich edit control.
*/
DWORD CALLBACK CaplRichEditCtrl::CBStreamIn(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	// We insert the rich text here.


	CString *pstr = (CString *) dwCookie;
	if(0==pstr) return 0;

	/* AY переделал т.к. не работал под Unicode
	if (pstr->GetLength()  < (int)(cb/sizeof(TCHAR)))
	{
		*pcb = pstr->GetLength()*sizeof(TCHAR);
		memcpy(pbBuff, (LPCTSTR) *pstr, *pcb);
		pstr->Empty();
	}
	else
	{
		*pcb = cb;
		memcpy(pbBuff, (LPCTSTR) *pstr, *pcb);
		*pstr = pstr->Right(pstr->GetLength() - (cb/sizeof(TCHAR)));
	}*/

	CStringA  ansiStr((char*)CaplStringAdapter(*pstr));
	if (ansiStr.GetLength()  < (int)cb)
	{
		*pcb = pstr->GetLength();
		memcpy(pbBuff, (LPCSTR) ansiStr, *pcb);
		pstr->Empty();
	}
	else
	{
		*pcb = cb;
		memcpy(pbBuff, (LPCSTR) ansiStr, *pcb);
		*pstr = pstr->Right(pstr->GetLength() - cb);
	}



	///

	return 0;
}

/*
	Callback function to stream the RTF string out of the rich edit control.
*/
DWORD CALLBACK CaplRichEditCtrl::CBStreamOut(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	// Address of our string var is in psEntry
	CString *psEntry = (CString*) dwCookie;
	
	/* ЯАИ - немного переделал  т.к.  не работало под Unicode
	CString tmpEntry = _T("");
	tmpEntry = (CString) pbBuff;

	// And write it!!!
	*psEntry += tmpEntry.Left(cb/sizeof(TCHAR));
	*/

	CaplStringAdapter sa((char*)pbBuff);
	CString tmpEntry=LPCTSTR(sa);
	*psEntry +=tmpEntry;

	return 0;
}

bool CaplRichEditCtrl::SelectionIsBold()
{
	CHARFORMAT cf = GetCharFormat();	
	
	if (cf.dwEffects & CFM_BOLD)
		return true;
	else
		return false;
}

bool CaplRichEditCtrl::SelectionIsItalic()
{
	CHARFORMAT cf = GetCharFormat();	
	
	if (cf.dwEffects & CFM_ITALIC)
		return true;
	else
		return false;
}

bool CaplRichEditCtrl::SelectionIsUnderlined()
{
	CHARFORMAT cf = GetCharFormat();	
	
	if (cf.dwEffects & CFM_UNDERLINE)
		return true;
	else
		return false;
}

bool CaplRichEditCtrl::SelectionIsStrikeouted()
{
	CHARFORMAT cf = GetCharFormat();	
	
	if (cf.dwEffects & CFM_STRIKEOUT)
		return true;
	else
		return false;
}

CHARFORMAT CaplRichEditCtrl::GetCharFormat(DWORD dwMask)
{
	CHARFORMAT cf;
	cf.cbSize = sizeof(CHARFORMAT);

	cf.dwMask = dwMask;

	GetSelectionCharFormat(cf);

	return cf;
}

void CaplRichEditCtrl::SetCharStyle(int MASK, int STYLE, int nStart, int nEnd)
{
	CHARFORMAT cf;
	cf.cbSize = sizeof(CHARFORMAT);
	//cf.dwMask = MASK;
	
	GetSelectionCharFormat(cf);
	
	if (cf.dwMask & MASK)	// selection is all the same
	{
		cf.dwEffects ^= STYLE; 
	}
	else
	{
		cf.dwEffects |= STYLE;
	}
	
	cf.dwMask = MASK;

	SetSelectionCharFormat(cf);

}

void CaplRichEditCtrl::SetSelectionBold()
{
	long start=0, end=0;
	GetSel(start, end);		// Get the current selection

	SetCharStyle(CFM_BOLD, CFE_BOLD, start, end);	// Make it bold
}

void CaplRichEditCtrl::SetSelectionItalic()
{
	CString rtf = GetRTF(APL_RC_SELECTION);
	long start=0, end=0;
	GetSel(start, end);

	SetCharStyle(CFM_ITALIC, CFE_ITALIC, start, end);
}

void CaplRichEditCtrl::SetSelectionUnderlined()
{
	long start=0, end=0;
	GetSel(start, end);

	SetCharStyle(CFM_UNDERLINE, CFE_UNDERLINE, start, end);
}

void CaplRichEditCtrl::SetSelectionStrikeouted()
{
	long start=0, end=0;
	GetSel(start, end);

	SetCharStyle(CFM_STRIKEOUT, CFM_STRIKEOUT, start, end);
}

void CaplRichEditCtrl::SetParagraphCenter()
{
	PARAFORMAT paraFormat;    
	paraFormat.cbSize = sizeof(PARAFORMAT);
	paraFormat.dwMask = PFM_ALIGNMENT;    
	paraFormat.wAlignment = PFA_CENTER;
	
	SetParaFormat(paraFormat);	// Set the paragraph.
}

void CaplRichEditCtrl::SetParagraphLeft()
{
	PARAFORMAT paraFormat;
	paraFormat.cbSize = sizeof(PARAFORMAT);
	paraFormat.dwMask = PFM_ALIGNMENT;    
	paraFormat.wAlignment = PFA_LEFT;
	
	SetParaFormat(paraFormat);
}

void CaplRichEditCtrl::SetParagraphRight()
{
	PARAFORMAT paraFormat;
	paraFormat.cbSize = sizeof(PARAFORMAT);
	paraFormat.dwMask = PFM_ALIGNMENT;    
	paraFormat.wAlignment = PFA_RIGHT;
	
	SetParaFormat(paraFormat);
}

void CaplRichEditCtrl::SetParagraphJustify()
{
	::SendMessage(m_hWnd, EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY);

	PARAFORMAT pf;
	pf.cbSize=sizeof(pf);
	pf.dwMask=PFM_ALIGNMENT;
	pf.wAlignment=PFA_JUSTIFY;
	::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);	
}

bool CaplRichEditCtrl::ParagraphIsCentered()
{
	PARAFORMAT pf = GetParagraphFormat();

	if (pf.wAlignment == PFA_CENTER)
		return true;
	else
		return false;
}

bool CaplRichEditCtrl::ParagraphIsLeft()
{
	PARAFORMAT pf = GetParagraphFormat();

	if (pf.wAlignment == PFA_LEFT)
		return true;
	else
		return false;
}

bool CaplRichEditCtrl::ParagraphIsRight()
{
	PARAFORMAT pf = GetParagraphFormat();

	if (pf.wAlignment == PFA_RIGHT)
		return true;
	else
		return false;
}

bool CaplRichEditCtrl::ParagraphIsJustify()
{
	PARAFORMAT pf = GetParagraphFormat();

	if (pf.wAlignment == PFA_JUSTIFY)
		return true;
	else
		return false;
}

PARAFORMAT CaplRichEditCtrl::GetParagraphFormat()
{
	PARAFORMAT pf;
	pf.cbSize = sizeof(PARAFORMAT);

	pf.dwMask = PFM_ALIGNMENT | PFM_NUMBERING;    	

	GetParaFormat(pf);

	return pf;
}

void CaplRichEditCtrl::SetParagraphBulleted()
{
	PARAFORMAT paraformat = GetParagraphFormat();

	if ( (paraformat.dwMask & PFM_NUMBERING) && (paraformat.wNumbering == PFN_BULLET) )
	{
		paraformat.wNumbering = 0;
		paraformat.dxOffset = 0;
		paraformat.dxStartIndent = 0;
		paraformat.dwMask = PFM_NUMBERING | PFM_STARTINDENT | PFM_OFFSET;
	}
	else
	{
		paraformat.wNumbering = PFN_BULLET;
		paraformat.dwMask = PFM_NUMBERING;
		if (paraformat.dxOffset == 0)
		{
			paraformat.dxOffset = 4;
			paraformat.dwMask = PFM_NUMBERING | PFM_STARTINDENT | PFM_OFFSET;
		}
	}
	
	SetParaFormat(paraformat);

}

bool CaplRichEditCtrl::ParagraphIsBulleted()
{
	PARAFORMAT pf = GetParagraphFormat();

	if (pf.wNumbering == PFN_BULLET)
		return true;
	else
		return false;
}

void CaplRichEditCtrl::SetParagraphOrderList()
{
	PARAFORMAT paraformat = GetParagraphFormat();

	if ( (paraformat.dwMask & PFM_NUMBERING) && (paraformat.wNumbering == PFN_ARABIC) )
	{
		paraformat.wNumbering = 0;
		paraformat.dxOffset = 0;
		paraformat.dxStartIndent = 0;
		paraformat.dwMask = PFM_NUMBERING | PFM_STARTINDENT | PFM_OFFSET;
	}
	else
	{
		paraformat.wNumbering = PFN_ARABIC;
		paraformat.dwMask = PFM_NUMBERING;
		if (paraformat.dxOffset == 0)
		{
			paraformat.dxOffset = 4;
			paraformat.dwMask = PFM_NUMBERING | PFM_STARTINDENT | PFM_OFFSET;
		}
	}

	SetParaFormat(paraformat);

}


bool CaplRichEditCtrl::ParagraphIsOrderList()
{
	PARAFORMAT pf = GetParagraphFormat();

	if (pf.wNumbering == PFN_ARABIC)
		return true;
	else
		return false;
}

void CaplRichEditCtrl::SelectColor()
{
	CColorDialog dlg;

	CHARFORMAT cf = GetCharFormat();

	if (cf.dwEffects & CFE_AUTOCOLOR) cf.dwEffects -= CFE_AUTOCOLOR;

	// Get a color from the common color dialog.
	if( dlg.DoModal() == IDOK )
	{	
		cf.crTextColor = dlg.GetColor();
	}

	cf.dwMask = CFM_COLOR;

	SetSelectionCharFormat(cf);
}

void CaplRichEditCtrl::SetFontName(CString sFontName)
{
	CHARFORMAT cf = GetCharFormat();

	// Set the font name.
	int i;
	for (i = 0; i <= sFontName.GetLength()-1; i++)
		cf.szFaceName[i] = sFontName[i];

	cf.szFaceName[i]= _T('\0');
	cf.dwMask = CFM_FACE;

	SetSelectionCharFormat(cf);
}

void CaplRichEditCtrl::SetFontSize(int nPointSize)
{
	CHARFORMAT cf = GetCharFormat();
	if(SelectionIsSuperscribe())
	{
		cf.yOffset = 2*nPointSize*20/3;
		long sizes[FONTSIZESCOUNT] = {FONTSIZES};
		for(int i=0; i<FONTSIZESCOUNT;i++)
			if(sizes[i]==nPointSize) 
			{
				if(i<2)nPointSize=sizes[0];
				else nPointSize=sizes[i-2];
				break;
			}
	}
	if(SelectionIsSubscribe())
	{
		cf.yOffset = -nPointSize*20/3;
		long sizes[FONTSIZESCOUNT] = {FONTSIZES};
		for(int i=0; i<FONTSIZESCOUNT;i++)
			if(sizes[i]==nPointSize) 
			{
				if(i<2)nPointSize=sizes[0];
				else nPointSize=sizes[i-2];
				break;
			}
	}
	nPointSize *= 20;	// convert from to twips
	cf.yHeight = nPointSize;
	
	cf.dwMask = CFM_SIZE;

	SetSelectionCharFormat(cf);
}

void CaplRichEditCtrl::GetSystemFonts(CStringArray &saFontList)
{
	CDC *pDC = GetDC ();

	EnumFonts (pDC->GetSafeHdc(),NULL,(FONTENUMPROC) CBEnumFonts,(LPARAM)&saFontList);//Enumerate

	ReleaseDC(pDC);
}

BOOL CALLBACK CaplRichEditCtrl::CBEnumFonts(LPLOGFONT lplf, LPTEXTMETRIC lptm, DWORD dwType, LPARAM lpData)
{
	// This function was written with the help of CCustComboBox, by Girish Bharadwaj.
	// Available from Codeguru.

	if (dwType == TRUETYPE_FONTTYPE) 
	{
		((CStringArray *) lpData)->Add( lplf->lfFaceName );
	}

	return true;
}

CString CaplRichEditCtrl::GetSelectionFontName()
{
	CHARFORMAT cf = GetCharFormat();

	CString sName = cf.szFaceName;

	return sName;
}

long CaplRichEditCtrl::GetSelectionFontSize()
{
	CHARFORMAT cf = GetCharFormat();

	long nSize = cf.yHeight/20;

	if(SelectionIsSuperscribe() || SelectionIsSubscribe())
	{
		long sizes[FONTSIZESCOUNT] = {FONTSIZES};
		for(int i=0; i<FONTSIZESCOUNT;i++)
			if(sizes[i]==nSize) 
			{
				if(i>(FONTSIZESCOUNT-3))nSize=sizes[FONTSIZESCOUNT-1];
				else nSize=sizes[i+2];
				return nSize;
			}
	}
	return nSize;
}

COLORREF CaplRichEditCtrl::SetSelectionTextColor(COLORREF color)
{
	CHARFORMAT cf = GetCharFormat();
	if (cf.dwEffects & CFE_AUTOCOLOR) cf.dwEffects -= CFE_AUTOCOLOR;
	COLORREF old = cf.crTextColor;
	cf.crTextColor = color;
	SetSelectionCharFormat(cf);
	return old;
}

UINT CaplRichEditCtrl::OnGetDlgCode()
{
	return DLGC_WANTALLKEYS;
}

void CaplRichEditCtrl::SetParagraphSpacePara1()
{
}

void CaplRichEditCtrl::SetParagraphSpacePara15()
{
	PARAFORMAT2 pf;
	pf.cbSize = sizeof(PARAFORMAT2);
	pf.dwMask = PARAFORMAT_MASK;
	SendMessage(EM_GETPARAFORMAT,0,(LPARAM)&pf);
	pf.bLineSpacingRule = 0;//Установка одинарного интервала
	SendMessage(EM_SETPARAFORMAT,0,(LPARAM)&pf);
}



void CaplRichEditCtrl::SetSelectionBold(bool bold)
{
	if(bold && !SelectionIsBold())
		SetSelectionBold();
	else if(!bold && SelectionIsBold())
		SetSelectionBold();
}

void CaplRichEditCtrl::SetSelectionItalic(bool italic)
{
	if(italic && !SelectionIsItalic())
		SetSelectionItalic();
	else if(!italic && SelectionIsItalic())
		SetSelectionItalic();
}

void CaplRichEditCtrl::SetSelectionUnderlined(bool underline)
{
	if(underline && !SelectionIsUnderlined())
		SetSelectionUnderlined();
	else if(!underline && SelectionIsUnderlined())
		SetSelectionUnderlined();
}

void CaplRichEditCtrl::SetSelectionStrikeouted(bool strikeout)
{
	if(strikeout && !SelectionIsStrikeouted())
		SetSelectionStrikeouted();
	else if(!strikeout && SelectionIsStrikeouted())
		SetSelectionStrikeouted();
}

bool CaplRichEditCtrl::SelectFont()
{
	CHARFORMAT cf;
	cf.cbSize = sizeof(CHARFORMAT);
	GetSelectionCharFormat(cf);
	LOGFONT lf;
	_strcpy(lf.lfFaceName,cf.szFaceName);
	CDC* pDC = GetDC();
	lf.lfHeight = -MulDiv(-cf.yHeight/20, GetDeviceCaps(pDC->m_hDC, LOGPIXELSY), 72);
	ReleaseDC(pDC);
	lf.lfCharSet = cf.bCharSet;
	lf.lfOrientation = 0;
	lf.lfPitchAndFamily = cf.bPitchAndFamily;
	lf.lfEscapement = 0;
	lf.lfStrikeOut = SelectionIsStrikeouted();
	lf.lfItalic = SelectionIsItalic();
	lf.lfUnderline = SelectionIsUnderlined();
	if(SelectionIsBold()) lf.lfWeight = FW_BOLD;
	else lf.lfWeight = 0;
	lf.lfWidth = 0;
	lf.lfOutPrecision = 0;
	CFontDialog dlg(&lf);
	dlg.m_cf.rgbColors = cf.crTextColor;
	dlg.m_cf.Flags|=CF_LIMITSIZE;
	dlg.m_cf.nSizeMin = 6;
	dlg.m_cf.nSizeMax = 144;
	if(dlg.DoModal()==IDOK)
	{
		dlg.GetCurrentFont(&lf);
		int h = dlg.GetSize();
		SetFontName(lf.lfFaceName);
		SetFontSize(h/10);
		SetSelectionBold(lf.lfWeight==FW_BOLD);
		SetSelectionItalic(lf.lfItalic!=0);
		SetSelectionStrikeouted(lf.lfStrikeOut!=0);
		SetSelectionUnderlined(lf.lfUnderline!=0);
		SetSelectionCharSet(lf.lfCharSet);
		COLORREF color = dlg.GetColor();
		SetSelectionTextColor(color);
		GetParent()->SendMessage(WM_COMMAND,WM_FONTUPDATE,0);
		SetFocus();
		return true;
	}
	return false;
}

bool CaplRichEditCtrl::SetSelectionCharSet(BYTE charset)
{
	CHARFORMAT cf;
	cf = GetCharFormat();
	cf.bCharSet = charset;
	SetSelectionCharFormat(cf);
	return true;
}

void CaplRichEditCtrl::SetSuperscribe()
{
	long sizes[FONTSIZESCOUNT] = {FONTSIZES};
	CHARFORMAT cf;
	cf = GetCharFormat();
	long s = GetSelectionFontSize();
	if(cf.yOffset>0)
		cf.yOffset = 0;
	else
	{
		for(int i=0;i<FONTSIZESCOUNT;i++)
			if(sizes[i]==s)
			{
				if(i<2) s = sizes[0];
				else s = sizes[i-2];
				break;
			}
		cf.yOffset = 2*s*20/3;
	}
	cf.yHeight = s*20;
	SetSelectionCharFormat(cf);
	SetFocus();
}

void CaplRichEditCtrl::SetSubscribe()
{
	long sizes[FONTSIZESCOUNT] = {FONTSIZES};
	CHARFORMAT cf;
	cf = GetCharFormat();
	long s = GetSelectionFontSize();
	if(cf.yOffset<0)
		cf.yOffset = 0;
	else 
	{
		for(int i=0;i<FONTSIZESCOUNT;i++)
			if(sizes[i]==s)
			{
				if(i<2) s = sizes[0];
				else s = sizes[i-2];
			}
		cf.yOffset = -s*20/3;
	}
	cf.yHeight = s*20;
	SetSelectionCharFormat(cf);
	SetFocus();
}

bool CaplRichEditCtrl::SelectionIsSuperscribe()
{
	CHARFORMAT cf;
	cf = GetCharFormat();
	if(cf.yOffset>0) return true;
	return false;
}

bool CaplRichEditCtrl::SelectionIsSubscribe()
{
	CHARFORMAT cf;
	cf = GetCharFormat();
	if(cf.yOffset<0) return true;
	return false;
}
