📄 cpi_playlist.c
字号:
wp_SortFN pfnSort;
CP_CHECKOBJECT(pPlaylist);
// Skip if list is empty
if(pPlaylist->m_hFirst == NULL)
return;
// Decide sort function
{
switch(enElement)
{
case piseTrackStackPos:
pfnSort = cpl_sort_TrackStackPos;
break;
case piseTrackName:
pfnSort = cpl_sort_TrackName;
break;
case piseArtist:
pfnSort = cpl_sort_Artist;
break;
case piseAlbum:
pfnSort = cpl_sort_Album;
break;
case piseYear:
pfnSort = cpl_sort_Year;
break;
case piseTrackNum:
pfnSort = cpl_sort_TrackNum;
break;
case piseGenre:
pfnSort = cpl_sort_Genre;
break;
case piseComment:
pfnSort = cpl_sort_Comment;
break;
case piseFilename:
pfnSort = cpl_sort_Filename;
break;
case pisePath:
pfnSort = cpl_sort_Path;
break;
case piseLength:
pfnSort = cpl_sort_Length;
break;
default:
CP_FAIL(UnknownSortOrder);
}
}
// Count items
{
CP_HPLAYLISTITEM hCursor;
iNumItems = 0;
for(hCursor = pPlaylist->m_hFirst; hCursor; hCursor = CPLI_Next(hCursor))
iNumItems++;
}
// Build flat array
{
CP_HPLAYLISTITEM hCursor;
int iItemIDX;
pFlatArray = (CPs_PlaylistItem**)malloc(sizeof(CPs_PlaylistItem*) * iNumItems);
iItemIDX = 0;
for(hCursor = pPlaylist->m_hFirst; hCursor; hCursor = CPLI_Next(hCursor), iItemIDX++)
pFlatArray[iItemIDX] = CPLII_DECODEHANDLE(hCursor);
}
// Qsort it
qsort(pFlatArray, iNumItems, sizeof(CPs_PlaylistItem*), pfnSort);
// Relink list
{
int iFirstItem, iTermItem, iInc;
CP_HPLAYLISTITEM* phCursor_Referrer = &(pPlaylist->m_hFirst);
CP_HPLAYLISTITEM hCursor_Prev = NULL;
CP_HPLAYLISTITEM hLastAssignment = NULL;
int iItemIDX;
// Work out how to traverse the flat array
if(bDesc == FALSE)
{
iFirstItem = 0;
iTermItem = iNumItems;
iInc = 1;
}
else
{
iFirstItem = iNumItems-1;
iTermItem = -1;
iInc = -1;
}
// Traverse the array
for(iItemIDX = iFirstItem; iItemIDX != iTermItem; iItemIDX+=iInc)
{
*phCursor_Referrer = pFlatArray[iItemIDX];
pFlatArray[iItemIDX]->m_hPrev = hCursor_Prev;
phCursor_Referrer = &(CPLII_DECODEHANDLE(*phCursor_Referrer)->m_hNext);
hCursor_Prev = pFlatArray[iItemIDX];
hLastAssignment = hCursor_Prev;
}
pPlaylist->m_hLast = hLastAssignment;
CPLII_DECODEHANDLE(pPlaylist->m_hLast)->m_hNext = NULL;
}
free(pFlatArray);
CPL_cb_SetWindowToReflectList();
}
//
//
//
void CPL_InsertItemBefore(CP_HPLAYLIST hPlaylist, CP_HPLAYLISTITEM hItem_Anchor, CP_HPLAYLISTITEM hItem_ToMove)
{
CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
CPs_PlaylistItem* pAnchor = CPLII_DECODEHANDLE(hItem_Anchor);
CP_CHECKOBJECT(pPlaylist);
CPL_UnlinkItem(hPlaylist, hItem_ToMove);
if(pAnchor->m_hPrev)
{
CPLII_DECODEHANDLE(pAnchor->m_hPrev)->m_hNext = hItem_ToMove;
CPLII_DECODEHANDLE(hItem_ToMove)->m_hPrev = pAnchor->m_hPrev;
}
else
{
pPlaylist->m_hFirst = hItem_ToMove;
CPLII_DECODEHANDLE(hItem_ToMove)->m_hPrev = NULL;
}
pAnchor->m_hPrev = hItem_ToMove;
CPLII_DECODEHANDLE(hItem_ToMove)->m_hNext = hItem_Anchor;
}
//
//
//
void CPL_InsertItemAfter(CP_HPLAYLIST hPlaylist, CP_HPLAYLISTITEM hItem_Anchor, CP_HPLAYLISTITEM hItem_ToMove)
{
CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
CPs_PlaylistItem* pAnchor = CPLII_DECODEHANDLE(hItem_Anchor);
CP_CHECKOBJECT(pPlaylist);
CPL_UnlinkItem(hPlaylist, hItem_ToMove);
if(pAnchor->m_hNext)
{
CPLII_DECODEHANDLE(pAnchor->m_hNext)->m_hPrev = hItem_ToMove;
CPLII_DECODEHANDLE(hItem_ToMove)->m_hNext = pAnchor->m_hNext;
}
else
{
pPlaylist->m_hLast = hItem_ToMove;
CPLII_DECODEHANDLE(hItem_ToMove)->m_hNext = NULL;
}
pAnchor->m_hNext = hItem_ToMove;
CPLII_DECODEHANDLE(hItem_ToMove)->m_hPrev = hItem_Anchor;
}
//
//
//
void SortLList(CPs_FilenameLLItem* pFirst)
{
char** ppStrings;
int iNumStrings;
int iStringIDX;
CPs_FilenameLLItem* pCursor;
if(!pFirst)
return;
// Count the number of strings in the list
iNumStrings = 0;
for(pCursor = pFirst; pCursor; pCursor = (CPs_FilenameLLItem*)pCursor->m_pNextItem)
iNumStrings++;
// Allocate string buffer and assign strings to it
ppStrings = (char**)malloc(sizeof(char*) * iNumStrings);
iStringIDX = 0;
for(pCursor = pFirst; pCursor; pCursor = (CPs_FilenameLLItem*)pCursor->m_pNextItem)
{
ppStrings[iStringIDX] = pCursor->m_pcFilename;
iStringIDX++;
}
// Sort filelist
qsort(ppStrings, iNumStrings, sizeof(char*), exp_CompareStrings);
// Assign list to the now sorted string list
iStringIDX = 0;
for(pCursor = pFirst; pCursor; pCursor = (CPs_FilenameLLItem*)pCursor->m_pNextItem)
{
pCursor->m_pcFilename = ppStrings[iStringIDX];
iStringIDX++;
}
free(ppStrings);
}
//
//
//
void CPL_AddDirectory_Recurse(CP_HPLAYLIST hPlaylist, const char *pDir)
{
CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
CPs_FilenameLLItem* m_pFirstFile = NULL;
CPs_FilenameLLItem* m_pFirstDir = NULL;
CPs_FilenameLLItem* pCursor;
CPs_FilenameLLItem* pNextItem;
char cFullPath[MAX_PATH];
char cWildCard[MAX_PATH];
const int iDirStrLen = strlen(pDir);
WIN32_FIND_DATA finddata;
HANDLE hFileFind;
CP_CHECKOBJECT(pPlaylist);
// Build a full path to the directory
strcpy(cFullPath, pDir);
if(cFullPath[iDirStrLen-1] == '\\' && iDirStrLen > 1)
cFullPath[iDirStrLen-1] = '\0';
// Check that this is a correct path
if(cFullPath[0] == '\0' || path_is_directory(cFullPath) == FALSE)
{
MessageBox(NULL, "Not a valid directory.", cFullPath, MB_ICONERROR);
return;
}
//Scan directory building a list of filenames
if(strcmp(cFullPath, "\\") == 0)
strcpy(cWildCard, "\\*.*");
else
{
strcpy(cWildCard, cFullPath);
strcat(cWildCard, "\\*.*");
}
strcat(cFullPath, "\\");
hFileFind = FindFirstFile(cWildCard, &finddata);
if(hFileFind == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Could not perform scan", cFullPath, MB_ICONERROR);
return;
}
do
{
char pcFullPath[MAX_PATH];
// Skip dots
if(finddata.cFileName[0] == '.')
continue;
strcpy(pcFullPath, cFullPath);
strcat(pcFullPath, finddata.cFileName);
// Add to linked list
if(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Add to dirs list
CPs_FilenameLLItem* pNewItem = (CPs_FilenameLLItem*)malloc(sizeof(CPs_FilenameLLItem));
pNewItem->m_pNextItem = m_pFirstDir;
STR_AllocSetString(&pNewItem->m_pcFilename, pcFullPath, FALSE);
m_pFirstDir = pNewItem;
}
else
{
// Add to files list
CPs_FilenameLLItem* pNewItem = (CPs_FilenameLLItem*)malloc(sizeof(CPs_FilenameLLItem));
pNewItem->m_pNextItem = m_pFirstFile;
STR_AllocSetString(&pNewItem->m_pcFilename, pcFullPath, FALSE);
m_pFirstFile = pNewItem;
}
} while(FindNextFile(hFileFind, &finddata) != 0);
FindClose(hFileFind);
SortLList(m_pFirstDir);
SortLList(m_pFirstFile);
// Add files first - then directories
for(pCursor = m_pFirstFile; pCursor; pCursor = (CPs_FilenameLLItem*)pCursor->m_pNextItem)
CPL_AddFile(globals.m_hPlaylist, pCursor->m_pcFilename);
for(pCursor = m_pFirstDir; pCursor; pCursor = (CPs_FilenameLLItem*)pCursor->m_pNextItem)
CPL_AddDirectory_Recurse(hPlaylist, pCursor->m_pcFilename);
// Cleanup
for(pCursor = m_pFirstFile; pCursor; pCursor = pNextItem)
{
pNextItem = (CPs_FilenameLLItem*)pCursor->m_pNextItem;
free(pCursor->m_pcFilename);
free(pCursor);
}
for(pCursor = m_pFirstDir; pCursor; pCursor = pNextItem)
{
pNextItem = (CPs_FilenameLLItem*)pCursor->m_pNextItem;
free(pCursor->m_pcFilename);
free(pCursor);
}
}
//
//
//
void CPL_AddDroppedFiles(CP_HPLAYLIST hPlaylist, HDROP hDrop)
{
CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
int iNumFiles, iFileIDX;
char** ppFiles;
CP_CHECKOBJECT(pPlaylist);
// Read all the files into an array of strings
iNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
ppFiles = (char**)malloc(iNumFiles * sizeof(char*));
for(iFileIDX = 0; iFileIDX < iNumFiles; iFileIDX++)
{
const int iBufferSize = DragQueryFile(hDrop, iFileIDX, NULL, 0)+1;
ppFiles[iFileIDX] = (char*)malloc(iBufferSize * sizeof(char));
DragQueryFile(hDrop, iFileIDX, ppFiles[iFileIDX], iBufferSize);
}
DragFinish(hDrop);
// Sort filelist
qsort(ppFiles, iNumFiles, sizeof(char*), exp_CompareStrings);
// Add to playlist
CLV_BeginBatch(globals.m_hPlaylistViewControl);
for(iFileIDX = 0; iFileIDX < iNumFiles; iFileIDX++)
{
if(path_is_directory(ppFiles[iFileIDX]) == TRUE)
{
CPL_AddDirectory_Recurse(globals.m_hPlaylist, ppFiles[iFileIDX]);
strcpy(options.last_used_directory, ppFiles[iFileIDX]);
}
else
CPL_AddFile(globals.m_hPlaylist, ppFiles[iFileIDX]);
}
CLV_EndBatch(globals.m_hPlaylistViewControl);
// Free string array
for(iFileIDX = 0; iFileIDX < iNumFiles; iFileIDX++)
free(ppFiles[iFileIDX]);
free(ppFiles);
// Shuffle playlist
if(options.shuffle_play)
PostThreadMessage(pPlaylist->m_dwWorkerThreadID, CPPLWT_SYNCSHUFFLE, 0, 0);
}
//
//
//
void CPL_Stack_Append(CP_HPLAYLIST hPlaylist, CP_HPLAYLISTITEM hItem)
{
CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
int iItemNumber;
CP_CHECKOBJECT(pPlaylist);
// Ensure buffer is big enough
if( (pPlaylist->m_iTrackStackSize+1) >= pPlaylist->m_iTrackStackBufferSize)
{
pPlaylist->m_iTrackStackBufferSize += CPC_TRACKSTACK_BUFFER_QUANTISATION;
pPlaylist->m_pTrackStack = realloc(pPlaylist->m_pTrackStack, pPlaylist->m_iTrackStackBufferSize * sizeof(CP_HPLAYLISTITEM));
}
// Ensure cursor is rational
if(pPlaylist->m_iTrackStackCursor > pPlaylist->m_iTrackStackSize)
pPlaylist->m_iTrackStackCursor = pPlaylist->m_iTrackStackSize;
// Add item
pPlaylist->m_pTrackStack[pPlaylist->m_iTrackStackSize] = hItem;
pPlaylist->m_iTrackStackSize++;
// Number item
iItemNumber = (pPlaylist->m_iTrackStackSize-1) - pPlaylist->m_iTrackStackCursor;
CPLI_SetTrackStackPos(hItem, iItemNumber);
CPL_cb_TrackStackChanged();
}
//
//
//
void CPL_Stack_Renumber(CP_HPLAYLIST hPlaylist)
{
CPs_Playlist* pPlaylist = (CPs_Playlist*)hPlaylist;
unsigned int iStackIDX;
CP_CHECKOBJECT(pPlaylist);
for(iStackIDX = 0; iStackIDX < pPlaylist->m_iTrackStackSize; iStackIDX++)
CPLI_SetTrackStackPos(pPlaylist->m_pTrackStack[iStackIDX], iStackIDX - pPlaylist->m_iTrackStackCursor);
CPL_cb_TrackStackChanged();
}
//
//
//
void CPL_Stack_Remove(CP_HPLAYLIST hPlaylist, CP_HPLAYLISTITEM hItem)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -