00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Library.h"
00026 #include "SharedFile.h"
00027 #include "SharedFolder.h"
00028 #include "ImageServices.h"
00029 #include "ThumbCache.h"
00030 #include "ShellIcons.h"
00031 #include "CoolInterface.h"
00032 #include "Schema.h"
00033 #include "SchemaCache.h"
00034 #include "CtrlLibraryThumbView.h"
00035
00036 #ifdef _DEBUG
00037 #define new DEBUG_NEW
00038 #undef THIS_FILE
00039 static char THIS_FILE[] = __FILE__;
00040 #endif
00041
00042 IMPLEMENT_DYNCREATE(CLibraryThumbView, CLibraryFileView)
00043
00044 BEGIN_MESSAGE_MAP(CLibraryThumbView, CLibraryFileView)
00045
00046 ON_WM_CREATE()
00047 ON_WM_DESTROY()
00048 ON_WM_SIZE()
00049 ON_WM_PAINT()
00050 ON_WM_VSCROLL()
00051 ON_WM_MOUSEWHEEL()
00052 ON_WM_LBUTTONDOWN()
00053 ON_WM_MOUSEMOVE()
00054 ON_WM_LBUTTONUP()
00055 ON_WM_RBUTTONDOWN()
00056 ON_WM_KEYDOWN()
00057 ON_WM_LBUTTONDBLCLK()
00058 ON_WM_TIMER()
00059
00060 END_MESSAGE_MAP()
00061
00062 #define THUMB_ICON 48
00063 #define THUMB_STORE_SIZE 128
00064
00065
00067
00068
00069 CLibraryThumbView::CLibraryThumbView()
00070 {
00071 m_nCommandID = ID_LIBRARY_VIEW_THUMBNAIL;
00072 }
00073
00074 CLibraryThumbView::~CLibraryThumbView()
00075 {
00076 }
00077
00079
00080
00081 BOOL CLibraryThumbView::PreCreateWindow(CREATESTRUCT& cs)
00082 {
00083 cs.style |= WS_VSCROLL;
00084 return CLibraryFileView::PreCreateWindow( cs );
00085 }
00086
00087 int CLibraryThumbView::OnCreate(LPCREATESTRUCT lpCreateStruct)
00088 {
00089 if ( CLibraryFileView::OnCreate( lpCreateStruct ) == -1 ) return -1;
00090
00091 m_hThread = NULL;
00092 m_bThread = FALSE;
00093 m_nInvalidate = 0;
00094 m_bRush = FALSE;
00095
00096 m_szThumb = CSize( Settings.Library.ThumbSize, Settings.Library.ThumbSize );
00097 m_szBlock.cx = m_szThumb.cx + 32;
00098 m_szBlock.cy = m_szThumb.cy + 44;
00099 m_nColumns = 0;
00100 m_nRows = 0;
00101
00102 m_pList = NULL;
00103 m_nCount = 0;
00104 m_nBuffer = 0;
00105 m_nScroll = 0;
00106 m_nSelected = 0;
00107 m_pFocus = NULL;
00108 m_pFirst = NULL;
00109 m_bDrag = FALSE;
00110
00111 SetTimer( 1, 500, NULL );
00112
00113 return 0;
00114 }
00115
00116 void CLibraryThumbView::OnDestroy()
00117 {
00118 KillTimer( 1 );
00119 Clear();
00120 CLibraryFileView::OnDestroy();
00121 }
00122
00124
00125
00126 void CLibraryThumbView::Update()
00127 {
00128 CSingleLock pLock( &m_pSection, TRUE );
00129
00130 CSchema* pSchema = SchemaCache.Get( Settings.Library.FilterURI );
00131 DWORD nCookie = GetFolderCookie();
00132 BOOL bChanged = FALSE;
00133
00134 if ( Settings.Library.ShowVirtual ) pSchema = NULL;
00135
00136 CLibraryThumbItem** pList = m_pList + m_nCount - 1;
00137
00138 for ( int nItem = m_nCount ; nItem ; nItem--, pList-- )
00139 {
00140 CLibraryThumbItem* pThumb = *pList;
00141 CLibraryFile* pFile = Library.LookupFile( pThumb->m_nIndex );
00142
00143 if ( pFile != NULL && pFile->m_nSelectCookie == nCookie &&
00144 ( ! pSchema || pSchema->Equals( pFile->m_pSchema ) ||
00145 ( ! pFile->m_pMetadata && pSchema->FilterType( pFile->m_sName ) ) ) )
00146 {
00147 bChanged |= pThumb->Update( pFile );
00148
00149 pFile->m_nListCookie = nCookie;
00150 }
00151 else
00152 {
00153 if ( pThumb->m_bSelected ) Select( pThumb, TS_FALSE );
00154 if ( pThumb == m_pFocus ) m_pFocus = NULL;
00155 if ( pThumb == m_pFirst ) m_pFirst = NULL;
00156
00157 delete pThumb;
00158 MoveMemory( pList, pList + 1, 4 * ( m_nCount - nItem ) );
00159 m_nCount--;
00160
00161 bChanged = TRUE;
00162 }
00163 }
00164
00165 if ( bChanged )
00166 {
00167 CRect rcClient;
00168 GetClientRect( &rcClient );
00169 int nMax = ( ( m_nCount + m_nColumns - 1 ) / m_nColumns ) * m_szBlock.cy;
00170 m_nScroll = max( 0, min( m_nScroll, nMax - rcClient.Height() + 1 ) );
00171 }
00172
00173 for ( POSITION pos = LibraryMaps.GetFileIterator() ; pos ; )
00174 {
00175 CLibraryFile* pFile = LibraryMaps.GetNextFile( pos );
00176
00177 if ( pFile->m_nSelectCookie == nCookie &&
00178 pFile->m_nListCookie != nCookie &&
00179 ( ! pSchema || pSchema->Equals( pFile->m_pSchema ) ||
00180 ( ! pFile->m_pMetadata && pSchema->FilterType( pFile->m_sName ) ) ) )
00181 {
00182 CLibraryThumbItem* pThumb = new CLibraryThumbItem( pFile );
00183
00184 if ( m_nCount == m_nBuffer )
00185 {
00186 m_nBuffer += 64;
00187 CLibraryThumbItem** pList = new CLibraryThumbItem*[ m_nBuffer ];
00188 if ( m_nCount ) CopyMemory( pList, m_pList, 4 * m_nCount );
00189 if ( m_pList ) delete [] m_pList;
00190 m_pList = pList;
00191 }
00192
00193 m_pList[ m_nCount++ ] = pThumb;
00194 pFile->m_nListCookie = nCookie;
00195 bChanged = TRUE;
00196 }
00197 }
00198
00199 if ( bChanged )
00200 {
00201 qsort( m_pList, m_nCount, 4, SortList );
00202 UpdateScroll();
00203 StartThread();
00204 }
00205 }
00206
00207 BOOL CLibraryThumbView::Select(DWORD nObject)
00208 {
00209 CRect rcClient, rcItem;
00210
00211 CLibraryThumbItem** pList = m_pList + m_nCount - 1;
00212
00213 int nItem = m_nCount;
00214 for ( ; nItem ; nItem--, pList-- )
00215 {
00216 CLibraryThumbItem* pThumb = *pList;
00217 if ( pThumb->m_nIndex == nObject ) break;
00218 }
00219
00220 if ( nItem == 0 ) return FALSE;
00221
00222 m_pFocus = *pList;
00223 DeselectAll( m_pFocus );
00224 Select( m_pFocus );
00225 Invalidate();
00226
00227 GetClientRect( &rcClient );
00228 GetItemRect( m_pFocus, &rcItem );
00229
00230 if ( rcItem.top < rcClient.top )
00231 {
00232 ScrollBy( rcItem.top - rcClient.top );
00233 }
00234 else if ( rcItem.bottom > rcClient.bottom )
00235 {
00236 ScrollBy( rcItem.bottom - rcClient.bottom );
00237 }
00238
00239 return TRUE;
00240 }
00241
00242 DWORD CLibraryThumbView::HitTestIndex(const CPoint& point) const
00243 {
00244 CLibraryThumbItem* pThumb = HitTest( point );
00245 return ( pThumb ) ? pThumb->m_nIndex : 0;
00246 }
00247
00248 int CLibraryThumbView::SortList(LPCVOID pA, LPCVOID pB)
00249 {
00250 CLibraryThumbItem* ppA = *(CLibraryThumbItem**)pA;
00251 CLibraryThumbItem* ppB = *(CLibraryThumbItem**)pB;
00252 return _tcsicoll( ppA->m_sText, ppB->m_sText );
00253 }
00254
00256
00257
00258 void CLibraryThumbView::Clear()
00259 {
00260 StopThread();
00261
00262 for ( int nItem = 0 ; nItem < m_nCount ; nItem++ )
00263 {
00264 delete m_pList[ nItem ];
00265 }
00266
00267 if ( m_pList ) delete [] m_pList;
00268
00269 m_pList = NULL;
00270 m_nCount = 0;
00271 m_nBuffer = 0;
00272 m_nScroll = 0;
00273 m_nSelected = 0;
00274 m_pFocus = NULL;
00275 m_pFirst = NULL;
00276 m_pSelThumb.RemoveAll();
00277 SelClear();
00278 }
00279
00280 int CLibraryThumbView::GetThumbIndex(CLibraryThumbItem* pThumb) const
00281 {
00282 CLibraryThumbItem** pList = m_pList;
00283
00284 for ( int nItem = 0 ; nItem < m_nCount ; nItem++, pList++ )
00285 {
00286 if ( *pList == pThumb ) return nItem;
00287 }
00288
00289 return -1;
00290 }
00291
00292 BOOL CLibraryThumbView::Select(CLibraryThumbItem* pThumb, TRISTATE bSelect)
00293 {
00294 switch ( bSelect )
00295 {
00296 case TS_UNKNOWN:
00297 pThumb->m_bSelected = ! pThumb->m_bSelected;
00298 break;
00299 case TS_FALSE:
00300 if ( pThumb->m_bSelected == FALSE ) return FALSE;
00301 pThumb->m_bSelected = FALSE;
00302 break;
00303 case TS_TRUE:
00304 if ( pThumb->m_bSelected == TRUE ) return FALSE;
00305 pThumb->m_bSelected = TRUE;
00306 break;
00307 }
00308
00309 if ( pThumb->m_bSelected )
00310 {
00311 m_nSelected++;
00312 m_pSelThumb.AddTail( pThumb );
00313 SelAdd( pThumb->m_nIndex );
00314 }
00315 else
00316 {
00317 m_nSelected--;
00318 if ( POSITION pos = m_pSelThumb.Find( pThumb ) )
00319 {
00320 m_pSelThumb.RemoveAt( pos );
00321 SelRemove( pThumb->m_nIndex );
00322 }
00323 }
00324
00325 return TRUE;
00326 }
00327
00328 BOOL CLibraryThumbView::DeselectAll(CLibraryThumbItem* pThumb)
00329 {
00330 CLibraryThumbItem** pList = m_pList + m_nCount - 1;
00331 BOOL bChanged = FALSE;
00332
00333 for ( int nItem = m_nCount ; nItem ; nItem--, pList-- )
00334 {
00335 if ( *pList != pThumb )
00336 {
00337 if ( (*pList)->m_bSelected ) bChanged = Select( *pList, TS_FALSE );
00338 }
00339 }
00340
00341 return bChanged;
00342 }
00343
00344 BOOL CLibraryThumbView::SelectTo(CLibraryThumbItem* pThumb)
00345 {
00346 BOOL bChanged = FALSE;
00347
00348 if ( pThumb )
00349 {
00350 m_pFocus = pThumb;
00351
00352 int nFirst = GetThumbIndex( m_pFirst );
00353 int nFocus = GetThumbIndex( m_pFocus );
00354
00355 if ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 )
00356 {
00357 bChanged = Select( m_pFocus, TS_UNKNOWN );
00358 }
00359 else if ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 )
00360 {
00361 bChanged = DeselectAll();
00362
00363 if ( nFirst >= 0 && nFocus >= 0 )
00364 {
00365 if ( nFirst <= nFocus )
00366 {
00367 for ( ; nFirst <= nFocus ; nFirst++ ) Select( m_pList[ nFirst ], TS_TRUE );
00368 }
00369 else
00370 {
00371 for ( ; nFocus <= nFirst ; nFocus++ ) Select( m_pList[ nFocus ], TS_TRUE );
00372 }
00373
00374 bChanged = TRUE;
00375 }
00376 else
00377 {
00378 bChanged |= Select( m_pFocus, TS_TRUE );
00379 }
00380 }
00381 else
00382 {
00383 if ( m_pFocus->m_bSelected == FALSE ) bChanged = DeselectAll( m_pFocus );
00384 bChanged |= Select( m_pFocus );
00385 }
00386
00387 if ( m_nSelected == 1 && m_pFocus->m_bSelected ) m_pFirst = m_pFocus;
00388
00389 CRect rcClient, rcItem;
00390
00391 GetClientRect( &rcClient );
00392 GetItemRect( m_pFocus, &rcItem );
00393
00394 if ( rcItem.top < rcClient.top )
00395 {
00396 ScrollBy( rcItem.top - rcClient.top );
00397 }
00398 else if ( rcItem.bottom > rcClient.bottom )
00399 {
00400 ScrollBy( rcItem.bottom - rcClient.bottom );
00401 }
00402 }
00403 else if ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 &&
00404 ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) == 0 )
00405 {
00406 bChanged = DeselectAll();
00407 }
00408
00409 if ( m_nSelected == 0 ) m_pFirst = NULL;
00410
00411 return bChanged;
00412 }
00413
00414 void CLibraryThumbView::SelectTo(int nDelta)
00415 {
00416 if ( m_nCount == 0 ) return;
00417
00418 int nFocus = GetThumbIndex( m_pFocus );
00419
00420 if ( nFocus < 0 )
00421 {
00422 nFocus = 0;
00423 }
00424 else
00425 {
00426 nFocus += nDelta;
00427 if ( nFocus < 0 ) nFocus = 0;
00428 if ( nFocus >= m_nCount ) nFocus = m_nCount - 1;
00429 }
00430
00431 if ( SelectTo( m_pList[ nFocus ] ) ) Invalidate();
00432 }
00433
00435
00436
00437 void CLibraryThumbView::OnSize(UINT nType, int cx, int cy)
00438 {
00439 CLibraryFileView::OnSize( nType, cx, cy );
00440
00441 m_nColumns = cx / m_szBlock.cx;
00442 m_nRows = cy / m_szBlock.cy + 1;
00443
00444 UpdateScroll();
00445 }
00446
00447 void CLibraryThumbView::UpdateScroll()
00448 {
00449 if ( m_nColumns == 0 ) return;
00450
00451 SCROLLINFO pInfo;
00452 CRect rc;
00453
00454 GetClientRect( &rc );
00455
00456 pInfo.cbSize = sizeof(pInfo);
00457 pInfo.fMask = SIF_ALL & ~SIF_TRACKPOS;
00458 pInfo.nMin = 0;
00459 pInfo.nMax = ( ( m_nCount + m_nColumns - 1 ) / m_nColumns ) * m_szBlock.cy;
00460 pInfo.nPage = rc.Height();;
00461 pInfo.nPos = m_nScroll = max( 0, min( m_nScroll, pInfo.nMax - (int)pInfo.nPage + 1 ) );
00462
00463 SetScrollInfo( SB_VERT, &pInfo, TRUE );
00464
00465 Invalidate();
00466 }
00467
00468 void CLibraryThumbView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
00469 {
00470 CRect rc;
00471 GetClientRect( &rc );
00472
00473 SetFocus();
00474
00475 switch ( nSBCode )
00476 {
00477 case SB_BOTTOM:
00478 ScrollTo( 0xFFFFFF );
00479 break;
00480 case SB_LINEDOWN:
00481 ScrollBy( 32 );
00482 break;
00483 case SB_LINEUP:
00484 ScrollBy( -32 );
00485 break;
00486 case SB_PAGEDOWN:
00487 ScrollBy( rc.Height() );
00488 break;
00489 case SB_PAGEUP:
00490 ScrollBy( -rc.Height() );
00491 break;
00492 case SB_THUMBPOSITION:
00493 case SB_THUMBTRACK:
00494 ScrollTo( nPos );
00495 break;
00496 case SB_TOP:
00497 ScrollTo( 0 );
00498 break;
00499 }
00500 }
00501
00502 BOOL CLibraryThumbView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
00503 {
00504 ScrollBy( zDelta * -m_szBlock.cy / WHEEL_DELTA / 2 );
00505 return TRUE;
00506 }
00507
00508 void CLibraryThumbView::ScrollBy(int nDelta)
00509 {
00510 ScrollTo( max( 0, m_nScroll + nDelta ) );
00511 }
00512
00513 void CLibraryThumbView::ScrollTo(int nPosition)
00514 {
00515 if ( nPosition == m_nScroll ) return;
00516 m_nScroll = nPosition;
00517
00518 UpdateScroll();
00519 RedrawWindow( NULL, NULL, RDW_INVALIDATE );
00520 }
00521
00522 void CLibraryThumbView::OnTimer(UINT nIDEvent)
00523 {
00524 CSingleLock pLock( &m_pSection, TRUE );
00525
00526 if ( m_nInvalidate && ( GetAsyncKeyState( VK_LBUTTON ) & 0x8000 ) == 0 )
00527 {
00528 Invalidate();
00529 m_nInvalidate = 0;
00530 }
00531 }
00532
00533 void CLibraryThumbView::OnPaint()
00534 {
00535 CSingleLock pLock( &m_pSection, TRUE );
00536 CPaintDC dc( this );
00537
00538 CDC* pBuffer = CoolInterface.GetBuffer( dc, m_szBlock );
00539 CRect rcBuffer( 0, 0, m_szBlock.cx, m_szBlock.cy );
00540
00541 CFont* pOldFont = (CFont*)pBuffer->SelectObject( &CoolInterface.m_fntNormal );
00542 pBuffer->SetBkMode( OPAQUE );
00543 pBuffer->SetBkColor( CoolInterface.m_crWindow );
00544 pBuffer->SetTextColor( CoolInterface.m_crText );
00545
00546 CDC dcMem;
00547 dcMem.CreateCompatibleDC( &dc );
00548
00549 CRect rcClient;
00550 GetClientRect( &rcClient );
00551 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00552
00553 CLibraryThumbItem** pList = m_pList;
00554 m_bRush = FALSE;
00555
00556 for ( int nItem = m_nCount ; nItem && pt.y < rcClient.bottom ; nItem--, pList++ )
00557 {
00558 CLibraryThumbItem* pThumb = *pList;
00559
00560 CRect rcBlock( pt.x, pt.y, pt.x + m_szBlock.cx, pt.y + m_szBlock.cy );
00561
00562 if ( rcBlock.bottom >= rcClient.top && dc.RectVisible( &rcBlock ) )
00563 {
00564 pBuffer->FillSolidRect( &rcBuffer, CoolInterface.m_crWindow );
00565 pThumb->Paint( pBuffer, rcBuffer, m_szThumb, &dcMem );
00566 dc.BitBlt( rcBlock.left, rcBlock.top, m_szBlock.cx, m_szBlock.cy,
00567 pBuffer, 0, 0, SRCCOPY );
00568 dc.ExcludeClipRect( &rcBlock );
00569 if ( pThumb->m_nThumb == CLibraryThumbItem::thumbWaiting ) m_bRush = TRUE;
00570 }
00571
00572 pt.x += m_szBlock.cx;
00573
00574 if ( pt.x + m_szBlock.cx > rcClient.right )
00575 {
00576 pt.x = rcClient.left;
00577 pt.y += m_szBlock.cy;
00578 }
00579 }
00580
00581 pBuffer->SelectObject( pOldFont );
00582 dc.FillSolidRect( &rcClient, CoolInterface.m_crWindow );
00583 }
00584
00585 CLibraryThumbItem* CLibraryThumbView::HitTest(const CPoint& point) const
00586 {
00587 CRect rcClient;
00588 GetClientRect( &rcClient );
00589
00590 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00591
00592 CLibraryThumbItem** pList = m_pList;
00593
00594 for ( int nItem = m_nCount ; nItem && pt.y < rcClient.bottom ; nItem--, pList++ )
00595 {
00596 CLibraryThumbItem* pThumb = *pList;
00597
00598 CRect rcBlock( pt.x, pt.y, pt.x + m_szBlock.cx, pt.y + m_szBlock.cy );
00599
00600 if ( rcBlock.PtInRect( point ) ) return pThumb;
00601
00602 pt.x += m_szBlock.cx;
00603
00604 if ( pt.x + m_szBlock.cx > rcClient.right )
00605 {
00606 pt.x = rcClient.left;
00607 pt.y += m_szBlock.cy;
00608 }
00609 }
00610
00611 return NULL;
00612 }
00613
00614 BOOL CLibraryThumbView::GetItemRect(CLibraryThumbItem* pThumb, CRect* pRect)
00615 {
00616 CRect rcClient;
00617 GetClientRect( &rcClient );
00618
00619 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00620
00621 CLibraryThumbItem** pList = m_pList;
00622
00623 for ( int nItem = m_nCount ; nItem ; nItem--, pList++ )
00624 {
00625 CRect rcBlock( pt.x, pt.y, pt.x + m_szBlock.cx, pt.y + m_szBlock.cy );
00626
00627 if ( pThumb == *pList )
00628 {
00629 *pRect = rcBlock;
00630 return TRUE;
00631 }
00632
00633 pt.x += m_szBlock.cx;
00634
00635 if ( pt.x + m_szBlock.cx > rcClient.right )
00636 {
00637 pt.x = rcClient.left;
00638 pt.y += m_szBlock.cy;
00639 }
00640 }
00641
00642 return FALSE;
00643 }
00644
00645 void CLibraryThumbView::OnLButtonDown(UINT nFlags, CPoint point)
00646 {
00647 CLibraryThumbItem* pHit = HitTest( point );
00648
00649 if ( SelectTo( pHit ) ) Invalidate();
00650
00651 SetFocus();
00652 SetCapture();
00653
00654 if ( pHit && ( nFlags & MK_RBUTTON ) == 0 )
00655 {
00656 m_bDrag = TRUE;
00657 m_ptDrag = point;
00658 }
00659
00660 CLibraryFileView::OnLButtonDown( nFlags, point );
00661 }
00662
00663 void CLibraryThumbView::OnMouseMove(UINT nFlags, CPoint point)
00664 {
00665 if ( m_bDrag & ( nFlags & MK_LBUTTON ) )
00666 {
00667 CSize szDiff = point - m_ptDrag;
00668
00669 if ( abs( szDiff.cx ) > 5 || abs( szDiff.cy ) > 5 )
00670 {
00671 m_bDrag = FALSE;
00672 StartDragging( point );
00673 }
00674 }
00675
00676 CLibraryFileView::OnMouseMove( nFlags, point );
00677 }
00678
00679 void CLibraryThumbView::OnLButtonUp(UINT nFlags, CPoint point)
00680 {
00681 ReleaseCapture();
00682 m_bDrag = FALSE;
00683
00684 if ( ( nFlags & (MK_SHIFT|MK_CONTROL) ) == 0 && m_pFocus && m_pFocus->m_bSelected )
00685 {
00686 if ( DeselectAll( m_pFocus ) ) Invalidate();
00687 }
00688 }
00689
00690 void CLibraryThumbView::OnLButtonDblClk(UINT nFlags, CPoint point)
00691 {
00692 SendMessage( WM_COMMAND, ID_LIBRARY_LAUNCH );
00693 }
00694
00695 void CLibraryThumbView::OnRButtonDown(UINT nFlags, CPoint point)
00696 {
00697 OnLButtonDown( nFlags, point );
00698 CLibraryFileView::OnRButtonDown( nFlags, point );
00699 }
00700
00701 void CLibraryThumbView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
00702 {
00703 switch ( nChar )
00704 {
00705 case VK_LEFT:
00706 SelectTo( - 1 );
00707 break;
00708 case VK_RIGHT:
00709 SelectTo( 1 );
00710 break;
00711 case VK_UP:
00712 SelectTo( -m_nColumns );
00713 break;
00714 case VK_DOWN:
00715 SelectTo( m_nColumns );
00716 break;
00717 case VK_PRIOR:
00718 SelectTo( m_nRows * -m_nColumns );
00719 break;
00720 case VK_NEXT:
00721 SelectTo( m_nRows * m_nColumns );
00722 break;
00723 case VK_HOME:
00724 SelectTo( -m_nCount );
00725 break;
00726 case VK_END:
00727 SelectTo( m_nCount );
00728 break;
00729 }
00730
00731 CLibraryFileView::OnKeyDown( nChar, nRepCnt, nFlags );
00732 }
00733
00735
00736
00737 #define MAX_DRAG_SIZE 256
00738 #define MAX_DRAG_SIZE_2 128
00739
00740 void CLibraryThumbView::StartDragging(CPoint& ptMouse)
00741 {
00742 CSingleLock pLock( &m_pSection, TRUE );
00743
00744 CImageList* pImage = CreateDragImage( ptMouse );
00745 if ( ! pImage ) return;
00746
00747 ReleaseCapture();
00748 ClientToScreen( &ptMouse );
00749 DragObjects( pImage, ptMouse );
00750 }
00751
00752 CImageList* CLibraryThumbView::CreateDragImage(const CPoint& ptMouse)
00753 {
00754 CRect rcClient, rcOne, rcAll( 32000, 32000, -32000, -32000 );
00755
00756 GetClientRect( &rcClient );
00757
00758 for ( POSITION pos = m_pSelThumb.GetHeadPosition() ; pos ; )
00759 {
00760 CLibraryThumbItem* pThumb = (CLibraryThumbItem*)m_pSelThumb.GetNext( pos );
00761 GetItemRect( pThumb, &rcOne );
00762
00763 if ( rcOne.IntersectRect( &rcClient, &rcOne ) )
00764 {
00765 rcAll.left = min( rcAll.left, rcOne.left );
00766 rcAll.top = min( rcAll.top, rcOne.top );
00767 rcAll.right = max( rcAll.right, rcOne.right );
00768 rcAll.bottom = max( rcAll.bottom, rcOne.bottom );
00769 }
00770 }
00771
00772 BOOL bClipped = rcAll.Height() > MAX_DRAG_SIZE;
00773
00774 if ( bClipped )
00775 {
00776 rcAll.left = max( rcAll.left, ptMouse.x - MAX_DRAG_SIZE_2 );
00777 rcAll.right = max( rcAll.right, ptMouse.x + MAX_DRAG_SIZE_2 );
00778 rcAll.top = max( rcAll.top, ptMouse.y - MAX_DRAG_SIZE_2 );
00779 rcAll.bottom = max( rcAll.bottom, ptMouse.y + MAX_DRAG_SIZE_2 );
00780 }
00781
00782 CClientDC dcClient( this );
00783 CDC dcMem, dcDrag;
00784 CBitmap bmDrag;
00785
00786 if ( ! dcMem.CreateCompatibleDC( &dcClient ) )
00787 return NULL;
00788 if ( ! dcDrag.CreateCompatibleDC( &dcClient ) )
00789 return NULL;
00790 if ( ! bmDrag.CreateCompatibleBitmap( &dcClient, rcAll.Width(), rcAll.Height() ) )
00791 return NULL;
00792
00793 CBitmap *pOldDrag = dcDrag.SelectObject( &bmDrag );
00794
00795 dcDrag.FillSolidRect( 0, 0, rcAll.Width(), rcAll.Height(), RGB( 0, 255, 0 ) );
00796
00797 CRgn pRgn;
00798
00799 if ( bClipped )
00800 {
00801 CPoint ptMiddle( ptMouse.x - rcAll.left, ptMouse.y - rcAll.top );
00802 pRgn.CreateEllipticRgn( ptMiddle.x - MAX_DRAG_SIZE_2, ptMiddle.y - MAX_DRAG_SIZE_2,
00803 ptMiddle.x + MAX_DRAG_SIZE_2, ptMiddle.y + MAX_DRAG_SIZE_2 );
00804 dcDrag.SelectClipRgn( &pRgn );
00805 }
00806
00807 CDC* pBuffer = CoolInterface.GetBuffer( dcClient, m_szBlock );
00808 CRect rcBuffer( 0, 0, m_szBlock.cx, m_szBlock.cy );
00809
00810 CFont* pOldFont = (CFont*)pBuffer->SelectObject( &CoolInterface.m_fntNormal );
00811
00812 for ( POSITION pos = m_pSelThumb.GetHeadPosition() ; pos ; )
00813 {
00814 CLibraryThumbItem* pThumb = (CLibraryThumbItem*)m_pSelThumb.GetNext( pos );
00815 GetItemRect( pThumb, &rcOne );
00816 CRect rcDummy;
00817
00818 if ( rcDummy.IntersectRect( &rcAll, &rcOne ) )
00819 {
00820 pBuffer->FillSolidRect( &rcBuffer, RGB( 0, 255, 0 ) );
00821 pThumb->Paint( pBuffer, rcBuffer, m_szThumb, &dcMem );
00822 dcDrag.BitBlt( rcOne.left - rcAll.left, rcOne.top - rcAll.top,
00823 m_szBlock.cx, m_szBlock.cy, pBuffer, 0, 0, SRCCOPY );
00824 }
00825 }
00826
00827 pBuffer->SelectObject( pOldFont );
00828
00829 dcDrag.SelectObject( pOldDrag );
00830
00831 dcDrag.DeleteDC();
00832
00833 CImageList* pAll = new CImageList();
00834 pAll->Create( rcAll.Width(), rcAll.Height(), ILC_COLOR16|ILC_MASK, 1, 1 );
00835 pAll->Add( &bmDrag, RGB( 0, 255, 0 ) );
00836
00837 bmDrag.DeleteObject();
00838
00839 pAll->BeginDrag( 0, ptMouse - rcAll.TopLeft() );
00840
00841 return pAll;
00842 }
00843
00845
00846
00847 void CLibraryThumbView::StartThread()
00848 {
00849 CSingleLock pLock( &m_pSection, TRUE );
00850
00851 if ( m_hThread != NULL && m_bThread ) return;
00852
00853 CLibraryThumbItem** pList = m_pList;
00854 int nCount = 0;
00855
00856 for ( int nItem = m_nCount ; nItem ; nItem--, pList++ )
00857 {
00858 if ( (*pList)->m_nThumb == CLibraryThumbItem::thumbWaiting ) nCount++;
00859 }
00860
00861 if ( nCount == 0 )
00862 return;
00863 else if ( m_hThread != NULL && m_bThread )
00864 {
00865
00866
00867 StopThread();
00868 }
00869 else if ( m_hThread != NULL )
00870 {
00871 DWORD nCode;
00872 if ( GetExitCodeThread( m_hThread, &nCode ) ) Sleep( 100 );
00873 ASSERT( m_bThread == FALSE );
00874 }
00875
00876 m_bThread = TRUE;
00877 CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_IDLE );
00878 m_hThread = pThread->m_hThread;
00879 }
00880
00881 void CLibraryThumbView::StopThread()
00882 {
00883
00884
00885 CSingleLock pLock( &m_pSection, TRUE );
00886 if ( m_hThread == NULL || ! m_bThread ) return;
00887
00888 m_bThread = FALSE;
00889
00890 int nAttempt = 100;
00891 for ( ; nAttempt > 0 ; nAttempt-- )
00892 {
00893 DWORD nCode;
00894
00895 if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
00896 if ( nCode != STILL_ACTIVE ) break;
00897 Sleep( 100 );
00898 }
00899
00900 if ( nAttempt == 0 )
00901 {
00902 TerminateThread( m_hThread, 0 );
00903 theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CLibraryThumbView thread.") );
00904 Sleep( 100 );
00905 }
00906
00907 m_hThread = NULL;
00908 }
00909
00910 UINT CLibraryThumbView::ThreadStart(LPVOID pParam)
00911 {
00912 CLibraryThumbView* pView = (CLibraryThumbView*)pParam;
00913 pView->OnRun();
00914 return 0;
00915 }
00916
00917 void CLibraryThumbView::OnRun()
00918 {
00919 CSingleLock pLock( &m_pSection );
00920 CImageServices pServices;
00921 CThumbCache pCache;
00922
00923 while ( m_bThread )
00924 {
00925 CLibraryThumbItem* pThumb = NULL;
00926 DWORD nIndex = 0;
00927 CString strPath;
00928 BOOL bCache;
00929
00930 pLock.Lock();
00931
00932 CLibraryThumbItem** pList = m_pList;
00933 for ( int nItem = m_nCount ; nItem ; nItem--, pList++ )
00934 {
00935 if ( (*pList)->m_nThumb == CLibraryThumbItem::thumbWaiting )
00936 {
00937 CQuickLock oLock( Library.m_pSection );
00938 if ( CLibraryFile* pFile = Library.LookupFile( (*pList)->m_nIndex ) )
00939 {
00940 pThumb = *pList;
00941 nIndex = pFile->m_nIndex;
00942 strPath = pFile->GetPath();
00943 bCache = pFile->m_bCachedPreview;
00944 break;
00945 }
00946 }
00947 }
00948
00949 pLock.Unlock();
00950
00951 if ( pThumb == NULL ) break;
00952 pThumb = NULL;
00953
00954 DWORD tNow = GetTickCount();
00955
00956 CImageFile pFile( &pServices );
00957 BOOL bSuccess = FALSE;
00958 CSize Size( THUMB_STORE_SIZE, THUMB_STORE_SIZE );
00959
00960 if ( pCache.Load( strPath, &Size, nIndex, &pFile ) )
00961 {
00962 int nSize = m_szThumb.cy * pFile.m_nWidth / pFile.m_nHeight;
00963
00964 if ( nSize > m_szThumb.cx )
00965 {
00966 nSize = m_szThumb.cx * pFile.m_nHeight / pFile.m_nWidth;
00967 pFile.Resample( m_szThumb.cx, nSize );
00968 }
00969 else
00970 {
00971 pFile.Resample( nSize, m_szThumb.cy );
00972 }
00973
00974 bSuccess = TRUE;
00975 }
00976 else if ( pFile.LoadFromFile( strPath, FALSE, TRUE ) && pFile.EnsureRGB() )
00977 {
00978 int nSize = THUMB_STORE_SIZE * pFile.m_nWidth / pFile.m_nHeight;
00979
00980 if ( ! m_bThread ) break;
00981
00982 if ( nSize > THUMB_STORE_SIZE )
00983 {
00984 nSize = THUMB_STORE_SIZE * pFile.m_nHeight / pFile.m_nWidth;
00985 pFile.Resample( THUMB_STORE_SIZE, nSize );
00986 }
00987 else
00988 {
00989 pFile.Resample( nSize, THUMB_STORE_SIZE );
00990 }
00991
00992 if ( ! m_bThread ) break;
00993
00994 pCache.Store( strPath, &Size, nIndex, &pFile );
00995
00996
00997 nSize = m_szThumb.cy * pFile.m_nWidth / pFile.m_nHeight;
00998
00999 if ( nSize > m_szThumb.cx )
01000 {
01001 nSize = m_szThumb.cx * pFile.m_nHeight / pFile.m_nWidth;
01002 pFile.Resample( m_szThumb.cx, nSize );
01003 }
01004 else
01005 {
01006 pFile.Resample( nSize, m_szThumb.cy );
01007 }
01008
01009 bSuccess = TRUE;
01010 }
01011
01012 pLock.Lock();
01013
01014 pList = m_pList;
01015 for ( int nItem = m_nCount ; nItem ; nItem--, pList++ )
01016 {
01017 if ( (*pList)->m_nIndex == nIndex )
01018 {
01019 pThumb = *pList;
01020 break;
01021 }
01022 }
01023
01024 if ( pThumb )
01025 {
01026 if ( pThumb->m_bmThumb.m_hObject ) pThumb->m_bmThumb.DeleteObject();
01027
01028 if ( bSuccess )
01029 {
01030 pThumb->m_bmThumb.Attach( pFile.CreateBitmap() );
01031 pThumb->m_szThumb.cx = pFile.m_nWidth;
01032 pThumb->m_szThumb.cy = pFile.m_nHeight;
01033 pThumb->m_nThumb = CLibraryThumbItem::thumbValid;
01034 }
01035 else
01036 {
01037 pThumb->m_nThumb = CLibraryThumbItem::thumbError;
01038 }
01039
01040 m_nInvalidate++;
01041 }
01042
01043 pLock.Unlock();
01044
01045 if ( bSuccess && ! bCache )
01046 {
01047 CQuickLock oLock( Library.m_pSection );
01048 if ( CLibraryFile* pFile = Library.LookupFile( nIndex ) )
01049 {
01050 pFile->m_bCachedPreview = TRUE;
01051 }
01052 }
01053
01054 if ( ! m_bRush )
01055 {
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066 }
01067 }
01068 m_bThread = FALSE;
01069 }
01070
01071
01073
01074
01075 CLibraryThumbItem::CLibraryThumbItem(CLibraryFile* pFile)
01076 {
01077 m_nIndex = pFile->m_nIndex;
01078 m_nCookie = pFile->m_nUpdateCookie;
01079 m_sText = pFile->m_sName;
01080 m_bShared = pFile->IsShared();
01081 m_bSelected = FALSE;
01082 m_nThumb = 0;
01083 m_nShell = ShellIcons.Get( m_sText, THUMB_ICON );
01084 }
01085
01086 CLibraryThumbItem::~CLibraryThumbItem()
01087 {
01088 }
01089
01091
01092
01093 BOOL CLibraryThumbItem::Update(CLibraryFile* pFile)
01094 {
01095 BOOL bShared = pFile->IsShared();
01096
01097 if ( m_nCookie == pFile->m_nUpdateCookie && m_bShared == bShared ) return FALSE;
01098
01099 m_nCookie = pFile->m_nUpdateCookie;
01100 m_sText = pFile->m_sName;
01101 m_bShared = bShared;
01102
01103 m_nThumb = thumbWaiting;
01104 if ( m_bmThumb.m_hObject ) m_bmThumb.DeleteObject();
01105
01106 return TRUE;
01107 }
01108
01110
01111
01112 void CLibraryThumbItem::Paint(CDC* pDC, const CRect& rcBlock, const CSize& szThumb, CDC* pMemDC)
01113 {
01114 CRect rcThumb;
01115
01116 rcThumb.left = ( rcBlock.left + rcBlock.right ) / 2 - szThumb.cx / 2;
01117 rcThumb.right = rcThumb.left + szThumb.cx;
01118 rcThumb.top = rcBlock.top + 7;
01119 rcThumb.bottom = rcThumb.top + szThumb.cy;
01120
01121 CRect rcFrame( &rcThumb );
01122
01123 if ( m_bSelected )
01124 {
01125 for ( int nBorder = 3 ; nBorder ; nBorder-- )
01126 {
01127 rcFrame.InflateRect( 1, 1 );
01128 pDC->Draw3dRect( &rcFrame, CoolInterface.m_crHighlight, CoolInterface.m_crHighlight );
01129 }
01130 }
01131 else
01132 {
01133 rcFrame.InflateRect( 1, 1 );
01134 pDC->Draw3dRect( &rcFrame, CoolInterface.m_crMargin, CoolInterface.m_crMargin );
01135 }
01136
01137 if ( m_bmThumb.m_hObject != NULL )
01138 {
01139 pMemDC->SelectObject( &m_bmThumb );
01140
01141 CPoint ptImage( ( rcThumb.left + rcThumb.right ) / 2 - m_szThumb.cx / 2,
01142 ( rcThumb.top + rcThumb.bottom ) / 2 - m_szThumb.cy / 2 );
01143
01144 pDC->BitBlt( ptImage.x, ptImage.y, m_szThumb.cx, m_szThumb.cy,
01145 pMemDC, 0, 0, SRCCOPY );
01146 }
01147 else
01148 {
01149 if ( m_nThumb == thumbWaiting )
01150 pDC->FillSolidRect( &rcThumb, RGB( 255, 255, 255 ) );
01151 else
01152 pDC->FillSolidRect( &rcThumb, CoolInterface.m_crBackNormal );
01153
01154 ImageList_DrawEx( ShellIcons.GetHandle( THUMB_ICON ), m_nShell, pDC->GetSafeHdc(),
01155 ( rcThumb.left + rcThumb.right ) / 2 - THUMB_ICON / 2,
01156 ( rcThumb.top + rcThumb.bottom ) / 2 - THUMB_ICON / 2,
01157 THUMB_ICON, THUMB_ICON, CLR_NONE, CLR_NONE, ILD_NORMAL );
01158 }
01159
01160 if ( m_bSelected )
01161 {
01162 pDC->SetBkColor( CoolInterface.m_crHighlight );
01163 pDC->SetTextColor( CoolInterface.m_crHiText );
01164 }
01165 else if ( ! m_bShared )
01166 {
01167 pDC->SetBkColor( CoolInterface.m_crWindow );
01168 pDC->SetTextColor( CoolInterface.m_crHighlight );
01169 }
01170 else
01171 {
01172 pDC->SetBkColor( CoolInterface.m_crWindow );
01173 pDC->SetTextColor( CoolInterface.m_crText );
01174 }
01175
01176 rcThumb.top = rcThumb.bottom + 4;
01177 rcThumb.bottom = rcThumb.top + 27;
01178 rcThumb.left -= 3;
01179 rcThumb.right += 3;
01180
01181 CSize szText = pDC->GetTextExtent( m_sText );
01182
01183 if ( szText.cx < rcThumb.Width() - 4 )
01184 {
01185 rcThumb.left = ( rcThumb.left + rcThumb.right ) / 2 - szText.cx / 2 - 2;
01186 rcThumb.right = rcThumb.left + szText.cx + 4;
01187 rcThumb.bottom = rcThumb.top + szText.cy + 2;
01188 pDC->FillSolidRect( &rcThumb, pDC->GetBkColor() );
01189 pDC->ExtTextOut( rcThumb.left + 2, rcThumb.top, ETO_CLIPPED|ETO_OPAQUE,
01190 &rcThumb, m_sText, NULL );
01191 }
01192 else
01193 {
01194 int nSaveX = rcThumb.right;
01195 int nSaveY = rcThumb.bottom;
01196 int nHeight = pDC->DrawText( m_sText, &rcThumb, DT_CENTER|DT_WORDBREAK|DT_CALCRECT|DT_NOPREFIX );
01197 rcThumb.bottom = min( LONG(nSaveY), rcThumb.top + nHeight + 2 );
01198 rcThumb.right = nSaveX;
01199 pDC->FillSolidRect( &rcThumb, pDC->GetBkColor() );
01200 pDC->DrawText( m_sText, &rcThumb, DT_CENTER|DT_WORDBREAK|DT_NOPREFIX );
01201 }
01202 }
01203