⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syneditview.cpp

📁 VC++设计语法编辑器
💻 CPP
📖 第 1 页 / 共 4 页
字号:
////////////////////////////////////////////////////////////
//	文件:		SynEditView.cpp
//	版本:		1.0.0.1
//	创建:		2002年1月23日
//
//	作者:		郑旭
//  Website:	http://www.easysrc.com
//	E-mail:		happyfly@netease.com
//
//	CSynEditView语法编辑视实现代码
//
//	你可以自由使用或是改变CSynEditView的代码以适应你的需要,
//	但是请保留这段文字。
////////////////////////////////////////////////////////////

/*-----------------------------------------------------------------
|                                                                 |
|    设计思路 :                                                   |
|    假设 SynCtrl 即是隐藏在 CRichEditView 后面可以用             |
|    GetRichEditCtrl  函数取得的控制。 SynEditView 可看作覆盖在   |
|    SynCtrl  表面的一层不透明的画布,在程序中我们自己作画,再将  |
|    画出来的内容覆盖在 SynCtrl 表面,即可作成语法关键字编辑效果  |
|    。虽然在程序中重载 OnPaint 函数但不作任何操作带来的后果是    |
|    SynCtrl  不再重画,但是隐藏在 SynCtrl 后面的内容仍然存在,   |
|    我们可以通过 GetLine 取得其文本信息,也可以通过 GetFont 取   |
|    得其字体信息!我们可以取出这些信息进行加工,再将加工后的东   |
|    西显示出来。通过仔细的调整各个参数,使得画出来的东西与不重   |
|    载SynCtrl 的 OnPaint 函数前 SynCtrl 画出来的东西完全重合,   |
|    但只是把其中是关键字的部分进行着色,即可达到完美的语法编程   |
|    器的效果。                                                   |
|                                                                 |
-----------------------------------------------------------------*/


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

#include "SynEditView.h"
#include "Mainfrm.h"


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

DWORD CALLBACK EditStreamCallbackReadFromFile(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);
DWORD CALLBACK EditStreamCallbackWriteToFile(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);
DWORD CALLBACK EditStreamCallbackOut(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);

/////////////////////////////////////////////////////////////////////////////
// CSynEditView

IMPLEMENT_DYNCREATE(CSynEditView, CRichEditView)

BEGIN_MESSAGE_MAP(CSynEditView, CRichEditView)
//{{AFX_MSG_MAP(CSynEditView)
ON_WM_SIZE()
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_HSCROLL()
ON_WM_KEYDOWN()
ON_WM_LBUTTONDOWN()
	ON_WM_KEYUP()
	ON_WM_VSCROLL()
	ON_WM_PAINT()
	ON_WM_SETFOCUS()
	ON_WM_CHAR()
	//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CRichEditView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CRichEditView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CRichEditView::OnFilePrintPreview)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSynEditView construction/destruction

CSynEditView::CSynEditView()
{
	ReadSettings();	

	m_nLineNumberCharNumber = 0;
	m_nLineCount = 0;
	m_nCharTabWidth = 1;
	m_nCharSpaceWidth = 1;
	m_nParseArraySize = 0;
	m_nHorzPos = 0;
	m_nCharNumberWidth = 1;
	m_nLineHeight = 17;
	m_nLeftMargin = 1;
	m_nCurrentLine = 0;
	m_bAllowDraw = TRUE;
	m_bRealReturn = TRUE;
	m_nDefaultLeftMargin = 0;

	m_nBookMarksCount = 0;

	m_bTrack = FALSE;
	m_pdwParseCookies = NULL;
	m_rcClient = NULL;
	m_pCacheBitmap = NULL;

	memset(anBookMarks, 0, sizeof(int)*256);

	m_nHorzMaxOld = 0;
}

CSynEditView::~CSynEditView()
{
	if (m_pCacheBitmap != NULL)
		delete m_pCacheBitmap;
	
	if (m_pdwParseCookies != NULL)
		delete m_pdwParseCookies;
}

BOOL CSynEditView::PreCreateWindow(CREATESTRUCT& cs)
{
//*
	if (LoadLibraryA("RICHED20.DLL") == NULL)
	{
		AfxMessageBox(_T("Fail to load \"riched20.dll\"."),
			MB_OK | MB_ICONERROR);
		PostMessage(WM_QUIT,0,0);
	}
	m_strClass = RICHEDIT_CLASSA;	//for 2.0 class 	
//*/
	return CRichEditView::PreCreateWindow(cs);
}

void CSynEditView::OnInitialUpdate()
{
	CRichEditView::OnInitialUpdate();

	// Set the printing margins (720 twips = 1/2 inch).
	SetMargins(CRect(1000, 800, 800, 800));

	ResetParseCookie();
	
	SelectLanguage(m_nLanguage);

	GetRichEditCtrl().HideSelection(TRUE, FALSE);
	SetWrapMode(m_nWrapMode);
	GetRichEditCtrl().SetReadOnly(m_bReadOnly); 

	SendMessage(EM_SETUNDOLIMIT, m_nUndoLimits, 0);
  	SetAutoWordSelect(m_bAutoWordSelect);
	
	CSynEditView::m_nWordWrap = m_nWrapMode;
	CSynEditView::WrapChanged(); 

	ResetParseCookie();

	if(m_nWrapMode == WrapNone)
		GetRichEditCtrl().ShowScrollBar(SB_HORZ, TRUE); 
	else
		GetRichEditCtrl().ShowScrollBar(SB_HORZ, FALSE); 

	InitEditorFont();

	PostMessage( WM_PAINT, 0, 0 );
}

/////////////////////////////////////////////////////////////////////////////
// CSynEditView printing

BOOL CSynEditView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}


/////////////////////////////////////////////////////////////////////////////
// CSynEditView diagnostics

#ifdef _DEBUG
void CSynEditView::AssertValid() const
{
	CRichEditView::AssertValid();
}

void CSynEditView::Dump(CDumpContext& dc) const
{
	CRichEditView::Dump(dc);
}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSynEditView message handlers

void CSynEditView::LoadFile(CString strFile)
{
	SetWindowText(_T(""));
	ResetParseCookie();		
	SetSynEditViewFont(m_lf);
	
	CRichEditCtrl &SynCtrl = GetRichEditCtrl();	

	CFile* pInputFile = NULL;
	try
	{
		pInputFile = new CFile(strFile, CFile::modeRead | CFile::shareDenyNone);
		
		EDITSTREAM strm;
		strm.dwCookie = (DWORD) pInputFile;
		strm.pfnCallback = EditStreamCallbackReadFromFile;
		
		long lResult = SynCtrl.StreamIn(SF_TEXT, strm);
		
		pInputFile->Close();
	}
	catch (CFileException* pEx)
	{
		pEx->Delete();
	}	
	delete pInputFile;	

	SynCtrl.SetModify(FALSE);
	return;
}
 
//将文件中的内容装入到richeditctrl中,正常工作
DWORD CALLBACK EditStreamCallbackReadFromFile(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	CFile* pFile = (CFile*) dwCookie;
	ASSERT_KINDOF(CFile, pFile);

	*pcb = pFile->Read(pbBuff, cb);

	return 0;
}

//将richeditctrl中的内容写入到文件中,正常工作
DWORD CALLBACK EditStreamCallbackWriteToFile(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	CFile* pFile = (CFile*) dwCookie;
	
	pFile->Write(pbBuff, cb);
	*pcb = cb;
	
	return 0;
}

BOOL CSynEditView::IsFileExist(CString &strFile)
{
	if(strFile.IsEmpty())
		return FALSE;
	FILE *file;
	if((file=fopen(strFile, _T("r")))==NULL)
		return FALSE;
	fclose(file);
	return TRUE;
}

void CSynEditView::SetSynEditViewFont(LOGFONT lf)
{
	ResetParseCookie();
	SetSynCtrlFont(lf);
	WriteSettings();
}

void CSynEditView::SetSynCtrlFont(LOGFONT lf)
{
	ShowWindow(SW_HIDE);
		
	CString str;
	EDITSTREAM stream;
	stream.dwCookie = (DWORD)&str;
	stream.pfnCallback = EditStreamCallbackOut;
	GetRichEditCtrl().StreamOut(SF_TEXT, stream);
	
	BOOL bModify = GetRichEditCtrl().GetModify();

	m_font.DeleteObject();
	m_font.CreateFontIndirect(&lf);
	//先设置视的字体
	SetFont(&m_font);
	m_lf = lf;

/*
	SetWindowText((" "));
	GetRichEditCtrl().SetSel(0, 1);
	CHARFORMAT cr = GetCharFormatSelection();
	//设置视的字体可能改变,所以还要取其字体,看真正的结果,用GetFont不管用
	m_lf.lfCharSet = cr.bCharSet;
	m_lf.lfHeight = cr.yHeight/14;
	strcpy(m_lf.lfFaceName, cr.szFaceName);		
//*/
	SetCharWidth();
	SetLineHeight();
	SetLeftMargin();

	WriteSettings();
	
	SetWindowText(str);
	GetRichEditCtrl().SetModify(bModify);
	ShowWindow(SW_SHOW); 
}


void CSynEditView::SetSynCtrlTabSize(int nSize)
{
	CRichEditCtrl &SynCtrl = GetRichEditCtrl();	

	CString str;
	EDITSTREAM stream;
	stream.dwCookie = (DWORD)&str;
	stream.pfnCallback = EditStreamCallbackOut;
	SynCtrl.StreamOut(SF_TEXT, stream);

	//因为tab宽度一直是固定的,所以开始就取tab宽度
	//又因为要计算最开始tab相当于几个数字宽,所以下面几行必须放在上面一行之后
	//RichEditView开始时tab宽为一常数,即0.5英寸=720 points
	SynCtrl.SetWindowText(_T("\t")); 
	CPoint p1 = SynCtrl.GetCharPos(0);	
	CPoint p2 = SynCtrl.GetCharPos(1);
	m_nCharTabWidth = p2.x - p1.x; //取tab在字体m_lf下的以point表示的宽度

	//设置TAB间隔
	PARAFORMAT pf ;
	pf.cbSize = sizeof(PARAFORMAT);
	pf.dwMask = PFM_TABSTOPS ;
	pf.cTabCount = MAX_TAB_STOPS;
	SynCtrl.GetParaFormat( pf );
	int nSynCtrlTabSize = pf.rgxTabs[0];
	if(nSynCtrlTabSize == 0)
		nSynCtrlTabSize = 720;
	
	/*
	Tab的计算方法:
	1、先取SynCtrl默认的Tab宽度nSynCtrlTabSize(用英寸表示)
	2、计算SynCtrl默认的Tab宽度对应几个数字m_nCharTabWidth / m_nCharNumberWidth
	2、根据以上值计算每个数字的宽度nSynCtrlTabSize / (m_nCharTabWidth / m_nCharNumberWidth)
	3、根据每个数字的宽度计算新的Tab宽度
	*/

	SetWindowText(""); //此行不能删除,不然设置tab宽度会失败

	int nNewTab = int(nSynCtrlTabSize * 1.0 * nSize * m_nCharNumberWidth / m_nCharTabWidth);

	pf.cTabCount = MAX_TAB_STOPS;
	pf.dwMask = PFM_TABSTOPS;
	for(int itab = 0; itab < pf.cTabCount; itab++ )
		pf.rgxTabs[itab] = (itab+1) * nNewTab ;
	SetParaFormat( pf );

	m_nTabSize = nSize;	

	m_nCharTabWidth = nSize * m_nCharNumberWidth;

	WriteSettings();

	SetWindowText(str);
}

void CSynEditView::OnSize(UINT nType, int cx, int cy) 
{
	CRichEditView::OnSize(nType, cx, cy);

	GetClientRect(&m_rcClient);
	
	if (m_pCacheBitmap != NULL)
	{
		delete m_pCacheBitmap;
		m_pCacheBitmap = NULL;
	}

	SetLeftMargin();

	PostMessage(WM_PAINT, 0, 0);
}

void CSynEditView::LoadText(CString &strText)
{
	ResetParseCookie();
	
	SetSynEditViewFont(m_lf);

	SetWindowText(strText);	
	GetRichEditCtrl().SetModify( FALSE ); 
}


