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