📄 ctrllibrarythumbview.cpp
字号:
//
// CtrlLibraryThumbView.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 "Settings.h"
#include "Library.h"
#include "SharedFile.h"
#include "SharedFolder.h"
#include "ImageServices.h"
#include "ThumbCache.h"
#include "ShellIcons.h"
#include "CoolInterface.h"
#include "Schema.h"
#include "SchemaCache.h"
#include "CtrlLibraryThumbView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CLibraryThumbView, CLibraryFileView)
BEGIN_MESSAGE_MAP(CLibraryThumbView, CLibraryFileView)
//{{AFX_MSG_MAP(CLibraryThumbView)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_SIZE()
ON_WM_PAINT()
ON_WM_VSCROLL()
ON_WM_MOUSEWHEEL()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_KEYDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#define THUMB_ICON 48
/////////////////////////////////////////////////////////////////////////////
// CLibraryThumbView construction
CLibraryThumbView::CLibraryThumbView()
{
m_nCommandID = ID_LIBRARY_VIEW_THUMBNAIL;
}
CLibraryThumbView::~CLibraryThumbView()
{
}
/////////////////////////////////////////////////////////////////////////////
// CLibraryThumbView create and destroy
BOOL CLibraryThumbView::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= WS_VSCROLL;
return CLibraryFileView::PreCreateWindow( cs );
}
int CLibraryThumbView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if ( CLibraryFileView::OnCreate( lpCreateStruct ) == -1 ) return -1;
m_hThread = NULL;
m_bThread = FALSE;
m_nInvalidate = 0;
m_bRush = FALSE;
m_szThumb = CSize( Settings.Library.ThumbSize, Settings.Library.ThumbSize );
m_szBlock.cx = m_szThumb.cx + 32;
m_szBlock.cy = m_szThumb.cy + 44;
m_nColumns = 0;
m_nRows = 0;
m_pList = NULL;
m_nCount = 0;
m_nBuffer = 0;
m_nScroll = 0;
m_nSelected = 0;
m_pFocus = NULL;
m_pFirst = NULL;
m_bDrag = FALSE;
SetTimer( 1, 500, NULL );
return 0;
}
void CLibraryThumbView::OnDestroy()
{
KillTimer( 1 );
Clear();
CLibraryFileView::OnDestroy();
}
/////////////////////////////////////////////////////////////////////////////
// CLibraryThumbView view operations
void CLibraryThumbView::Update()
{
CSingleLock pLock( &m_pSection, TRUE );
CSchema* pSchema = SchemaCache.Get( Settings.Library.FilterURI );
DWORD nCookie = GetFolderCookie();
BOOL bChanged = FALSE;
if ( Settings.Library.ShowVirtual ) pSchema = NULL;
CLibraryThumbItem** pList = m_pList + m_nCount - 1;
for ( int nItem = m_nCount ; nItem ; nItem--, pList-- )
{
CLibraryThumbItem* pThumb = *pList;
CLibraryFile* pFile = Library.LookupFile( pThumb->m_nIndex );
if ( pFile != NULL && pFile->m_nSelectCookie == nCookie &&
( ! pSchema || pSchema->Equals( pFile->m_pSchema ) ||
( ! pFile->m_pMetadata && pSchema->FilterType( pFile->m_sName ) ) ) )
{
bChanged |= pThumb->Update( pFile );
pFile->m_nListCookie = nCookie;
}
else
{
if ( pThumb->m_bSelected ) Select( pThumb, TS_FALSE );
if ( pThumb == m_pFocus ) m_pFocus = NULL;
if ( pThumb == m_pFirst ) m_pFirst = NULL;
delete pThumb;
MoveMemory( pList, pList + 1, 4 * ( m_nCount - nItem ) );
m_nCount--;
bChanged = TRUE;
}
}
if ( bChanged )
{
CRect rcClient;
GetClientRect( &rcClient );
int nMax = ( ( m_nCount + m_nColumns - 1 ) / m_nColumns ) * m_szBlock.cy;
m_nScroll = max( 0, min( m_nScroll, nMax - rcClient.Height() + 1 ) );
}
for ( POSITION pos = LibraryMaps.GetFileIterator() ; pos ; )
{
CLibraryFile* pFile = LibraryMaps.GetNextFile( pos );
if ( pFile->m_nSelectCookie == nCookie &&
pFile->m_nListCookie != nCookie &&
( ! pSchema || pSchema->Equals( pFile->m_pSchema ) ||
( ! pFile->m_pMetadata && pSchema->FilterType( pFile->m_sName ) ) ) )
{
CLibraryThumbItem* pThumb = new CLibraryThumbItem( pFile );
if ( m_nCount == m_nBuffer )
{
m_nBuffer += 64;
CLibraryThumbItem** pList = new CLibraryThumbItem*[ m_nBuffer ];
if ( m_nCount ) CopyMemory( pList, m_pList, 4 * m_nCount );
if ( m_pList ) delete [] m_pList;
m_pList = pList;
}
m_pList[ m_nCount++ ] = pThumb;
pFile->m_nListCookie = nCookie;
bChanged = TRUE;
}
}
if ( bChanged )
{
qsort( m_pList, m_nCount, 4, SortList );
UpdateScroll();
StartThread();
}
}
BOOL CLibraryThumbView::Select(DWORD nObject)
{
CRect rcClient, rcItem;
CLibraryThumbItem** pList = m_pList + m_nCount - 1;
for ( int nItem = m_nCount ; nItem ; nItem--, pList-- )
{
CLibraryThumbItem* pThumb = *pList;
if ( pThumb->m_nIndex == nObject ) break;
}
if ( nItem == 0 ) return FALSE;
m_pFocus = *pList;
DeselectAll( m_pFocus );
Select( m_pFocus );
Invalidate();
GetClientRect( &rcClient );
GetItemRect( m_pFocus, &rcItem );
if ( rcItem.top < rcClient.top )
{
ScrollBy( rcItem.top - rcClient.top );
}
else if ( rcItem.bottom > rcClient.bottom )
{
ScrollBy( rcItem.bottom - rcClient.bottom );
}
return TRUE;
}
DWORD CLibraryThumbView::HitTestIndex(const CPoint& point) const
{
CLibraryThumbItem* pThumb = HitTest( point );
return ( pThumb ) ? pThumb->m_nIndex : 0;
}
int CLibraryThumbView::SortList(LPCVOID pA, LPCVOID pB)
{
CLibraryThumbItem* ppA = *(CLibraryThumbItem**)pA;
CLibraryThumbItem* ppB = *(CLibraryThumbItem**)pB;
return _tcsicoll( ppA->m_sText, ppB->m_sText );
}
/////////////////////////////////////////////////////////////////////////////
// CLibraryThumbView item list management operations
void CLibraryThumbView::Clear()
{
StopThread();
for ( int nItem = 0 ; nItem < m_nCount ; nItem++ )
{
delete m_pList[ nItem ];
}
if ( m_pList ) delete [] m_pList;
m_pList = NULL;
m_nCount = 0;
m_nBuffer = 0;
m_nScroll = 0;
m_nSelected = 0;
m_pFocus = NULL;
m_pFirst = NULL;
m_pSelThumb.RemoveAll();
SelClear();
}
int CLibraryThumbView::GetThumbIndex(CLibraryThumbItem* pThumb) const
{
CLibraryThumbItem** pList = m_pList;
for ( int nItem = 0 ; nItem < m_nCount ; nItem++, pList++ )
{
if ( *pList == pThumb ) return nItem;
}
return -1;
}
BOOL CLibraryThumbView::Select(CLibraryThumbItem* pThumb, TRISTATE bSelect)
{
switch ( bSelect )
{
case TS_UNKNOWN:
pThumb->m_bSelected = ! pThumb->m_bSelected;
break;
case TS_FALSE:
if ( pThumb->m_bSelected == FALSE ) return FALSE;
pThumb->m_bSelected = FALSE;
break;
case TS_TRUE:
if ( pThumb->m_bSelected == TRUE ) return FALSE;
pThumb->m_bSelected = TRUE;
break;
}
if ( pThumb->m_bSelected )
{
m_nSelected++;
m_pSelThumb.AddTail( pThumb );
SelAdd( pThumb->m_nIndex );
}
else
{
m_nSelected--;
if ( POSITION pos = m_pSelThumb.Find( pThumb ) )
{
m_pSelThumb.RemoveAt( pos );
SelRemove( pThumb->m_nIndex );
}
}
return TRUE;
}
BOOL CLibraryThumbView::DeselectAll(CLibraryThumbItem* pThumb)
{
CLibraryThumbItem** pList = m_pList + m_nCount - 1;
BOOL bChanged = FALSE;
for ( int nItem = m_nCount ; nItem ; nItem--, pList-- )
{
if ( *pList != pThumb )
{
if ( (*pList)->m_bSelected ) bChanged = Select( *pList, TS_FALSE );
}
}
return bChanged;
}
BOOL CLibraryThumbView::SelectTo(CLibraryThumbItem* pThumb)
{
BOOL bChanged = FALSE;
if ( pThumb )
{
m_pFocus = pThumb;
int nFirst = GetThumbIndex( m_pFirst );
int nFocus = GetThumbIndex( m_pFocus );
if ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 )
{
bChanged = Select( m_pFocus, TS_UNKNOWN );
}
else if ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 )
{
bChanged = DeselectAll();
if ( nFirst >= 0 && nFocus >= 0 )
{
if ( nFirst <= nFocus )
{
for ( ; nFirst <= nFocus ; nFirst++ ) Select( m_pList[ nFirst ], TS_TRUE );
}
else
{
for ( ; nFocus <= nFirst ; nFocus++ ) Select( m_pList[ nFocus ], TS_TRUE );
}
bChanged = TRUE;
}
else
{
bChanged |= Select( m_pFocus, TS_TRUE );
}
}
else
{
if ( m_pFocus->m_bSelected == FALSE ) bChanged = DeselectAll( m_pFocus );
bChanged |= Select( m_pFocus );
}
if ( m_nSelected == 1 && m_pFocus->m_bSelected ) m_pFirst = m_pFocus;
CRect rcClient, rcItem;
GetClientRect( &rcClient );
GetItemRect( m_pFocus, &rcItem );
if ( rcItem.top < rcClient.top )
{
ScrollBy( rcItem.top - rcClient.top );
}
else if ( rcItem.bottom > rcClient.bottom )
{
ScrollBy( rcItem.bottom - rcClient.bottom );
}
}
else if ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 &&
( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) == 0 )
{
bChanged = DeselectAll();
}
if ( m_nSelected == 0 ) m_pFirst = NULL;
return bChanged;
}
void CLibraryThumbView::SelectTo(int nDelta)
{
if ( m_nCount == 0 ) return;
int nFocus = GetThumbIndex( m_pFocus );
if ( nFocus < 0 )
{
nFocus = 0;
}
else
{
nFocus += nDelta;
if ( nFocus < 0 ) nFocus = 0;
if ( nFocus >= m_nCount ) nFocus = m_nCount - 1;
}
if ( SelectTo( m_pList[ nFocus ] ) ) Invalidate();
}
/////////////////////////////////////////////////////////////////////////////
// CLibraryThumbView message handlers
void CLibraryThumbView::OnSize(UINT nType, int cx, int cy)
{
CLibraryFileView::OnSize( nType, cx, cy );
m_nColumns = cx / m_szBlock.cx;
m_nRows = cy / m_szBlock.cy + 1;
UpdateScroll();
}
void CLibraryThumbView::UpdateScroll()
{
if ( m_nColumns == 0 ) return;
SCROLLINFO pInfo;
CRect rc;
GetClientRect( &rc );
pInfo.cbSize = sizeof(pInfo);
pInfo.fMask = SIF_ALL & ~SIF_TRACKPOS;
pInfo.nMin = 0;
pInfo.nMax = ( ( m_nCount + m_nColumns - 1 ) / m_nColumns ) * m_szBlock.cy;
pInfo.nPage = rc.Height();;
pInfo.nPos = m_nScroll = max( 0, min( m_nScroll, pInfo.nMax - (int)pInfo.nPage + 1 ) );
SetScrollInfo( SB_VERT, &pInfo, TRUE );
Invalidate();
}
void CLibraryThumbView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CRect rc;
GetClientRect( &rc );
SetFocus();
switch ( nSBCode )
{
case SB_BOTTOM:
ScrollTo( 0xFFFFFF );
break;
case SB_LINEDOWN:
ScrollBy( 32 );
break;
case SB_LINEUP:
ScrollBy( -32 );
break;
case SB_PAGEDOWN:
ScrollBy( rc.Height() );
break;
case SB_PAGEUP:
ScrollBy( -rc.Height() );
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
ScrollTo( nPos );
break;
case SB_TOP:
ScrollTo( 0 );
break;
}
}
BOOL CLibraryThumbView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
ScrollBy( zDelta * -m_szBlock.cy / WHEEL_DELTA / 2 );
return TRUE;
}
void CLibraryThumbView::ScrollBy(int nDelta)
{
ScrollTo( max( 0, m_nScroll + nDelta ) );
}
void CLibraryThumbView::ScrollTo(int nPosition)
{
if ( nPosition == m_nScroll ) return;
m_nScroll = nPosition;
UpdateScroll();
RedrawWindow( NULL, NULL, RDW_INVALIDATE );
}
void CLibraryThumbView::OnTimer(UINT nIDEvent)
{
CSingleLock pLock( &m_pSection, TRUE );
if ( m_nInvalidate && ( GetAsyncKeyState( VK_LBUTTON ) & 0x8000 ) == 0 )
{
Invalidate();
m_nInvalidate = 0;
}
}
void CLibraryThumbView::OnPaint()
{
CSingleLock pLock( &m_pSection, TRUE );
CPaintDC dc( this );
CDC* pBuffer = CoolInterface.GetBuffer( dc, m_szBlock );
CRect rcBuffer( 0, 0, m_szBlock.cx, m_szBlock.cy );
CFont* pOldFont = (CFont*)pBuffer->SelectObject( &CoolInterface.m_fntNormal );
pBuffer->SetBkMode( OPAQUE );
pBuffer->SetBkColor( CoolInterface.m_crWindow );
pBuffer->SetTextColor( CoolInterface.m_crText );
CDC dcMem;
dcMem.CreateCompatibleDC( &dc );
CRect rcClient;
GetClientRect( &rcClient );
CPoint pt( rcClient.left, rcClient.top - m_nScroll );
CLibraryThumbItem** pList = m_pList;
m_bRush = FALSE;
for ( int nItem = m_nCount ; nItem && pt.y < rcClient.bottom ; nItem--, pList++ )
{
CLibraryThumbItem* pThumb = *pList;
CRect rcBlock( pt.x, pt.y, pt.x + m_szBlock.cx, pt.y + m_szBlock.cy );
if ( rcBlock.bottom >= rcClient.top && dc.RectVisible( &rcBlock ) )
{
pBuffer->FillSolidRect( &rcBuffer, CoolInterface.m_crWindow );
pThumb->Paint( pBuffer, rcBuffer, m_szThumb, &dcMem );
dc.BitBlt( rcBlock.left, rcBlock.top, m_szBlock.cx, m_szBlock.cy,
pBuffer, 0, 0, SRCCOPY );
dc.ExcludeClipRect( &rcBlock );
if ( pThumb->m_nThumb == CLibraryThumbItem::thumbWaiting ) m_bRush = TRUE;
}
pt.x += m_szBlock.cx;
if ( pt.x + m_szBlock.cx > rcClient.right )
{
pt.x = rcClient.left;
pt.y += m_szBlock.cy;
}
}
pBuffer->SelectObject( pOldFont );
dc.FillSolidRect( &rcClient, CoolInterface.m_crWindow );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -