📄 richviewctrl.cpp
字号:
//
// 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 + -