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