📄 richviewctrl.cpp
字号:
m_pFragments.RemoveAll();
m_nLength = 0;
if ( m_bSelecting )
{
m_bSelecting = FALSE;
ReleaseCapture();
}
m_pSelStart.nFragment = m_pSelStart.nOffset = 0;
m_pSelEnd.nFragment = m_pSelEnd.nOffset = 0;
m_pSelAbsStart.nFragment = m_pSelAbsStart.nOffset = 0;
m_pSelAbsEnd.nFragment = m_pSelAbsEnd.nOffset = 0;
}
void CRichViewCtrl::Layout(CDC* pDC, CRect* pRect)
{
ASSERT( m_pDocument != NULL );
CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
ClearFragments();
pRect->DeflateRect( m_pDocument->m_szMargin.cx, m_pDocument->m_szMargin.cy );
CPoint pt( pRect->left, pRect->top );
int nLeftPoint = pRect->left;
int nWidth = pRect->Width();
int nLineHeight = 0;
int nAlign = reaLeft;
CRichFragment* pFrag = NULL;
CPtrList pLine;
for ( POSITION pos = m_pDocument->GetIterator() ; pos ; )
{
CRichElement* pElement = m_pDocument->GetNext( pos );
if ( pElement->m_nFlags & retfHidden ) continue;
pElement->PrePaint( pDC, FALSE );
if ( pElement->m_nType == retNewline )
{
WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
int nGap = 0, nIndent = 0;
if ( _stscanf( pElement->m_sText, _T("%lu.%lu"), &nGap, &nIndent ) == 2 )
{
nLeftPoint = pRect->left + nIndent;
nWidth = pRect->right - nIndent;
}
pt.x = nLeftPoint;
pt.y += nGap;
continue;
}
else if ( pElement->m_nType == retAlign )
{
WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
if ( pElement->m_sText.CompareNoCase( _T("center") ) == 0 )
{
nAlign = reaCenter;
}
else if ( pElement->m_sText.CompareNoCase( _T("right") ) == 0 )
{
nAlign = reaRight;
}
else
{
nAlign = reaLeft;
}
continue;
}
else if ( pElement->m_nType == retGap || pElement->m_nType < retText )
{
pFrag = new CRichFragment( pElement, &pt );
m_pFragments.Add( pFrag );
if ( pt.x + pFrag->m_sz.cx > nWidth )
{
WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
pFrag->m_pt = pt;
}
pt.x += pFrag->m_sz.cx;
if ( pElement->m_nType != retGap )
{
nLineHeight = max( nLineHeight, pFrag->m_sz.cy );
pLine.AddTail( pFrag );
}
continue;
}
LPTSTR pszText = (LPTSTR)(LPCTSTR)pElement->m_sText;
LPCTSTR pszWord = pszText;
LPCTSTR pszLast = NULL;
int nWordStart = 0;
int nSpace = pDC->GetTextExtent( _T(" ") ).cx;
pFrag = NULL;
for ( int nChar = 0 ; nChar <= pElement->m_sText.GetLength() ; nChar++, pszText++ )
{
if ( *pszText != ' ' && *pszText != '\t' && *pszText != 0 ) continue;
if ( nChar > nWordStart || *pszText == 0 )
{
TCHAR cSave = *pszText;
*pszText = 0;
CSize szWord = pDC->GetTextExtent( pszWord );
if ( pFrag != NULL )
{
CSize szLast = pDC->GetTextExtent( pszLast );
if ( pFrag->m_pt.x + szLast.cx <= nWidth )
{
pt.x -= pFrag->m_sz.cx;
pFrag->Add( nChar - pFrag->m_nOffset, &szLast );
pt.x += pFrag->m_sz.cx;
nWordStart = -1;
}
}
if ( nChar == nWordStart && *pszText == 0 ) break;
if ( nWordStart >= 0 )
{
if ( pt.x + szWord.cx + ( pFrag ? nSpace : 0 ) > nWidth )
{
WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
}
else if ( pFrag != NULL ) pt.x += nSpace;
pFrag = new CRichFragment( pElement, nWordStart, nChar - nWordStart, &pt, &szWord );
pszLast = pszWord;
pt.x += pFrag->m_sz.cx;
nLineHeight = max( nLineHeight, pFrag->m_sz.cy );
m_pFragments.Add( pFrag );
pLine.AddTail( pFrag );
}
*pszText = cSave;
}
if ( pFrag != NULL )
{
nWordStart = nChar + 1;
pszWord = pszText + 1;
}
}
}
WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
pRect->InflateRect( m_pDocument->m_szMargin.cx, m_pDocument->m_szMargin.cy );
m_nLength = pt.y - pRect->top + m_pDocument->m_szMargin.cy;
SCROLLINFO pInfo;
pInfo.cbSize = sizeof(pInfo);
pInfo.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
GetScrollInfo( SB_VERT, &pInfo, pInfo.fMask );
if ( m_bFollowBottom && pInfo.nPos >= pInfo.nMax - (int)pInfo.nPage - 1 )
pInfo.nPos = m_nLength;
pInfo.fMask = SIF_ALL & ~SIF_TRACKPOS;
pInfo.nMin = 0;
pInfo.nMax = m_nLength - 1;
pInfo.nPage = ( pRect->bottom == -1 ) ? m_nLength : pRect->Height();
pInfo.nPos = min( pInfo.nPos, max( 0, pInfo.nMax - (int)pInfo.nPage ) );
SetScrollInfo( SB_VERT, &pInfo, TRUE );
m_nCookie = m_pDocument->m_nCookie;
OnLayoutComplete();
}
void CRichViewCtrl::WrapLineHelper(CPtrList& pLine, CPoint& pt, int& nLineHeight, int nWidth, int nAlign)
{
if ( pLine.GetCount() == 0 ) return;
int nLeft = ((CRichFragment*)pLine.GetHead())->m_pt.x;
int nHorz = 0;
if ( nAlign == reaCenter )
{
nHorz = nWidth / 2 - ( pt.x - nLeft ) / 2;
}
else if ( nAlign == reaRight )
{
nHorz = nWidth - pt.x;
}
for ( POSITION posAlign = pLine.GetHeadPosition() ; posAlign ; )
{
CRichFragment* pAlign = (CRichFragment*)pLine.GetNext( posAlign );
if ( pAlign->m_pElement->m_nFlags & retfMiddle )
{
pAlign->m_pt.y += ( nLineHeight / 2 - pAlign->m_sz.cy / 2 );
}
else
{
pAlign->m_pt.y += ( nLineHeight - pAlign->m_sz.cy );
}
pAlign->m_pt.x += nHorz;
}
pt.x = nLeft;
pt.y += nLineHeight;
pLine.RemoveAll();
nLineHeight = 0;
}
/////////////////////////////////////////////////////////////////////////////
// CRichViewCtrl coordinate mapping
CRichFragment* CRichViewCtrl::PointToFrag(CPoint& pt)
{
if ( m_pDocument == NULL || m_pDocument->m_nCookie != m_nCookie ) return NULL;
pt.y += GetScrollPos( SB_VERT );
for ( int nFragment = m_pFragments.GetSize() - 1 ; nFragment >= 0 ; nFragment-- )
{
CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
if ( pt.x >= pFragment->m_pt.x && pt.y >= pFragment->m_pt.y &&
pt.x < pFragment->m_pt.x + pFragment->m_sz.cx &&
pt.y < pFragment->m_pt.y + pFragment->m_sz.cy )
{
pt.y -= GetScrollPos( SB_VERT );
return pFragment;
}
}
pt.y -= GetScrollPos( SB_VERT );
return NULL;
}
RICHPOSITION CRichViewCtrl::PointToPosition(CPoint& pt)
{
RICHPOSITION pos = { -1, 0 };
if ( m_pDocument == NULL || m_pDocument->m_nCookie != m_nCookie ) return pos;
pt.y += GetScrollPos( SB_VERT );
for ( int nFragment = 0 ; nFragment < m_pFragments.GetSize() ; nFragment++ )
{
CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
if ( pt.x >= pFragment->m_pt.x && pt.y >= pFragment->m_pt.y &&
pt.x < pFragment->m_pt.x + pFragment->m_sz.cx &&
pt.y < pFragment->m_pt.y + pFragment->m_sz.cy )
{
pos.nFragment = nFragment;
if ( pFragment->m_nLength > 0 )
{
CClientDC dc( this );
CFont* pOld = dc.GetCurrentFont();
pFragment->m_pElement->PrePaint( &dc, FALSE );
LPCTSTR pszText = pFragment->m_pElement->m_sText;
pszText += pFragment->m_nOffset;
int nX = pt.x - pFragment->m_pt.x;
for ( pos.nOffset = 0 ; pos.nOffset < pFragment->m_nLength ; pszText ++ )
{
int nWidth = dc.GetTextExtent( pszText, 1 ).cx;
if ( nX < ( nWidth >> 1 ) ) break;
pos.nOffset++;
if ( nX < nWidth ) break;
nX -= nWidth;
}
dc.SelectObject( pOld );
}
break;
}
}
pt.y -= GetScrollPos( SB_VERT );
return pos;
}
CPoint CRichViewCtrl::PositionToPoint(RICHPOSITION& pos)
{
CPoint pt( 0, - GetScrollPos( SB_VERT ) );
if ( m_pDocument == NULL || m_pDocument->m_nCookie != m_nCookie ) return pt;
if ( pos.nFragment < 0 || m_pFragments.GetSize() == 0 ) return pt;
BOOL bOverload = pos.nFragment >= m_pFragments.GetSize();
CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt(
bOverload ? m_pFragments.GetSize() - 1 : pos.nFragment );
pt.x = pFragment->m_pt.x;
pt.y += pFragment->m_pt.y;
if ( bOverload )
{
pt.x += pFragment->m_sz.cx;
}
else if ( pos.nOffset > 0 )
{
if ( pos.nOffset < pFragment->m_nLength )
{
CClientDC dc( this );
CFont* pOld = dc.GetCurrentFont();
pFragment->m_pElement->PrePaint( &dc, FALSE );
LPCTSTR pszText = pFragment->m_pElement->m_sText;
pszText += pFragment->m_nOffset;
pt.x += dc.GetTextExtent( pszText, pos.nOffset ).cx;
dc.SelectObject( pOld );
}
else
{
pt.x += pFragment->m_sz.cx;
}
}
return pt;
}
/////////////////////////////////////////////////////////////////////////////
// CRichViewCtrl selection helpers
void CRichViewCtrl::UpdateSelection()
{
if ( m_pSelStart.nFragment < m_pSelEnd.nFragment || ( m_pSelStart.nFragment == m_pSelEnd.nFragment && m_pSelStart.nOffset <= m_pSelEnd.nOffset ) )
{
if ( m_pSelAbsStart.nFragment != m_pSelStart.nFragment ||
m_pSelAbsStart.nOffset != m_pSelStart.nOffset ||
m_pSelAbsEnd.nFragment != m_pSelEnd.nFragment ||
m_pSelAbsEnd.nOffset != m_pSelEnd.nOffset )
{
m_pSelAbsStart = m_pSelStart;
m_pSelAbsEnd = m_pSelEnd;
Invalidate();
}
}
else
{
if ( m_pSelAbsStart.nFragment != m_pSelEnd.nFragment ||
m_pSelAbsStart.nOffset != m_pSelEnd.nOffset ||
m_pSelAbsEnd.nFragment != m_pSelStart.nFragment ||
m_pSelAbsEnd.nOffset != m_pSelStart.nOffset )
{
m_pSelAbsStart = m_pSelEnd;
m_pSelAbsEnd = m_pSelStart;
Invalidate();
}
}
}
void CRichViewCtrl::CopySelection()
{
CString str;
for ( int nFragment = m_pSelAbsStart.nFragment ; nFragment <= m_pSelAbsEnd.nFragment ; nFragment++ )
{
CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
if ( pFragment->m_nLength == 0 )
{
if ( nFragment == m_pSelAbsEnd.nFragment ) break;
if ( pFragment->m_pElement->m_nType == retEmoticon )
{
int nToken = 0;
_stscanf( pFragment->m_pElement->m_sText, _T("%i"), &nToken );
if ( LPCTSTR pszToken = Emoticons.GetText( nToken ) )
str += pszToken;
}
else if ( pFragment->m_pElement->m_nType < retText )
{
str += ' ';
}
}
else
{
int nCharStart = 0, nCharEnd = pFragment->m_nLength;
if ( m_pSelAbsStart.nFragment == nFragment )
{
nCharStart = m_pSelAbsStart.nOffset;
}
if ( m_pSelAbsEnd.nFragment == nFragment )
{
nCharEnd = m_pSelAbsEnd.nOffset;
}
if ( nCharEnd > nCharStart )
{
str += pFragment->m_pElement->m_sText.Mid(
pFragment->m_nOffset + nCharStart,
nCharEnd - nCharStart );
}
}
if ( nFragment < m_pSelAbsEnd.nFragment )
{
CRichFragment* pNextFrag = (CRichFragment*)m_pFragments.GetAt( nFragment + 1 );
if ( pFragment->m_pElement != pNextFrag->m_pElement )
{
POSITION pos = m_pDocument->Find( pFragment->m_pElement );
while ( pos )
{
CRichElement* pCopy = m_pDocument->GetNext( pos );
if ( pCopy == pNextFrag->m_pElement ) break;
if ( pCopy->m_nType == retNewline ) str += _T("\r\n");
}
}
}
}
if ( str.GetLength() && AfxGetMainWnd()->OpenClipboard() )
{
USES_CONVERSION;
EmptyClipboard();
if ( theApp.m_bNT )
{
LPCWSTR pszWide = T2CW( (LPCTSTR)str );
HANDLE hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, ( wcslen(pszWide) + 1 ) * sizeof(WCHAR) );
LPVOID pMem = GlobalLock( hMem );
CopyMemory( pMem, pszWide, ( wcslen(pszWide) + 1 ) * sizeof(WCHAR) );
GlobalUnlock( hMem );
SetClipboardData( CF_UNICODETEXT, hMem );
}
else
{
LPCSTR pszASCII = T2CA( (LPCTSTR)str );
HANDLE hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, strlen(pszASCII) + 1 );
LPVOID pMem = GlobalLock( hMem );
CopyMemory( pMem, pszASCII, strlen(pszASCII) + 1 );
GlobalUnlock( hMem );
SetClipboardData( CF_TEXT, hMem );
}
CloseClipboard();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -