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