]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/menus.cpp
68d62bcad65a8c67257c385a4d74bd805b080f88
[vlc] / modules / gui / wxwindows / menus.cpp
1 /*****************************************************************************
2  * menus.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: menus.cpp,v 1.15 2003/06/05 21:22:28 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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
34 #ifdef WIN32                                                 /* mingw32 hack */
35 #undef Yield
36 #undef CreateDialog
37 #endif
38
39 /* Let vlc take care of the i18n stuff */
40 #define WXINTL_NO_GETTEXT_MACRO
41
42 #include <wx/wxprec.h>
43 #include <wx/wx.h>
44 #include <wx/listctrl.h>
45
46 #include <vlc/intf.h>
47
48 #if defined MODULE_NAME_IS_skins
49 #   include "../skins/src/skin_common.h"
50 #endif
51
52 #include "wxwindows.h"
53
54 class wxMenuItemExt: public wxMenuItem
55 {
56 public:
57     /* Constructor */
58     wxMenuItemExt( wxMenu* parentMenu, int id, const wxString& text,
59                    const wxString& helpString, wxItemKind kind,
60                    char *_psz_var, int _i_object_id, vlc_value_t _val,
61                    int _i_val_type );
62
63     virtual ~wxMenuItemExt();
64
65     char *psz_var;
66     int  i_val_type;
67     int  i_object_id;
68     vlc_value_t val;
69
70 private:
71
72 };
73
74 /*****************************************************************************
75  * Event Table.
76  *****************************************************************************/
77
78 /* IDs for the controls and the menu commands */
79 enum
80 {
81     /* menu items */
82     FirstAutoGenerated_Event = wxID_HIGHEST + 1000,
83     MenuDummy_Event,
84     AudioMenu_Events,
85     VideoMenu_Events = wxID_HIGHEST + 1100,
86     NavigMenu_Events = wxID_HIGHEST + 1200,
87     PopupMenu_Events = wxID_HIGHEST + 1300,
88 };
89
90 BEGIN_EVENT_TABLE(Menu, wxMenu)
91     /* Menu events */
92     EVT_MENU(MenuDummy_Event, Menu::OnEntrySelected)
93 END_EVENT_TABLE()
94
95 BEGIN_EVENT_TABLE(MenuEvtHandler, wxEvtHandler)
96     EVT_MENU(-1, MenuEvtHandler::OnMenuEvent)
97 END_EVENT_TABLE()
98
99 void PopupMenu( intf_thread_t *p_intf, wxWindow *p_parent,
100                 const wxPoint& pos )
101 {
102     vlc_object_t *p_object;
103     char *ppsz_varnames[29];
104     int pi_objects[29];
105     int i = 0;
106
107     /* Initializations */
108     memset( pi_objects, 0, 29 * sizeof(int) );
109
110     /* Audio menu */
111     ppsz_varnames[i++] = _("Audio menu");
112     ppsz_varnames[i++] = NULL; /* Separator */
113
114     p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,
115                                                 FIND_ANYWHERE );
116     if( p_object != NULL )
117     {
118         ppsz_varnames[i] = "audio-device";
119         pi_objects[i++] = p_object->i_object_id;
120         ppsz_varnames[i] = "audio-channels";
121         pi_objects[i++] = p_object->i_object_id;
122         vlc_object_release( p_object );
123     }
124
125     /* Video menu */
126     ppsz_varnames[i++] = NULL; /* Separator */
127     ppsz_varnames[i++] = _("Video menu");
128     ppsz_varnames[i++] = NULL; /* Separator */
129
130     p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
131                                                 FIND_ANYWHERE );
132     if( p_object != NULL )
133     {
134         ppsz_varnames[i] = "fullscreen";
135         pi_objects[i++] = p_object->i_object_id;
136         ppsz_varnames[i] = "deinterlace";
137         pi_objects[i++] = p_object->i_object_id;
138         ppsz_varnames[i] = "directx-on-top";
139         pi_objects[i++] = p_object->i_object_id;
140         vlc_object_release( p_object );
141     }
142
143     /* Input menu */
144     ppsz_varnames[i++] = NULL; /* Separator */
145     ppsz_varnames[i++] = _("Input menu");
146     ppsz_varnames[i++] = NULL; /* Separator */
147
148     p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
149                                                 FIND_ANYWHERE );
150     if( p_object != NULL )
151     {
152         ppsz_varnames[i] = "title";
153         pi_objects[i++] = p_object->i_object_id;
154         ppsz_varnames[i] = "chapter";
155         pi_objects[i++] = p_object->i_object_id;
156         ppsz_varnames[i] = "navigation";
157         pi_objects[i++] = p_object->i_object_id;
158         ppsz_varnames[i] = "program";
159         pi_objects[i++] = p_object->i_object_id;
160
161         ppsz_varnames[i] = "video-es";
162         pi_objects[i++] = p_object->i_object_id;
163         ppsz_varnames[i] = "audio-es";
164         pi_objects[i++] = p_object->i_object_id;
165         ppsz_varnames[i] = "spu-es";
166         pi_objects[i++] = p_object->i_object_id;
167
168         vlc_object_release( p_object );
169     }
170
171     /* Misc stuff */
172     ppsz_varnames[i++] = NULL; /* Separator */
173     ppsz_varnames[i++] = _("Close Menu");
174
175     /* Build menu */
176     Menu popupmenu( p_intf, p_parent, i,
177                      ppsz_varnames, pi_objects, PopupMenu_Events );
178
179     p_intf->p_sys->p_popup_menu = &popupmenu;
180     p_parent->PopupMenu( &popupmenu, pos.x, pos.y );
181     p_intf->p_sys->p_popup_menu = NULL;
182 }
183
184 wxMenu *AudioMenu( intf_thread_t *_p_intf, wxWindow *p_parent )
185 {
186     vlc_object_t *p_object;
187     char *ppsz_varnames[5];
188     int pi_objects[5];
189     int i = 0;
190
191     /* Initializations */
192     memset( pi_objects, 0, 5 * sizeof(int) );
193
194     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_AOUT,
195                                                 FIND_ANYWHERE );
196     if( p_object != NULL )
197     {
198         ppsz_varnames[i] = "audio-device";
199         pi_objects[i++] = p_object->i_object_id;
200         ppsz_varnames[i] = "audio-channels";
201         pi_objects[i++] = p_object->i_object_id;
202         vlc_object_release( p_object );
203     }
204
205     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_INPUT,
206                                                 FIND_ANYWHERE );
207     if( p_object != NULL )
208     {
209         ppsz_varnames[i] = "audio-es";
210         pi_objects[i++] = p_object->i_object_id;
211         vlc_object_release( p_object );
212     }
213
214     /* Build menu */
215     return new Menu( _p_intf, p_parent, i,
216                      ppsz_varnames, pi_objects, AudioMenu_Events );
217 }
218
219 wxMenu *VideoMenu( intf_thread_t *_p_intf, wxWindow *p_parent )
220 {
221     vlc_object_t *p_object;
222     char *ppsz_varnames[6];
223     int pi_objects[6];
224     int i = 0;
225
226     /* Initializations */
227     memset( pi_objects, 0, 6 * sizeof(int) );
228
229     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_VOUT,
230                                                 FIND_ANYWHERE );
231     if( p_object != NULL )
232     {
233         ppsz_varnames[i] = "fullscreen";
234         pi_objects[i++] = p_object->i_object_id;
235         ppsz_varnames[i] = "deinterlace";
236         pi_objects[i++] = p_object->i_object_id;
237         ppsz_varnames[i] = "directx-on-top";
238         pi_objects[i++] = p_object->i_object_id;
239         vlc_object_release( p_object );
240     }
241
242     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_INPUT,
243                                                 FIND_ANYWHERE );
244     if( p_object != NULL )
245     {
246         ppsz_varnames[i] = "video-es";
247         pi_objects[i++] = p_object->i_object_id;
248         ppsz_varnames[i] = "spu-es";
249         pi_objects[i++] = p_object->i_object_id;
250         vlc_object_release( p_object );
251     }
252
253     /* Build menu */
254     return new Menu( _p_intf, p_parent, i,
255                      ppsz_varnames, pi_objects, VideoMenu_Events );
256 }
257
258 wxMenu *NavigMenu( intf_thread_t *_p_intf, wxWindow *p_parent )
259 {
260     vlc_object_t *p_object;
261     char *ppsz_varnames[10];
262     int pi_objects[10];
263     int i = 0;
264
265     /* Initializations */
266     memset( pi_objects, 0, 4 * sizeof(int) );
267
268     p_object = (vlc_object_t *)vlc_object_find( _p_intf, VLC_OBJECT_INPUT,
269                                                 FIND_ANYWHERE );
270     if( p_object != NULL )
271     {
272         ppsz_varnames[i] = "title";
273         pi_objects[i++] = p_object->i_object_id;
274         ppsz_varnames[i] = "chapter";
275         pi_objects[i++] = p_object->i_object_id;
276         ppsz_varnames[i] = "navigation";
277         pi_objects[i++] = p_object->i_object_id;
278         ppsz_varnames[i] = "program";
279         pi_objects[i++] = p_object->i_object_id;
280
281         ppsz_varnames[i] = "prev-title";
282         pi_objects[i++] = p_object->i_object_id;
283         ppsz_varnames[i] = "next-title";
284         pi_objects[i++] = p_object->i_object_id;
285         ppsz_varnames[i] = "prev-chapter";
286         pi_objects[i++] = p_object->i_object_id;
287         ppsz_varnames[i] = "next-chapter";
288         pi_objects[i++] = p_object->i_object_id;
289
290         vlc_object_release( p_object );
291     }
292
293     /* Build menu */
294     return new Menu( _p_intf, p_parent, i,
295                      ppsz_varnames, pi_objects, NavigMenu_Events );
296 }
297
298 /*****************************************************************************
299  * Constructor.
300  *****************************************************************************/
301 Menu::Menu( intf_thread_t *_p_intf, wxWindow *p_parent,
302             int i_count, char **ppsz_varnames, int *pi_objects,
303             int i_start_id ): wxMenu( )
304 {
305     vlc_object_t *p_object;
306     int i;
307
308     /* Initializations */
309     p_intf = _p_intf;
310
311     i_item_id = i_start_id;
312
313     for( i = 0; i < i_count; i++ )
314     {
315         if( !ppsz_varnames[i] )
316         {
317             AppendSeparator();
318             continue;
319         }
320
321         if( !pi_objects[i] )
322         {
323             Append( MenuDummy_Event, wxU(ppsz_varnames[i]) );
324             continue;
325         }
326
327         p_object = (vlc_object_t *)vlc_object_get( p_intf, pi_objects[i] );
328         if( p_object == NULL ) continue;
329
330         CreateMenuItem( this, ppsz_varnames[i], p_object );
331         vlc_object_release( p_object );
332     }
333
334     /* Special case for empty menus */
335     if( GetMenuItemCount() == 0 )
336     {
337         Append( MenuDummy_Event, wxU(_("Empty")) );
338         Enable( MenuDummy_Event, FALSE );
339     }
340 }
341
342 Menu::~Menu()
343 {
344 }
345
346 /*****************************************************************************
347  * Private methods.
348  *****************************************************************************/
349 void Menu::OnEntrySelected( wxCommandEvent& WXUNUSED(event) )
350 {
351 }
352
353 void Menu::CreateMenuItem( wxMenu *menu, char *psz_var,
354                            vlc_object_t *p_object )
355 {
356     wxMenuItemExt *menuitem;
357     vlc_value_t val, text;
358     int i_type;
359
360     /* Check the type of the object variable */
361     i_type = var_Type( p_object, psz_var );
362
363     switch( i_type & VLC_VAR_TYPE )
364     {
365     case VLC_VAR_VOID:
366     case VLC_VAR_BOOL:
367     case VLC_VAR_VARIABLE:
368     case VLC_VAR_STRING:
369     case VLC_VAR_INTEGER:
370         break;
371     default:
372         /* Variable doesn't exist or isn't handled */
373         return;
374     }
375
376     /* Make sure we want to display the variable */
377     if( i_type & VLC_VAR_HASCHOICE )
378     {
379         var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
380         if( val.i_int == 0 ) return;
381         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
382             return;
383     }
384
385     /* Get the descriptive name of the variable */
386     var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );
387
388     var_Get( p_object, psz_var, &val );
389
390     if( i_type & VLC_VAR_HASCHOICE )
391     {
392         menu->Append( MenuDummy_Event,
393                       wxU(text.psz_string ? text.psz_string : psz_var),
394                       CreateChoicesMenu( psz_var, p_object ),
395                       wxT("")/* Nothing for now (maybe use a GETLONGTEXT) */ );
396
397         if( text.psz_string ) free( text.psz_string );
398         return;
399     }
400
401
402     switch( i_type & VLC_VAR_TYPE )
403     {
404     case VLC_VAR_VOID:
405         menuitem = new wxMenuItemExt( menu, ++i_item_id,
406                                       wxU(text.psz_string ?
407                                         text.psz_string : psz_var),
408                                       wxT(""), wxITEM_NORMAL, strdup(psz_var),
409                                       p_object->i_object_id, val, i_type );
410         menu->Append( menuitem );
411         break;
412
413     case VLC_VAR_BOOL:
414         val.b_bool = !val.b_bool;
415         menuitem = new wxMenuItemExt( menu, ++i_item_id,
416                                       wxU(text.psz_string ?
417                                         text.psz_string : psz_var),
418                                       wxT(""), wxITEM_CHECK, strdup(psz_var),
419                                       p_object->i_object_id, val, i_type );
420         menu->Append( menuitem );
421         Check( i_item_id, val.b_bool ? FALSE : TRUE );
422         break;
423
424     default:
425         if( text.psz_string ) free( text.psz_string );
426         return;
427     }
428
429     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
430     if( text.psz_string ) free( text.psz_string );
431 }
432
433 wxMenu *Menu::CreateChoicesMenu( char *psz_var, vlc_object_t *p_object )
434 {
435     vlc_value_t val, val_list, text_list;
436     int i_type, i;
437
438     /* Check the type of the object variable */
439     i_type = var_Type( p_object, psz_var );
440
441     /* Make sure we want to display the variable */
442     if( i_type & VLC_VAR_HASCHOICE )
443     {
444         var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
445         if( val.i_int == 0 ) return NULL;
446         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
447             return NULL;
448     }
449     else
450     {
451         return NULL;
452     }
453
454     switch( i_type & VLC_VAR_TYPE )
455     {
456     case VLC_VAR_VOID:
457     case VLC_VAR_BOOL:
458     case VLC_VAR_VARIABLE:
459     case VLC_VAR_STRING:
460     case VLC_VAR_INTEGER:
461         break;
462     default:
463         /* Variable doesn't exist or isn't handled */
464         return NULL;
465     }
466
467     if( var_Get( p_object, psz_var, &val ) < 0 )
468     {
469         return NULL;
470     }
471
472     if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
473                     &val_list, &text_list ) < 0 )
474     {
475         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
476         return NULL;
477     }
478
479     wxMenu *menu = new wxMenu;
480     for( i = 0; i < val_list.p_list->i_count; i++ )
481     {
482         vlc_value_t another_val;
483         wxMenuItemExt *menuitem;
484
485         switch( i_type & VLC_VAR_TYPE )
486         {
487         case VLC_VAR_VARIABLE:
488           menu->Append( MenuDummy_Event,
489                         wxU(text_list.p_list->p_values[i].psz_string ?
490                         text_list.p_list->p_values[i].psz_string :
491                         val_list.p_list->p_values[i].psz_string),
492                         CreateChoicesMenu(
493                             val_list.p_list->p_values[i].psz_string,
494                             p_object ), wxT("") );
495           break;
496
497         case VLC_VAR_STRING:
498           another_val.psz_string =
499               strdup(val_list.p_list->p_values[i].psz_string);
500           menuitem =
501               new wxMenuItemExt( menu, ++i_item_id,
502                                  wxU(text_list.p_list->p_values[i].psz_string ?
503                                  text_list.p_list->p_values[i].psz_string :
504                                  another_val.psz_string),
505                                  wxT(""), wxITEM_RADIO, strdup(psz_var),
506                                  p_object->i_object_id, another_val, i_type );
507
508           menu->Append( menuitem );
509
510           if( !strcmp( val.psz_string,
511                        val_list.p_list->p_values[i].psz_string ) )
512               menu->Check( i_item_id, TRUE );
513           break;
514
515         case VLC_VAR_INTEGER:
516           menuitem =
517               new wxMenuItemExt( menu, ++i_item_id,
518                                  text_list.p_list->p_values[i].psz_string ?
519                                  wxU(text_list.p_list->p_values[i].psz_string):
520                                  wxString::Format(wxT("%d"),
521                                  val_list.p_list->p_values[i].i_int),
522                                  wxT(""), wxITEM_RADIO, strdup(psz_var),
523                                  p_object->i_object_id,
524                                  val_list.p_list->p_values[i], i_type );
525
526           menu->Append( menuitem );
527
528           if( val_list.p_list->p_values[i].i_int == val.i_int )
529               menu->Check( i_item_id, TRUE );
530           break;
531
532         default:
533           break;
534         }
535     }
536
537     /* clean up everything */
538     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
539     var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, &text_list );
540
541     return menu;
542 }
543
544 /*****************************************************************************
545  * A small helper class which intercepts all popup menu events
546  *****************************************************************************/
547 MenuEvtHandler::MenuEvtHandler( intf_thread_t *_p_intf,
548                                 Interface *_p_main_interface )
549 {
550     /* Initializations */
551     p_intf = _p_intf;
552     p_main_interface = _p_main_interface;
553 }
554
555 MenuEvtHandler::~MenuEvtHandler()
556 {
557 }
558
559 void MenuEvtHandler::OnMenuEvent( wxCommandEvent& event )
560 {
561     wxMenuItem *p_menuitem = NULL;
562
563     /* Check if this is an auto generated menu item */
564     if( event.GetId() < FirstAutoGenerated_Event )
565     {
566         event.Skip();
567         return;
568     }
569
570     if( !p_main_interface ||
571         (p_menuitem = p_main_interface->GetMenuBar()->FindItem(event.GetId()))
572         == NULL )
573     {
574         if( p_intf->p_sys->p_popup_menu )
575         {
576             p_menuitem = 
577                 p_intf->p_sys->p_popup_menu->FindItem( event.GetId() );
578         }
579     }
580
581     if( p_menuitem )
582     {
583         wxMenuItemExt *p_menuitemext = (wxMenuItemExt *)p_menuitem;
584         vlc_object_t *p_object;
585
586         p_object = (vlc_object_t *)vlc_object_get( p_intf,
587                                        p_menuitemext->i_object_id );
588         if( p_object == NULL ) return;
589
590         var_Set( p_object, p_menuitemext->psz_var, p_menuitemext->val );
591
592         vlc_object_release( p_object );
593     }
594     else
595         event.Skip();
596 }
597
598 /*****************************************************************************
599  * A small helper class which encapsulate wxMenuitem with some other useful
600  * things.
601  *****************************************************************************/
602 wxMenuItemExt::wxMenuItemExt( wxMenu* parentMenu, int id, const wxString& text,
603     const wxString& helpString, wxItemKind kind,
604     char *_psz_var, int _i_object_id, vlc_value_t _val, int _i_val_type ):
605     wxMenuItem( parentMenu, id, text, helpString, kind )
606 {
607     /* Initializations */
608     psz_var = _psz_var;
609     i_val_type = _i_val_type;
610     i_object_id = _i_object_id;
611     val = _val;
612 };
613
614 wxMenuItemExt::~wxMenuItemExt()
615 {
616     if( psz_var ) free( psz_var );
617     if( ((i_val_type & VLC_VAR_TYPE) == VLC_VAR_STRING)
618         && val.psz_string ) free( val.psz_string );
619 };