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