playlist_CreateNode(): add an argument to specify an input_item_t to be linked with...
[vlc.git] / modules / gui / wxwidgets / menus.cpp
1 /*****************************************************************************
2  * menus.cpp : wxWidgets plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include <vlc/vlc.h>
25 #include <vlc_interface.h>
26
27 #include "wxwidgets.hpp"
28 #include "interface.hpp"
29
30 #include <wx/dynarray.h>
31 WX_DEFINE_ARRAY(int, ArrayOfInts);
32 WX_DEFINE_ARRAY_PTR(const char *, ArrayOfStrings);
33
34
35 class wxMenuItemExt: public wxMenuItem
36 {
37 public:
38     /* Constructor */
39     wxMenuItemExt( wxMenu* parentMenu, int id, const wxString& text,
40                    const wxString& helpString, wxItemKind kind,
41                    char *_psz_var, int _i_object_id, vlc_value_t _val,
42                    int _i_val_type );
43     virtual ~wxMenuItemExt();
44
45     char *psz_var;
46     int  i_val_type;
47     int  i_object_id;
48     vlc_value_t val;
49 };
50
51 class Menu: public wxMenu
52 {
53 public:
54     /* Constructor */
55     Menu( intf_thread_t *p_intf, int i_start_id );
56     virtual ~Menu();
57
58     void Populate( ArrayOfStrings &, ArrayOfInts &);
59     void Clear();
60
61 private:
62     wxMenu *CreateDummyMenu();
63     void   CreateMenuItem( wxMenu *, const char *, vlc_object_t * );
64     wxMenu *CreateChoicesMenu( const char *, vlc_object_t *, bool );
65
66     DECLARE_EVENT_TABLE();
67
68     intf_thread_t *p_intf;
69
70     int i_start_id;
71     int i_item_id;
72 };
73
74 /*****************************************************************************
75  * Event Table.
76  *****************************************************************************/
77 enum
78 {
79     /* menu items */
80     MenuDummy_Event = wxID_HIGHEST + 1000,
81     OpenFileSimple_Event = wxID_HIGHEST + 1100,
82     OpenFile_Event,
83     OpenDirectory_Event,
84     OpenDisc_Event,
85     OpenNet_Event,
86     OpenCapture_Event,
87     MediaInfo_Event,
88     Messages_Event,
89     Preferences_Event,
90     Play_Event,
91     Pause_Event,
92     Previous_Event,
93     Next_Event,
94     Stop_Event,
95     FirstAutoGenerated_Event = wxID_HIGHEST + 1999,
96     SettingsMenu_Events = wxID_HIGHEST + 5000,
97     AudioMenu_Events = wxID_HIGHEST + 2000,
98     VideoMenu_Events = wxID_HIGHEST + 3000,
99     NavigMenu_Events = wxID_HIGHEST + 4000,
100     PopupMenu_Events = wxID_HIGHEST + 6000,
101     Hotkeys_Events = wxID_HIGHEST + 7000
102 };
103
104 BEGIN_EVENT_TABLE(Menu, wxMenu)
105 END_EVENT_TABLE()
106
107 BEGIN_EVENT_TABLE(MenuEvtHandler, wxEvtHandler)
108     EVT_MENU(OpenFileSimple_Event, MenuEvtHandler::OnShowDialog)
109     EVT_MENU(OpenFile_Event, MenuEvtHandler::OnShowDialog)
110     EVT_MENU(OpenDirectory_Event, MenuEvtHandler::OnShowDialog)
111     EVT_MENU(OpenDisc_Event, MenuEvtHandler::OnShowDialog)
112     EVT_MENU(OpenNet_Event, MenuEvtHandler::OnShowDialog)
113     EVT_MENU(OpenCapture_Event, MenuEvtHandler::OnShowDialog)
114     EVT_MENU(MediaInfo_Event, MenuEvtHandler::OnShowDialog)
115     EVT_MENU(Messages_Event, MenuEvtHandler::OnShowDialog)
116     EVT_MENU(Preferences_Event, MenuEvtHandler::OnShowDialog)
117     EVT_MENU(-1, MenuEvtHandler::OnMenuEvent)
118 END_EVENT_TABLE()
119
120 /*****************************************************************************
121  * Static menu helpers
122  *****************************************************************************/
123 wxMenu *OpenStreamMenu( intf_thread_t *p_intf )
124 {
125     wxMenu *menu = new wxMenu;
126     menu->Append( OpenFileSimple_Event, wxU(_("Quick &Open File...")) );
127     menu->Append( OpenFile_Event, wxU(_("Open &File...")) );
128     menu->Append( OpenDirectory_Event, wxU(_("Open D&irectory...")) );
129     menu->Append( OpenDisc_Event, wxU(_("Open &Disc...")) );
130     menu->Append( OpenNet_Event, wxU(_("Open &Network Stream...")) );
131     menu->Append( OpenCapture_Event, wxU(_("Open &Capture Device...")) );
132     return menu;
133 }
134
135 wxMenu *MiscMenu( intf_thread_t *p_intf )
136 {
137     wxMenu *menu = new wxMenu;
138     menu->Append( MediaInfo_Event, wxU(_("Media &Info...")) );
139     menu->Append( Messages_Event, wxU(_("&Messages...")) );
140     menu->Append( Preferences_Event, wxU(_("&Preferences...")) );
141     return menu;
142 }
143
144 /*****************************************************************************
145  * Builders for the dynamic menus
146  *****************************************************************************/
147 #define PUSH_VAR( var ) rs_varnames.Add( var ); \
148                         ri_objects.Add( p_object->i_object_id )
149
150 int InputAutoMenuBuilder( vlc_object_t *p_object, ArrayOfInts &ri_objects,
151                           ArrayOfStrings &rs_varnames )
152 {
153     PUSH_VAR( "bookmark");
154     PUSH_VAR( "title" );
155     PUSH_VAR ("chapter" );
156     PUSH_VAR( "program" );
157     PUSH_VAR( "navigation" );
158     PUSH_VAR( "dvd_menus" );
159     return VLC_SUCCESS;
160 }
161
162 int VideoAutoMenuBuilder( vlc_object_t *p_object, ArrayOfInts &ri_objects,
163                           ArrayOfStrings &rs_varnames )
164 {
165     PUSH_VAR( "fullscreen" );
166     PUSH_VAR( "zoom" );
167     PUSH_VAR( "deinterlace" );
168     PUSH_VAR( "aspect-ratio" );
169     PUSH_VAR( "crop" );
170     PUSH_VAR( "video-on-top" );
171     PUSH_VAR( "directx-wallpaper" );
172     PUSH_VAR( "video-snapshot" );
173
174     vlc_object_t *p_dec_obj = (vlc_object_t *)vlc_object_find( p_object,
175                                                  VLC_OBJECT_DECODER,
176                                                  FIND_PARENT );
177     if( p_dec_obj != NULL )
178     {
179         vlc_object_t *p_object = p_dec_obj;
180         PUSH_VAR( "ffmpeg-pp-q" );
181         vlc_object_release( p_dec_obj );
182     }
183     return VLC_SUCCESS;
184 }
185
186 int AudioAutoMenuBuilder( vlc_object_t *p_object, ArrayOfInts &ri_objects,
187                           ArrayOfStrings &rs_varnames )
188 {
189     PUSH_VAR( "audio-device" );
190     PUSH_VAR( "audio-channels" );
191     PUSH_VAR( "visual" );
192     PUSH_VAR( "equalizer" );
193     return VLC_SUCCESS;
194 }
195
196 int IntfAutoMenuBuilder( intf_thread_t *p_intf, ArrayOfInts &ri_objects,
197                          ArrayOfStrings &rs_varnames, bool is_popup)
198 {
199     /* vlc_object_find is needed because of the dialogs provider case */
200     vlc_object_t *p_object;
201     p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INTF,
202                                                 FIND_PARENT );
203     if( p_object != NULL )
204     {
205         if( is_popup )
206         {
207 #ifndef WIN32
208             PUSH_VAR( "intf-switch" );
209 #endif
210         }
211         else
212         {
213             PUSH_VAR( "intf-switch" );
214         }
215         PUSH_VAR( "intf-add" );
216         PUSH_VAR( "intf-skins" );
217         vlc_object_release( p_object );
218     }
219     return VLC_SUCCESS;
220 }
221
222 #undef PUSH_VAR
223 /*****************************************************************************
224  * Popup menus
225  *****************************************************************************/
226 #define PUSH_VAR( var ) as_varnames.Add( var ); \
227                         ai_objects.Add( p_object->i_object_id )
228
229 #define PUSH_SEPARATOR if( ai_objects.GetCount() != i_last_separator ) { \
230                             ai_objects.Add( 0 ); \
231                             as_varnames.Add( "" ); \
232                             i_last_separator = ai_objects.GetCount(); }
233
234 #define POPUP_BOILERPLATE \
235     unsigned int i_last_separator = 0; \
236     ArrayOfInts ai_objects; \
237     ArrayOfStrings as_varnames; \
238     playlist_t *p_playlist = (playlist_t *) vlc_object_find( p_intf, \
239                                           VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );\
240     if( !p_playlist ) \
241         return; \
242     input_thread_t *p_input = p_playlist->p_input
243
244 #define CREATE_POPUP    \
245     Menu popupmenu( p_intf, PopupMenu_Events ); \
246     popupmenu.Populate( as_varnames, ai_objects ); \
247     p_intf->p_sys->p_popup_menu = &popupmenu; \
248     p_parent->PopupMenu( &popupmenu, pos.x, pos.y ); \
249     p_intf->p_sys->p_popup_menu = NULL; \
250     i_last_separator = 0 /* stop compiler warning */
251
252 #define POPUP_STATIC_ENTRIES \
253     if( p_input != NULL ) \
254     { \
255         vlc_value_t val; \
256         popupmenu.InsertSeparator( 0 ); \
257         if (!minimal) \
258         { \
259         popupmenu.Insert( 0, Stop_Event, wxU(_("Stop")) ); \
260         popupmenu.Insert( 0, Previous_Event, wxU(_("Previous")) ); \
261         popupmenu.Insert( 0, Next_Event, wxU(_("Next")) ); \
262         } \
263          \
264         var_Get( p_input, "state", &val ); \
265         if( val.i_int == PAUSE_S ) \
266             popupmenu.Insert( 0, Play_Event, wxU(_("Play")) ); \
267         else \
268             popupmenu.Insert( 0, Pause_Event, wxU(_("Pause")) ); \
269          \
270         vlc_object_release( p_input ); \
271     } \
272     else \
273     { \
274         if( p_playlist && !playlist_IsEmpty( p_playlist ) ) \
275         { \
276             popupmenu.InsertSeparator( 0 ); \
277             popupmenu.Insert( 0, Play_Event, wxU(_("Play")) ); \
278         } \
279         if( p_playlist ) vlc_object_release( p_playlist ); \
280     } \
281     \
282     popupmenu.Append( MenuDummy_Event, wxU(_("Miscellaneous")), \
283                       MiscMenu( p_intf ), wxT("") )
284
285
286 void VideoPopupMenu( intf_thread_t *p_intf, wxWindow *p_parent,
287                      const wxPoint& pos )
288 {
289     POPUP_BOILERPLATE;
290     if( p_input )
291     {
292         vlc_object_yield( p_input );
293         as_varnames.Add( "video-es" );
294         ai_objects.Add( p_input->i_object_id );
295         as_varnames.Add( "spu-es" );
296         ai_objects.Add( p_input->i_object_id );
297         vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
298                                                 VLC_OBJECT_VOUT, FIND_CHILD );
299         if( p_vout )
300         {
301             VideoAutoMenuBuilder( p_vout, ai_objects, as_varnames );
302             vlc_object_release( p_vout );
303         }
304         vlc_object_release( p_input );
305     }
306     vlc_object_release( p_playlist );
307     CREATE_POPUP;
308 }
309
310 void AudioPopupMenu( intf_thread_t *p_intf, wxWindow *p_parent,
311                      const wxPoint& pos )
312 {
313     POPUP_BOILERPLATE;
314     if( p_input )
315     {
316         vlc_object_yield( p_input );
317         as_varnames.Add( "audio-es" );
318         ai_objects.Add( p_input->i_object_id );
319         vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
320                                              VLC_OBJECT_AOUT, FIND_ANYWHERE );
321         if( p_aout )
322         {
323             AudioAutoMenuBuilder( p_aout, ai_objects, as_varnames );
324             vlc_object_release( p_aout );
325         }
326         vlc_object_release( p_input );
327     }
328     vlc_object_release( p_playlist );
329     CREATE_POPUP;
330 }
331
332 /* Navigation stuff, and general */
333 void MiscPopupMenu( intf_thread_t *p_intf, wxWindow *p_parent,
334                     const wxPoint& pos )
335 {
336     int minimal = 0;
337     POPUP_BOILERPLATE;
338     if( p_input )
339     {
340         vlc_object_yield( p_input );
341         as_varnames.Add( "audio-es" );
342         InputAutoMenuBuilder( VLC_OBJECT(p_input), ai_objects, as_varnames );
343         PUSH_SEPARATOR;
344     }
345     IntfAutoMenuBuilder( p_intf, ai_objects, as_varnames, true );
346
347     Menu popupmenu( p_intf, PopupMenu_Events );
348     popupmenu.Populate( as_varnames, ai_objects );
349
350     POPUP_STATIC_ENTRIES;
351     popupmenu.Append( MenuDummy_Event, wxU(_("Open")),
352                       OpenStreamMenu( p_intf ), wxT("") );
353
354     p_intf->p_sys->p_popup_menu = &popupmenu;
355     p_parent->PopupMenu( &popupmenu, pos.x, pos.y );
356     p_intf->p_sys->p_popup_menu = NULL;
357     vlc_object_release( p_playlist );
358 }
359
360 void PopupMenu( intf_thread_t *p_intf, wxWindow *p_parent,
361                 const wxPoint& pos )
362 {
363     int minimal = config_GetInt( p_intf, "wx-minimal" );
364     POPUP_BOILERPLATE;
365     if( p_input )
366     {
367         vlc_object_yield( p_input );
368         InputAutoMenuBuilder( VLC_OBJECT(p_input), ai_objects, as_varnames );
369
370         /* Video menu */
371         PUSH_SEPARATOR;
372         as_varnames.Add( "video-es" );
373         ai_objects.Add( p_input->i_object_id );
374         as_varnames.Add( "spu-es" );
375         ai_objects.Add( p_input->i_object_id );
376         vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
377                                                 VLC_OBJECT_VOUT, FIND_CHILD );
378         if( p_vout )
379         {
380             VideoAutoMenuBuilder( p_vout, ai_objects, as_varnames );
381             vlc_object_release( p_vout );
382         }
383         /* Audio menu */
384         PUSH_SEPARATOR
385         as_varnames.Add( "audio-es" );
386         ai_objects.Add( p_input->i_object_id );
387         vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
388                                              VLC_OBJECT_AOUT, FIND_ANYWHERE );
389         if( p_aout )
390         {
391             AudioAutoMenuBuilder( p_aout, ai_objects, as_varnames );
392             vlc_object_release( p_aout );
393         }
394     }
395
396     /* Interface menu */
397     PUSH_SEPARATOR
398     IntfAutoMenuBuilder( p_intf, ai_objects, as_varnames, true );
399
400     /* Build menu */
401     Menu popupmenu( p_intf, PopupMenu_Events );
402     popupmenu.Populate( as_varnames, ai_objects );
403     POPUP_STATIC_ENTRIES;
404
405     if (!minimal)
406     {
407         popupmenu.Append( MenuDummy_Event, wxU(_("Open")),
408                           OpenStreamMenu( p_intf ), wxT("") );
409     }
410     p_intf->p_sys->p_popup_menu = &popupmenu;
411     p_parent->PopupMenu( &popupmenu, pos.x, pos.y );
412     p_intf->p_sys->p_popup_menu = NULL;
413     vlc_object_release( p_playlist );
414 }
415
416 /*****************************************************************************
417  * Auto menus
418  *****************************************************************************/
419 wxMenu *AudioMenu( intf_thread_t *_p_intf, wxWindow *p_parent, wxMenu *p_menu )
420 {
421     vlc_object_t *p_object;
422     ArrayOfInts ai_objects;
423     ArrayOfStrings as_varnames;
424
425     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_INPUT,
426                                                 FIND_ANYWHERE );
427     if( p_object != NULL )
428     {
429         PUSH_VAR( "audio-es" );
430         vlc_object_release( p_object );
431     }
432
433     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_AOUT,
434                                                 FIND_ANYWHERE );
435     if( p_object )
436     {
437         AudioAutoMenuBuilder( p_object, ai_objects, as_varnames );
438         vlc_object_release( p_object );
439     }
440
441     /* Build menu */
442     Menu *p_vlc_menu = (Menu *)p_menu;
443     if( !p_vlc_menu )
444         p_vlc_menu = new Menu( _p_intf, AudioMenu_Events );
445     else
446         p_vlc_menu->Clear();
447
448     p_vlc_menu->Populate(  as_varnames, ai_objects );
449
450     return p_vlc_menu;
451 }
452
453 wxMenu *VideoMenu( intf_thread_t *_p_intf, wxWindow *p_parent, wxMenu *p_menu )
454 {
455     vlc_object_t *p_object;
456     ArrayOfInts ai_objects;
457     ArrayOfStrings as_varnames;
458
459     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_INPUT,
460                                                 FIND_ANYWHERE );
461     if( p_object != NULL )
462     {
463         PUSH_VAR( "video-es" );
464         PUSH_VAR( "spu-es" );
465         vlc_object_release( p_object );
466     }
467
468     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_VOUT,
469                                                 FIND_ANYWHERE );
470     if( p_object != NULL )
471     {
472         VideoAutoMenuBuilder( p_object, ai_objects, as_varnames );
473         vlc_object_release( p_object );
474     }
475
476     /* Build menu */
477     Menu *p_vlc_menu = (Menu *)p_menu;
478     if( !p_vlc_menu )
479         p_vlc_menu = new Menu( _p_intf, VideoMenu_Events );
480     else
481         p_vlc_menu->Clear();
482
483     p_vlc_menu->Populate(  as_varnames, ai_objects );
484     return p_vlc_menu;
485 }
486
487 wxMenu *NavigMenu( intf_thread_t *_p_intf, wxWindow *p_parent, wxMenu *p_menu )
488 {
489     vlc_object_t *p_object;
490     ArrayOfInts ai_objects;
491     ArrayOfStrings as_varnames;
492
493     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_INPUT,
494                                                 FIND_ANYWHERE );
495     if( p_object != NULL )
496     {
497         InputAutoMenuBuilder( p_object, ai_objects, as_varnames );
498         PUSH_VAR( "prev-title"); PUSH_VAR ( "next-title" );
499         PUSH_VAR( "prev-chapter"); PUSH_VAR( "next-chapter" );
500         vlc_object_release( p_object );
501     }
502
503     /* Build menu */
504     Menu *p_vlc_menu = (Menu *)p_menu;
505     if( !p_vlc_menu )
506         p_vlc_menu = new Menu( _p_intf, NavigMenu_Events );
507     else
508         p_vlc_menu->Clear();
509
510     p_vlc_menu->Populate( as_varnames, ai_objects );
511
512     return p_vlc_menu;
513 }
514
515 wxMenu *SettingsMenu( intf_thread_t *_p_intf, wxWindow *p_parent,
516                       wxMenu *p_menu )
517 {
518     vlc_object_t *p_object;
519     ArrayOfInts ai_objects;
520     ArrayOfStrings as_varnames;
521
522     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_INTF,
523                                                 FIND_PARENT );
524     if( p_object != NULL )
525     {
526         PUSH_VAR( "intf-switch" );
527         PUSH_VAR( "intf-add" );
528         vlc_object_release( p_object );
529     }
530
531     /* Build menu */
532     Menu *p_vlc_menu = (Menu *)p_menu;
533     if( !p_vlc_menu )
534         p_vlc_menu = new Menu( _p_intf, SettingsMenu_Events );
535     else
536         p_vlc_menu->Clear();
537
538     p_vlc_menu->Populate( as_varnames, ai_objects );
539
540     return p_vlc_menu;
541 }
542
543 /*****************************************************************************
544  * Constructor.
545  *****************************************************************************/
546 Menu::Menu( intf_thread_t *_p_intf, int _i_start_id ) : wxMenu( )
547 {
548     /* Initializations */
549     p_intf = _p_intf;
550     i_start_id = _i_start_id;
551 }
552
553 Menu::~Menu()
554 {
555 }
556
557 /*****************************************************************************
558  * Public methods.
559  *****************************************************************************/
560 void Menu::Populate( ArrayOfStrings & ras_varnames,
561                      ArrayOfInts & rai_objects )
562 {
563     vlc_object_t *p_object;
564     vlc_bool_t b_section_empty = VLC_FALSE;
565     int i;
566
567     i_item_id = i_start_id;
568
569     for( i = 0; i < (int)rai_objects.GetCount() ; i++ )
570     {
571         if( !ras_varnames[i] || !*ras_varnames[i] )
572         {
573             if( b_section_empty )
574             {
575                 Append( MenuDummy_Event + i, wxU(_("Empty")) );
576                 Enable( MenuDummy_Event + i, FALSE );
577             }
578             AppendSeparator();
579             b_section_empty = VLC_TRUE;
580             continue;
581         }
582
583         if( rai_objects[i] == 0  )
584         {
585             Append( MenuDummy_Event, wxU(ras_varnames[i]) );
586             b_section_empty = VLC_FALSE;
587             continue;
588         }
589
590         p_object = (vlc_object_t *)vlc_object_get( p_intf,
591                                                    rai_objects[i] );
592         if( p_object == NULL ) continue;
593
594         b_section_empty = VLC_FALSE;
595         CreateMenuItem( this, ras_varnames[i], p_object );
596         vlc_object_release( p_object );
597     }
598
599     /* Special case for empty menus */
600     if( GetMenuItemCount() == 0 || b_section_empty )
601     {
602         Append( MenuDummy_Event + i, wxU(_("Empty")) );
603         Enable( MenuDummy_Event + i, FALSE );
604     }
605 }
606
607 /* Work-around helper for buggy wxGTK */
608 static void RecursiveDestroy( wxMenu *menu )
609 {
610     wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
611     for( ; node; )
612     {
613         wxMenuItem *item = node->GetData();
614         node = node->GetNext();
615
616         /* Delete the submenus */
617         wxMenu *submenu = item->GetSubMenu();
618         if( submenu )
619         {
620             RecursiveDestroy( submenu );
621         }
622         menu->Delete( item );
623     }
624 }
625
626 void Menu::Clear( )
627 {
628     RecursiveDestroy( this );
629 }
630
631 /*****************************************************************************
632  * Private methods.
633  *****************************************************************************/
634 static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object,
635                          bool b_root = TRUE )
636 {
637     vlc_value_t val, val_list;
638     int i_type, i_result, i;
639
640     /* Check the type of the object variable */
641     i_type = var_Type( p_object, psz_var );
642
643     /* Check if we want to display the variable */
644     if( !(i_type & VLC_VAR_HASCHOICE) ) return FALSE;
645
646     var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
647     if( val.i_int == 0 ) return TRUE;
648
649     if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE )
650     {
651         /* Very evil hack ! intf-switch can have only one value */
652         if( !strcmp( psz_var, "intf-switch" ) ) return FALSE;
653         if( val.i_int == 1 && b_root ) return TRUE;
654         else return FALSE;
655     }
656
657     /* Check children variables in case of VLC_VAR_VARIABLE */
658     if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
659     {
660         return TRUE;
661     }
662
663     for( i = 0, i_result = TRUE; i < val_list.p_list->i_count; i++ )
664     {
665         if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
666                           p_object, FALSE ) )
667         {
668             i_result = FALSE;
669             break;
670         }
671     }
672
673     /* clean up everything */
674     var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, NULL );
675
676     return i_result;
677 }
678
679 void Menu::CreateMenuItem( wxMenu *menu, const char *psz_var,
680                            vlc_object_t *p_object )
681 {
682     wxMenuItemExt *menuitem;
683     vlc_value_t val, text;
684     int i_type;
685
686     /* Check the type of the object variable */
687     i_type = var_Type( p_object, psz_var );
688
689     switch( i_type & VLC_VAR_TYPE )
690     {
691     case VLC_VAR_VOID:
692     case VLC_VAR_BOOL:
693     case VLC_VAR_VARIABLE:
694     case VLC_VAR_STRING:
695     case VLC_VAR_INTEGER:
696     case VLC_VAR_FLOAT:
697         break;
698     default:
699         /* Variable doesn't exist or isn't handled */
700         return;
701     }
702
703     /* Make sure we want to display the variable */
704     if( IsMenuEmpty( psz_var, p_object ) )  return;
705
706     /* Get the descriptive name of the variable */
707     var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );
708
709     if( i_type & VLC_VAR_HASCHOICE )
710     {
711         menu->Append( MenuDummy_Event,
712                       wxU(text.psz_string ? text.psz_string : psz_var),
713                       CreateChoicesMenu( psz_var, p_object, TRUE ),
714                       wxT("")/* Nothing for now (maybe use a GETLONGTEXT) */ );
715
716         if( text.psz_string ) free( text.psz_string );
717         return;
718     }
719
720
721     switch( i_type & VLC_VAR_TYPE )
722     {
723     case VLC_VAR_VOID:
724         var_Get( p_object, psz_var, &val );
725         menuitem = new wxMenuItemExt( menu, ++i_item_id,
726                                       wxU(text.psz_string ?
727                                         text.psz_string : psz_var),
728                                       wxT(""), wxITEM_NORMAL, strdup(psz_var),
729                                       p_object->i_object_id, val, i_type );
730         menu->Append( menuitem );
731         break;
732
733     case VLC_VAR_BOOL:
734         var_Get( p_object, psz_var, &val );
735         val.b_bool = !val.b_bool;
736         menuitem = new wxMenuItemExt( menu, ++i_item_id,
737                                       wxU(text.psz_string ?
738                                         text.psz_string : psz_var),
739                                       wxT(""), wxITEM_CHECK, strdup(psz_var),
740                                       p_object->i_object_id, val, i_type );
741         menu->Append( menuitem );
742         Check( i_item_id, val.b_bool ? FALSE : TRUE );
743         break;
744     }
745
746     if( text.psz_string ) free( text.psz_string );
747 }
748
749 wxMenu *Menu::CreateChoicesMenu( const char *psz_var, vlc_object_t *p_object,
750                                  bool b_root )
751 {
752     vlc_value_t val, val_list, text_list;
753     int i_type, i;
754
755     /* Check the type of the object variable */
756     i_type = var_Type( p_object, psz_var );
757
758     /* Make sure we want to display the variable */
759     if( IsMenuEmpty( psz_var, p_object, b_root ) ) return NULL;
760
761     switch( i_type & VLC_VAR_TYPE )
762     {
763     case VLC_VAR_VOID:
764     case VLC_VAR_BOOL:
765     case VLC_VAR_VARIABLE:
766     case VLC_VAR_STRING:
767     case VLC_VAR_INTEGER:
768     case VLC_VAR_FLOAT:
769         break;
770     default:
771         /* Variable doesn't exist or isn't handled */
772         return NULL;
773     }
774
775     if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
776                     &val_list, &text_list ) < 0 )
777     {
778         return NULL;
779     }
780
781     wxMenu *menu = new wxMenu;
782     for( i = 0; i < val_list.p_list->i_count; i++ )
783     {
784         vlc_value_t another_val;
785         wxMenuItemExt *menuitem;
786
787         switch( i_type & VLC_VAR_TYPE )
788         {
789         case VLC_VAR_VARIABLE:
790           menu->Append( MenuDummy_Event,
791                         wxU(text_list.p_list->p_values[i].psz_string ?
792                         text_list.p_list->p_values[i].psz_string :
793                         val_list.p_list->p_values[i].psz_string),
794                         CreateChoicesMenu(
795                             val_list.p_list->p_values[i].psz_string,
796                             p_object, FALSE ), wxT("") );
797           break;
798
799         case VLC_VAR_STRING:
800           var_Get( p_object, psz_var, &val );
801
802           another_val.psz_string =
803               strdup(val_list.p_list->p_values[i].psz_string);
804           menuitem =
805               new wxMenuItemExt( menu, ++i_item_id,
806                                  wxU(text_list.p_list->p_values[i].psz_string ?
807                                  text_list.p_list->p_values[i].psz_string :
808                                  another_val.psz_string), wxT(""),
809                                  i_type & VLC_VAR_ISCOMMAND ?
810                                    wxITEM_NORMAL : wxITEM_RADIO,
811                                  strdup(psz_var),
812                                  p_object->i_object_id, another_val, i_type );
813
814           menu->Append( menuitem );
815
816           if( !(i_type & VLC_VAR_ISCOMMAND) && val.psz_string &&
817               !strcmp( val.psz_string,
818                        val_list.p_list->p_values[i].psz_string ) )
819               menu->Check( i_item_id, TRUE );
820
821           if( val.psz_string ) free( val.psz_string );
822           break;
823
824         case VLC_VAR_INTEGER:
825           var_Get( p_object, psz_var, &val );
826
827           menuitem =
828               new wxMenuItemExt( menu, ++i_item_id,
829                                  text_list.p_list->p_values[i].psz_string ?
830                                  (wxString)wxU(
831                                    text_list.p_list->p_values[i].psz_string) :
832                                  wxString::Format(wxT("%d"),
833                                  val_list.p_list->p_values[i].i_int), wxT(""),
834                                  i_type & VLC_VAR_ISCOMMAND ?
835                                    wxITEM_NORMAL : wxITEM_RADIO,
836                                  strdup(psz_var),
837                                  p_object->i_object_id,
838                                  val_list.p_list->p_values[i], i_type );
839
840           menu->Append( menuitem );
841
842           if( !(i_type & VLC_VAR_ISCOMMAND) &&
843               val_list.p_list->p_values[i].i_int == val.i_int )
844               menu->Check( i_item_id, TRUE );
845           break;
846
847         case VLC_VAR_FLOAT:
848           var_Get( p_object, psz_var, &val );
849
850           menuitem =
851               new wxMenuItemExt( menu, ++i_item_id,
852                                  text_list.p_list->p_values[i].psz_string ?
853                                  (wxString)wxU(
854                                    text_list.p_list->p_values[i].psz_string) :
855                                  wxString::Format(wxT("%.2f"),
856                                  val_list.p_list->p_values[i].f_float),wxT(""),
857                                  i_type & VLC_VAR_ISCOMMAND ?
858                                    wxITEM_NORMAL : wxITEM_RADIO,
859                                  strdup(psz_var),
860                                  p_object->i_object_id,
861                                  val_list.p_list->p_values[i], i_type );
862
863           menu->Append( menuitem );
864
865           if( !(i_type & VLC_VAR_ISCOMMAND) &&
866               val_list.p_list->p_values[i].f_float == val.f_float )
867               menu->Check( i_item_id, TRUE );
868           break;
869
870         default:
871           break;
872         }
873     }
874
875     /* clean up everything */
876     var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, &text_list );
877
878     return menu;
879 }
880
881 /*****************************************************************************
882  * A small helper class which intercepts all popup menu events
883  *****************************************************************************/
884 MenuEvtHandler::MenuEvtHandler( intf_thread_t *_p_intf,
885                                 Interface *_p_main_interface )
886 {
887     /* Initializations */
888     p_intf = _p_intf;
889     p_main_interface = _p_main_interface;
890 }
891
892 MenuEvtHandler::~MenuEvtHandler()
893 {
894 }
895
896 void MenuEvtHandler::OnShowDialog( wxCommandEvent& event )
897 {
898     if( p_intf->p_sys->pf_show_dialog )
899     {
900         int i_id;
901
902         switch( event.GetId() )
903         {
904         case OpenFileSimple_Event:
905             i_id = INTF_DIALOG_FILE_SIMPLE;
906             break;
907         case OpenFile_Event:
908             i_id = INTF_DIALOG_FILE;
909             break;
910         case OpenDirectory_Event:
911             i_id = INTF_DIALOG_DIRECTORY;
912             break;
913         case OpenDisc_Event:
914             i_id = INTF_DIALOG_DISC;
915             break;
916         case OpenNet_Event:
917             i_id = INTF_DIALOG_NET;
918             break;
919         case OpenCapture_Event:
920             i_id = INTF_DIALOG_CAPTURE;
921             break;
922         case MediaInfo_Event:
923             i_id = INTF_DIALOG_FILEINFO;
924             break;
925         case Messages_Event:
926             i_id = INTF_DIALOG_MESSAGES;
927             break;
928         case Preferences_Event:
929             i_id = INTF_DIALOG_PREFS;
930             break;
931         default:
932             i_id = INTF_DIALOG_FILE;
933             break;
934
935         }
936
937         p_intf->p_sys->pf_show_dialog( p_intf, i_id, 1, 0 );
938     }
939 }
940
941 void MenuEvtHandler::OnMenuEvent( wxCommandEvent& event )
942 {
943     wxMenuItem *p_menuitem = NULL;
944     int i_hotkey_event = p_intf->p_sys->i_first_hotkey_event;
945     int i_hotkeys = p_intf->p_sys->i_hotkeys;
946
947     if( event.GetId() >= Play_Event && event.GetId() <= Stop_Event )
948     {
949         input_thread_t *p_input;
950         playlist_t * p_playlist =
951             (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
952                                            FIND_ANYWHERE );
953         if( !p_playlist ) return;
954
955         switch( event.GetId() )
956         {
957         case Play_Event:
958         case Pause_Event:
959             p_input =
960                 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
961                                                    FIND_ANYWHERE );
962             if( !p_input ) playlist_Play( p_playlist );
963             else
964             {
965                 vlc_value_t val;
966                 var_Get( p_input, "state", &val );
967                 if( val.i_int != PAUSE_S ) val.i_int = PAUSE_S;
968                 else val.i_int = PLAYING_S;
969                 var_Set( p_input, "state", val );
970                 vlc_object_release( p_input );
971             }
972             break;
973         case Stop_Event:
974             playlist_Stop( p_playlist );
975             break;
976         case Previous_Event:
977             playlist_Prev( p_playlist );
978             break;
979         case Next_Event:
980             playlist_Next( p_playlist );
981             break;
982         }
983
984         vlc_object_release( p_playlist );
985         return;
986     }
987
988     /* Check if this is an auto generated menu item */
989     if( event.GetId() < FirstAutoGenerated_Event )
990     {
991         event.Skip();
992         return;
993     }
994
995     /* Check if this is an hotkey event */
996     if( event.GetId() >= i_hotkey_event &&
997         event.GetId() < i_hotkey_event + i_hotkeys )
998     {
999         vlc_value_t val;
1000
1001         val.i_int =
1002             p_intf->p_libvlc->p_hotkeys[event.GetId() - i_hotkey_event].i_key;
1003
1004         /* Get the key combination and send it to the hotkey handler */
1005         var_Set( p_intf->p_libvlc, "key-pressed", val );
1006         return;
1007     }
1008
1009     if( !p_main_interface ||
1010         (p_menuitem = p_main_interface->GetMenuBar()->FindItem(event.GetId()))
1011         == NULL )
1012     {
1013         if( p_intf->p_sys->p_popup_menu )
1014         {
1015             p_menuitem =
1016                 p_intf->p_sys->p_popup_menu->FindItem( event.GetId() );
1017         }
1018     }
1019
1020     if( p_menuitem )
1021     {
1022         wxMenuItemExt *p_menuitemext = (wxMenuItemExt *)p_menuitem;
1023         vlc_object_t *p_object;
1024
1025         p_object = (vlc_object_t *)vlc_object_get( p_intf,
1026                                        p_menuitemext->i_object_id );
1027         if( p_object == NULL ) return;
1028
1029         wxMutexGuiLeave(); // We don't want deadlocks
1030         var_Set( p_object, p_menuitemext->psz_var, p_menuitemext->val );
1031         //wxMutexGuiEnter();
1032
1033         vlc_object_release( p_object );
1034     }
1035     else
1036         event.Skip();
1037 }
1038
1039 /*****************************************************************************
1040  * A small helper class which encapsulate wxMenuitem with some other useful
1041  * things.
1042  *****************************************************************************/
1043 wxMenuItemExt::wxMenuItemExt( wxMenu* parentMenu, int id, const wxString& text,
1044     const wxString& helpString, wxItemKind kind,
1045     char *_psz_var, int _i_object_id, vlc_value_t _val, int _i_val_type ):
1046     wxMenuItem( parentMenu, id, text, helpString, kind )
1047 {
1048     /* Initializations */
1049     psz_var = _psz_var;
1050     i_val_type = _i_val_type;
1051     i_object_id = _i_object_id;
1052     val = _val;
1053 };
1054
1055 wxMenuItemExt::~wxMenuItemExt()
1056 {
1057     if( psz_var ) free( psz_var );
1058     if( ((i_val_type & VLC_VAR_TYPE) == VLC_VAR_STRING)
1059         && val.psz_string ) free( val.psz_string );
1060 };