📄 bcgpeditctrl.cpp
字号:
// BCGPEditCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "Bcgglobals.h"
#include "BCGPDrawManager.h"
#include "BCGPEditCtrl.h"
#include "BCGPIntelliSenseWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static const CString g_strEOL = _T ("\n");
static const TCHAR g_chEOL = _T ('\n');
static const CString g_strEOLExport = _T ("\r\n");
static CString strTipText;
static CLIPFORMAT g_cFormat = 0;
IMPLEMENT_DYNAMIC(CBCGPEditCtrl,CWnd)
IMPLEMENT_DYNAMIC(CBCGPEditMarker,CObject)
IMPLEMENT_DYNAMIC(CBCGPLineColorMarker,CBCGPEditMarker)
IMPLEMENT_DYNAMIC(CBCGPHiliteMarker,CBCGPEditMarker)
IMPLEMENT_SERIAL(CBCGPOutlineBaseNode,CObject,1)
IMPLEMENT_SERIAL(CBCGPOutlineNode,CBCGPOutlineBaseNode, 1)
#define ID_TEXT_SCROLL 1
#define _MAX_COLOR_BLOCK_STR_LEN 4
BOOL CBCGPEditCtrl::m_bOvrMode = FALSE;
UINT BCGM_ON_EDITCHANGE = ::RegisterWindowMessage (_T("BCGM_ON_EDITCHANGE"));
#ifdef _UNICODE
#define _TCF_TEXT CF_UNICODETEXT
#else
#define _TCF_TEXT CF_TEXT
#endif
/////////////////////////////////////////////////////////////////////////////
// CBCGPEditCtrl
CBCGPEditCtrl::CBCGPEditCtrl() :
m_clrBack ((COLORREF) -1),
m_clrText ((COLORREF) -1),
m_nLineHeight (0),
m_nMaxCharWidth (0),
m_hFont (NULL),
m_nCurrOffset (0),
m_nLeftMarginWidth (20),
m_nLineNumbersMarginWidth (40),
m_nOutlineMarginWidth (20),
m_ptCaret (CPoint (m_nLeftMarginWidth, 0)),
m_nTabSize (4),
m_iStartSel (-1),
m_iEndSel (-1),
m_bEnableWholeTextCopy (FALSE),
m_nScrollOffsetHorz (0),
m_nScrollOffsetVert (0),
m_nScrollHiddenVert (0),
m_nTopVisibleOffset (0),
m_szTotalScroll (0, 0),
m_nCurRow (0),
m_nCurColumn (0),
m_nLastSelOffset (-1),
m_nLastMaxColumn (0),
m_posUndoBuffer (NULL),
m_nUndoBufferSize (300),
m_bEOL (FALSE),
m_bBOL (FALSE),
m_bIntelliSenseSupport(FALSE),
m_bIsLastActionUndo (TRUE),
m_bUndoCharMode (FALSE),
m_bDragTextMode (FALSE),
m_nSavedOffset (0),
m_nDropOffset (-1),
m_bDefaultIndent (TRUE),
m_pIntelliSenseWnd (NULL),
m_pIntelliSenseImgList (NULL),
m_pIntelliSenseLBFont (NULL),
m_bIntelliSenseMode (FALSE),
m_bKeepTabs (TRUE),
m_nTabLogicalSize (0),
m_bBlockSelectionMode (FALSE),
m_bAltPressedForBlockSel (FALSE),
m_nIndentSize (4),
m_bReadOnly (FALSE),
m_nLineVertSpacing (1),
m_nMaxScrollWidth (2048),
m_nTotalLines (0),
m_nHiddenLines (0),
m_bEnableToolTips (FALSE),
m_bReplaceTabsAndEOLOnCopy (TRUE),
m_bIntelliSenseUpdate(FALSE),
m_bIsModified (FALSE),
m_nScrollTimeOut (100),
m_nScrollTimer (-1),
m_bToolTipCleared (FALSE),
m_posDocSavedUndoPos (NULL),
m_dwLastUndoReason (g_dwUATUndefined)
{
m_strWordDelimeters = _T(" \t\n,./?<>;:\"'{[}]~`%^&*()-+=!");
m_strSpecialDelimiters = _T (";.{}\n");
m_strNonSelectableChars = _T (" \n\t");
m_strIndentChars = _T (" \t");
m_strIntelliSenseChars = _T (".>:");
m_strContinueStringSymbols = _T ("\\");
m_rectText.SetRectEmpty ();
m_ptStartBlockSel = m_ptEndBlockSel = CPoint (-1, -1);
m_nScrollRightOffset = 15; // percents
m_nScrollLeftOffset = 2; // symbols
m_nPrevKey = m_nLastKey = -1;
m_hPrinterFont = NULL;
m_hMirrorFont = NULL;
m_nDlgCode = DLGC_WANTALLKEYS | DLGC_WANTMESSAGE;
m_pSymbolsImgList = NULL;
m_bEnableSymSupport = FALSE;
m_bEnableLineNumbersMargin = FALSE;
m_bEnableOutlineMargin = FALSE;
m_bEnableOutlining = FALSE;
m_bAutoOutlining = FALSE;
m_nMaxHintCharsNum = 512;
m_pOutlineNodeCurr = NULL;
m_pOutlineParser = NULL;
if (m_bEnableLineNumbersMargin)
{
m_ptCaret.x += m_nLineNumbersMarginWidth;
}
if (m_bEnableOutlineMargin)
{
m_ptCaret.x += m_nOutlineMarginWidth;
}
}
CBCGPEditCtrl::~CBCGPEditCtrl ()
{
CleanUpMarkers ();
EmptyUndoList ();
delete m_pOutlineParser;
}
void CBCGPEditCtrl::EmptyUndoList ()
{
while (!m_lstUndoActions.IsEmpty ())
{
BCGP_EDIT_UNDO_ACTION* pUndoAction = m_lstUndoActions.GetHead ();
OnRemoveUndoAction (pUndoAction);
delete m_lstUndoActions.RemoveHead ();
}
m_posUndoBuffer = NULL;
m_bEOL = FALSE;
m_bBOL = FALSE;
m_bIsLastActionUndo = TRUE;
}
BEGIN_MESSAGE_MAP(CBCGPEditCtrl, CWnd)
//{{AFX_MSG_MAP(CBCGPEditCtrl)
ON_WM_CREATE()
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_SETCURSOR()
ON_WM_KEYDOWN()
ON_WM_SIZE()
ON_WM_LBUTTONDOWN()
ON_WM_CHAR()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_VSCROLL()
ON_WM_HSCROLL()
ON_WM_MOUSEWHEEL()
ON_WM_LBUTTONDBLCLK()
ON_WM_KILLFOCUS()
ON_WM_SETFOCUS()
ON_WM_RBUTTONDOWN()
ON_WM_TIMER()
ON_WM_SYSCOLORCHANGE()
ON_WM_GETDLGCODE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETFONT, OnSetFont)
ON_MESSAGE(WM_GETFONT, OnGetFont)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, OnTTNeedTipText)
ON_MESSAGE(WM_SETTEXT, OnSetText)
ON_MESSAGE(WM_GETTEXT, OnGetText)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBCGPEditCtrl message handlers
int CBCGPEditCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_DropTarget.Register (this);
CRect rectClient;
GetClientRect (&rectClient);
m_wndToolTip.Create (this, TTS_ALWAYSTIP | TTS_NOPREFIX);
if(globalData.m_nMaxToolTipWidth != -1)
{
m_wndToolTip.SetMaxTipWidth(globalData.m_nMaxToolTipWidth);
}
m_wndToolTip.AddTool (this, LPSTR_TEXTCALLBACK, &rectClient, GetDlgCtrlID ());
Initialize ();
SetCaret (0);
return 0;
}
//********************************************************************************
void CBCGPEditCtrl::PreSubclassWindow()
{
CWnd::PreSubclassWindow();
}
//********************************************************************************
void CBCGPEditCtrl::Initialize ()
{
//-----------------
// Initialize font:
//-----------------
OnChangeFont ();
InitColors ();
g_cFormat = (CLIPFORMAT) RegisterClipboardFormat (_T ("BCGP_TEXT"));
CString strBuffer;
ProcessTextBeforeInsert (strBuffer);
InsertText (strBuffer, -1, FALSE, TRUE);
m_strBuffer = strBuffer;
ModifyStyle (0, WS_HSCROLL | WS_VSCROLL);
m_pOutlineParser = CreateOutlineParser ();
if (m_pOutlineParser != NULL)
{
m_pOutlineParser->Init ();
}
}
//********************************************************************************
BOOL CBCGPEditCtrl::OnEraseBkgnd(CDC* /*pDC*/)
{
return TRUE;
}
//*******************************************************************************
void CBCGPEditCtrl::OnPaint()
{
CPaintDC dcPaint(this); // device context for painting
CRect rectClient;
GetClientRect (rectClient);
CRect rectClip;
dcPaint.GetClipBox (rectClip);
CDC* pDC = &dcPaint;
BOOL bMemDC = FALSE;
CDC dcMem;
CBitmap bmp;
CBitmap* pOldBmp = NULL;
if (dcMem.CreateCompatibleDC (&dcPaint) &&
bmp.CreateCompatibleBitmap (&dcPaint, rectClient.Width (),
rectClient.Height ()))
{
//-------------------------------------------------------------
// Off-screen DC successfully created. Better paint to it then!
//-------------------------------------------------------------
bMemDC = TRUE;
pOldBmp = dcMem.SelectObject (&bmp);
pDC = &dcMem;
}
//-------------------------
// Fill control background:
//-------------------------
OnFillBackground (pDC);
//---------------------
// Set text attributes:
//---------------------
int nOldBkMode = pDC->SetBkMode (TRANSPARENT);
COLORREF clrOldText = pDC->SetTextColor (GetDefaultTextColor ());
CFont* pOldFont = SelectFont (pDC);
int nVertOffset = m_nScrollOffsetVert * m_nLineHeight;
//---------------
// Draw side bar:
//---------------
if (m_nLeftMarginWidth > 0 && rectClip.left < m_nLeftMarginWidth)
{
CRect rectLeft = rectClient;
rectLeft.right = rectLeft.left + m_nLeftMarginWidth;
rectLeft.top -= nVertOffset;
OnDrawSideBar (pDC, rectLeft);
}
int nMargin = m_nLeftMarginWidth;
// ---------------------------
// Draw line numbers side bar:
// ---------------------------
if (m_bEnableLineNumbersMargin)
{
if (m_nLineNumbersMarginWidth > 0 && rectClip.left < nMargin + m_nLineNumbersMarginWidth)
{
CRect rectLeft = rectClient;
rectLeft.left = rectLeft.left + nMargin;
rectLeft.right = rectLeft.left + m_nLineNumbersMarginWidth;
rectLeft.top -= nVertOffset;
OnDrawLineNumbersBar (pDC, rectLeft);
}
nMargin += m_nLineNumbersMarginWidth;
}
//--------------------------
// Draw outlining side bar :
//--------------------------
if (m_bEnableOutlineMargin)
{
if (m_nOutlineMarginWidth > 0 && rectClip.left < nMargin + m_nOutlineMarginWidth)
{
CRect rectLeft = rectClient;
rectLeft.left = rectLeft.left + nMargin;
rectLeft.right = rectLeft.left + m_nOutlineMarginWidth;
rectLeft.top -= nVertOffset;
OnDrawOutlineBar (pDC, rectLeft);
}
nMargin += m_nOutlineMarginWidth;
}
//-------------
// Draw border:
//-------------
if (GetExStyle () & WS_EX_CLIENTEDGE)
{
pDC->DrawEdge (rectClient, BDR_SUNKENINNER, BF_RECT);
}
else if (GetExStyle () & WS_EX_WINDOWEDGE)
{
pDC->DrawEdge (rectClient, BDR_RAISEDINNER, BF_RECT);
}
else if (GetStyle () & WS_BORDER)
{
pDC->Draw3dRect (rectClient, ::GetSysColor (COLOR_WINDOWTEXT),
::GetSysColor (COLOR_WINDOWTEXT));
}
//-----------
// Draw text:
//-----------
if (!m_strBuffer.IsEmpty ())
{
rectClip.IntersectRect (rectClip, m_rectText);
CRgn rgnClip;
rgnClip.CreateRectRgnIndirect (&rectClip);
pDC->SelectClipRgn (&rgnClip);
OnDrawText (pDC);
pDC->SelectClipRgn (NULL);
rectClip = rectClient;
}
pDC->SelectObject (pOldFont);
pDC->SetTextColor (clrOldText);
pDC->SetBkMode (nOldBkMode);
if (bMemDC)
{
//--------------------------------------
// Copy the results to the on-screen DC:
//--------------------------------------
dcPaint.BitBlt (rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(),
&dcMem, rectClip.left, rectClip.top, SRCCOPY);
dcMem.SelectObject(pOldBmp);
}
}
//*****************************************************************************
afx_msg LRESULT CBCGPEditCtrl::OnSetFont (WPARAM wParam, LPARAM lParam)
{
m_hFont = (HFONT) wParam;
OnChangeFont ();
if ((BOOL)lParam)
{
RedrawWindow ();
}
return 0;
}
//*****************************************************************************
afx_msg LRESULT CBCGPEditCtrl::OnGetFont (WPARAM, LPARAM)
{
return (LRESULT) m_hFont;
}
//*****************************************************************************
CFont* CBCGPEditCtrl::SelectFont (CDC* pDC)
{
CFont* pOldFont = NULL;
if (pDC->IsPrinting ())
{
if (m_hPrinterFont != NULL)
{
pOldFont = pDC->SelectObject (CFont::FromHandle(m_hPrinterFont));
}
}
else
{
pOldFont = (m_hFont == NULL) ?
(CFont*) pDC->SelectStockObject (DEFAULT_GUI_FONT) :
pDC->SelectObject (CFont::FromHandle (m_hFont));
}
ASSERT (pOldFont != NULL);
return pOldFont;
}
//*****************************************************************************
LRESULT CBCGPEditCtrl::OnSetText (WPARAM, LPARAM lp)
{
LPCTSTR lpszText = (LPCTSTR) lp;
m_nCurrOffset = 0;
m_nTotalLines = 0;
m_nHiddenLines = 0;
m_iEndSel = -1;
m_iStartSel = -1;
//workaround for vertical scroll bar
m_strBuffer = _T(" ");
UpdateScrollBars ();
m_strBuffer = _T("");
if (lpszText != NULL)
{
InsertText (lpszText, -1, FALSE, TRUE, FALSE);
}
m_posUndoBuffer = NULL;
while (!m_lstUndoActions.IsEmpty ())
{
delete m_lstUndoActions.RemoveHead ();
}
SetCaret (0);
Invalidate ();
UpdateWindow ();
return TRUE;
}
//*****************************************************************************
LRESULT CBCGPEditCtrl::OnGetText (WPARAM wp, LPARAM lp)
{
int nMaxChars = min ((int) wp, m_strBuffer.GetLength ());
LPTSTR lpszText = (LPTSTR) lp;
ASSERT (lpszText != NULL);
::lstrcpyn (lpszText, m_strBuffer, nMaxChars);
return nMaxChars;
}
//*****************************************************************************
BOOL CBCGPEditCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
CPoint ptCursor;
::GetCursorPos (&ptCursor);
ScreenToClient (&ptCursor);
if (m_rectText.PtInRect (ptCursor))
{
if (IsPointInSelectionRect (ptCursor))
{
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
if (m_bReadOnly)
{
CPoint pt = ptCursor;
HitTest (pt, TRUE, TRUE);
if (abs (pt.x - ptCursor.x) > m_nMaxCharWidth ||
abs (pt.y - ptCursor.y) > m_nLineHeight)
{
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
}
::SetCursor (AfxGetApp ()->LoadStandardCursor (IDC_IBEAM));
return TRUE;
}
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
//*****************************************************************************
void CBCGPEditCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
const BOOL bShift = ::GetAsyncKeyState (VK_SHIFT) & 0x8000;
const BOOL bCtrl = ::GetAsyncKeyState (VK_CONTROL) & 0x8000;
if (nChar > VK_ESCAPE && nChar < VK_NUMLOCK)
{
ToolTipPop ();
}
if (m_bReadOnly)
{
switch (nChar)
{
case VK_LEFT:
ScrollUp (SB_HORZ, TRUE);
break;
case VK_RIGHT:
ScrollDown (SB_HORZ, TRUE);
break;
case VK_HOME:
StartOfText ();
break;
case VK_END:
EndOfText ();
break;
case VK_UP:
ScrollUp (SB_VERT, TRUE);
break;
case VK_DOWN:
ScrollDown (SB_VERT, TRUE);
break;
case VK_PRIOR:
PageUp ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -