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