menus.cpp 32 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
 *
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
7
 * Authors: Clément 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.
 *****************************************************************************/

zorglub's avatar
zorglub committed
25
#include <vlc_intf_strings.h>
zorglub's avatar
zorglub committed
26

zorglub's avatar
zorglub committed
27
#include "main_interface.hpp"
zorglub's avatar
zorglub committed
28 29 30 31
#include "menus.hpp"
#include "dialogs_provider.hpp"
#include "input_manager.hpp"

32 33 34 35 36 37 38
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QActionGroup>
#include <QSignalMapper>
#include <QSystemTrayIcon>

zorglub's avatar
zorglub committed
39 40 41 42 43 44 45 46 47
enum
{
    ITEM_NORMAL,
    ITEM_CHECK,
    ITEM_RADIO
};

static QActionGroup *currentGroup;

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

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

#define PUSH_SEPARATOR if( objects.size() != i_last_separator ) { \
97 98
    objects.push_back( 0 ); varnames.push_back( "" ); \
    i_last_separator = objects.size(); }
zorglub's avatar
zorglub committed
99 100

static int InputAutoMenuBuilder( vlc_object_t *p_object,
101 102
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
103 104 105 106 107 108 109 110 111 112
{
    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
113
static int VideoAutoMenuBuilder( vlc_object_t *p_object,
114 115
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
116 117 118 119 120 121 122 123 124 125 126
{
    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,
127 128
            VLC_OBJECT_DECODER,
            FIND_PARENT );
zorglub's avatar
zorglub committed
129 130
    if( p_dec_obj != NULL )
    {
131
        vlc_object_t *p_object = p_dec_obj;
zorglub's avatar
zorglub committed
132 133 134 135 136 137 138
        PUSH_VAR( "ffmpeg-pp-q" );
        vlc_object_release( p_dec_obj );
    }
    return VLC_SUCCESS;
}

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

149 150
/*****************************************************************************
 * All normal menus
151
 * Simple Code
152 153 154 155 156 157 158 159
 *****************************************************************************/

#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
160
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
161 162
    THEDP->menusUpdateMapper->setMapping( menu, f ); }

163 164 165
/**
 * Main Menu Bar Creation
 **/
zorglub's avatar
zorglub committed
166
void QVLCMenu::createMenuBar( MainInterface *mi, intf_thread_t *p_intf,
167 168
        bool playlist, bool adv_controls_enabled,
        bool visual_selector_enabled )
zorglub's avatar
Qt4:  
zorglub committed
169
{
zorglub's avatar
zorglub committed
170
    QMenuBar *bar = mi->menuBar();
171
    BAR_ADD( FileMenu(), qtr("&Media") );
zorglub's avatar
zorglub committed
172 173
    if( playlist )
    {
174
        BAR_ADD( PlaylistMenu( mi,p_intf ), qtr("&Playlist" ) );
zorglub's avatar
zorglub committed
175
    }
176
    BAR_ADD( ToolsMenu( p_intf, mi, adv_controls_enabled,
177
                visual_selector_enabled ), qtr("&Tools") );
178 179 180
    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 );
181

182
    BAR_ADD( HelpMenu(), qtr("&Help" ) );
183
}
184 185 186 187 188

/**
 * Media (File) Menu
 * Opening, streaming and quit
 **/
189 190 191
QMenu *QVLCMenu::FileMenu()
{
    QMenu *menu = new QMenu();
192 193
    DP_SADD( menu, qtr("Open &File..." ), "",
            ":/pixmaps/vlc_file-asym_16px.png", openFileDialog(), "Ctrl+O" );
194 195 196 197 198 199 200 201 202 203

    /* 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 */

204 205
    DP_SADD( menu, qtr("Open &Disc..." ), "", ":/pixmaps/vlc_disc_16px.png",
             openDiscDialog(), "Ctrl+D" );
206 207 208 209
    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(),
210
            "Ctrl+C" );
211
    menu->addSeparator();
212 213
    DP_SADD( menu, qtr("&Streaming..."), "", ":/pixmaps/vlc_stream_16px.png",
            openThenStreamingDialogs(), "Ctrl+S" );
214 215
    DP_SADD( menu, qtr("Conve&rt / Save..."), "", "",
            openThenTranscodingDialogs(), "Ctrl+R" );
216
    menu->addSeparator();
217
    DP_SADD( menu, qtr("&Quit") , "", ":/pixmaps/vlc_quit_16px.png", quit(),
218
            "Ctrl+Q");
219 220 221
    return menu;
}

222
/* Playlist Menu, undocked when playlist is undocked */
zorglub's avatar
zorglub committed
223
QMenu *QVLCMenu::PlaylistMenu( MainInterface *mi, intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
224 225 226
{
    QMenu *menu = new QMenu();
    menu->addMenu( SDMenu( p_intf ) );
227
    menu->addAction ( QIcon(":/pixmaps/vlc_playlist_16px.png"),
228
                      qtr( "Show Playlist"), mi, SLOT( togglePlaylist() ) );
zorglub's avatar
zorglub committed
229 230
    menu->addSeparator();

231 232
    DP_SADD( menu, qtr( I_PL_LOAD ), "", "", openPlaylist(), "Ctrl+X" );
    DP_SADD( menu, qtr( I_PL_SAVE ), "", "", savePlaylist(), "Ctrl+Y" );
zorglub's avatar
zorglub committed
233 234
    menu->addSeparator();
    menu->addAction( qtr("Undock from interface"), mi,
235
            SLOT( undockPlaylist() ), qtr("Ctrl+U") );
zorglub's avatar
zorglub committed
236 237 238
    return menu;
}

239 240
/**
 * Tools/View Menu
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
241
 * This is kept in the same menu for now, but could change if it gets much
242 243
 * longer.
 **/
zorglub's avatar
zorglub committed
244
QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf, MainInterface *mi,
245 246
        bool adv_controls_enabled,
        bool visual_selector_enabled, bool with_intf )
247 248 249 250 251
{
    QMenu *menu = new QMenu();
    if( with_intf )
    {
        QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
zorglub's avatar
zorglub committed
252
        intfmenu->setTitle( qtr("Interfaces" ) );
253 254 255
        menu->addMenu( intfmenu );
        menu->addSeparator();
    }
256
    DP_SADD( menu, qtr( I_MENU_MSG ), "", ":/pixmaps/vlc_messages_16px.png",
257
             messagesDialog(), "Ctrl+M" );
258 259
    DP_SADD( menu, qtr( I_MENU_INFO ) , "", "", mediaInfoDialog(), "Ctrl+J" );
    DP_SADD( menu, qtr( I_MENU_CODECINFO ) , "", ":/pixmaps/vlc_info_16px.png",
260
             mediaCodecDialog(), "Ctrl+I" );
261
    DP_SADD( menu, qtr( I_MENU_GOTOTIME ), "","", gotoTimeDialog(), "Ctrl+T" );
262
#if 0 /* Not Implemented yet */
263 264
    DP_SADD( menu, qtr( I_MENU_BOOKMARK ), "","", bookmarksDialog(), "Ctrl+B" );
    DP_SADD( menu, qtr( I_MENU_VLM ), "","", vlmDialog(), "Ctrl+V" );
265
#endif
266

267
    menu->addSeparator();
zorglub's avatar
zorglub committed
268 269 270
    if( mi )
    {
        QAction *adv = menu->addAction( qtr("Advanced controls" ),
271
                mi, SLOT( toggleAdvanced() ) );
zorglub's avatar
zorglub committed
272 273
        adv->setCheckable( true );
        if( adv_controls_enabled ) adv->setChecked( true );
274

275 276
        menu->addAction( qtr( "Hide Menus..." ), mi, SLOT( toggleMenus() ),
                qtr( "Ctrl+H") );
277
        menu->addSeparator();
278

279
#if 0 /* For Visualisations. Not yet working */
280
        adv = menu->addAction( qtr("Visualizations selector" ),
281
                mi, SLOT( visual() ) );
282 283
        adv->setCheckable( true );
        if( visual_selector_enabled ) adv->setChecked( true );
284
#endif
285
        menu->addAction ( QIcon(":/pixmaps/vlc_playlist_16px.png"),
286
                          qtr( "Playlist"), mi, SLOT( togglePlaylist() ),
287
                          qtr( "Ctrl+L") );
zorglub's avatar
zorglub committed
288
    }
289 290
    DP_SADD( menu, qtr( I_MENU_EXT ), "", ":/pixmaps/vlc_settings_16px.png",
                 extendedDialog() ,  "Ctrl+E"  );
291

292
    menu->addSeparator();
293 294
    DP_SADD( menu, qtr("Preferences"), "", ":/pixmaps/vlc_preferences_16px.png",
             prefsDialog(), "Ctrl+P" );
295 296 297
    return menu;
}

298 299 300
/**
 * Interface Sub-Menu, to list extras interface and skins
 **/
301 302 303 304 305 306 307
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
308

309
    QMenu *menu = Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
310 311 312 313

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

zorglub's avatar
zorglub committed
318
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() );
319 320 321 322
    THEDP->menusUpdateMapper->setMapping( menu, 4 );
    return menu;
}

323 324 325
/**
 * Main Audio Menu
 */
326 327 328 329 330 331
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,
332
            VLC_OBJECT_INPUT, FIND_ANYWHERE );
333 334 335 336 337 338 339
    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,
340
            FIND_ANYWHERE );
341 342 343 344 345 346 347 348
    if( p_object )
    {
        AudioAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}

349 350 351 352
/**
 * Main Video Menu
 * Subtitles are part of Video.
 **/
353
QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
zorglub's avatar
zorglub committed
354 355
{
    vlc_object_t *p_object;
356 357 358 359
    vector<int> objects;
    vector<const char *> varnames;

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
360
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
361 362
    if( p_object != NULL )
    {
363 364
        PUSH_VAR( "video-es" );
        PUSH_VAR( "spu-es" );
zorglub's avatar
zorglub committed
365 366
        vlc_object_release( p_object );
    }
367 368

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
369
            FIND_ANYWHERE );
370 371 372 373 374 375
    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
376 377
}

378 379 380 381
/**
 * Navigation Menu
 * For DVD, MP4, MOV and other chapter based format
 **/
382 383 384 385 386
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
387

388 389
    /* FIXME */
    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
390
            FIND_ANYWHERE );
391 392 393 394 395 396 397 398 399
    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
400

401 402 403
/**
 * Service Discovery Menu
 **/
zorglub's avatar
zorglub committed
404 405 406
QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
407
    menu->setTitle( qtr( I_PL_SD ) );
zorglub's avatar
zorglub committed
408
    vlc_list_t *p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
409
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
410 411 412 413
    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 ;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
414
        if( module_IsCapable( p_parser, "services_discovery" ) )
zorglub's avatar
zorglub committed
415 416 417 418 419
            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;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
420 421 422
        if( !module_IsCapable( p_parser, "services_discovery" ) )
            continue;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
423
        QAction *a = new QAction( qfu( module_GetLongName( p_parser ) ), menu );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
424 425 426 427 428 429
        a->setCheckable( true );
        /* hack to handle submodules properly */
        int i = -1;
        while( p_parser->pp_shortcuts[++i] != NULL );
        i--;
        if( playlist_IsServicesDiscoveryLoaded( THEPL,
430 431
                    i>=0?p_parser->pp_shortcuts[i]
                    : module_GetObjName( p_parser ) ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
432 433 434
            a->setChecked( true );
        CONNECT( a , triggered(), THEDP->SDMapper, map() );
        THEDP->SDMapper->setMapping( a, i>=0? p_parser->pp_shortcuts[i] :
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
435
                                              module_GetObjName( p_parser ) );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
436
        menu->addAction( a );
437 438 439 440 441 442 443 444

        if( !strcmp( p_parser->psz_object_name, "podcast" ) )
        {
            QAction *b = new QAction( qfu( "Configure podcasts..." ), menu );
            //b->setEnabled( a->isChecked() );
            menu->addAction( b );
            CONNECT( b, triggered(), THEDP, podcastConfigureDialog() );
        }
zorglub's avatar
zorglub committed
445 446 447 448
    }
    vlc_list_release( p_list );
    return menu;
}
449 450 451
/**
 * Help/About Menu
**/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
452 453 454
QMenu *QVLCMenu::HelpMenu()
{
    QMenu *menu = new QMenu();
455 456
    DP_SADD( menu, qtr("Help") , "", ":/pixmaps/vlc_help_16px.png",
             helpDialog(), "F1" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
457
    menu->addSeparator();
458
    DP_SADD( menu, qtr( I_MENU_ABOUT ), "", "", aboutDialog(), "Ctrl+F1");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
459 460 461 462
    return menu;
}


463
/*****************************************************************************
464
 * Popup menus - Right Click menus                                           *
465
 *****************************************************************************/
zorglub's avatar
zorglub committed
466 467
#define POPUP_BOILERPLATE \
    unsigned int i_last_separator = 0; \
468 469 470 471 472 473 474 475 476
    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
477
    p_intf->p_sys->p_popup_menu = NULL; \
478
    i_last_separator = 0;
zorglub's avatar
zorglub committed
479

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

501
#define POPUP_STATIC_ENTRIES( menu ) \
502
    QMenu *intfmenu = InterfacesMenu( p_intf, NULL ); \
zorglub's avatar
zorglub committed
503
    intfmenu->setTitle( qtr("Interfaces" ) ); \
504 505
    menu->addMenu( intfmenu ); \
    \
506
    QMenu *toolsmenu = ToolsMenu( p_intf, NULL, false, false, false ); \
zorglub's avatar
zorglub committed
507
    toolsmenu->setTitle( qtr("Tools" ) ); \
508
    menu->addMenu( toolsmenu ); \
509 510 511 512 513 514 515 516 517 518 519 520 521 522
    \
    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 ); \
    \
523
    DP_SADD( menu, qtr("Quit"), "", "", quit() , "Ctrl+Q" );
zorglub's avatar
Qt4:  
zorglub committed
524

525
/* Video Tracks and Subtitles tracks */
526
void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
527 528 529 530 531
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
532 533 534 535
        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
536
        vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
537
                VLC_OBJECT_VOUT, FIND_CHILD );
zorglub's avatar
zorglub committed
538 539
        if( p_vout )
        {
540
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
541 542 543 544
            vlc_object_release( p_vout );
        }
        vlc_object_release( p_input );
    }
545
    CREATE_POPUP;
zorglub's avatar
zorglub committed
546 547
}

548
/* Audio Tracks */
549
void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
550 551 552 553 554
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
555 556
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
557
        vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
558
                VLC_OBJECT_AOUT, FIND_ANYWHERE );
zorglub's avatar
zorglub committed
559 560
        if( p_aout )
        {
561
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
562 563 564 565
            vlc_object_release( p_aout );
        }
        vlc_object_release( p_input );
    }
566
    CREATE_POPUP;
zorglub's avatar
zorglub committed
567 568
}

569
/* Navigation stuff, and general menus (open) */
570
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
571
{
572
    vlc_value_t val;
zorglub's avatar
zorglub committed
573
    POPUP_BOILERPLATE;
574

zorglub's avatar
zorglub committed
575 576 577
    if( p_input )
    {
        vlc_object_yield( p_input );
578 579
        varnames.push_back( "audio-es" );
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
580 581 582
        PUSH_SEPARATOR;
    }

583 584
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
585

586
    menu->addSeparator();
587 588 589 590
    POPUP_PLAY_ENTRIES( menu );

    menu->addSeparator();
    POPUP_STATIC_ENTRIES( menu );
zorglub's avatar
zorglub committed
591

592 593
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
594 595 596
    p_intf->p_sys->p_popup_menu = NULL;
}

597
/* Main Menu that sticks everything together  */
damienf's avatar
damienf committed
598
void QVLCMenu::PopupMenu( intf_thread_t *p_intf, bool show )
zorglub's avatar
zorglub committed
599
{
damienf's avatar
damienf committed
600
    if( show )
zorglub's avatar
zorglub committed
601
    {
602
        // create a  popup if there is none
damienf's avatar
damienf committed
603
        if( ! p_intf->p_sys->p_popup_menu )
604
        {
605 606 607 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
            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 );
                }
            }
636

637 638 639
            QMenu *menu = new QMenu();
            Populate( p_intf, menu, varnames, objects );
            menu->addSeparator();
640 641 642
            POPUP_PLAY_ENTRIES( menu );
            menu->addSeparator();
            POPUP_STATIC_ENTRIES( menu );
643

644 645 646
            p_intf->p_sys->p_popup_menu = menu;
        }
        p_intf->p_sys->p_popup_menu->popup( QCursor::pos() );
damienf's avatar
damienf committed
647 648
    }
    else
649
    {
650 651 652
        // 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
653 654 655
    }
}

656 657 658 659
/************************************************************************
 * Systray Menu                                                         *
 ************************************************************************/

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

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

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

684 685
    sysMenu->addSeparator();
    POPUP_PLAY_ENTRIES( sysMenu );
686

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

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

697 698
#undef PUSH_VAR
#undef PUSH_SEPARATOR
zorglub's avatar
zorglub committed
699

700

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

    currentGroup = NULL;

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

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

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

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

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

        b_section_empty = VLC_FALSE;
747 748 749 750 751
        /* 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
752 753 754 755 756 757 758
        vlc_object_release( p_object );
    }

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

759
            return menu;
zorglub's avatar
zorglub committed
760 761 762 763 764 765 766
}

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

static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object,
767
        bool b_root = TRUE )
zorglub's avatar
zorglub committed
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
{
    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
783
        /* Very evil hack ! intf-switch can have only one value */
zorglub's avatar
zorglub committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797
        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,
798
                    p_object, FALSE ) )
zorglub's avatar
zorglub committed
799 800 801 802 803 804 805 806 807 808 809 810 811
        {
            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,
812
        vlc_object_t *p_object, bool b_submenu )
zorglub's avatar
zorglub committed
813 814 815 816 817 818 819 820 821
{
    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 )
    {
822 823 824 825 826 827 828 829 830 831
        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
832 833 834 835 836 837 838 839 840 841 842
    }

    /* 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 */
843 844 845
        if( b_submenu )
        {
            QMenu *submenu = new QMenu();
zorglub's avatar
Qt4:  
zorglub committed
846
            submenu->setTitle( qfu( text.psz_string ?
847
                        text.psz_string : psz_var ) );
848 849 850 851 852
            if( CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0)
                menu->addMenu( submenu );
        }
        else
            CreateChoicesMenu( menu, psz_var, p_object, true );
853
        FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
854 855 856
        return;
    }

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

    switch( i_type & VLC_VAR_TYPE )
    {
861 862 863 864 865 866 867 868 869 870 871 872
        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
873
    }
874
    FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
875 876 877
}


zorglub's avatar
zorglub committed
878
int QVLCMenu::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
879
        vlc_object_t *p_object, bool b_root )
zorglub's avatar
zorglub committed
880 881 882 883 884 885 886 887
{
    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 */
888
    if( IsMenuEmpty( psz_var, p_object, b_root ) ) return VLC_EGENERIC;
zorglub's avatar
zorglub committed
889 890 891

    switch( i_type & VLC_VAR_TYPE )
    {
892 893 894 895 896 897 898 899 900 901
        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
902 903 904
    }

    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
905
                &val_list, &text_list ) < 0 )
zorglub's avatar
zorglub committed
906
    {
907
        return VLC_EGENERIC;
zorglub's avatar
zorglub committed
908 909
    }
#define NORMAL_OR_RADIO i_type & VLC_VAR_ISCOMMAND ? ITEM_NORMAL: ITEM_RADIO
zorglub's avatar
Qt4:  
zorglub committed
910
#define NOTCOMMAND !(i_type & VLC_VAR_ISCOMMAND)
zorglub's avatar
zorglub committed
911 912 913 914 915 916 917
#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