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