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