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