📄 ccrystaltextview.cpp
字号:
}
}
}
}
void CCrystalTextView::RecalcVertScrollBar(BOOL bPositionOnly /*= FALSE*/)
{
SCROLLINFO si;
si.cbSize = sizeof(si);
if (bPositionOnly)
{
si.fMask = SIF_POS;
si.nPos = m_nTopLine;
}
else
{
if (GetScreenLines() >= GetLineCount() && m_nTopLine > 0)
{
m_nTopLine = 0;
Invalidate();
UpdateCaret();
}
si.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE;
si.nMin = 0;
si.nMax = GetLineCount() - 1;
si.nPage = GetScreenLines();
si.nPos = m_nTopLine;
}
VERIFY(SetScrollInfo(SB_VERT, &si));
}
void CCrystalTextView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CView::OnVScroll(nSBCode, nPos, pScrollBar);
// Note we cannot use nPos because of its 16-bit nature
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
VERIFY(GetScrollInfo(SB_VERT, &si));
int nPageLines = GetScreenLines();
int nLineCount = GetLineCount();
int nNewTopLine;
BOOL bDisableSmooth = TRUE;
switch (nSBCode)
{
case SB_TOP:
nNewTopLine = 0;
bDisableSmooth = FALSE;
break;
case SB_BOTTOM:
nNewTopLine = nLineCount - nPageLines + 1;
bDisableSmooth = FALSE;
break;
case SB_LINEUP:
nNewTopLine = m_nTopLine - 1;
break;
case SB_LINEDOWN:
nNewTopLine = m_nTopLine + 1;
break;
case SB_PAGEUP:
nNewTopLine = m_nTopLine - si.nPage + 1;
bDisableSmooth = FALSE;
break;
case SB_PAGEDOWN:
nNewTopLine = m_nTopLine + si.nPage - 1;
bDisableSmooth = FALSE;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
nNewTopLine = si.nTrackPos;
break;
default:
return;
}
if (nNewTopLine < 0)
nNewTopLine = 0;
if (nNewTopLine >= nLineCount)
nNewTopLine = nLineCount - 1;
ScrollToLine(nNewTopLine, bDisableSmooth);
}
void CCrystalTextView::RecalcHorzScrollBar(BOOL bPositionOnly /*= FALSE*/)
{
// Again, we cannot use nPos because it's 16-bit
SCROLLINFO si;
si.cbSize = sizeof(si);
if (bPositionOnly)
{
si.fMask = SIF_POS;
si.nPos = m_nOffsetChar;
}
else
{
if (GetScreenChars() >= GetMaxLineLength() && m_nOffsetChar > 0)
{
m_nOffsetChar = 0;
Invalidate();
UpdateCaret();
}
si.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE;
si.nMin = 0;
si.nMax = GetMaxLineLength() - 1;
si.nPage = GetScreenChars();
si.nPos = m_nOffsetChar;
}
VERIFY(SetScrollInfo(SB_HORZ, &si));
}
void CCrystalTextView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CView::OnHScroll(nSBCode, nPos, pScrollBar);
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))
{
// [JRT]: Support For Disabling Drag and Drop...
if (!m_bDisableDragAndDrop) // If Drag And Drop Not Disabled
::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); // Set To Arrow Cursor
}
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; //todo
}
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)
{
// Scroll vertically
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);
}
// Scroll horizontally
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));
}
// This line'th actual length must be recalculated
if (m_pnActualLineLength != NULL)
{
ASSERT(m_nActualLengthArraySize == nLineCount);
m_pnActualLineLength[nLineIndex] = -1;
}
// Repaint the lines
InvalidateLines(nLineIndex, -1, TRUE);
}
else
{
if (nLineIndex == -1)
nLineIndex = 0; // Refresh all text
// All text below this line should be reparsed
if (m_pdwParseCookies != NULL)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -