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