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