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 "CoolInterface.h"
00026 #include "ShellIcons.h"
00027 #include "Library.h"
00028 #include "LibraryFolders.h"
00029 #include "CtrlLibraryTree.h"
00030 #include "CtrlLibraryFrame.h"
00031 #include "CtrlCoolTip.h"
00032 #include "SharedFolder.h"
00033 #include "AlbumFolder.h"
00034 #include "Schema.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_DYNAMIC(CLibraryTreeCtrl, CWnd)
00043
00044 BEGIN_MESSAGE_MAP(CLibraryTreeCtrl, CWnd)
00045
00046 ON_WM_SIZE()
00047 ON_WM_VSCROLL()
00048 ON_WM_ERASEBKGND()
00049 ON_WM_PAINT()
00050 ON_WM_LBUTTONDOWN()
00051 ON_WM_LBUTTONDBLCLK()
00052 ON_WM_MOUSEWHEEL()
00053 ON_WM_KEYDOWN()
00054 ON_WM_RBUTTONDOWN()
00055 ON_WM_MOUSEMOVE()
00056 ON_WM_LBUTTONUP()
00057
00058 END_MESSAGE_MAP()
00059
00060 #define ITEM_HEIGHT 16
00061
00062
00064
00065
00066 CLibraryTreeCtrl::CLibraryTreeCtrl()
00067 {
00068 m_pRoot = new CLibraryTreeItem();
00069 m_pRoot->m_bExpanded = TRUE;
00070
00071 m_nTotal = 0;
00072 m_nVisible = 0;
00073 m_nScroll = 0;
00074 m_nSelected = 0;
00075 m_pSelFirst = NULL;
00076 m_pSelLast = NULL;
00077 m_pFocus = NULL;
00078 m_bDrag = FALSE;
00079 m_pDropItem = NULL;
00080 m_nCleanCookie = 0;
00081 m_pTip = NULL;
00082 }
00083
00084 CLibraryTreeCtrl::~CLibraryTreeCtrl()
00085 {
00086 delete m_pRoot;
00087 }
00088
00090
00091
00092 BOOL CLibraryTreeCtrl::Create(CWnd* pParentWnd)
00093 {
00094 CRect rect;
00095 return CWnd::Create( NULL, _T("CLibraryTreeCtrl"),
00096 WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL, rect, pParentWnd, IDC_LIBRARY_TREE, NULL );
00097 }
00098
00099 void CLibraryTreeCtrl::SetToolTip(CCoolTipCtrl* pTip)
00100 {
00101 if ( m_pTip ) m_pTip->Hide();
00102 m_pTip = pTip;
00103 if ( m_pTip ) m_pTip->SetOwner( this );
00104 }
00105
00106 void CLibraryTreeCtrl::Clear()
00107 {
00108 if ( m_pRoot->m_nCount == 0 ) return;
00109
00110 m_pRoot->Clear();
00111
00112 m_nTotal = 0;
00113 m_nSelected = 0;
00114 m_pSelFirst = NULL;
00115 m_pSelLast = NULL;
00116 m_pFocus = NULL;
00117 m_pDropItem = NULL;
00118
00119 if ( m_pTip ) m_pTip->Hide();
00120
00121
00122 UpdateScroll();
00123 Invalidate();
00124 }
00125
00127
00128
00129 BOOL CLibraryTreeCtrl::Expand(CLibraryTreeItem* pItem, TRISTATE bExpand, BOOL bInvalidate)
00130 {
00131 if ( pItem == NULL ) return FALSE;
00132
00133 switch ( bExpand )
00134 {
00135 case TS_UNKNOWN:
00136 pItem->m_bExpanded = ! pItem->m_bExpanded;
00137 break;
00138 case TS_TRUE:
00139 if ( pItem->m_bExpanded ) return FALSE;
00140 pItem->m_bExpanded = TRUE;
00141 break;
00142 case TS_FALSE:
00143 if ( ! pItem->m_bExpanded ) return FALSE;
00144 pItem->m_bExpanded = FALSE;
00145 break;
00146 }
00147
00148 if ( pItem->m_pPhysical )
00149 {
00150 pItem->m_pPhysical->m_bExpanded = pItem->m_bExpanded;
00151 }
00152 else
00153 {
00154 pItem->m_pVirtual->m_bExpanded = pItem->m_bExpanded;
00155 }
00156
00157 if ( ! pItem->IsVisible() ) return FALSE;
00158
00159 if ( pItem->m_bExpanded )
00160 {
00161 m_nTotal += pItem->GetChildCount();
00162 }
00163 else
00164 {
00165 m_nTotal -= pItem->GetChildCount();
00166 DeselectAll( NULL, pItem, FALSE );
00167 }
00168
00169 pItem->m_bContract1 = pItem->m_bExpanded == TRUE && bExpand == TS_TRUE && bInvalidate == FALSE;
00170
00171 if ( pItem->m_bContract1 == FALSE )
00172 {
00173 for ( CLibraryTreeItem* pParent = pItem ; pParent != NULL ; pParent = pParent->m_pParent )
00174 pParent->m_bContract1 = FALSE;
00175 }
00176
00177 if ( bInvalidate )
00178 {
00179 UpdateScroll();
00180 Invalidate();
00181 }
00182
00183 return TRUE;
00184 }
00185
00186 BOOL CLibraryTreeCtrl::CollapseRecursive(CLibraryTreeItem* pItem)
00187 {
00188 BOOL bChanged = FALSE;
00189
00190 if ( pItem != m_pRoot && pItem->m_bExpanded && pItem->m_bContract1 )
00191 {
00192 bChanged |= Expand( pItem, TS_FALSE, FALSE );
00193 }
00194
00195 CLibraryTreeItem** pChild = pItem->m_pList;
00196
00197 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00198 {
00199 bChanged |= CollapseRecursive( *pChild );
00200 }
00201
00202 return bChanged;
00203 }
00204
00206
00207
00208 BOOL CLibraryTreeCtrl::Select(CLibraryTreeItem* pItem, TRISTATE bSelect, BOOL bInvalidate)
00209 {
00210 if ( pItem == NULL ) return FALSE;
00211
00212 switch ( bSelect )
00213 {
00214 case TS_UNKNOWN:
00215 pItem->m_bSelected = ! pItem->m_bSelected;
00216 break;
00217 case TS_TRUE:
00218 if ( pItem->m_bSelected ) return FALSE;
00219 pItem->m_bSelected = TRUE;
00220 break;
00221 case TS_FALSE:
00222 if ( ! pItem->m_bSelected ) return FALSE;
00223 pItem->m_bSelected = FALSE;
00224 break;
00225 }
00226
00227 if ( pItem->m_bSelected )
00228 {
00229 m_nSelected++;
00230
00231 if ( m_pSelLast )
00232 {
00233 m_pSelLast->m_pSelNext = pItem;
00234 pItem->m_pSelPrev = m_pSelLast;
00235 pItem->m_pSelNext = NULL;
00236 m_pSelLast = pItem;
00237 }
00238 else
00239 {
00240 m_pSelFirst = m_pSelLast = pItem;
00241 pItem->m_pSelPrev = pItem->m_pSelNext = NULL;
00242 }
00243 }
00244 else
00245 {
00246 m_nSelected--;
00247
00248 if ( pItem->m_pSelPrev )
00249 pItem->m_pSelPrev->m_pSelNext = pItem->m_pSelNext;
00250 else
00251 m_pSelFirst = pItem->m_pSelNext;
00252
00253 if ( pItem->m_pSelNext )
00254 pItem->m_pSelNext = pItem->m_pSelNext->m_pSelPrev = pItem->m_pSelPrev;
00255 else
00256 m_pSelLast = pItem->m_pSelPrev;
00257 }
00258
00259 if ( pItem->IsVisible() )
00260 {
00261 if ( bInvalidate ) Invalidate();
00262 return TRUE;
00263 }
00264 else
00265 {
00266 return FALSE;
00267 }
00268 }
00269
00270 BOOL CLibraryTreeCtrl::SelectAll(CLibraryTreeItem* pParent, BOOL bInvalidate)
00271 {
00272 if ( pParent == NULL ) pParent = m_pRoot;
00273 else if ( pParent->m_bExpanded == FALSE ) return FALSE;
00274
00275 CLibraryTreeItem** pChild = pParent->m_pList;
00276 BOOL bChanged = FALSE;
00277
00278 for ( int nCount = pParent->m_nCount ; nCount ; nCount--, pChild++ )
00279 {
00280 if ( (*pChild)->m_bSelected == FALSE )
00281 {
00282 Select( *pChild, TS_TRUE, FALSE );
00283 bChanged = TRUE;
00284 }
00285
00286 if ( (*pChild)->m_bExpanded && (*pChild)->m_nCount )
00287 {
00288 bChanged |= SelectAll( *pChild, FALSE );
00289 }
00290 }
00291
00292 if ( bInvalidate && bChanged && pParent == m_pRoot ) Invalidate();
00293
00294 return bChanged;
00295 }
00296
00297 BOOL CLibraryTreeCtrl::DeselectAll(CLibraryTreeItem* pExcept, CLibraryTreeItem* pParent, BOOL bInvalidate)
00298 {
00299 if ( pParent == NULL ) pParent = m_pRoot;
00300
00301 CLibraryTreeItem** pChild = pParent->m_pList;
00302 BOOL bChanged = FALSE;
00303
00304 for ( int nCount = pParent->m_nCount ; nCount ; nCount--, pChild++ )
00305 {
00306 if ( *pChild != pExcept && (*pChild)->m_bSelected )
00307 {
00308 Select( *pChild, TS_FALSE, FALSE );
00309 bChanged = TRUE;
00310 }
00311
00312 if ( (*pChild)->m_nCount ) bChanged |= DeselectAll( pExcept, *pChild, FALSE );
00313 }
00314
00315 if ( bInvalidate && bChanged && pParent == m_pRoot ) Invalidate();
00316
00317 return bChanged;
00318 }
00319
00320 int CLibraryTreeCtrl::GetSelectedCount() const
00321 {
00322 return m_nSelected;
00323 }
00324
00325 CLibraryTreeItem* CLibraryTreeCtrl::GetFirstSelected() const
00326 {
00327 return m_pSelFirst;
00328 }
00329
00330 CLibraryTreeItem* CLibraryTreeCtrl::GetLastSelected() const
00331 {
00332 return m_pSelLast;
00333 }
00334
00335 BOOL CLibraryTreeCtrl::Highlight(CLibraryTreeItem* pItem)
00336 {
00337 m_pFocus = pItem;
00338
00339 for ( CLibraryTreeItem* pParent = m_pFocus->m_pParent ; pParent ; pParent = pParent->m_pParent )
00340 {
00341 Expand( pParent, TS_TRUE, FALSE );
00342
00343 pParent->m_bContract2 = pParent->m_bContract1;
00344 pParent->m_bContract1 = FALSE;
00345 }
00346
00347 CollapseRecursive( m_pRoot );
00348
00349 for ( CLibraryTreeItem* pParent = m_pFocus->m_pParent ; pParent ; pParent = pParent->m_pParent )
00350 {
00351 pParent->m_bContract1 = pParent->m_bContract2;
00352 }
00353
00354 CRect rcItem, rcClient;
00355
00356 if ( GetRect( m_pFocus, &rcItem ) )
00357 {
00358 GetClientRect( &rcClient );
00359
00360 if ( rcItem.top <= rcClient.top )
00361 ScrollBy( rcItem.top - rcClient.top );
00362 else if ( rcItem.bottom > rcClient.bottom )
00363 ScrollBy( rcItem.bottom - rcClient.bottom );
00364 }
00365
00366 UpdateScroll();
00367 Invalidate();
00368
00369 return TRUE;
00370 }
00371
00373
00374
00375 BOOL CLibraryTreeCtrl::CleanItems(CLibraryTreeItem* pItem, DWORD nCookie, BOOL bVisible)
00376 {
00377 CLibraryTreeItem** pChild = pItem->m_pList + pItem->m_nCount - 1;
00378 BOOL bChanged = FALSE;
00379
00380 for ( int nChild = pItem->m_nCount ; nChild ; nChild--, pChild-- )
00381 {
00382 if ( (*pChild)->m_nCleanCookie != nCookie )
00383 {
00384 if ( m_pFocus == *pChild ) m_pFocus = NULL;
00385
00386 if ( (*pChild)->m_bSelected ) Select( *pChild, TS_FALSE, FALSE );
00387 bChanged |= DeselectAll( NULL, *pChild, FALSE );
00388
00389 if ( bVisible )
00390 {
00391 m_nTotal -= (*pChild)->GetChildCount() + 1;
00392 bChanged = TRUE;
00393 }
00394
00395 delete *pChild;
00396 MoveMemory( pChild, pChild + 1, 4 * ( pItem->m_nCount - nChild ) );
00397 pItem->m_nCount--;
00398 }
00399 }
00400
00401 return bChanged;
00402 }
00403
00404 void CLibraryTreeCtrl::NotifySelection()
00405 {
00406 if (!m_hWnd) return;
00407 NMHDR pNM = { GetSafeHwnd(), GetDlgCtrlID(), LTN_SELCHANGED };
00408 GetOwner()->SendMessage( WM_NOTIFY, pNM.idFrom, (LPARAM)&pNM );
00409 }
00410
00412
00413
00414 CLibraryTreeItem* CLibraryTreeCtrl::GetFolderItem(LPVOID pSearch, CLibraryTreeItem* pParent)
00415 {
00416 if ( pParent == NULL ) pParent = m_pRoot;
00417
00418 CLibraryTreeItem** pChild = pParent->m_pList;
00419
00420 for ( int nChild = pParent->m_nCount ; nChild ; nChild--, pChild++ )
00421 {
00422 if ( pSearch == (*pChild)->m_pPhysical ) return *pChild;
00423 if ( pSearch == (*pChild)->m_pVirtual ) return *pChild;
00424
00425 if ( (*pChild)->m_nCount )
00426 {
00427 CLibraryTreeItem* pFound = GetFolderItem( pSearch, *pChild );
00428 if ( pFound ) return pFound;
00429 }
00430 }
00431
00432 return NULL;
00433 }
00434
00436
00437
00438 void CLibraryTreeCtrl::OnSize(UINT nType, int cx, int cy)
00439 {
00440 CWnd::OnSize( nType, cx, cy );
00441
00442 m_nVisible = cy;
00443
00444 UpdateScroll();
00445 }
00446
00447 void CLibraryTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
00448 {
00449 CRect rc;
00450 CLibraryTreeItem* pHit = HitTest( point, &rc );
00451 BOOL bChanged = FALSE;
00452
00453 SetFocus();
00454
00455 if ( m_pTip ) m_pTip->Hide();
00456
00457 if ( pHit && pHit->m_nCount && point.x >= rc.left && point.x < rc.left + 16 )
00458 {
00459 bChanged = Expand( pHit, TS_UNKNOWN );
00460 }
00461 else if ( nFlags & MK_CONTROL )
00462 {
00463 if ( pHit ) bChanged = Select( pHit, TS_UNKNOWN );
00464 }
00465 else if ( nFlags & MK_SHIFT )
00466 {
00467 if ( pHit ) bChanged = Select( pHit );
00468 }
00469 else
00470 {
00471 if ( ( nFlags & MK_RBUTTON ) == 0 || ( pHit && pHit->m_bSelected == FALSE ) )
00472 bChanged = DeselectAll( pHit );
00473 if ( pHit ) bChanged |= Select( pHit );
00474 }
00475
00476 m_pFocus = pHit;
00477
00478 if ( pHit != NULL )
00479 {
00480 if ( m_pFocus->m_pVirtual && ( nFlags & MK_RBUTTON ) == 0 )
00481 {
00482 m_bDrag = TRUE;
00483 m_ptDrag = point;
00484 SetCapture();
00485 }
00486 }
00487
00488 if ( bChanged ) NotifySelection();
00489 }
00490
00491 void CLibraryTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
00492 {
00493 OnLButtonDown( nFlags, point );
00494
00495 if ( m_pFocus != NULL && m_pFocus->m_nCount )
00496 {
00497 if ( Expand( m_pFocus, TS_UNKNOWN ) ) NotifySelection();
00498 }
00499 }
00500
00501 void CLibraryTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point)
00502 {
00503 OnLButtonDown( nFlags, point );
00504 CWnd::OnRButtonDown( nFlags, point );
00505 }
00506
00507 void CLibraryTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
00508 {
00509 if ( m_bDrag & ( nFlags & MK_LBUTTON ) )
00510 {
00511 CSize szDiff = point - m_ptDrag;
00512
00513 if ( abs( szDiff.cx ) > 5 || abs( szDiff.cy ) > 5 )
00514 {
00515 m_bDrag = FALSE;
00516 StartDragging( point );
00517 }
00518 }
00519 else if ( m_pTip != NULL )
00520 {
00521 if ( CLibraryTreeItem* pItem = HitTest( point ) )
00522 {
00523 m_pTip->Show( pItem->m_pPhysical ? (LPVOID)pItem->m_pPhysical : (LPVOID)pItem->m_pVirtual );
00524 }
00525 else
00526 {
00527 m_pTip->Hide();
00528 }
00529 }
00530
00531 CWnd::OnMouseMove( nFlags, point );
00532 }
00533
00534 void CLibraryTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
00535 {
00536 ReleaseCapture();
00537 m_bDrag = FALSE;
00538
00539 CWnd::OnLButtonUp( nFlags, point );
00540 }
00541
00542 void CLibraryTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
00543 {
00544 CLibraryTreeItem* pTo = NULL;
00545 BOOL bChanged = FALSE;
00546 CRect rc;
00547
00548 if ( m_pTip ) m_pTip->Hide();
00549
00550 if ( nChar == VK_HOME || ( nChar == VK_UP && m_pFocus == NULL ) )
00551 {
00552 if ( m_pRoot->m_nCount ) pTo = m_pRoot->m_pList[0];
00553 }
00554 else if ( nChar == VK_END || ( nChar == VK_DOWN && m_pFocus == NULL ) )
00555 {
00556 if ( m_pRoot->m_nCount ) pTo = m_pRoot->m_pList[ m_pRoot->m_nCount - 1 ];
00557 }
00558 else if ( nChar == VK_UP && m_pFocus != NULL )
00559 {
00560 if ( GetRect( m_pFocus, &rc ) )
00561 {
00562 CPoint pt( rc.left, ( rc.top + rc.bottom ) / 2 );
00563 pt.y -= ITEM_HEIGHT;
00564 pTo = HitTest( pt );
00565 }
00566 }
00567 else if ( nChar == VK_DOWN && m_pFocus != NULL )
00568 {
00569 if ( GetRect( m_pFocus, &rc ) )
00570 {
00571 CPoint pt( rc.left, ( rc.top + rc.bottom ) / 2 );
00572 pt.y += ITEM_HEIGHT;
00573 pTo = HitTest( pt );
00574 }
00575 }
00576 else if ( ( nChar == VK_LEFT || nChar == VK_SUBTRACT ) && m_pFocus != NULL )
00577 {
00578 while ( TRUE )
00579 {
00580 if ( m_pFocus->m_bExpanded && m_pFocus->m_nCount )
00581 {
00582 Expand( m_pFocus, TS_FALSE );
00583 break;
00584 }
00585
00586 if ( m_pFocus->m_pParent == m_pRoot ) break;
00587 m_pFocus = m_pFocus->m_pParent;
00588
00589 bChanged |= DeselectAll( m_pFocus );
00590 bChanged |= Select( m_pFocus );
00591 }
00592
00593 Highlight( m_pFocus );
00594 }
00595 else if ( ( nChar == VK_RIGHT || nChar == VK_ADD ) && m_pFocus != NULL )
00596 {
00597 if ( ! m_pFocus->m_bExpanded && m_pFocus->m_nCount )
00598 {
00599 bChanged |= Expand( m_pFocus, TS_TRUE );
00600 }
00601 }
00602 else if ( _istalnum( nChar ) )
00603 {
00604 CLibraryTreeItem* pStart = m_pFocus;
00605 CLibraryTreeItem* pBase = pStart ? pStart->m_pParent : m_pRoot;
00606
00607 for ( int nLoop = 0 ; nLoop < 2 ; nLoop++ )
00608 {
00609 CLibraryTreeItem** pChild = pBase->m_pList;
00610
00611 for ( int nCount = pBase->m_nCount ; nCount ; nCount--, pChild++ )
00612 {
00613 if ( pStart != NULL )
00614 {
00615 if ( pStart == *pChild ) pStart = NULL;
00616 }
00617 else if ( toupper( (*pChild)->m_sText.GetAt( 0 ) ) == (int)nChar )
00618 {
00619 DeselectAll( m_pFocus = *pChild, NULL, FALSE );
00620 Select( m_pFocus, TS_TRUE, FALSE );
00621 Highlight( m_pFocus );
00622 NotifySelection();
00623 return;
00624 }
00625 }
00626 }
00627 }
00628
00629 if ( pTo != NULL )
00630 {
00631 if ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 || m_pFocus == NULL )
00632 {
00633 bChanged |= DeselectAll( m_pFocus = pTo );
00634 bChanged |= Select( m_pFocus );
00635 }
00636 else
00637 {
00638 bChanged |= Select( m_pFocus = pTo );
00639 }
00640
00641 Highlight( m_pFocus );
00642 }
00643
00644 if ( bChanged ) NotifySelection();
00645 }
00646
00648
00649
00650 void CLibraryTreeCtrl::UpdateScroll()
00651 {
00652 SCROLLINFO pInfo;
00653
00654 pInfo.cbSize = sizeof(pInfo);
00655 pInfo.fMask = SIF_ALL & ~SIF_TRACKPOS;
00656 pInfo.nMin = 0;
00657 pInfo.nMax = m_nTotal * ITEM_HEIGHT;
00658 pInfo.nPage = m_nVisible;
00659 pInfo.nPos = m_nScroll = max( 0, min( m_nScroll, pInfo.nMax - (int)pInfo.nPage + 1 ) );
00660
00661 SetScrollInfo( SB_VERT, &pInfo, TRUE );
00662 }
00663
00664 void CLibraryTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
00665 {
00666 switch ( nSBCode )
00667 {
00668 case SB_BOTTOM:
00669 ScrollTo( 0xFFFFFFFF );
00670 break;
00671 case SB_LINEDOWN:
00672 ScrollBy( 16 );
00673 break;
00674 case SB_LINEUP:
00675 ScrollBy( -16 );
00676 break;
00677 case SB_PAGEDOWN:
00678 ScrollBy( m_nVisible );
00679 break;
00680 case SB_PAGEUP:
00681 ScrollBy( -m_nVisible );
00682 break;
00683 case SB_THUMBPOSITION:
00684 case SB_THUMBTRACK:
00685 ScrollTo( nPos );
00686 break;
00687 case SB_TOP:
00688 ScrollTo( 0 );
00689 break;
00690 }
00691 }
00692
00693 BOOL CLibraryTreeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
00694 {
00695 ScrollBy( zDelta * 3 * -ITEM_HEIGHT / WHEEL_DELTA );
00696 return TRUE;
00697 }
00698
00699 void CLibraryTreeCtrl::ScrollBy(int nDelta)
00700 {
00701 ScrollTo( max( 0, m_nScroll + nDelta ) );
00702 }
00703
00704 void CLibraryTreeCtrl::ScrollTo(int nPosition)
00705 {
00706 if ( nPosition == m_nScroll ) return;
00707 m_nScroll = nPosition;
00708
00709 UpdateScroll();
00710
00711 CRect rc;
00712 GetClientRect( &rc );
00713 RedrawWindow( &rc, NULL, RDW_INVALIDATE );
00714 }
00715
00717
00718
00719 BOOL CLibraryTreeCtrl::OnEraseBkgnd(CDC* pDC)
00720 {
00721 return TRUE;
00722 }
00723
00724 void CLibraryTreeCtrl::OnPaint()
00725 {
00726 CPaintDC dc( this );
00727
00728 CRect rcClient;
00729 GetClientRect( &rcClient );
00730
00731 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00732
00733 CLibraryTreeItem** pChild = m_pRoot->m_pList;
00734
00735 CFont* pOldFont = (CFont*)dc.SelectObject( &CoolInterface.m_fntNormal );
00736
00737 for ( int nCount = m_pRoot->m_nCount ; nCount && pt.y < rcClient.bottom ; nCount--, pChild++ )
00738 {
00739 Paint( dc, rcClient, pt, *pChild );
00740 }
00741
00742 dc.SelectObject( pOldFont );
00743
00744 dc.FillSolidRect( &rcClient, CoolInterface.m_crWindow );
00745 }
00746
00747 void CLibraryTreeCtrl::Paint(CDC& dc, CRect& rcClient, CPoint& pt, CLibraryTreeItem* pItem)
00748 {
00749 CRect rc( pt.x, pt.y, pt.x, pt.y + ITEM_HEIGHT );
00750 pt.y += ITEM_HEIGHT;
00751
00752 if ( rc.top >= rcClient.bottom )
00753 {
00754 return;
00755 }
00756 else if ( rc.bottom >= rcClient.top )
00757 {
00758 if ( pItem->m_bBold ) dc.SelectObject( &CoolInterface.m_fntBold );
00759
00760 rc.right += 32 + dc.GetTextExtent( pItem->m_sText ).cx + 6;
00761
00762 if ( dc.RectVisible( &rc ) )
00763 {
00764 pItem->Paint( dc, rc, m_pDropItem == pItem );
00765 dc.ExcludeClipRect( &rc );
00766 }
00767
00768 if ( pItem->m_bBold ) dc.SelectObject( &CoolInterface.m_fntNormal );
00769 }
00770
00771 if ( pItem->m_bExpanded && pItem->m_nCount )
00772 {
00773 pt.x += 16;
00774
00775 CLibraryTreeItem** pChild = pItem->m_pList;
00776
00777 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00778 {
00779 Paint( dc, rcClient, pt, *pChild );
00780 if ( pt.y >= rcClient.bottom ) break;
00781 }
00782
00783 pt.x -= 16;
00784 }
00785 }
00786
00788
00789
00790 CLibraryTreeItem* CLibraryTreeCtrl::HitTest(const POINT& point, RECT* pRect) const
00791 {
00792 CRect rcClient;
00793 GetClientRect( &rcClient );
00794
00795 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00796
00797 CLibraryTreeItem** pChild = m_pRoot->m_pList;
00798
00799 for ( int nCount = m_pRoot->m_nCount ; nCount && pt.y < rcClient.bottom ; nCount--, pChild++ )
00800 {
00801 CLibraryTreeItem* pItem = HitTest( rcClient, pt, *pChild, point, pRect );
00802 if ( pItem ) return pItem;
00803 }
00804
00805 return NULL;
00806 }
00807
00808 CLibraryTreeItem* CLibraryTreeCtrl::HitTest(CRect& rcClient, CPoint& pt, CLibraryTreeItem* pItem, const POINT& point, RECT* pRect) const
00809 {
00810 CRect rc( rcClient.left, pt.y, rcClient.right, pt.y + ITEM_HEIGHT );
00811 pt.y += ITEM_HEIGHT;
00812
00813 if ( rc.top >= rcClient.bottom + ITEM_HEIGHT )
00814 {
00815 return NULL;
00816 }
00817 else if ( rc.bottom >= rcClient.top - ITEM_HEIGHT )
00818 {
00819 if ( rc.PtInRect( point ) )
00820 {
00821 if ( pRect )
00822 {
00823 CopyMemory( pRect, &rc, sizeof(RECT) );
00824 pRect->left = pt.x;
00825 }
00826 return pItem;
00827 }
00828 }
00829
00830 if ( pItem->m_bExpanded && pItem->m_nCount )
00831 {
00832 pt.x += 16;
00833
00834 CLibraryTreeItem** pChild = pItem->m_pList;
00835
00836 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00837 {
00838 CLibraryTreeItem* pItem = HitTest( rcClient, pt, *pChild, point, pRect );
00839 if ( pItem ) return pItem;
00840 if ( pt.y >= rcClient.bottom + ITEM_HEIGHT ) break;
00841 }
00842
00843 pt.x -= 16;
00844 }
00845
00846 return NULL;
00847 }
00848
00850
00851
00852 BOOL CLibraryTreeCtrl::GetRect(CLibraryTreeItem* pItem, RECT* pRect)
00853 {
00854 CRect rcClient;
00855 GetClientRect( &rcClient );
00856
00857 CPoint pt( rcClient.left, rcClient.top - m_nScroll );
00858
00859 CLibraryTreeItem** pChild = m_pRoot->m_pList;
00860
00861 for ( int nCount = m_pRoot->m_nCount ; nCount ; nCount--, pChild++ )
00862 {
00863 if ( GetRect( pt, *pChild, pItem, pRect ) ) return TRUE;
00864 }
00865
00866 return FALSE;
00867 }
00868
00869 BOOL CLibraryTreeCtrl::GetRect(CPoint& pt, CLibraryTreeItem* pItem, CLibraryTreeItem* pFind, RECT* pRect)
00870 {
00871 if ( pItem == pFind )
00872 {
00873 pRect->left = pt.x;
00874 pRect->top = pt.y;
00875 pRect->right = pt.x;
00876 pRect->bottom = pt.y = pRect->top + ITEM_HEIGHT;
00877
00878 CClientDC dc( this );
00879 CFont* pOld = (CFont*)dc.SelectObject( pItem->m_bBold ?
00880 &CoolInterface.m_fntBold : &CoolInterface.m_fntNormal );
00881 pRect->right += 33 + dc.GetTextExtent( pItem->m_sText ).cx + 4;
00882 dc.SelectObject( pOld );
00883
00884 return TRUE;
00885 }
00886 else
00887 {
00888 pt.y += ITEM_HEIGHT;
00889 }
00890
00891 if ( pItem->m_bExpanded && pItem->m_nCount )
00892 {
00893 pt.x += 16;
00894
00895 CLibraryTreeItem** pChild = pItem->m_pList;
00896
00897 for ( int nCount = pItem->m_nCount ; nCount ; nCount--, pChild++ )
00898 {
00899 if ( GetRect( pt, *pChild, pFind, pRect ) ) return TRUE;
00900 }
00901
00902 pt.x -= 16;
00903 }
00904
00905 return FALSE;
00906 }
00907
00909
00910
00911 #define MAX_DRAG_SIZE 256
00912 #define MAX_DRAG_SIZE_2 128
00913
00914 void CLibraryTreeCtrl::StartDragging(CPoint& ptMouse)
00915 {
00916 CImageList* pImage = CreateDragImage( ptMouse );
00917 if ( pImage == NULL ) return;
00918
00919 ReleaseCapture();
00920 ClientToScreen( &ptMouse );
00921
00922 CLibraryFrame* pFrame = (CLibraryFrame*)GetOwner();
00923 CLibraryList* pList = new CLibraryList( m_nSelected );
00924
00925 for ( CLibraryTreeItem* pItem = m_pSelFirst ; pItem ;
00926 pItem = pItem->m_pSelNext )
00927 {
00928 if ( pItem->m_pVirtual ) pList->AddTail( (DWORD)pItem->m_pVirtual );
00929 }
00930
00931 pFrame->DragObjects( pList, pImage, ptMouse );
00932 }
00933
00934 CImageList* CLibraryTreeCtrl::CreateDragImage(const CPoint& ptMouse)
00935 {
00936 CRect rcClient, rcOne, rcAll( 32000, 32000, -32000, -32000 );
00937
00938 GetClientRect( &rcClient );
00939
00940 for ( CLibraryTreeItem* pItem = m_pSelFirst ; pItem ;
00941 pItem = pItem->m_pSelNext )
00942 {
00943 GetRect( pItem, &rcOne );
00944
00945 if ( rcOne.IntersectRect( &rcClient, &rcOne ) )
00946 {
00947 rcAll.left = min( rcAll.left, rcOne.left );
00948 rcAll.top = min( rcAll.top, rcOne.top );
00949 rcAll.right = max( rcAll.right, rcOne.right );
00950 rcAll.bottom = max( rcAll.bottom, rcOne.bottom );
00951 }
00952 }
00953
00954 BOOL bClipped = rcAll.Height() > MAX_DRAG_SIZE;
00955
00956 if ( bClipped )
00957 {
00958 rcAll.left = max( rcAll.left, ptMouse.x - MAX_DRAG_SIZE_2 );
00959 rcAll.right = max( rcAll.right, ptMouse.x + MAX_DRAG_SIZE_2 );
00960 rcAll.top = max( rcAll.top, ptMouse.y - MAX_DRAG_SIZE_2 );
00961 rcAll.bottom = max( rcAll.bottom, ptMouse.y + MAX_DRAG_SIZE_2 );
00962 }
00963
00964 CClientDC dcClient( this );
00965 CDC dcMem, dcDrag;
00966 CBitmap bmDrag;
00967
00968 if ( ! dcMem.CreateCompatibleDC( &dcClient ) )
00969 return NULL;
00970 if ( ! dcDrag.CreateCompatibleDC( &dcClient ) )
00971 return NULL;
00972 if ( ! bmDrag.CreateCompatibleBitmap( &dcClient, rcAll.Width(), rcAll.Height() ) )
00973 return NULL;
00974
00975 CBitmap *pOldDrag = dcDrag.SelectObject( &bmDrag );
00976
00977 dcDrag.FillSolidRect( 0, 0, rcAll.Width(), rcAll.Height(), RGB( 250, 255, 250 ) );
00978
00979 CRgn pRgn;
00980
00981 if ( bClipped )
00982 {
00983 CPoint ptMiddle( ptMouse.x - rcAll.left, ptMouse.y - rcAll.top );
00984 pRgn.CreateEllipticRgn( ptMiddle.x - MAX_DRAG_SIZE_2, ptMiddle.y - MAX_DRAG_SIZE_2,
00985 ptMiddle.x + MAX_DRAG_SIZE_2, ptMiddle.y + MAX_DRAG_SIZE_2 );
00986 dcDrag.SelectClipRgn( &pRgn );
00987 }
00988
00989 CFont* pOldFont = (CFont*)dcDrag.SelectObject( &CoolInterface.m_fntNormal );
00990
00991 for ( CLibraryTreeItem* pItem = m_pSelFirst ; pItem ; pItem = pItem->m_pSelNext )
00992 {
00993 GetRect( pItem, &rcOne );
00994 CRect rcDummy;
00995
00996 if ( rcDummy.IntersectRect( &rcAll, &rcOne ) )
00997 {
00998 rcOne.OffsetRect( -rcAll.left, -rcAll.top );
00999 pItem->Paint( dcDrag, rcOne, FALSE, RGB( 250, 255, 250 ) );
01000 }
01001 }
01002
01003 dcDrag.SelectObject( pOldFont );
01004 dcDrag.SelectObject( pOldDrag );
01005 dcDrag.DeleteDC();
01006
01007 CImageList* pAll = new CImageList();
01008 pAll->Create( rcAll.Width(), rcAll.Height(), ILC_COLOR16|ILC_MASK, 1, 1 );
01009 pAll->Add( &bmDrag, RGB( 250, 255, 250 ) );
01010
01011 bmDrag.DeleteObject();
01012
01013 pAll->BeginDrag( 0, ptMouse - rcAll.TopLeft() );
01014
01015 return pAll;
01016 }
01017
01018
01020
01021
01022 CLibraryTreeItem::CLibraryTreeItem(CLibraryTreeItem* pParent)
01023 {
01024 m_pParent = pParent;
01025 m_pList = NULL;
01026 m_nCount = 0;
01027 m_nBuffer = 0;
01028 m_pSelPrev = NULL;
01029 m_pSelNext = NULL;
01030 m_nCleanCookie = 0;
01031
01032 m_bExpanded = FALSE;
01033 m_bSelected = FALSE;
01034 m_bContract1 = FALSE;
01035 m_bContract2 = FALSE;
01036
01037 m_pPhysical = NULL;
01038 m_pVirtual = NULL;
01039 m_nCookie = 0;
01040 m_bBold = FALSE;
01041 m_bShared = TRUE;
01042 m_bCollection = FALSE;
01043 m_nIcon16 = -1;
01044 }
01045
01046 CLibraryTreeItem::~CLibraryTreeItem()
01047 {
01048 if ( m_pList )
01049 {
01050 Clear();
01051 delete [] m_pList;
01052 }
01053 }
01054
01056
01057
01058 CLibraryTreeItem* CLibraryTreeItem::Add(LPCTSTR pszName)
01059 {
01060 if ( m_nCount == m_nBuffer )
01061 {
01062 if ( m_nBuffer ) m_nBuffer += min( m_nBuffer, 16 ); else m_nBuffer = 4;
01063
01064 CLibraryTreeItem** pList = new CLibraryTreeItem*[ m_nBuffer ];
01065
01066 if ( m_nCount ) CopyMemory( pList, m_pList, m_nCount * 4 );
01067 if ( m_pList ) delete [] m_pList;
01068
01069 m_pList = pList;
01070 }
01071
01072 if ( m_nCount == 0 ) return m_pList[ m_nCount++ ] = new CLibraryTreeItem( this );
01073
01074 int nFirst = 0;
01075 for ( int nLast = m_nCount - 1 ; nLast >= nFirst ; )
01076 {
01077 int nMiddle = ( nFirst + nLast ) >> 1;
01078
01079 CLibraryTreeItem* pItem = m_pList[ nMiddle ];
01080
01081 if ( _tcsicoll( pszName, pItem->m_sText ) >= 0 )
01082 {
01083 nFirst = nMiddle + 1;
01084 }
01085 else
01086 {
01087 nLast = nMiddle - 1;
01088 }
01089 }
01090
01091 MoveMemory( m_pList + nFirst + 1, m_pList + nFirst, ( m_nCount - nFirst ) << 2 );
01092 m_nCount++;
01093
01094 return m_pList[ nFirst ] = new CLibraryTreeItem( this );
01095 }
01096
01098
01099
01100 void CLibraryTreeItem::Delete()
01101 {
01102 m_pParent->Delete( this );
01103 }
01104
01105 void CLibraryTreeItem::Delete(CLibraryTreeItem* pItem)
01106 {
01107 ASSERT( pItem->m_bSelected == FALSE );
01108
01109 CLibraryTreeItem** pChild = m_pList;
01110
01111 for ( int nChild = m_nCount ; nChild ; nChild--, pChild++ )
01112 {
01113 if ( *pChild == pItem )
01114 {
01115 MoveMemory( pChild, pChild + 1, 4 * ( nChild - 1 ) );
01116 m_nCount--;
01117 break;
01118 }
01119 }
01120
01121 delete pItem;
01122 }
01123
01124 void CLibraryTreeItem::Delete(int nItem)
01125 {
01126 if ( nItem < 0 || nItem >= m_nCount ) return;
01127
01128 ASSERT( m_pList[ nItem ]->m_bSelected == FALSE );
01129 delete m_pList[ nItem ];
01130 MoveMemory( m_pList + nItem, m_pList + nItem + 1, 4 * ( m_nCount - nItem - 1 ) );
01131 m_nCount--;
01132 }
01133
01135
01136
01137 void CLibraryTreeItem::Clear()
01138 {
01139 if ( m_pList )
01140 {
01141 for ( int nChild = 0 ; nChild < m_nCount ; nChild++ ) delete m_pList[ nChild ];
01142 delete [] m_pList;
01143 }
01144
01145 m_pList = NULL;
01146 m_nCount = 0;
01147 m_nBuffer = 0;
01148 }
01149
01151
01152
01153 BOOL CLibraryTreeItem::IsVisible() const
01154 {
01155 for ( CLibraryTreeItem* pRoot = m_pParent ; pRoot ; pRoot = pRoot->m_pParent )
01156 {
01157 if ( ! pRoot->m_bExpanded ) return FALSE;
01158 }
01159
01160 return TRUE;
01161 }
01162
01163 int CLibraryTreeItem::GetChildCount() const
01164 {
01165 int nCount = m_nCount;
01166
01167 CLibraryTreeItem** pChild = m_pList;
01168
01169 for ( int nChild = m_nCount ; nChild ; nChild--, pChild++ )
01170 {
01171 if ( (*pChild)->m_bExpanded ) nCount += (*pChild)->GetChildCount();
01172 }
01173
01174 return nCount;
01175 }
01176
01178
01179
01180 void CLibraryTreeItem::Paint(CDC& dc, CRect& rc, BOOL bTarget, COLORREF crBack) const
01181 {
01182 if ( crBack == CLR_NONE ) crBack = CoolInterface.m_crWindow;
01183
01184 if ( m_nCount )
01185 {
01186 ImageList_DrawEx( ShellIcons.GetHandle( 16 ),
01187 m_bExpanded ? SHI_MINUS : SHI_PLUS,
01188 dc.GetSafeHdc(), rc.left, rc.top, 16, 16,
01189 crBack, CLR_NONE, ILD_NORMAL );
01190 }
01191 else
01192 {
01193 dc.FillSolidRect( rc.left, rc.top, 16, 16, crBack );
01194 }
01195
01196 int nImage = ( m_bExpanded && m_nCount ) ? SHI_FOLDER_OPEN : SHI_FOLDER_CLOSED;
01197 if ( m_nIcon16 >= 0 ) nImage = m_nIcon16;
01198
01199 UINT nIconStyle = ( m_bSelected || bTarget ) ? ILD_SELECTED : ILD_NORMAL;
01200
01201 if ( ! m_bShared ) nIconStyle |= INDEXTOOVERLAYMASK( SHI_O_LOCKED );
01202 if ( m_bCollection ) nIconStyle |= INDEXTOOVERLAYMASK( SHI_O_COLLECTION );
01203
01204 ImageList_DrawEx( ShellIcons.GetHandle( 16 ), nImage,
01205 dc.GetSafeHdc(), rc.left + 16, rc.top, 16, 16,
01206 crBack, CLR_DEFAULT, nIconStyle );
01207
01208 crBack = ( m_bSelected || bTarget ) ? CoolInterface.m_crHighlight : crBack;
01209 COLORREF crText = ( m_bSelected || bTarget ) ? CoolInterface.m_crHiText : CoolInterface.m_crText;
01210
01211 dc.SetTextColor( crText );
01212 dc.SetBkColor( crBack );
01213 dc.SetBkMode( OPAQUE );
01214
01215 rc.left += 32;
01216 CString strName = m_sText;
01217 if ( theApp.m_bRTL ) strName = _T("\x202A") + strName;
01218 dc.ExtTextOut( rc.left + 3, rc.top + 1, ETO_OPAQUE|ETO_CLIPPED, &rc,
01219 strName, NULL );
01220 rc.left -= 32;
01221 }
01222
01224
01225
01226 int CLibraryTreeItem::GetFileList(CLibraryList* pList, BOOL bRecursive) const
01227 {
01228 if ( LibraryFolders.CheckFolder( m_pPhysical, TRUE ) )
01229 {
01230 return m_pPhysical->GetFileList( pList, bRecursive );
01231 }
01232 else if ( LibraryFolders.CheckAlbum( m_pVirtual ) )
01233 {
01234 return m_pVirtual->GetFileList( pList, bRecursive );
01235 }
01236
01237 return 0;
01238 }