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