📄 syneditview.cpp
字号:
{
m_nParseArraySize = 0;
m_nHorzPos = 0;
if(m_pdwParseCookies != NULL) {
delete m_pdwParseCookies;
m_pdwParseCookies = NULL;
}
if(m_pCacheBitmap!=NULL) {
delete m_pCacheBitmap;
m_pCacheBitmap = NULL;
}
return;
}
int CSynEditView::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
if (CSynEditView::OnCreate(lpCreateStruct) == -1)
return -1;
GetRichEditCtrl().HideSelection(TRUE, FALSE);
return 0;
}
void CSynEditView::CalcSelection()
{
CRichEditCtrl &SynCtrl = GetRichEditCtrl();
CHARRANGE cr;
SynCtrl.GetSel( cr );
m_ptSelStart = SynCtrl.GetCharPos( cr.cpMin );
m_ptSelEnd = SynCtrl.GetCharPos( cr.cpMax );
}
/*////////////////////////////////////////////////////
[函数]: IsStrInSelection(int ptLeft, int ptTop)
[功能] 根据给定点的x,y坐标判断该点是否在选定区域内
[入口参数]:
ptLeft - 给定点的x位置
ptTop - 给定点的y位置
[返回值]:
TRUE - 该点在选定区域内
FLASE - 该点在在选定区域内
/*////////////////////////////////////////////////////
BOOL CSynEditView::IsStrInSelection(int ptLeft, int ptTop)
{
if( m_ptSelStart == m_ptSelEnd ) //如果没有选定直接返回FALSE
return FALSE;
CPoint ptSelStart = m_ptSelStart;
CPoint ptSelEnd = m_ptSelEnd;
//考虑边界的情况,将选定区域左右延伸半个字符宽度
ptSelStart.x -= m_nCharNumberWidth/2;
ptSelEnd.x += m_nCharNumberWidth/2;
if( ptSelStart.y == ptSelEnd.y ) { //如果选定行为单行
if( ptTop != ptSelStart.y ) //如果光标不在该行
return FALSE;
else {
if( ptLeft >= ptSelStart.x && ptLeft <= ptSelEnd.x)
return TRUE;
else
return FALSE;
}
}
else {
if( ptTop == ptSelStart.y ) { //如果当前位置在选取定行的第一行
if( ptLeft < ptSelStart.x )
return FALSE;
else
return TRUE;
}
if( ptTop == ptSelEnd.y ) { //如果当前位置在选定行的最后一行
if( ptLeft < ptSelEnd.x )
return TRUE;
else
return FALSE;
}
else if( ptTop > ptSelStart.y && ptTop < ptSelEnd.y ) //如果当前位置在选定行的中间
return TRUE;
else
return FALSE;
}
}
//判断给定的字符是否在选择区域内,并画出该字符串
void CSynEditView::JudgeInSeletioAndDrawText(CDC *cacheDC, CRect &rcLine, CString &str, COLORREF clrBkColor, COLORREF clrText)
{
COLORREF clrSelText;
int nFormat = DT_LEFT|DT_NOPREFIX|DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE|DT_RTLREADING;
CSize size = cacheDC->GetTextExtent(str);
if( !IsSelectionInStr(rcLine.left, size.cx, rcLine.top) ) {
BOOL bStrLeft = IsStrInSelection( rcLine.left, rcLine.top );
BOOL bStrRight = IsStrInSelection( rcLine.left + size.cx, rcLine.top );
if( !bStrLeft && !bStrRight ) { //如果str的左右都不在选定区域内
cacheDC->SetBkColor( clrBkColor );
cacheDC->SetTextColor( clrText );
cacheDC->TextOut( rcLine.left, rcLine.top, str);
rcLine.OffsetRect( size.cx, 0 );
return;
}
else if( bStrLeft && bStrRight ) { //如果str的左右都在选定区域内
CRect rect(rcLine);
rect.right = rect.left + size.cx;
cacheDC->FillSolidRect( &rect, m_clrBKSelText );
clrSelText = RGB( 255-GetRValue(clrText), 255-GetGValue(clrText), 255-GetBValue(clrText) );
cacheDC->SetTextColor( clrSelText );
cacheDC->TextOut( rcLine.left, rcLine.top, str);
rcLine.OffsetRect( size.cx, 0 );
return;
}
}
//如果str部分在选定区域内, 或者选定区域在str内执行以下代码
CString strChar;
for( int nChar = 0; nChar < str.GetLength(); nChar++ ) {
strChar = str.Mid( nChar, 1 );
size = cacheDC->GetTextExtent( strChar );
BOOL bStrLeft = IsStrInSelection( rcLine.left, rcLine.top );
BOOL bStrRight = IsStrInSelection( rcLine.left + size.cx, rcLine.top );
if( bStrLeft && bStrRight ) {
CRect rect(rcLine);
rect.right = rect.left + size.cx;
cacheDC->FillSolidRect( &rect, m_clrBKSelText );
clrSelText = RGB( 255-GetRValue(clrText), 255-GetGValue(clrText), 255-GetBValue(clrText) );
cacheDC->SetTextColor( clrSelText );
}
else {
cacheDC->SetBkColor( clrBkColor );
cacheDC->SetTextColor( clrText );
}
cacheDC->TextOut( rcLine.left, rcLine.top, strChar);
rcLine.OffsetRect( size.cx, 0 );
}
}
//计算水平滚动位置,以便在水平滚动时可以正确显示
void CSynEditView::CalcHorzScrollPos()
{
if(m_nWordWrap == WrapToWindow)
{
m_nHorzPos = 0;
return;
}
SCROLLINFO si;
si.cbSize = sizeof(si);
GetScrollInfo(SB_HORZ, &si);
if( m_bTracking )
m_nHorzPos = si.nTrackPos;
else
m_nHorzPos = si.nPos;
}
//在RichEditView上画出内容
void CSynEditView::DrawSynEditView()
{
if(!m_bAllowDraw)
return;
CRichEditCtrl &SynCtrl = GetRichEditCtrl();
m_nLineCount = SynCtrl.GetLineCount();
m_nCurrentLine = GetCurrentLine();
if (m_pdwParseCookies != NULL)
{
if (m_nParseArraySize != m_nLineCount)
{
int nCurrentLine = m_nCurrentLine;
if(m_nParseArraySize < m_nLineCount)
{
nCurrentLine = m_nParseArraySize + m_nCurrentLine - m_nLineCount;
if(nCurrentLine<0)
nCurrentLine = m_nCurrentLine;
}
if(m_nCurrentLine>m_nLineCount)
nCurrentLine=0;
// 重新分配缓冲区大小
DWORD *pdwNewArray = new DWORD[m_nLineCount];
if (m_nCurrentLine > 0)
memcpy(pdwNewArray, m_pdwParseCookies, sizeof(DWORD) * nCurrentLine);
delete m_pdwParseCookies;
m_nParseArraySize = m_nLineCount;
m_pdwParseCookies = pdwNewArray;
memset(m_pdwParseCookies + nCurrentLine, 0xff, sizeof(DWORD) * (m_nParseArraySize - nCurrentLine));
}
}
CDC *pdc=GetDC();
CDC cacheDC;
VERIFY(cacheDC.CreateCompatibleDC(pdc));
if (m_pCacheBitmap == NULL)
{
m_pCacheBitmap = new CBitmap;
m_pCacheBitmap->CreateCompatibleBitmap(pdc, m_rcClient.Width(), m_rcClient.Height()); //nLineHeight);
}
CBitmap *pOldBitmap = cacheDC.SelectObject(m_pCacheBitmap);
CalcSelection();
CalcHorzScrollPos();
CString str;
int nLine = SynCtrl.GetFirstVisibleLine();
if(nLine==0)
m_bRealReturn = TRUE;
else
m_bRealReturn = GetLineString(nLine-1, str);
CRect rcEditor(m_rcClient);
//将显示区域背景色画好
cacheDC.FillSolidRect(&rcEditor, m_clrBkColor);
rcEditor.left = m_nLeftMargin - m_nHorzPos - 1;
int nLinesTop = GetLinesTop(nLine); //第一行要计算好偏移值,因为第一行可能只显示部分
rcEditor.top = nLinesTop + m_nTopMargin;
rcEditor.bottom = rcEditor.top + m_nLineHeight;
int nNumberToDraw = 0;
while(rcEditor.top <= m_rcClient.bottom )
{
if(nLine > m_nLineCount-1)
break;
//画出一行文本
DrawSingleLineColorText(&cacheDC, nLine++, rcEditor);
//重新定位下一行的位置
rcEditor.OffsetRect(0, m_nLineHeight );
}
//将缓冲画布cacheDC上的内容复制到RichEditView视上
pdc->BitBlt(m_rcClient.left, m_rcClient.top, m_rcClient.Width(), m_rcClient.Height(), &cacheDC, 0, 0, SRCCOPY);
cacheDC.SelectObject(pOldBitmap);
cacheDC.DeleteDC();
}
/*////////////////////////////////////////////////////
[函数]: IsSelectionInStr(int nFromHere, int nStrWidth, int nTop)
[功能]: 判断选择选区域是否在字符串所处位置的内部
[入口参数]:
nFromHere - 待测试的字符串的起始位置
nStrWidth - 待测试的字符串的宽度
nTop - 待测试的字符串的顶部位置
[返回值]:
TRUE - 选定区域在字符串所处位置的内部
FLASE - 选定区域不在字符串所处位置的内部
/*////////////////////////////////////////////////////
BOOL CSynEditView::IsSelectionInStr(int nFromHere, int nStrWidth, int nTop)
{
if( m_ptSelStart == m_ptSelEnd )
return FALSE;
if( m_ptSelStart.y != m_ptSelEnd.y ) //如果选定行不为单行,返回,因为字符不可能跨行
return FALSE;
if( m_ptSelStart.y != nTop ) //如果待测试行的顶部不等于选定行的顶部则返回
return FALSE;
if( (m_ptSelStart.x > nFromHere) && (m_ptSelEnd.x < nFromHere + nStrWidth) )
return TRUE;
else
return FALSE;
}
COLORREF CSynEditView::GetColor(int nColorIndex)
{
switch(nColorIndex)
{
case COLORINDEX_NUMBER:
return m_clrNumberColor;
case COLORINDEX_BK:
return m_clrBkColor;
case COLORINDEX_COMMENT:
return m_clrCommentColor;
case COLORINDEX_SYNTAX:
return m_clrSyntaxColor;
case COLORINDEX_NORMAL:
return m_clrNormalColor;
case COLORINDEX_STRING:
return m_clrStringColor;
case COLORINDEX_CHAR:
return m_clrCharColor;
default:
return m_clrNormalColor;
}
}
//这个函数的作用是在粘贴时重置nParseArraySize的语法解析缓冲区
void CSynEditView::SetParseCookieZeroFromGivenLine(int nParseArraySize)
{
memset(m_pdwParseCookies + nParseArraySize, 0xff, sizeof(DWORD) * (m_nParseArraySize - nParseArraySize));
}
//语法解析相关函数,判断给定的串是否是当前是语言的语法关键字
BOOL CSynEditView::IsSynWord(CString &strReadyToTest)
{
BOOL bCase, bMatch;
//设定当前语言是否区分大小写
switch(m_nLanguage)
{
case _CPP:
bCase = TRUE;
break;
case _BASIC:
bCase = FALSE;
break;
default:
bCase = FALSE;
}
for(int i=0; i<m_strArrayKeyWords.GetSize(); i++)
{
CString str = m_strArrayKeyWords[i];
if(bCase)
bMatch = (strReadyToTest.Compare(m_strArrayKeyWords[i])==0);
else
bMatch = (strReadyToTest.CompareNoCase(m_strArrayKeyWords[i])==0);
if(bMatch)
return TRUE;
}
return FALSE;
}
//语法解析相关函数,装入指定语言的语法关键字
void CSynEditView::LoadSynWord(INT nLanguage)
{
CString strAllSynWord;
m_strArrayKeyWords.RemoveAll();
switch (nLanguage)
{
case _CPP:
strAllSynWord = _T(" #define,#else,#elif,#elseif,#endif,#error,#if,#ifdef,#ifndef,#include,#pragma,#undef,__asm,__based,__cdecl,__declspec,__except,__fastcall,__finally,__inline,__int16,__int32,__int64,__int8,__leave,__multiple_inheritance,__pascal,__single_inheritance,__stdcall,__try,__uuidof,__virtual_inheritance,_asm,_cdecl,_fastcall,_pascal,_stdcall,afx_msg,auto,bool,break,case,catch,char,class,code_seg,const,const_cast,continue,default,defined,delete,dllexport,dllimport,do,double,dynamic_cast,else,enum,explicit,extern,false,float,for,friend,goto,if,inline,int,interface,long,main,mutable,naked,namespace,new,off,on,once,operator,pack,pascal,pop,private,protected,public,push,register,reinterpret_cast,return,short,signed,sizeof,static,static_cast,struct,switch,template,this,thread,throw,true,try,typedef,typeid,typename,union,unsigned,using,uuid,virtual,void,volatile,while,wmain,xalloc,");
break;
case _BASIC:
strAllSynWord = _T(" Alias,And,Any,As,Base,Boolean,Byref,Byte,Byval,Call,Case,Close,Compare,Const,Currency,Data,Date,Declare,Defbool,Defbyte,Defcur,Defdate,Defdbl,Defdec,Defint,Deflng,Defobj,Defsng,Defstr,Defvar,Dim,Do,Double,Each,Else,Elseif,End,Enum,Eqv,Erase,Error,Event,Exit,Explicit,False,For,Function,Get,Global,Gosub,Goto,If,IIf,Imp,Implements,In,Integer,Is,Let,Lib,Line,Lock,Long,Loop,Lset,New,Next,Not,Object,On,Open,Option,Optional,Or,Preserve,Print,Private,Property,Public,Put,Raiseevent,Redim,Resume,Return,Rset,Select,Set,Single,Static,Stop,String,Sub,Then,To,True,Type,Ubound,Unload,Unlock,Variant,Wend,While,With,Write,Xor,");
break;
default: //纯文本
strAllSynWord = _T("");
return;
}
CString strTemp;
int nPosPrior = 0;
int nPos;
nPos = strAllSynWord.Find(_T(","), nPosPrior);
while(nPos!=-1)
{
strTemp = strAllSynWord.Mid(nPosPrior+1 , nPos - nPosPrior - 1);
m_strArrayKeyWords.Add(strTemp);
nPosPrior = nPos;
nPos = strAllSynWord.Find(_T(","), nPosPrior + 1);
}
}
void CSynEditView::CalcEditorInfo()
{
ShowWindow(FALSE);
CPoint p1, p2;
CRichEditCtrl &SynCtrl = GetRichEditCtrl();
SynCtrl.SetWindowText(_T("8"));
p1 = SynCtrl.GetCharPos(0);
p2 = SynCtrl.GetCharPos(1);
m_nCharNumberWidth = p2.x - p1.x; //数字宽度
SynCtrl.SetWindowText(_T(" "));
p1 = SynCtrl.GetCharPos(0);
p2 = SynCtrl.GetCharPos(1);
m_nCharSpaceWidth = p2.x - p1.x; //空格宽度
SynCtrl.SetWindowText(_T("\t"));
p1 = SynCtrl.GetCharPos(0);
p2 = SynCtrl.GetCharPos(1);
m_nCharTabWidth = p2.x - p1.x; //TAB宽度
SynCtrl.SetWindowText(_T("\n "));
CPoint ps, pe;
p1 = SynCtrl.GetCharPos(0);
p2 = SynCtrl.GetCharPos(3);
//m_nLineHeight = p2.y - p1.y; //行高
m_nLineHeight = 16;
ShowWindow(TRUE);
}
LRESULT CSynEditView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
CPaintDC dc(this); // device context for painting
DrawSynEditView();
return FALSE;
}
case WM_PASTE:
{
//处理粘贴的情况,当用户粘入rtf格式时,只取出其中的文本,否则直接粘可能会引起文本错位
char * buffer;
if(!OpenClipboard())
return FALSE;
buffer = (char*)::GetClipboardData(CF_TEXT);
CloseClipboard();
CString str = buffer;
CRichEditCtrl &edit = GetRichEditCtrl();
CHARRANGE cr;
edit.GetSel(cr);
SetParseCookieZeroFromGivenLine(edit.LineFromChar(cr.cpMin)); //粘贴时需重置解析缓冲区
edit.ReplaceSel(str, TRUE);
return FALSE;
}
case WM_SIZE:
{
CSynEditView::WindowProc(message, wParam, lParam);
GetParent()->GetClientRect(&m_rcClient);
MoveWindow(&m_rcClient);
if (m_pCacheBitmap != NULL)
{
delete m_pCacheBitmap;
m_pCacheBitmap = NULL;
}
return FALSE;
}
default:
return CSynEditView::WindowProc(message, wParam, lParam);
}
}
void CSynEditView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
InvalidateRect(m_rcClient, FALSE);
m_bAllowDraw = FALSE;
CSynEditView::OnHScroll(nSBCode, nPos, pScrollBar);
m_bAllowDraw = TRUE;
ValidateRect(m_rcClient);
//判断用户是否正在拖动水平滚动条
SCROLLINFO si;
si.cbSize = sizeof(si);
GetScrollInfo(SB_HORZ, &si);
if(nSBCode==SB_THUMBPOSITION || nSBCode==SB_THUMBTRACK)
m_bTracking = TRUE;
else
m_bTracking = FALSE;
SendMessage(WM_PAINT, 0, 0);
}
void CSynEditView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
InvalidateRect(m_rcClient, FALSE);
m_bAllowDraw = FALSE;
CSynEditView::OnVScroll(nSBCode, nPos, pScrollBar);
m_bAllowDraw = TRUE;
ValidateRect(m_rcClient);
SendMessage(WM_PAINT, 0, 0);
}
/*//////////////////////////////////////////////////////////////////////////////////////
[函数]:ParseLine(m_strArrayKeyWords, dwCookie, strLine, ColorInfo, nActualItems) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -