📄 ccrystaltextview.cpp
字号:
if (nSelEnd < nCount)
{
DrawLineHelperImpl(pdc, ptOrigin, rcClip, pszChars, nOffset + nSelEnd, nCount - nSelEnd);
}
}
else
{
DrawLineHelperImpl(pdc, ptOrigin, rcClip, pszChars, nOffset, nCount);
}
}
}
void CCrystalTextView::GetLineColors(int nLineIndex, COLORREF &crBkgnd,
COLORREF &crText, BOOL &bDrawWhitespace)
{
DWORD dwLineFlags = GetLineFlags(nLineIndex);
bDrawWhitespace = TRUE;
crText = RGB(255, 255, 255);
if (dwLineFlags & LF_EXECUTION)
{
crBkgnd = RGB(0, 128, 0);
return;
}
if (dwLineFlags & LF_BREAKPOINT)
{
crBkgnd = RGB(255, 0, 0);
return;
}
if (dwLineFlags & LF_INVALID_BREAKPOINT)
{
crBkgnd = RGB(128, 128, 0);
return;
}
crBkgnd = CLR_NONE;
crText = CLR_NONE;
bDrawWhitespace = FALSE;
}
DWORD CCrystalTextView::GetParseCookie(int nLineIndex)
{
int nLineCount = GetLineCount();
if (m_pdwParseCookies == NULL)
{
m_nParseArraySize = nLineCount;
m_pdwParseCookies = new DWORD[nLineCount];
memset(m_pdwParseCookies, 0xff, nLineCount * sizeof(DWORD));
}
if (nLineIndex < 0)
return 0;
if (m_pdwParseCookies[nLineIndex] != (DWORD) -1)
return m_pdwParseCookies[nLineIndex];
int L = nLineIndex;
while (L >= 0 && m_pdwParseCookies[L] == (DWORD) -1)
L --;
L ++;
int nBlocks;
while (L <= nLineIndex)
{
DWORD dwCookie = 0;
if (L > 0)
dwCookie = m_pdwParseCookies[L - 1];
ASSERT(dwCookie != (DWORD) -1);
m_pdwParseCookies[L] = ParseLine(dwCookie, L, NULL, nBlocks);
ASSERT(m_pdwParseCookies[L] != (DWORD) -1);
L ++;
}
return m_pdwParseCookies[nLineIndex];
}
void CCrystalTextView::DrawSingleLine(CDC *pdc, const CRect &rc, int nLineIndex)
{
ASSERT(nLineIndex >= -1 && nLineIndex < GetLineCount());
if (nLineIndex == -1)
{
// Draw line beyond the text
pdc->FillSolidRect(rc, GetColor(COLORINDEX_WHITESPACE));
return;
}
// Acquire the background color for the current line
BOOL bDrawWhitespace = FALSE;
COLORREF crBkgnd, crText;
GetLineColors(nLineIndex, crBkgnd, crText, bDrawWhitespace);
if (crBkgnd == CLR_NONE)
crBkgnd = GetColor(COLORINDEX_BKGND);
int nLength = GetLineLength(nLineIndex);
if (nLength == 0)
{
// Draw the empty line
CRect rect = rc;
if ((m_bFocused || m_bShowInactiveSelection) && IsInsideSelBlock(CPoint(0, nLineIndex)))
{
pdc->FillSolidRect(rect.left, rect.top, GetCharWidth(), rect.Height(), GetColor(COLORINDEX_SELBKGND));
rect.left += GetCharWidth();
}
pdc->FillSolidRect(rect, bDrawWhitespace ? crBkgnd : GetColor(COLORINDEX_WHITESPACE));
return;
}
// Parse the line
LPCTSTR pszChars = GetLineChars(nLineIndex);
DWORD dwCookie = GetParseCookie(nLineIndex - 1);
TEXTBLOCK *pBuf = (TEXTBLOCK *) _alloca(sizeof(TEXTBLOCK) * nLength * 3);
int nBlocks = 0;
m_pdwParseCookies[nLineIndex] = ParseLine(dwCookie, nLineIndex, pBuf, nBlocks);
ASSERT(m_pdwParseCookies[nLineIndex] != (DWORD) -1);
// Draw the line text
CPoint origin(rc.left - m_nOffsetChar * GetCharWidth(), rc.top);
pdc->SetBkColor(crBkgnd);
if (crText != CLR_NONE)
pdc->SetTextColor(crText);
BOOL bColorSet = FALSE;
if (nBlocks > 0)
{
ASSERT(pBuf[0].m_nCharPos >= 0 && pBuf[0].m_nCharPos <= nLength);
if (crText == CLR_NONE)
pdc->SetTextColor(GetColor(COLORINDEX_NORMALTEXT));
pdc->SelectObject(GetFont(GetItalic(COLORINDEX_NORMALTEXT), GetBold(COLORINDEX_NORMALTEXT)));
DrawLineHelper(pdc, origin, rc, COLORINDEX_NORMALTEXT, pszChars, 0, pBuf[0].m_nCharPos, CPoint(0, nLineIndex));
for (int I = 0; I < nBlocks - 1; I ++)
{
ASSERT(pBuf[I].m_nCharPos >= 0 && pBuf[I].m_nCharPos <= nLength);
if (crText == CLR_NONE)
pdc->SetTextColor(GetColor(pBuf[I].m_nColorIndex));
pdc->SelectObject(GetFont(GetItalic(pBuf[I].m_nColorIndex), GetBold(pBuf[I].m_nColorIndex)));
DrawLineHelper(pdc, origin, rc, pBuf[I].m_nColorIndex, pszChars,
pBuf[I].m_nCharPos, pBuf[I + 1].m_nCharPos - pBuf[I].m_nCharPos,
CPoint(pBuf[I].m_nCharPos, nLineIndex));
}
ASSERT(pBuf[nBlocks - 1].m_nCharPos >= 0 && pBuf[nBlocks - 1].m_nCharPos <= nLength);
if (crText == CLR_NONE)
pdc->SetTextColor(GetColor(pBuf[nBlocks - 1].m_nColorIndex));
pdc->SelectObject(GetFont(GetItalic(pBuf[nBlocks - 1].m_nColorIndex),
GetBold(pBuf[nBlocks - 1].m_nColorIndex)));
DrawLineHelper(pdc, origin, rc, pBuf[nBlocks - 1].m_nColorIndex, pszChars,
pBuf[nBlocks - 1].m_nCharPos, nLength - pBuf[nBlocks - 1].m_nCharPos,
CPoint(pBuf[nBlocks - 1].m_nCharPos, nLineIndex));
}
else
{
if (crText == CLR_NONE)
pdc->SetTextColor(GetColor(COLORINDEX_NORMALTEXT));
pdc->SelectObject(GetFont(GetItalic(COLORINDEX_NORMALTEXT), GetBold(COLORINDEX_NORMALTEXT)));
DrawLineHelper(pdc, origin, rc, COLORINDEX_NORMALTEXT, pszChars, 0, nLength, CPoint(0, nLineIndex));
}
// Draw whitespaces to the left of the text
CRect frect = rc;
if (origin.x > frect.left)
frect.left = origin.x;
if (frect.right > frect.left)
{
if ((m_bFocused || m_bShowInactiveSelection) && IsInsideSelBlock(CPoint(nLength, nLineIndex)))
{
pdc->FillSolidRect(frect.left, frect.top, GetCharWidth(), frect.Height(),
GetColor(COLORINDEX_SELBKGND));
frect.left += GetCharWidth();
}
if (frect.right > frect.left)
pdc->FillSolidRect(frect, bDrawWhitespace ? crBkgnd : GetColor(COLORINDEX_WHITESPACE));
}
}
COLORREF CCrystalTextView::GetColor(int nColorIndex)
{
switch (nColorIndex)
{
case COLORINDEX_WHITESPACE:
case COLORINDEX_BKGND:
return ::GetSysColor(COLOR_WINDOW);
case COLORINDEX_NORMALTEXT:
return ::GetSysColor(COLOR_WINDOWTEXT);
case COLORINDEX_SELMARGIN:
return ::GetSysColor(COLOR_SCROLLBAR);
case COLORINDEX_PREPROCESSOR:
return RGB(0, 128, 192);
case COLORINDEX_COMMENT:
return RGB(128, 128, 128);
// [JRT]: Enabled Support For Numbers...
case COLORINDEX_NUMBER:
return RGB(0x80, 0x00, 0x00);
// [JRT]: Support For C/C++ Operators
case COLORINDEX_OPERATOR:
return RGB(0x00, 0x00, 0x00);
case COLORINDEX_KEYWORD:
return RGB(0, 0, 255);
case COLORINDEX_SELBKGND:
return RGB(0, 0, 0);
case COLORINDEX_SELTEXT:
return RGB(255, 255, 255);
}
return RGB(255, 0, 0);
}
DWORD CCrystalTextView::GetLineFlags(int nLineIndex)
{
if (m_pTextBuffer == NULL)
return 0;
return m_pTextBuffer->GetLineFlags(nLineIndex);
}
void CCrystalTextView::DrawMargin(CDC *pdc, const CRect &rect, int nLineIndex)
{
if (! m_bSelMargin)
{
pdc->FillSolidRect(rect, GetColor(COLORINDEX_BKGND));
return;
}
pdc->FillSolidRect(rect, GetColor(COLORINDEX_SELMARGIN));
int nImageIndex = -1;
if (nLineIndex >= 0)
{
DWORD dwLineFlags = GetLineFlags(nLineIndex);
static const DWORD adwFlags[] =
{
LF_EXECUTION,
LF_BREAKPOINT,
LF_COMPILATION_ERROR,
LF_BOOKMARK(1),
LF_BOOKMARK(2),
LF_BOOKMARK(3),
LF_BOOKMARK(4),
LF_BOOKMARK(5),
LF_BOOKMARK(6),
LF_BOOKMARK(7),
LF_BOOKMARK(8),
LF_BOOKMARK(9),
LF_BOOKMARK(0),
LF_BOOKMARKS,
LF_INVALID_BREAKPOINT
};
for (int I = 0; I <= sizeof(adwFlags) / sizeof(adwFlags[0]); I ++)
{
if ((dwLineFlags & adwFlags[I]) != 0)
{
nImageIndex = I;
break;
}
}
}
if (nImageIndex >= 0)
{
if (m_pIcons == NULL)
{
m_pIcons = new CImageList;
VERIFY(m_pIcons->Create(IDR_MARGIN_ICONS, 16, 16, RGB(255, 255, 255)));
}
CPoint pt(rect.left + 2, rect.top + (rect.Height() - 16) / 2);
VERIFY(m_pIcons->Draw(pdc, nImageIndex, pt, ILD_TRANSPARENT));
}
}
BOOL CCrystalTextView::IsInsideSelBlock(CPoint ptTextPos)
{
ASSERT_VALIDTEXTPOS(ptTextPos);
if (ptTextPos.y < m_ptDrawSelStart.y)
return FALSE;
if (ptTextPos.y > m_ptDrawSelEnd.y)
return FALSE;
if (ptTextPos.y < m_ptDrawSelEnd.y && ptTextPos.y > m_ptDrawSelStart.y)
return TRUE;
if (m_ptDrawSelStart.y < m_ptDrawSelEnd.y)
{
if (ptTextPos.y == m_ptDrawSelEnd.y)
return ptTextPos.x < m_ptDrawSelEnd.x;
ASSERT(ptTextPos.y == m_ptDrawSelStart.y);
return ptTextPos.x >= m_ptDrawSelStart.x;
}
ASSERT(m_ptDrawSelStart.y == m_ptDrawSelEnd.y);
return ptTextPos.x >= m_ptDrawSelStart.x && ptTextPos.x < m_ptDrawSelEnd.x;
}
BOOL CCrystalTextView::IsInsideSelection(const CPoint &ptTextPos)
{
PrepareSelBounds();
return IsInsideSelBlock(ptTextPos);
}
void CCrystalTextView::PrepareSelBounds()
{
if (m_ptSelStart.y < m_ptSelEnd.y ||
(m_ptSelStart.y == m_ptSelEnd.y && m_ptSelStart.x < m_ptSelEnd.x))
{
m_ptDrawSelStart = m_ptSelStart;
m_ptDrawSelEnd = m_ptSelEnd;
}
else
{
m_ptDrawSelStart = m_ptSelEnd;
m_ptDrawSelEnd = m_ptSelStart;
}
}
void CCrystalTextView::OnDraw(CDC *pdc)
{
CRect rcClient;
GetClientRect(rcClient);
int nLineCount = GetLineCount();
int nLineHeight = GetLineHeight();
PrepareSelBounds();
CDC cacheDC;
VERIFY(cacheDC.CreateCompatibleDC(pdc));
if (m_pCacheBitmap == NULL)
{
m_pCacheBitmap = new CBitmap;
VERIFY(m_pCacheBitmap->CreateCompatibleBitmap(pdc, rcClient.Width(), nLineHeight));
}
CBitmap *pOldBitmap = cacheDC.SelectObject(m_pCacheBitmap);
CRect rcLine;
rcLine = rcClient;
rcLine.bottom = rcLine.top + nLineHeight;
CRect rcCacheMargin(0, 0, GetMarginWidth(), nLineHeight);
CRect rcCacheLine(GetMarginWidth(), 0, rcLine.Width(), nLineHeight);
int nCurrentLine = m_nTopLine;
while (rcLine.top < rcClient.bottom)
{
if (nCurrentLine < nLineCount)
{
DrawMargin(&cacheDC, rcCacheMargin, nCurrentLine);
DrawSingleLine(&cacheDC, rcCacheLine, nCurrentLine);
}
else
{
DrawMargin(&cacheDC, rcCacheMargin, -1);
DrawSingleLine(&cacheDC, rcCacheLine, -1);
}
VERIFY(pdc->BitBlt(rcLine.left, rcLine.top, rcLine.Width(), rcLine.Height(), &cacheDC, 0, 0, SRCCOPY));
nCurrentLine ++;
rcLine.OffsetRect(0, nLineHeight);
}
cacheDC.SelectObject(pOldBitmap);
cacheDC.DeleteDC();
}
void CCrystalTextView::ResetView()
{
m_nTopLine = 0;
m_nOffsetChar = 0;
m_nLineHeight = -1;
m_nCharWidth = -1;
m_nTabSize = 4;
m_nMaxLineLength = -1;
m_nScreenLines = -1;
m_nScreenChars = -1;
m_nIdealCharPos = -1;
m_ptAnchor.x = 0;
m_ptAnchor.y = 0;
if (m_pIcons != NULL)
{
delete m_pIcons;
m_pIcons = NULL;
}
for (int I = 0; I < 4; I ++)
{
if (m_apFonts[I] != NULL)
{
m_apFonts[I]->DeleteObject();
delete m_apFonts[I];
m_apFonts[I] = NULL;
}
}
if (m_pdwParseCookies != NULL)
{
delete m_pdwParseCookies;
m_pdwParseCookies = NULL;
}
if (m_pnActualLineLength != NULL)
{
delete m_pnActualLineLength;
m_pnActualLineLength = NULL;
}
m_nParseArraySize = 0;
m_nActualLengthArraySize = 0;
m_ptCursorPos.x = 0;
m_ptCursorPos.y = 0;
m_ptSelStart = m_ptSelEnd = m_ptCursorPos;
m_bDragSelection = FALSE;
m_bVertScrollBarLocked = FALSE;
m_bHorzScrollBarLocked = FALSE;
if (::IsWindow(m_hWnd))
UpdateCaret();
m_bLastSearch = FALSE;
// m_bLastSearch = TRUE;
m_bShowInactiveSelection = FALSE;
m_bPrintHeader = FALSE;
m_bPrintFooter = TRUE;
m_bBookmarkExist = FALSE; // More bookmarks
m_bMultipleSearch = FALSE; // More search
}
void CCrystalTextView::UpdateCaret()
{
ASSERT_VALIDTEXTPOS(m_ptCursorPos);
if (m_bFocused && ! m_bCursorHidden &&
CalculateActualOffset(m_ptCursorPos.y, m_ptCursorPos.x) >= m_nOffsetChar)
{
CreateSolidCaret(2, GetLineHeight());
SetCaretPos(TextToClient(m_ptCursorPos));
ShowCaret();
}
else
{
HideCaret();
}
}
int CCrystalTextView::GetTabSize()
{
ASSERT(m_nTabSize >= 0 && m_nTabSize <= 64);
return m_nTabSize;
}
void CCrystalTextView::SetTabSize(int nTabSize)
{
ASSERT(nTabSize >= 0 && nTabSize <= 64);
if (m_nTabSize != nTabSize)
{
m_nTabSize = nTabSize;
if (m_pnActualLineLength != NULL)
{
delete m_pnActualLineLength;
m_pnActualLineLength = NULL;
}
m_nActualLengthArraySize = 0;
m_nMaxLineLength = -1;
RecalcHorzScrollBar();
Invalidate();
UpdateCaret();
}
}
CFont *CCrystalTextView::GetFont(BOOL bItalic /*= FALSE*/, BOOL bBold /*= FALSE*/)
{
int nIndex = 0;
if (bBold)
nIndex |= 1;
if (bItalic)
nIndex |= 2;
if (m_apFonts[nIndex] == NULL)
{
m_apFonts[nIndex] = new CFont;
m_lfBaseFont.lfWeight = bBold ? FW_BOLD : FW_NORMAL;
m_lfBaseFont.lfItalic = (BYTE) bItalic;
if (! m_apFonts[nIndex]->CreateFontIndirect(&m_lfBaseFont))
{
delete m_apFonts[nIndex];
m_apFonts[nIndex] = NULL;
return CView::GetFont();
}
}
return m_apFonts[nIndex];
}
void CCrystalTextView::CalcLineCharDim()
{
CDC *pdc = GetDC();
CFont *pOldFont = pdc->SelectObject(GetFont());
CSize szCharExt = pdc->GetTextExtent(_T("X"));
m_nLineHeight = szCharExt.cy;
if (m_nLineHeight < 1)
m_nLineHeight = 1;
m_nCharWidth = szCharExt.cx;
/*
TEXTMETRIC tm;
if (pdc->GetTextMetrics(&tm))
m_nCharWidth -= tm.tmOverhang;
*/
pdc->SelectObject(pOldFont);
ReleaseDC(pdc);
}
int CCrystalTextView::GetLineHeight()
{
if (m_nLineHeight == -1)
CalcLineCharDim();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -