1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2006 the VideoLAN team
7 * Authors: ClÃment Stenac <zorglub@videolan.org>
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
25 #include "dialogs_provider.hpp"
26 #include "input_manager.hpp"
30 #include <QActionGroup>
31 #include <QSignalMapper>
40 static QActionGroup *currentGroup;
42 // Add static entries to menus
43 #define DP_SADD( text, help, icon, slot ) { if( strlen(icon) > 0 ) { QAction *action = menu->addAction( text, THEDP, SLOT( slot ) ); action->setIcon(QIcon(icon));} else { menu->addAction( text, THEDP, SLOT( slot ) ); } }
44 #define MIM_SADD( text, help, icon, slot ) { if( strlen(icon) > 0 ) { QAction *action = menu->addAction( text, THEMIM, SLOT( slot ) ); action->setIcon(QIcon(icon));} else { menu->addAction( text, THEMIM, SLOT( slot ) ); } }
46 /*****************************************************************************
47 * Definitions of variables for the dynamic menus
48 *****************************************************************************/
49 #define PUSH_VAR( var ) varnames.push_back( var ); \
50 objects.push_back( p_object->i_object_id )
52 #define PUSH_SEPARATOR if( objects.size() != i_last_separator ) { \
53 objects.push_back( 0 ); varnames.push_back( "" ); \
54 i_last_separator = objects.size(); }
56 static int InputAutoMenuBuilder( vlc_object_t *p_object,
58 vector<const char *> &varnames )
60 PUSH_VAR( "bookmark");
62 PUSH_VAR ("chapter" );
63 PUSH_VAR( "program" );
64 PUSH_VAR( "navigation" );
65 PUSH_VAR( "dvd_menus" );
69 static int VideoAutoMenuBuilder( vlc_object_t *p_object,
71 vector<const char *> &varnames )
73 PUSH_VAR( "fullscreen" );
75 PUSH_VAR( "deinterlace" );
76 PUSH_VAR( "aspect-ratio" );
78 PUSH_VAR( "video-on-top" );
79 PUSH_VAR( "directx-wallpaper" );
80 PUSH_VAR( "video-snapshot" );
82 vlc_object_t *p_dec_obj = (vlc_object_t *)vlc_object_find( p_object,
85 if( p_dec_obj != NULL )
87 PUSH_VAR( "ffmpeg-pp-q" );
88 vlc_object_release( p_dec_obj );
93 static int AudioAutoMenuBuilder( vlc_object_t *p_object,
95 vector<const char *> &varnames )
97 PUSH_VAR( "audio-device" );
98 PUSH_VAR( "audio-channels" );
100 PUSH_VAR( "equalizer" );
104 /*****************************************************************************
106 *****************************************************************************/
108 void QVLCMenu::createMenuBar( QMenuBar *bar, intf_thread_t *p_intf )
110 #define BAR_ADD( func, title ) { \
111 QMenu *menu = func; menu->setTitle( title ); bar->addMenu( menu ); }
113 #define BAR_DADD( func, title, id ) { \
114 QMenu *menu = func; menu->setTitle( title ); bar->addMenu( menu ); \
115 MenuFunc *f = new MenuFunc( menu, id ); \
116 connect( menu, SIGNAL( aboutToShow() ), \
117 THEDP->menusUpdateMapper, SLOT(map()) ); \
118 THEDP->menusUpdateMapper->setMapping( menu, f ); }
120 BAR_ADD( FileMenu(), qtr("File") );
121 BAR_ADD( ToolsMenu( p_intf ), qtr("Tools") );
122 BAR_DADD( VideoMenu( p_intf, NULL ), qtr("Video"), 1 );
123 BAR_DADD( AudioMenu( p_intf, NULL ), qtr("Audio"), 2 );
124 BAR_DADD( NavigMenu( p_intf, NULL ), qtr("Navigation"), 3 );
126 // BAR_ADD( HelpMenu(), qtr("Help" ) );
129 QMenu *QVLCMenu::FileMenu()
131 QMenu *menu = new QMenu();
132 DP_SADD( qtr("Quick &Open File...") , "", "", simpleOpenDialog() );
133 DP_SADD( qtr("&Advanced Open..." ), "", "", openDialog() );
134 menu->addSeparator();
135 DP_SADD( qtr("Streaming..."), "", "", streamingDialog() );
136 menu->addSeparator();
137 DP_SADD( qtr("&Quit") , "", "", quit() );
141 QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf, bool with_intf )
143 QMenu *menu = new QMenu();
146 QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
147 intfmenu->setTitle( qtr("Interfaces" ) );
148 menu->addMenu( intfmenu );
149 /** \todo ADD EXT GUI HERE */
150 menu->addSeparator();
152 DP_SADD( qtr("Messages" ), "", "", messagesDialog() );
153 DP_SADD( qtr("Information") , "", "", streaminfoDialog() );
154 DP_SADD( qtr("Bookmarks"), "", "", bookmarksDialog() );
155 menu->addSeparator();
156 DP_SADD( qtr("Preferences"), "", "", prefsDialog() );
160 QMenu *QVLCMenu::InterfacesMenu( intf_thread_t *p_intf, QMenu *current )
163 vector<const char *> varnames;
164 /** \todo add "switch to XXX" */
165 varnames.push_back( "intf-add" );
166 objects.push_back( p_intf->i_object_id );
168 QMenu *menu = Populate( p_intf, current, varnames, objects );
169 connect( menu, SIGNAL( aboutToShow() ),
170 THEDP->menusUpdateMapper, SLOT(map()) );
171 THEDP->menusUpdateMapper->setMapping( menu, 4 );
176 QMenu *QVLCMenu::AudioMenu( intf_thread_t *p_intf, QMenu * current )
179 vector<const char *> varnames;
181 vlc_object_t *p_object = (vlc_object_t *)vlc_object_find( p_intf,
182 VLC_OBJECT_INPUT, FIND_ANYWHERE );
183 if( p_object != NULL )
185 PUSH_VAR( "audio-es" );
186 vlc_object_release( p_object );
189 p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,
193 AudioAutoMenuBuilder( p_object, objects, varnames );
194 vlc_object_release( p_object );
196 return Populate( p_intf, current, varnames, objects );
200 QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
202 vlc_object_t *p_object;
204 vector<const char *> varnames;
206 p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
208 if( p_object != NULL )
210 PUSH_VAR( "video-es" );
211 PUSH_VAR( "spu-es" );
212 vlc_object_release( p_object );
215 p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
217 if( p_object != NULL )
219 VideoAutoMenuBuilder( p_object, objects, varnames );
220 vlc_object_release( p_object );
222 return Populate( p_intf, current, varnames, objects );
225 QMenu *QVLCMenu::NavigMenu( intf_thread_t *p_intf, QMenu *current )
227 vlc_object_t *p_object;
229 vector<const char *> varnames;
232 p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
234 if( p_object != NULL )
236 InputAutoMenuBuilder( p_object, objects, varnames );
237 PUSH_VAR( "prev-title"); PUSH_VAR ( "next-title" );
238 PUSH_VAR( "prev-chapter"); PUSH_VAR( "next-chapter" );
239 vlc_object_release( p_object );
241 return Populate( p_intf, current, varnames, objects );
245 /*****************************************************************************
247 *****************************************************************************/
248 #define POPUP_BOILERPLATE \
249 unsigned int i_last_separator = 0; \
250 vector<int> objects; \
251 vector<const char *> varnames; \
252 input_thread_t *p_input = THEMIM->getInput();
254 #define CREATE_POPUP \
255 QMenu *menu = new QMenu(); \
256 Populate( p_intf, menu, varnames, objects ); \
257 p_intf->p_sys->p_popup_menu = menu; \
258 menu->popup( QCursor::pos() ); \
259 p_intf->p_sys->p_popup_menu = NULL; \
260 i_last_separator = 0;
262 #define POPUP_STATIC_ENTRIES \
264 MIM_SADD( qtr("Stop"), "", "", stop() ); \
265 MIM_SADD( qtr("Previous"), "", "", prev() ); \
266 MIM_SADD( qtr("Next"), "", "", next() ); \
269 var_Get( p_input, "state", &val ); \
270 if( val.i_int == PAUSE_S ) \
271 MIM_SADD( qtr("Play"), "", "", togglePlayPause() ) \
273 MIM_SADD( qtr("Pause"), "", "", togglePlayPause() ) \
275 else if( THEPL->i_size && THEPL->i_enabled ) \
276 MIM_SADD( qtr("Play"), "", "", togglePlayPause() ) \
278 QMenu *intfmenu = InterfacesMenu( p_intf, NULL ); \
279 intfmenu->setTitle( qtr("Interfaces" ) ); \
280 menu->addMenu( intfmenu ); \
282 QMenu *toolsmenu = ToolsMenu( p_intf, false ); \
283 toolsmenu->setTitle( qtr("Tools" ) ); \
284 menu->addMenu( toolsmenu ); \
286 void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
291 vlc_object_yield( p_input );
292 varnames.push_back( "video-es" );
293 objects.push_back( p_input->i_object_id );
294 varnames.push_back( "spu-es" );
295 objects.push_back( p_input->i_object_id );
296 vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
297 VLC_OBJECT_VOUT, FIND_CHILD );
300 VideoAutoMenuBuilder( p_vout, objects, varnames );
301 vlc_object_release( p_vout );
303 vlc_object_release( p_input );
308 void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
313 vlc_object_yield( p_input );
314 varnames.push_back( "audio-es" );
315 objects.push_back( p_input->i_object_id );
316 vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
317 VLC_OBJECT_AOUT, FIND_ANYWHERE );
320 AudioAutoMenuBuilder( p_aout, objects, varnames );
321 vlc_object_release( p_aout );
323 vlc_object_release( p_input );
328 /* Navigation stuff, and general */
329 void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
334 vlc_object_yield( p_input );
335 varnames.push_back( "audio-es" );
336 InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
340 QMenu *menu = new QMenu();
341 Populate( p_intf, menu, varnames, objects );
342 menu->addSeparator();
343 POPUP_STATIC_ENTRIES;
345 p_intf->p_sys->p_popup_menu = menu;
346 menu->popup( QCursor::pos() );
347 p_intf->p_sys->p_popup_menu = NULL;
350 void QVLCMenu::PopupMenu( intf_thread_t *p_intf )
355 vlc_object_yield( p_input );
356 InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
360 varnames.push_back( "video-es" );
361 objects.push_back( p_input->i_object_id );
362 varnames.push_back( "spu-es" );
363 objects.push_back( p_input->i_object_id );
364 vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
365 VLC_OBJECT_VOUT, FIND_CHILD );
368 VideoAutoMenuBuilder( p_vout, objects, varnames );
369 vlc_object_release( p_vout );
373 varnames.push_back( "audio-es" );
374 objects.push_back( p_input->i_object_id );
375 vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
376 VLC_OBJECT_AOUT, FIND_ANYWHERE );
379 AudioAutoMenuBuilder( p_aout, objects, varnames );
380 vlc_object_release( p_aout );
384 QMenu *menu = new QMenu();
385 Populate( p_intf, menu, varnames, objects );
386 menu->addSeparator();
387 POPUP_STATIC_ENTRIES;
389 p_intf->p_sys->p_popup_menu = menu;
390 menu->popup( QCursor::pos() );
391 p_intf->p_sys->p_popup_menu = NULL;
395 #undef PUSH_SEPARATOR
397 /*************************************************************************
398 * Builders for automenus
399 *************************************************************************/
400 QMenu * QVLCMenu::Populate( intf_thread_t *p_intf, QMenu *current,
401 vector< const char *> & varnames,
402 vector<int> & objects, bool append )
404 QMenu *menu = current;
412 vlc_object_t *p_object;
413 vlc_bool_t b_section_empty = VLC_FALSE;
416 #define APPEND_EMPTY { QAction *action = menu->addAction( qtr("Empty" ) ); \
417 action->setEnabled( false ); }
419 for( i = 0; i < (int)objects.size() ; i++ )
421 if( !varnames[i] || !*varnames[i] )
423 if( b_section_empty )
425 menu->addSeparator();
426 b_section_empty = VLC_TRUE;
430 if( objects[i] == 0 )
432 /// \bug What is this ?
433 // Append( menu, varnames[i], NULL );
434 b_section_empty = VLC_FALSE;
438 p_object = (vlc_object_t *)vlc_object_get( p_intf,
440 if( p_object == NULL ) continue;
442 b_section_empty = VLC_FALSE;
443 /* Ugly specific stuff */
444 if( strstr(varnames[i], "intf-add" ) )
445 CreateItem( menu, varnames[i], p_object, false );
447 CreateItem( menu, varnames[i], p_object, true );
448 vlc_object_release( p_object );
451 /* Special case for empty menus */
452 if( menu->actions().size() == 0 || b_section_empty )
458 /*****************************************************************************
460 *****************************************************************************/
462 #define FREE(x) if(x) { free(x);x=NULL;}
464 static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object,
467 vlc_value_t val, val_list;
468 int i_type, i_result, i;
470 /* Check the type of the object variable */
471 i_type = var_Type( p_object, psz_var );
473 /* Check if we want to display the variable */
474 if( !(i_type & VLC_VAR_HASCHOICE) ) return FALSE;
476 var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
477 if( val.i_int == 0 ) return TRUE;
479 if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE )
481 /* Very evil hack ! intf-switch can have only one value */
482 if( !strcmp( psz_var, "intf-switch" ) ) return FALSE;
483 if( val.i_int == 1 && b_root ) return TRUE;
487 /* Check children variables in case of VLC_VAR_VARIABLE */
488 if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
493 for( i = 0, i_result = TRUE; i < val_list.p_list->i_count; i++ )
495 if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
503 /* clean up everything */
504 var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, NULL );
509 void QVLCMenu::CreateItem( QMenu *menu, const char *psz_var,
510 vlc_object_t *p_object, bool b_submenu )
512 vlc_value_t val, text;
515 /* Check the type of the object variable */
516 i_type = var_Type( p_object, psz_var );
518 switch( i_type & VLC_VAR_TYPE )
522 case VLC_VAR_VARIABLE:
524 case VLC_VAR_INTEGER:
528 /* Variable doesn't exist or isn't handled */
532 /* Make sure we want to display the variable */
533 if( IsMenuEmpty( psz_var, p_object ) ) return;
535 /* Get the descriptive name of the variable */
536 var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );
538 if( i_type & VLC_VAR_HASCHOICE )
540 /* Append choices menu */
543 QMenu *submenu = new QMenu();
544 submenu->setTitle( qfu( text.psz_string ?
545 text.psz_string : psz_var ) );
546 if( CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0)
547 menu->addMenu( submenu );
550 CreateChoicesMenu( menu, psz_var, p_object, true );
551 FREE( text.psz_string );
555 #define TEXT_OR_VAR qfu ( text.psz_string ? text.psz_string : psz_var )
557 switch( i_type & VLC_VAR_TYPE )
560 var_Get( p_object, psz_var, &val );
561 CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_NORMAL,
562 p_object->i_object_id, val, i_type );
566 var_Get( p_object, psz_var, &val );
567 val.b_bool = !val.b_bool;
568 CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
569 p_object->i_object_id, val, i_type, val.b_bool );
572 FREE( text.psz_string );
576 int QVLCMenu::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
577 vlc_object_t *p_object, bool b_root )
579 vlc_value_t val, val_list, text_list;
582 /* Check the type of the object variable */
583 i_type = var_Type( p_object, psz_var );
585 /* Make sure we want to display the variable */
586 if( IsMenuEmpty( psz_var, p_object, b_root ) ) return VLC_EGENERIC;
588 switch( i_type & VLC_VAR_TYPE )
592 case VLC_VAR_VARIABLE:
594 case VLC_VAR_INTEGER:
598 /* Variable doesn't exist or isn't handled */
602 if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
603 &val_list, &text_list ) < 0 )
607 #define NORMAL_OR_RADIO i_type & VLC_VAR_ISCOMMAND ? ITEM_NORMAL: ITEM_RADIO
608 #define NOTCOMMAND !(i_type & VLC_VAR_ISCOMMAND)
609 #define CURVAL val_list.p_list->p_values[i]
610 #define CURTEXT text_list.p_list->p_values[i].psz_string
612 for( i = 0; i < val_list.p_list->i_count; i++ )
614 vlc_value_t another_val;
616 QMenu *subsubmenu = new QMenu();
618 switch( i_type & VLC_VAR_TYPE )
620 case VLC_VAR_VARIABLE:
621 CreateChoicesMenu( subsubmenu, CURVAL.psz_string, p_object, false );
622 subsubmenu->setTitle( qfu( CURTEXT ? CURTEXT :CURVAL.psz_string ) );
623 submenu->addMenu( subsubmenu );
627 var_Get( p_object, psz_var, &val );
628 another_val.psz_string = strdup( CURVAL.psz_string );
630 menutext = qfu( CURTEXT ? CURTEXT : another_val.psz_string );
631 CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
632 p_object->i_object_id, another_val, i_type,
633 NOTCOMMAND && val.psz_string &&
634 !strcmp( val.psz_string, CURVAL.psz_string ) );
636 if( val.psz_string ) free( val.psz_string );
639 case VLC_VAR_INTEGER:
640 var_Get( p_object, psz_var, &val );
641 if( CURTEXT ) menutext = qfu( CURTEXT );
642 else menutext.sprintf( "%d", CURVAL.i_int);
643 CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
644 p_object->i_object_id, CURVAL, i_type,
645 NOTCOMMAND && CURVAL.i_int == val.i_int );
649 var_Get( p_object, psz_var, &val );
650 if( CURTEXT ) menutext = qfu( CURTEXT );
651 else menutext.sprintf( "%.2f", CURVAL.f_float );
652 CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
653 p_object->i_object_id, CURVAL, i_type,
654 NOTCOMMAND && CURVAL.f_float == val.f_float );
662 /* clean up everything */
663 var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, &text_list );
665 #undef NORMAL_OR_RADIO
672 void QVLCMenu::CreateAndConnect( QMenu *menu, const char *psz_var,
673 QString text, QString help,
674 int i_item_type, int i_object_id,
675 vlc_value_t val, int i_val_type,
678 QAction *action = new QAction( text, menu );
679 action->setText( text );
680 action->setToolTip( help );
682 if( i_item_type == ITEM_CHECK )
684 action->setCheckable( true );
687 else if( i_item_type == ITEM_RADIO )
689 action->setCheckable( true );
691 currentGroup = new QActionGroup(menu);
692 currentGroup->addAction( action );
696 if( checked ) action->setChecked( true );
698 MenuItemData *itemData = new MenuItemData( i_object_id, i_val_type,
700 connect( action, SIGNAL(triggered()), THEDP->menusMapper, SLOT(map()) );
701 THEDP->menusMapper->setMapping( action, itemData );
703 menu->addAction( action );
706 void QVLCMenu::DoAction( intf_thread_t *p_intf, QObject *data )
708 MenuItemData *itemData = qobject_cast<MenuItemData *>(data);
710 vlc_object_t *p_object = (vlc_object_t *)vlc_object_get( p_intf,
711 itemData->i_object_id );
712 if( p_object == NULL ) return;
714 fprintf( stderr, "Setting %s on %i\n", itemData->psz_var,
715 p_object->i_object_id );
716 var_Set( p_object, itemData->psz_var, itemData->val );
717 vlc_object_release( p_object );