menus.cpp 31.8 KB
Newer Older
zorglub's avatar
zorglub committed
1 2 3
/*****************************************************************************
 * menus.cpp : Qt menus
 *****************************************************************************
4
 * Copyright (C) 2006-2007 the VideoLAN team
5
 * $Id$
zorglub's avatar
zorglub committed
6
 *
7
 * Authors: Clment Stenac <zorglub@videolan.org>
8
 *          Jean-Baptiste Kempf <jb@videolan.org>
zorglub's avatar
zorglub committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

25 26 27 28
#ifndef WIN32
#   include <signal.h>
#endif

zorglub's avatar
zorglub committed
29
#include <vlc_intf_strings.h>
zorglub's avatar
zorglub committed
30

zorglub's avatar
zorglub committed
31
#include "main_interface.hpp"
zorglub's avatar
zorglub committed
32 33 34 35
#include "menus.hpp"
#include "dialogs_provider.hpp"
#include "input_manager.hpp"

36 37 38 39 40 41 42
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QActionGroup>
#include <QSignalMapper>
#include <QSystemTrayIcon>

zorglub's avatar
zorglub committed
43 44 45 46 47 48 49 50 51
enum
{
    ITEM_NORMAL,
    ITEM_CHECK,
    ITEM_RADIO
};

static QActionGroup *currentGroup;

52
// Add static entries to menus
53
#define DP_SADD( menu, text, help, icon, slot, shortcut ) \
54
{ \
55
    if( strlen( icon ) > 0 ) \
56
    { \
57
        if( strlen( shortcut ) > 0 ) \
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
58
        { \
59 60
            menu->addAction( QIcon( icon ), text, THEDP, SLOT( slot ), \
                    qtr( shortcut ) );\
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
61 62 63
        } \
        else \
        { \
64
            menu->addAction( QIcon( icon ), text, THEDP, SLOT( slot ) );\
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
65
        } \
66 67 68
    } \
    else \
    { \
69
        if( strlen( shortcut ) > 0 ) \
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
70 71
        { \
            menu->addAction( text, THEDP, SLOT( slot ), \
72
                    qtr( shortcut ) ); \
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
73 74 75 76 77
        } \
        else \
        { \
            menu->addAction( text, THEDP, SLOT( slot ) ); \
        } \
78
    } \
79
}
80
#define MIM_SADD( menu, text, help, icon, slot ) \
81
{ \
82
    if( strlen( icon ) > 0 ) \
83 84
    { \
        QAction *action = menu->addAction( text, THEMIM, SLOT( slot ) ); \
85
        action->setIcon( QIcon( icon ) ); \
86 87 88 89 90
    } \
    else \
    { \
        menu->addAction( text, THEMIM, SLOT( slot ) ); \
    } \
91
}
zorglub's avatar
Qt4:  
zorglub committed
92
#define PL_SADD
zorglub's avatar
zorglub committed
93 94

/*****************************************************************************
95
 * Definitions of variables for the dynamic menus
zorglub's avatar
zorglub committed
96
 *****************************************************************************/
97
#define PUSH_VAR( var ) varnames.push_back( var ); \
98
    objects.push_back( p_object->i_object_id )
99 100

#define PUSH_SEPARATOR if( objects.size() != i_last_separator ) { \
101 102
    objects.push_back( 0 ); varnames.push_back( "" ); \
    i_last_separator = objects.size(); }
zorglub's avatar
zorglub committed
103 104

static int InputAutoMenuBuilder( vlc_object_t *p_object,
105 106
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
107 108 109 110 111 112 113 114 115 116
{
    PUSH_VAR( "bookmark");
    PUSH_VAR( "title" );
    PUSH_VAR ("chapter" );
    PUSH_VAR( "program" );
    PUSH_VAR( "navigation" );
    PUSH_VAR( "dvd_menus" );
    return VLC_SUCCESS;
}

zorglub's avatar
Qt4:  
zorglub committed
117
static int VideoAutoMenuBuilder( vlc_object_t *p_object,
118 119
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
120 121 122 123 124 125 126 127 128 129 130
{
    PUSH_VAR( "fullscreen" );
    PUSH_VAR( "zoom" );
    PUSH_VAR( "deinterlace" );
    PUSH_VAR( "aspect-ratio" );
    PUSH_VAR( "crop" );
    PUSH_VAR( "video-on-top" );
    PUSH_VAR( "directx-wallpaper" );
    PUSH_VAR( "video-snapshot" );

    vlc_object_t *p_dec_obj = (vlc_object_t *)vlc_object_find( p_object,
131 132
            VLC_OBJECT_DECODER,
            FIND_PARENT );
zorglub's avatar
zorglub committed
133 134
    if( p_dec_obj != NULL )
    {
135
        vlc_object_t *p_object = p_dec_obj;
zorglub's avatar
zorglub committed
136 137 138 139 140 141 142
        PUSH_VAR( "ffmpeg-pp-q" );
        vlc_object_release( p_dec_obj );
    }
    return VLC_SUCCESS;
}

static int AudioAutoMenuBuilder( vlc_object_t *p_object,
143 144
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
145 146 147 148 149 150 151 152
{
    PUSH_VAR( "audio-device" );
    PUSH_VAR( "audio-channels" );
    PUSH_VAR( "visual" );
    PUSH_VAR( "equalizer" );
    return VLC_SUCCESS;
}

153 154
/*****************************************************************************
 * All normal menus
155
 * Simple Code
156 157 158 159 160 161 162 163
 *****************************************************************************/

#define BAR_ADD( func, title ) { \
    QMenu *menu = func; menu->setTitle( title  ); bar->addMenu( menu ); }

#define BAR_DADD( func, title, id ) { \
    QMenu *menu = func; menu->setTitle( title  ); bar->addMenu( menu ); \
    MenuFunc *f = new MenuFunc( menu, id ); \
zorglub's avatar
zorglub committed
164
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
165 166
    THEDP->menusUpdateMapper->setMapping( menu, f ); }

167 168 169
/**
 * Main Menu Bar Creation
 **/
zorglub's avatar
zorglub committed
170
void QVLCMenu::createMenuBar( MainInterface *mi, intf_thread_t *p_intf,
171 172
        bool playlist, bool adv_controls_enabled,
        bool visual_selector_enabled )
zorglub's avatar
Qt4:  
zorglub committed
173
{
174
#ifndef WIN32
175
    /* Ugly klugde
176 177 178 179 180 181
     * Remove SIGCHLD from the ignored signal the time to initialise
     * Qt because it call gconf to get the icon theme */
    sigset_t set;

    sigemptyset( &set );
    sigaddset( &set, SIGCHLD );
182
    pthread_sigmask( SIG_UNBLOCK, &set, NULL );
183
#endif /* WIN32 */
zorglub's avatar
zorglub committed
184
    QMenuBar *bar = mi->menuBar();
185
#ifndef WIN32
186
    pthread_sigmask( SIG_BLOCK, &set, NULL );
187
#endif /* WIN32 */
188
    BAR_ADD( FileMenu(), qtr("&Media") );
zorglub's avatar
zorglub committed
189 190
    if( playlist )
    {
191
        BAR_ADD( PlaylistMenu( mi,p_intf ), qtr("&Playlist" ) );
zorglub's avatar
zorglub committed
192
    }
193
    BAR_ADD( ToolsMenu( p_intf, mi, adv_controls_enabled,
194
                visual_selector_enabled ), qtr("&Tools") );
195 196 197
    BAR_DADD( VideoMenu( p_intf, NULL ), qtr("&Video"), 1 );
    BAR_DADD( AudioMenu( p_intf, NULL ), qtr("&Audio"), 2 );
    BAR_DADD( NavigMenu( p_intf, NULL ), qtr("&Navigation"), 3 );
198

199
    BAR_ADD( HelpMenu(), qtr("&Help" ) );
200
}
201 202 203 204 205

/**
 * Media (File) Menu
 * Opening, streaming and quit
 **/
206 207 208
QMenu *QVLCMenu::FileMenu()
{
    QMenu *menu = new QMenu();
209 210
    DP_SADD( menu, qtr("Open &File..." ), "",
            ":/pixmaps/vlc_file-asym_16px.png", openFileDialog(), "Ctrl+O" );
211 212 213 214 215 216 217 218 219 220

    /* Folder vs. Directory */
#ifdef WIN32
    DP_SADD( menu, qtr( "Open Folder..." ), "",
            ":/pixmaps/vlc_folder-grey_16px.png", openDirDialog(), "Ctrl+F" );
#else
    DP_SADD( menu, qtr( "Open Directory..." ), "",
            ":/pixmaps/vlc_folder-grey_16px.png", openDirDialog(), "Ctrl+F" );
#endif /* WIN32 */

221 222
    DP_SADD( menu, qtr("Open &Disc..." ), "", ":/pixmaps/vlc_disc_16px.png",
             openDiscDialog(), "Ctrl+D" );
223 224 225 226
    DP_SADD( menu, qtr("Open &Network..." ), "",
                ":/pixmaps/vlc_network_16px.png", openNetDialog(), "Ctrl+N" );
    DP_SADD( menu, qtr("Open &Capture Device..." ), "",
            ":/pixmaps/vlc_capture-card_16px.png", openCaptureDialog(),
227
            "Ctrl+C" );
228
    menu->addSeparator();
229 230
    DP_SADD( menu, qtr("&Streaming..."), "", ":/pixmaps/vlc_stream_16px.png",
            openThenStreamingDialogs(), "Ctrl+S" );
231 232
    DP_SADD( menu, qtr("Conve&rt / Save..."), "", "",
            openThenTranscodingDialogs(), "Ctrl+R" );
233
    menu->addSeparator();
234
    DP_SADD( menu, qtr("&Quit") , "", ":/pixmaps/vlc_quit_16px.png", quit(),
235
            "Ctrl+Q");
236 237 238
    return menu;
}

239
/* Playlist Menu, undocked when playlist is undocked */
zorglub's avatar
zorglub committed
240
QMenu *QVLCMenu::PlaylistMenu( MainInterface *mi, intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
241 242 243 244 245
{
    QMenu *menu = new QMenu();
    menu->addMenu( SDMenu( p_intf ) );
    menu->addSeparator();

246 247
    DP_SADD( menu, qtr( I_PL_LOAD ), "", "", openPlaylist(), "Ctrl+L" );
    DP_SADD( menu, qtr( I_PL_SAVE ), "", "", savePlaylist(), "Ctrl+K" );
zorglub's avatar
zorglub committed
248 249
    menu->addSeparator();
    menu->addAction( qtr("Undock from interface"), mi,
250
            SLOT( undockPlaylist() ), qtr("Ctrl+U") );
zorglub's avatar
zorglub committed
251 252 253
    return menu;
}

254 255 256 257 258
/**
 * Tools/View Menu
 * This is kept in the same menu for now, but could change if it gets much 
 * longer.
 **/
zorglub's avatar
zorglub committed
259
QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf, MainInterface *mi,
260 261
        bool adv_controls_enabled,
        bool visual_selector_enabled, bool with_intf )
262 263 264 265 266
{
    QMenu *menu = new QMenu();
    if( with_intf )
    {
        QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
zorglub's avatar
zorglub committed
267
        intfmenu->setTitle( qtr("Interfaces" ) );
268 269 270
        menu->addMenu( intfmenu );
        menu->addSeparator();
    }
271
    DP_SADD( menu, qtr( I_MENU_MSG ), "", ":/pixmaps/vlc_messages_16px.png",
272
             messagesDialog(), "Ctrl+M" );
273 274
    DP_SADD( menu, qtr( I_MENU_INFO ) , "", "", mediaInfoDialog(), "Ctrl+J" );
    DP_SADD( menu, qtr( I_MENU_CODECINFO ) , "", ":/pixmaps/vlc_info_16px.png",
275
             mediaCodecDialog(), "Ctrl+I" );
276
    DP_SADD( menu, qtr( I_MENU_GOTOTIME ), "","", gotoTimeDialog(), "Ctrl+T" );
277
#if 0 /* Not Implemented yet */
278 279
    DP_SADD( menu, qtr( I_MENU_BOOKMARK ), "","", bookmarksDialog(), "Ctrl+B" );
    DP_SADD( menu, qtr( I_MENU_VLM ), "","", vlmDialog(), "Ctrl+V" );
280
#endif
281

282
    menu->addSeparator();
zorglub's avatar
zorglub committed
283 284 285
    if( mi )
    {
        QAction *adv = menu->addAction( qtr("Advanced controls" ),
286
                mi, SLOT( advanced() ) );
zorglub's avatar
zorglub committed
287 288
        adv->setCheckable( true );
        if( adv_controls_enabled ) adv->setChecked( true );
289 290 291 292

	DP_SADD( menu, qtr( "Hide Menus..." ), "","",hideMenus(), "Ctrl+H" );
    	menu->addSeparator();

293
#if 0 /* For Visualisations. Not yet working */
294
        adv = menu->addAction( qtr("Visualizations selector" ),
295
                mi, SLOT( visual() ) );
296 297
        adv->setCheckable( true );
        if( visual_selector_enabled ) adv->setChecked( true );
298
#endif
299 300
  	menu->addAction ( QIcon(":/pixmaps/vlc_playlist_16px.png"),
	   		  qtr( "Playlist"), mi, SLOT( playlist() ) );
zorglub's avatar
zorglub committed
301
    }
302 303
    DP_SADD( menu, qtr( I_MENU_EXT ), "", ":/pixmaps/vlc_settings_16px.png",
                 extendedDialog() ,  "Ctrl+E"  );
304

305
    menu->addSeparator();
306 307
    DP_SADD( menu, qtr("Preferences"), "", ":/pixmaps/vlc_preferences_16px.png",
             prefsDialog(), "Ctrl+P" );
308 309 310
    return menu;
}

311 312 313
/**
 * Interface Sub-Menu, to list extras interface and skins
 **/
314 315 316 317 318 319 320
QMenu *QVLCMenu::InterfacesMenu( intf_thread_t *p_intf, QMenu *current )
{
    vector<int> objects;
    vector<const char *> varnames;
    /** \todo add "switch to XXX" */
    varnames.push_back( "intf-add" );
    objects.push_back( p_intf->i_object_id );
zorglub's avatar
Qt4:  
zorglub committed
321

322
    QMenu *menu = Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
323 324 325 326

    if( !p_intf->pf_show_dialog )
    {
        menu->addSeparator();
327
        menu->addAction( qtr("Switch to skins"), THEDP, SLOT( switchToSkins() ),
Christophe Mutricy's avatar
Christophe Mutricy committed
328
                QString("Ctrl+Z") );
zorglub's avatar
zorglub committed
329 330
    }

zorglub's avatar
zorglub committed
331
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() );
332 333 334 335
    THEDP->menusUpdateMapper->setMapping( menu, 4 );
    return menu;
}

336 337 338
/**
 * Main Audio Menu
 */
339 340 341 342 343 344
QMenu *QVLCMenu::AudioMenu( intf_thread_t *p_intf, QMenu * current )
{
    vector<int> objects;
    vector<const char *> varnames;

    vlc_object_t *p_object = (vlc_object_t *)vlc_object_find( p_intf,
345
            VLC_OBJECT_INPUT, FIND_ANYWHERE );
346 347 348 349 350 351 352
    if( p_object != NULL )
    {
        PUSH_VAR( "audio-es" );
        vlc_object_release( p_object );
    }

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,
353
            FIND_ANYWHERE );
354 355 356 357 358 359 360 361
    if( p_object )
    {
        AudioAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}

362 363 364 365
/**
 * Main Video Menu
 * Subtitles are part of Video.
 **/
366
QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
zorglub's avatar
zorglub committed
367 368
{
    vlc_object_t *p_object;
369 370 371 372
    vector<int> objects;
    vector<const char *> varnames;

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
373
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
374 375
    if( p_object != NULL )
    {
376 377
        PUSH_VAR( "video-es" );
        PUSH_VAR( "spu-es" );
zorglub's avatar
zorglub committed
378 379
        vlc_object_release( p_object );
    }
380 381

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
382
            FIND_ANYWHERE );
383 384 385 386 387 388
    if( p_object != NULL )
    {
        VideoAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
389 390
}

391 392 393 394
/**
 * Navigation Menu
 * For DVD, MP4, MOV and other chapter based format
 **/
395 396 397 398 399
QMenu *QVLCMenu::NavigMenu( intf_thread_t *p_intf, QMenu *current )
{
    vlc_object_t *p_object;
    vector<int> objects;
    vector<const char *> varnames;
zorglub's avatar
zorglub committed
400

401 402
    /* FIXME */
    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
403
            FIND_ANYWHERE );
404 405 406 407 408 409 410 411 412
    if( p_object != NULL )
    {
        InputAutoMenuBuilder( p_object, objects, varnames );
        PUSH_VAR( "prev-title"); PUSH_VAR ( "next-title" );
        PUSH_VAR( "prev-chapter"); PUSH_VAR( "next-chapter" );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}
zorglub's avatar
zorglub committed
413

414 415 416
/**
 * Service Discovery Menu
 **/
zorglub's avatar
zorglub committed
417 418 419
QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
420
    menu->setTitle( qtr( I_PL_SD ) );
zorglub's avatar
zorglub committed
421
    vlc_list_t *p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
422
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
    int i_num = 0;
    for( int i_index = 0 ; i_index < p_list->i_count; i_index++ )
    {
        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
            i_num++;
    }
    for( int i_index = 0 ; i_index < p_list->i_count; i_index++ )
    {
        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object;
        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
        {
            QAction *a = new QAction( qfu( p_parser->psz_longname ), menu );
            a->setCheckable( true );
            /* hack to handle submodules properly */
            int i = -1;
            while( p_parser->pp_shortcuts[++i] != NULL );
            i--;
            if( playlist_IsServicesDiscoveryLoaded( THEPL,
442 443
                        i>=0?p_parser->pp_shortcuts[i]
                        : p_parser->psz_object_name ) )
zorglub's avatar
zorglub committed
444 445 446 447 448
            {
                a->setChecked( true );
            }
            CONNECT( a , triggered(), THEDP->SDMapper, map() );
            THEDP->SDMapper->setMapping( a, i>=0? p_parser->pp_shortcuts[i] :
449
                    p_parser->psz_object_name );
zorglub's avatar
zorglub committed
450 451 452 453 454 455
            menu->addAction( a );
        }
    }
    vlc_list_release( p_list );
    return menu;
}
456 457 458
/**
 * Help/About Menu
**/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
459 460 461
QMenu *QVLCMenu::HelpMenu()
{
    QMenu *menu = new QMenu();
462 463
    DP_SADD( menu, qtr("Help") , "", ":/pixmaps/vlc_help_16px.png",
             helpDialog(), "F1" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
464
    menu->addSeparator();
465
    DP_SADD( menu, qtr( I_MENU_ABOUT ), "", "", aboutDialog(), "Ctrl+F1");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
466 467 468 469
    return menu;
}


470
/*****************************************************************************
471
 * Popup menus - Right Click menus                                           *
472
 *****************************************************************************/
zorglub's avatar
zorglub committed
473 474
#define POPUP_BOILERPLATE \
    unsigned int i_last_separator = 0; \
475 476 477 478 479 480 481 482 483
    vector<int> objects; \
    vector<const char *> varnames; \
    input_thread_t *p_input = THEMIM->getInput();

#define CREATE_POPUP \
    QMenu *menu = new QMenu(); \
    Populate( p_intf, menu, varnames, objects ); \
    p_intf->p_sys->p_popup_menu = menu; \
    menu->popup( QCursor::pos() ); \
zorglub's avatar
zorglub committed
484
    p_intf->p_sys->p_popup_menu = NULL; \
485
    i_last_separator = 0;
zorglub's avatar
zorglub committed
486

487
#define POPUP_PLAY_ENTRIES( menu )\
488 489
    vlc_value_t val; \
    if( p_input ) \
zorglub's avatar
zorglub committed
490 491
    { \
        var_Get( p_input, "state", &val ); \
492
        if( val.i_int == PLAYING_S ) \
493 494
            MIM_SADD( menu, qtr("Pause"), "", ":/pixmaps/vlc_pause_16px.png", \
                    togglePlayPause() ) \
495
        else \
496 497
            MIM_SADD( menu, qtr("Play"), "", ":/pixmaps/vlc_play_16px.png", \
                    togglePlayPause() ) \
zorglub's avatar
zorglub committed
498
    } \
zorglub's avatar
zorglub committed
499
    else if( THEPL->items.i_size && THEPL->i_enabled ) \
500 501
        MIM_SADD( menu, qtr("Play"), "", ":/pixmaps/vlc_play_16px.png", \
                togglePlayPause() ); \
502
    \
503
    MIM_SADD( menu, qtr("Stop"), "", ":/pixmaps/vlc_stop_16px.png", stop() ); \
504 505 506
    MIM_SADD( menu, qtr("Previous"), "", ":/pixmaps/vlc_previous_16px.png", \
            prev() ); \
    MIM_SADD( menu, qtr("Next"), "", ":/pixmaps/vlc_next_16px.png", next() );
507 508 509

#define POPUP_STATIC_ENTRIES \
    POPUP_PLAY_ENTRIES( menu ); \
zorglub's avatar
zorglub committed
510
    \
511
    menu->addSeparator(); \
512
    QMenu *intfmenu = InterfacesMenu( p_intf, NULL ); \
zorglub's avatar
zorglub committed
513
    intfmenu->setTitle( qtr("Interfaces" ) ); \
514 515
    menu->addMenu( intfmenu ); \
    \
516
    QMenu *toolsmenu = ToolsMenu( p_intf, NULL, false, false, false ); \
zorglub's avatar
zorglub committed
517
    toolsmenu->setTitle( qtr("Tools" ) ); \
518
    menu->addMenu( toolsmenu ); \
519 520 521 522 523 524 525 526 527 528 529 530 531 532
    \
    QMenu *openmenu = new QMenu( qtr("Open") ); \
    openmenu->addAction( qtr("Open &File..." ), THEDP, SLOT( openFileDialog() ) ); \
    openmenu->addAction( qtr("Open &Disc..." ), THEDP, SLOT( openDiscDialog() ) ); \
    openmenu->addAction( qtr("Open &Network..." ), THEDP, SLOT( openNetDialog() ) ); \
    openmenu->addAction( qtr("Open &Capture Device..." ), THEDP, \
            SLOT( openCaptureDialog() ) ); \
    menu->addMenu( openmenu ); \
    \
    menu->addSeparator(); \
    QMenu *helpmenu = HelpMenu(); \
    helpmenu->setTitle( qtr("Help") ); \
    menu->addMenu( helpmenu ); \
    \
533
    DP_SADD( menu, qtr("Quit"), "", "", quit() , "Ctrl+Q" );
zorglub's avatar
Qt4:  
zorglub committed
534

535
/* Video Tracks and Subtitles tracks */
536
void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
537 538 539 540 541
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
542 543 544 545
        varnames.push_back( "video-es" );
        objects.push_back( p_input->i_object_id );
        varnames.push_back( "spu-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
546
        vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
547
                VLC_OBJECT_VOUT, FIND_CHILD );
zorglub's avatar
zorglub committed
548 549
        if( p_vout )
        {
550
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
551 552 553 554
            vlc_object_release( p_vout );
        }
        vlc_object_release( p_input );
    }
555
    CREATE_POPUP;
zorglub's avatar
zorglub committed
556 557
}

558
/* Audio Tracks */
559
void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
560 561 562 563 564
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
565 566
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
567
        vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
568
                VLC_OBJECT_AOUT, FIND_ANYWHERE );
zorglub's avatar
zorglub committed
569 570
        if( p_aout )
        {
571
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
572 573 574 575
            vlc_object_release( p_aout );
        }
        vlc_object_release( p_input );
    }
576
    CREATE_POPUP;
zorglub's avatar
zorglub committed
577 578
}

579
/* Navigation stuff, and general menus (open) */
580
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
581 582 583 584 585
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
586 587
        varnames.push_back( "audio-es" );
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
588 589 590
        PUSH_SEPARATOR;
    }

591 592 593
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
    menu->addSeparator();
zorglub's avatar
zorglub committed
594 595
    POPUP_STATIC_ENTRIES;

596 597
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
598 599 600
    p_intf->p_sys->p_popup_menu = NULL;
}

601
/* Main Menu that sticks everything together  */
damienf's avatar
damienf committed
602
void QVLCMenu::PopupMenu( intf_thread_t *p_intf, bool show )
zorglub's avatar
zorglub committed
603
{
damienf's avatar
damienf committed
604
    if( show )
zorglub's avatar
zorglub committed
605
    {
606
        // create a  popup if there is none
damienf's avatar
damienf committed
607
        if( ! p_intf->p_sys->p_popup_menu )
608
        {
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
            POPUP_BOILERPLATE;
            if( p_input )
            {
                vlc_object_yield( p_input );
                InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );

                /* Video menu */
                PUSH_SEPARATOR;
                varnames.push_back( "video-es" );
                objects.push_back( p_input->i_object_id );
                varnames.push_back( "spu-es" );
                objects.push_back( p_input->i_object_id );
                vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
                        VLC_OBJECT_VOUT, FIND_CHILD );
                if( p_vout )
                {
                    VideoAutoMenuBuilder( p_vout, objects, varnames );
                    vlc_object_release( p_vout );
                }
                /* Audio menu */
                PUSH_SEPARATOR
                    varnames.push_back( "audio-es" );
                objects.push_back( p_input->i_object_id );
                vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
                        VLC_OBJECT_AOUT, FIND_ANYWHERE );
                if( p_aout )
                {
                    AudioAutoMenuBuilder( p_aout, objects, varnames );
                    vlc_object_release( p_aout );
                }
            }
640

641 642 643 644
            QMenu *menu = new QMenu();
            Populate( p_intf, menu, varnames, objects );
            menu->addSeparator();
            POPUP_STATIC_ENTRIES;
645

646 647 648
            p_intf->p_sys->p_popup_menu = menu;
        }
        p_intf->p_sys->p_popup_menu->popup( QCursor::pos() );
damienf's avatar
damienf committed
649 650
    }
    else
651
    {
652 653 654
        // destroy popup if there is one
        delete p_intf->p_sys->p_popup_menu;
        p_intf->p_sys->p_popup_menu = NULL;
zorglub's avatar
zorglub committed
655 656 657
    }
}

658 659 660 661
/************************************************************************
 * Systray Menu                                                         *
 ************************************************************************/

662 663 664
void QVLCMenu::updateSystrayMenu( MainInterface *mi,
                                  intf_thread_t *p_intf,
                                  bool b_force_visible )
665 666
{
    POPUP_BOILERPLATE;
667 668

    /* Get the systray menu and clean it */
669 670
    QMenu *sysMenu = mi->getSysTrayMenu();
    sysMenu->clear();
671 672

    /* Hide / Show VLC and cone */
673
    if( mi->isVisible() || b_force_visible )
674
    {
675 676
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
                qtr("Hide VLC media player"), mi,
677
                SLOT( toggleUpdateSystrayMenu() ) );
678 679 680
    }
    else
    {
681 682
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
                qtr("Show VLC media player"), mi,
683
                SLOT( toggleUpdateSystrayMenu() ) );
684
    }
685

686 687
    sysMenu->addSeparator();
    POPUP_PLAY_ENTRIES( sysMenu );
688

689
    sysMenu->addSeparator();
690 691
    DP_SADD( sysMenu, qtr("&Open Media" ), "",
            ":/pixmaps/vlc_file-wide_16px.png", openFileDialog(), "" );
692 693
    DP_SADD( sysMenu, qtr("&Quit") , "", ":/pixmaps/vlc_quit_16px.png",
             quit(), "" );
694

695
    /* Set the menu */
696 697 698
    mi->getSysTray()->setContextMenu( sysMenu );
}

699 700
#undef PUSH_VAR
#undef PUSH_SEPARATOR
zorglub's avatar
zorglub committed
701

702

703 704 705
/*************************************************************************
 * Builders for automenus
 *************************************************************************/
zorglub's avatar
zorglub committed
706
QMenu * QVLCMenu::Populate( intf_thread_t *p_intf, QMenu *current,
707 708
        vector< const char *> & varnames,
        vector<int> & objects, bool append )
zorglub's avatar
zorglub committed
709 710 711 712
{
    QMenu *menu = current;
    if( !menu )
        menu = new QMenu();
713
    else if( !append )
zorglub's avatar
zorglub committed
714 715 716 717 718 719 720 721
        menu->clear();

    currentGroup = NULL;

    vlc_object_t *p_object;
    vlc_bool_t b_section_empty = VLC_FALSE;
    int i;

zorglub's avatar
zorglub committed
722
#define APPEND_EMPTY { QAction *action = menu->addAction( qtr("Empty" ) ); \
723
    action->setEnabled( false ); }
zorglub's avatar
zorglub committed
724

725
    for( i = 0; i < (int)objects.size() ; i++ )
zorglub's avatar
zorglub committed
726
    {
727
        if( !varnames[i] || !*varnames[i] )
zorglub's avatar
zorglub committed
728 729 730 731 732 733 734 735
        {
            if( b_section_empty )
                APPEND_EMPTY;
            menu->addSeparator();
            b_section_empty = VLC_TRUE;
            continue;
        }

736
        if( objects[i] == 0  )
zorglub's avatar
zorglub committed
737 738
        {
            /// \bug What is this ?
739
            // Append( menu, varnames[i], NULL );
zorglub's avatar
zorglub committed
740 741 742 743 744
            b_section_empty = VLC_FALSE;
            continue;
        }

        p_object = (vlc_object_t *)vlc_object_get( p_intf,
745
                objects[i] );
zorglub's avatar
zorglub committed
746 747 748
        if( p_object == NULL ) continue;

        b_section_empty = VLC_FALSE;
749 750 751 752 753
        /* Ugly specific stuff */
        if( strstr(varnames[i], "intf-add" ) )
            CreateItem( menu, varnames[i], p_object, false );
        else
            CreateItem( menu, varnames[i], p_object, true );
zorglub's avatar
zorglub committed
754 755 756 757 758 759 760
        vlc_object_release( p_object );
    }

    /* Special case for empty menus */
    if( menu->actions().size() == 0 || b_section_empty )
        APPEND_EMPTY

761
            return menu;
zorglub's avatar
zorglub committed
762 763 764 765 766 767 768
}

/*****************************************************************************
 * Private methods.
 *****************************************************************************/

static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object,
769
        bool b_root = TRUE )
zorglub's avatar
zorglub committed
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
{
    vlc_value_t val, val_list;
    int i_type, i_result, i;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    /* Check if we want to display the variable */
    if( !(i_type & VLC_VAR_HASCHOICE) ) return FALSE;

    var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
    if( val.i_int == 0 ) return TRUE;

    if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE )
    {
zorglub's avatar
zorglub committed
785
        /* Very evil hack ! intf-switch can have only one value */
zorglub's avatar
zorglub committed
786 787 788 789 790 791 792 793 794 795 796 797 798 799
        if( !strcmp( psz_var, "intf-switch" ) ) return FALSE;
        if( val.i_int == 1 && b_root ) return TRUE;
        else return FALSE;
    }

    /* Check children variables in case of VLC_VAR_VARIABLE */
    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
    {
        return TRUE;
    }

    for( i = 0, i_result = TRUE; i < val_list.p_list->i_count; i++ )
    {
        if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
800
                    p_object, FALSE ) )
zorglub's avatar
zorglub committed
801 802 803 804 805 806 807 808 809 810 811 812 813
        {
            i_result = FALSE;
            break;
        }
    }

    /* clean up everything */
    var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, NULL );

    return i_result;
}

void QVLCMenu::CreateItem( QMenu *menu, const char *psz_var,
814
        vlc_object_t *p_object, bool b_submenu )
zorglub's avatar
zorglub committed
815 816 817 818 819 820 821 822 823
{
    vlc_value_t val, text;
    int i_type;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    switch( i_type & VLC_VAR_TYPE )
    {
824 825 826 827 828 829 830 831 832 833
        case VLC_VAR_VOID:
        case VLC_VAR_BOOL:
        case VLC_VAR_VARIABLE:
        case VLC_VAR_STRING:
        case VLC_VAR_INTEGER:
        case VLC_VAR_FLOAT:
            break;
        default:
            /* Variable doesn't exist or isn't handled */
            return;
zorglub's avatar
zorglub committed
834 835 836 837 838 839 840 841 842 843 844
    }

    /* Make sure we want to display the variable */
    if( IsMenuEmpty( psz_var, p_object ) )  return;

    /* Get the descriptive name of the variable */
    var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );

    if( i_type & VLC_VAR_HASCHOICE )
    {
        /* Append choices menu */
845 846 847
        if( b_submenu )
        {
            QMenu *submenu = new QMenu();
zorglub's avatar
Qt4:  
zorglub committed
848
            submenu->setTitle( qfu( text.psz_string ?
849
                        text.psz_string : psz_var ) );
850 851 852 853 854
            if( CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0)
                menu->addMenu( submenu );
        }
        else
            CreateChoicesMenu( menu, psz_var, p_object, true );
855
        FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
856 857 858
        return;
    }

859
#define TEXT_OR_VAR qfu ( text.psz_string ? text.psz_string : psz_var )
zorglub's avatar
zorglub committed
860 861 862

    switch( i_type & VLC_VAR_TYPE )
    {
863 864 865 866 867 868 869 870 871 872 873 874
        case VLC_VAR_VOID:
            var_Get( p_object, psz_var, &val );
            CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_NORMAL,
                    p_object->i_object_id, val, i_type );
            break;

        case VLC_VAR_BOOL:
            var_Get( p_object, psz_var, &val );
            val.b_bool = !val.b_bool;
            CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
                    p_object->i_object_id, val, i_type, !val.b_bool );
            break;
zorglub's avatar
zorglub committed
875
    }
876
    FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
877 878 879
}


zorglub's avatar
zorglub committed
880
int QVLCMenu::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
881
        vlc_object_t *p_object, bool b_root )
zorglub's avatar
zorglub committed
882 883 884 885 886 887 888 889
{
    vlc_value_t val, val_list, text_list;
    int i_type, i;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    /* Make sure we want to display the variable */
890
    if( IsMenuEmpty( psz_var, p_object, b_root ) ) return VLC_EGENERIC;
zorglub's avatar
zorglub committed
891 892 893

    switch( i_type & VLC_VAR_TYPE )
    {
894 895 896 897 898 899 900 901 902 903
        case VLC_VAR_VOID:
        case VLC_VAR_BOOL:
        case VLC_VAR_VARIABLE:
        case VLC_VAR_STRING:
        case VLC_VAR_INTEGER:
        case VLC_VAR_FLOAT:
            break;
        default:
            /* Variable doesn't exist or isn't handled */
            return VLC_EGENERIC;
zorglub's avatar
zorglub committed
904 905 906
    }

    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
907
                &val_list, &text_list ) < 0 )
zorglub's avatar
zorglub committed
908
    {
909
        return VLC_EGENERIC;
zorglub's avatar
zorglub committed
910 911
    }
#define NORMAL_OR_RADIO i_type & VLC_VAR_ISCOMMAND ? ITEM_NORMAL: ITEM_RADIO
zorglub's avatar
Qt4:  
zorglub committed
912
#define NOTCOMMAND !(i_type & VLC_VAR_ISCOMMAND)
zorglub's avatar
zorglub committed
913 914 915 916 917 918 919
#define CURVAL val_list.p_list->p_values[i]
#define CURTEXT text_list.p_list->p_values[i].psz_string

    for( i = 0; i < val_list.p_list->i_count; i++ )
    {
        vlc_value_t another_val;
        QString menutext;
920
        QMenu *subsubmenu = new QMenu();
zorglub's avatar
zorglub committed
921 922 923

        switch( i_type & VLC_VAR_TYPE )
        {
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
            case VLC_VAR_VARIABLE:
                CreateChoicesMenu( subsubmenu, CURVAL.psz_string, p_object, false );
                subsubmenu->setTitle( qfu( CURTEXT ? CURTEXT :CURVAL.psz_string ) );
                submenu->addMenu( subsubmenu );
                break;

            case VLC_VAR_STRING:
                var_Get( p_object, psz_var, &val );
                another_val.psz_string = strdup( CURVAL.psz_string );
                menutext = qfu( CURTEXT ? CURTEXT : another_val.psz_string );
                CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
                        p_object->i_object_id, another_val, i_type,
                        NOTCOMMAND && val.psz_string &&
                        !strcmp( val.psz_string, CURVAL.psz_string ) );

                if( val.psz_string ) free( val.psz_string );
                break;

            case VLC_VAR_INTEGER:
                var_Get( p_object, psz_var, &val );
                if( CURTEXT ) menutext = qfu( CURTEXT );
                else menutext.sprintf( "%d", CURVAL.i_int);
                CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
                        p_object->i_object_id, CURVAL, i_type,
                        NOTCOMMAND && CURVAL.i_int == val.i_int );
                break;

            case VLC_VAR_FLOAT:
                var_Get( p_object, psz_var, &val );
                if( CURTEXT ) menutext = qfu( CURTEXT );
                else menutext.sprintf( "%.2f", CURVAL.f_float );
                Crea