CPI_PlaylistWindow.c
上传用户:tuheem
上传日期:2007-05-01
资源大小:21889k
文件大小:50k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /*
  2.  * CoolPlayer - Blazing fast audio player.
  3.  * Copyright (C) 2000-2001 Niek Albers
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. ////////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "globals.h"
  22. #include "WindowsOS.h"
  23. #include "CPI_Player.h"
  24. #include "CPI_ID3.h"
  25. #include "CPI_Playlist.h"
  26. #include "CPI_PlaylistItem.h"
  27. #include "CPI_PlaylistWindow.h"
  28. #include "CPI_Indicators.h"
  29. ////////////////////////////////////////////////////////////////////////////////
  30. //
  31. typedef enum _CIe_PlaylistWindowMode
  32. {
  33.     wmQuiescent,
  34.     wmListItem_Drag,
  35.     wmCommandTarget_Click
  36. } CIe_PlaylistWindowMode;
  37. //
  38. //
  39. //
  40. struct _CPs_PlaylistWindowState
  41. {
  42.     CIe_PlaylistWindowMode m_enWindowMode;
  43.     CPs_CommandTarget* m_pActiveCommandTarget;
  44.     CPs_CommandTarget* m_pFloatActiveCommandTarget;
  45.     BOOL m_bMouseEventSet;
  46. } glb_PLW_State;
  47. //
  48. ////////////////////////////////////////////////////////////////////////////////
  49. #define IDC_PL_LISTVIEW 0x0100
  50. #define IDC_PL_FLOATINGEDIT 0x0101
  51. #define IDC_PL_FLOATINGCOMBO 0x0102
  52. #define CPPLM_CREATEINPLACE (WM_APP+0x001)
  53. #define CPPLM_DESTROYINPLACE (WM_APP+0x002)
  54. #define CPC_SIZEBORDER 0x4
  55. //
  56. #define IDC_CMDTS_CLEARSTACK 0x1
  57. #define IDC_CMDTS_RESTACKALL 0x2
  58. #define IDC_CMDTS_PLAYFROMHERE 0x3
  59. #define IDC_CMDTS_UNSTACK 0x4
  60. #define IDC_CMDTS_PLAYNOW 0x5
  61. #define IDC_CMDTS_STOPAFTER 0x6
  62. #define IDC_CMDTS_STOPAFTER_NOREP 0x7
  63. #define IDC_CMDTS_PLAYNEXT 0x8
  64. #define IDC_CMDTS_QUEUE 0x9
  65. //
  66. void LVCB_DrawBackgroundRect(CPs_DrawContext* pDC);
  67. void LVCB_HeaderChanged(CP_HLISTVIEW _hListData);
  68. void LVCB_ItemSelected(CP_HLISTVIEW _hListData, const int iItemIDX, const CP_HPLAYLISTITEM hItem);
  69. void LVCB_ItemAction(CP_HLISTVIEW _hListData, const int iItemIDX, const CP_HPLAYLISTITEM hItem);
  70. void LVCB_ItemDrag(CP_HLISTVIEW _hListData, const int iItemIDX, const CP_HPLAYLISTITEM hItem);
  71. void LVCB_ItemRightClick(CP_HLISTVIEW _hListData, const int iItemIDX, const int iColumnIDX, const CP_HPLAYLISTITEM hItem);
  72. void LVCB_ColHeaderClick(CP_HLISTVIEW _hListData, const int iColIDX);
  73. void LVCB_UnhandledKeyPress(CP_HLISTVIEW _hListData, const int iVKey, const BOOL bAlt, const BOOL bCtrl, const BOOL bShift);
  74. CPe_CustomDrawColour LVCB_GetTrackStackItemColour(const void* pvItemData);
  75. CPe_CustomDrawColour LVCB_GetItemColour(const void* pvItemData);
  76. void CPlaylistWindow_CB_onCreate(CP_HINTERFACE hInterface, const RECT* pInitialPosition);
  77. void CPlaylistWindow_CB_onDraw(CP_HINTERFACE hInterface, CPs_DrawContext* pContext);
  78. void CPlaylistWindow_CB_onKeyDown(CP_HINTERFACE hInterface, const unsigned int iVKeyCode, const BOOL bAlt, const BOOL bCtrl, const BOOL bShift);
  79. void CPlaylistWindow_CB_onDropFiles(CP_HINTERFACE hInterface, HDROP hDrop);
  80. void CPlaylistWindow_CB_onPosChange(CP_HINTERFACE hInterface, const RECT* pNewPosition, const BOOL bSizeChanged);
  81. void CPlaylistWindow_CB_onFocus(CP_HINTERFACE hInterface, const BOOL bHasFocus);
  82. void CPlaylistWindow_CB_onCommandMessage(CP_HINTERFACE hInterface, const WPARAM wParam, const LPARAM lParam);
  83. void CPlaylistWindow_CB_onMouseMove(CP_HINTERFACE hInterface, const POINTS ptMouse, const unsigned short iFlags);
  84. void CPlaylistWindow_CB_onMouseButton_LUp(CP_HINTERFACE hInterface, const POINTS ptMouse, const unsigned short iFlags);
  85. LRESULT CPlaylistWindow_CB_onAppMessage(CP_HINTERFACE hInterface, const UINT uiMessage, const WPARAM wParam, const LPARAM lParam);
  86. void CPlaylistWindow_CB_onClose(CP_HINTERFACE hInterface);
  87. //
  88. void CPlaylistWindow_CreateSubparts();
  89. ////////////////////////////////////////////////////////////////////////////////
  90. //
  91. //
  92. //
  93. void CPlaylistWindow_Create()
  94. {
  95.     // Init playlist window state
  96.     glb_PLW_State.m_enWindowMode = wmQuiescent;
  97.     glb_PLW_State.m_pActiveCommandTarget = NULL;
  98.     glb_PLW_State.m_pFloatActiveCommandTarget = NULL;
  99.     glb_PLW_State.m_bMouseEventSet = FALSE;
  100.     // Create user interface window
  101.     windows.m_hifPlaylist = IF_Create();
  102.     IF_sethandler_onCreate(windows.m_hifPlaylist, CPlaylistWindow_CB_onCreate);
  103.     IF_sethandler_onDraw(windows.m_hifPlaylist, CPlaylistWindow_CB_onDraw);
  104.     IF_sethandler_onKeyDown(windows.m_hifPlaylist, CPlaylistWindow_CB_onKeyDown);
  105.     IF_sethandler_onDropFiles(windows.m_hifPlaylist, CPlaylistWindow_CB_onDropFiles);
  106.     IF_sethandler_onPosChange(windows.m_hifPlaylist, CPlaylistWindow_CB_onPosChange);
  107.     IF_sethandler_onFocus(windows.m_hifPlaylist, CPlaylistWindow_CB_onFocus);
  108.     IF_sethandler_onCommandMessage(windows.m_hifPlaylist, CPlaylistWindow_CB_onCommandMessage);
  109.     IF_sethandler_onAppMessage(windows.m_hifPlaylist, CPlaylistWindow_CB_onAppMessage);
  110.     IF_sethandler_onClose(windows.m_hifPlaylist, CPlaylistWindow_CB_onClose);
  111.     // Add interface subparts
  112.     CPlaylistWindow_CreateSubparts();
  113.     IF_SetMinSize(windows.m_hifPlaylist, &glb_pSkin->mpl_szMinWindow);
  114.     IF_OpenWindow(windows.m_hifPlaylist, "CoolPlayer Playlist", &options.playlist_window_pos, CPC_INTERFACE_STYLE_RESIZING);
  115.     IF_SetVisible(windows.m_hifPlaylist, options.show_playlist);
  116. }
  117. //
  118. //
  119. //
  120. void CPlaylistWindow_Destroy()
  121. {
  122.     // Cleanup windows
  123.     IF_CloseWindow(windows.m_hifPlaylist);
  124.     globals.m_hPlaylistViewControl = NULL;
  125. }
  126. //
  127. //
  128. //
  129. void CPlaylistWindow_CreateSubparts()
  130. {
  131.     IF_RemoveAllSubparts(windows.m_hifPlaylist);
  132.     {
  133.         CPs_CommandTarget* pCT_Cursor;
  134.         for(pCT_Cursor = glb_pSkin->mpl_pCommandTargets; pCT_Cursor; pCT_Cursor = (CPs_CommandTarget*)pCT_Cursor->m_pNext)
  135.         {
  136.             IF_AddSubPart_CommandButton(windows.m_hifPlaylist,
  137.                                         pCT_Cursor->m_dwAlign,
  138.                                         &pCT_Cursor->m_ptOffset,
  139.                                         pCT_Cursor->m_pStateImage,
  140.                                         pCT_Cursor->m_pfnVerb);
  141.         }
  142.     }
  143.     {
  144.         CPs_Indicator* pI_Cursor;
  145.         for(pI_Cursor = glb_pSkin->mpl_pIndicators; pI_Cursor; pI_Cursor = (CPs_Indicator*)pI_Cursor->m_pNext)
  146.         {
  147.             IF_AddSubPart_Indicator(windows.m_hifPlaylist,
  148.                                     pI_Cursor->m_pcName,
  149.                                     pI_Cursor->m_dwAlign,
  150.                                     &pI_Cursor->m_rAlign);
  151.         }
  152.     }
  153. }
  154. //
  155. //
  156. //
  157. void CPlaylistWindow_SetVisible(const BOOL bNewVisibleState)
  158. {
  159.     CheckMenuItem(globals.main_menu_popup, MENU_PLAYLIST, MF_BYCOMMAND | (bNewVisibleState ? MF_CHECKED : 0));
  160.     IF_SetVisible(windows.m_hifPlaylist, bNewVisibleState);
  161. }
  162. //
  163. //
  164. //
  165. void CPlaylistWindow_CreateListView()
  166. {
  167.     RECT rClient;
  168.     int iColumnIDX;
  169.     // Create listview control
  170.     GetClientRect(IF_GetHWnd(windows.m_hifPlaylist), &rClient);
  171.     globals.m_hPlaylistViewControl = CLV_Create(IF_GetHWnd(windows.m_hifPlaylist),
  172.                                      glb_pSkin->mpl_rList_Border.left, glb_pSkin->mpl_rList_Border.top,
  173.                                      (rClient.right - glb_pSkin->mpl_rList_Border.right) - glb_pSkin->mpl_rList_Border.left,
  174.                                      (rClient.bottom - glb_pSkin->mpl_rList_Border.bottom) - glb_pSkin->mpl_rList_Border.top);
  175.     // Setup callbacks
  176.     CLV_sethandler_DrawBackgroundRect(globals.m_hPlaylistViewControl, LVCB_DrawBackgroundRect);
  177.     CLV_sethandler_HeaderChanged(globals.m_hPlaylistViewControl, LVCB_HeaderChanged);
  178.     CLV_sethandler_ItemSelected(globals.m_hPlaylistViewControl, (wp_ItemCallback)LVCB_ItemSelected);
  179.     CLV_sethandler_ItemAction(globals.m_hPlaylistViewControl, (wp_ItemCallback)LVCB_ItemAction);
  180.     CLV_sethandler_ItemDrag(globals.m_hPlaylistViewControl, (wp_ItemCallback)LVCB_ItemDrag);
  181.     CLV_sethandler_ItemRightClick(globals.m_hPlaylistViewControl, (wp_ItemSubCallback)LVCB_ItemRightClick);
  182.     CLV_sethandler_ColHeaderClick(globals.m_hPlaylistViewControl, LVCB_ColHeaderClick);
  183.     CLV_sethandler_UnhandledKeyPress(globals.m_hPlaylistViewControl, LVCB_UnhandledKeyPress);
  184.     // Setup columns
  185.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  186.                   "Stack",
  187.                   options.playlist_column_widths[0],
  188.                   (wp_GetItemText)CPLI_GetTrackStackPos_AsText,
  189.                   CPLV_COLFLAG_NOHIDE);
  190.     CLV_SetColumnCustomDrawColour(globals.m_hPlaylistViewControl, PLAYLIST_TRACKSTACK, LVCB_GetTrackStackItemColour);
  191.     CLV_SetColumnAlign(globals.m_hPlaylistViewControl, PLAYLIST_TRACKSTACK, lcaRight);
  192.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  193.                   "Title",
  194.                   options.playlist_column_widths[1],
  195.                   (wp_GetItemText)CPLI_GetTrackName,
  196.                   options.playlist_column_visible[1] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  197.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  198.                   "Artist",
  199.                   options.playlist_column_widths[2],
  200.                   (wp_GetItemText)CPLI_GetArtist,
  201.                   options.playlist_column_visible[2] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  202.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  203.                   "Album",
  204.                   options.playlist_column_widths[3],
  205.                   (wp_GetItemText)CPLI_GetAlbum,
  206.                   options.playlist_column_visible[3] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  207.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  208.                   "Year",
  209.                   options.playlist_column_widths[4],
  210.                   (wp_GetItemText)CPLI_GetYear,
  211.                   options.playlist_column_visible[4] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  212.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  213.                   "TrackNum",
  214.                   options.playlist_column_widths[5],
  215.                   (wp_GetItemText)CPLI_GetTrackNum_AsText,
  216.                   options.playlist_column_visible[5] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  217.     CLV_SetColumnAlign(globals.m_hPlaylistViewControl, PLAYLIST_TRACKNUM, lcaRight);
  218.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  219.                   "Comment",
  220.                   options.playlist_column_widths[6],
  221.                   (wp_GetItemText)CPLI_GetComment,
  222.                   options.playlist_column_visible[6] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  223.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  224.                   "Genre",
  225.                   options.playlist_column_widths[7],
  226.                   (wp_GetItemText)CPLI_GetGenre,
  227.                   options.playlist_column_visible[7] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  228.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  229.                   "Path",
  230.                   options.playlist_column_widths[8],
  231.                   (wp_GetItemText)CPLI_GetPath,
  232.                   options.playlist_column_visible[8] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  233.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  234.                   "Filename",
  235.                   options.playlist_column_widths[9],
  236.                   (wp_GetItemText)CPLI_GetFilename,
  237.                   options.playlist_column_visible[9] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  238.     CLV_AddColumn(globals.m_hPlaylistViewControl,
  239.                   "Length",
  240.                   options.playlist_column_widths[10],
  241.                   (wp_GetItemText)CPLI_GetTrackLength_AsText,
  242.                   options.playlist_column_visible[10] ? CPLV_COLFLAG_NONE : CPLV_COLFLAG_HIDDEN);
  243.     CLV_SetColumnAlign(globals.m_hPlaylistViewControl, PLAYLIST_LENGTH, lcaRight);
  244.     for(iColumnIDX = 1; iColumnIDX <= PLAYLIST_last; iColumnIDX++)
  245.         CLV_SetColumnCustomDrawColour(globals.m_hPlaylistViewControl, iColumnIDX, LVCB_GetItemColour);
  246.     CLV_SetColumnOrder(globals.m_hPlaylistViewControl, options.playlist_column_seq, PLAYLIST_last+1);
  247.     CPL_cb_SetWindowToReflectList();
  248. }
  249. //
  250. //
  251. //
  252. int __cdecl exp_CompareStrings(const void *elem1, const void *elem2)
  253. {
  254.     const char* pcElem1 = *(const char**)elem1;
  255.     const char* pcElem2 = *(const char**)elem2;
  256.     return stricmp(pcElem1, pcElem2);
  257. }
  258. //
  259. //
  260. //
  261. void CPlaylistWindow_DestroyIPEdit()
  262. {
  263.     HWND hWnd_IPEdit;
  264.     if(!windows.wnd_playlist_IPEdit)
  265.         return;
  266.     hWnd_IPEdit = windows.wnd_playlist_IPEdit;
  267.     UnhookWindowsHookEx(globals.m_hhkListView_Posted);
  268.     globals.m_hhkListView_Posted = NULL;
  269.     windows.wnd_playlist_IPEdit = NULL;
  270.     DestroyWindow(hWnd_IPEdit);
  271.     // Write any dirty playlist items - Check all items because the selection could have
  272.     // changed by now
  273.    {
  274.         char cStatusMessage[1024];
  275.         CP_HPLAYLISTITEM hCursor;
  276.         SetCursor(LoadCursor(NULL, IDC_WAIT));
  277.         for(hCursor = CPL_GetFirstItem(globals.m_hPlaylist); hCursor; hCursor = CPLI_Next(hCursor))
  278.         {
  279.             if(CPLI_IsTagDirty(hCursor) == FALSE)
  280.                 continue;
  281.             sprintf(cStatusMessage, "Tagging "%s"", CPLI_GetFilename(hCursor));
  282.             CPIC_SetIndicatorValue("status", cStatusMessage);
  283.             UpdateWindow(IF_GetHWnd(windows.m_hifPlaylist));
  284.             CPLI_WriteTag(hCursor);
  285.         }
  286.         SetCursor(LoadCursor(NULL, IDC_ARROW));
  287.         CPIC_SetIndicatorValue("status", NULL);
  288.     } 
  289. }
  290. //
  291. //
  292. //
  293. LRESULT CALLBACK exp_ListViewHookProc_Posted(int iCode, WPARAM wParam, LPARAM lParam)
  294. {
  295.     if(iCode == HC_ACTION && windows.wnd_playlist_IPEdit)
  296.     {
  297.         MSG* pMSG = (MSG*)lParam;
  298.         // If any window (apart from the IP window) has a mouse click - close the IP window
  299.         if( (pMSG->message == WM_LBUTTONDOWN
  300.                 || pMSG->message == WM_MBUTTONDOWN
  301.                 || pMSG->message == WM_RBUTTONDOWN
  302.                 || pMSG->message == WM_NCLBUTTONDOWN
  303.                 || pMSG->message == WM_NCMBUTTONDOWN
  304.                 || pMSG->message == WM_NCRBUTTONDOWN)
  305.                 && pMSG->hwnd != windows.wnd_playlist_IPEdit)
  306.         {
  307.             // Get the classname to ensure that it's not our combo popup that's got the message
  308.             char cClassname[64];
  309.             GetClassName(pMSG->hwnd, cClassname, 64);
  310.             if(strcmp("ComboLBox", cClassname))
  311.                 CPlaylistWindow_DestroyIPEdit();
  312.         }
  313.     }
  314.     if(globals.m_hhkListView_Posted)
  315.         return CallNextHookEx(globals.m_hhkListView_Posted, iCode, wParam, lParam);
  316.     else
  317.         return 0;
  318. }
  319. //
  320. //
  321. //
  322. void CPlaylistWindow_TrackStackMenu(iItem)
  323. {
  324.     HWND hWndList;
  325.     POINT ptItem;
  326.     RECT rSubItem;
  327.     HMENU hmMenu;
  328.     UINT uiMenuCommand;
  329.     int iSearchItemIDX;
  330.     CP_HPLAYLISTITEM hClickedItem;
  331.     CPe_ItemStackState enClickedItemState;
  332.     BOOL bMultipleSelection;
  333.     // We want to get the subitem's rect in the co-ordinate space of the dialog
  334.     hWndList = CLV_GetHWND(globals.m_hPlaylistViewControl);
  335.     CLV_GetItemSubRect(globals.m_hPlaylistViewControl, &rSubItem, iItem, 0);
  336.     // Are there multiple items selected?
  337.     iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  338.     if(iSearchItemIDX != CPC_INVALIDITEM)
  339.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX);
  340.     if(iSearchItemIDX != CPC_INVALIDITEM)
  341.         bMultipleSelection = TRUE;
  342.     else
  343.         bMultipleSelection = FALSE;
  344.     ptItem.x = rSubItem.left;
  345.     ptItem.y = rSubItem.bottom;
  346.     ClientToScreen(hWndList, &ptItem);
  347.     // Create menu
  348.     hmMenu = CreatePopupMenu();
  349.     hClickedItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iItem);
  350.     enClickedItemState = CPL_Stack_GetItemState(globals.m_hPlaylist, hClickedItem);
  351.     if(enClickedItemState != issUnstacked)
  352.     {
  353.         AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_PLAYFROMHERE, "Play from here");
  354.         SetMenuDefaultItem(hmMenu, IDC_CMDTS_PLAYFROMHERE, FALSE);
  355.         if(enClickedItemState != issStacked_Top)
  356.         {
  357.             AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_PLAYNEXT, "Play next");
  358.             AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_UNSTACK, "Unstack");
  359.         }
  360.         // Not played yet?
  361.         if(enClickedItemState == issStacked || enClickedItemState == issStacked_Top)
  362.         {
  363.             if(options.repeat_playlist == TRUE)
  364.             {
  365.                 AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_STOPAFTER, "Repeat after this");
  366.                 AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_STOPAFTER_NOREP, "Stop after this (repeat->off)");
  367.             }
  368.             else
  369.             {
  370.                 AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_STOPAFTER, "Stop after this");
  371.             }
  372.         }
  373.         if(enClickedItemState != issStacked_Top)
  374.             AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_QUEUE, "Queue at end");
  375.     }
  376.     else
  377.     {
  378.         AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_PLAYNOW, "Play now");
  379.         SetMenuDefaultItem(hmMenu, IDC_CMDTS_PLAYNOW, FALSE);
  380.         AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_PLAYNEXT, "Play next");
  381.         AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_QUEUE, "Queue at end");
  382.     }
  383.     AppendMenu(hmMenu, MF_SEPARATOR, 0, NULL);
  384.     AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_CLEARSTACK, "Clear stack");
  385.     AppendMenu(hmMenu, MF_STRING, IDC_CMDTS_RESTACKALL, "Restack all");
  386.     uiMenuCommand = TrackPopupMenuEx( hmMenu,
  387.                                       TPM_NONOTIFY
  388.                                       | TPM_RETURNCMD
  389.                                       | TPM_RIGHTBUTTON,
  390.                                       ptItem.x, ptItem.y,
  391.                                       IF_GetHWnd(windows.m_hifPlaylist),
  392.                                       NULL);
  393.     DestroyMenu(hmMenu);
  394.     if(uiMenuCommand == IDC_CMDTS_CLEARSTACK)
  395.     {
  396.         CPL_Stack_Clear(globals.m_hPlaylist);
  397.     }
  398.     else if(uiMenuCommand == IDC_CMDTS_RESTACKALL)
  399.     {
  400.         CPL_Stack_RestackAll(globals.m_hPlaylist);
  401.     }
  402.     else if(uiMenuCommand == IDC_CMDTS_PLAYFROMHERE)
  403.     {
  404.         CPL_Stack_SetCursor(globals.m_hPlaylist, hClickedItem);
  405.         CPL_PlayItem(globals.m_hPlaylist, TRUE, pmCurrentItem);
  406.     }
  407.     else if(uiMenuCommand == IDC_CMDTS_UNSTACK)
  408.     {
  409.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  410.         while(iSearchItemIDX != CPC_INVALIDITEM)
  411.         {
  412.             CPL_Stack_Remove(globals.m_hPlaylist, (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX) );
  413.             iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX);
  414.         }
  415.     }
  416.     else if(uiMenuCommand == IDC_CMDTS_PLAYNOW)
  417.     {
  418.         CP_HPLAYLISTITEM hFirstItem;
  419.         CPL_Stack_ClipFromCurrent(globals.m_hPlaylist);
  420.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  421.         hFirstItem = NULL;
  422.         while(iSearchItemIDX != CPC_INVALIDITEM)
  423.         {
  424.             CP_HPLAYLISTITEM hItem;
  425.             hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  426.             if(!hFirstItem)
  427.                 hFirstItem = hItem;
  428.             CPL_Stack_Append(globals.m_hPlaylist, hItem);
  429.             iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX);
  430.         }
  431.         CPL_Stack_SetCursor(globals.m_hPlaylist, hFirstItem);
  432.         CPL_PlayItem(globals.m_hPlaylist, TRUE, pmCurrentItem);
  433.     }
  434.     else if(uiMenuCommand == IDC_CMDTS_STOPAFTER)
  435.     {
  436.         CPL_Stack_ClipFromItem(globals.m_hPlaylist, hClickedItem);
  437.     }
  438.     else if(uiMenuCommand == IDC_CMDTS_STOPAFTER_NOREP)
  439.     {
  440.         options.repeat_playlist = FALSE;
  441.         InvalidateRect(windows.wnd_main, NULL, FALSE);
  442.         CPL_Stack_ClipFromItem(globals.m_hPlaylist, hClickedItem);
  443.     }
  444.     else if(uiMenuCommand == IDC_CMDTS_PLAYNEXT)
  445.     {
  446.         iSearchItemIDX = CLV_GetPrevSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  447.         while(iSearchItemIDX != CPC_INVALIDITEM)
  448.         {
  449.             CPL_Stack_PlayNext(globals.m_hPlaylist, (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX) );
  450.             iSearchItemIDX = CLV_GetPrevSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX);
  451.         }
  452.     }
  453.     else if(uiMenuCommand == IDC_CMDTS_QUEUE)
  454.     {
  455.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  456.         while(iSearchItemIDX != CPC_INVALIDITEM)
  457.         {
  458.             CP_HPLAYLISTITEM hItem;
  459.             hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  460.             CPL_Stack_Remove(globals.m_hPlaylist, hItem);
  461.             CPL_Stack_Append(globals.m_hPlaylist, hItem);
  462.             iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX);
  463.         }
  464.     }
  465. }
  466. //
  467. //
  468. //
  469. void CPlaylistWindow_RenameMenu(const int iItem, const int iSubItem)
  470. {
  471.     HWND hWndList;
  472.     POINT ptItem;
  473.     RECT rSubItem;
  474.     HMENU hmMenu;
  475.     UINT uiMenuCommand;
  476.     // We want to get the subitem's rect in the co-ordinate space of the dialog
  477.     hWndList = CLV_GetHWND(globals.m_hPlaylistViewControl);
  478.     CLV_GetItemSubRect(globals.m_hPlaylistViewControl, &rSubItem, iItem, iSubItem);
  479.     ptItem.x = rSubItem.left;
  480.     ptItem.y = rSubItem.bottom;
  481.     ClientToScreen(hWndList, &ptItem);
  482.     // Create menu
  483.     hmMenu = CreatePopupMenu();
  484.     AppendMenu(hmMenu, MF_STRING, (DWORD)rwsArtistAlbumNumberTitle, "Rename to <artist> - <album> - <tracknum> - <title>");
  485.     AppendMenu(hmMenu, MF_STRING, (DWORD)rwsArtistNumberTitle, "Rename to <artist> - <tracknum> - <title>");
  486.     AppendMenu(hmMenu, MF_STRING, (DWORD)rwsAlbumNumberTitle, "Rename to <album> - <tracknum> - <title>");
  487.     AppendMenu(hmMenu, MF_STRING, (DWORD)rwsAlbumNumber, "Rename to <album> - <tracknum>");
  488.     AppendMenu(hmMenu, MF_STRING, (DWORD)rwsNumberTitle, "Rename to <tracknum> - <title>");
  489.     AppendMenu(hmMenu, MF_STRING, (DWORD)rwsTitle, "Rename to <title>");
  490.     uiMenuCommand = TrackPopupMenuEx( hmMenu,
  491.                                       TPM_NONOTIFY
  492.                                       | TPM_RETURNCMD
  493.                                       | TPM_RIGHTBUTTON,
  494.                                       ptItem.x, ptItem.y,
  495.                                       IF_GetHWnd(windows.m_hifPlaylist),
  496.                                       NULL);
  497.     DestroyMenu(hmMenu);
  498.     if(uiMenuCommand)
  499.     {
  500.         int iSearchItemIDX;
  501.         int iNumberOfErrors;
  502.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  503.         iNumberOfErrors = 0;
  504.         while(iSearchItemIDX != CPC_INVALIDITEM)
  505.         {
  506.             BOOL bSucceeded;
  507.             bSucceeded = CPLI_RenameTrack((CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX),
  508.                                           (CPe_FilenameFormat)uiMenuCommand);
  509.             iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX);
  510.             if(!bSucceeded)
  511.                 iNumberOfErrors++;
  512.         }
  513.         if(iNumberOfErrors > 0)
  514.         {
  515.             MessageBox(IF_GetHWnd(windows.m_hifPlaylist),
  516.                        "Some files could not be renamed.nnThis could be because they are either currently playing or are read-only.",
  517.                        "Error",
  518.                        MB_OK | MB_ICONASTERISK);
  519.         }
  520.     }
  521. }
  522. //
  523. //
  524. //
  525. void CPlaylistWindow_CreateIPEdit(const int iItem, const int iSubItem)
  526. {
  527.     RECT rSubItem;
  528.     const char* pcClass;
  529.     DWORD dwStyle;
  530.     int iSearchItemIDX;
  531.     UINT uiControlID;
  532.     BOOL bClearNonSelectedItems;
  533.     CP_HPLAYLISTITEM hClickedItem;
  534.     HWND hWndList;
  535.     int iNumItemsSelected;
  536.     // If the clicked item is not read/write then skip this
  537.     hClickedItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iItem);
  538.     if(CPLI_GetReadWriteState(hClickedItem) != rwsReadWrite)
  539.     {
  540.         MessageBox(windows.m_hWndPlaylist, "This file's ID3 tag cannot be updated.  This is because CoolPlayer cannot write to this file.", "Cannot update tag", MB_OK | MB_ICONSTOP);
  541.         return;
  542.     }
  543.     // For some sub items it is not logical to multi update - action these
  544.     if(iSubItem == PLAYLIST_TITLE)
  545.         bClearNonSelectedItems = TRUE;
  546.     else
  547.         bClearNonSelectedItems = FALSE;
  548.     // Go through the selected items and remove the selection of items that
  549.     // cannot be written to (eg because of a read only file)
  550.     iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  551.     iNumItemsSelected = 1;
  552.     for(;iSearchItemIDX != -1; iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX))
  553.     {
  554.         CP_HPLAYLISTITEM hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  555.         CPLI_ReadTag(hItem);
  556.         // We've already checked this item
  557.         if(iSearchItemIDX == iItem)
  558.             continue;
  559.         iNumItemsSelected++;
  560.         if(bClearNonSelectedItems == TRUE || CPLI_GetReadWriteState(hItem) != rwsReadWrite)
  561.             CLV_SetItemSelected(globals.m_hPlaylistViewControl, iSearchItemIDX, FALSE);
  562.     }
  563.     // If the "track number" column was clicked - and there are multiple selections - auto number them
  564.     if(iSubItem == PLAYLIST_TRACKNUM && iNumItemsSelected > 1)
  565.     {
  566.         char cStatusMessage[1024];
  567.         int iTrackNumber;
  568.         // Autonumber
  569.         SetCursor(LoadCursor(NULL, IDC_WAIT));
  570.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  571.         iTrackNumber = 1;
  572.         for(;iSearchItemIDX != CPC_INVALIDITEM; iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX))
  573.         {
  574.             CP_HPLAYLISTITEM hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  575.             sprintf(cStatusMessage, "Tagging "%s"", CPLI_GetFilename(hItem));
  576.   CP_TRACE1("status: %s",cStatusMessage);
  577.            CPIC_SetIndicatorValue("status", cStatusMessage);
  578.             UpdateWindow(IF_GetHWnd(windows.m_hifPlaylist));
  579. //            CPLI_SetTrackNum(hItem, iTrackNumber);
  580.             CPLI_WriteTag(hItem);
  581.             iTrackNumber++;
  582.         }
  583.         SetCursor(LoadCursor(NULL, IDC_ARROW));
  584.         CPIC_SetIndicatorValue("status", NULL);
  585.         return;
  586.     }
  587.     // If the length was clicked - work out the lengths for all selected items
  588.     if(iSubItem == PLAYLIST_LENGTH)
  589.     {
  590.         char cStatusMessage[1024];
  591.         SetCursor(LoadCursor(NULL, IDC_WAIT));
  592.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  593.         for(; iSearchItemIDX != CPC_INVALIDITEM; iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX))
  594.         {
  595.             CP_HPLAYLISTITEM hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  596.             CPLI_CalculateLength(hItem);
  597.             sprintf(cStatusMessage, "Tagging "%s"", CPLI_GetFilename(hItem));
  598.             
  599. CPIC_SetIndicatorValue("status", cStatusMessage);
  600. CP_TRACE1("status: %s",cStatusMessage);
  601.            UpdateWindow(IF_GetHWnd(windows.m_hifPlaylist));
  602.             CPLI_WriteTag(hItem);
  603.         }
  604.         SetCursor(LoadCursor(NULL, IDC_ARROW));
  605.         CPIC_SetIndicatorValue("status", NULL);
  606.         return;
  607.     }
  608.     // We want to get the subitem's rect in the co-ordinate space of the dialog
  609.     hWndList = CLV_GetHWND(globals.m_hPlaylistViewControl);
  610.     CLV_GetItemSubRect(globals.m_hPlaylistViewControl, &rSubItem, iItem, iSubItem);
  611.     ClientToScreen(hWndList, (POINT*)&rSubItem);
  612.     ClientToScreen(hWndList, ((POINT*)&rSubItem)+1);
  613.     ScreenToClient(IF_GetHWnd(windows.m_hifPlaylist), (POINT*)&rSubItem);
  614.     ScreenToClient(IF_GetHWnd(windows.m_hifPlaylist), ((POINT*)&rSubItem)+1);
  615.     if(iSubItem == PLAYLIST_GENRE)
  616.     {
  617.         int iRectHeight = rSubItem.bottom-rSubItem.top;
  618.         int iListHeight = iRectHeight<<3;
  619.         InflateRect(&rSubItem, 2, 2);
  620.         pcClass = "COMBOBOX";
  621.         uiControlID = IDC_PL_FLOATINGCOMBO;
  622.         dwStyle = CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL;
  623.         rSubItem.bottom += (rSubItem.bottom-rSubItem.top)<<3;
  624.     }
  625.     else
  626.     {
  627.         InflateRect(&rSubItem, 2, 2);
  628.         pcClass = "EDIT";
  629.         dwStyle = ES_AUTOHSCROLL;
  630.         uiControlID = IDC_PL_FLOATINGEDIT;
  631.         if(iSubItem == PLAYLIST_TRACKNUM || iSubItem == PLAYLIST_YEAR)
  632.             dwStyle |= ES_NUMBER;
  633.     }
  634.     // Setup window class and style (the Genre window will be a combo)
  635.     globals.m_bIP_InhibitUpdates = TRUE;
  636.     windows.wnd_playlist_IPEdit = CreateWindow( pcClass,
  637.                                   "",
  638.                                   WS_CHILD
  639.                                   | WS_BORDER
  640.                                   | WS_CLIPSIBLINGS
  641.                                   | dwStyle,
  642.                                   rSubItem.left, rSubItem.top,
  643.                                   rSubItem.right-rSubItem.left, rSubItem.bottom-rSubItem.top,
  644.                                   IF_GetHWnd(windows.m_hifPlaylist),
  645.                                   (HMENU)uiControlID,
  646.                                   GetModuleHandle(NULL), NULL);
  647.     SetWindowPos(windows.wnd_playlist_IPEdit, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  648.     ShowWindow(windows.wnd_playlist_IPEdit, SW_SHOW);
  649.     SetFocus(windows.wnd_playlist_IPEdit);
  650.     // Setup the font in the control
  651.     SendMessage(windows.wnd_playlist_IPEdit, WM_SETFONT, (WPARAM)glb_pSkin->mpl_hfFont, MAKELPARAM(TRUE, 0));
  652.     // Hook the listview window (so that we can dismiss on VScroll)
  653.     globals.m_hhkListView_Posted = SetWindowsHookEx(WH_GETMESSAGE, exp_ListViewHookProc_Posted, NULL, GetCurrentThreadId());
  654.     // Add the genre items to the list
  655.     if(iSubItem == PLAYLIST_GENRE)
  656.     {
  657.         int iGenreIDX;
  658.         for(iGenreIDX = 0; iGenreIDX < CIC_NUMGENRES; iGenreIDX++)
  659.         {
  660.             int iNewItemIDX = SendMessage(windows.wnd_playlist_IPEdit,
  661.                                           CB_ADDSTRING,
  662.                                           0L,
  663.                                           (LPARAM)glb_pcGenres[iGenreIDX]);
  664.             SendMessage(windows.wnd_playlist_IPEdit, CB_SETITEMDATA, (WPARAM)iNewItemIDX, (LPARAM)iGenreIDX);
  665.         }
  666.     }
  667.     // Setup the initial string
  668.     globals.m_iInPlaceSubItem = iSubItem;
  669.     {
  670.         switch(iSubItem)
  671.         {
  672.         case PLAYLIST_TITLE:
  673.             SendMessage(windows.wnd_playlist_IPEdit, WM_SETTEXT, 0L, (LPARAM)CPLI_GetTrackName(hClickedItem));
  674.             if(!options.support_id3v2)
  675.                 SendMessage(windows.wnd_playlist_IPEdit, EM_LIMITTEXT, 30, 0);
  676.             break;
  677.         case PLAYLIST_ARTIST:
  678.             SendMessage(windows.wnd_playlist_IPEdit, WM_SETTEXT, 0L, (LPARAM)CPLI_GetArtist(hClickedItem));
  679.             if(!options.support_id3v2)
  680.                 SendMessage(windows.wnd_playlist_IPEdit, EM_LIMITTEXT, 30, 0);
  681.             break;
  682.         case PLAYLIST_ALBUM:
  683.             SendMessage(windows.wnd_playlist_IPEdit, WM_SETTEXT, 0L, (LPARAM)CPLI_GetAlbum(hClickedItem));
  684.             if(!options.support_id3v2)
  685.                 SendMessage(windows.wnd_playlist_IPEdit, EM_LIMITTEXT, 30, 0);
  686.             break;
  687.         case PLAYLIST_YEAR:
  688.             SendMessage(windows.wnd_playlist_IPEdit, WM_SETTEXT, 0L, (LPARAM)CPLI_GetYear(hClickedItem));
  689.             if(!options.support_id3v2)
  690.                 SendMessage(windows.wnd_playlist_IPEdit, EM_LIMITTEXT, 4, 0);
  691.             break;
  692.         case PLAYLIST_TRACKNUM:
  693.             {
  694.                 char cTrackNum[33];
  695.                 unsigned char iTrackNum;
  696.                 iTrackNum = CPLI_GetTrackNum(hClickedItem);
  697.                 if(iTrackNum != CIC_INVALIDTRACKNUM && iTrackNum != 0)
  698.                     SendMessage(windows.wnd_playlist_IPEdit, WM_SETTEXT, 0L, (LPARAM)itoa(iTrackNum, cTrackNum, 10));
  699.             }
  700.             SendMessage(windows.wnd_playlist_IPEdit, EM_LIMITTEXT, 3, 0);
  701.             break;
  702.         case PLAYLIST_COMMENT:
  703.             SendMessage(windows.wnd_playlist_IPEdit, WM_SETTEXT, 0L, (LPARAM)CPLI_GetComment(hClickedItem));
  704.             if(!options.support_id3v2)
  705.                 SendMessage(windows.wnd_playlist_IPEdit, EM_LIMITTEXT, 28, 0);
  706.             break;
  707.         case PLAYLIST_GENRE:
  708.             SendMessage(windows.wnd_playlist_IPEdit, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)CPLI_GetGenre(hClickedItem));
  709.             break;
  710.         }
  711.     }
  712.     globals.m_bIP_InhibitUpdates = FALSE;
  713. }
  714. //
  715. //
  716. //
  717. BOOL CPlaylistWindow_OffsetSelectedItems(const int iOffset)
  718. {
  719.     int iNumItemsInList;
  720.     int iStartItem, iTermItem, iItemInc, iItemIDX;
  721.     int iScanStartItem, iScanTermItem;
  722.     CP_HPLAYLISTITEM hActive;
  723.     int iNewFocusItemIDX;
  724.     if(iOffset == 0)
  725.         return FALSE;
  726.     // Determine which direction to move in list
  727.     iNumItemsInList = CLV_GetItemCount(globals.m_hPlaylistViewControl);
  728.     if(iOffset < 0)
  729.     {
  730.         iStartItem = 0;
  731.         iTermItem = iNumItemsInList;
  732.         iItemInc = 1;
  733.         iScanStartItem = 0;
  734.         iScanTermItem = -iOffset;
  735.     }
  736.     else
  737.     {
  738.         iStartItem = iNumItemsInList-1;
  739.         iTermItem = -1;
  740.         iItemInc = -1;
  741.         iScanStartItem = iNumItemsInList-1;
  742.         iScanTermItem = iScanStartItem-iOffset;
  743.     }
  744.     // Ensure that the selection can move intact (ie there are no selected items that could
  745.     // be "scrolled off" the list
  746.     for(iItemIDX = iScanStartItem; iItemIDX != iScanTermItem; iItemIDX += iItemInc)
  747.     {
  748.         if(CLV_IsItemSelected(globals.m_hPlaylistViewControl, iItemIDX))
  749.             return FALSE;
  750.     }
  751.     iNewFocusItemIDX = CLV_GetFocusItem(globals.m_hPlaylistViewControl) + iOffset;
  752.     CLV_SetFocusItem(globals.m_hPlaylistViewControl, iNewFocusItemIDX);
  753.     CLV_EnsureVisible(globals.m_hPlaylistViewControl, iNewFocusItemIDX);
  754.     // Go through all the items scanning the -ve offset item and swapping it
  755.     // in if needed
  756.     for(iItemIDX = iStartItem; iItemIDX != iTermItem; iItemIDX += iItemInc)
  757.     {
  758.         // Work out the item to probe
  759.         const int iProbeItemIDX = iItemIDX - iOffset;
  760.         CP_HPLAYLISTITEM hItem, hItem_Probe, hReindexCursor;
  761.         CP_HPLAYLISTITEM hReindexStart, hReindexEnd;
  762.         int iReindexItemIDX;
  763.         // If this probe item is unselected (or out of bounds) - set the current item's selection
  764.         // to unselected and try the next item
  765.         if(iProbeItemIDX < 0 || iProbeItemIDX >= iNumItemsInList
  766.                 || CLV_IsItemSelected(globals.m_hPlaylistViewControl, iProbeItemIDX) == FALSE)
  767.         {
  768.             CLV_SetItemSelected(globals.m_hPlaylistViewControl, iItemIDX, FALSE);
  769.             continue;
  770.         }
  771.         // The probe item is selected - move that item over to this item
  772.         // - If the item is moving down it needs to be inserted after - otherwise it
  773.         // needs to be inserted before
  774.         hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iItemIDX);
  775.         hItem_Probe = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iProbeItemIDX);
  776.         if(iOffset > 0)
  777.         {
  778.             // Get start reindex item
  779.             hReindexStart = CPLI_Next(hItem_Probe);
  780.             if(hReindexStart == NULL)
  781.                 hReindexStart = CPL_GetFirstItem(globals.m_hPlaylist);
  782.             CPL_InsertItemAfter(globals.m_hPlaylist, hItem, hItem_Probe);
  783.             // Get end reindex item
  784.             hReindexEnd = CPLI_Next(hItem_Probe);
  785.             // Perform reindexing
  786.             iReindexItemIDX = iProbeItemIDX;
  787.             for(hReindexCursor = hReindexStart; hReindexCursor != hReindexEnd; hReindexCursor = CPLI_Next(hReindexCursor))
  788.             {
  789.                 CPLI_SetCookie(hReindexCursor, iReindexItemIDX);
  790.                 CPL_cb_OnItemUpdated(hReindexCursor);
  791.                 iReindexItemIDX++;
  792.             }
  793.         }
  794.         else
  795.         {
  796.             // Get start reindex item
  797.             hReindexStart = CPLI_Prev(hItem_Probe);
  798.             if(hReindexStart == NULL)
  799.                 hReindexStart = CPL_GetLastItem(globals.m_hPlaylist);
  800.             CPL_InsertItemBefore(globals.m_hPlaylist, hItem, hItem_Probe);
  801.             // Get end reindex item
  802.             hReindexEnd = CPLI_Prev(hItem_Probe);
  803.             // Perform reindexing
  804.             iReindexItemIDX = iProbeItemIDX;
  805.             for(hReindexCursor = hReindexStart; hReindexCursor != hReindexEnd; hReindexCursor = CPLI_Prev(hReindexCursor))
  806.             {
  807.                 CPLI_SetCookie(hReindexCursor, iReindexItemIDX);
  808.                 CPL_cb_OnItemUpdated(hReindexCursor);
  809.                 iReindexItemIDX--;
  810.             }
  811.         }
  812.         // Set the item's selection
  813.         CLV_SetItemSelected(globals.m_hPlaylistViewControl, iItemIDX, TRUE);
  814.     }
  815.     // Set the "active" item in the list
  816.     hActive = CPL_GetActiveItem(globals.m_hPlaylist);
  817.     return TRUE;
  818. }
  819. //
  820. //
  821. //
  822. void CPlaylistWindow_CB_onMouseMove(CP_HINTERFACE hInterface, const POINTS _ptMouse, const unsigned short iFlags)
  823. {
  824.     POINT ptMouse;
  825.     int iHitItem;
  826.     ptMouse.x = _ptMouse.x;
  827.     ptMouse.y = _ptMouse.y;
  828.     // Which item is this over?
  829.     ClientToScreen(IF_GetHWnd(windows.m_hifPlaylist), &ptMouse);
  830.     ScreenToClient(CLV_GetHWND(globals.m_hPlaylistViewControl), &ptMouse);
  831.     iHitItem = CLV_GetNearestItem(globals.m_hPlaylistViewControl, &ptMouse);
  832.     // Perform drag
  833.     if(iHitItem != CPC_INVALIDITEM && iHitItem != globals.main_drag_anchor_point)
  834.     {
  835.         BOOL bDragResult;
  836.         bDragResult = CPlaylistWindow_OffsetSelectedItems(iHitItem - globals.main_drag_anchor_point);
  837.         if(bDragResult == TRUE)
  838.             globals.main_drag_anchor_point = iHitItem;
  839.     }
  840. }
  841. //
  842. //
  843. //
  844. void CPlaylistWindow_CB_onMouseButton_LUp(CP_HINTERFACE hInterface, const POINTS ptMouse, const unsigned short iFlags)
  845. {
  846.     IF_ReleaseMouseCapture(windows.m_hifPlaylist);
  847. }
  848. //
  849. //
  850. //
  851. void CPlaylistWindow_WM_COMMAND_IDC_PL_FLOATINGEDIT(WPARAM wParam, LPARAM lParam)
  852. {
  853.     if(HIWORD(wParam) == EN_KILLFOCUS)
  854.     {
  855.         // Floating combo control looses focus - destroy it (after breaking out of kill focus context)
  856.         IF_PostAppMessage(windows.m_hifPlaylist, CPPLM_DESTROYINPLACE, 0L, 0L);
  857.     }
  858.     else if(HIWORD(wParam) == EN_CHANGE && globals.m_bIP_InhibitUpdates == FALSE)
  859.     {
  860.         int iSearchItemIDX;
  861.         char* pcEditText;
  862.         DWORD dwTextLen;
  863.         // Get the text from the control
  864.         dwTextLen = SendMessage(windows.wnd_playlist_IPEdit, WM_GETTEXTLENGTH, 0L, 0L) + 1;
  865.         pcEditText = (char*)malloc( dwTextLen * sizeof(char));
  866.         SendMessage(windows.wnd_playlist_IPEdit, WM_GETTEXT, (WPARAM)dwTextLen, (LPARAM)pcEditText);
  867.         // Update all of the selected items
  868.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  869.         for(;iSearchItemIDX != -1; iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX))
  870.         {
  871.             CP_HPLAYLISTITEM hPlaylistItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  872.             switch(globals.m_iInPlaceSubItem)
  873.             {
  874.             case PLAYLIST_TITLE:
  875.                 CPLI_SetTrackName(hPlaylistItem, pcEditText);
  876.                 break;
  877.             case PLAYLIST_ARTIST:
  878.                 CPLI_SetArtist(hPlaylistItem, pcEditText);
  879.                 break;
  880.             case PLAYLIST_ALBUM:
  881.                 CPLI_SetAlbum(hPlaylistItem, pcEditText);
  882.                 break;
  883.             case PLAYLIST_YEAR:
  884.                 CPLI_SetYear(hPlaylistItem, pcEditText);
  885.                 break;
  886.             case PLAYLIST_TRACKNUM:
  887.                 CPLI_SetTrackNum_AsText(hPlaylistItem, pcEditText);
  888.                 break;
  889.             case PLAYLIST_COMMENT:
  890.                 CPLI_SetComment(hPlaylistItem, pcEditText);
  891.                 break;
  892.             }
  893.         }
  894.         free(pcEditText);
  895.     }
  896. }
  897. //
  898. //
  899. //
  900. void CPlaylistWindow_WM_COMMAND_IDC_PL_FLOATINGCOMBO(WPARAM wParam, LPARAM lParam)
  901. {
  902.     if(HIWORD(wParam) == CBN_KILLFOCUS)
  903.     {
  904.         // Floating combo control looses focus - destroy it (after breaking out of kill focus context)
  905.         IF_PostAppMessage(windows.m_hifPlaylist, CPPLM_DESTROYINPLACE, 0L, 0L);
  906.     }
  907.     else if(HIWORD(wParam) == CBN_SELCHANGE && globals.m_bIP_InhibitUpdates == FALSE)
  908.     {
  909.         int iSearchItemIDX;
  910.         int iSelectedItemIDX;
  911.         unsigned char cNewGenre;
  912.         iSelectedItemIDX = SendMessage(windows.wnd_playlist_IPEdit, CB_GETCURSEL, 0L, 0L);
  913.         cNewGenre = (unsigned char)SendMessage(windows.wnd_playlist_IPEdit, CB_GETITEMDATA, (WPARAM)iSelectedItemIDX, 0L);
  914.         // Update all of the selected items
  915.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  916.         for(;iSearchItemIDX != -1; iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, iSearchItemIDX))
  917.         {
  918.             CP_HPLAYLISTITEM hPlaylistItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  919.             CPLI_SetGenreIDX(hPlaylistItem, cNewGenre);
  920.         }
  921.     }
  922. }
  923. //
  924. //
  925. //
  926. void LVCB_DrawBackgroundRect(CPs_DrawContext* pDC)
  927. {
  928.     RECT rClient;
  929.     GetClientRect(IF_GetHWnd(windows.m_hifPlaylist), &rClient);
  930.     // Draw the window background
  931.     CPIG_TiledFill(pDC, &rClient, &glb_pSkin->mpl_rBackground_SourceTile, glb_pSkin->mpl_pBackground, CIC_TILEDFILOPTIONS_NONE);
  932. }
  933. //
  934. //
  935. //
  936. void CPlaylistWindow_CB_onClose(CP_HINTERFACE hInterface)
  937. {
  938.     options.show_playlist = FALSE;
  939.     CPlaylistWindow_SetVisible(FALSE);
  940. }
  941. //
  942. //
  943. //
  944. void LVCB_HeaderChanged(CP_HLISTVIEW _hListData)
  945. {
  946.     CLV_GetColumnOrder(_hListData, options.playlist_column_seq, PLAYLIST_last + 1);
  947.     CLV_GetColumnWidths(_hListData, options.playlist_column_widths, PLAYLIST_last + 1);
  948.     CLV_GetColumnVisibleState(_hListData, options.playlist_column_visible, PLAYLIST_last + 1);
  949. }
  950. //
  951. //
  952. //
  953. void LVCB_ItemSelected(CP_HLISTVIEW _hListData, const int iItemIDX, const CP_HPLAYLISTITEM hItem)
  954. {
  955.     if(options.read_id3_tag_of_selected)
  956.         CPLI_ReadTag(hItem);
  957. }
  958. //
  959. //
  960. //
  961. void LVCB_ItemAction(CP_HLISTVIEW _hListData, const int iItemIDX, const CP_HPLAYLISTITEM hItem)
  962. {
  963.     // Setup & play the active item
  964.     if(CPL_Stack_GetItemState(globals.m_hPlaylist, hItem) == issUnstacked)
  965.     {
  966.         CPL_Stack_ClipFromCurrent(globals.m_hPlaylist);
  967.         CPL_Stack_Append(globals.m_hPlaylist, hItem);
  968.         CPL_SetActiveItem(globals.m_hPlaylist, hItem);
  969.         CPL_PlayItem(globals.m_hPlaylist, TRUE, pmCurrentItem);
  970.     }
  971.     else
  972.     {
  973.         CPL_SetActiveItem(globals.m_hPlaylist, hItem);
  974.         CPL_PlayItem(globals.m_hPlaylist, TRUE, pmCurrentItem);
  975.     }
  976. }
  977. //
  978. //
  979. //
  980. void LVCB_ItemDrag(CP_HLISTVIEW _hListData, const int iItemIDX, const CP_HPLAYLISTITEM hItem)
  981. {
  982.     globals.main_drag_anchor_point = iItemIDX;
  983.     IF_SetMouseCapture(windows.m_hifPlaylist, CPlaylistWindow_CB_onMouseMove, CPlaylistWindow_CB_onMouseButton_LUp);
  984. }
  985. //
  986. //
  987. //
  988. void LVCB_ColHeaderClick(CP_HLISTVIEW _hListData, const int iColIDX)
  989. {
  990.     // Work out assending or decending
  991.     BOOL bDesc;
  992.     if(iColIDX == globals.m_iLastPlaylistSortColoumn)
  993.     {
  994.         globals.m_iLastPlaylistSortColoumn = -1;
  995.         bDesc = TRUE;
  996.     }
  997.     else
  998.     {
  999.         globals.m_iLastPlaylistSortColoumn = iColIDX;
  1000.         bDesc = FALSE;
  1001.     }
  1002.     // Perform sorting
  1003.     switch(iColIDX)
  1004.     {
  1005.     case PLAYLIST_TRACKSTACK:
  1006.         CPL_SortList(globals.m_hPlaylist, piseTrackStackPos, FALSE);
  1007.         break;
  1008.     case PLAYLIST_TITLE:
  1009.         CPL_SortList(globals.m_hPlaylist, piseTrackName, bDesc);
  1010.         break;
  1011.     case PLAYLIST_ARTIST:
  1012.         CPL_SortList(globals.m_hPlaylist, piseArtist, bDesc);
  1013.         break;
  1014.     case PLAYLIST_ALBUM:
  1015.         CPL_SortList(globals.m_hPlaylist, piseAlbum, bDesc);
  1016.         break;
  1017.     case PLAYLIST_YEAR:
  1018.         CPL_SortList(globals.m_hPlaylist, piseYear, bDesc);
  1019.         break;
  1020.     case PLAYLIST_TRACKNUM:
  1021.         CPL_SortList(globals.m_hPlaylist, piseTrackNum, bDesc);
  1022.         break;
  1023.     case PLAYLIST_COMMENT:
  1024.         CPL_SortList(globals.m_hPlaylist, piseComment, bDesc);
  1025.         break;
  1026.     case PLAYLIST_GENRE:
  1027.         CPL_SortList(globals.m_hPlaylist, piseGenre, bDesc);
  1028.         break;
  1029.     case PLAYLIST_PATH:
  1030.         CPL_SortList(globals.m_hPlaylist, pisePath, bDesc);
  1031.         break;
  1032.     case PLAYLIST_FILENAME:
  1033.         CPL_SortList(globals.m_hPlaylist, piseFilename, bDesc);
  1034.         break;
  1035.     case PLAYLIST_LENGTH:
  1036.         CPL_SortList(globals.m_hPlaylist, piseLength, bDesc);
  1037.         break;
  1038.     }
  1039. }
  1040. //
  1041. //
  1042. //
  1043. void LVCB_ItemRightClick(CP_HLISTVIEW _hListData, const int iItemIDX, const int iColumnIDX, const CP_HPLAYLISTITEM hItem)
  1044. {
  1045.     IF_PostAppMessage(windows.m_hifPlaylist, CPPLM_CREATEINPLACE, (WPARAM)iItemIDX, (LPARAM)iColumnIDX);
  1046. }
  1047. //
  1048. //
  1049. //
  1050. void LVCB_UnhandledKeyPress(CP_HLISTVIEW _hListData, const int iVKey, const BOOL bAlt, const BOOL bCtrl, const BOOL bShift)
  1051. {
  1052.     CP_HandleKeyPress_Playlist(windows.m_hWndPlaylist, iVKey, bAlt, bCtrl, bShift);
  1053. }
  1054. //
  1055. //
  1056. //
  1057. void CPlaylistWindow_ClearSelectedItems()
  1058. {
  1059.     int iSearchItemIDX;
  1060.     int iFocusItem;
  1061.     CLV_BeginBatch(globals.m_hPlaylistViewControl);
  1062.     iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  1063.     while(iSearchItemIDX != CPC_INVALIDITEM)
  1064.     {
  1065.         CP_HPLAYLISTITEM hItem = (CP_HPLAYLISTITEM)CLV_GetItemData(globals.m_hPlaylistViewControl, iSearchItemIDX);
  1066.         CPL_RemoveItem(globals.m_hPlaylist, hItem);
  1067.         iSearchItemIDX = CLV_GetNextSelectedItem(globals.m_hPlaylistViewControl, CPC_INVALIDITEM);
  1068.     }
  1069.     iFocusItem = CLV_GetFocusItem(globals.m_hPlaylistViewControl);
  1070.     if(iFocusItem != CPC_INVALIDITEM)
  1071.         CLV_SetItemSelected(globals.m_hPlaylistViewControl, iFocusItem, TRUE);
  1072.     CLV_EndBatch(globals.m_hPlaylistViewControl);
  1073. }
  1074. //
  1075. //
  1076. //
  1077. void CPlaylistWindow_CB_onCreate(CP_HINTERFACE hInterface, const RECT* pInitialPosition)
  1078. {
  1079.     CPlaylistWindow_CreateListView();
  1080. }
  1081. //
  1082. //
  1083. //
  1084. void CPlaylistWindow_CB_onDraw(CP_HINTERFACE hInterface, CPs_DrawContext* pContext)
  1085. {
  1086.     RECT rClient;
  1087.     // Draw the window background
  1088.     GetClientRect(IF_GetHWnd(windows.m_hifPlaylist), &rClient);
  1089.     CPIG_TiledFill(pContext, &rClient, &glb_pSkin->mpl_rBackground_SourceTile, glb_pSkin->mpl_pBackground, CIC_TILEDFILOPTIONS_NONE);
  1090. }
  1091. //
  1092. //
  1093. //
  1094. void CPlaylistWindow_CB_onKeyDown(CP_HINTERFACE hInterface, const unsigned int iVKeyCode, const BOOL bAlt, const BOOL bCtrl, const BOOL bShift)
  1095. {
  1096.     CP_HandleKeyPress_Playlist(NULL, iVKeyCode, bAlt, bCtrl, bShift);
  1097. }
  1098. //
  1099. //
  1100. //
  1101. void CPlaylistWindow_CB_onDropFiles(CP_HINTERFACE hInterface, HDROP hDrop)
  1102. {
  1103.     CPL_SyncLoadNextFile(globals.m_hPlaylist);
  1104.     CPL_AddDroppedFiles(globals.m_hPlaylist, hDrop);
  1105. }
  1106. //
  1107. //
  1108. //
  1109. void CPlaylistWindow_CB_onPosChange(CP_HINTERFACE hInterface, const RECT* pNewPosition, const BOOL bSizeChanged)
  1110. {
  1111.     options.playlist_window_pos = *pNewPosition;
  1112.     if(bSizeChanged)
  1113.     {
  1114.         SIZE szWindow;
  1115.         szWindow.cx = pNewPosition->right - pNewPosition->left;
  1116.         szWindow.cy = pNewPosition->bottom - pNewPosition->top;
  1117.         MoveWindow(CLV_GetHWND(globals.m_hPlaylistViewControl),
  1118.                    glb_pSkin->mpl_rList_Border.left,
  1119.                    glb_pSkin->mpl_rList_Border.top,
  1120.                    (szWindow.cx - glb_pSkin->mpl_rList_Border.right) - glb_pSkin->mpl_rList_Border.left,
  1121.                    (szWindow.cy - glb_pSkin->mpl_rList_Border.bottom) - glb_pSkin->mpl_rList_Border.top,
  1122.                    TRUE);
  1123.     }
  1124. }
  1125. //
  1126. //
  1127. //
  1128. void CPlaylistWindow_CB_onFocus(CP_HINTERFACE hInterface, const BOOL bHasFocus)
  1129. {
  1130.     if(bHasFocus == TRUE)
  1131.         SetFocus(CLV_GetHWND(globals.m_hPlaylistViewControl));
  1132. }
  1133. //
  1134. //
  1135. //
  1136. void CPlaylistWindow_CB_onCommandMessage(CP_HINTERFACE hInterface, const WPARAM wParam, const LPARAM lParam)
  1137. {
  1138.     if(LOWORD(wParam) == IDC_PL_FLOATINGEDIT)
  1139.         CPlaylistWindow_WM_COMMAND_IDC_PL_FLOATINGEDIT(wParam, lParam);
  1140.     else if(LOWORD(wParam) == IDC_PL_FLOATINGCOMBO)
  1141.         CPlaylistWindow_WM_COMMAND_IDC_PL_FLOATINGCOMBO(wParam, lParam);
  1142. }
  1143. //
  1144. //
  1145. //
  1146. LRESULT CPlaylistWindow_CB_onAppMessage(CP_HINTERFACE hInterface, const UINT uiMessage, const WPARAM wParam, const LPARAM lParam)
  1147. {
  1148.     if(uiMessage == CPPLM_CREATEINPLACE)
  1149.     {
  1150.         int iItem = (int)wParam;
  1151.         int iSubItem = (int)lParam;
  1152.         CPlaylistWindow_DestroyIPEdit();
  1153.         // It's a hit - create sub control (for IP controls)
  1154.         if(iItem != CPC_INVALIDITEM && iSubItem != CPC_INVALIDCOLUMN)
  1155.         {
  1156.             if(iSubItem != PLAYLIST_TRACKSTACK
  1157.                     && iSubItem != PLAYLIST_PATH
  1158.                     && iSubItem != PLAYLIST_FILENAME)
  1159.             {
  1160.                 CPlaylistWindow_CreateIPEdit(iItem, iSubItem);
  1161.             }
  1162.             else if(iSubItem == PLAYLIST_TRACKSTACK)
  1163.             {
  1164.                 CPlaylistWindow_TrackStackMenu(iItem);
  1165.             }
  1166.             else if(iSubItem == PLAYLIST_PATH || iSubItem == PLAYLIST_FILENAME)
  1167.             {
  1168.                 CPlaylistWindow_RenameMenu(iItem, iSubItem);
  1169.             }
  1170.         }
  1171.     }
  1172.     else if(uiMessage == CPPLM_DESTROYINPLACE)
  1173.         CPlaylistWindow_DestroyIPEdit();
  1174.     return 0;
  1175. }
  1176. //
  1177. //
  1178. //
  1179. CPe_CustomDrawColour LVCB_GetTrackStackItemColour(const void* pvItemData)
  1180. {
  1181.     CP_HPLAYLISTITEM hItem = (CP_HPLAYLISTITEM)pvItemData;
  1182.     int iTrackStackPos;
  1183.     iTrackStackPos = CPLI_GetTrackStackPos(hItem);
  1184.     if(iTrackStackPos == CIC_TRACKSTACK_UNSTACKED)
  1185.         return cdcNormal;
  1186.     else if(iTrackStackPos == 0)
  1187.         return cdcHighlighted;
  1188.     else if(iTrackStackPos < 0)
  1189.         return cdcLowlighted;
  1190.     return cdcNormal;
  1191. }
  1192. //
  1193. //
  1194. //
  1195. CPe_CustomDrawColour LVCB_GetItemColour(const void* pvItemData)
  1196. {
  1197.     CP_HPLAYLISTITEM hItem = (CP_HPLAYLISTITEM)pvItemData;
  1198.     if(CPLI_GetTrackStackPos(hItem) == 0)
  1199.         return cdcHighlighted;
  1200.     return cdcNormal;
  1201. }
  1202. //
  1203. //
  1204. //