* modules/gui/wxwindows/*: misc improvements to the main interface, implementation of
[vlc.git] / modules / gui / wxwindows / playlist.cpp
1 /*****************************************************************************
2  * interface.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $$
6  *
7  * Authors: Olivier Teulière <ipkiss@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *-
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30 #include <stdio.h>
31
32 #include <wx/wxprec.h>
33 #include <wx/wx.h>
34 #include <wx/listctrl.h>
35
36 /* Let vlc take care of the i18n stuff */
37 #undef _
38
39 #ifdef WIN32                                                 /* mingw32 hack */
40 #undef Yield
41 #undef CreateDialog
42 #endif
43
44 #include <vlc/vlc.h>
45 #include <vlc/intf.h>
46
47 #include "wxwindows.h"
48
49 /*****************************************************************************
50  * Event Table.
51  *****************************************************************************/
52
53 /* IDs for the controls and the menu commands */
54 enum
55 {
56     /* menu items */
57     AddUrl_Event = 1,
58     AddDirectory_Event,
59     Close_Event,
60
61     InvertSelection_Event,
62     DeleteSelection_Event,
63     SelectAll_Event,
64
65     /* controls */
66     ListView_Event
67 };
68
69 BEGIN_EVENT_TABLE(Playlist, wxFrame)
70     /* Menu events */
71     EVT_MENU(AddUrl_Event, Playlist::OnAddUrl)
72     EVT_MENU(AddDirectory_Event, Playlist::OnAddDirectory)
73     EVT_MENU(Close_Event, Playlist::OnClose)
74     EVT_MENU(InvertSelection_Event, Playlist::OnInvertSelection)
75     EVT_MENU(DeleteSelection_Event, Playlist::OnDeleteSelection)
76     EVT_MENU(SelectAll_Event, Playlist::OnSelectAll)
77
78     /* Listview events */
79     EVT_LIST_ITEM_ACTIVATED(ListView_Event, Playlist::OnActivateItem)
80     EVT_LIST_KEY_DOWN(ListView_Event, Playlist::OnKeyDown)
81
82     /* Button events */
83     EVT_BUTTON( wxID_OK, Playlist::OnClose)
84
85     /* Special events : we don't want to destroy the window when the user
86      * clicks on (X) */
87     EVT_CLOSE(Playlist::OnClose)
88 END_EVENT_TABLE()
89
90 /*****************************************************************************
91  * Constructor.
92  *****************************************************************************/
93 Playlist::Playlist( intf_thread_t *_p_intf, Interface *_p_main_interface ):
94     wxFrame( _p_main_interface, -1, "Playlist", wxDefaultPosition,
95              wxSize::wxSize( 400, 500 ), wxDEFAULT_FRAME_STYLE )
96 {
97     /* Initializations */
98     p_intf = _p_intf;
99     p_main_interface = _p_main_interface;
100
101     /* Create our "Manage" menu */
102     wxMenu *manage_menu = new wxMenu;
103     manage_menu->Append( AddUrl_Event, _("Add &Url...") );
104     manage_menu->Append( AddDirectory_Event, _("Add &Directory...") );
105     manage_menu->AppendSeparator();
106     manage_menu->Append( Close_Event, _("&Close") );
107
108     /* Create our "Selection" menu */
109     wxMenu *selection_menu = new wxMenu;
110     selection_menu->Append( InvertSelection_Event, _("&Invert") );
111     selection_menu->Append( DeleteSelection_Event, _("&Delete") );
112     selection_menu->Append( SelectAll_Event, _("&Select All") );
113
114     /* Append the freshly created menus to the menu bar */
115     wxMenuBar *menubar = new wxMenuBar( wxMB_DOCKABLE );
116     menubar->Append( manage_menu, _("&Manage") );
117     menubar->Append( selection_menu, _("&Selection") );
118
119     /* Attach the menu bar to the frame */
120     SetMenuBar( menubar );
121
122     /* Create the listview */
123     /* FIXME: the given size is arbitrary, and prevents us from resizing
124      * the window to smaller dimensions. But the sizers don't seem to adjust
125      * themselves to the size of a listview, and with a wxDefaultSize the
126      * playlist window is ridiculously small */
127     listview = new wxListView( this, ListView_Event, wxDefaultPosition,
128                                wxSize( 350, 300 ), wxLC_REPORT );
129     listview->InsertColumn( 0, _("Url") );
130     listview->InsertColumn( 1, _("Duration") );
131     listview->SetColumnWidth( 0, 250 );
132     listview->SetColumnWidth( 1, 100 );
133
134     /* Create the OK button */
135     ok_button = new wxButton( this, wxID_OK, _("OK") );
136     ok_button->SetDefault();
137
138     /* Place everything in sizers */
139     wxBoxSizer *ok_button_sizer = new wxBoxSizer( wxHORIZONTAL );
140     ok_button_sizer->Add( ok_button, 0, wxALL, 5 );
141     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
142     main_sizer->Add( listview, 1, wxEXPAND | wxALL, 5 );
143     main_sizer->Add( ok_button_sizer, 0, wxALIGN_CENTRE );
144
145     SetSizerAndFit( main_sizer );
146
147     /* Associate drop targets with the playlist */
148     SetDropTarget( new DragAndDrop( p_intf ) );
149
150     /* Update the playlist */
151     Rebuild();
152
153 }
154
155 Playlist::~Playlist()
156 {
157 }
158
159 void Playlist::Rebuild()
160 {
161     playlist_t *p_playlist =
162         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
163                                        FIND_ANYWHERE );
164     if( p_playlist == NULL )
165     {
166         return;
167     }
168
169     /* Clear the list... */
170     listview->DeleteAllItems();
171
172     /* ...and rebuild it */
173     vlc_mutex_lock( &p_playlist->object_lock );
174     for( int i = 0; i < p_playlist->i_size; i++ )
175     {
176         wxString filename = p_playlist->pp_items[i]->psz_name;
177         listview->InsertItem( i, filename );
178         /* FIXME: we should try to find the actual duration... */
179         listview->SetItem( i, 1, _("no info") );
180     }
181     vlc_mutex_unlock( &p_playlist->object_lock );
182
183     /* Change the colour for the currenty played stream */
184     wxListItem listitem;
185     listitem.m_itemId = p_playlist->i_index;
186     listitem.SetTextColour( *wxRED );
187     listview->SetItem( listitem );
188
189     vlc_object_release( p_playlist );
190 }
191
192 /* Update the colour of items */
193 void Playlist::Manage()
194 {
195     playlist_t *p_playlist =
196         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
197                                        FIND_ANYWHERE );
198     if( p_playlist == NULL )
199     {
200         return;
201     }
202
203     vlc_mutex_lock( &p_playlist->object_lock );
204     if( p_intf->p_sys->i_playing != p_playlist->i_index )
205     {
206         wxListItem listitem;
207         listitem.m_itemId = p_playlist->i_index;
208         listitem.SetTextColour( *wxRED );
209         listview->SetItem( listitem );
210
211         if( p_intf->p_sys->i_playing != -1 )
212         {
213             listitem.m_itemId = p_intf->p_sys->i_playing;
214             listitem.SetTextColour( *wxBLACK );
215             listview->SetItem( listitem );
216         }
217         p_intf->p_sys->i_playing = p_playlist->i_index;
218     }
219     vlc_mutex_unlock( &p_playlist->object_lock );
220
221     vlc_object_release( p_playlist );
222 }
223
224 /*****************************************************************************
225  * Private methods.
226  *****************************************************************************/
227 void Playlist::DeleteItem( int item )
228 {
229     playlist_t *p_playlist =
230         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
231                                        FIND_ANYWHERE );
232     if( p_playlist == NULL )
233     {
234         return;
235     }
236
237     playlist_Delete( p_playlist, item );
238     listview->DeleteItem( item );
239
240     vlc_object_release( p_playlist );
241 }
242
243 void Playlist::OnClose( wxCommandEvent& WXUNUSED(event) )
244 {
245     Hide();
246 }
247
248 void Playlist::OnAddUrl( wxCommandEvent& WXUNUSED(event) )
249 {
250     /* TODO */
251 }
252
253 void Playlist::OnAddDirectory( wxCommandEvent& WXUNUSED(event) )
254 {
255     /* TODO */
256 }
257
258 void Playlist::OnInvertSelection( wxCommandEvent& WXUNUSED(event) )
259 {
260     for( long item = 0; item < listview->GetItemCount(); item++ )
261     {
262         listview->Select( item, ! listview->IsSelected( item ) );
263     }
264 }
265
266 void Playlist::OnDeleteSelection( wxCommandEvent& WXUNUSED(event) )
267 {
268     /* Delete from the end to the beginning, to avoid a shift of indices */
269     for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
270     {
271         if( listview->IsSelected( item ) )
272         {
273             DeleteItem( item );
274         }
275     }
276
277     Rebuild();
278 }
279
280 void Playlist::OnSelectAll( wxCommandEvent& WXUNUSED(event) )
281 {
282     for( long item = 0; item < listview->GetItemCount(); item++ )
283     {
284         listview->Select( item, TRUE );
285     }
286 }
287
288 void Playlist::OnActivateItem( wxListEvent& event )
289 {
290     playlist_t *p_playlist =
291         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
292                                        FIND_ANYWHERE );
293     if( p_playlist == NULL )
294     {
295         return;
296     }
297
298     playlist_Goto( p_playlist, event.GetIndex() );
299
300     vlc_object_release( p_playlist );
301 }
302
303 void Playlist::OnKeyDown( wxListEvent& event )
304 {
305     long keycode = event.GetKeyCode();
306     /* Delete selected items */
307     if( keycode == WXK_BACK || keycode == WXK_DELETE )
308     {
309         /* We send a dummy event */
310         OnDeleteSelection( event );
311     }
312 }
313