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