📄 ccrystaltextview.cpp
字号:
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
VERIFY(GetScrollInfo(SB_HORZ, &si));
int nPageChars = GetScreenChars();
int nMaxLineLength = GetMaxLineLength();
int nNewOffset;
switch (nSBCode)
{
case SB_LEFT:
nNewOffset = 0;
break;
case SB_BOTTOM:
nNewOffset = nMaxLineLength - nPageChars + 1;
break;
case SB_LINEUP:
nNewOffset = m_nOffsetChar - 1;
break;
case SB_LINEDOWN:
nNewOffset = m_nOffsetChar + 1;
break;
case SB_PAGEUP:
nNewOffset = m_nOffsetChar - si.nPage + 1;
break;
case SB_PAGEDOWN:
nNewOffset = m_nOffsetChar + si.nPage - 1;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
nNewOffset = si.nTrackPos;
break;
default:
return;
}
if (nNewOffset >= nMaxLineLength)
nNewOffset = nMaxLineLength - 1;
if (nNewOffset < 0)
nNewOffset = 0;
ScrollToChar(nNewOffset, TRUE);
UpdateCaret();
}
BOOL CCrystalTextView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (nHitTest == HTCLIENT)
{
CPoint pt;
::GetCursorPos(&pt);
ScreenToClient(&pt);
if (pt.x < GetMarginWidth())
{
::SetCursor(::LoadCursor(GetResourceHandle(), MAKEINTRESOURCE(IDR_MARGIN_CURSOR)));
}
else
{
CPoint ptText = ClientToText(pt);
PrepareSelBounds();
if (IsInsideSelBlock(ptText))
{
if (!m_bDisableDragAndDrop)
::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
}
else
::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_IBEAM)));
}
return TRUE;
}
return CView::OnSetCursor(pWnd, nHitTest, message);
}
CPoint CCrystalTextView::ClientToText(const CPoint &point)
{
int nLineCount = GetLineCount();
CPoint pt;
pt.y = m_nTopLine + point.y / GetLineHeight();
if (pt.y >= nLineCount)
pt.y = nLineCount - 1;
if (pt.y < 0)
pt.y = 0;
int nLength = 0;
LPCTSTR pszLine = NULL;
if (pt.y >= 0 && pt.y < nLineCount)
{
nLength = GetLineLength(pt.y);
pszLine = GetLineChars(pt.y);
}
int nPos = m_nOffsetChar + (point.x - GetMarginWidth()) / GetCharWidth();
if (nPos < 0)
nPos = 0;
int nIndex = 0, nCurPos = 0;
int nTabSize = GetTabSize();
while (nIndex < nLength)
{
if (pszLine[nIndex] == _T('\t'))
nCurPos += (nTabSize - nCurPos % nTabSize);
else
nCurPos ++;
if (nCurPos > nPos)
break;
nIndex ++;
}
ASSERT(nIndex >= 0 && nIndex <= nLength);
pt.x = nIndex;
return pt;
}
#ifdef _DEBUG
void CCrystalTextView::AssertValidTextPos(const CPoint &point)
{
if (GetLineCount() > 0)
{
ASSERT(m_nTopLine >= 0 && m_nOffsetChar >= 0);
ASSERT(point.y >= 0 && point.y < GetLineCount());
ASSERT(point.x >= 0 && point.x <= GetLineLength(point.y));
}
}
#endif
CPoint CCrystalTextView::TextToClient(const CPoint &point)
{
ASSERT_VALIDTEXTPOS(point);
int nLength = GetLineLength(point.y);
LPCTSTR pszLine = GetLineChars(point.y);
CPoint pt;
pt.y = (point.y - m_nTopLine) * GetLineHeight();
pt.x = 0;
int nTabSize = GetTabSize();
for (int nIndex = 0; nIndex < point.x; nIndex ++)
{
if (pszLine[nIndex] == _T('\t'))
pt.x += (nTabSize - pt.x % nTabSize);
else
pt.x ++;
}
pt.x = (pt.x - m_nOffsetChar) * GetCharWidth() + GetMarginWidth();
return pt;
}
void CCrystalTextView::InvalidateLines(int nLine1, int nLine2, BOOL bInvalidateMargin /*= FALSE*/)
{
bInvalidateMargin = TRUE;
if (nLine2 == -1)
{
CRect rcInvalid;
GetClientRect(&rcInvalid);
if (! bInvalidateMargin)
rcInvalid.left += GetMarginWidth();
rcInvalid.top = (nLine1 - m_nTopLine) * GetLineHeight();
InvalidateRect(&rcInvalid, FALSE);
}
else
{
if (nLine2 < nLine1)
{
int nTemp = nLine1;
nLine1 = nLine2;
nLine2 = nTemp;
}
CRect rcInvalid;
GetClientRect(&rcInvalid);
if (! bInvalidateMargin)
rcInvalid.left += GetMarginWidth();
rcInvalid.top = (nLine1 - m_nTopLine) * GetLineHeight();
rcInvalid.bottom = (nLine2 - m_nTopLine + 1) * GetLineHeight();
InvalidateRect(&rcInvalid, FALSE);
}
}
void CCrystalTextView::SetSelection(const CPoint &ptStart, const CPoint &ptEnd)
{
ASSERT_VALIDTEXTPOS(ptStart);
ASSERT_VALIDTEXTPOS(ptEnd);
if (m_ptSelStart == ptStart)
{
if (m_ptSelEnd != ptEnd)
InvalidateLines(ptEnd.y, m_ptSelEnd.y);
}
else
{
InvalidateLines(ptStart.y, ptEnd.y);
InvalidateLines(m_ptSelStart.y, m_ptSelEnd.y);
}
m_ptSelStart = ptStart;
m_ptSelEnd = ptEnd;
}
void CCrystalTextView::AdjustTextPoint(CPoint &point)
{
point.x += GetCharWidth() / 2;
}
void CCrystalTextView::OnSetFocus(CWnd* pOldWnd)
{
CView::OnSetFocus(pOldWnd);
m_bFocused = TRUE;
if (m_ptSelStart != m_ptSelEnd)
InvalidateLines(m_ptSelStart.y, m_ptSelEnd.y);
UpdateCaret();
}
DWORD CCrystalTextView::ParseLine(DWORD dwCookie, int nLineIndex, TEXTBLOCK *pBuf, int &nActualItems)
{
return 0;
}
int CCrystalTextView::CalculateActualOffset(int nLineIndex, int nCharIndex)
{
int nLength = GetLineLength(nLineIndex);
ASSERT(nCharIndex >= 0 && nCharIndex <= nLength);
LPCTSTR pszChars = GetLineChars(nLineIndex);
int nOffset = 0;
int nTabSize = GetTabSize();
for (int I = 0; I < nCharIndex; I ++)
{
if (pszChars[I] == _T('\t'))
nOffset += (nTabSize - nOffset % nTabSize);
else
nOffset ++;
}
return nOffset;
}
int CCrystalTextView::ApproxActualOffset(int nLineIndex, int nOffset)
{
if (nOffset == 0)
return 0;
int nLength = GetLineLength(nLineIndex);
LPCTSTR pszChars = GetLineChars(nLineIndex);
int nCurrentOffset = 0;
int nTabSize = GetTabSize();
for (int I = 0; I < nLength; I ++)
{
if (pszChars[I] == _T('\t'))
nCurrentOffset += (nTabSize - nCurrentOffset % nTabSize);
else
nCurrentOffset ++;
if (nCurrentOffset >= nOffset)
{
if (nOffset <= nCurrentOffset - nTabSize / 2)
return I;
return I + 1;
}
}
return nLength;
}
void CCrystalTextView::EnsureVisible(CPoint pt)
{
int nLineCount = GetLineCount();
int nNewTopLine = m_nTopLine;
if (pt.y >= nNewTopLine + GetScreenLines())
{
nNewTopLine = pt.y - GetScreenLines() + 1;
}
if (pt.y < nNewTopLine)
{
nNewTopLine = pt.y;
}
if (nNewTopLine < 0)
nNewTopLine = 0;
if (nNewTopLine >= nLineCount)
nNewTopLine = nLineCount - 1;
if (m_nTopLine != nNewTopLine)
{
ScrollToLine(nNewTopLine);
UpdateSiblingScrollPos(TRUE);
}
int nActualPos = CalculateActualOffset(pt.y, pt.x);
int nNewOffset = m_nOffsetChar;
if (nActualPos > nNewOffset + GetScreenChars())
{
nNewOffset = nActualPos - GetScreenChars();
}
if (nActualPos < nNewOffset)
{
nNewOffset = nActualPos;
}
if (nNewOffset >= GetMaxLineLength())
nNewOffset = GetMaxLineLength() - 1;
if (nNewOffset < 0)
nNewOffset = 0;
if (m_nOffsetChar != nNewOffset)
{
ScrollToChar(nNewOffset);
UpdateCaret();
UpdateSiblingScrollPos(FALSE);
}
}
void CCrystalTextView::OnKillFocus(CWnd* pNewWnd)
{
CView::OnKillFocus(pNewWnd);
m_bFocused = FALSE;
UpdateCaret();
if (m_ptSelStart != m_ptSelEnd)
InvalidateLines(m_ptSelStart.y, m_ptSelEnd.y);
if (m_bDragSelection)
{
ReleaseCapture();
KillTimer(m_nDragSelTimer);
m_bDragSelection = FALSE;
}
}
void CCrystalTextView::OnSysColorChange()
{
CView::OnSysColorChange();
Invalidate();
}
void CCrystalTextView::GetText(const CPoint &ptStart, const CPoint &ptEnd, CString &text)
{
if (m_pTextBuffer != NULL)
m_pTextBuffer->GetText(ptStart.y, ptStart.x, ptEnd.y, ptEnd.x, text);
else
text = _T("");
}
void CCrystalTextView::UpdateView(CCrystalTextView *pSource, CUpdateContext *pContext,
DWORD dwFlags, int nLineIndex /*= -1*/)
{
if (dwFlags & UPDATE_RESET)
{
ResetView();
RecalcVertScrollBar();
RecalcHorzScrollBar();
return;
}
int nLineCount = GetLineCount();
ASSERT(nLineCount > 0);
ASSERT(nLineIndex >= -1 && nLineIndex < nLineCount);
if ((dwFlags & UPDATE_SINGLELINE) != 0)
{
ASSERT(nLineIndex != -1);
// All text below this line should be reparsed
if (m_pdwParseCookies != NULL)
{
ASSERT(m_nParseArraySize == nLineCount);
memset(m_pdwParseCookies + nLineIndex, 0xff, sizeof(DWORD) * (m_nParseArraySize - nLineIndex));
}
if (m_pnActualLineLength != NULL)
{
ASSERT(m_nActualLengthArraySize == nLineCount);
m_pnActualLineLength[nLineIndex] = -1;
}
InvalidateLines(nLineIndex, -1, TRUE);
}
else
{
if (nLineIndex == -1)
nLineIndex = 0;
if (m_pdwParseCookies != NULL)
{
if (m_nParseArraySize != nLineCount)
{
DWORD *pdwNewArray = new DWORD[nLineCount];
if (nLineIndex > 0)
memcpy(pdwNewArray, m_pdwParseCookies, sizeof(DWORD) * nLineIndex);
delete m_pdwParseCookies;
m_nParseArraySize = nLineCount;
m_pdwParseCookies = pdwNewArray;
}
memset(m_pdwParseCookies + nLineIndex, 0xff, sizeof(DWORD) * (m_nParseArraySize - nLineIndex));
}
if (m_pnActualLineLength != NULL)
{
if (m_nActualLengthArraySize != nLineCount)
{
int *pnNewArray = new int[nLineCount];
if (nLineIndex > 0)
memcpy(pnNewArray, m_pnActualLineLength, sizeof(int) * nLineIndex);
delete m_pnActualLineLength;
m_nActualLengthArraySize = nLineCount;
m_pnActualLineLength = pnNewArray;
}
memset(m_pnActualLineLength + nLineIndex, 0xff, sizeof(DWORD) * (m_nActualLengthArraySize - nLineIndex));
}
InvalidateLines(nLineIndex, -1, TRUE);
}
if (pContext != NULL)
{
pContext->RecalcPoint(m_ptCursorPos);
pContext->RecalcPoint(m_ptSelStart);
pContext->RecalcPoint(m_ptSelEnd);
pContext->RecalcPoint(m_ptAnchor);
ASSERT_VALIDTEXTPOS(m_ptCursorPos);
ASSERT_VALIDTEXTPOS(m_ptSelStart);
ASSERT_VALIDTEXTPOS(m_ptSelEnd);
ASSERT_VALIDTEXTPOS(m_ptAnchor);
if (m_bDraggingText)
{
pContext->RecalcPoint(m_ptDraggedTextBegin);
pContext->RecalcPoint(m_ptDraggedTextEnd);
ASSERT_VALIDTEXTPOS(m_ptDraggedTextBegin);
ASSERT_VALIDTEXTPOS(m_ptDraggedTextEnd);
}
CPoint ptTopLine(0, m_nTopLine);
pContext->RecalcPoint(ptTopLine);
ASSERT_VALIDTEXTPOS(ptTopLine);
m_nTopLine = ptTopLine.y;
UpdateCaret();
}
if ((dwFlags & UPDATE_VERTRANGE) != 0)
{
if (! m_bVertScrollBarLocked)
RecalcVertScrollBar();
}
if ((dwFlags & UPDATE_HORZRANGE) != 0)
{
m_nMaxLineLength = -1;
if (! m_bHorzScrollBarLocked)
RecalcHorzScrollBar();
}
}
HINSTANCE CCrystalTextView::GetResourceHandle()
{
#ifdef CRYSEDIT_RES_HANDLE
return CRYSEDIT_RES_HANDLE;
#else
if (s_hResourceInst != NULL)
return s_hResourceInst;
return AfxGetResourceHandle();
#endif
}
int CCrystalTextView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
memset(&m_lfBaseFont, 0, sizeof(m_lfBaseFont));
lstrcpy(m_lfBaseFont.lfFaceName, _T("FixedSys"));
m_lfBaseFont.lfHeight = 0;
m_lfBaseFont.lfWeight = FW_NORMAL;
m_lfBaseFont.lfItalic = FALSE;
m_lfBaseFont.lfCharSet = DEFAULT_CHARSET;
m_lfBaseFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
m_lfBaseFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
m_lfBaseFont.lfQuality = DEFAULT_QUALITY;
m_lfBaseFont.lfPitchAndFamily = DEFAULT_PITCH;
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
ASSERT(m_hAccel == NULL);
m_hAccel = ::LoadAccelerators(GetResourceHandle(), MAKEINTRESOURCE(IDR_DEFAULT_ACCEL));
ASSERT(m_hAccel != NULL);
return 0;
}
void CCrystalTextView::SetAnchor(const CPoint &ptNewAnchor)
{
ASSERT_VALIDTEXTPOS(ptNewAnchor);
m_ptAnchor = ptNewAnchor;
}
void CCrystalTextView::OnEditOperation(int nAction, LPCTSTR pszText)
{
}
BOOL CCrystalTextView::PreTranslateMessage(MSG *pMsg)
{
if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
{
if (m_hAccel != NULL)
{
if (::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
return TRUE;
}
}
return CView::PreTranslateMessage(pMsg);
}
CPoint CCrystalTextView::GetCursorPos()
{
return m_ptCursorPos;
}
void CCrystalTextView::SetCursorPos(const CPoint &ptCursorPos)
{
ASSERT_VALIDTEXTPOS(ptCursorPos);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -