extended_panels.cpp 56.7 KB
Newer Older
Clément Stenac's avatar
Clément Stenac committed
1
/*****************************************************************************
Clément Stenac's avatar
Clément Stenac committed
2
 * extended_panels.cpp : Extended controls panels
Clément Stenac's avatar
Clément Stenac committed
3
 ****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
4
 * Copyright (C) 2006-2013 the VideoLAN team
5
 * $Id$
Clément Stenac's avatar
Clément Stenac 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>
Clément Stenac's avatar
Clément Stenac 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.
Clément Stenac's avatar
Clément Stenac 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
Clément Stenac's avatar
Clément Stenac committed
29

30 31
#include <math.h>

Clément Stenac's avatar
Clément Stenac 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>
Clément Stenac's avatar
Clément Stenac committed
43

Clément Stenac's avatar
Clément Stenac 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"
Clément Stenac's avatar
Clément Stenac committed
50

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
51
#include "../../audio_filter/equalizer_presets.h"
Clément Stenac's avatar
Clément Stenac committed
52
#include <vlc_vout.h>
53
#include <vlc_modules.h>
54
#include <vlc_plugin.h>
Clément Stenac's avatar
Clément Stenac 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
}
Clément Stenac's avatar
Clément Stenac committed
73

74
static inline void setup_vfilter( intf_thread_t *p_intf, const char* psz_name, QWidget *widget )
Clément Stenac's avatar
Clément Stenac 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 );
    }
}
Clément Stenac's avatar
Clément Stenac 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() );
Antoine Cellerier's avatar
Antoine Cellerier 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 )
116
    SETUP_VFILTER_OPTION( extractComponentText, textChanged( const QString& ) )
117

118 119
    SETUP_VFILTER( posterize )

120
    SETUP_VFILTER( colorthres )
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 )
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 ) );
Clément Stenac's avatar
Clément Stenac 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 )
Clément Stenac's avatar
Clément Stenac 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 );
Clément Stenac's avatar
Clément Stenac committed
259

260 261
    if( b_add ) list << psz_name;
    else        list.removeAll( psz_name );
Clément Stenac's avatar
Clément Stenac committed
262

263
    free( psz_chain );
Clément Stenac's avatar
Clément Stenac committed
264

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

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

    /* Try to set on the fly */
318
    if( !strcmp( psz_filter_type, "video-splitter" ) )
Clément Stenac's avatar
Clément Stenac 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 );
        }
Clément Stenac's avatar
Clément Stenac committed
331 332 333 334 335
    }
}

void ExtVideo::updateFilters()
{
336
    QString module = ModuleFromWidgetName( sender() );
Clément Stenac's avatar
Clément Stenac 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() );
Clément Stenac's avatar
Clément Stenac 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
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
    {
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
    }

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) );