menus.cpp 25.9 KB
Newer Older
zorglub's avatar
zorglub committed
1
2
3
/*****************************************************************************
 * menus.cpp : Qt menus
 *****************************************************************************
4
5
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
zorglub's avatar
zorglub committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Authors: Clment Stenac <zorglub@videolan.org>
 *
 * 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.
 *****************************************************************************/

#include <QMenu>
25
#include <QMenuBar>
zorglub's avatar
zorglub committed
26
27
28
29
#include <QAction>
#include <QActionGroup>
#include <QSignalMapper>

zorglub's avatar
zorglub committed
30
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"

zorglub's avatar
zorglub committed
36
37
38
39
40
41
42
43
44
enum
{
    ITEM_NORMAL,
    ITEM_CHECK,
    ITEM_RADIO
};

static QActionGroup *currentGroup;

45
46
47
// Add static entries to menus
#define DP_SADD( text, help, icon, slot ) { if( strlen(icon) > 0 ) { QAction *action = menu->addAction( text, THEDP, SLOT( slot ) ); action->setIcon(QIcon(icon));} else { menu->addAction( text, THEDP, SLOT( slot ) ); } }
#define MIM_SADD( text, help, icon, slot ) { if( strlen(icon) > 0 ) { QAction *action = menu->addAction( text, THEMIM, SLOT( slot ) ); action->setIcon(QIcon(icon));} else { menu->addAction( text, THEMIM, SLOT( slot ) ); } }
zorglub's avatar
Qt4:    
zorglub committed
48
#define PL_SADD
zorglub's avatar
zorglub committed
49
50

/*****************************************************************************
51
 * Definitions of variables for the dynamic menus
zorglub's avatar
zorglub committed
52
 *****************************************************************************/
53
54
55
56
57
58
#define PUSH_VAR( var ) varnames.push_back( var ); \
                        objects.push_back( p_object->i_object_id )

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

static int InputAutoMenuBuilder( vlc_object_t *p_object,
61
62
                                 vector<int> &objects,
                                 vector<const char *> &varnames )
zorglub's avatar
zorglub committed
63
64
65
66
67
68
69
70
71
72
{
    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
73
static int VideoAutoMenuBuilder( vlc_object_t *p_object,
74
75
                                 vector<int> &objects,
                                 vector<const char *> &varnames )
zorglub's avatar
zorglub committed
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
{
    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,
                                                 VLC_OBJECT_DECODER,
                                                 FIND_PARENT );
    if( p_dec_obj != NULL )
    {
91
        vlc_object_t *p_object = p_dec_obj;
zorglub's avatar
zorglub committed
92
93
94
95
96
97
98
        PUSH_VAR( "ffmpeg-pp-q" );
        vlc_object_release( p_dec_obj );
    }
    return VLC_SUCCESS;
}

static int AudioAutoMenuBuilder( vlc_object_t *p_object,
99
100
                                 vector<int> &objects,
                                 vector<const char *> &varnames )
zorglub's avatar
zorglub committed
101
102
103
104
105
106
107
108
{
    PUSH_VAR( "audio-device" );
    PUSH_VAR( "audio-channels" );
    PUSH_VAR( "visual" );
    PUSH_VAR( "equalizer" );
    return VLC_SUCCESS;
}

109
110
111
112
113
114
115
116
117
118
/*****************************************************************************
 * All normal menus
 *****************************************************************************/

#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
119
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
120
121
    THEDP->menusUpdateMapper->setMapping( menu, f ); }

zorglub's avatar
zorglub committed
122
void QVLCMenu::createMenuBar( MainInterface *mi, intf_thread_t *p_intf,
123
124
                              bool playlist, bool adv_controls_enabled,
                              bool visual_selector_enabled )
zorglub's avatar
Qt4:    
zorglub committed
125
{
zorglub's avatar
zorglub committed
126
    QMenuBar *bar = mi->menuBar();
zorglub's avatar
zorglub committed
127
    BAR_ADD( FileMenu(), qtr("Media") );
zorglub's avatar
zorglub committed
128
129
    if( playlist )
    {
zorglub's avatar
zorglub committed
130
        BAR_ADD( PlaylistMenu( mi,p_intf ), qtr("Playlist" ) );
zorglub's avatar
zorglub committed
131
    }
132
133
    BAR_ADD( ToolsMenu( p_intf, mi, adv_controls_enabled,
                        visual_selector_enabled ), qtr("Tools") );
zorglub's avatar
zorglub committed
134
135
136
    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 );
137

zorglub's avatar
zorglub committed
138
    //    BAR_ADD( HelpMenu(), qtr("Help" ) );
139
140
141
142
}
QMenu *QVLCMenu::FileMenu()
{
    QMenu *menu = new QMenu();
zorglub's avatar
zorglub committed
143
144
    DP_SADD( qtr("Quick &Open File...") , "", "", simpleOpenDialog() );
    DP_SADD( qtr("&Advanced Open..." ), "", "", openDialog() );
145
    menu->addSeparator();
zorglub's avatar
zorglub committed
146
    DP_SADD( qtr("Streaming..."), "", "", streamingDialog() );
147
    menu->addSeparator();
zorglub's avatar
zorglub committed
148
    DP_SADD( qtr("&Quit") , "", "", quit() );
149
150
151
    return menu;
}

zorglub's avatar
zorglub committed
152
QMenu *QVLCMenu::PlaylistMenu( MainInterface *mi, intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
153
154
155
156
157
158
159
{
    QMenu *menu = new QMenu();
    menu->addMenu( SDMenu( p_intf ) );
    menu->addSeparator();

    DP_SADD( qtr( "Open playlist file"), "", "", openPlaylist() );
//    DP_SADD( qtr( "Save playlist to file" ), "", "", savePlaylist() );
zorglub's avatar
zorglub committed
160
161
162
    menu->addSeparator();
    menu->addAction( qtr("Undock from interface"), mi,
                     SLOT( undockPlaylist() ) );
zorglub's avatar
zorglub committed
163
164
165
    return menu;
}

zorglub's avatar
zorglub committed
166
QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf, MainInterface *mi,
167
168
                            bool adv_controls_enabled,
                            bool visual_selector_enabled, bool with_intf )
169
170
171
172
173
{
    QMenu *menu = new QMenu();
    if( with_intf )
    {
        QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
zorglub's avatar
zorglub committed
174
        intfmenu->setTitle( qtr("Interfaces" ) );
175
176
177
        menu->addMenu( intfmenu );
        menu->addSeparator();
    }
zorglub's avatar
zorglub committed
178
    DP_SADD( qtr("Messages" ), "", "", messagesDialog() );
179
    DP_SADD( qtr("Information") , "", "", MediaInfoDialog() );
zorglub's avatar
zorglub committed
180
    DP_SADD( qtr("Bookmarks"), "", "", bookmarksDialog() );
zorglub's avatar
zorglub committed
181
182
183
184
185
186
187
188
    DP_SADD( qtr("Extended settings"), "","",extendedDialog() );
    if( mi )
    {
        menu->addSeparator();
        QAction *adv = menu->addAction( qtr("Advanced controls" ),
                                        mi, SLOT( advanced() ) );
        adv->setCheckable( true );
        if( adv_controls_enabled ) adv->setChecked( true );
189
#if 0
190
191
192
193
        adv = menu->addAction( qtr("Visualizations selector" ),
                               mi, SLOT( visual() ) );
        adv->setCheckable( true );
        if( visual_selector_enabled ) adv->setChecked( true );
194
#endif
zorglub's avatar
zorglub committed
195
    }
196
    menu->addSeparator();
zorglub's avatar
zorglub committed
197
    DP_SADD( qtr("Preferences"), "", "", prefsDialog() );
198
199
200
201
202
203
204
205
206
207
    return menu;
}

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
208

209
    QMenu *menu = Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
210
211
212
213
214
215
216

    if( !p_intf->pf_show_dialog )
    {
        menu->addSeparator();
        menu->addAction( qtr("Switch to skins"), THEDP, SLOT(switchToSkins()) );
    }

zorglub's avatar
zorglub committed
217
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() );
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
    THEDP->menusUpdateMapper->setMapping( menu, 4 );
    return menu;
}

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,
                                        VLC_OBJECT_INPUT, FIND_ANYWHERE );
    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,
                                                FIND_ANYWHERE );
    if( p_object )
    {
        AudioAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}


QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
zorglub's avatar
zorglub committed
247
248
{
    vlc_object_t *p_object;
249
250
251
252
253
    vector<int> objects;
    vector<const char *> varnames;

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                FIND_ANYWHERE );
zorglub's avatar
zorglub committed
254
255
    if( p_object != NULL )
    {
256
257
        PUSH_VAR( "video-es" );
        PUSH_VAR( "spu-es" );
zorglub's avatar
zorglub committed
258
259
        vlc_object_release( p_object );
    }
260
261
262
263
264
265
266
267
268

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
                                                FIND_ANYWHERE );
    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
269
270
}

271
272
273
274
275
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
276

277
278
279
280
281
282
283
284
285
286
287
288
    /* FIXME */
    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                FIND_ANYWHERE );
    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
289

zorglub's avatar
zorglub committed
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
    menu->setTitle( qtr( "Additional sources" ) );
    vlc_list_t *p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
                                        FIND_ANYWHERE );
    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,
                 i>=0?p_parser->pp_shortcuts[i] : p_parser->psz_object_name ) )
            {
                a->setChecked( true );
            }
            CONNECT( a , triggered(), THEDP->SDMapper, map() );
            THEDP->SDMapper->setMapping( a, i>=0? p_parser->pp_shortcuts[i] :
                                                  p_parser->psz_object_name );
            menu->addAction( a );
        }
    }
    vlc_list_release( p_list );
    return menu;
}
zorglub's avatar
zorglub committed
328

329
330
331
/*****************************************************************************
 * Popup menus
 *****************************************************************************/
zorglub's avatar
zorglub committed
332
333
#define POPUP_BOILERPLATE \
    unsigned int i_last_separator = 0; \
334
335
336
337
338
339
340
341
342
    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
343
    p_intf->p_sys->p_popup_menu = NULL; \
344
    i_last_separator = 0;
zorglub's avatar
zorglub committed
345
346

#define POPUP_STATIC_ENTRIES \
347
    vlc_value_t val; \
zorglub's avatar
zorglub committed
348
349
350
    MIM_SADD( qtr("Stop"), "", "", stop() ); \
    MIM_SADD( qtr("Previous"), "", "", prev() ); \
    MIM_SADD( qtr("Next"), "", "", next() ); \
351
    if( p_input ) \
zorglub's avatar
zorglub committed
352
353
354
    { \
        var_Get( p_input, "state", &val ); \
        if( val.i_int == PAUSE_S ) \
zorglub's avatar
zorglub committed
355
            MIM_SADD( qtr("Play"), "", "", togglePlayPause() ) \
zorglub's avatar
zorglub committed
356
        else \
zorglub's avatar
zorglub committed
357
            MIM_SADD( qtr("Pause"), "", "", togglePlayPause() ) \
zorglub's avatar
zorglub committed
358
    } \
zorglub's avatar
zorglub committed
359
    else if( THEPL->items.i_size && THEPL->i_enabled ) \
zorglub's avatar
zorglub committed
360
        MIM_SADD( qtr("Play"), "", "", togglePlayPause() ) \
zorglub's avatar
zorglub committed
361
    \
362
    QMenu *intfmenu = InterfacesMenu( p_intf, NULL ); \
zorglub's avatar
zorglub committed
363
    intfmenu->setTitle( qtr("Interfaces" ) ); \
364
365
    menu->addMenu( intfmenu ); \
    \
zorglub's avatar
zorglub committed
366
    QMenu *toolsmenu = ToolsMenu( p_intf, NULL, false, false ); \
zorglub's avatar
zorglub committed
367
    toolsmenu->setTitle( qtr("Tools" ) ); \
368
    menu->addMenu( toolsmenu ); \
zorglub's avatar
Qt4:    
zorglub committed
369

370
void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
371
372
373
374
375
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
376
377
378
379
        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
380
381
382
383
        vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
                                                VLC_OBJECT_VOUT, FIND_CHILD );
        if( p_vout )
        {
384
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
385
386
387
388
            vlc_object_release( p_vout );
        }
        vlc_object_release( p_input );
    }
389
    CREATE_POPUP;
zorglub's avatar
zorglub committed
390
391
}

392
void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
393
394
395
396
397
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
398
399
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
400
401
402
403
        vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
                                             VLC_OBJECT_AOUT, FIND_ANYWHERE );
        if( p_aout )
        {
404
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
405
406
407
408
            vlc_object_release( p_aout );
        }
        vlc_object_release( p_input );
    }
409
    CREATE_POPUP;
zorglub's avatar
zorglub committed
410
411
412
}

/* Navigation stuff, and general */
413
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
414
415
416
417
418
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
419
420
        varnames.push_back( "audio-es" );
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
421
422
423
        PUSH_SEPARATOR;
    }

424
425
426
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
    menu->addSeparator();
zorglub's avatar
zorglub committed
427
428
    POPUP_STATIC_ENTRIES;

429
430
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
431
432
433
    p_intf->p_sys->p_popup_menu = NULL;
}

434
void QVLCMenu::PopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
435
436
437
438
439
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
440
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
441
442
443

        /* Video menu */
        PUSH_SEPARATOR;
444
445
446
447
        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
448
449
450
451
        vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
                                                VLC_OBJECT_VOUT, FIND_CHILD );
        if( p_vout )
        {
452
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
453
454
455
456
            vlc_object_release( p_vout );
        }
        /* Audio menu */
        PUSH_SEPARATOR
457
458
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
459
460
461
462
        vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
                                             VLC_OBJECT_AOUT, FIND_ANYWHERE );
        if( p_aout )
        {
463
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
464
465
466
467
            vlc_object_release( p_aout );
        }
    }

468
469
470
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
    menu->addSeparator();
zorglub's avatar
zorglub committed
471
472
    POPUP_STATIC_ENTRIES;

473
474
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
475
476
477
    p_intf->p_sys->p_popup_menu = NULL;
}

478
479
#undef PUSH_VAR
#undef PUSH_SEPARATOR
zorglub's avatar
zorglub committed
480

481
482
483
/*************************************************************************
 * Builders for automenus
 *************************************************************************/
zorglub's avatar
zorglub committed
484
QMenu * QVLCMenu::Populate( intf_thread_t *p_intf, QMenu *current,
485
486
                            vector< const char *> & varnames,
                            vector<int> & objects, bool append )
zorglub's avatar
zorglub committed
487
488
489
490
{
    QMenu *menu = current;
    if( !menu )
        menu = new QMenu();
491
    else if( !append )
zorglub's avatar
zorglub committed
492
493
494
495
496
497
498
499
        menu->clear();

    currentGroup = NULL;

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

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

503
    for( i = 0; i < (int)objects.size() ; i++ )
zorglub's avatar
zorglub committed
504
    {
505
        if( !varnames[i] || !*varnames[i] )
zorglub's avatar
zorglub committed
506
507
508
509
510
511
512
513
        {
            if( b_section_empty )
                APPEND_EMPTY;
            menu->addSeparator();
            b_section_empty = VLC_TRUE;
            continue;
        }

514
        if( objects[i] == 0  )
zorglub's avatar
zorglub committed
515
516
        {
            /// \bug What is this ?
517
            // Append( menu, varnames[i], NULL );
zorglub's avatar
zorglub committed
518
519
520
521
522
            b_section_empty = VLC_FALSE;
            continue;
        }

        p_object = (vlc_object_t *)vlc_object_get( p_intf,
523
                                                   objects[i] );
zorglub's avatar
zorglub committed
524
525
526
        if( p_object == NULL ) continue;

        b_section_empty = VLC_FALSE;
527
528
529
530
531
        /* 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
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
        vlc_object_release( p_object );
    }

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

    return menu;
}

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

static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object,
                         bool b_root = TRUE )
{
    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
563
        /* Very evil hack ! intf-switch can have only one value */
zorglub's avatar
zorglub committed
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
        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,
                          p_object, FALSE ) )
        {
            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,
592
                           vlc_object_t *p_object, bool b_submenu )
zorglub's avatar
zorglub committed
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
{
    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 )
    {
    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;
    }

    /* 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 */
623
624
625
        if( b_submenu )
        {
            QMenu *submenu = new QMenu();
zorglub's avatar
Qt4:    
zorglub committed
626
            submenu->setTitle( qfu( text.psz_string ?
zorglub's avatar
zorglub committed
627
                                    text.psz_string : psz_var ) );
628
629
630
631
632
            if( CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0)
                menu->addMenu( submenu );
        }
        else
            CreateChoicesMenu( menu, psz_var, p_object, true );
633
        FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
634
635
636
        return;
    }

637
#define TEXT_OR_VAR qfu ( text.psz_string ? text.psz_string : psz_var )
zorglub's avatar
zorglub committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652

    switch( i_type & VLC_VAR_TYPE )
    {
    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 );
        CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
                          p_object->i_object_id, val, i_type, val.b_bool );
        break;
    }
653
    FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
654
655
656
}


zorglub's avatar
zorglub committed
657
int QVLCMenu::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
658
                                 vlc_object_t *p_object, bool b_root )
zorglub's avatar
zorglub committed
659
660
661
662
663
664
665
666
{
    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 */
667
    if( IsMenuEmpty( psz_var, p_object, b_root ) ) return VLC_EGENERIC;
zorglub's avatar
zorglub committed
668
669
670
671
672
673
674
675
676
677
678
679

    switch( i_type & VLC_VAR_TYPE )
    {
    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 */
680
        return VLC_EGENERIC;
zorglub's avatar
zorglub committed
681
682
683
684
685
    }

    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
                    &val_list, &text_list ) < 0 )
    {
686
        return VLC_EGENERIC;
zorglub's avatar
zorglub committed
687
688
    }
#define NORMAL_OR_RADIO i_type & VLC_VAR_ISCOMMAND ? ITEM_NORMAL: ITEM_RADIO
zorglub's avatar
Qt4:    
zorglub committed
689
#define NOTCOMMAND !(i_type & VLC_VAR_ISCOMMAND)
zorglub's avatar
zorglub committed
690
691
692
693
694
695
696
#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;
697
        QMenu *subsubmenu = new QMenu();
zorglub's avatar
zorglub committed
698
699
700
701

        switch( i_type & VLC_VAR_TYPE )
        {
        case VLC_VAR_VARIABLE:
702
            CreateChoicesMenu( subsubmenu, CURVAL.psz_string, p_object, false );
703
            subsubmenu->setTitle( qfu( CURTEXT ? CURTEXT :CURVAL.psz_string ) );
zorglub's avatar
zorglub committed
704
705
706
707
708
709
            submenu->addMenu( subsubmenu );
            break;

        case VLC_VAR_STRING:
          var_Get( p_object, psz_var, &val );
          another_val.psz_string = strdup( CURVAL.psz_string );
710
          menutext = qfu( CURTEXT ? CURTEXT : another_val.psz_string );
zorglub's avatar
zorglub committed
711
          CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
zorglub's avatar
Qt4:    
zorglub committed
712
                            p_object->i_object_id, another_val, i_type,
zorglub's avatar
zorglub committed
713
714
715
716
717
718
719
720
                            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 );
721
          if( CURTEXT ) menutext = qfu( CURTEXT );
zorglub's avatar
zorglub committed
722
723
724
725
726
727
728
729
          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 );
730
          if( CURTEXT ) menutext = qfu( CURTEXT );
zorglub's avatar
zorglub committed
731
732
733
734
735
736
737
738
739
740
          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
741
    currentGroup = NULL;
zorglub's avatar
zorglub committed
742
743
744
745
746
747
748
749

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

#undef NORMAL_OR_RADIO
#undef NOTCOMMAND
#undef CURVAL
#undef CURTEXT
750
    return VLC_SUCCESS;
zorglub's avatar
zorglub committed
751
752
753
754
}

void QVLCMenu::CreateAndConnect( QMenu *menu, const char *psz_var,
                                 QString text, QString help,
zorglub's avatar
Qt4:    
zorglub committed
755
                                 int i_item_type, int i_object_id,
zorglub's avatar
zorglub committed
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
                                 vlc_value_t val, int i_val_type,
                                 bool checked )
{
    QAction *action = new QAction( text, menu );
    action->setText( text );
    action->setToolTip( help );

    if( i_item_type == ITEM_CHECK )
    {
        action->setCheckable( true );
    }
    else if( i_item_type == ITEM_RADIO )
    {
        action->setCheckable( true );
        if( !currentGroup )
            currentGroup = new QActionGroup(menu);
        currentGroup->addAction( action );
    }

zorglub's avatar
zorglub committed
775
776
777
778
    if( checked )
    {
        action->setChecked( true );
    }
zorglub's avatar
zorglub committed
779
780
    MenuItemData *itemData = new MenuItemData( i_object_id, i_val_type,
                                               val, psz_var );
zorglub's avatar
zorglub committed
781
    CONNECT( action, triggered(), THEDP->menusMapper, map() );
zorglub's avatar
zorglub committed
782
783
784
785
786
787
788
789
790
791
792
793
794
795
    THEDP->menusMapper->setMapping( action, itemData );
    menu->addAction( action );
}

void QVLCMenu::DoAction( intf_thread_t *p_intf, QObject *data )
{
    MenuItemData *itemData = qobject_cast<MenuItemData *>(data);
    vlc_object_t *p_object = (vlc_object_t *)vlc_object_get( p_intf,
                                           itemData->i_object_id );
    if( p_object == NULL ) return;

    var_Set( p_object, itemData->psz_var, itemData->val );
    vlc_object_release( p_object );
}