menus.cpp 31.7 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
    DP_SADD( menu, qtr("Open &Disc..." ), "", "", openDiscDialog(), "Ctrl+D" );
222 223 224 225
    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(),
226
            "Ctrl+C" );
227
    menu->addSeparator();
228 229
    DP_SADD( menu, qtr("&Streaming..."), "", ":/pixmaps/vlc_stream_16px.png",
            openThenStreamingDialogs(), "Ctrl+S" );
230 231
    DP_SADD( menu, qtr("Conve&rt / Save..."), "", "",
            openThenTranscodingDialogs(), "Ctrl+R" );
232
    menu->addSeparator();
233
    DP_SADD( menu, qtr("&Quit") , "", ":/pixmaps/vlc_quit_16px.png", quit(),
234
            "Ctrl+Q");
235 236 237
    return menu;
}

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

245 246
    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
247 248
    menu->addSeparator();
    menu->addAction( qtr("Undock from interface"), mi,
249
            SLOT( undockPlaylist() ), qtr("Ctrl+U") );
zorglub's avatar
zorglub committed
250 251 252
    return menu;
}

253 254 255 256 257
/**
 * 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
258
QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf, MainInterface *mi,
259 260
        bool adv_controls_enabled,
        bool visual_selector_enabled, bool with_intf )
261 262 263 264 265
{
    QMenu *menu = new QMenu();
    if( with_intf )
    {
        QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
zorglub's avatar
zorglub committed
266
        intfmenu->setTitle( qtr("Interfaces" ) );
267 268 269
        menu->addMenu( intfmenu );
        menu->addSeparator();
    }
270
    DP_SADD( menu, qtr( I_MENU_MSG ), "", ":/pixmaps/vlc_messages_16px.png",
271
             messagesDialog(), "Ctrl+M" );
272 273
    DP_SADD( menu, qtr( I_MENU_INFO ) , "", "", mediaInfoDialog(), "Ctrl+J" );
    DP_SADD( menu, qtr( I_MENU_CODECINFO ) , "", ":/pixmaps/vlc_info_16px.png",
274
             mediaCodecDialog(), "Ctrl+I" );
275
    DP_SADD( menu, qtr( I_MENU_GOTOTIME ), "","", gotoTimeDialog(), "Ctrl+T" );
276
#if 0 /* Not Implemented yet */
277 278
    DP_SADD( menu, qtr( I_MENU_BOOKMARK ), "","", bookmarksDialog(), "Ctrl+B" );
    DP_SADD( menu, qtr( I_MENU_VLM ), "","", vlmDialog(), "Ctrl+V" );
279
#endif
280

281
    menu->addSeparator();
zorglub's avatar
zorglub committed
282 283 284
    if( mi )
    {
        QAction *adv = menu->addAction( qtr("Advanced controls" ),
285
                mi, SLOT( advanced() ) );
zorglub's avatar
zorglub committed
286 287
        adv->setCheckable( true );
        if( adv_controls_enabled ) adv->setChecked( true );
288
#if 0 /* For Visualisations. Not yet working */
289
        adv = menu->addAction( qtr("Visualizations selector" ),
290
                mi, SLOT( visual() ) );
291 292
        adv->setCheckable( true );
        if( visual_selector_enabled ) adv->setChecked( true );
293
#endif
294
        menu->addAction ( qtr( "Playlist"), mi, SLOT( playlist() ) );
zorglub's avatar
zorglub committed
295
    }
296 297
    DP_SADD( menu, qtr( I_MENU_EXT ), "","",extendedDialog(), "Ctrl+E" );
    DP_SADD( menu, qtr( "Hide Menus..." ), "","",hideMenus(), "Ctrl+H" );
298

299
    menu->addSeparator();
300 301
    DP_SADD( menu, qtr("Preferences"), "", ":/pixmaps/vlc_preferences_16px.png",
             prefsDialog(), "Ctrl+P" );
302 303 304
    return menu;
}

305 306 307
/**
 * Interface Sub-Menu, to list extras interface and skins
 **/
308 309 310 311 312 313 314
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
315

316
    QMenu *menu = Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
317 318 319 320

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

zorglub's avatar
zorglub committed
325
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() );
326 327 328 329
    THEDP->menusUpdateMapper->setMapping( menu, 4 );
    return menu;
}

330 331 332
/**
 * Main Audio Menu
 */
333 334 335 336 337 338
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,
339
            VLC_OBJECT_INPUT, FIND_ANYWHERE );
340 341 342 343 344 345 346
    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,
347
            FIND_ANYWHERE );
348 349 350 351 352 353 354 355
    if( p_object )
    {
        AudioAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}

356 357 358 359
/**
 * Main Video Menu
 * Subtitles are part of Video.
 **/
360
QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
zorglub's avatar
zorglub committed
361 362
{
    vlc_object_t *p_object;
363 364 365 366
    vector<int> objects;
    vector<const char *> varnames;

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
367
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
368 369
    if( p_object != NULL )
    {
370 371
        PUSH_VAR( "video-es" );
        PUSH_VAR( "spu-es" );
zorglub's avatar
zorglub committed
372 373
        vlc_object_release( p_object );
    }
374 375

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
376
            FIND_ANYWHERE );
377 378 379 380 381 382
    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
383 384
}

385 386 387 388
/**
 * Navigation Menu
 * For DVD, MP4, MOV and other chapter based format
 **/
389 390 391 392 393
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
394

395 396
    /* FIXME */
    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
397
            FIND_ANYWHERE );
398 399 400 401 402 403 404 405 406
    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
407

408 409 410
/**
 * Service Discovery Menu
 **/
zorglub's avatar
zorglub committed
411 412 413
QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
414
    menu->setTitle( qtr( I_PL_SD ) );
zorglub's avatar
zorglub committed
415
    vlc_list_t *p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
416
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
    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,
436 437
                        i>=0?p_parser->pp_shortcuts[i]
                        : p_parser->psz_object_name ) )
zorglub's avatar
zorglub committed
438 439 440 441 442
            {
                a->setChecked( true );
            }
            CONNECT( a , triggered(), THEDP->SDMapper, map() );
            THEDP->SDMapper->setMapping( a, i>=0? p_parser->pp_shortcuts[i] :
443
                    p_parser->psz_object_name );
zorglub's avatar
zorglub committed
444 445 446 447 448 449
            menu->addAction( a );
        }
    }
    vlc_list_release( p_list );
    return menu;
}
450 451 452
/**
 * Help/About Menu
**/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
453 454 455
QMenu *QVLCMenu::HelpMenu()
{
    QMenu *menu = new QMenu();
456 457
    DP_SADD( menu, qtr("Help") , "", ":/pixmaps/vlc_help_16px.png",
             helpDialog(), "F1" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
458
    menu->addSeparator();
459
    DP_SADD( menu, qtr( I_MENU_ABOUT ), "", "", aboutDialog(), "Ctrl+F1");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
460 461 462 463
    return menu;
}


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

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

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

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

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

573
/* Navigation stuff, and general menus (open) */
574
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
575 576 577 578 579
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
580 581
        varnames.push_back( "audio-es" );
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
582 583 584
        PUSH_SEPARATOR;
    }

585 586 587
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
    menu->addSeparator();
zorglub's avatar
zorglub committed
588 589
    POPUP_STATIC_ENTRIES;

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

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

635 636 637 638
            QMenu *menu = new QMenu();
            Populate( p_intf, menu, varnames, objects );
            menu->addSeparator();
            POPUP_STATIC_ENTRIES;
639

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

652 653 654 655
/************************************************************************
 * Systray Menu                                                         *
 ************************************************************************/

656 657 658
void QVLCMenu::updateSystrayMenu( MainInterface *mi,
                                  intf_thread_t *p_intf,
                                  bool b_force_visible )
659 660
{
    POPUP_BOILERPLATE;
661 662

    /* Get the systray menu and clean it */
663 664
    QMenu *sysMenu = mi->getSysTrayMenu();
    sysMenu->clear();
665 666

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

680 681
    sysMenu->addSeparator();
    POPUP_PLAY_ENTRIES( sysMenu );
682

683
    sysMenu->addSeparator();
684 685
    DP_SADD( sysMenu, qtr("&Open Media" ), "",
            ":/pixmaps/vlc_file-wide_16px.png", openFileDialog(), "" );
686 687
    DP_SADD( sysMenu, qtr("&Quit") , "", ":/pixmaps/vlc_quit_16px.png",
             quit(), "" );
688

689
    /* Set the menu */
690 691 692
    mi->getSysTray()->setContextMenu( sysMenu );
}

693 694
#undef PUSH_VAR
#undef PUSH_SEPARATOR
zorglub's avatar
zorglub committed
695

696

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

    currentGroup = NULL;

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

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

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

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

        p_object = (vlc_object_t *)vlc_object_get( p_intf,
739
                objects[i] );
zorglub's avatar
zorglub committed
740 741 742
        if( p_object == NULL ) continue;

        b_section_empty = VLC_FALSE;
743 744 745 746 747
        /* 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
748 749 750 751 752 753 754
        vlc_object_release( p_object );
    }

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

755
            return menu;
zorglub's avatar
zorglub committed
756 757 758 759 760 761 762
}

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

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

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

853
#define TEXT_OR_VAR qfu ( text.psz_string ? text.psz_string : psz_var )
zorglub's avatar
zorglub committed
854 855 856

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


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

    switch( i_type & VLC_VAR_TYPE )
    {
888 889 890 891 892 893 894 895 896 897
        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
898 899 900
    }

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

        switch( i_type & VLC_VAR_TYPE )
        {
918 919 920 921 922 923 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
            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 );
                CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
                        p_object->i_object_id, CURVAL, i_type,
                        NOTCOMMAND && CURVAL.f_float == val.f_float );
                break;

            default:
                break;
zorglub's avatar
zorglub committed
956 957
        }
    }
zorglub's avatar