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