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