📄 ctrlsearchdetailpanel.cpp
字号:
CRect rcThumb( rcClient.left + 8, rcClient.top + 8,
rcClient.left + 8 + nThumbSize, rcClient.top + 8 + nThumbSize );
rcWork.CopyRect( &rcThumb );
pDC->Draw3dRect( &rcWork, CoolInterface.m_crMargin, CoolInterface.m_crMargin );
rcWork.DeflateRect( 1, 1 );
m_nThumbSize = rcWork.Width();
DrawThumbnail( pDC, rcWork );
pDC->ExcludeClipRect( &rcThumb );
rcWork.SetRect( rcThumb.right + 8, rcThumb.top, rcClient.right - 8, rcClient.bottom );
}
void CSearchDetailPanel::DrawThumbnail(CDC* pDC, CRect& rcThumb)
{
m_rcThumb = rcThumb;
if ( m_bmThumb.m_hObject != NULL &&
m_szThumb.cx != m_nThumbSize && m_szThumb.cy != m_nThumbSize )
{
CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
if ( m_pMatches->FileToItem( m_pFile ) < 0xFFFFFFFF )
{
if ( m_pFile->m_pPreview != NULL && m_pFile->m_nPreview > 0 )
{
CImageServices pServices;
CImageFile pImage( &pServices );
if ( pImage.LoadFromMemory( _T(".jpg"), (LPCVOID)m_pFile->m_pPreview, m_pFile->m_nPreview, FALSE, TRUE ) )
{
pLock.Unlock();
OnPreviewLoaded( &m_pSHA1, &pImage );
}
}
}
}
if ( m_bmThumb.m_hObject &&
( m_szThumb.cx == m_nThumbSize || m_szThumb.cy == m_nThumbSize ) )
{
CDC dcMem;
dcMem.CreateCompatibleDC( pDC );
CBitmap* pOld = (CBitmap*)dcMem.SelectObject( &m_bmThumb );
CPoint ptImage( ( rcThumb.left + rcThumb.right ) / 2 - m_szThumb.cx / 2,
( rcThumb.top + rcThumb.bottom ) / 2 - m_szThumb.cy / 2 );
pDC->BitBlt( ptImage.x, ptImage.y, m_szThumb.cx, m_szThumb.cy,
&dcMem, 0, 0, SRCCOPY );
pDC->ExcludeClipRect( ptImage.x, ptImage.y,
ptImage.x + m_szThumb.cx, ptImage.y + m_szThumb.cy );
dcMem.SelectObject( pOld );
pDC->FillSolidRect( &rcThumb, m_crLight );
}
else
{
CPoint pt( ( rcThumb.left + rcThumb.right ) / 2 - 24,
( rcThumb.top + rcThumb.bottom ) / 2 - 24 );
if ( m_bCanPreview )
{
CString str;
LoadString( str, m_bIsPreviewing ? IDS_SEARCH_DETAILS_PREVIEWING : IDS_SEARCH_DETAILS_PREVIEW );
pDC->SetBkColor( m_crLight );
pDC->SetTextColor( m_bIsPreviewing ? RGB( 255, 0, 0 ) : RGB( 0, 0, 255 ) );
pDC->SelectObject( m_bIsPreviewing ? &theApp.m_gdiFontBold : &theApp.m_gdiFontLine );
CSize sz = pDC->GetTextExtent( str );
if ( sz.cx + 4 < rcThumb.Width() )
{
pt.y -= sz.cy / 2;
CPoint ptText(
( rcThumb.left + rcThumb.right ) / 2 - sz.cx / 2,
pt.y + 50 );
DrawText( pDC, ptText.x, ptText.y, str );
}
}
if ( m_nIcon48 >= 0 )
{
ShellIcons.Draw( pDC, m_nIcon48, 48, pt.x, pt.y, m_crLight );
}
else if ( m_nIcon32 >= 0 )
{
pt.x += 8; pt.y += 8;
ShellIcons.Draw( pDC, m_nIcon32, 32, pt.x, pt.y, m_crLight );
}
pDC->FillSolidRect( &rcThumb, m_crLight );
}
}
BOOL CSearchDetailPanel::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
CPoint point;
GetCursorPos( &point );
ScreenToClient( &point );
if ( m_bValid && m_bCanPreview && ! m_bIsPreviewing && m_rcThumb.PtInRect( point ) )
{
SetCursor( AfxGetApp()->LoadCursor( IDC_HAND ) );
return TRUE;
}
point.y += GetScrollPos( SB_VERT );
if ( m_bValid && m_pReviews.GetCount() > 0 && m_rcStatus.PtInRect( point ) )
{
SetCursor( AfxGetApp()->LoadCursor( IDC_HAND ) );
return TRUE;
}
if ( m_bValid && m_pMetadata.HitTest( point, TRUE ) != NULL )
{
SetCursor( AfxGetApp()->LoadCursor( IDC_HAND ) );
return TRUE;
}
return CWnd::OnSetCursor( pWnd, nHitTest, message );
}
void CSearchDetailPanel::OnLButtonUp(UINT nFlags, CPoint point)
{
if ( m_bValid && m_bCanPreview && ! m_bIsPreviewing && m_rcThumb.PtInRect( point ) )
{
RequestPreview();
}
point.y += GetScrollPos( SB_VERT );
if ( m_bValid && m_pReviews.GetCount() > 0 && m_rcStatus.PtInRect( point ) )
{
int nHeight = 54 + m_pMetadata.m_nHeight;
SetScrollPos( SB_VERT, nHeight );
OnVScroll( SB_THUMBPOSITION, nHeight, NULL );
Invalidate();
}
m_pMetadata.OnClick( point );
CWnd::OnLButtonUp( nFlags, point );
}
/////////////////////////////////////////////////////////////////////////////
// CSearchDetailPanel::Review construction
CSearchDetailPanel::Review::Review(GGUID* pGUID, IN_ADDR* pAddress, LPCTSTR pszNick, int nRating, LPCTSTR pszComments)
{
m_pGUID = *pGUID;
m_nRating = nRating;
if ( pszNick != NULL && *pszNick != 0 )
{
m_sNick.Format( _T("%s (%s)"), pszNick,
(LPCTSTR)CString( inet_ntoa( *pAddress ) ) );
}
else
{
m_sNick = inet_ntoa( *pAddress );
}
if ( pszComments != NULL )
{
m_pComments.m_szMargin = CSize( 6, 0 );
Emoticons.FormatText( &m_pComments, pszComments, TRUE );
}
}
CSearchDetailPanel::Review::~Review()
{
if ( m_wndComments.m_hWnd != NULL ) m_wndComments.DestroyWindow();
}
void CSearchDetailPanel::Review::Layout(CSearchDetailPanel* pParent, CRect* pRect)
{
pRect->bottom += 22;
if ( m_pComments.GetCount() )
{
if ( m_wndComments.m_hWnd == NULL )
{
m_wndComments.Create( WS_CHILD, *pRect, pParent, IDC_REVIEW_VIEW );
m_wndComments.SetSelectable( TRUE );
m_wndComments.SetDocument( &m_pComments );
}
pRect->bottom += m_wndComments.FullHeightMove( pRect->left, pRect->bottom, pRect->Width(), TRUE );
pRect->bottom += 4;
}
else
{
pRect->bottom += 2;
}
m_rc.CopyRect( pRect );
}
void CSearchDetailPanel::Review::Reposition(int nScroll)
{
if ( m_wndComments.m_hWnd != NULL )
{
m_wndComments.SetWindowPos( NULL, m_rc.left, m_rc.top - nScroll + 22, 0, 0,
SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE );
}
}
void CSearchDetailPanel::Review::Paint(CDC* pDC, int nScroll)
{
CRect rc( &m_rc );
rc.OffsetRect( 0, -nScroll );
pDC->FillSolidRect( rc.left, rc.top, rc.Width(), 1, CoolInterface.m_crMargin );
pDC->ExcludeClipRect( rc.left, rc.top, rc.right, rc.top + 1 );
rc.top += 4;
CString strFormat, strCaption;
LoadString( strFormat, m_pComments.GetCount() > 0 ? IDS_SEARCH_DETAILS_WRITES : IDS_SEARCH_DETAILS_RATES );
strCaption.Format( strFormat, (LPCTSTR)m_sNick );
pDC->SetBkColor( CoolInterface.m_crWindow );
DrawText( pDC, rc.left, rc.top, strCaption );
CPoint ptStar( rc.right - 3, rc.top );
if ( m_nRating > 1 )
{
for ( int nRating = m_nRating - 1 ; nRating ; nRating-- )
{
ptStar.x -= 16;
ShellIcons.Draw( pDC, SHI_STAR, 16, ptStar.x, ptStar.y, CoolInterface.m_crWindow );
}
}
else if ( m_nRating == 1 )
{
ptStar.x -= 16;
ShellIcons.Draw( pDC, SHI_FAKE, 16, ptStar.x, ptStar.y, CoolInterface.m_crWindow );
}
rc.top += 20;
}
void CSearchDetailPanel::OnClickReview(RVN_ELEMENTEVENT* pNotify, LRESULT *pResult)
{
if ( CRichElement* pElement = pNotify->pElement )
{
theApp.InternalURI( pElement->m_sLink );
}
}
/////////////////////////////////////////////////////////////////////////////
// CSearchDetailPanel previewing functionality
BOOL CSearchDetailPanel::RequestPreview()
{
CSingleLock pLock( &m_pSection, TRUE );
if ( ! m_bValid || ! m_bCanPreview || m_pPreviewURLs.IsEmpty() ) return FALSE;
if ( m_hThread == NULL )
{
m_bThread = TRUE;
CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_IDLE );
m_hThread = pThread->m_hThread;
}
m_bRunPreview = TRUE;
pLock.Unlock();
m_pWakeup.SetEvent();
return TRUE;
}
void CSearchDetailPanel::CancelPreview()
{
CSingleLock pLock( &m_pSection, TRUE );
m_bRunPreview = FALSE;
m_pPreviewURLs.RemoveAll();
if ( m_bmThumb.m_hObject != NULL )
{
m_bmThumb.DeleteObject();
Invalidate();
}
if ( m_bIsPreviewing )
{
m_bIsPreviewing = FALSE;
Invalidate();
}
m_pRequest.Cancel();
}
UINT CSearchDetailPanel::ThreadStart(LPVOID pParam)
{
CSearchDetailPanel* pPanel = (CSearchDetailPanel*)pParam;
pPanel->OnRun();
return 0;
}
void CSearchDetailPanel::OnRun()
{
CSingleLock pLock( &m_pSection );
CImageServices pServices;
while ( m_bThread )
{
pLock.Lock();
if ( ! m_bValid || ! m_bRunPreview || m_pPreviewURLs.IsEmpty() )
{
if ( m_bIsPreviewing )
{
m_bIsPreviewing = FALSE;
Invalidate();
}
pLock.Unlock();
WaitForSingleObject( m_pWakeup, INFINITE );
continue;
}
CString strURL = m_pPreviewURLs.RemoveHead();
SHA1 pSHA1 = m_pSHA1;
if ( ! m_bIsPreviewing )
{
m_bIsPreviewing = TRUE;
Invalidate();
}
pLock.Unlock();
BYTE* pBuffer;
DWORD nBuffer;
if ( ExecuteRequest( strURL, &pBuffer, &nBuffer ) )
{
CImageFile pImage( &pServices );
if ( pImage.LoadFromMemory( _T(".jpg"), (LPCVOID)pBuffer, nBuffer, FALSE, TRUE ) )
{
OnPreviewLoaded( &pSHA1, &pImage );
CachePreviewImage( &pSHA1, pBuffer, nBuffer );
}
else
{
theApp.Message( MSG_ERROR, IDS_SEARCH_DETAILS_PREVIEW_FAILED, (LPCTSTR)strURL );
}
free( pBuffer );
}
else
{
theApp.Message( MSG_ERROR, IDS_SEARCH_DETAILS_PREVIEW_FAILED, (LPCTSTR)strURL );
}
}
}
BOOL CSearchDetailPanel::ExecuteRequest(CString strURL, BYTE** ppBuffer, DWORD* pnBuffer)
{
m_pRequest.Clear();
m_pRequest.SetURL( strURL );
m_pRequest.AddHeader( _T("Accept"), _T("image/jpeg") );
m_pRequest.LimitContentLength( Settings.Search.MaxPreviewLength );
if ( ! m_pRequest.Execute( FALSE ) )
{
theApp.Message( MSG_DEBUG, _T("Preview failed: unable to execute request.") );
return FALSE;
}
int nCode = m_pRequest.GetStatusCode();
if ( m_pRequest.GetStatusSuccess() == FALSE )
{
theApp.Message( MSG_DEBUG, _T("Preview failed: HTTP status code %i"),
m_pRequest.GetStatusCode() );
return FALSE;
}
CString strURN = m_pRequest.GetHeader( _T("X-Previewed-URN") );
if ( strURN.GetLength() )
{
SHA1 pSHA1;
if ( CSHA::HashFromURN( strURN, &pSHA1 ) && pSHA1 != m_pSHA1 )
{
theApp.Message( MSG_DEBUG, _T("Preview failed: wrong URN.") );
return FALSE;
}
}
CString strMIME = m_pRequest.GetHeader( _T("Content-Type") );
if ( strMIME.CompareNoCase( _T("image/jpeg") ) != 0 )
{
theApp.Message( MSG_DEBUG, _T("Preview failed: unacceptable content type.") );
return FALSE;
}
CBuffer* pBuffer = m_pRequest.GetResponseBuffer();
if ( pBuffer == NULL ) return FALSE;
*pnBuffer = pBuffer->m_nLength;
*ppBuffer = (BYTE*)malloc( *pnBuffer );
CopyMemory( *ppBuffer, pBuffer->m_pBuffer, *pnBuffer );
return TRUE;
}
void CSearchDetailPanel::OnPreviewLoaded(SHA1* pSHA1, CImageFile* pImage)
{
if ( m_nThumbSize == 0 ) return;
int nSize = m_nThumbSize * pImage->m_nWidth / pImage->m_nHeight;
if ( nSize > m_nThumbSize )
{
nSize = m_nThumbSize * pImage->m_nHeight / pImage->m_nWidth;
pImage->Resample( m_nThumbSize, nSize );
}
else
{
pImage->Resample( nSize, m_nThumbSize );
}
CSingleLock pLock( &m_pSection, TRUE );
if ( m_pSHA1 != *pSHA1 ) return;
m_bCanPreview = m_bRunPreview = m_bIsPreviewing = FALSE;
if ( m_bmThumb.m_hObject ) m_bmThumb.DeleteObject();
m_bmThumb.Attach( pImage->CreateBitmap() );
m_szThumb.cx = pImage->m_nWidth;
m_szThumb.cy = pImage->m_nHeight;
pLock.Unlock();
Invalidate();
}
BOOL CSearchDetailPanel::CachePreviewImage(SHA1* pSHA1, LPBYTE pBuffer, DWORD nBuffer)
{
CSingleLock pLock( &m_pMatches->m_pSection, TRUE );
if ( m_pMatches->FileToItem( m_pFile ) != 0xFFFFFFFF )
{
if ( m_pFile->m_pPreview != NULL ) delete [] m_pFile->m_pPreview;
m_pFile->m_nPreview = nBuffer;
m_pFile->m_pPreview = new BYTE[ nBuffer ];
CopyMemory( m_pFile->m_pPreview, pBuffer, nBuffer );
return TRUE;
}
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -