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