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