void CSynEditView::DrawSingleLineColorText( CDC *cacheDC, int nLine, CRect rcLine)
{
	COLORREF clrBkColor = m_clrBkColor;
	CRect rtSrc(rcLine);
	//显示当前行
	if(m_bShowSelectLine) {
		if(nLine == m_nCurrentLine && m_ptStart == m_ptEnd) 
			clrBkColor = m_clrBkCurLine;
		else
			clrBkColor = m_clrBkColor;
		cacheDC->FillSolidRect(rcLine, clrBkColor);
	}	
	////////////
	
	CFont cf;
	cf.CreateFontIndirect(&m_lf);
	CFont *pOldFont = cacheDC->SelectObject(&cf);
	
	CString  strLine;
	BOOL bRealReturn = GetLineString(nLine, strLine); //取指定行文本,并返回是否为硬回车标志

	int nLength = strLine.GetLength(); 
	
	int nActualItems = 0;
	COLORINFO *ColorInfo = (COLORINFO *)_alloca( sizeof(COLORINFO) * (nLength + 1) );	
	DWORD dwCookie = GetParseCookie(nLine-1);
	CString str;
	if( m_bRealReturn && (m_nLanguage != _HTML) && (m_nLanguage != _XML))
		dwCookie &= COOKIE_EXT_COMMENT; 
	m_bRealReturn = bRealReturn;
	dwCookie = ParseLine(m_strArrayKeyWords, dwCookie, strLine, ColorInfo, nActualItems);
	m_pdwParseCookies[nLine] = dwCookie;
	
	COLORREF clr;
	CSize sizeContinueStr(0, 0);
	int nlen, nTabCount = 0;

	if (nActualItems > 0)
	{
		ASSERT(ColorInfo[0].Pos >= 0 && ColorInfo[0].Pos <= nLength);
		for (int I = 0; I < nActualItems; I ++)
		{
			nlen = ColorInfo[I + 1].Pos - ColorInfo[I].Pos;
			if( I == nActualItems - 1 )
				str = strLine.Mid(ColorInfo[I].Pos, strLine.GetLength() - ColorInfo[I].Pos);
			else
				str = strLine.Mid(ColorInfo[I].Pos, nlen);

			if(str.IsEmpty())
				continue;

			clr = GetColor(ColorInfo[I].Color);

			int nPos = str.Find(_T("\t"));
			while(-1 != nPos)
			{
				//遇到一个tab字符时,先将前面的字符画出来
				CString strTemp = str.Left(nPos);
				JudgeInSeletioAndDrawText( cacheDC, rcLine, strTemp, clrBkColor, clr );
				
				CSize sizeTemp = cacheDC->GetTextExtent(strTemp);

				nTabCount += 1; //既然找到了tab,那么就加1吧
				//把前面已经输出的字符串宽度换算成相应的tab个数
				nTabCount += int((sizeTemp.cx+sizeContinueStr.cx) / m_nCharTabWidth);

				int nOldLeft = rcLine.left;
				//然后直接定位到下一个tab位置
				rcLine.left = rtSrc.left + nTabCount * m_nCharTabWidth;
				
				//开始画tab////////////////////////
				BOOL bLeftInSel = IsStrInSelection(nOldLeft, rcLine.top, TRUE);
				BOOL bRightInSel = IsStrInSelection(rcLine.left, rcLine.top, FALSE);
				if(bLeftInSel && bRightInSel)
				{
					//如果tab在选择区域内,则要画背景
					CRect rtTab(nOldLeft, rcLine.top, rcLine.left, rcLine.bottom);
					cacheDC->FillSolidRect( &rtTab, m_clrBKSelText ); 
				}

				if(m_bShowTab)
				{					
					int nleft = nOldLeft;
					int nCenterY = rcLine.top + (rcLine.bottom-rcLine.top)/2;
					for(int pos=1; pos<4; pos++)
					{
						cacheDC->SetPixel( nleft + pos + 0,  pos + nCenterY - 4, m_clrTab );
						cacheDC->SetPixel( nleft + pos + 3,  pos + nCenterY - 4, m_clrTab );
						cacheDC->SetPixel( nleft + pos + 0, -pos + nCenterY + 2, m_clrTab );
						cacheDC->SetPixel( nleft + pos + 3, -pos + nCenterY + 2, m_clrTab );
					}
				}
				//////////////////////////////////////

				str = str.Right(str.GetLength()-nPos-1);
				nPos = str.Find(_T("\t"));

				//重置输出字符串宽度
				sizeContinueStr.cx = 0;
			}

			JudgeInSeletioAndDrawText( cacheDC, rcLine, str, clrBkColor, clr );
			//保存已输出的字符中宽度
			CSize sizeTemp = cacheDC->GetTextExtent(str);
			sizeContinueStr += sizeTemp;
		}
	}
	
	if(m_bShowReturnLineToken)
		DrawReturnLineToken( m_bRealReturn, cacheDC, rcLine );

		//显示下划线
	if(m_bShowUnderLine) {	
		CPen NewPen(PS_SOLID, 1, m_clrUnderLine);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -