⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 richviewctrl.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// RichViewCtrl.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "RichViewCtrl.h"
#include "RichDocument.h"
#include "RichElement.h"
#include "RichFragment.h"

#include "Emoticons.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

BEGIN_MESSAGE_MAP(CRichViewCtrl, CWnd)
	//{{AFX_MSG_MAP(CRichViewCtrl)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_SETCURSOR()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_VSCROLL()
	ON_WM_LBUTTONDOWN()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CRichViewCtrl construction

CRichViewCtrl::CRichViewCtrl()
{
	m_bSelectable	= FALSE;
	m_bFollowBottom	= FALSE;
	m_bDefaultLink	= TRUE;

	m_pDocument		= NULL;
	m_nLength		= 0;
	m_pHover		= NULL;
	m_bSelecting	= FALSE;
}

CRichViewCtrl::~CRichViewCtrl()
{
	ClearFragments();
}

/////////////////////////////////////////////////////////////////////////////
// CRichViewCtrl operations

BOOL CRichViewCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) 
{
	dwStyle |= WS_CHILD|WS_VSCROLL;
	return CWnd::Create( NULL, NULL, dwStyle, rect, pParentWnd, nID, NULL );
}

void CRichViewCtrl::SetSelectable(BOOL bSelectable)
{
	m_bSelectable = bSelectable;
}

void CRichViewCtrl::SetFollowBottom(BOOL bFollowBottom)
{
	m_bFollowBottom = bFollowBottom;
}

void CRichViewCtrl::SetDefaultLink(BOOL bDefaultLink)
{
	m_bDefaultLink = bDefaultLink;
}

void CRichViewCtrl::SetDocument(CRichDocument* pDocument)
{
	m_pDocument	= pDocument;
	m_nCookie	= 0xFFFFFFFF;
	m_pHover	= NULL;	
	
	KillTimer( 1 );
	ClearFragments();
	Invalidate();
}

BOOL CRichViewCtrl::IsModified() const
{
	return ( m_pDocument != NULL && m_pDocument->m_nCookie != m_nCookie );
}

void CRichViewCtrl::InvalidateIfModified()
{
	if ( m_pDocument != NULL && m_pDocument->m_nCookie != m_nCookie ) Invalidate();
}

int CRichViewCtrl::FullHeightMove(int nX, int nY, int nWidth, BOOL bShow)
{
	if ( m_pDocument == NULL ) return 0;
	
	CRect rc( 0, 0, nWidth, -1 );
	
	CClientDC dc( this );
	CFont* pOldFont = (CFont*)dc.SelectObject( &theApp.m_gdiFont );
	Layout( &dc, &rc );
	dc.SelectObject( pOldFont );
	
	SetWindowPos( NULL, nX, nY, nWidth, m_nLength, SWP_NOZORDER | ( bShow ? SWP_SHOWWINDOW : 0 ) );
	
	return m_nLength;
}

BOOL CRichViewCtrl::GetElementRect(CRichElement* pElement, RECT* prc)
{
	for ( int nFragment = 0 ; nFragment < m_pFragments.GetCount() ; nFragment ++ )
	{
		CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
		
		if ( pFragment->m_pElement == pElement )
		{
			prc->left	= pFragment->m_pt.x;
			prc->top	= pFragment->m_pt.y;
			prc->right	= prc->left + pFragment->m_sz.cx;
			prc->bottom	= prc->top + pFragment->m_sz.cy;
			
			return TRUE;
		}
	}
	
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// CRichViewCtrl message handlers

int CRichViewCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if ( CWnd::OnCreate( lpCreateStruct ) == -1 ) return -1;
	
	m_hcHand = theApp.LoadCursor( IDC_HAND );
	m_hcText = theApp.LoadStandardCursor( IDC_IBEAM );
	
	SetScrollRange( SB_VERT, 0, 0 );
	
	return 0;
}

void CRichViewCtrl::OnDestroy() 
{
	CWnd::OnDestroy();
}

void CRichViewCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize( nType, cx, cy );
	m_nCookie = 0xFFFFFFFF;
	Invalidate();
}

BOOL CRichViewCtrl::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

void CRichViewCtrl::OnPaint() 
{
	CPaintDC dc( this );
	CRect rc;
	
	GetClientRect( &rc );
	
	if ( m_pDocument == NULL )
	{
		dc.FillSolidRect( &rc, GetSysColor( COLOR_WINDOW ) );
		return;
	}
	
	CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
	
	CFont* pOldFont = (CFont*)dc.SelectObject( &theApp.m_gdiFont );
	
	if ( m_pDocument->m_nCookie != m_nCookie || m_pBrush.m_hObject == NULL )
	{
		Layout( &dc, &rc );
		
		if ( m_pBrush.m_hObject != NULL ) m_pBrush.DeleteObject();
		m_pBrush.CreateSolidBrush( m_pDocument->m_crBackground );
	}
	
	dc.SetBkMode( OPAQUE );
	dc.SetBkColor( m_pDocument->m_crBackground );
	dc.SetViewportOrg( 0, -GetScrollPos( SB_VERT ) );
	
	OnPaintBegin( &dc );
	
	CRichElement* pElement = NULL;
	
	for ( int nFragment = 0 ; nFragment < m_pFragments.GetSize() ; nFragment++ )
	{
		CRichFragment* pFragment = (CRichFragment*)m_pFragments.GetAt( nFragment );
		
		if ( pFragment->m_pElement != pElement )
		{
			pElement = pFragment->m_pElement;
			pElement->PrePaint( &dc, m_pHover == pElement );
		}
		
		pFragment->Paint( &dc, this, nFragment );
	}
	
	OnPaintComplete( &dc );
	
	dc.SelectObject( pOldFont );
	
	dc.SetViewportOrg( 0, 0 );
	
	dc.FillSolidRect( &rc, m_pDocument->m_crBackground );
}

BOOL CRichViewCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	if ( nHitTest == HTCLIENT && m_pDocument != NULL )
	{
		CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
		CPoint pt;
		
		GetCursorPos( &pt );
		ScreenToClient( &pt );
		
		CRichFragment* pFrag = m_bSelecting ? NULL : PointToFrag( pt );

		if ( pFrag != NULL && pFrag->m_pElement->m_sLink.GetLength() )
		{
			SetCursor( m_hcHand );
			return TRUE;
		}
		else if ( m_bSelectable )
		{
			if ( m_bSelecting || ( pFrag != NULL && pFrag->m_nLength > 0 ) )
			{
				SetCursor( m_hcText );
				return TRUE;
			}
		}
	}
	
	return CWnd::OnSetCursor( pWnd, nHitTest, message );
}

void CRichViewCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	SetFocus();
	
	if ( m_bSelectable && m_pDocument != NULL )
	{
		CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
		
		RICHPOSITION pos = PointToPosition( point );
		
		if ( pos.nFragment >= 0 )
		{
			m_bSelecting	= TRUE;
			m_pSelStart		= pos;
			m_pSelEnd		= pos;
			UpdateSelection();
			SetCapture();
		}
	}
	
	CWnd::OnLButtonDown( nFlags, point );
}

void CRichViewCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	if ( m_pDocument != NULL )
	{
		CSingleLock pLock( &m_pDocument->m_pSection, TRUE );
		
		if ( m_bSelecting )
		{
			RICHPOSITION pos = PointToPosition( point );
			
			if ( pos.nFragment >= 0 )
			{
				m_pSelEnd = ( pos.nFragment >= 0 ) ? pos : m_pSelStart;
				UpdateSelection();
			}
		}
		else
		{
			CRichFragment* pFrag = PointToFrag( point );
			CRichElement* pHover = pFrag != NULL ? pFrag->m_pElement : NULL;
			
			if ( pHover != m_pHover )
			{
				BOOL bPaint =	( pHover != NULL && pHover->m_nType == retLink ) ||
								( m_pHover != NULL && m_pHover->m_nType == retLink );
				
				if ( pHover != NULL && m_pHover == NULL )
					SetTimer( 1, 200, NULL );
				else if ( pHover == NULL && m_pHover != NULL )
					KillTimer( 1 );
				
				m_pHover = pHover;
				
				if ( bPaint ) Invalidate();
			}
		}
	}
	
	CRect rc;
	GetClientRect( &rc );

	if ( point.y < 0 )
	{
		PostMessage( WM_VSCROLL, SB_LINEUP );
	}
	else if ( point.y >= rc.bottom )
	{
		PostMessage( WM_VSCROLL, SB_LINEDOWN );
	}

	CWnd::OnMouseMove( nFlags, point );
}

void CRichViewCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	CWnd::OnLButtonUp( nFlags, point );
	
	if ( m_pDocument != NULL )
	{
		CSingleLock pLock( &m_pDocument->m_pSection, TRUE );

		if ( m_bSelecting &&
				( m_pSelStart.nFragment != m_pSelEnd.nFragment ||
				  m_pSelStart.nOffset != m_pSelEnd.nOffset ) )
		{
			CopySelection();
		}
		else if ( CRichFragment* pFrag = PointToFrag( point ) )
		{
			ReleaseCapture();

			if ( m_bDefaultLink && pFrag->m_pElement->m_sLink.Find( _T("http://") ) == 0 )
			{
				ShellExecute( GetSafeHwnd(), _T("open"), pFrag->m_pElement->m_sLink,
					NULL, NULL, SW_SHOWNORMAL );
			}
			
			if ( m_pHover == pFrag->m_pElement && m_pHover->m_nType == retLink )
			{
				KillTimer( 1 );
				m_pHover = NULL;
				Invalidate();
			}
			
			RVN_ELEMENTEVENT pNotify;
			pNotify.hdr.hwndFrom	= GetSafeHwnd();
			pNotify.hdr.idFrom		= GetDlgCtrlID();
			pNotify.hdr.code		= RVN_CLICK;
			pNotify.pElement		= pFrag->m_pElement;
			
			GetOwner()->SendMessage( WM_NOTIFY, pNotify.hdr.idFrom, (LPARAM)&pNotify );
		}
	}
	
	if ( m_bSelecting )
	{
		m_bSelecting = FALSE;
		m_pSelStart.nFragment = m_pSelStart.nOffset = 0;
		m_pSelEnd = m_pSelStart;
		
		UpdateSelection();
		ReleaseCapture();
	}
}

void CRichViewCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	SCROLLINFO pInfo;
	
	pInfo.cbSize	= sizeof(pInfo);
	pInfo.fMask		= SIF_POS|SIF_RANGE|SIF_PAGE;
	
	GetScrollInfo( SB_VERT, &pInfo );
	
	switch ( nSBCode )
	{
	case SB_BOTTOM:
		pInfo.nPos = pInfo.nMax;
		break;
	case SB_LINEDOWN:
		pInfo.nPos += 16;
		break;
	case SB_LINEUP:
		pInfo.nPos -= 16;
		break;
	case SB_PAGEDOWN:
		pInfo.nPos += pInfo.nPage;
		break;
	case SB_PAGEUP:
		pInfo.nPos -= pInfo.nPage;
		break;
	case SB_THUMBPOSITION:
	case SB_THUMBTRACK:
		pInfo.nPos = nPos;
		break;
	case SB_TOP:
		pInfo.nPos = 0;
		break;
	}
	
	pInfo.fMask	= SIF_POS;
	pInfo.nPos	= max( 0, min( pInfo.nPos, pInfo.nMax - (int)pInfo.nPage ) );
	SetScrollInfo( SB_VERT, &pInfo );
	
	OnVScrolled();
	Invalidate();
}

void CRichViewCtrl::OnTimer(UINT nIDEvent)
{
	CPoint point;
	CRect rect;
	
	GetCursorPos( &point );
	GetWindowRect( &rect );
	
	if ( rect.PtInRect( point ) ) return;
	
	KillTimer( 1 );
	
	if ( m_pHover != NULL )
	{
		m_pHover = NULL;
		Invalidate();
	}
}

/////////////////////////////////////////////////////////////////////////////
// CRichViewCtrl layout engine

void CRichViewCtrl::ClearFragments()
{
	for ( int nFragment = 0 ; nFragment < m_pFragments.GetSize() ; nFragment++ )
	{
		delete (CRichFragment*)m_pFragments.GetAt( nFragment );
	}
	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -