00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "RichViewCtrl.h"
00025 #include "RichDocument.h"
00026 #include "RichElement.h"
00027 #include "RichFragment.h"
00028
00029 #include "Emoticons.h"
00030
00031 #ifdef _DEBUG
00032 #define new DEBUG_NEW
00033 #undef THIS_FILE
00034 static char THIS_FILE[] = __FILE__;
00035 #endif
00036
00037 BEGIN_MESSAGE_MAP(CRichViewCtrl, CWnd)
00038
00039 ON_WM_CREATE()
00040 ON_WM_DESTROY()
00041 ON_WM_ERASEBKGND()
00042 ON_WM_PAINT()
00043 ON_WM_SIZE()
00044 ON_WM_SETCURSOR()
00045 ON_WM_MOUSEMOVE()
00046 ON_WM_LBUTTONUP()
00047 ON_WM_VSCROLL()
00048 ON_WM_LBUTTONDOWN()
00049 ON_WM_TIMER()
00050 ON_WM_MOUSEWHEEL()
00051
00052 END_MESSAGE_MAP()
00053
00054
00056
00057
00058 CRichViewCtrl::CRichViewCtrl()
00059 {
00060 m_bSelectable = FALSE;
00061 m_bFollowBottom = FALSE;
00062 m_bDefaultLink = TRUE;
00063
00064 m_pDocument = NULL;
00065 m_nLength = 0;
00066 m_pHover = NULL;
00067 m_bSelecting = FALSE;
00068
00069
00070 if( !SystemParametersInfo ( SPI_GETWHEELSCROLLLINES, 0, &m_nScrollWheelLines, 0) )
00071 {
00072 m_nScrollWheelLines = 3;
00073 }
00074 }
00075
00076 CRichViewCtrl::~CRichViewCtrl()
00077 {
00078 ClearFragments();
00079 }
00080
00082
00083
00084 BOOL CRichViewCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
00085 {
00086 dwStyle |= WS_CHILD|WS_VSCROLL;
00087 return CWnd::Create( NULL, NULL, dwStyle, rect, pParentWnd, nID, NULL );
00088 }
00089
00090 void CRichViewCtrl::SetSelectable(BOOL bSelectable)
00091 {
00092 m_bSelectable = bSelectable;
00093 }
00094
00095 void CRichViewCtrl::SetFollowBottom(BOOL bFollowBottom)
00096 {
00097 m_bFollowBottom = bFollowBottom;
00098 }
00099
00100 void CRichViewCtrl::SetDefaultLink(BOOL bDefaultLink)
00101 {
00102 m_bDefaultLink = bDefaultLink;
00103 }
00104
00105 void CRichViewCtrl::SetDocument(CRichDocument* pDocument)
00106 {
00107 m_pDocument = pDocument;
00108 m_nCookie = 0xFFFFFFFF;
00109 m_pHover = NULL;
00110
00111 KillTimer( 1 );
00112 ClearFragments();
00113 Invalidate();
00114 }
00115
00116 BOOL CRichViewCtrl::IsModified() const
00117 {
00118 return ( m_pDocument != NULL && m_pDocument->m_nCookie != m_nCookie );
00119 }
00120
00121 void CRichViewCtrl::InvalidateIfModified()
00122 {
00123 if ( m_pDocument != NULL && m_pDocument->m_nCookie != m_nCookie ) Invalidate();
00124 }
00125
00126 int CRichViewCtrl::FullHeightMove(int nX, int nY, int nWidth, BOOL bShow)
00127 {
00128 if ( m_pDocument == NULL ) return 0;
00129
00130 CRect rc( 0, 0, nWidth, -1 );
00131
00132 CClientDC dc( this );
00133 CFont* pOldFont = (CFont*)dc.SelectObject( &theApp.m_gdiFont );
00134 Layout( &dc, &rc );
00135 dc.SelectObject( pOldFont );
00136
00137 SetWindowPos( NULL, nX, nY, nWidth, m_nLength, SWP_NOZORDER | ( bShow ? SWP_SHOWWINDOW : 0 ) );
00138
00139 return m_nLength;
00140 }
00141
00142 BOOL CRichViewCtrl::GetElementRect(CRichElement* pElement, RECT* prc)
00143 {
00144 for ( int nFragment = 0 ; nFragment < m_pFragments.GetCount() ; nFragment ++ )
00145 {
00146 CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
00147
00148 if ( pFragment->m_pElement == pElement )
00149 {
00150 prc->left = pFragment->m_pt.x;
00151 prc->top = pFragment->m_pt.y;
00152 prc->right = prc->left + pFragment->m_sz.cx;
00153 prc->bottom = prc->top + pFragment->m_sz.cy;
00154
00155 return TRUE;
00156 }
00157 }
00158
00159 return FALSE;
00160 }
00161
00163
00164
00165 int CRichViewCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
00166 {
00167 if ( CWnd::OnCreate( lpCreateStruct ) == -1 ) return -1;
00168
00169 m_hcHand = theApp.LoadCursor( IDC_HAND );
00170 m_hcText = theApp.LoadStandardCursor( IDC_IBEAM );
00171
00172 SetScrollRange( SB_VERT, 0, 0 );
00173 if ( theApp.m_bRTL ) ModifyStyleEx( 0, WS_EX_LAYOUTRTL, 0 );
00174
00175 return 0;
00176 }
00177
00178 void CRichViewCtrl::OnDestroy()
00179 {
00180 CWnd::OnDestroy();
00181 }
00182
00183 void CRichViewCtrl::OnSize(UINT nType, int cx, int cy)
00184 {
00185 CWnd::OnSize( nType, cx, cy );
00186 m_nCookie = 0xFFFFFFFF;
00187 Invalidate();
00188 }
00189
00190 BOOL CRichViewCtrl::OnEraseBkgnd(CDC* pDC)
00191 {
00192 return TRUE;
00193 }
00194
00195 void CRichViewCtrl::OnPaint()
00196 {
00197 CPaintDC dc( this );
00198 CRect rc;
00199
00200 GetClientRect( &rc );
00201
00202 if ( m_pDocument == NULL )
00203 {
00204 dc.FillSolidRect( &rc, GetSysColor( COLOR_WINDOW ) );
00205 return;
00206 }
00207
00208 CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
00209
00210 CFont* pOldFont = (CFont*)dc.SelectObject( &theApp.m_gdiFont );
00211
00212 if ( m_pDocument->m_nCookie != m_nCookie || m_pBrush.m_hObject == NULL )
00213 {
00214 Layout( &dc, &rc );
00215
00216 if ( m_pBrush.m_hObject != NULL ) m_pBrush.DeleteObject();
00217 m_pBrush.CreateSolidBrush( m_pDocument->m_crBackground );
00218 }
00219
00220 dc.SetBkMode( OPAQUE );
00221 dc.SetBkColor( m_pDocument->m_crBackground );
00222 dc.SetViewportOrg( 0, -GetScrollPos( SB_VERT ) );
00223
00224 OnPaintBegin( &dc );
00225
00226 CRichElement* pElement = NULL;
00227
00228 for ( int nFragment = 0 ; nFragment < m_pFragments.GetSize() ; nFragment++ )
00229 {
00230 CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
00231
00232 if ( pFragment->m_pElement != pElement )
00233 {
00234 pElement = pFragment->m_pElement;
00235 pElement->PrePaint( &dc, m_pHover == pElement );
00236 }
00237
00238 pFragment->Paint( &dc, this, nFragment );
00239 }
00240
00241 OnPaintComplete( &dc );
00242
00243 dc.SelectObject( pOldFont );
00244
00245 dc.SetViewportOrg( 0, 0 );
00246
00247 dc.FillSolidRect( &rc, m_pDocument->m_crBackground );
00248 }
00249
00250 BOOL CRichViewCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
00251 {
00252 if ( nHitTest == HTCLIENT && m_pDocument != NULL )
00253 {
00254 CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
00255 CPoint pt;
00256
00257 GetCursorPos( &pt );
00258 ScreenToClient( &pt );
00259
00260 CRichFragment* pFrag = m_bSelecting ? NULL : PointToFrag( pt );
00261
00262 if ( pFrag != NULL && pFrag->m_pElement->m_sLink.GetLength() )
00263 {
00264 SetCursor( m_hcHand );
00265 return TRUE;
00266 }
00267 else if ( m_bSelectable )
00268 {
00269 if ( m_bSelecting || ( pFrag != NULL && pFrag->m_nLength > 0 ) )
00270 {
00271 SetCursor( m_hcText );
00272 return TRUE;
00273 }
00274 }
00275 }
00276
00277 return CWnd::OnSetCursor( pWnd, nHitTest, message );
00278 }
00279
00280 void CRichViewCtrl::OnLButtonDown(UINT nFlags, CPoint point)
00281 {
00282 SetFocus();
00283
00284 if ( m_bSelectable && m_pDocument != NULL )
00285 {
00286 CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
00287
00288 RICHPOSITION pos = PointToPosition( point );
00289
00290 if ( pos.nFragment >= 0 )
00291 {
00292 m_bSelecting = TRUE;
00293 m_pSelStart = pos;
00294 m_pSelEnd = pos;
00295 UpdateSelection();
00296 SetCapture();
00297 }
00298 }
00299
00300 CWnd::OnLButtonDown( nFlags, point );
00301 }
00302
00303 void CRichViewCtrl::OnMouseMove(UINT nFlags, CPoint point)
00304 {
00305 if ( m_pDocument != NULL )
00306 {
00307 CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
00308
00309 if ( m_bSelecting )
00310 {
00311 RICHPOSITION pos = PointToPosition( point );
00312
00313 if ( pos.nFragment >= 0 )
00314 {
00315 m_pSelEnd = ( pos.nFragment >= 0 ) ? pos : m_pSelStart;
00316 UpdateSelection();
00317 }
00318 }
00319 else
00320 {
00321 CRichFragment* pFrag = PointToFrag( point );
00322 CRichElement* pHover = pFrag != NULL ? pFrag->m_pElement : NULL;
00323
00324 if ( pHover != m_pHover )
00325 {
00326 BOOL bPaint = ( pHover != NULL && pHover->m_nType == retLink ) ||
00327 ( m_pHover != NULL && m_pHover->m_nType == retLink );
00328
00329 if ( pHover != NULL && m_pHover == NULL )
00330 SetTimer( 1, 200, NULL );
00331 else if ( pHover == NULL && m_pHover != NULL )
00332 KillTimer( 1 );
00333
00334 m_pHover = pHover;
00335
00336 if ( bPaint ) Invalidate();
00337 }
00338 }
00339 }
00340
00341 CRect rc;
00342 GetClientRect( &rc );
00343
00344 if ( point.y < 0 )
00345 {
00346 PostMessage( WM_VSCROLL, SB_LINEUP );
00347 }
00348 else if ( point.y >= rc.bottom )
00349 {
00350 PostMessage( WM_VSCROLL, SB_LINEDOWN );
00351 }
00352
00353 CWnd::OnMouseMove( nFlags, point );
00354 }
00355
00356 void CRichViewCtrl::OnLButtonUp(UINT nFlags, CPoint point)
00357 {
00358 CWnd::OnLButtonUp( nFlags, point );
00359
00360 if ( m_pDocument != NULL )
00361 {
00362 CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
00363
00364 if ( m_bSelecting &&
00365 ( m_pSelStart.nFragment != m_pSelEnd.nFragment ||
00366 m_pSelStart.nOffset != m_pSelEnd.nOffset ) )
00367 {
00368 CopySelection();
00369 }
00370 else if ( CRichFragment* pFrag = PointToFrag( point ) )
00371 {
00372 ReleaseCapture();
00373
00374 if ( m_bDefaultLink && pFrag->m_pElement->m_sLink.Find( _T("http://") ) == 0 )
00375 {
00376
00377
00378
00379
00380 }
00381
00382 if ( m_pHover == pFrag->m_pElement && m_pHover->m_nType == retLink )
00383 {
00384 KillTimer( 1 );
00385 m_pHover = NULL;
00386 Invalidate();
00387 }
00388
00389 RVN_ELEMENTEVENT pNotify;
00390 pNotify.hdr.hwndFrom = GetSafeHwnd();
00391 pNotify.hdr.idFrom = GetDlgCtrlID();
00392 pNotify.hdr.code = RVN_CLICK;
00393 pNotify.pElement = pFrag->m_pElement;
00394
00395 GetOwner()->SendMessage( WM_NOTIFY, pNotify.hdr.idFrom, (LPARAM)&pNotify );
00396 }
00397 }
00398
00399 if ( m_bSelecting )
00400 {
00401 m_bSelecting = FALSE;
00402 m_pSelStart.nFragment = m_pSelStart.nOffset = 0;
00403 m_pSelEnd = m_pSelStart;
00404
00405 UpdateSelection();
00406 ReleaseCapture();
00407 }
00408 }
00409
00410 void CRichViewCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
00411 {
00412 SCROLLINFO pInfo;
00413
00414 pInfo.cbSize = sizeof(pInfo);
00415 pInfo.fMask = SIF_POS|SIF_RANGE|SIF_PAGE;
00416
00417 GetScrollInfo( SB_VERT, &pInfo );
00418
00419 switch ( nSBCode )
00420 {
00421 case SB_BOTTOM:
00422 pInfo.nPos = pInfo.nMax;
00423 break;
00424 case SB_LINEDOWN:
00425 pInfo.nPos += 16;
00426 break;
00427 case SB_LINEUP:
00428 pInfo.nPos -= 16;
00429 break;
00430 case SB_PAGEDOWN:
00431 pInfo.nPos += pInfo.nPage;
00432 break;
00433 case SB_PAGEUP:
00434 pInfo.nPos -= pInfo.nPage;
00435 break;
00436 case SB_THUMBPOSITION:
00437 case SB_THUMBTRACK:
00438 pInfo.nPos = nPos;
00439 break;
00440 case SB_TOP:
00441 pInfo.nPos = 0;
00442 break;
00443 }
00444
00445 pInfo.fMask = SIF_POS;
00446 pInfo.nPos = max( 0, min( pInfo.nPos, pInfo.nMax - (int)pInfo.nPage ) );
00447 SetScrollInfo( SB_VERT, &pInfo );
00448
00449 OnVScrolled();
00450 Invalidate();
00451 }
00452
00453 void CRichViewCtrl::OnTimer(UINT nIDEvent)
00454 {
00455 CPoint point;
00456 CRect rect;
00457
00458 GetCursorPos( &point );
00459 GetWindowRect( &rect );
00460
00461 if ( rect.PtInRect( point ) ) return;
00462
00463 KillTimer( 1 );
00464
00465 if ( m_pHover != NULL )
00466 {
00467 m_pHover = NULL;
00468 Invalidate();
00469 }
00470 }
00471
00472 BOOL CRichViewCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
00473 {
00474 OnVScroll( SB_THUMBPOSITION, (int)( GetScrollPos( SB_VERT ) - zDelta / WHEEL_DELTA * m_nScrollWheelLines * 16 ), NULL );
00475 return TRUE;
00476 }
00477
00479
00480
00481 void CRichViewCtrl::ClearFragments()
00482 {
00483 for ( int nFragment = 0 ; nFragment < m_pFragments.GetSize() ; nFragment++ )
00484 {
00485 delete (CRichFragment*)m_pFragments.GetAt( nFragment );
00486 }
00487
00488 m_pFragments.RemoveAll();
00489 m_nLength = 0;
00490
00491 if ( m_bSelecting )
00492 {
00493 m_bSelecting = FALSE;
00494 ReleaseCapture();
00495 }
00496
00497 m_pSelStart.nFragment = m_pSelStart.nOffset = 0;
00498 m_pSelEnd.nFragment = m_pSelEnd.nOffset = 0;
00499 m_pSelAbsStart.nFragment = m_pSelAbsStart.nOffset = 0;
00500 m_pSelAbsEnd.nFragment = m_pSelAbsEnd.nOffset = 0;
00501 }
00502
00503 void CRichViewCtrl::Layout(CDC* pDC, CRect* pRect)
00504 {
00505 ASSERT( m_pDocument != NULL );
00506
00507 CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
00508
00509 ClearFragments();
00510
00511 pRect->DeflateRect( m_pDocument->m_szMargin.cx, m_pDocument->m_szMargin.cy );
00512
00513 CPoint pt( pRect->left, pRect->top );
00514
00515 int nLeftPoint = pRect->left;
00516 int nWidth = pRect->Width();
00517 int nLineHeight = 0;
00518 int nAlign = reaLeft;
00519
00520 CRichFragment* pFrag = NULL;
00521 CPtrList pLine;
00522
00523 for ( POSITION pos = m_pDocument->GetIterator() ; pos ; )
00524 {
00525 CRichElement* pElement = m_pDocument->GetNext( pos );
00526
00527 if ( pElement->m_nFlags & retfHidden ) continue;
00528
00529 pElement->PrePaint( pDC, FALSE );
00530
00531 if ( pElement->m_nType == retNewline )
00532 {
00533 WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
00534
00535 int nGap = 0, nIndent = 0;
00536
00537 if ( _stscanf( pElement->m_sText, _T("%lu.%lu"), &nGap, &nIndent ) == 2 )
00538 {
00539 nLeftPoint = pRect->left + nIndent;
00540 nWidth = pRect->right - nIndent;
00541 }
00542
00543 pt.x = nLeftPoint;
00544 pt.y += nGap;
00545
00546 continue;
00547 }
00548 else if ( pElement->m_nType == retAlign )
00549 {
00550 WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
00551
00552 if ( pElement->m_sText.CompareNoCase( _T("center") ) == 0 )
00553 {
00554 nAlign = reaCenter;
00555 }
00556 else if ( pElement->m_sText.CompareNoCase( _T("right") ) == 0 )
00557 {
00558 nAlign = reaRight;
00559 }
00560 else
00561 {
00562 nAlign = reaLeft;
00563 }
00564
00565 continue;
00566 }
00567 else if ( pElement->m_nType == retGap || pElement->m_nType < retText )
00568 {
00569 pFrag = new CRichFragment( pElement, &pt );
00570 m_pFragments.Add( pFrag );
00571
00572 if ( pt.x + pFrag->m_sz.cx > nWidth )
00573 {
00574 WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
00575 pFrag->m_pt = pt;
00576 }
00577
00578 pt.x += pFrag->m_sz.cx;
00579
00580 if ( pElement->m_nType != retGap )
00581 {
00582 nLineHeight = max( nLineHeight, int(pFrag->m_sz.cy) );
00583 pLine.AddTail( pFrag );
00584 }
00585
00586 continue;
00587 }
00588
00589 LPTSTR pszText = (LPTSTR)(LPCTSTR)pElement->m_sText;
00590 LPCTSTR pszWord = pszText;
00591 LPCTSTR pszLast = NULL;
00592
00593 int nWordStart = 0;
00594 int nSpace = pDC->GetTextExtent( _T(" ") ).cx;
00595
00596 pFrag = NULL;
00597
00598 for ( int nChar = 0 ; nChar <= pElement->m_sText.GetLength() ; nChar++, pszText++ )
00599 {
00600 if ( *pszText != ' ' && *pszText != '\t' && *pszText != 0 ) continue;
00601
00602 if ( nChar > nWordStart || *pszText == 0 )
00603 {
00604 TCHAR cSave = *pszText;
00605 *pszText = 0;
00606
00607 CSize szWord = pDC->GetTextExtent( pszWord );
00608
00609 if ( pFrag != NULL )
00610 {
00611 CSize szLast = pDC->GetTextExtent( pszLast );
00612
00613 if ( pFrag->m_pt.x + szLast.cx <= nWidth )
00614 {
00615 pt.x -= pFrag->m_sz.cx;
00616 pFrag->Add( nChar - pFrag->m_nOffset, &szLast );
00617 pt.x += pFrag->m_sz.cx;
00618 nWordStart = -1;
00619 }
00620 }
00621
00622 if ( nChar == nWordStart && *pszText == 0 ) break;
00623
00624 if ( nWordStart >= 0 )
00625 {
00626 if ( pt.x + szWord.cx + ( pFrag ? nSpace : 0 ) > nWidth )
00627 {
00628 WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
00629 }
00630 else if ( pFrag != NULL ) pt.x += nSpace;
00631
00632 pFrag = new CRichFragment( pElement, nWordStart, nChar - nWordStart, &pt, &szWord );
00633 pszLast = pszWord;
00634
00635 pt.x += pFrag->m_sz.cx;
00636 nLineHeight = max( nLineHeight, int(pFrag->m_sz.cy) );
00637
00638 m_pFragments.Add( pFrag );
00639 pLine.AddTail( pFrag );
00640 }
00641
00642 *pszText = cSave;
00643 }
00644
00645 if ( pFrag != NULL )
00646 {
00647 nWordStart = nChar + 1;
00648 pszWord = pszText + 1;
00649 }
00650 }
00651 }
00652
00653 WrapLineHelper( pLine, pt, nLineHeight, nWidth, nAlign );
00654
00655 pRect->InflateRect( m_pDocument->m_szMargin.cx, m_pDocument->m_szMargin.cy );
00656
00657 m_nLength = pt.y - pRect->top + m_pDocument->m_szMargin.cy;
00658
00659 SCROLLINFO pInfo;
00660
00661 pInfo.cbSize = sizeof(pInfo);
00662 pInfo.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
00663
00664 GetScrollInfo( SB_VERT, &pInfo, pInfo.fMask );
00665
00666 if ( m_bFollowBottom && pInfo.nPos >= pInfo.nMax - (int)pInfo.nPage - 1 )
00667 pInfo.nPos = m_nLength;
00668
00669 pInfo.fMask = SIF_ALL & ~SIF_TRACKPOS;
00670 pInfo.nMin = 0;
00671 pInfo.nMax = m_nLength - 1;
00672 pInfo.nPage = ( pRect->bottom == -1 ) ? m_nLength : pRect->Height();
00673 pInfo.nPos = min( pInfo.nPos, max( 0, pInfo.nMax - (int)pInfo.nPage ) );
00674
00675 SetScrollInfo( SB_VERT, &pInfo, TRUE );
00676
00677 m_nCookie = m_pDocument->m_nCookie;
00678 OnLayoutComplete();
00679 }
00680
00681 void CRichViewCtrl::WrapLineHelper(CPtrList& pLine, CPoint& pt, int& nLineHeight, int nWidth, int nAlign)
00682 {
00683 if ( pLine.GetCount() == 0 ) return;
00684
00685 int nLeft = ((CRichFragment*)pLine.GetHead())->m_pt.x;
00686 int nHorz = 0;
00687
00688 if ( nAlign == reaCenter )
00689 {
00690 nHorz = nWidth / 2 - ( pt.x - nLeft ) / 2;
00691 }
00692 else if ( nAlign == reaRight )
00693 {
00694 nHorz = nWidth - pt.x;
00695 }
00696
00697 for ( POSITION posAlign = pLine.GetHeadPosition() ; posAlign ; )
00698 {
00699 CRichFragment* pAlign = (CRichFragment*)pLine.GetNext( posAlign );
00700
00701 if ( pAlign->m_pElement->m_nFlags & retfMiddle )
00702 {
00703 pAlign->m_pt.y += ( nLineHeight / 2 - pAlign->m_sz.cy / 2 );
00704 }
00705 else
00706 {
00707 pAlign->m_pt.y += ( nLineHeight - pAlign->m_sz.cy );
00708 }
00709
00710 pAlign->m_pt.x += nHorz;
00711 }
00712
00713 pt.x = nLeft;
00714 pt.y += nLineHeight;
00715
00716 pLine.RemoveAll();
00717 nLineHeight = 0;
00718 }
00719
00721
00722
00723 CRichFragment* CRichViewCtrl::PointToFrag(CPoint& pt)
00724 {
00725 if ( m_pDocument == NULL || m_pDocument->m_nCookie != m_nCookie ) return NULL;
00726
00727 pt.y += GetScrollPos( SB_VERT );
00728
00729 for ( int nFragment = m_pFragments.GetSize() - 1 ; nFragment >= 0 ; nFragment-- )
00730 {
00731 CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
00732
00733 if ( pt.x >= pFragment->m_pt.x && pt.y >= pFragment->m_pt.y &&
00734 pt.x < pFragment->m_pt.x + pFragment->m_sz.cx &&
00735 pt.y < pFragment->m_pt.y + pFragment->m_sz.cy )
00736 {
00737 pt.y -= GetScrollPos( SB_VERT );
00738 return pFragment;
00739 }
00740 }
00741
00742 pt.y -= GetScrollPos( SB_VERT );
00743
00744 return NULL;
00745 }
00746
00747 RICHPOSITION CRichViewCtrl::PointToPosition(CPoint& pt)
00748 {
00749 RICHPOSITION pos = { -1, 0 };
00750
00751 if ( m_pDocument == NULL || m_pDocument->m_nCookie != m_nCookie ) return pos;
00752
00753 pt.y += GetScrollPos( SB_VERT );
00754
00755 for ( int nFragment = 0 ; nFragment < m_pFragments.GetSize() ; nFragment++ )
00756 {
00757 CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
00758
00759 if ( pt.x >= pFragment->m_pt.x && pt.y >= pFragment->m_pt.y &&
00760 pt.x < pFragment->m_pt.x + pFragment->m_sz.cx &&
00761 pt.y < pFragment->m_pt.y + pFragment->m_sz.cy )
00762 {
00763 pos.nFragment = nFragment;
00764
00765 if ( pFragment->m_nLength > 0 )
00766 {
00767 CClientDC dc( this );
00768 CFont* pOld = dc.GetCurrentFont();
00769 pFragment->m_pElement->PrePaint( &dc, FALSE );
00770
00771 LPCTSTR pszText = pFragment->m_pElement->m_sText;
00772 pszText += pFragment->m_nOffset;
00773 int nX = pt.x - pFragment->m_pt.x;
00774
00775 for ( pos.nOffset = 0 ; pos.nOffset < pFragment->m_nLength ; pszText ++ )
00776 {
00777 int nWidth = dc.GetTextExtent( pszText, 1 ).cx;
00778 if ( nX < ( nWidth >> 1 ) ) break;
00779 pos.nOffset++;
00780 if ( nX < nWidth ) break;
00781 nX -= nWidth;
00782 }
00783
00784 dc.SelectObject( pOld );
00785 }
00786
00787 break;
00788 }
00789 }
00790
00791 pt.y -= GetScrollPos( SB_VERT );
00792
00793 return pos;
00794 }
00795
00796 CPoint CRichViewCtrl::PositionToPoint(RICHPOSITION& pos)
00797 {
00798 CPoint pt( 0, - GetScrollPos( SB_VERT ) );
00799
00800 if ( m_pDocument == NULL || m_pDocument->m_nCookie != m_nCookie ) return pt;
00801 if ( pos.nFragment < 0 || m_pFragments.GetSize() == 0 ) return pt;
00802
00803 BOOL bOverload = pos.nFragment >= m_pFragments.GetSize();
00804
00805 CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt(
00806 bOverload ? m_pFragments.GetSize() - 1 : pos.nFragment );
00807
00808 pt.x = pFragment->m_pt.x;
00809 pt.y += pFragment->m_pt.y;
00810
00811 if ( bOverload )
00812 {
00813 pt.x += pFragment->m_sz.cx;
00814 }
00815 else if ( pos.nOffset > 0 )
00816 {
00817 if ( pos.nOffset < pFragment->m_nLength )
00818 {
00819 CClientDC dc( this );
00820 CFont* pOld = dc.GetCurrentFont();
00821 pFragment->m_pElement->PrePaint( &dc, FALSE );
00822 LPCTSTR pszText = pFragment->m_pElement->m_sText;
00823 pszText += pFragment->m_nOffset;
00824 pt.x += dc.GetTextExtent( pszText, pos.nOffset ).cx;
00825 dc.SelectObject( pOld );
00826 }
00827 else
00828 {
00829 pt.x += pFragment->m_sz.cx;
00830 }
00831 }
00832
00833 return pt;
00834 }
00835
00837
00838
00839 void CRichViewCtrl::UpdateSelection()
00840 {
00841 if ( m_pSelStart.nFragment < m_pSelEnd.nFragment || ( m_pSelStart.nFragment == m_pSelEnd.nFragment && m_pSelStart.nOffset <= m_pSelEnd.nOffset ) )
00842 {
00843 if ( m_pSelAbsStart.nFragment != m_pSelStart.nFragment ||
00844 m_pSelAbsStart.nOffset != m_pSelStart.nOffset ||
00845 m_pSelAbsEnd.nFragment != m_pSelEnd.nFragment ||
00846 m_pSelAbsEnd.nOffset != m_pSelEnd.nOffset )
00847 {
00848 m_pSelAbsStart = m_pSelStart;
00849 m_pSelAbsEnd = m_pSelEnd;
00850 Invalidate();
00851 }
00852 }
00853 else
00854 {
00855 if ( m_pSelAbsStart.nFragment != m_pSelEnd.nFragment ||
00856 m_pSelAbsStart.nOffset != m_pSelEnd.nOffset ||
00857 m_pSelAbsEnd.nFragment != m_pSelStart.nFragment ||
00858 m_pSelAbsEnd.nOffset != m_pSelStart.nOffset )
00859 {
00860 m_pSelAbsStart = m_pSelEnd;
00861 m_pSelAbsEnd = m_pSelStart;
00862 Invalidate();
00863 }
00864 }
00865 }
00866
00867 void CRichViewCtrl::CopySelection()
00868 {
00869 CString str;
00870
00871 for ( int nFragment = m_pSelAbsStart.nFragment ; nFragment <= m_pSelAbsEnd.nFragment ; nFragment++ )
00872 {
00873 CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
00874
00875 if ( pFragment->m_nLength == 0 )
00876 {
00877 if ( nFragment == m_pSelAbsEnd.nFragment ) break;
00878
00879 if ( pFragment->m_pElement->m_nType == retEmoticon )
00880 {
00881 int nToken = 0;
00882 _stscanf( pFragment->m_pElement->m_sText, _T("%i"), &nToken );
00883 if ( LPCTSTR pszToken = Emoticons.GetText( nToken ) )
00884 str += pszToken;
00885 }
00886 else if ( pFragment->m_pElement->m_nType < retText )
00887 {
00888 str += ' ';
00889 }
00890 }
00891 else
00892 {
00893 int nCharStart = 0, nCharEnd = pFragment->m_nLength;
00894
00895 if ( m_pSelAbsStart.nFragment == nFragment )
00896 {
00897 nCharStart = m_pSelAbsStart.nOffset;
00898 }
00899
00900 if ( m_pSelAbsEnd.nFragment == nFragment )
00901 {
00902 nCharEnd = m_pSelAbsEnd.nOffset;
00903 }
00904
00905 if ( nCharEnd > nCharStart )
00906 {
00907 str += pFragment->m_pElement->m_sText.Mid(
00908 pFragment->m_nOffset + nCharStart,
00909 nCharEnd - nCharStart );
00910 }
00911 }
00912
00913 if ( nFragment < m_pSelAbsEnd.nFragment )
00914 {
00915 CRichFragment* pNextFrag = (CRichFragment*)m_pFragments.GetAt( nFragment + 1 );
00916
00917 if ( pFragment->m_pElement != pNextFrag->m_pElement )
00918 {
00919 POSITION pos = m_pDocument->Find( pFragment->m_pElement );
00920
00921 while ( pos )
00922 {
00923 CRichElement* pCopy = m_pDocument->GetNext( pos );
00924 if ( pCopy == pNextFrag->m_pElement ) break;
00925 if ( pCopy->m_nType == retNewline ) str += _T("\r\n");
00926 }
00927 }
00928 }
00929 }
00930
00931 if ( str.GetLength() && AfxGetMainWnd()->OpenClipboard() )
00932 {
00933 USES_CONVERSION;
00934 EmptyClipboard();
00935
00936 if ( theApp.m_bNT )
00937 {
00938 LPCWSTR pszWide = T2CW( (LPCTSTR)str );
00939 HANDLE hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, ( wcslen(pszWide) + 1 ) * sizeof(WCHAR) );
00940 LPVOID pMem = GlobalLock( hMem );
00941 CopyMemory( pMem, pszWide, ( wcslen(pszWide) + 1 ) * sizeof(WCHAR) );
00942 GlobalUnlock( hMem );
00943 SetClipboardData( CF_UNICODETEXT, hMem );
00944 }
00945 else
00946 {
00947 LPCSTR pszASCII = T2CA( (LPCTSTR)str );
00948 HANDLE hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, strlen(pszASCII) + 1 );
00949 LPVOID pMem = GlobalLock( hMem );
00950 CopyMemory( pMem, pszASCII, strlen(pszASCII) + 1 );
00951 GlobalUnlock( hMem );
00952 SetClipboardData( CF_TEXT, hMem );
00953 }
00954
00955 CloseClipboard();
00956 }
00957 }