📄 ccrystaltextview.cpp
字号:
return m_nLineHeight;
}
int CCrystalTextView::GetCharWidth()
{
if (m_nCharWidth == -1)
CalcLineCharDim();
return m_nCharWidth;
}
int CCrystalTextView::GetMaxLineLength()
{
if (m_nMaxLineLength == -1)
{
m_nMaxLineLength = 0;
int nLineCount = GetLineCount();
for (int I = 0; I < nLineCount; I ++)
{
int nActualLength = GetLineActualLength(I);
if (m_nMaxLineLength < nActualLength)
m_nMaxLineLength = nActualLength;
}
}
return m_nMaxLineLength;
}
CCrystalTextView *CCrystalTextView::GetSiblingView(int nRow, int nCol)
{
CSplitterWnd *pSplitter = GetParentSplitter(this, FALSE);
if (pSplitter == NULL)
return NULL;
CWnd *pWnd = CWnd::FromHandlePermanent(
::GetDlgItem(pSplitter->m_hWnd, pSplitter->IdFromRowCol(nRow, nCol)));
if (pWnd == NULL || ! pWnd->IsKindOf(RUNTIME_CLASS(CCrystalTextView)))
return NULL;
return (CCrystalTextView *) pWnd;
}
void CCrystalTextView::OnInitialUpdate()
{
CView::OnInitialUpdate();
AttachToBuffer(NULL);
CSplitterWnd *pSplitter = GetParentSplitter(this, FALSE);
if (pSplitter != NULL)
{
// See CSplitterWnd::IdFromRowCol() implementation
int nRow = (GetDlgCtrlID() - AFX_IDW_PANE_FIRST) / 16;
int nCol = (GetDlgCtrlID() - AFX_IDW_PANE_FIRST) % 16;
ASSERT(nRow >= 0 && nRow < pSplitter->GetRowCount());
ASSERT(nCol >= 0 && nCol < pSplitter->GetColumnCount());
if (nRow > 0)
{
CCrystalTextView *pSiblingView = GetSiblingView(0, nCol);
if (pSiblingView != NULL && pSiblingView != this)
{
m_nOffsetChar = pSiblingView->m_nOffsetChar;
ASSERT(m_nOffsetChar >= 0 && m_nOffsetChar <= GetMaxLineLength());
}
}
if (nCol > 0)
{
CCrystalTextView *pSiblingView = GetSiblingView(nRow, 0);
if (pSiblingView != NULL && pSiblingView != this)
{
m_nTopLine = pSiblingView->m_nTopLine;
ASSERT(m_nTopLine >= 0 && m_nTopLine < GetLineCount());
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CCrystalTextView printing
void CCrystalTextView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
CView::OnPrepareDC(pDC, pInfo);
if (pInfo != NULL)
{
pInfo->m_bContinuePrinting = TRUE;
if (m_pnPages != NULL && (int) pInfo->m_nCurPage > m_nPrintPages)
pInfo->m_bContinuePrinting = FALSE;
}
}
BOOL CCrystalTextView::OnPreparePrinting(CPrintInfo* pInfo)
{
return DoPreparePrinting(pInfo);
}
int CCrystalTextView::PrintLineHeight(CDC *pdc, int nLine)
{
ASSERT(nLine >= 0 && nLine < GetLineCount());
ASSERT(m_nPrintLineHeight > 0);
int nLength = GetLineLength(nLine);
if (nLength == 0)
return m_nPrintLineHeight;
CString line;
LPCTSTR pszChars = GetLineChars(nLine);
ExpandChars(pszChars, 0, nLength, line);
CRect rcPrintArea = m_rcPrintArea;
pdc->DrawText(line, &rcPrintArea, DT_LEFT | DT_NOPREFIX | DT_TOP | DT_WORDBREAK | DT_CALCRECT);
return rcPrintArea.Height();
}
void CCrystalTextView::GetPrintHeaderText(int nPageNum, CString &text)
{
ASSERT(m_bPrintHeader);
text = _T("");
}
void CCrystalTextView::GetPrintFooterText(int nPageNum, CString &text)
{
ASSERT(m_bPrintFooter);
text.Format(_T("Page %d/%d"), nPageNum, m_nPrintPages);
}
void CCrystalTextView::PrintHeader(CDC *pdc, int nPageNum)
{
CRect rcHeader = m_rcPrintArea;
rcHeader.bottom = rcHeader.top;
rcHeader.top -= (m_nPrintLineHeight + m_nPrintLineHeight / 2);
CString text;
GetPrintHeaderText(nPageNum, text);
if (! text.IsEmpty())
pdc->DrawText(text, &rcHeader, DT_CENTER | DT_NOPREFIX | DT_TOP | DT_SINGLELINE);
}
void CCrystalTextView::PrintFooter(CDC *pdc, int nPageNum)
{
CRect rcFooter = m_rcPrintArea;
rcFooter.top = rcFooter.bottom;
rcFooter.bottom += (m_nPrintLineHeight + m_nPrintLineHeight / 2);
CString text;
GetPrintFooterText(nPageNum, text);
if (! text.IsEmpty())
pdc->DrawText(text, &rcFooter, DT_CENTER | DT_NOPREFIX | DT_BOTTOM | DT_SINGLELINE);
}
void CCrystalTextView::RecalcPageLayouts(CDC *pdc, CPrintInfo *pInfo)
{
m_ptPageArea = pInfo->m_rectDraw;
m_ptPageArea.NormalizeRect();
m_nPrintLineHeight = pdc->GetTextExtent(_T("X")).cy;
m_rcPrintArea = m_ptPageArea;
CSize szTopLeft, szBottomRight;
CWinApp *pApp = AfxGetApp();
ASSERT(pApp != NULL);
szTopLeft.cx = pApp->GetProfileInt(REG_PAGE_SUBKEY, REG_MARGIN_LEFT, DEFAULT_PRINT_MARGIN);
szBottomRight.cx = pApp->GetProfileInt(REG_PAGE_SUBKEY, REG_MARGIN_RIGHT, DEFAULT_PRINT_MARGIN);
szTopLeft.cy = pApp->GetProfileInt(REG_PAGE_SUBKEY, REG_MARGIN_TOP, DEFAULT_PRINT_MARGIN);
szBottomRight.cy = pApp->GetProfileInt(REG_PAGE_SUBKEY, REG_MARGIN_BOTTOM, DEFAULT_PRINT_MARGIN);
pdc->HIMETRICtoLP(&szTopLeft);
pdc->HIMETRICtoLP(&szBottomRight);
m_rcPrintArea.left += szTopLeft.cx;
m_rcPrintArea.right -= szBottomRight.cx;
m_rcPrintArea.top += szTopLeft.cy;
m_rcPrintArea.bottom -= szBottomRight.cy;
if (m_bPrintHeader)
m_rcPrintArea.top += m_nPrintLineHeight + m_nPrintLineHeight / 2;
if (m_bPrintFooter)
m_rcPrintArea.bottom += m_nPrintLineHeight + m_nPrintLineHeight / 2;
int nLimit = 32;
m_nPrintPages = 1;
m_pnPages = new int[nLimit];
m_pnPages[0] = 0;
int nLineCount = GetLineCount();
int nLine = 1;
int y = m_rcPrintArea.top + PrintLineHeight(pdc, 0);
while (nLine < nLineCount)
{
int nHeight = PrintLineHeight(pdc, nLine);
if (y + nHeight <= m_rcPrintArea.bottom)
{
y += nHeight;
}
else
{
ASSERT(nLimit >= m_nPrintPages);
if (nLimit <= m_nPrintPages)
{
nLimit += 32;
int *pnNewPages = new int[nLimit];
memcpy(pnNewPages, m_pnPages, sizeof(int) * m_nPrintPages);
delete m_pnPages;
m_pnPages = pnNewPages;
}
ASSERT(nLimit > m_nPrintPages);
m_pnPages[m_nPrintPages ++] = nLine;
y = m_rcPrintArea.top + nHeight;
}
nLine ++;
}
}
void CCrystalTextView::OnBeginPrinting(CDC *pdc, CPrintInfo *pInfo)
{
ASSERT(m_pnPages == NULL);
ASSERT(m_pPrintFont == NULL);
CFont *pDisplayFont = GetFont();
LOGFONT lf;
pDisplayFont->GetLogFont(&lf);
CDC *pDisplayDC = GetDC();
lf.lfHeight = MulDiv(lf.lfHeight, pdc->GetDeviceCaps(LOGPIXELSY), pDisplayDC->GetDeviceCaps(LOGPIXELSY) * 2);
lf.lfWidth = MulDiv(lf.lfWidth, pdc->GetDeviceCaps(LOGPIXELSX), pDisplayDC->GetDeviceCaps(LOGPIXELSX) * 2);
ReleaseDC(pDisplayDC);
m_pPrintFont = new CFont;
if (! m_pPrintFont->CreateFontIndirect(&lf))
{
delete m_pPrintFont;
m_pPrintFont = NULL;
return;
}
pdc->SelectObject(m_pPrintFont);
}
void CCrystalTextView::OnEndPrinting(CDC *pdc, CPrintInfo *pInfo)
{
if (m_pPrintFont != NULL)
{
delete m_pPrintFont;
m_pPrintFont = NULL;
}
if (m_pnPages != NULL)
{
delete m_pnPages;
m_pnPages = NULL;
}
m_nPrintPages = 0;
m_nPrintLineHeight = 0;
}
void CCrystalTextView::OnPrint(CDC* pdc, CPrintInfo* pInfo)
{
if (m_pnPages == NULL)
{
RecalcPageLayouts(pdc, pInfo);
ASSERT(m_pnPages != NULL);
}
ASSERT(pInfo->m_nCurPage >= 1 && (int) pInfo->m_nCurPage <= m_nPrintPages);
int nLine = m_pnPages[pInfo->m_nCurPage - 1];
int nEndLine = GetLineCount();
if ((int) pInfo->m_nCurPage < m_nPrintPages)
nEndLine = m_pnPages[pInfo->m_nCurPage];
TRACE(_T("Printing page %d of %d, lines %d - %d\n"), pInfo->m_nCurPage, m_nPrintPages,
nLine, nEndLine - 1);
if (m_bPrintHeader)
PrintHeader(pdc, pInfo->m_nCurPage);
if (m_bPrintFooter)
PrintFooter(pdc, pInfo->m_nCurPage);
int y = m_rcPrintArea.top;
for (; nLine < nEndLine; nLine ++)
{
int nLineLength = GetLineLength(nLine);
if (nLineLength == 0)
{
y += m_nPrintLineHeight;
continue;
}
CRect rcPrintRect = m_rcPrintArea;
rcPrintRect.top = y;
LPCTSTR pszChars = GetLineChars(nLine);
CString line;
ExpandChars(pszChars, 0, nLineLength, line);
y += pdc->DrawText(line, &rcPrintRect, DT_LEFT | DT_NOPREFIX | DT_TOP | DT_WORDBREAK);
}
}
/////////////////////////////////////////////////////////////////////////////
// CCrystalTextView message handlers
int CCrystalTextView::GetLineCount()
{
if (m_pTextBuffer == NULL)
return 1; // Single empty line
int nLineCount = m_pTextBuffer->GetLineCount();
ASSERT(nLineCount > 0);
return nLineCount;
}
int CCrystalTextView::GetLineLength(int nLineIndex)
{
if (m_pTextBuffer == NULL)
return 0;
return m_pTextBuffer->GetLineLength(nLineIndex);
}
LPCTSTR CCrystalTextView::GetLineChars(int nLineIndex)
{
if (m_pTextBuffer == NULL)
return NULL;
return m_pTextBuffer->GetLineChars(nLineIndex);
}
void CCrystalTextView::AttachToBuffer(CCrystalTextBuffer *pBuf /*= NULL*/)
{
if (m_pTextBuffer != NULL)
m_pTextBuffer->RemoveView(this);
if (pBuf == NULL)
{
pBuf = LocateTextBuffer();
// ...
}
m_pTextBuffer = pBuf;
if (m_pTextBuffer != NULL)
m_pTextBuffer->AddView(this);
ResetView();
// Init scrollbars
CScrollBar *pVertScrollBarCtrl = GetScrollBarCtrl(SB_VERT);
if (pVertScrollBarCtrl != NULL)
pVertScrollBarCtrl->EnableScrollBar(GetScreenLines() >= GetLineCount() ?
ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
CScrollBar *pHorzScrollBarCtrl = GetScrollBarCtrl(SB_HORZ);
if (pHorzScrollBarCtrl != NULL)
pHorzScrollBarCtrl->EnableScrollBar(GetScreenChars() >= GetMaxLineLength() ?
ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
// Update scrollbars
RecalcVertScrollBar();
RecalcHorzScrollBar();
}
void CCrystalTextView::DetachFromBuffer()
{
if (m_pTextBuffer != NULL)
{
m_pTextBuffer->RemoveView(this);
m_pTextBuffer = NULL;
ResetView();
}
}
int CCrystalTextView::GetScreenLines()
{
if (m_nScreenLines == -1)
{
CRect rect;
GetClientRect(&rect);
m_nScreenLines = rect.Height() / GetLineHeight();
}
return m_nScreenLines;
}
BOOL CCrystalTextView::GetItalic(int nColorIndex)
{
return FALSE;
}
BOOL CCrystalTextView::GetBold(int nColorIndex)
{
return FALSE;
}
int CCrystalTextView::GetScreenChars()
{
if (m_nScreenChars == -1)
{
CRect rect;
GetClientRect(&rect);
m_nScreenChars = (rect.Width() - GetMarginWidth()) / GetCharWidth();
}
return m_nScreenChars;
}
void CCrystalTextView::OnDestroy()
{
DetachFromBuffer();
m_hAccel = NULL;
CView::OnDestroy();
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_pCacheBitmap != NULL)
{
delete m_pCacheBitmap;
m_pCacheBitmap = NULL;
}
}
BOOL CCrystalTextView::OnEraseBkgnd(CDC *pdc)
{
return TRUE;
}
void CCrystalTextView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if (m_pCacheBitmap != NULL)
{
m_pCacheBitmap->DeleteObject();
delete m_pCacheBitmap;
m_pCacheBitmap = NULL;
}
m_nScreenLines = -1;
m_nScreenChars = -1;
RecalcVertScrollBar();
RecalcHorzScrollBar();
}
void CCrystalTextView::UpdateSiblingScrollPos(BOOL bHorz)
{
CSplitterWnd *pSplitterWnd = GetParentSplitter(this, FALSE);
if (pSplitterWnd != NULL)
{
// See CSplitterWnd::IdFromRowCol() implementation for details
int nCurrentRow = (GetDlgCtrlID() - AFX_IDW_PANE_FIRST) / 16;
int nCurrentCol = (GetDlgCtrlID() - AFX_IDW_PANE_FIRST) % 16;
ASSERT(nCurrentRow >= 0 && nCurrentRow < pSplitterWnd->GetRowCount());
ASSERT(nCurrentCol >= 0 && nCurrentCol < pSplitterWnd->GetColumnCount());
if (bHorz)
{
int nCols = pSplitterWnd->GetColumnCount();
for (int nCol = 0; nCol < nCols; nCol ++)
{
if (nCol != nCurrentCol) // We don't need to update ourselves
{
CCrystalTextView *pSiblingView = GetSiblingView(nCurrentRow, nCol);
if (pSiblingView != NULL)
pSiblingView->OnUpdateSibling(this, TRUE);
}
}
}
else
{
int nRows = pSplitterWnd->GetRowCount();
for (int nRow = 0; nRow < nRows; nRow ++)
{
if (nRow != nCurrentRow) // We don't need to update ourselves
{
CCrystalTextView *pSiblingView = GetSiblingView(nRow, nCurrentCol);
if (pSiblingView != NULL)
pSiblingView->OnUpdateSibling(this, FALSE);
}
}
}
}
}
void CCrystalTextView::OnUpdateSibling(CCrystalTextView *pUpdateSource, BOOL bHorz)
{
if (pUpdateSource != this)
{
ASSERT(pUpdateSource != NULL);
ASSERT_KINDOF(CCrystalTextView, pUpdateSource);
if (bHorz)
{
ASSERT(pUpdateSource->m_nTopLine >= 0);
ASSERT(pUpdateSource->m_nTopLine < GetLineCount());
if (pUpdateSource->m_nTopLine != m_nTopLine)
{
ScrollToLine(pUpdateSource->m_nTopLine, TRUE, FALSE);
UpdateCaret();
}
}
else
{
ASSERT(pUpdateSource->m_nOffsetChar >= 0);
ASSERT(pUpdateSource->m_nOffsetChar < GetMaxLineLength());
if (pUpdateSource->m_nOffsetChar != m_nOffsetChar)
{
ScrollToChar(pUpdateSource->m_nOffsetChar, TRUE, FALSE);
UpdateCaret();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -