extended_panels.cpp 55.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 57 58 59 60 61 62 63 64 65 66
static bool filterIsPresent( const QString &filters, const QString &filter )
{
    QStringList list = filters.split( ':', QString::SplitBehavior::SkipEmptyParts );
    foreach( const QString &filterCmp, list )
    {
        if( filterCmp.compare( filter ) == 0 )
            return true;
    }
    return false;
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
static const char* GetVFilterType( struct intf_thread_t *p_intf, const char *psz_name )
{
    module_t *p_obj = module_find( psz_name );
    if( !p_obj )
    {
        msg_Err( p_intf, "Unable to find filter module \"%s\".", psz_name );
        return NULL;
    }

    if( module_provides( p_obj, "video splitter" ) )
        return "video-splitter";
    else if( module_provides( p_obj, "video filter" ) )
        return "video-filter";
    else if( module_provides( p_obj, "sub source" ) )
        return "sub-source";
    else if( module_provides( p_obj, "sub filter" ) )
        return "sub-filter";
    else
    {
        msg_Err( p_intf, "Unknown video filter type." );
        return NULL;
    }
}
90

91
static const QString ModuleFromWidgetName( QObject *obj )
92
{
93
    return obj->objectName().replace( "Enable","" );
94 95
}

96
static QString OptionFromWidgetName( QObject *obj )
97 98
{
    /* Gruik ? ... nah */
99 100 101 102
    return obj->objectName()
        .remove( QRegExp( "Slider|Combo|Dial|Check|Spin|Text" ) )
        .replace( QRegExp( "([A-Z])" ), "-\\1" )
        .toLower();
103
}
Clément Stenac's avatar
Clément Stenac committed
104

105
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
106
{
107
    vlc_object_t *p_obj = ( vlc_object_t * )
108
        vlc_object_find_name( p_intf->obj.libvlc, psz_name );
109 110 111 112 113 114 115 116 117 118 119 120 121 122
    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
123

124
#define SETUP_VFILTER( widget ) \
125
    setup_vfilter( p_intf, #widget, ui.widget##Enable ); \
126
    CONNECT( ui.widget##Enable, clicked(), this, updateFilters() );
127

128
#define SETUP_VFILTER_OPTION( widget, signal ) \
129
    initComboBoxItems( ui.widget ); \
130 131
    setWidgetValue( ui.widget ); \
    CONNECT( ui.widget, signal, this, updateFilterOptions() );
Antoine Cellerier's avatar
Antoine Cellerier committed
132

133 134 135 136 137
ExtVideo::ExtVideo( intf_thread_t *_p_intf, QTabWidget *_parent ) :
            QObject( _parent ), p_intf( _p_intf )
{
    ui.setupUi( _parent );

138
    SETUP_VFILTER( adjust )
139 140 141 142 143 144
    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 ) )
145 146

    SETUP_VFILTER( extract )
147
    SETUP_VFILTER_OPTION( extractComponentText, textChanged( const QString& ) )
148

149 150
    SETUP_VFILTER( posterize )

151
    SETUP_VFILTER( colorthres )
152
    SETUP_VFILTER_OPTION( colorthresColorText, textChanged( const QString& ) )
153 154
    SETUP_VFILTER_OPTION( colorthresSaturationthresSlider, valueChanged( int ) )
    SETUP_VFILTER_OPTION( colorthresSimilaritythresSlider, valueChanged( int ) )
155

156 157 158
    SETUP_VFILTER( sepia )
    SETUP_VFILTER_OPTION( sepiaIntensitySpin, valueChanged( int ) )

159 160 161
    SETUP_VFILTER( invert )

    SETUP_VFILTER( gradient )
162 163 164
    SETUP_VFILTER_OPTION( gradientModeCombo, currentIndexChanged( QString ) )
    SETUP_VFILTER_OPTION( gradientTypeCheck, stateChanged( int ) )
    SETUP_VFILTER_OPTION( gradientCartoonCheck, stateChanged( int ) )
165

166
    SETUP_VFILTER( motionblur )
167
    SETUP_VFILTER_OPTION( blurFactorSlider, valueChanged( int ) )
168 169 170 171 172 173

    SETUP_VFILTER( motiondetect )

    SETUP_VFILTER( psychedelic )

    SETUP_VFILTER( sharpen )
174
    SETUP_VFILTER_OPTION( sharpenSigmaSlider, valueChanged( int ) )
175 176 177 178 179 180

    SETUP_VFILTER( ripple )

    SETUP_VFILTER( wave )

    SETUP_VFILTER( transform )
181
    SETUP_VFILTER_OPTION( transformTypeCombo, currentIndexChanged( QString ) )
182 183

    SETUP_VFILTER( rotate )
184
    SETUP_VFILTER_OPTION( rotateAngleDial, valueChanged( int ) )
185 186
    ui.rotateAngleDial->setWrapping( true );
    ui.rotateAngleDial->setNotchesVisible( true );
187 188

    SETUP_VFILTER( puzzle )
189 190
    SETUP_VFILTER_OPTION( puzzleRowsSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( puzzleColsSpin, valueChanged( int ) )
191 192 193 194

    SETUP_VFILTER( magnify )

    SETUP_VFILTER( clone )
195
    SETUP_VFILTER_OPTION( cloneCountSpin, valueChanged( int ) )
196 197

    SETUP_VFILTER( wall )
198 199
    SETUP_VFILTER_OPTION( wallRowsSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( wallColsSpin, valueChanged( int ) )
200

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

202 203
    SETUP_VFILTER( erase )
    SETUP_VFILTER_OPTION( eraseMaskText, editingFinished() )
204 205
    SETUP_VFILTER_OPTION( eraseYSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( eraseXSpin, valueChanged( int ) )
206
    BUTTONACT( ui.eraseBrowseBtn, browseEraseFile() );
207 208

    SETUP_VFILTER( marq )
209
    SETUP_VFILTER_OPTION( marqMarqueeText, textChanged( const QString& ) )
210
    SETUP_VFILTER_OPTION( marqPositionCombo, currentIndexChanged( QString ) )
211 212 213

    SETUP_VFILTER( logo )
    SETUP_VFILTER_OPTION( logoFileText, editingFinished() )
214 215
    SETUP_VFILTER_OPTION( logoYSpin, valueChanged( int ) )
    SETUP_VFILTER_OPTION( logoXSpin, valueChanged( int ) )
216
    SETUP_VFILTER_OPTION( logoOpacitySlider, valueChanged( int ) )
217
    BUTTONACT( ui.logoBrowseBtn, browseLogo() );
218

219 220 221
    SETUP_VFILTER( gradfun )
    SETUP_VFILTER_OPTION( gradfunRadiusSlider, valueChanged( int ) )

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
222 223 224
    SETUP_VFILTER( grain )
    SETUP_VFILTER_OPTION( grainVarianceSlider, valueChanged( int ) )

225 226 227
    SETUP_VFILTER( mirror )

    SETUP_VFILTER( gaussianblur )
228
    SETUP_VFILTER_OPTION( gaussianblurSigmaSlider, valueChanged( int ) )
229 230 231 232

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

233 234 235 236 237 238
    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 ) )

239

240 241
    SETUP_VFILTER( anaglyph )

242 243
#undef SETUP_VFILTER
#undef SETUP_VFILTER_OPTION
244 245 246 247 248

    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
249 250
    CONNECT( ui.leftRightCropSync, toggled ( bool ), this, cropChange() );
    CONNECT( ui.topBotCropSync, toggled ( bool ), this, cropChange() );
251 252 253 254
    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
255 256
}

257 258
void ExtVideo::cropChange()
{
Dylan Yudaken's avatar
Dylan Yudaken committed
259 260 261 262 263
    if( ui.topBotCropSync->isChecked() )
        ui.cropBotPx->setValue( ui.cropTopPx->value() );
    if( ui.leftRightCropSync->isChecked() )
        ui.cropRightPx->setValue( ui.cropLeftPx->value() );

264
    vout_thread_t *p_vout = THEMIM->getVout();
265
    if( p_vout )
266
    {
267 268 269 270
        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() );
271
        vlc_object_release( p_vout );
272 273 274
    }
}

275 276 277 278 279 280 281 282
void ExtVideo::clean()
{
    ui.cropTopPx->setValue( 0 );
    ui.cropBotPx->setValue( 0 );
    ui.cropLeftPx->setValue( 0 );
    ui.cropRightPx->setValue( 0 );
}

283
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
284
{
285
    char* psz_chain = config_GetPsz( p_intf, psz_filter_type );
286

287 288
    QString const chain = QString( psz_chain ? psz_chain : "" );
    QStringList list = chain.split( ':', QString::SplitBehavior::SkipEmptyParts );
Clément Stenac's avatar
Clément Stenac committed
289

290 291
    if( b_add ) list << psz_name;
    else        list.removeAll( psz_name );
Clément Stenac's avatar
Clément Stenac committed
292

293
    free( psz_chain );
Clément Stenac's avatar
Clément Stenac committed
294

KO Myung-Hun's avatar
KO Myung-Hun committed
295
    return list.join( ":" );
296 297
}

298 299 300 301 302 303 304 305 306
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;
    }

307
    QString result = ChangeFiltersString( p_intf, "audio-filter", psz_name, b_add );
308
    config_PutPsz( p_intf, "audio-filter", qtu( result ) );
309 310
}

311 312 313
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 );
314

315 316 317
    if( psz_filter_type == NULL )
        return;

318
    QString result = ChangeFiltersString( p_intf, psz_filter_type, psz_name, b_add );
319

Clément Stenac's avatar
Clément Stenac committed
320
    /* Vout is not kept, so put that in the config */
321
    config_PutPsz( p_intf, psz_filter_type, qtu( result ) );
Clément Stenac's avatar
Clément Stenac committed
322 323

    /* Try to set on the fly */
324
    if( !strcmp( psz_filter_type, "video-splitter" ) )
Clément Stenac's avatar
Clément Stenac committed
325
    {
326
        playlist_t *p_playlist = THEPL;
327
        var_SetString( p_playlist, psz_filter_type, qtu( result ) );
328 329 330
    }
    else
    {
331
        vout_thread_t *p_vout = THEMIM->getVout();
332 333
        if( p_vout )
        {
334
            var_SetString( p_vout, psz_filter_type, qtu( result ) );
335 336
            vlc_object_release( p_vout );
        }
Clément Stenac's avatar
Clément Stenac committed
337 338 339 340 341
    }
}

void ExtVideo::updateFilters()
{
342
    QString module = ModuleFromWidgetName( sender() );
Clément Stenac's avatar
Clément Stenac committed
343

344 345
    QCheckBox *checkbox = qobject_cast<QCheckBox*>( sender() );
    QGroupBox *groupbox = qobject_cast<QGroupBox*>( sender() );
346

347
    ChangeVFiltersString( p_intf, qtu( module ),
348 349
                          checkbox ? checkbox->isChecked()
                                   : groupbox->isChecked() );
Clément Stenac's avatar
Clément Stenac committed
350 351
}

352 353 354 355 356 357
#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& ) ) );

358 359 360 361
void ExtVideo::browseLogo()
{
    QString file = QFileDialog::getOpenFileName( NULL, qtr( "Logo filenames" ),
                   p_intf->p_sys->filepath, "Images (*.png *.jpg);;All (*)" );
362 363

    UPDATE_AND_APPLY_TEXT( logoFileText, file );
364 365 366 367 368 369
}

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

    UPDATE_AND_APPLY_TEXT( eraseMaskText, file );
372 373
}

374 375
#undef UPDATE_AND_APPLY_TEXT

376 377
void ExtVideo::initComboBoxItems( QObject *widget )
{
378
    QComboBox *combobox = qobject_cast<QComboBox*>( widget );
379
    if( !combobox ) return;
380

381
    QString option = OptionFromWidgetName( widget );
382
    module_config_t *p_item = config_FindConfig( VLC_OBJECT( p_intf ),
383
                                                 qtu( option ) );
384
    if( p_item == NULL )
385
    {
386 387 388 389 390 391 392 393 394 395 396 397
        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++ )
398
        {
399
            combobox->addItem( qtr( texts[i] ), qlonglong(values[i]) );
400
            free( texts[i] );
401
        }
402 403
        free( texts );
        free( values );
404
    }
405
    else if( p_item->i_type == CONFIG_ITEM_STRING )
406
    {
407 408 409 410 411 412
        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++ )
        {
413
            combobox->addItem( qtr( texts[i] ), qfu(values[i]) );
414 415 416 417 418
            free( texts[i] );
            free( values[i] );
        }
        free( texts );
        free( values );
419 420 421
    }
}

422 423 424 425 426 427 428
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;

429
    vlc_object_t *p_obj = ( vlc_object_t * )
430
        vlc_object_find_name( p_intf->obj.libvlc, qtu( module ) );
431 432 433 434 435
    int i_type;
    vlc_value_t val;

    if( !p_obj )
    {
436
#if 0
437 438
        msg_Dbg( p_intf,
                 "Module instance %s not found, looking in config values.",
439
                 qtu( module ) );
440
#endif
441
        i_type = config_GetType( p_intf, qtu( option ) ) & VLC_VAR_CLASS;
442 443 444 445
        switch( i_type )
        {
            case VLC_VAR_INTEGER:
            case VLC_VAR_BOOL:
446
                val.i_int = config_GetInt( p_intf, qtu( option ) );
447 448
                break;
            case VLC_VAR_FLOAT:
449
                val.f_float = config_GetFloat( p_intf, qtu( option ) );
450 451
                break;
            case VLC_VAR_STRING:
452
                val.psz_string = config_GetPsz( p_intf, qtu( option ) );
453 454 455 456 457
                break;
        }
    }
    else
    {
458
        i_type = var_Type( p_obj, qtu( option ) ) & VLC_VAR_CLASS;
459
        var_Get( p_obj, qtu( option ), &val );
460 461 462 463 464
        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. */
465 466 467 468
    QSlider        *slider        = qobject_cast<QSlider*>       ( widget );
    QCheckBox      *checkbox      = qobject_cast<QCheckBox*>     ( widget );
    QSpinBox       *spinbox       = qobject_cast<QSpinBox*>      ( widget );
    QDoubleSpinBox *doublespinbox = qobject_cast<QDoubleSpinBox*>( widget );
469
    VLCQDial       *dial          = qobject_cast<VLCQDial*>      ( widget );
470 471
    QLineEdit      *lineedit      = qobject_cast<QLineEdit*>     ( widget );
    QComboBox      *combobox      = qobject_cast<QComboBox*>     ( widget );
472 473 474 475 476 477 478

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

514 515
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 )
516
{
517
    vlc_object_t *p_obj = ( vlc_object_t * )vlc_object_find_name( p_intf->obj.libvlc, psz_module );
518 519
    int i_type;
    bool b_is_command;
520

521 522
    if( !p_obj )
    {
523 524
        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 );
525 526 527 528
        b_is_command = false;
    }
    else
    {
529
        i_type = var_Type( p_obj, psz_option );
530
        if( i_type == 0 )
531
            i_type = config_GetType( p_intf, psz_option );
532
        b_is_command = ( i_type & VLC_VAR_ISCOMMAND );
533 534
    }

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

572 573 574
    if( !b_is_command )
    {
        msg_Warn( p_intf, "Module %s's %s variable isn't a command. Brute-restarting the filter.",
575 576 577 578
                 psz_module,
                 psz_option );
        ChangeVFiltersString( p_intf, psz_module, false );
        ChangeVFiltersString( p_intf, psz_module, true );
579 580
    }

581
    if( p_obj ) vlc_object_release( p_obj );
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 607 608 609 610 611 612
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 ) {
613 614
        i_int = (360 - dial->value()) % 360;
        f_float = i_int;
615 616 617 618 619 620 621 622 623 624 625 626 627 628
    }
    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);
}

629 630 631 632 633
/**********************************************************************
 * v4l2 controls
 **********************************************************************/

ExtV4l2::ExtV4l2( intf_thread_t *_p_intf, QWidget *_parent )
634
    : QWidget( _parent ), p_intf( _p_intf ), box( NULL )
635
{
636 637 638 639 640 641
    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 );
642
    help->setWordWrap( true );
643 644
    layout->addWidget( help );
    setLayout( layout );
645 646
}

647 648 649 650 651 652
void ExtV4l2::showEvent( QShowEvent *event )
{
    QWidget::showEvent( event );
    Refresh();
}

653 654
void ExtV4l2::Refresh( void )
{
655
    vlc_object_t *p_obj = (vlc_object_t*)vlc_object_find_name( THEPL, "v4l2" );
656
    help->hide();
657 658
    if( box )
    {
659
        layout()->removeWidget( box );
660 661 662
        delete box;
        box = NULL;
    }
663 664
    if( p_obj )
    {
665
        vlc_value_t val, text;
666 667 668 669
        int i_ret = var_Change( p_obj, "controls", VLC_VAR_GETCHOICES,
                                &val, &text );
        if( i_ret < 0 )
        {
670
            msg_Err( p_intf, "Oops, v4l2 object doesn't have a 'controls' variable." );
671
            help->show();
672 673 674
            vlc_object_release( p_obj );
            return;
        }
675 676

        box = new QGroupBox( this );
677
        layout()->addWidget( box );
678 679 680
        QVBoxLayout *layout = new QVBoxLayout( box );
        box->setLayout( layout );

681 682
        for( int i = 0; i < val.p_list->i_count; i++ )
        {
683
            vlc_value_t vartext;
684
            const char *psz_var = text.p_list->p_values[i].psz_string;
685 686 687 688 689 690

            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
691
            msg_Dbg( p_intf, "v4l2 control \"%" PRIx64 "\": %s (%s)",
692
                     val.p_list->p_values[i].i_int, psz_var, qtu( name ) );
693 694 695 696 697 698

            int i_type = var_Type( p_obj, psz_var );
            switch( i_type & VLC_VAR_TYPE )
            {
                case VLC_VAR_INTEGER:
                {
699
                    QLabel *label = new QLabel( name, box );
700
                    QHBoxLayout *hlayout = new QHBoxLayout();
701 702 703 704
                    hlayout->addWidget( label );
                    int i_val = var_GetInteger( p_obj, psz_var );
                    if( i_type & VLC_VAR_HASCHOICE )
                    {
705
                        QComboBox *combobox = new QComboBox( box );
706
                        combobox->setObjectName( qfu( psz_var ) );
707 708 709 710 711 712 713 714

                        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
715
                                       qlonglong( val2.p_list->p_values[j].i_int) );
716 717 718
                            if( i_val == val2.p_list->p_values[j].i_int )
                                combobox->setCurrentIndex( j );
                        }
719
                        var_FreeList( &val2, &text2 );
720 721 722 723 724 725 726

                        CONNECT( combobox, currentIndexChanged( int ), this,
                                 ValueChange( int ) );
                        hlayout->addWidget( combobox );
                    }
                    else
                    {
727
                        QSlider *slider = new QSlider( box );
728
                        slider->setObjectName( qfu( psz_var ) );
729 730 731 732
                        slider->setOrientation( Qt::Horizontal );
                        vlc_value_t val2;
                        var_Change( p_obj, psz_var, VLC_VAR_GETMIN,
                                    &val2, NULL );
733 734
                        if( val2.i_int < INT_MIN )
                            val2.i_int = INT_MIN; /* FIXME */
735 736 737
                        slider->setMinimum( val2.i_int );
                        var_Change( p_obj, psz_var, VLC_VAR_GETMAX,
                                    &val2, NULL );
738 739
                        if( val2.i_int > INT_MAX )
                            val2.i_int = INT_MAX; /* FIXME */
740
                        slider->setMaximum( val2.i_int );
741 742 743
                        if( !var_Change( p_obj, psz_var, VLC_VAR_GETSTEP,
                                         &val2, NULL ) )
                            slider->setSingleStep( val2.i_int );
744 745 746 747 748 749 750 751 752 753
                        slider->setValue( i_val );
                        CONNECT( slider, valueChanged( int ), this,
                                 ValueChange( int ) );
                        hlayout->addWidget( slider );
                    }
                    layout->addLayout( hlayout );
                    break;
                }
                case VLC_VAR_BOOL:
                {
754
                    QCheckBox *button = new QCheckBox( name, box );
755
                    button->setObjectName( qfu( psz_var ) );
756 757 758 759 760 761 762 763 764
                    button->setChecked( var_GetBool( p_obj, psz_var ) );

                    CONNECT( button, clicked( bool ), this,
                             ValueChange( bool ) );
                    layout->addWidget( button );
                    break;
                }
                case VLC_VAR_VOID:
                {
765 766
                    if( i_type & VLC_VAR_ISCOMMAND )
                    {
767
                        QPushButton *button = new QPushButton( name, box );
768
                        button->setObjectName( qfu( psz_var ) );
769

770 771 772 773 774 775
                        CONNECT( button, clicked( bool ), this,
                                 ValueChange( bool ) );
                        layout->addWidget( button );
                    }
                    else
                    {
776
                        QLabel *label = new QLabel( name, box );
777 778
                        layout->addWidget( label );
                    }
779 780 781 782 783 784 785
                    break;
                }
                default:
                    msg_Warn( p_intf, "Unhandled var type for %s", psz_var );
                    break;
            }
        }
786
        var_FreeList( &val, &text );
787 788 789 790 791
        vlc_object_release( p_obj );
    }
    else
    {
        msg_Dbg( p_intf, "Couldn't find v4l2 instance" );
792 793 794
        help->show();
        if ( isVisible() )
            QTimer::singleShot( 2000, this, SLOT(Refresh()) );
795 796 797 798 799 800 801 802 803 804 805
    }
}

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

void ExtV4l2::ValueChange( int value )
{
    QObject *s = sender();
806
    vlc_object_t *p_obj = (vlc_object_t*)vlc_object_find_name( THEPL, "v4l2" );
807 808
    if( p_obj )
    {
809 810
        QString var = s->objectName();
        int i_type = var_Type( p_obj, qtu( var ) );
811 812 813 814 815 816 817 818
        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();
                }
819
                var_SetInteger( p_obj, qtu( var ), value );
820 821
                break;
            case VLC_VAR_BOOL:
822
                var_SetBool( p_obj, qtu( var ), value );
823 824
                break;
            case VLC_VAR_VOID:
825
                var_TriggerCallback( p_obj, qtu( var ) );
826 827 828 829 830 831 832 833 834 835 836
                break;
        }
        vlc_object_release( p_obj );
    }
    else
    {
        msg_Warn( p_intf, "Oops, v4l2 object isn't available anymore" );
        Refresh();
    }
}

837 838 839 840
/**********************************************************************
 * Sliders
 **********************************************************************/

841 842
FilterSliderData::FilterSliderData( QObject *parent, QSlider *_slider ) :
    QObject( parent ), slider( _slider )
843 844 845
{
    b_save_to_config = false;
}
846

847 848 849 850 851
FilterSliderData::FilterSliderData( QObject *parent,
                                    intf_thread_t *_p_intf,
                                    QSlider *_slider,
                                    QLabel *_label, QLabel *_nameLabel,
                                    const slider_data_t *_p_data ):
852 853
    QObject( parent ), slider( _slider ), valueLabel( _label ),
    nameLabel( _nameLabel ), p_data( _p_data ), p_intf( _p_intf )
854
{
855
    b_save_to_config = false;
856 857
    slider->setMinimum( p_data->f_min / p_data->f_resolution );
    slider->setMaximum( p_data->f_max / p_data->f_resolution );
858
    nameLabel->setText( p_data->descs );
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
    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 )
{
875
    float f = ((float) i) * p_data->f_resolution * p_data->f_visual_multiplier;
876
    valueLabel->setText( QString( p_data->units )
877
                    .prepend( "%1 " )
878 879 880 881 882 883 884 885 886
                    .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 )
    {
887
        if ( var_Type( p_aout, qtu(p_data->name) ) == 0 )
888 889 890 891 892 893
        {
            vlc_object_release( p_aout );
            /* Not found, will try in config */
        }
        else
        {
894
            f = var_GetFloat( p_aout, qtu(p_data->name) );
895 896 897 898 899
            vlc_object_release( p_aout );
            return f;
        }
    }

900
    if ( ! config_FindConfig( VLC_OBJECT(p_intf), qtu(p_data->name) ) )
901 902
        return f;

903
    f = config_GetFloat( p_intf, qtu(p_data->name) );
904 905 906
    return f;
}

907
void FilterSliderData::onValueChanged( int i ) const
908 909 910 911 912
{
    float f = ((float) i) * p_data->f_resolution;
    vlc_object_t *p_aout = (vlc_object_t *) THEMIM->getAout();
    if ( p_aout )
    {
913
        var_SetFloat( p_aout, qtu(p_data->name), f );
914 915 916 917 918
        vlc_object_release( p_aout );
    }
    writeToConfig();
}

919
void FilterSliderData::writeToConfig() const
920
{
921
    if ( !b_save_to_config ) return;
922
    float f = ((float) slider->value()) * p_data->f_resolution;
923 924 925
    config_PutFloat( p_intf, qtu(p_data->name), f );
}

926 927 928 929 930
void FilterSliderData::setSaveToConfig( bool b )
{
    b_save_to_config = b;
}

931 932
AudioFilterControlWidget::AudioFilterControlWidget
( intf_thread_t *_p_intf, QWidget *parent, const char *_name ) :
933
    QWidget( parent ), p_intf( _p_intf ), name( _name ), i_smallfont(0)