Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

RichViewCtrl.cpp

Go to the documentation of this file.
00001 //
00002 // RichViewCtrl.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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         //{{AFX_MSG_MAP(CRichViewCtrl)
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         //}}AFX_MSG_MAP
00052 END_MESSAGE_MAP()
00053 
00054 
00056 // CRichViewCtrl construction
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         // Try to get the number of lines to scroll when the mouse wheel is rotated
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 // CRichViewCtrl operations
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 // CRichViewCtrl message handlers
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                                 // CShareazaApp::InternalURI intercepts it
00377 
00378                                 //ShellExecute( GetSafeHwnd(), _T("open"), pFrag->m_pElement->m_sLink,
00379                                 //      NULL, NULL, SW_SHOWNORMAL );
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 // CRichViewCtrl layout engine
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 // CRichViewCtrl coordinate mapping
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 // CRichViewCtrl selection helpers
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 }

Generated on Thu Dec 15 10:39:47 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2