playlist.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:33k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * playlist.cpp : WinCE gui plugin for VLC
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2004 the VideoLAN team
  5.  * $Id: fd695a4b8ff09051db0517036acb26104f9bdf79 $
  6.  *
  7.  * Authors: Marodon Cedric <cedric_marodon@yahoo.fr>
  8.  *          Gildas Bazin <gbazin@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <vlc_interface.h>
  32. #include <vlc_playlist.h>
  33. #include "wince.h"
  34. #include <commctrl.h>
  35. #include <commdlg.h>
  36. #ifndef TEXTMAXBUF
  37. #define TEXTMAXBUF 512 // at least 500
  38. #endif
  39. #define LONG2POINT(l, pt)  ((pt).x = (SHORT)LOWORD(l), (pt).y = (SHORT)HIWORD(l))
  40. #define NUMIMAGES     11   // Number of buttons in the toolbar
  41. #define IMAGEWIDTH    16   // Width of the buttons in the toolbar
  42. #define IMAGEHEIGHT   16   // Height of the buttons in the toolbar
  43. #define BUTTONWIDTH   0    // Width of the button images in the toolbar
  44. #define BUTTONHEIGHT  0    // Height of the button images in the toolbar
  45. #define ID_TOOLBAR    2000 // Identifier of the main tool bar
  46. enum
  47. {
  48.   Infos_Event = 1000,
  49.   Up_Event,
  50.   Down_Event,
  51.   Random_Event,
  52.   Loop_Event,
  53.   Repeat_Event,
  54.   PopupPlay_Event,
  55.   PopupDel_Event,
  56.   PopupEna_Event,
  57.   PopupInfo_Event
  58. };
  59. // Help strings
  60. #define HELP_OPENPL _T("Open playlist")
  61. #define HELP_SAVEPL _T("Save playlist")
  62. #define HELP_ADDFILE _T("Add File")
  63. #define HELP_ADDMRL _T("Add MRL")
  64. #define HELP_DELETE _T("Delete selection")
  65. #define HELP_INFOS _T("Item info")
  66. #define HELP_UP _T("Up")
  67. #define HELP_DOWN _T("Down")
  68. #define HELP_RANDOM _T("Random")
  69. #define HELP_LOOP _T("Repeat all")
  70. #define HELP_REPEAT _T("Repeat one")
  71. // The TBBUTTON structure contains information the toolbar buttons.
  72. static TBBUTTON tbButton2[] =
  73. {
  74.   {0,  ID_MANAGE_OPENPL,        TBSTATE_ENABLED, TBSTYLE_BUTTON },
  75.   {1,  ID_MANAGE_SAVEPL,        TBSTATE_ENABLED, TBSTYLE_BUTTON },
  76.   {0,  0,                       TBSTATE_ENABLED, TBSTYLE_SEP    },
  77.   {2,  ID_MANAGE_ADDFILE,       TBSTATE_ENABLED, TBSTYLE_BUTTON },
  78.   {3,  ID_MANAGE_ADDMRL,        TBSTATE_ENABLED, TBSTYLE_BUTTON },
  79.   {4,  ID_SEL_DELETE,           TBSTATE_ENABLED, TBSTYLE_BUTTON },
  80.   {0,  0,                       TBSTATE_ENABLED, TBSTYLE_SEP    },
  81.   {5,  Infos_Event,             TBSTATE_ENABLED, TBSTYLE_BUTTON },
  82.   {0,  0,                       TBSTATE_ENABLED, TBSTYLE_SEP    },
  83.   {6,  Up_Event,                TBSTATE_ENABLED, TBSTYLE_BUTTON },
  84.   {7,  Down_Event,              TBSTATE_ENABLED, TBSTYLE_BUTTON },
  85.   {0,  0,                       TBSTATE_ENABLED, TBSTYLE_SEP    },
  86.   {8,  Random_Event,            TBSTATE_ENABLED, TBSTYLE_CHECK  },
  87.   {9,  Loop_Event,              TBSTATE_ENABLED, TBSTYLE_CHECK  },
  88.   {10, Repeat_Event,            TBSTATE_ENABLED, TBSTYLE_CHECK  }
  89. };
  90. // Toolbar ToolTips
  91. TCHAR * szToolTips2[] =
  92. {
  93.     HELP_OPENPL,
  94.     HELP_SAVEPL,
  95.     HELP_ADDFILE,
  96.     HELP_ADDMRL,
  97.     HELP_DELETE,
  98.     HELP_INFOS,
  99.     HELP_UP,
  100.     HELP_DOWN,
  101.     HELP_RANDOM,
  102.     HELP_LOOP,
  103.     HELP_REPEAT
  104. };
  105. /*****************************************************************************
  106.  * Event Table.
  107.  *****************************************************************************/
  108. /*****************************************************************************
  109.  * Constructor.
  110.  *****************************************************************************/
  111. Playlist::Playlist( intf_thread_t *p_intf, CBaseWindow *p_parent,
  112.                     HINSTANCE h_inst )
  113.   :  CBaseWindow( p_intf, p_parent, h_inst )
  114. {
  115.     /* Initializations */
  116.     hListView = NULL;
  117.     i_title_sorted = 1;
  118.     i_author_sorted = 1;
  119.     b_need_update = true;
  120. }
  121. /***********************************************************************
  122. FUNCTION:
  123.   CreateMenuBar
  124. PURPOSE:
  125.   Creates a menu bar.
  126. ***********************************************************************/
  127. static HWND CreateMenuBar( HWND hwnd, HINSTANCE hInst )
  128. {
  129. #ifdef UNDER_CE
  130.     SHMENUBARINFO mbi;
  131.     memset( &mbi, 0, sizeof(SHMENUBARINFO) );
  132.     mbi.cbSize     = sizeof(SHMENUBARINFO);
  133.     mbi.hwndParent = hwnd;
  134.     mbi.hInstRes   = hInst;
  135.     mbi.nToolBarId = IDR_MENUBAR2;
  136.     if( !SHCreateMenuBar( &mbi ) )
  137.     {
  138.         MessageBox(hwnd, _T("SHCreateMenuBar Failed"), _T("Error"), MB_OK);
  139.         return 0;
  140.     }
  141.     TBBUTTONINFO tbbi;
  142.     tbbi.cbSize = sizeof(tbbi);
  143.     tbbi.dwMask = TBIF_LPARAM;
  144.     SendMessage( mbi.hwndMB, TB_GETBUTTONINFO, IDM_MANAGE, (LPARAM)&tbbi );
  145.     HMENU hmenu_file = (HMENU)tbbi.lParam;
  146.     RemoveMenu( hmenu_file, 0, MF_BYPOSITION );
  147.     SendMessage( mbi.hwndMB, TB_GETBUTTONINFO, IDM_SORT, (LPARAM)&tbbi );
  148.     HMENU hmenu_sort = (HMENU)tbbi.lParam;
  149.     RemoveMenu( hmenu_sort, 0, MF_BYPOSITION );
  150.     SendMessage( mbi.hwndMB, TB_GETBUTTONINFO, IDM_SEL, (LPARAM)&tbbi );
  151.     HMENU hmenu_sel = (HMENU)tbbi.lParam;
  152.     RemoveMenu( hmenu_sel, 0, MF_BYPOSITION );
  153. #else
  154.     HMENU hmenu_file = CreatePopupMenu();
  155.     HMENU hmenu_sort = CreatePopupMenu();
  156.     HMENU hmenu_sel = CreatePopupMenu();
  157. #endif
  158.     AppendMenu( hmenu_file, MF_STRING, ID_MANAGE_ADDFILE,
  159.                 _T("&Add File...") );
  160.     AppendMenu( hmenu_file, MF_STRING, ID_MANAGE_ADDDIRECTORY,
  161.                 _T("Add Directory...") );
  162.     AppendMenu( hmenu_file, MF_STRING, ID_MANAGE_ADDMRL,
  163.                 _T("Add MRL...") );
  164.     AppendMenu( hmenu_file, MF_SEPARATOR, 0, 0 );
  165.     AppendMenu( hmenu_file, MF_STRING, ID_MANAGE_OPENPL,
  166.                 _T("Open &Playlist") );
  167.     AppendMenu( hmenu_file, MF_STRING, ID_MANAGE_SAVEPL,
  168.                 _T("Save Playlist") );
  169.     AppendMenu( hmenu_sort, MF_STRING, ID_SORT_TITLE,
  170.                 _T("Sort by &title") );
  171.     AppendMenu( hmenu_sort, MF_STRING, ID_SORT_RTITLE,
  172.                 _T("&Reverse sort by title") );
  173.     AppendMenu( hmenu_sort, MF_SEPARATOR, 0, 0 );
  174.     AppendMenu( hmenu_sort, MF_STRING, ID_SORT_AUTHOR,
  175.                 _T("Sort by &author") );
  176.     AppendMenu( hmenu_sort, MF_STRING, ID_SORT_RAUTHOR,
  177.                 _T("Reverse sort by &author") );
  178.     AppendMenu( hmenu_sort, MF_SEPARATOR, 0, 0 );
  179.     AppendMenu( hmenu_sort, MF_STRING, ID_SORT_SHUFFLE,
  180.                 _T("&Shuffle Playlist") );
  181.     AppendMenu( hmenu_sel, MF_STRING, ID_SEL_ENABLE,
  182.                 _T("&Enable") );
  183.     AppendMenu( hmenu_sel, MF_STRING, ID_SEL_DISABLE,
  184.                 _T("&Disable") );
  185.     AppendMenu( hmenu_sel, MF_SEPARATOR, 0, 0 );
  186.     AppendMenu( hmenu_sel, MF_STRING, ID_SEL_INVERT,
  187.                 _T("&Invert") );
  188.     AppendMenu( hmenu_sel, MF_STRING, ID_SEL_DELETE,
  189.                 _T("D&elete") );
  190.     AppendMenu( hmenu_sel, MF_SEPARATOR, 0, 0 );
  191.     AppendMenu( hmenu_sel, MF_STRING, ID_SEL_SELECTALL,
  192.                 _T("&Select All") );
  193. #ifdef UNDER_CE
  194.     return mbi.hwndMB;
  195. #else
  196.     HMENU hmenu = CreateMenu();
  197.     AppendMenu( hmenu, MF_POPUP|MF_STRING, (UINT)hmenu_file, _T("Manage") );
  198.     AppendMenu( hmenu, MF_POPUP|MF_STRING, (UINT)hmenu_sort, _T("Sort") );
  199.     AppendMenu( hmenu, MF_POPUP|MF_STRING, (UINT)hmenu_sel, _T("Selection") );
  200.     SetMenu( hwnd, hmenu );
  201.     return hwnd;
  202. #endif
  203. }
  204. /***********************************************************************
  205. FUNCTION:
  206.   WndProc
  207. PURPOSE:
  208.   Processes messages sent to the main window.
  209. ***********************************************************************/
  210. LRESULT Playlist::WndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
  211. {
  212.     SHINITDLGINFO shidi;
  213.     SHMENUBARINFO mbi;
  214.     INITCOMMONCONTROLSEX iccex;
  215.     RECT rect, rectTB;
  216.     DWORD dwStyle;
  217.     int bState;
  218.     playlist_t *p_playlist;
  219.     switch( msg )
  220.     {
  221.     case WM_INITDIALOG:
  222.         shidi.dwMask = SHIDIM_FLAGS;
  223.         shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN |
  224.             SHIDIF_FULLSCREENNOMENUBAR;//SHIDIF_SIZEDLGFULLSCREEN;
  225.         shidi.hDlg = hwnd;
  226.         SHInitDialog( &shidi );
  227.         hwndCB = CreateMenuBar( hwnd, hInst );
  228.         iccex.dwSize = sizeof (INITCOMMONCONTROLSEX);
  229.         iccex.dwICC = ICC_BAR_CLASSES;
  230.         // Registers TOOLBAR control classes from the common control dll
  231.         InitCommonControlsEx (&iccex);
  232.         //  Create the toolbar control.
  233.         dwStyle = WS_VISIBLE | WS_CHILD | TBSTYLE_TOOLTIPS |
  234.             WS_EX_OVERLAPPEDWINDOW | CCS_NOPARENTALIGN;
  235.         hwndTB = CreateToolbarEx( hwnd, dwStyle, 0, NUMIMAGES,
  236.                                   hInst, IDB_BITMAP3, tbButton2,
  237.                                   sizeof (tbButton2) / sizeof (TBBUTTON),
  238.                                   BUTTONWIDTH, BUTTONHEIGHT,
  239.                                   IMAGEWIDTH, IMAGEHEIGHT, sizeof(TBBUTTON) );
  240.         if( !hwndTB ) break;
  241.  
  242.         // Add ToolTips to the toolbar.
  243.         SendMessage( hwndTB, TB_SETTOOLTIPS, (WPARAM) NUMIMAGES,
  244.                      (LPARAM)szToolTips2 );
  245.         // Reposition the toolbar.
  246.         GetClientRect( hwnd, &rect );
  247.         GetWindowRect( hwndTB, &rectTB );
  248.         MoveWindow( hwndTB, rect.left, rect.top - 2, rect.right - rect.left,
  249.                     MENU_HEIGHT /*rectTB.bottom - rectTB.top */, TRUE);
  250.         // random, loop, repeat buttons states
  251.         vlc_value_t val;
  252.         p_playlist = pl_Hold( p_intf );
  253.         if( !p_playlist ) break;
  254.         var_Get( p_playlist , "random", &val );
  255.         bState = val.b_bool ? TBSTATE_CHECKED : 0;
  256.         SendMessage( hwndTB, TB_SETSTATE, Random_Event,
  257.                      MAKELONG(bState | TBSTATE_ENABLED, 0) );
  258.         var_Get( p_playlist , "loop", &val );
  259.         bState = val.b_bool ? TBSTATE_CHECKED : 0;
  260.         SendMessage( hwndTB, TB_SETSTATE, Loop_Event,
  261.                      MAKELONG(bState | TBSTATE_ENABLED, 0) );
  262.         var_Get( p_playlist , "repeat", &val );
  263.         bState = val.b_bool ? TBSTATE_CHECKED : 0;
  264.         SendMessage( hwndTB, TB_SETSTATE, Repeat_Event,
  265.                      MAKELONG(bState | TBSTATE_ENABLED, 0) );
  266.         pl_Release( p_intf );
  267.         GetClientRect( hwnd, &rect );
  268.         hListView = CreateWindow( WC_LISTVIEW, NULL, WS_VISIBLE | WS_CHILD |
  269.             LVS_REPORT | LVS_SHOWSELALWAYS | WS_VSCROLL | WS_HSCROLL,
  270.             rect.left, rect.top + 2*(MENU_HEIGHT+1), rect.right - rect.left,
  271.             rect.bottom - ( rect.top + 2*MENU_HEIGHT) - MENU_HEIGHT,
  272.             hwnd, NULL, hInst, NULL );
  273.         ListView_SetExtendedListViewStyle( hListView, LVS_EX_FULLROWSELECT );
  274.         LVCOLUMN lv;
  275.         lv.mask = LVCF_WIDTH | LVCF_FMT | LVCF_TEXT;
  276.         lv.fmt = LVCFMT_LEFT ;
  277.         GetClientRect( hwnd, &rect );
  278.         lv.cx = 120;
  279.         lv.pszText = _T("Name");
  280.         lv.cchTextMax = 9;
  281.         ListView_InsertColumn( hListView, 0, &lv);
  282.         lv.cx = 55;
  283.         lv.pszText = _T("Author");
  284.         lv.cchTextMax = 9;
  285.         ListView_InsertColumn( hListView, 1, &lv);
  286.         lv.cx = rect.right - rect.left - 180;
  287.         lv.pszText = _T("Duration");
  288.         lv.cchTextMax = 9;
  289.         ListView_InsertColumn( hListView, 2, &lv);
  290.         SetTimer( hwnd, 1, 500 /*milliseconds*/, NULL );
  291.         break;
  292.     case WM_TIMER:
  293.         UpdatePlaylist();
  294.         break;
  295.     case WM_CLOSE:
  296.         EndDialog( hwnd, LOWORD( wp ) );
  297.         break;
  298.     case WM_SETFOCUS:
  299.         SHSipPreference( hwnd, SIP_DOWN );
  300.         SHFullScreen( hwnd, SHFS_HIDESIPBUTTON );
  301.         break;
  302.     case WM_COMMAND:
  303.         switch( LOWORD(wp) )
  304.         {
  305.         case IDOK:
  306.             EndDialog( hwnd, LOWORD( wp ) );
  307.             break;
  308.         case ID_MANAGE_OPENPL:
  309.             OnOpen();
  310.             b_need_update = true;
  311.             break;
  312.         case ID_MANAGE_SAVEPL:
  313.             OnSave();
  314.             break;
  315.         case ID_MANAGE_ADDFILE:
  316.             p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_SIMPLE,
  317.                                            0, 0 );
  318.             b_need_update = true;
  319.             break;
  320.         case ID_MANAGE_ADDDIRECTORY:
  321.             p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_DIRECTORY,
  322.                                            0, 0 );
  323.             b_need_update = true;
  324.             break;
  325.         case ID_MANAGE_ADDMRL:
  326.             p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE, 0, 0 );
  327.             b_need_update = true;
  328.             break;
  329.         case ID_SEL_DELETE:
  330.             OnDeleteSelection();
  331.             b_need_update = true;
  332.             break;
  333.         case Infos_Event:
  334.             OnPopupInfo( hwnd );
  335.             b_need_update = true;
  336.             break;
  337.         case Up_Event:
  338.             OnUp();
  339.             b_need_update = true;
  340.             break;
  341.         case Down_Event:
  342.             OnDown();
  343.             b_need_update = true;
  344.             break;
  345.         case Random_Event:
  346.             OnRandom();
  347.             break;
  348.         case Loop_Event:
  349.             OnLoop();
  350.             break;
  351.         case Repeat_Event:
  352.             OnRepeat();
  353.             break;
  354.         case ID_SORT_TITLE:
  355.             OnSort( ID_SORT_TITLE );
  356.             break;
  357.         case ID_SORT_RTITLE:
  358.             OnSort( ID_SORT_RTITLE );
  359.             break;
  360.         case ID_SORT_AUTHOR:
  361.             OnSort( ID_SORT_AUTHOR );
  362.             break;
  363.         case ID_SORT_RAUTHOR:
  364.             OnSort( ID_SORT_RAUTHOR );
  365.             break;
  366.         case ID_SORT_SHUFFLE:
  367.             OnSort( ID_SORT_SHUFFLE );
  368.             break;
  369.         case ID_SEL_ENABLE:
  370.             OnEnableSelection();
  371.             break;
  372.         case ID_SEL_DISABLE:
  373.             OnDisableSelection();
  374.             break;
  375.         case ID_SEL_INVERT:
  376.             OnInvertSelection();
  377.             break;
  378.         case ID_SEL_SELECTALL:
  379.             OnSelectAll();
  380.             break;
  381.         case PopupPlay_Event:
  382.             OnPopupPlay();
  383.             b_need_update = true;
  384.             break;
  385.         case PopupDel_Event:
  386.             OnPopupDel();
  387.             b_need_update = true;
  388.             break;
  389.         case PopupEna_Event:
  390.             OnPopupEna();
  391.             b_need_update = true;
  392.             break;
  393.         case PopupInfo_Event:
  394.             OnPopupInfo( hwnd );
  395.             b_need_update = true;
  396.             break;
  397.         default:
  398.             break;
  399.         }
  400.         break;
  401.     case WM_NOTIFY:
  402.         if( ( ((LPNMHDR)lp)->hwndFrom == hListView ) &&
  403.             ( ((LPNMHDR)lp)->code == NM_CUSTOMDRAW ) )
  404.         {
  405.             SetWindowLong( hwnd, DWL_MSGRESULT,
  406.                            (LONG)ProcessCustomDraw(lp) );
  407.         }
  408.         else if( ( ((LPNMHDR)lp)->hwndFrom == hListView ) &&
  409.                  ( ((LPNMHDR)lp)->code == GN_CONTEXTMENU  ) )
  410.         {
  411.             HandlePopupMenu( hwnd, ((PNMRGINFO)lp)->ptAction );
  412.         }
  413.         else if( ( ((LPNMHDR)lp)->hwndFrom == hListView ) &&
  414.                  ( ((LPNMHDR)lp)->code == LVN_COLUMNCLICK  ) )
  415.         {
  416.             OnColSelect( ((LPNMLISTVIEW)lp)->iSubItem );
  417.         }
  418.         else if( ( ((LPNMHDR)lp)->hwndFrom == hListView ) &&
  419.                  ( ((LPNMHDR)lp)->code == LVN_ITEMACTIVATE  ) )
  420.         {
  421.             OnActivateItem( ((LPNMLISTVIEW)lp)->iSubItem );
  422.         }
  423.         break;
  424.     default:
  425.          // the message was not processed
  426.          // indicate if the base class handled it
  427.         break;
  428.     }
  429.     return FALSE;
  430. }
  431. LRESULT Playlist::ProcessCustomDraw( LPARAM lParam )
  432. {
  433.     LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
  434.     switch( lplvcd->nmcd.dwDrawStage )
  435.     {
  436.     case CDDS_PREPAINT : //Before the paint cycle begins
  437.         //request notifications for individual listview items
  438.         return CDRF_NOTIFYITEMDRAW;
  439.     case CDDS_ITEMPREPAINT: //Before an item is drawn
  440.         playlist_t *p_playlist = pl_Hold( p_intf );
  441.         if( p_playlist == NULL ) return CDRF_DODEFAULT;
  442.         if( (int)lplvcd->nmcd.dwItemSpec == p_playlist->i_current_index )
  443.         {
  444.             lplvcd->clrText = RGB(255,0,0);
  445.             pl_Release( p_intf );
  446.             return CDRF_NEWFONT;
  447.         }
  448.         PL_LOCK;
  449.         playlist_item_t *p_item = playlist_ItemGetById( p_playlist,
  450.                                         (int)lplvcd->nmcd.dwItemSpec );
  451.         if( !p_item )
  452.         {
  453.             PL_UNLOCK;
  454.             pl_Release( p_intf );
  455.             return CDRF_DODEFAULT;
  456.         }
  457.         if( p_item->i_flags & PLAYLIST_DBL_FLAG )
  458.         {
  459.             lplvcd->clrText = RGB(192,192,192);
  460.             PL_UNLOCK;
  461.             pl_Release( p_intf );
  462.             return CDRF_NEWFONT;
  463.         }
  464.         PL_UNLOCK;
  465.         pl_Release( p_intf );
  466.     }
  467.     return CDRF_DODEFAULT;
  468. }
  469. /**********************************************************************
  470.  * Handles the display of the "floating" popup
  471.  **********************************************************************/
  472. void Playlist::HandlePopupMenu( HWND hwnd, POINT point )
  473. {
  474.     HMENU hMenuTrackPopup;
  475.     // Create the popup menu.
  476.     hMenuTrackPopup = CreatePopupMenu();
  477.     // Append some items.
  478.     AppendMenu( hMenuTrackPopup, MF_STRING, PopupPlay_Event, _T("Play") );
  479.     AppendMenu( hMenuTrackPopup, MF_STRING, PopupDel_Event, _T("Delete") );
  480.     AppendMenu( hMenuTrackPopup, MF_STRING, PopupEna_Event,
  481.                 _T("Toggle enabled") );
  482.     AppendMenu( hMenuTrackPopup, MF_STRING, PopupInfo_Event, _T("Info") );
  483.     /* Draw and track the "floating" popup */
  484.     TrackPopupMenu( hMenuTrackPopup, 0, point.x, point.y, 0, hwnd, NULL );
  485.     /* Destroy the menu since were are done with it. */
  486.     DestroyMenu( hMenuTrackPopup );
  487. }
  488. /**********************************************************************
  489.  * Show the playlist
  490.  **********************************************************************/
  491. void Playlist::ShowPlaylist( bool b_show )
  492. {
  493.     if( b_show ) Rebuild();
  494.     Show( b_show );
  495. }
  496. /**********************************************************************
  497.  * Update the playlist
  498.  **********************************************************************/
  499. void Playlist::UpdatePlaylist()
  500. {
  501.     if( b_need_update )
  502.     {
  503.         Rebuild();
  504.         b_need_update = false;
  505.     }
  506.  
  507.     playlist_t *p_playlist = pl_Hold( p_intf );
  508.     if( p_playlist == NULL ) return;
  509.  
  510.     /* Update the colour of items */
  511.     PL_LOCK;
  512.     if( p_intf->p_sys->i_playing != playlist_CurrentSize( p_playlist ) )
  513.     {
  514.         // p_playlist->i_index in RED
  515.         Rebuild();
  516.         // if exists, p_intf->p_sys->i_playing in BLACK
  517.         p_intf->p_sys->i_playing = p_playlist->i_current_index;
  518.     }
  519.     PL_UNLOCK;
  520.     pl_Release( p_intf );
  521. }
  522. /**********************************************************************
  523.  * Rebuild the playlist
  524.  **********************************************************************/
  525. void Playlist::Rebuild()
  526. {
  527.     playlist_t *p_playlist = pl_Hold( p_intf );
  528.     if( p_playlist == NULL ) return;
  529.     int i_focused =
  530.         ListView_GetNextItem( hListView, -1, LVIS_SELECTED | LVNI_ALL );
  531.     /* Clear the list... */
  532.     ListView_DeleteAllItems( hListView );
  533.     /* ...and rebuild it */
  534.     PL_LOCK;
  535.     playlist_item_t * p_root = p_playlist->p_local_onelevel;
  536.     playlist_item_t * p_child = NULL;
  537.     int iItem = 0;
  538.     while( ( p_child = playlist_GetNextLeaf( p_playlist, p_root, p_child, FALSE, FALSE ) ) )
  539.     {
  540.         LVITEM lv;
  541.         lv.mask = LVIF_TEXT;
  542.         lv.pszText = _T("");
  543.         lv.cchTextMax = 1;
  544.         lv.iSubItem = 0;
  545.         lv.iItem = iItem;
  546.         ListView_InsertItem( hListView, &lv );
  547.         ListView_SetItemText( hListView, lv.iItem, 0,
  548.             _FROMMB(p_child->p_input->psz_name) );
  549.         UpdateItem( p_child->i_id );
  550.         iItem++;
  551.     }
  552.     PL_UNLOCK;
  553.     if ( i_focused )
  554.         ListView_SetItemState( hListView, i_focused, LVIS_FOCUSED |
  555.                                LVIS_SELECTED, LVIS_STATEIMAGEMASK )
  556.     else
  557.         ListView_SetItemState( hListView, i_focused, LVIS_FOCUSED,
  558.                                LVIS_STATEIMAGEMASK );
  559.     pl_Release( p_intf );
  560. }
  561. /**********************************************************************
  562.  * Update one playlist item
  563.  **********************************************************************/
  564. void Playlist::UpdateItem( int i )
  565. {
  566.     playlist_t *p_playlist = pl_Hold( p_intf );
  567.     if( p_playlist == NULL ) return;
  568.     PL_LOCK;
  569.     playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i );
  570.     if( !p_item )
  571.     {
  572.         PL_UNLOCK;
  573.         pl_Release( p_intf );
  574.         return;
  575.     }
  576.     ListView_SetItemText( hListView, i, 0, _FROMMB(p_item->p_input->psz_name) );
  577.     ListView_SetItemText( hListView, i, 1,
  578.                           _FROMMB( input_item_GetInfo( p_item->p_input,
  579.                                    _("General") , _("Author") ) ) );
  580.     char psz_duration[MSTRTIME_MAX_SIZE];
  581.     mtime_t dur = input_item_GetDuration( p_item->p_input );
  582.     PL_UNLOCK;
  583.     if( dur != -1 ) secstotimestr( psz_duration, dur/1000000 );
  584.     else memcpy( psz_duration , "-:--:--", sizeof("-:--:--") );
  585.     ListView_SetItemText( hListView, i, 2, _FROMMB(psz_duration) );
  586.     pl_Release( p_intf );
  587. }
  588. /**********************************************************************
  589.  * Private functions
  590.  **********************************************************************/
  591. void Playlist::DeleteItem( int item )
  592. {
  593.     playlist_t *p_playlist = pl_Hold( p_intf );
  594.     if( p_playlist == NULL ) return;
  595.     playlist_DeleteFromInput( p_playlist, item, FALSE );
  596.     ListView_DeleteItem( hListView, item );
  597.     pl_Release( p_intf );
  598. }
  599. /**********************************************************************
  600.  * I/O functions
  601.  **********************************************************************/
  602. static void OnOpenCB( intf_dialog_args_t *p_arg )
  603. {
  604.     intf_thread_t *p_intf = (intf_thread_t *)p_arg->p_arg;
  605.     if( p_arg->i_results && p_arg->psz_results[0] )
  606.     {
  607.         playlist_t * p_playlist = pl_Hold( p_intf );
  608.         if( p_playlist )
  609.         {
  610.             playlist_Import( p_playlist, p_arg->psz_results[0] );
  611.             pl_Release( p_intf );
  612.         }
  613.     }
  614. }
  615. void Playlist::OnOpen()
  616. {
  617.     char *psz_filters ="All playlists|*.pls;*.m3u;*.asx;*.b4s|M3U files|*.m3u";
  618.     intf_dialog_args_t *p_arg =
  619.         (intf_dialog_args_t *)malloc( sizeof(intf_dialog_args_t) );
  620.     memset( p_arg, 0, sizeof(intf_dialog_args_t) );
  621.     p_arg->psz_title = strdup( "Open playlist" );
  622.     p_arg->psz_extensions = strdup( psz_filters );
  623.     p_arg->p_arg = p_intf;
  624.     p_arg->pf_callback = OnOpenCB;
  625.     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_GENERIC, 0, p_arg);
  626. }
  627. static void OnSaveCB( intf_dialog_args_t *p_arg )
  628. {
  629.     intf_thread_t *p_intf = (intf_thread_t *)p_arg->p_arg;
  630.     if( p_arg->i_results && p_arg->psz_results[0] )
  631.     {
  632.         playlist_t * p_playlist = pl_Hold( p_intf );
  633.         if( p_playlist )
  634.         {
  635.             char *psz_export;
  636.             char *psz_ext = strrchr( p_arg->psz_results[0], '.' );
  637.             if( psz_ext && !strcmp( psz_ext, ".pls") )
  638.                 psz_export = "export-pls";
  639.             else psz_export = "export-m3u";
  640.             playlist_Export( p_playlist, p_arg->psz_results[0], p_playlist->p_local_onelevel, psz_export );
  641.             pl_Release( p_intf );
  642.         }
  643.     }
  644. }
  645. void Playlist::OnSave()
  646. {
  647.     char *psz_filters ="M3U file|*.m3u|PLS file|*.pls";
  648.     intf_dialog_args_t *p_arg =
  649.         (intf_dialog_args_t *)malloc( sizeof(intf_dialog_args_t) );
  650.     memset( p_arg, 0, sizeof(intf_dialog_args_t) );
  651.     p_arg->psz_title = strdup( "Save playlist" );
  652.     p_arg->psz_extensions = strdup( psz_filters );
  653.     p_arg->b_save = true;
  654.     p_arg->p_arg = p_intf;
  655.     p_arg->pf_callback = OnSaveCB;
  656.     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_GENERIC,
  657.                                    0, p_arg );
  658. }
  659. /**********************************************************************
  660.  * Selection functions
  661.  **********************************************************************/
  662. void Playlist::OnDeleteSelection()
  663. {
  664.     /* Delete from the end to the beginning, to avoid a shift of indices */
  665.     for( long item = ((int) ListView_GetItemCount( hListView ) - 1);
  666.          item >= 0; item-- )
  667.     {
  668.         if( ListView_GetItemState( hListView, item, LVIS_SELECTED ) )
  669.         {
  670.             DeleteItem( item );
  671.         }
  672.     }
  673. }
  674. void Playlist::OnInvertSelection()
  675. {
  676.     UINT iState;
  677.     for( long item = 0; item < ListView_GetItemCount( hListView ); item++ )
  678.     {
  679.         iState = ListView_GetItemState( hListView, item, LVIS_STATEIMAGEMASK );
  680.         ListView_SetItemState( hListView, item, iState ^ LVIS_SELECTED,
  681.                                LVIS_STATEIMAGEMASK );
  682.     }
  683. }
  684. void Playlist::OnEnableSelection()
  685. {
  686.     playlist_t *p_playlist = pl_Hold( p_intf );
  687.     if( p_playlist == NULL ) return;
  688.     for( long item = ListView_GetItemCount( hListView ) - 1;
  689.          item >= 0; item-- )
  690.     {
  691.         if( ListView_GetItemState( hListView, item, LVIS_SELECTED ) )
  692.         {
  693.             PL_LOCK;
  694.             playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item );
  695.             p_item->i_flags ^= PLAYLIST_DBL_FLAG;
  696.             PL_UNLOCK;
  697.             UpdateItem( item );
  698.         }
  699.     }
  700.     pl_Release( p_intf );
  701. }
  702. void Playlist::OnDisableSelection()
  703. {
  704.     playlist_t *p_playlist = pl_Hold( p_intf );
  705.     if( p_playlist == NULL ) return;
  706.     for( long item = ListView_GetItemCount( hListView ) - 1;
  707.          item >= 0; item-- )
  708.     {
  709.         if( ListView_GetItemState( hListView, item, LVIS_SELECTED ) )
  710.         {
  711.             PL_LOCK;
  712.             playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item );
  713.             p_item->i_flags |= PLAYLIST_DBL_FLAG;
  714.             PL_UNLOCK;
  715.             UpdateItem( item );
  716.         }
  717.     }
  718.     pl_Release( p_intf );
  719. }
  720. void Playlist::OnSelectAll()
  721. {
  722.     for( long item = 0; item < ListView_GetItemCount( hListView ); item++ )
  723.     {
  724.         ListView_SetItemState( hListView, item, LVIS_FOCUSED | LVIS_SELECTED,
  725.                                LVIS_STATEIMAGEMASK );
  726.     }
  727. }
  728. void Playlist::OnActivateItem( int i_item )
  729. {
  730.     playlist_t *p_playlist = pl_Hold( p_intf );
  731.     if( p_playlist == NULL ) return;
  732.     playlist_Skip( p_playlist, i_item - p_playlist->i_current_index );
  733.     pl_Release( p_intf );
  734. }
  735. void Playlist::ShowInfos( HWND hwnd, int i_item )
  736. {
  737.     playlist_t *p_playlist = pl_Hold( p_intf );
  738.     if( p_playlist == NULL ) return;
  739.     PL_LOCK;
  740.     playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_item );
  741.     if( p_item )
  742.     {
  743.         ItemInfoDialog *iteminfo_dialog =
  744.             new ItemInfoDialog( p_intf, this, hInst, p_item );
  745.         PL_UNLOCK;
  746.         CreateDialogBox( hwnd, iteminfo_dialog );
  747.         UpdateItem( i_item );
  748.         delete iteminfo_dialog;
  749.     }
  750.     pl_Release( p_intf );
  751. }
  752. /********************************************************************
  753.  * Move functions
  754.  ********************************************************************/
  755. void Playlist::OnUp()
  756. {
  757.     playlist_t *p_playlist = pl_Hold( p_intf );
  758.     if( p_playlist == NULL ) return;
  759.     /* We use the first selected item, so find it */
  760.     long i_item =
  761.         ListView_GetNextItem( hListView, -1, LVIS_SELECTED | LVNI_ALL );
  762.     if( i_item > 0 && i_item < playlist_CurrentSize( p_playlist ) )
  763.     {
  764.         playlist_Prev( p_playlist );
  765.         if( i_item > 1 )
  766.         {
  767.             ListView_SetItemState( hListView, i_item - 1, LVIS_FOCUSED,
  768.                                    LVIS_STATEIMAGEMASK );
  769.         }
  770.         else
  771.         {
  772.             ListView_SetItemState( hListView, 0, LVIS_FOCUSED,
  773.                                    LVIS_STATEIMAGEMASK );
  774.         }
  775.     }
  776.     pl_Release( p_intf );
  777.     return;
  778. }
  779. void Playlist::OnDown()
  780. {
  781.     playlist_t *p_playlist = pl_Hold( p_intf );
  782.     if( p_playlist == NULL ) return;
  783.     /* We use the first selected item, so find it */
  784.     long i_item =
  785.         ListView_GetNextItem( hListView, -1, LVIS_SELECTED | LVNI_ALL );
  786.     if( i_item >= 0 && i_item < playlist_CurrentSize( p_playlist ) - 1 )
  787.     {
  788.         playlist_Next( p_playlist );
  789.         ListView_SetItemState( hListView, i_item + 1, LVIS_FOCUSED,
  790.                                LVIS_STATEIMAGEMASK );
  791.     }
  792.     pl_Release( p_intf );
  793.     return;
  794. }
  795. /**********************************************************************
  796.  * Playlist mode functions
  797.  **********************************************************************/
  798. void Playlist::OnRandom()
  799. {
  800.     vlc_value_t val;
  801.     int bState = SendMessage( hwndTB, TB_GETSTATE, Random_Event, 0 );
  802.     val.b_bool = (bState & TBSTATE_CHECKED) ? true : false;
  803.     playlist_t *p_playlist = pl_Hold( p_intf );
  804.     if( p_playlist == NULL ) return;
  805.     var_Set( p_playlist , "random", val );
  806.     pl_Release( p_intf );
  807. }
  808. void Playlist::OnLoop ()
  809. {
  810.     vlc_value_t val;
  811.     int bState = SendMessage( hwndTB, TB_GETSTATE, Loop_Event, 0 );
  812.     val.b_bool = (bState & TBSTATE_CHECKED) ? true : false;
  813.     playlist_t *p_playlist = pl_Hold( p_intf );
  814.     if( p_playlist == NULL ) return;
  815.     var_Set( p_playlist , "loop", val );
  816.     pl_Release( p_intf );
  817. }
  818. void Playlist::OnRepeat ()
  819. {
  820.     vlc_value_t val;
  821.     int bState = SendMessage( hwndTB, TB_GETSTATE, Repeat_Event, 0 );
  822.     val.b_bool = (bState & TBSTATE_CHECKED) ? true : false;
  823.     playlist_t *p_playlist = pl_Hold( p_intf );
  824.     if( p_playlist == NULL ) return;
  825.     var_Set( p_playlist , "repeat", val );
  826.     pl_Release( p_intf );
  827. }
  828. /********************************************************************
  829.  * Sorting functions
  830.  ********************************************************************/
  831. void Playlist::OnSort( UINT event )
  832. {
  833.     playlist_t *p_playlist = pl_Hold( p_intf );
  834.     if( p_playlist == NULL ) return;
  835.     switch( event )
  836.     {
  837.     case ID_SORT_TITLE:
  838.         playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  839.                                     SORT_TITLE, ORDER_NORMAL);
  840.         break;
  841.     case ID_SORT_RTITLE:
  842.         playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  843.                                     SORT_TITLE, ORDER_REVERSE );
  844.         break;
  845.     case ID_SORT_AUTHOR:
  846.         playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  847.                                     SORT_ARTIST, ORDER_NORMAL);
  848.         break;
  849.     case ID_SORT_RAUTHOR:
  850.         playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  851.                                     SORT_ARTIST, ORDER_REVERSE);
  852.         break;
  853.     case ID_SORT_SHUFFLE:
  854.         playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  855.                                     SORT_RANDOM, ORDER_NORMAL);
  856.         break;
  857.     }
  858.     pl_Release( p_intf );
  859.     b_need_update = true;
  860.     return;
  861. }
  862. void Playlist::OnColSelect( int iSubItem )
  863. {
  864.     playlist_t *p_playlist = pl_Hold( p_intf );
  865.     if( p_playlist == NULL ) return;
  866.     switch( iSubItem )
  867.     {
  868.     case 0:
  869.         if( i_title_sorted != 1 )
  870.         {
  871.             playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  872.                                     SORT_TITLE, ORDER_NORMAL);
  873.             i_title_sorted = 1;
  874.         }
  875.         else
  876.         {
  877.             playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  878.                                     SORT_TITLE, ORDER_REVERSE );
  879.             i_title_sorted = -1;
  880.         }
  881.         break;
  882.     case 1:
  883.         if( i_author_sorted != 1 )
  884.         {
  885.             playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  886.                                     SORT_ARTIST, ORDER_NORMAL);
  887.             i_author_sorted = 1;
  888.         }
  889.         else
  890.         {
  891.             playlist_RecursiveNodeSort(p_playlist , p_playlist->p_root_onelevel,
  892.                                     SORT_ARTIST, ORDER_REVERSE);
  893.             i_author_sorted = -1;
  894.         }
  895.         break;
  896.     default:
  897.         break;
  898.     }
  899.     pl_Release( p_intf );
  900.     b_need_update = true;
  901.     return;
  902. }
  903. /*****************************************************************************
  904.  * Popup management functions
  905.  *****************************************************************************/
  906. void Playlist::OnPopupPlay()
  907. {
  908.     int i_popup_item =
  909.         ListView_GetNextItem( hListView, -1, LVIS_SELECTED | LVNI_ALL );
  910.     playlist_t *p_playlist = pl_Hold( p_intf );
  911.     if( p_playlist == NULL ) return;
  912.     if( i_popup_item != -1 )
  913.     {
  914.         playlist_Skip( p_playlist, i_popup_item - p_playlist->i_current_index );
  915.     }
  916.     pl_Release( p_intf );
  917. }
  918. void Playlist::OnPopupDel()
  919. {
  920.     int i_popup_item =
  921.         ListView_GetNextItem( hListView, -1, LVIS_SELECTED | LVNI_ALL );
  922.     DeleteItem( i_popup_item );
  923. }
  924. void Playlist::OnPopupEna()
  925. {
  926.     int i_popup_item =
  927.         ListView_GetNextItem( hListView, -1, LVIS_SELECTED | LVNI_ALL );
  928.     playlist_t *p_playlist = pl_Hold( p_intf );
  929.     if( p_playlist == NULL ) return;
  930.     PL_LOCK;
  931.     playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_popup_item );
  932.     if( !(p_playlist->items.p_elems[i_popup_item]->i_flags & PLAYLIST_DBL_FLAG) )
  933.         //playlist_IsEnabled( p_playlist, i_popup_item ) )
  934.     {
  935.         p_item->i_flags |= PLAYLIST_DBL_FLAG;
  936.     }
  937.     else
  938.     {
  939.         p_item->i_flags ^= PLAYLIST_DBL_FLAG;
  940.     }
  941.     PL_UNLOCK;
  942.     pl_Release( p_intf );
  943.     UpdateItem( i_popup_item );
  944. }
  945. void Playlist::OnPopupInfo( HWND hwnd )
  946. {
  947.     int i_popup_item =
  948.         ListView_GetNextItem( hListView, -1, LVIS_SELECTED | LVNI_ALL );
  949.     ShowInfos( hwnd, i_popup_item );
  950. }