extended_panels.cpp 56.7 KB
Newer Older
zorglub's avatar
zorglub committed
1
/*****************************************************************************
zorglub's avatar
zorglub committed
2
 * extended_panels.cpp : Extended controls panels
zorglub's avatar
zorglub committed
3
 ****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
4
 * Copyright (C) 2006-2013 the VideoLAN team
5
 * $Id$
zorglub's avatar
zorglub committed
6
7
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *          Antoine Cellerier <dionoea .t videolan d@t org>
9
 *          Jean-Baptiste Kempf <jb@videolan.org>
zorglub's avatar
zorglub committed
10
11
12
13
 *
 * 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
14
 * ( at your option ) any later version.
zorglub's avatar
zorglub committed
15
16
17
18
19
20
21
22
23
24
 *
 * 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
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
zorglub's avatar
zorglub committed
29

30
31
#include <math.h>

zorglub's avatar
zorglub committed
32
33
34
35
36
#include <QLabel>
#include <QVariant>
#include <QString>
#include <QFont>
#include <QGridLayout>
37
#include <QComboBox>
38
#include <QTimer>
39
#include <QFileDialog>
40
41
#include <QGraphicsScene>
#include <QPainter>
42
#include <QRegExp>
zorglub's avatar
zorglub committed
43

zorglub's avatar
zorglub committed
44
#include "components/extended_panels.hpp"
45
#include "dialogs/preferences.hpp"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
46
#include "qt.hpp"
47
#include "input_manager.hpp"
48
#include "util/qt_dirs.hpp"
49
#include "util/customwidgets.hpp"
zorglub's avatar
zorglub committed
50

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
51
#include "../../audio_filter/equalizer_presets.h"
zorglub's avatar
zorglub committed
52
#include <vlc_vout.h>
53
#include <vlc_modules.h>
54
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
55

56
static QString ChangeFiltersString( struct intf_thread_t *p_intf, const char *psz_filter_type, const char *psz_name, bool b_add );
57
static void ChangeAFiltersString( struct intf_thread_t *p_intf, const char *psz_name, bool b_add );
58
59
static void ChangeVFiltersString( struct intf_thread_t *p_intf, const char *psz_name, bool b_add );

60
static const QString ModuleFromWidgetName( QObject *obj )
61
{
62
    return obj->objectName().replace( "Enable","" );
63
64
}

65
static QString OptionFromWidgetName( QObject *obj )
66
67
{
    /* Gruik ? ... nah */
68
69
70
71
    return obj->objectName()
        .remove( QRegExp( "Slider|Combo|Dial|Check|Spin|Text" ) )
        .replace( QRegExp( "([A-Z])" ), "-\\1" )
        .toLower();
72
}
zorglub's avatar
zorglub committed
73

74
static inline void setup_vfilter( intf_thread_t *p_intf, const char* psz_name, QWidget *widget )
zorglub's avatar
zorglub committed
75
{
76
    vlc_object_t *p_obj = ( vlc_object_t * )
77
        vlc_object_find_name( p_intf->obj.libvlc, psz_name );
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    QCheckBox *checkbox = qobject_cast<QCheckBox*>( widget );
    QGroupBox *groupbox = qobject_cast<QGroupBox*>( widget );
    if( p_obj )
    {
        vlc_object_release( p_obj ); \
        if( checkbox ) checkbox->setChecked( true ); \
        else if (groupbox) groupbox->setChecked( true ); \
    }
    else
    {
        if( checkbox ) checkbox->setChecked( false );
        else if (groupbox) groupbox->setChecked( false );
    }
}
zorglub's avatar
zorglub committed
92

93
#define SETUP_VFILTER( widget ) \
94
    setup_vfilter( p_intf, #widget, ui.widget##Enable ); \
95
    CONNECT( ui.widget##Enable, clicked(), this, updateFilters() );
96

97
#define SETUP_VFILTER_OPTION( widget, signal ) \
98
    initComboBoxItems( ui.widget ); \
99
100
    setWidgetValue( ui.widget ); \
    CONNECT( ui.widget, signal, this, updateFilterOptions() );
dionoea's avatar
dionoea committed
101

102
103
104
105
106
ExtVideo::ExtVideo( intf_thread_t *_p_intf, QTabWidget *_parent ) :
            QObject( _parent ), p_intf( _p_intf )
{
    ui.setupUi( _parent );

107
    SETUP_VFILTER( adjust )
108
109
110
111
112
113
    SETUP_VFILTER_OPTION( hueSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( contrastSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( brightnessSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( saturationSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( gammaSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( brightnessThresholdCheck, stateChanged( int ) )
114
115

    SETUP_VFILTER( extract )
ivoire's avatar
ivoire committed
116
    SETUP_VFILTER_OPTION( extractComponentText, textChanged( const QString& ) )
117

118
119
    SETUP_VFILTER( posterize )

120
    SETUP_VFILTER( colorthres )
ivoire's avatar
ivoire committed
121
    SETUP_VFILTER_OPTION( colorthresColorText, textChanged( const QString& ) )
122
123
    SETUP_VFILTER_OPTION( colorthresSaturationthresSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( colorthresSimilaritythresSlider, valueChanged( int ) )
124

125
126
127
    SETUP_VFILTER( sepia )
    SETUP_VFILTER_OPTION( sepiaIntensitySpin, valueChanged( int ) )

128
129
130
    SETUP_VFILTER( invert )

    SETUP_VFILTER( gradient )
131
132
133
    SETUP_VFILTER_OPTION( gradientModeCombo, currentIndexChanged( QString ) )
    SETUP_VFILTER_OPTION( gradientTypeCheck, stateChanged( int ) )
    SETUP_VFILTER_OPTION( gradientCartoonCheck, stateChanged( int ) )
134

135
    SETUP_VFILTER( motionblur )
136
    SETUP_VFILTER_OPTION( blurFactorSlider, valueChanged( int ) )
137
138
139
140
141
142

    SETUP_VFILTER( motiondetect )

    SETUP_VFILTER( psychedelic )

    SETUP_VFILTER( sharpen )
143
    SETUP_VFILTER_OPTION( sharpenSigmaSlider, valueChanged( int ) )
144
145
146
147
148
149

    SETUP_VFILTER( ripple )

    SETUP_VFILTER( wave )

    SETUP_VFILTER( transform )
150
    SETUP_VFILTER_OPTION( transformTypeCombo, currentIndexChanged( QString ) )
151
152

    SETUP_VFILTER( rotate )
153
    SETUP_VFILTER_OPTION( rotateAngleDial, valueChanged( int ) )
154
155
    ui.rotateAngleDial->setWrapping( true );
    ui.rotateAngleDial->setNotchesVisible( true );
156
157

    SETUP_VFILTER( puzzle )
158
159
160
    SETUP_VFILTER_OPTION( puzzleRowsSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( puzzleColsSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( puzzleBlackSlotCheck, stateChanged( int ) )
161
162
163
164

    SETUP_VFILTER( magnify )

    SETUP_VFILTER( clone )
165
    SETUP_VFILTER_OPTION( cloneCountSpin, valueChanged( int ) )
166
167

    SETUP_VFILTER( wall )
168
169
    SETUP_VFILTER_OPTION( wallRowsSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( wallColsSpin, valueChanged( int ) )
170

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
171

172
173
    SETUP_VFILTER( erase )
    SETUP_VFILTER_OPTION( eraseMaskText, editingFinished() )
174
175
    SETUP_VFILTER_OPTION( eraseYSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( eraseXSpin, valueChanged( int ) )
176
    BUTTONACT( ui.eraseBrowseBtn, browseEraseFile() );
177
178

    SETUP_VFILTER( marq )
ivoire's avatar
ivoire committed
179
    SETUP_VFILTER_OPTION( marqMarqueeText, textChanged( const QString& ) )
180
    SETUP_VFILTER_OPTION( marqPositionCombo, currentIndexChanged( QString ) )
181
182
183

    SETUP_VFILTER( logo )
    SETUP_VFILTER_OPTION( logoFileText, editingFinished() )
184
185
    SETUP_VFILTER_OPTION( logoYSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( logoXSpin, valueChanged( int ) )
186
    SETUP_VFILTER_OPTION( logoOpacitySlider, valueChanged( int ) )
187
    BUTTONACT( ui.logoBrowseBtn, browseLogo() );
188

189
190
191
    SETUP_VFILTER( gradfun )
    SETUP_VFILTER_OPTION( gradfunRadiusSlider, valueChanged( int ) )

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
192
193
194
    SETUP_VFILTER( grain )
    SETUP_VFILTER_OPTION( grainVarianceSlider, valueChanged( int ) )

195
196
197
    SETUP_VFILTER( mirror )

    SETUP_VFILTER( gaussianblur )
198
    SETUP_VFILTER_OPTION( gaussianblurSigmaSlider, valueChanged( int ) )
199
200
201
202

    SETUP_VFILTER( antiflicker )
    SETUP_VFILTER_OPTION( antiflickerSofteningSizeSlider, valueChanged( int ) )

203
204
205
206
207
208
    SETUP_VFILTER( hqdn3d )
    SETUP_VFILTER_OPTION( hqdn3dLumaSpatSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( hqdn3dLumaTempSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( hqdn3dChromaSpatSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( hqdn3dChromaTempSlider, valueChanged( int ) )

209

210
211
    SETUP_VFILTER( anaglyph )

212
213
#undef SETUP_VFILTER
#undef SETUP_VFILTER_OPTION
214
215
216
217
218

    CONNECT( ui.cropTopPx, valueChanged( int ), this, cropChange() );
    CONNECT( ui.cropBotPx, valueChanged( int ), this, cropChange() );
    CONNECT( ui.cropLeftPx, valueChanged( int ), this, cropChange() );
    CONNECT( ui.cropRightPx, valueChanged( int ), this, cropChange() );
Dylan Yudaken's avatar
Dylan Yudaken committed
219
220
    CONNECT( ui.leftRightCropSync, toggled ( bool ), this, cropChange() );
    CONNECT( ui.topBotCropSync, toggled ( bool ), this, cropChange() );
221
222
223
224
    CONNECT( ui.topBotCropSync, toggled( bool ),
             ui.cropBotPx, setDisabled( bool ) );
    CONNECT( ui.leftRightCropSync, toggled( bool ),
             ui.cropRightPx, setDisabled( bool ) );
zorglub's avatar
zorglub committed
225
226
}

227
228
void ExtVideo::cropChange()
{
Dylan Yudaken's avatar
Dylan Yudaken committed
229
230
231
232
233
    if( ui.topBotCropSync->isChecked() )
        ui.cropBotPx->setValue( ui.cropTopPx->value() );
    if( ui.leftRightCropSync->isChecked() )
        ui.cropRightPx->setValue( ui.cropLeftPx->value() );

234
    vout_thread_t *p_vout = THEMIM->getVout();
235
    if( p_vout )
236
    {
237
238
239
240
        var_SetInteger( p_vout, "crop-top", ui.cropTopPx->value() );
        var_SetInteger( p_vout, "crop-bottom", ui.cropBotPx->value() );
        var_SetInteger( p_vout, "crop-left", ui.cropLeftPx->value() );
        var_SetInteger( p_vout, "crop-right", ui.cropRightPx->value() );
241
        vlc_object_release( p_vout );
242
243
244
    }
}

245
246
247
248
249
250
251
252
void ExtVideo::clean()
{
    ui.cropTopPx->setValue( 0 );
    ui.cropBotPx->setValue( 0 );
    ui.cropLeftPx->setValue( 0 );
    ui.cropRightPx->setValue( 0 );
}

253
static QString ChangeFiltersString( struct intf_thread_t *p_intf, const char *psz_filter_type, const char *psz_name, bool b_add )
zorglub's avatar
zorglub committed
254
{
255
    char* psz_chain = config_GetPsz( p_intf, psz_filter_type );
256

257
258
    QString const chain = QString( psz_chain ? psz_chain : "" );
    QStringList list = chain.split( ':', QString::SplitBehavior::SkipEmptyParts );
zorglub's avatar
zorglub committed
259

260
261
    if( b_add ) list << psz_name;
    else        list.removeAll( psz_name );
zorglub's avatar
zorglub committed
262

263
    free( psz_chain );
zorglub's avatar
zorglub committed
264

KO Myung-Hun's avatar
KO Myung-Hun committed
265
    return list.join( ":" );
266
267
}

268
269
270
271
272
273
274
275
276
static void ChangeAFiltersString( struct intf_thread_t *p_intf, const char *psz_name, bool b_add )
{
    module_t *p_obj = module_find( psz_name );
    if( !p_obj )
    {
        msg_Err( p_intf, "Unable to find filter module \"%s\".", psz_name );
        return;
    }

277
278
    QString result = ChangeFiltersString( p_intf, "audio-filteR", psz_name, b_add );
    config_PutPsz( p_intf, "audio-filter", qtu( result ) );
279
280
}

281
static const char* GetVFilterType( struct intf_thread_t *p_intf, const char *psz_name )
282
283
284
285
286
{
    module_t *p_obj = module_find( psz_name );
    if( !p_obj )
    {
        msg_Err( p_intf, "Unable to find filter module \"%s\".", psz_name );
287
        return NULL;
288
289
290
    }

    if( module_provides( p_obj, "video splitter" ) )
291
        return "video-splitter";
292
    else if( module_provides( p_obj, "video filter" ) )
293
        return "video-filter";
294
    else if( module_provides( p_obj, "sub source" ) )
295
        return "sub-source";
296
    else if( module_provides( p_obj, "sub filter" ) )
297
        return "sub-filter";
298
299
300
    else
    {
        msg_Err( p_intf, "Unknown video filter type." );
301
        return NULL;
302
    }
303
304
305
306
307
}

static void ChangeVFiltersString( struct intf_thread_t *p_intf, const char *psz_name, bool b_add )
{
    const char *psz_filter_type = GetVFilterType( p_intf, psz_name );
308

309
310
311
    if( psz_filter_type == NULL )
        return;

312
    QString result = ChangeFiltersString( p_intf, psz_filter_type, psz_name, b_add );
313

zorglub's avatar
zorglub committed
314
    /* Vout is not kept, so put that in the config */
315
    config_PutPsz( p_intf, psz_filter_type, qtu( result ) );
zorglub's avatar
zorglub committed
316
317

    /* Try to set on the fly */
318
    if( !strcmp( psz_filter_type, "video-splitter" ) )
zorglub's avatar
zorglub committed
319
    {
320
        playlist_t *p_playlist = THEPL;
321
        var_SetString( p_playlist, psz_filter_type, qtu( result ) );
322
323
324
    }
    else
    {
325
        vout_thread_t *p_vout = THEMIM->getVout();
326
327
        if( p_vout )
        {
328
            var_SetString( p_vout, psz_filter_type, qtu( result ) );
329
330
            vlc_object_release( p_vout );
        }
zorglub's avatar
zorglub committed
331
332
333
334
335
    }
}

void ExtVideo::updateFilters()
{
336
    QString module = ModuleFromWidgetName( sender() );
zorglub's avatar
zorglub committed
337

338
339
    QCheckBox *checkbox = qobject_cast<QCheckBox*>( sender() );
    QGroupBox *groupbox = qobject_cast<QGroupBox*>( sender() );
340

341
    ChangeVFiltersString( p_intf, qtu( module ),
342
343
                          checkbox ? checkbox->isChecked()
                                   : groupbox->isChecked() );
zorglub's avatar
zorglub committed
344
345
}

346
347
348
349
350
351
#define UPDATE_AND_APPLY_TEXT( widget, file ) \
    CONNECT( ui.widget, textChanged( const QString& ), \
             this, updateFilterOptions() ); \
    ui.widget->setText( toNativeSeparators( file ) ); \
    ui.widget->disconnect( SIGNAL( textChanged( const QString& ) ) );

352
353
354
355
void ExtVideo::browseLogo()
{
    QString file = QFileDialog::getOpenFileName( NULL, qtr( "Logo filenames" ),
                   p_intf->p_sys->filepath, "Images (*.png *.jpg);;All (*)" );
356
357

    UPDATE_AND_APPLY_TEXT( logoFileText, file );
358
359
360
361
362
363
}

void ExtVideo::browseEraseFile()
{
    QString file = QFileDialog::getOpenFileName( NULL, qtr( "Image mask" ),
                   p_intf->p_sys->filepath, "Images (*.png *.jpg);;All (*)" );
364
365

    UPDATE_AND_APPLY_TEXT( eraseMaskText, file );
366
367
}

368
369
#undef UPDATE_AND_APPLY_TEXT

370
371
void ExtVideo::initComboBoxItems( QObject *widget )
{
372
    QComboBox *combobox = qobject_cast<QComboBox*>( widget );
373
    if( !combobox ) return;
374

375
    QString option = OptionFromWidgetName( widget );
376
    module_config_t *p_item = config_FindConfig( VLC_OBJECT( p_intf ),
377
                                                 qtu( option ) );
378
    if( p_item == NULL )
379
    {
380
381
382
383
384
385
386
387
388
389
390
391
        msg_Err( p_intf, "Couldn't find option \"%s\".", qtu( option ) );
        return;
    }

    if( p_item->i_type == CONFIG_ITEM_INTEGER
     || p_item->i_type == CONFIG_ITEM_BOOL )
    {
        int64_t *values;
        char **texts;
        ssize_t count = config_GetIntChoices( VLC_OBJECT( p_intf ),
                                              qtu( option ), &values, &texts );
        for( ssize_t i = 0; i < count; i++ )
392
        {
393
            combobox->addItem( qtr( texts[i] ), qlonglong(values[i]) );
394
            free( texts[i] );
395
        }
396
397
        free( texts );
        free( values );
398
    }
399
    else if( p_item->i_type == CONFIG_ITEM_STRING )
400
    {
401
402
403
404
405
406
        char **values;
        char **texts;
        ssize_t count = config_GetPszChoices( VLC_OBJECT( p_intf ),
                                              qtu( option ), &values, &texts );
        for( ssize_t i = 0; i < count; i++ )
        {
407
            combobox->addItem( qtr( texts[i] ), qfu(values[i]) );
408
409
410
411
412
            free( texts[i] );
            free( values[i] );
        }
        free( texts );
        free( values );
413
414
415
    }
}

416
417
418
419
420
421
422
void ExtVideo::setWidgetValue( QObject *widget )
{
    QString module = ModuleFromWidgetName( widget->parent() );
    //std::cout << "Module name: " << module.toStdString() << std::endl;
    QString option = OptionFromWidgetName( widget );
    //std::cout << "Option name: " << option.toStdString() << std::endl;

423
    vlc_object_t *p_obj = ( vlc_object_t * )
424
        vlc_object_find_name( p_intf->obj.libvlc, qtu( module ) );
425
426
427
428
429
    int i_type;
    vlc_value_t val;

    if( !p_obj )
    {
430
#if 0
431
432
        msg_Dbg( p_intf,
                 "Module instance %s not found, looking in config values.",
433
                 qtu( module ) );
434
#endif
ivoire's avatar
ivoire committed
435
        i_type = config_GetType( p_intf, qtu( option ) ) & VLC_VAR_CLASS;
436
437
438
439
        switch( i_type )
        {
            case VLC_VAR_INTEGER:
            case VLC_VAR_BOOL:
440
                val.i_int = config_GetInt( p_intf, qtu( option ) );
441
442
                break;
            case VLC_VAR_FLOAT:
443
                val.f_float = config_GetFloat( p_intf, qtu( option ) );
444
445
                break;
            case VLC_VAR_STRING:
446
                val.psz_string = config_GetPsz( p_intf, qtu( option ) );
447
448
449
450
451
                break;
        }
    }
    else
    {
ivoire's avatar
ivoire committed
452
        i_type = var_Type( p_obj, qtu( option ) ) & VLC_VAR_CLASS;
453
        var_Get( p_obj, qtu( option ), &val );
454
455
456
457
458
        vlc_object_release( p_obj );
    }

    /* Try to cast to all the widgets we're likely to encounter. Only
     * one of the casts is expected to work. */
459
460
461
462
    QSlider        *slider        = qobject_cast<QSlider*>       ( widget );
    QCheckBox      *checkbox      = qobject_cast<QCheckBox*>     ( widget );
    QSpinBox       *spinbox       = qobject_cast<QSpinBox*>      ( widget );
    QDoubleSpinBox *doublespinbox = qobject_cast<QDoubleSpinBox*>( widget );
463
    VLCQDial       *dial          = qobject_cast<VLCQDial*>      ( widget );
464
465
    QLineEdit      *lineedit      = qobject_cast<QLineEdit*>     ( widget );
    QComboBox      *combobox      = qobject_cast<QComboBox*>     ( widget );
466
467
468
469
470
471
472

    if( i_type == VLC_VAR_INTEGER || i_type == VLC_VAR_BOOL )
    {
        if( slider )        slider->setValue( val.i_int );
        else if( checkbox ) checkbox->setCheckState( val.i_int? Qt::Checked
                                                              : Qt::Unchecked );
        else if( spinbox )  spinbox->setValue( val.i_int );
473
        else if( dial )     dial->setValue( (360 - val.i_int) % 360 );
474
475
476
        else if( lineedit )
        {
            char str[30];
Tristan Matthews's avatar
Tristan Matthews committed
477
            snprintf( str, sizeof(str), "%06" PRIX64, val.i_int );
478
479
            lineedit->setText( str );
        }
480
        else if( combobox ) combobox->setCurrentIndex(
481
                            combobox->findData( qlonglong(val.i_int) ) );
482
        else msg_Warn( p_intf, "Could not find the correct Integer widget" );
483
484
485
    }
    else if( i_type == VLC_VAR_FLOAT )
    {
486
487
        if( slider ) slider->setValue( ( int )( val.f_float*( double )slider->tickInterval() ) ); /* hack alert! */
        else if( doublespinbox ) doublespinbox->setValue( val.f_float );
488
        else if( dial ) dial->setValue( (360 - lroundf(val.f_float)) % 360 );
489
        else msg_Warn( p_intf, "Could not find the correct Float widget" );
490
491
492
    }
    else if( i_type == VLC_VAR_STRING )
    {
493
        if( lineedit ) lineedit->setText( qfu( val.psz_string ) );
494
        else if( combobox ) combobox->setCurrentIndex(
495
                            combobox->findData( qfu( val.psz_string ) ) );
496
        else msg_Warn( p_intf, "Could not find the correct String widget" );
497
498
499
        free( val.psz_string );
    }
    else
500
501
502
503
504
505
        if( p_obj )
            msg_Err( p_intf,
                     "Module %s's %s variable is of an unsupported type ( %d )",
                     qtu( module ),
                     qtu( option ),
                     i_type );
506
507
}

508
509
void ExtVideo::setFilterOption( struct intf_thread_t *p_intf, const char *psz_module, const char *psz_option,
        int i_int, double f_float, QString val )
510
{
511
    vlc_object_t *p_obj = ( vlc_object_t * )vlc_object_find_name( p_intf->obj.libvlc, psz_module );
512
513
    int i_type;
    bool b_is_command;
514

515
516
    if( !p_obj )
    {
517
518
        msg_Warn( p_intf, "Module %s not found. You'll need to restart the filter to take the change into account.", psz_module );
        i_type = config_GetType( p_intf, psz_option );
519
520
521
522
        b_is_command = false;
    }
    else
    {
523
        i_type = var_Type( p_obj, psz_option );
524
        if( i_type == 0 )
525
            i_type = config_GetType( p_intf, psz_option );
526
        b_is_command = ( i_type & VLC_VAR_ISCOMMAND );
527
528
    }

ivoire's avatar
ivoire committed
529
    i_type &= VLC_VAR_CLASS;
530
531
    if( i_type == VLC_VAR_INTEGER || i_type == VLC_VAR_BOOL )
    {
532
533
534
        if( i_int == -1 )
            msg_Warn( p_intf, "Could not find the correct Integer widget" );
        config_PutInt( p_intf, psz_option, i_int );
535
536
537
        if( b_is_command )
        {
            if( i_type == VLC_VAR_INTEGER )
538
                var_SetInteger( p_obj, psz_option, i_int );
539
            else
540
                var_SetBool( p_obj, psz_option, i_int );
541
        }
542
543
544
    }
    else if( i_type == VLC_VAR_FLOAT )
    {
545
546
547
        if( f_float == -1 )
            msg_Warn( p_intf, "Could not find the correct Float widget" );
        config_PutFloat( p_intf, psz_option, f_float );
548
        if( b_is_command )
549
            var_SetFloat( p_obj, psz_option, f_float );
550
551
552
    }
    else if( i_type == VLC_VAR_STRING )
    {
553
        if( val.isNull() )
554
            msg_Warn( p_intf, "Could not find the correct String widget" );
555
        config_PutPsz( p_intf, psz_option, qtu( val ) );
556
        if( b_is_command )
557
            var_SetString( p_obj, psz_option, qtu( val ) );
558
559
560
    }
    else
        msg_Err( p_intf,
561
                 "Module %s's %s variable is of an unsupported type ( %d )",
562
563
                 psz_module,
                 psz_option,
564
565
                 i_type );

566
567
568
    if( !b_is_command )
    {
        msg_Warn( p_intf, "Module %s's %s variable isn't a command. Brute-restarting the filter.",
569
570
571
572
                 psz_module,
                 psz_option );
        ChangeVFiltersString( p_intf, psz_module, false );
        ChangeVFiltersString( p_intf, psz_module, true );
573
574
    }

575
    if( p_obj ) vlc_object_release( p_obj );
576
577
}

578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
void ExtVideo::updateFilterOptions()
{
    QString module = ModuleFromWidgetName( sender()->parent() );
    //msg_Dbg( p_intf, "Module name: %s", qtu( module ) );
    QString option = OptionFromWidgetName( sender() );
    //msg_Dbg( p_intf, "Option name: %s", qtu( option ) );

    /* Try to cast to all the widgets we're likely to encounter. Only
     * one of the casts is expected to work. */
    QSlider        *slider        = qobject_cast<QSlider*>       ( sender() );
    QCheckBox      *checkbox      = qobject_cast<QCheckBox*>     ( sender() );
    QSpinBox       *spinbox       = qobject_cast<QSpinBox*>      ( sender() );
    QDoubleSpinBox *doublespinbox = qobject_cast<QDoubleSpinBox*>( sender() );
    VLCQDial       *dial          = qobject_cast<VLCQDial*>      ( sender() );
    QLineEdit      *lineedit      = qobject_cast<QLineEdit*>     ( sender() );
    QComboBox      *combobox      = qobject_cast<QComboBox*>     ( sender() );

    int i_int = -1;
    double f_float = -1.;
    QString val;

    if( slider ) {
        i_int = slider->value();
        f_float = ( double )slider->value() / ( double )slider->tickInterval(); /* hack alert! */
    }
    else if( checkbox ) i_int = checkbox->checkState() == Qt::Checked;
    else if( spinbox ) i_int = spinbox->value();
    else if( doublespinbox ) f_float = doublespinbox->value();
    else if( dial ) {
607
608
        i_int = (360 - dial->value()) % 360;
        f_float = i_int;
609
610
611
612
613
614
615
616
617
618
619
620
621
622
    }
    else if( lineedit ) {
        i_int = lineedit->text().toInt( NULL,16 );
        f_float = lineedit->text().toDouble();
        val = lineedit->text();
    }
    else if( combobox ) {
        i_int = combobox->itemData( combobox->currentIndex() ).toInt();
        val = combobox->itemData( combobox->currentIndex() ).toString();
    }

    setFilterOption( p_intf, qtu( module ), qtu( option ), i_int, f_float, val);
}

623
624
625
626
627
628
629
630
631
632
633
634
int ExtVideo::getPostprocessing( struct intf_thread_t *p_intf)
{
    char *psz_config = config_GetPsz(p_intf, "video-filter");
    int i_q = -1;
    if (psz_config) {
        if (strstr(psz_config, "postproc"))
            i_q = config_GetInt(p_intf, "postproc-q");
        free(psz_config);
    }
    return i_q;
}

635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
void ExtVideo::setPostprocessing( struct intf_thread_t *p_intf, int q)
{
    const char *psz_name = "postproc";

    if( q == -1 )
    {
        ChangeVFiltersString( p_intf, psz_name, false );
    }
    else
    {
        ChangeVFiltersString( p_intf, psz_name, false );
        setFilterOption( p_intf, "postproc", "postproc-q", q, -1, QString() );
    }
}

650
651
652
653
654
/**********************************************************************
 * v4l2 controls
 **********************************************************************/

ExtV4l2::ExtV4l2( intf_thread_t *_p_intf, QWidget *_parent )
655
    : QWidget( _parent ), p_intf( _p_intf ), box( NULL )
656
{
657
658
659
660
661
662
    QVBoxLayout *layout = new QVBoxLayout( this );
    help = new QLabel( qtr("No v4l2 instance found.\n"
      "Please check that the device has been opened with VLC and is playing.\n\n"
      "Controls will automatically appear here.")
      , this );
    help->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
663
    help->setWordWrap( true );
664
665
    layout->addWidget( help );
    setLayout( layout );
666
667
}

668
669
670
671
672
673
void ExtV4l2::showEvent( QShowEvent *event )
{
    QWidget::showEvent( event );
    Refresh();
}

674
675
void ExtV4l2::Refresh( void )
{
676
    vlc_object_t *p_obj = (vlc_object_t*)vlc_object_find_name( THEPL, "v4l2" );
677
    help->hide();
678
679
    if( box )
    {
680
        layout()->removeWidget( box );
681
682
683
        delete box;
        box = NULL;
    }
684
685
    if( p_obj )
    {
686
        vlc_value_t val, text;
687
688
689
690
        int i_ret = var_Change( p_obj, "controls", VLC_VAR_GETCHOICES,
                                &val, &text );
        if( i_ret < 0 )
        {
691
            msg_Err( p_intf, "Oops, v4l2 object doesn't have a 'controls' variable." );
692
            help->show();
693
694
695
            vlc_object_release( p_obj );
            return;
        }
696
697

        box = new QGroupBox( this );
698
        layout()->addWidget( box );
699
700
701
        QVBoxLayout *layout = new QVBoxLayout( box );
        box->setLayout( layout );

702
703
        for( int i = 0; i < val.p_list->i_count; i++ )
        {
704
            vlc_value_t vartext;
705
            const char *psz_var = text.p_list->p_values[i].psz_string;
706
707
708
709
710
711

            if( var_Change( p_obj, psz_var, VLC_VAR_GETTEXT, &vartext, NULL ) )
                continue;

            QString name = qtr( vartext.psz_string );
            free( vartext.psz_string );
Tristan Matthews's avatar
Tristan Matthews committed
712
            msg_Dbg( p_intf, "v4l2 control \"%" PRIx64 "\": %s (%s)",
713
                     val.p_list->p_values[i].i_int, psz_var, qtu( name ) );
714
715
716
717
718
719

            int i_type = var_Type( p_obj, psz_var );
            switch( i_type & VLC_VAR_TYPE )
            {
                case VLC_VAR_INTEGER:
                {
720
                    QLabel *label = new QLabel( name, box );
721
                    QHBoxLayout *hlayout = new QHBoxLayout();
722
723
724
725
                    hlayout->addWidget( label );
                    int i_val = var_GetInteger( p_obj, psz_var );
                    if( i_type & VLC_VAR_HASCHOICE )
                    {
726
                        QComboBox *combobox = new QComboBox( box );
727
                        combobox->setObjectName( qfu( psz_var ) );
728
729
730
731
732
733
734
735

                        vlc_value_t val2, text2;
                        var_Change( p_obj, psz_var, VLC_VAR_GETCHOICES,
                                    &val2, &text2 );
                        for( int j = 0; j < val2.p_list->i_count; j++ )
                        {
                            combobox->addItem(
                                       text2.p_list->p_values[j].psz_string,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
736
                                       qlonglong( val2.p_list->p_values[j].i_int) );
737
738
739
                            if( i_val == val2.p_list->p_values[j].i_int )
                                combobox->setCurrentIndex( j );
                        }
740
                        var_FreeList( &val2, &text2 );
741
742
743
744
745
746
747

                        CONNECT( combobox, currentIndexChanged( int ), this,
                                 ValueChange( int ) );
                        hlayout->addWidget( combobox );
                    }
                    else
                    {
748
                        QSlider *slider = new QSlider( box );
749
                        slider->setObjectName( qfu( psz_var ) );
750
751
752
753
                        slider->setOrientation( Qt::Horizontal );
                        vlc_value_t val2;
                        var_Change( p_obj, psz_var, VLC_VAR_GETMIN,
                                    &val2, NULL );
754
755
                        if( val2.i_int < INT_MIN )
                            val2.i_int = INT_MIN; /* FIXME */
756
757
758
                        slider->setMinimum( val2.i_int );
                        var_Change( p_obj, psz_var, VLC_VAR_GETMAX,
                                    &val2, NULL );
759
760
                        if( val2.i_int > INT_MAX )
                            val2.i_int = INT_MAX; /* FIXME */
761
                        slider->setMaximum( val2.i_int );
762
763
764
                        if( !var_Change( p_obj, psz_var, VLC_VAR_GETSTEP,
                                         &val2, NULL ) )
                            slider->setSingleStep( val2.i_int );
765
766
767
768
769
770
771
772
773
774
                        slider->setValue( i_val );
                        CONNECT( slider, valueChanged( int ), this,
                                 ValueChange( int ) );
                        hlayout->addWidget( slider );
                    }
                    layout->addLayout( hlayout );
                    break;
                }
                case VLC_VAR_BOOL:
                {
775
                    QCheckBox *button = new QCheckBox( name, box );
776
                    button->setObjectName( qfu( psz_var ) );
777
778
779
780
781
782
783
784
785
                    button->setChecked( var_GetBool( p_obj, psz_var ) );

                    CONNECT( button, clicked( bool ), this,
                             ValueChange( bool ) );
                    layout->addWidget( button );
                    break;
                }
                case VLC_VAR_VOID:
                {
786
787
                    if( i_type & VLC_VAR_ISCOMMAND )
                    {
788
                        QPushButton *button = new QPushButton( name, box );
789
                        button->setObjectName( qfu( psz_var ) );
790

791
792
793
794
795
796
                        CONNECT( button, clicked( bool ), this,
                                 ValueChange( bool ) );
                        layout->addWidget( button );
                    }
                    else
                    {
797
                        QLabel *label = new QLabel( name, box );
798
799
                        layout->addWidget( label );
                    }
800
801
802
803
804
805
806
                    break;
                }
                default:
                    msg_Warn( p_intf, "Unhandled var type for %s", psz_var );
                    break;
            }
        }
807
        var_FreeList( &val, &text );
808
809
810
811
812
        vlc_object_release( p_obj );
    }
    else
    {
        msg_Dbg( p_intf, "Couldn't find v4l2 instance" );
813
814
815
        help->show();
        if ( isVisible() )
            QTimer::singleShot( 2000, this, SLOT(Refresh()) );
816
817
818
819
820
821
822
823
824
825
826
    }
}

void ExtV4l2::ValueChange( bool value )
{
    ValueChange( (int)value );
}

void ExtV4l2::ValueChange( int value )
{
    QObject *s = sender();
827
    vlc_object_t *p_obj = (vlc_object_t*)vlc_object_find_name( THEPL, "v4l2" );
828
829
    if( p_obj )
    {
830
831
        QString var = s->objectName();
        int i_type = var_Type( p_obj, qtu( var ) );
832
833
834
835
836
837
838
839
        switch( i_type & VLC_VAR_TYPE )
        {
            case VLC_VAR_INTEGER:
                if( i_type & VLC_VAR_HASCHOICE )
                {
                    QComboBox *combobox = qobject_cast<QComboBox*>( s );
                    value = combobox->itemData( value ).toInt();
                }
840
                var_SetInteger( p_obj, qtu( var ), value );
841
842
                break;
            case VLC_VAR_BOOL:
843
                var_SetBool( p_obj, qtu( var ), value );
844
845
                break;
            case VLC_VAR_VOID:
846
                var_TriggerCallback( p_obj, qtu( var ) );
847
848
849
850
851
852
853
854
855
856
857
                break;
        }
        vlc_object_release( p_obj );
    }
    else
    {
        msg_Warn( p_intf, "Oops, v4l2 object isn't available anymore" );
        Refresh();
    }
}

858
859
860
861
/**********************************************************************
 * Sliders
 **********************************************************************/

862
863
FilterSliderData::FilterSliderData( QObject *parent, QSlider *_slider ) :
    QObject( parent ), slider( _slider )
864
865
866
{
    b_save_to_config = false;
}
867

868
869
870
871
872
FilterSliderData::FilterSliderData( QObject *parent,
                                    intf_thread_t *_p_intf,
                                    QSlider *_slider,
                                    QLabel *_label, QLabel *_nameLabel,
                                    const slider_data_t *_p_data ):
873
874
    QObject( parent ), slider( _slider ), valueLabel( _label ),
    nameLabel( _nameLabel ), p_data( _p_data ), p_intf( _p_intf )
875
{
876
    b_save_to_config = false;
877
878
    slider->setMinimum( p_data->f_min / p_data->f_resolution );
    slider->setMaximum( p_data->f_max / p_data->f_resolution );
879
    nameLabel->setText( p_data->descs );
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
    CONNECT( slider, valueChanged( int ), this, updateText( int ) );
    setValue( initialValue() );
    /* In case current == min|max text would not be first updated */
    if ( slider->value() == slider->maximum() ||
         slider->value() == slider->minimum() )
        updateText( slider->value() );
    CONNECT( slider, valueChanged( int ), this, onValueChanged( int ) );
}

void FilterSliderData::setValue( float f )
{
    slider->setValue( f / p_data->f_resolution );
}

void FilterSliderData::updateText( int i )
{
896
    float f = ((float) i) * p_data->f_resolution * p_data->f_visual_multiplier;
897
    valueLabel->setText( QString( p_data->units )
898
                    .prepend( "%1 " )
899
900
901
902
903
904
905
906
907
                    .arg( QString::number( f, 'f', 1 ) ) );
}

float FilterSliderData::initialValue()
{
    vlc_object_t *p_aout = (vlc_object_t *) THEMIM->getAout();
    float f = p_data->f_value;
    if( p_aout )
    {
908
        if ( var_Type( p_aout, qtu(p_data->name) ) == 0 )
909
910
911
912
913
914
        {
            vlc_object_release( p_aout );
            /* Not found, will try in config */
        }
        else
        {
915
            f = var_GetFloat( p_aout, qtu(p_data->name) );
916
917
918
919
920
            vlc_object_release( p_aout );
            return f;
        }
    }

921
    if ( ! config_FindConfig( VLC_OBJECT(p_intf), qtu(p_data->name) ) )
922
923
        return f;

924
    f = config_GetFloat( p_intf, qtu(p_data->name) );
925
926
927
    return f;
}

928
void FilterSliderData::onValueChanged( int i ) const
929
930
931
932
933
{
    float f = ((float) i) * p_data->f_resolution;
    vlc_object_t *p_aout = (vlc_object_t *) THEMIM->getAout();
    if ( p_aout )
    {
934
        var_SetFloat( p_aout, qtu(p_data->name), f );
935
936
937
938
939
        vlc_object_release( p_aout );
    }
    writeToConfig();
}

940
void FilterSliderData::writeToConfig() const
941
{
942
    if ( !b_save_to_config ) return;
943
    float f = ((float) slider->value()) * p_data->f_resolution;
944
945
946
    config_PutFloat( p_intf, qtu(p_data->name), f );
}

947
948
949
950
951
void FilterSliderData::setSaveToConfig( bool b )
{
    b_save_to_config = b;
}

952
953
AudioFilterControlWidget::AudioFilterControlWidget
( intf_thread_t *_p_intf, QWidget *parent, const char *_name ) :
954
    QWidget( parent ), p_intf( _p_intf ), name( _name ), i_smallfont(0)
955
956
957
958
959
{}

void AudioFilterControlWidget::build()
{
    QFont smallFont = QApplication::font();
960
    smallFont.setPointSize( smallFont.pointSize() + i_smallfont );
961
962
963
964
965
966
967