]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/extended_panels.cpp
Qt: SoutInputBox: show decoded mrl (fix #8436 part1)
[vlc] / modules / gui / qt4 / components / extended_panels.cpp
1 /*****************************************************************************
2  * extended_panels.cpp : Extended controls panels
3  ****************************************************************************
4  * Copyright (C) 2006-2012 the VideoLAN team
5  * $Id$
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>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * ( at your option ) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #define __STDC_FORMAT_MACROS 1
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <math.h>
33
34 #include <QLabel>
35 #include <QVariant>
36 #include <QString>
37 #include <QFont>
38 #include <QGridLayout>
39 #include <QComboBox>
40 #include <QTimer>
41 #include <QFileDialog>
42 #include <QGraphicsScene>
43 #include <QPainter>
44
45 #include "components/extended_panels.hpp"
46 #include "dialogs/preferences.hpp"
47 #include "qt4.hpp"
48 #include "input_manager.hpp"
49 #include "util/qt_dirs.hpp"
50
51 #include "../../audio_filter/equalizer_presets.h"
52 #include <vlc_intf_strings.h>
53 #include <vlc_vout.h>
54 #include <vlc_modules.h>
55 #include <vlc_plugin.h>
56
57 #include <vlc_charset.h> /* us_strtod */
58
59 static void ChangeVFiltersString( struct intf_thread_t *p_intf, const char *psz_name, bool b_add );
60
61 #if 0
62 class ConfClickHandler : public QObject
63 {
64 public:
65     ConfClickHandler( intf_thread_t *_p_intf, ExtVideo *_e ) : QObject ( _e ) {
66         e = _e; p_intf = _p_intf;
67     }
68     virtual ~ConfClickHandler() {}
69     bool eventFilter( QObject *obj, QEvent *evt )
70     {
71         if( evt->type() == QEvent::MouseButtonPress )
72         {
73             e->gotoConf( obj );
74             return true;
75         }
76         return false;
77     }
78 private:
79     ExtVideo* e;
80     intf_thread_t *p_intf;
81 };
82 #endif
83
84 const QString ModuleFromWidgetName( QObject *obj )
85 {
86     return obj->objectName().replace( "Enable","" );
87 }
88
89 QString OptionFromWidgetName( QObject *obj )
90 {
91     /* Gruik ? ... nah */
92     QString option = obj->objectName().replace( "Slider", "" )
93                                       .replace( "Combo" , "" )
94                                       .replace( "Dial"  , "" )
95                                       .replace( "Check" , "" )
96                                       .replace( "Spin"  , "" )
97                                       .replace( "Text"  , "" );
98     for( char a = 'A'; a <= 'Z'; a++ )
99     {
100         option = option.replace( QString( a ),
101                                  QString( '-' ) + QString( a + 'a' - 'A' ) );
102     }
103     return option;
104 }
105
106 ExtVideo::ExtVideo( intf_thread_t *_p_intf, QTabWidget *_parent ) :
107             QObject( _parent ), p_intf( _p_intf )
108 {
109     ui.setupUi( _parent );
110
111 #define SETUP_VFILTER( widget ) \
112     { \
113         vlc_object_t *p_obj = ( vlc_object_t * ) \
114             vlc_object_find_name( p_intf->p_libvlc, \
115                                   #widget ); \
116         QCheckBox *checkbox = qobject_cast<QCheckBox*>( ui.widget##Enable ); \
117         QGroupBox *groupbox = qobject_cast<QGroupBox*>( ui.widget##Enable ); \
118         if( p_obj ) \
119         { \
120             vlc_object_release( p_obj ); \
121             if( checkbox ) checkbox->setChecked( true ); \
122             else if (groupbox) groupbox->setChecked( true ); \
123         } \
124         else \
125         { \
126             if( checkbox ) checkbox->setChecked( false ); \
127             else if (groupbox)  groupbox->setChecked( false ); \
128         } \
129     } \
130     CONNECT( ui.widget##Enable, clicked(), this, updateFilters() );
131
132
133 #define SETUP_VFILTER_OPTION( widget, signal ) \
134     initComboBoxItems( ui.widget ); \
135     setWidgetValue( ui.widget ); \
136     CONNECT( ui.widget, signal, this, updateFilterOptions() );
137
138     SETUP_VFILTER( adjust )
139     SETUP_VFILTER_OPTION( hueSlider, valueChanged( int ) )
140     SETUP_VFILTER_OPTION( contrastSlider, valueChanged( int ) )
141     SETUP_VFILTER_OPTION( brightnessSlider, valueChanged( int ) )
142     SETUP_VFILTER_OPTION( saturationSlider, valueChanged( int ) )
143     SETUP_VFILTER_OPTION( gammaSlider, valueChanged( int ) )
144     SETUP_VFILTER_OPTION( brightnessThresholdCheck, stateChanged( int ) )
145
146     SETUP_VFILTER( extract )
147     SETUP_VFILTER_OPTION( extractComponentText, textChanged( const QString& ) )
148
149     SETUP_VFILTER( posterize )
150
151     SETUP_VFILTER( colorthres )
152     SETUP_VFILTER_OPTION( colorthresColorText, textChanged( const QString& ) )
153     SETUP_VFILTER_OPTION( colorthresSaturationthresSlider, valueChanged( int ) )
154     SETUP_VFILTER_OPTION( colorthresSimilaritythresSlider, valueChanged( int ) )
155
156     SETUP_VFILTER( sepia )
157     SETUP_VFILTER_OPTION( sepiaIntensitySpin, valueChanged( int ) )
158
159     SETUP_VFILTER( invert )
160
161     SETUP_VFILTER( gradient )
162     SETUP_VFILTER_OPTION( gradientModeCombo, currentIndexChanged( QString ) )
163     SETUP_VFILTER_OPTION( gradientTypeCheck, stateChanged( int ) )
164     SETUP_VFILTER_OPTION( gradientCartoonCheck, stateChanged( int ) )
165
166     SETUP_VFILTER( motionblur )
167     SETUP_VFILTER_OPTION( blurFactorSlider, valueChanged( int ) )
168
169     SETUP_VFILTER( motiondetect )
170
171     SETUP_VFILTER( psychedelic )
172
173     SETUP_VFILTER( sharpen )
174     SETUP_VFILTER_OPTION( sharpenSigmaSlider, valueChanged( int ) )
175
176     SETUP_VFILTER( ripple )
177
178     SETUP_VFILTER( wave )
179
180     SETUP_VFILTER( transform )
181     SETUP_VFILTER_OPTION( transformTypeCombo, currentIndexChanged( QString ) )
182
183     SETUP_VFILTER( rotate )
184     SETUP_VFILTER_OPTION( rotateAngleDial, valueChanged( int ) )
185     ui.rotateAngleDial->setWrapping( true );
186     ui.rotateAngleDial->setNotchesVisible( true );
187
188     SETUP_VFILTER( puzzle )
189     SETUP_VFILTER_OPTION( puzzleRowsSpin, valueChanged( int ) )
190     SETUP_VFILTER_OPTION( puzzleColsSpin, valueChanged( int ) )
191     SETUP_VFILTER_OPTION( puzzleBlackSlotCheck, stateChanged( int ) )
192
193     SETUP_VFILTER( magnify )
194
195     SETUP_VFILTER( clone )
196     SETUP_VFILTER_OPTION( cloneCountSpin, valueChanged( int ) )
197
198     SETUP_VFILTER( wall )
199     SETUP_VFILTER_OPTION( wallRowsSpin, valueChanged( int ) )
200     SETUP_VFILTER_OPTION( wallColsSpin, valueChanged( int ) )
201
202
203     SETUP_VFILTER( erase )
204     SETUP_VFILTER_OPTION( eraseMaskText, editingFinished() )
205     SETUP_VFILTER_OPTION( eraseYSpin, valueChanged( int ) )
206     SETUP_VFILTER_OPTION( eraseXSpin, valueChanged( int ) )
207     BUTTONACT( ui.eraseBrowseBtn, browseEraseFile() );
208
209     SETUP_VFILTER( marq )
210     SETUP_VFILTER_OPTION( marqMarqueeText, textChanged( const QString& ) )
211     SETUP_VFILTER_OPTION( marqPositionCombo, currentIndexChanged( QString ) )
212
213     SETUP_VFILTER( logo )
214     SETUP_VFILTER_OPTION( logoFileText, editingFinished() )
215     SETUP_VFILTER_OPTION( logoYSpin, valueChanged( int ) )
216     SETUP_VFILTER_OPTION( logoXSpin, valueChanged( int ) )
217     SETUP_VFILTER_OPTION( logoOpacitySlider, valueChanged( int ) )
218     BUTTONACT( ui.logoBrowseBtn, browseLogo() );
219
220     SETUP_VFILTER( gradfun )
221     SETUP_VFILTER_OPTION( gradfunRadiusSlider, valueChanged( int ) )
222
223     SETUP_VFILTER( grain )
224     SETUP_VFILTER_OPTION( grainVarianceSlider, valueChanged( int ) )
225
226     SETUP_VFILTER( mirror )
227
228     SETUP_VFILTER( gaussianblur )
229     SETUP_VFILTER_OPTION( gaussianbluSigmaSlider, valueChanged( int ) )
230
231     SETUP_VFILTER( antiflicker )
232     SETUP_VFILTER_OPTION( antiflickerSofteningSizeSlider, valueChanged( int ) )
233
234
235     if( module_exists( "atmo" ) )
236     {
237         SETUP_VFILTER( atmo )
238         SETUP_VFILTER_OPTION( atmoEdgeweightningSlider, valueChanged( int ) )
239         SETUP_VFILTER_OPTION( atmoBrightnessSlider, valueChanged( int ) )
240         SETUP_VFILTER_OPTION( atmoDarknesslimitSlider, valueChanged( int ) )
241         SETUP_VFILTER_OPTION( atmoMeanlengthSlider, valueChanged( int ) )
242         SETUP_VFILTER_OPTION( atmoMeanthresholdSlider, valueChanged( int ) )
243         SETUP_VFILTER_OPTION( atmoPercentnewSlider, valueChanged( int ) )
244         SETUP_VFILTER_OPTION( atmoFiltermodeCombo, currentIndexChanged( int ) )
245         SETUP_VFILTER_OPTION( atmoShowdotsCheck, stateChanged( int ) )
246     }
247     else
248     {
249         _parent->removeTab( _parent->indexOf( ui.tab_atmo ) );
250     }
251
252     SETUP_VFILTER( anaglyph )
253
254 #undef SETUP_VFILTER
255 #undef SETUP_VFILTER_OPTION
256
257     CONNECT( ui.cropTopPx, valueChanged( int ), this, cropChange() );
258     CONNECT( ui.cropBotPx, valueChanged( int ), this, cropChange() );
259     CONNECT( ui.cropLeftPx, valueChanged( int ), this, cropChange() );
260     CONNECT( ui.cropRightPx, valueChanged( int ), this, cropChange() );
261     CONNECT( ui.leftRightCropSync, toggled ( bool ), this, cropChange() );
262     CONNECT( ui.topBotCropSync, toggled ( bool ), this, cropChange() );
263     CONNECT( ui.topBotCropSync, toggled( bool ),
264              ui.cropBotPx, setDisabled( bool ) );
265     CONNECT( ui.leftRightCropSync, toggled( bool ),
266              ui.cropRightPx, setDisabled( bool ) );
267 }
268
269 void ExtVideo::cropChange()
270 {
271     if( ui.topBotCropSync->isChecked() )
272         ui.cropBotPx->setValue( ui.cropTopPx->value() );
273     if( ui.leftRightCropSync->isChecked() )
274         ui.cropRightPx->setValue( ui.cropLeftPx->value() );
275
276     vout_thread_t *p_vout = THEMIM->getVout();
277     if( p_vout )
278     {
279         var_SetInteger( p_vout, "crop-top", ui.cropTopPx->value() );
280         var_SetInteger( p_vout, "crop-bottom", ui.cropBotPx->value() );
281         var_SetInteger( p_vout, "crop-left", ui.cropLeftPx->value() );
282         var_SetInteger( p_vout, "crop-right", ui.cropRightPx->value() );
283         vlc_object_release( p_vout );
284     }
285 }
286
287 void ExtVideo::clean()
288 {
289     ui.cropTopPx->setValue( 0 );
290     ui.cropBotPx->setValue( 0 );
291     ui.cropLeftPx->setValue( 0 );
292     ui.cropRightPx->setValue( 0 );
293 }
294
295 static void ChangeVFiltersString( struct intf_thread_t *p_intf, const char *psz_name, bool b_add )
296 {
297     char *psz_parser, *psz_string;
298     const char *psz_filter_type;
299
300     module_t *p_obj = module_find( psz_name );
301     if( !p_obj )
302     {
303         msg_Err( p_intf, "Unable to find filter module \"%s\".", psz_name );
304         return;
305     }
306
307     if( module_provides( p_obj, "video splitter" ) )
308     {
309         psz_filter_type = "video-splitter";
310     }
311     else if( module_provides( p_obj, "video filter2" ) )
312     {
313         psz_filter_type = "video-filter";
314     }
315     else if( module_provides( p_obj, "sub source" ) )
316     {
317         psz_filter_type = "sub-source";
318     }
319     else if( module_provides( p_obj, "sub filter" ) )
320     {
321         psz_filter_type = "sub-filter";
322     }
323     else
324     {
325         msg_Err( p_intf, "Unknown video filter type." );
326         return;
327     }
328
329     psz_string = config_GetPsz( p_intf, psz_filter_type );
330
331     if( !psz_string ) psz_string = strdup( "" );
332
333     psz_parser = strstr( psz_string, psz_name );
334
335     if( b_add )
336     {
337         if( !psz_parser )
338         {
339             psz_parser = psz_string;
340             if( asprintf( &psz_string, ( *psz_string ) ? "%s:%s" : "%s%s",
341                             psz_string, psz_name ) == -1 )
342             {
343                 free( psz_parser );
344                 return;
345             }
346             free( psz_parser );
347         }
348         else
349         {
350             free( psz_string );
351             return;
352         }
353     }
354     else
355     {
356         if( psz_parser )
357         {
358             if( *( psz_parser + strlen( psz_name ) ) == ':' )
359             {
360                 memmove( psz_parser, psz_parser + strlen( psz_name ) + 1,
361                          strlen( psz_parser + strlen( psz_name ) + 1 ) + 1 );
362             }
363             else
364             {
365                 *psz_parser = '\0';
366             }
367
368             /* Remove trailing : : */
369             size_t i_len = strlen( psz_string );
370             if( i_len > 0 && *( psz_string + i_len - 1 ) == ':' )
371             {
372                 *( psz_string + i_len - 1 ) = '\0';
373             }
374         }
375         else
376         {
377             free( psz_string );
378             return;
379         }
380     }
381     /* Vout is not kept, so put that in the config */
382     config_PutPsz( p_intf, psz_filter_type, psz_string );
383
384     /* Try to set on the fly */
385     if( !strcmp( psz_filter_type, "video-splitter" ) )
386     {
387         playlist_t *p_playlist = pl_Get( p_intf );
388         var_SetString( p_playlist, psz_filter_type, psz_string );
389     }
390     else
391     {
392         vout_thread_t *p_vout = THEMIM->getVout();
393         if( p_vout )
394         {
395             var_SetString( p_vout, psz_filter_type, psz_string );
396             vlc_object_release( p_vout );
397         }
398     }
399
400     free( psz_string );
401 }
402
403 void ExtVideo::updateFilters()
404 {
405     QString module = ModuleFromWidgetName( sender() );
406
407     QCheckBox *checkbox = qobject_cast<QCheckBox*>( sender() );
408     QGroupBox *groupbox = qobject_cast<QGroupBox*>( sender() );
409
410     ChangeVFiltersString( p_intf, qtu( module ),
411                           checkbox ? checkbox->isChecked()
412                                    : groupbox->isChecked() );
413 }
414
415 #define UPDATE_AND_APPLY_TEXT( widget, file ) \
416     CONNECT( ui.widget, textChanged( const QString& ), \
417              this, updateFilterOptions() ); \
418     ui.widget->setText( toNativeSeparators( file ) ); \
419     ui.widget->disconnect( SIGNAL( textChanged( const QString& ) ) );
420
421 void ExtVideo::browseLogo()
422 {
423     QString file = QFileDialog::getOpenFileName( NULL, qtr( "Logo filenames" ),
424                    p_intf->p_sys->filepath, "Images (*.png *.jpg);;All (*)" );
425
426     UPDATE_AND_APPLY_TEXT( logoFileText, file );
427 }
428
429 void ExtVideo::browseEraseFile()
430 {
431     QString file = QFileDialog::getOpenFileName( NULL, qtr( "Image mask" ),
432                    p_intf->p_sys->filepath, "Images (*.png *.jpg);;All (*)" );
433
434     UPDATE_AND_APPLY_TEXT( eraseMaskText, file );
435 }
436
437 #undef UPDATE_AND_APPLY_TEXT
438
439 void ExtVideo::initComboBoxItems( QObject *widget )
440 {
441     QComboBox *combobox = qobject_cast<QComboBox*>( widget );
442     if( !combobox ) return;
443
444     QString option = OptionFromWidgetName( widget );
445     module_config_t *p_item = config_FindConfig( VLC_OBJECT( p_intf ),
446                                                  qtu( option ) );
447     if( p_item == NULL )
448     {
449         msg_Err( p_intf, "Couldn't find option \"%s\".", qtu( option ) );
450         return;
451     }
452
453     if( p_item->i_type == CONFIG_ITEM_INTEGER
454      || p_item->i_type == CONFIG_ITEM_BOOL )
455     {
456         int64_t *values;
457         char **texts;
458         ssize_t count = config_GetIntChoices( VLC_OBJECT( p_intf ),
459                                               qtu( option ), &values, &texts );
460         for( ssize_t i = 0; i < count; i++ )
461         {
462             combobox->addItem( qtr( texts[i] ), qlonglong(values[i]) );
463             free( texts[i] );
464         }
465         free( texts );
466         free( values );
467     }
468     else if( p_item->i_type == CONFIG_ITEM_STRING )
469     {
470         char **values;
471         char **texts;
472         ssize_t count = config_GetPszChoices( VLC_OBJECT( p_intf ),
473                                               qtu( option ), &values, &texts );
474         for( ssize_t i = 0; i < count; i++ )
475         {
476             combobox->addItem( qtr( texts[i] ), qfu(values[i]) );
477             free( texts[i] );
478             free( values[i] );
479         }
480         free( texts );
481         free( values );
482     }
483 }
484
485 void ExtVideo::setWidgetValue( QObject *widget )
486 {
487     QString module = ModuleFromWidgetName( widget->parent() );
488     //std::cout << "Module name: " << module.toStdString() << std::endl;
489     QString option = OptionFromWidgetName( widget );
490     //std::cout << "Option name: " << option.toStdString() << std::endl;
491
492     vlc_object_t *p_obj = ( vlc_object_t * )
493         vlc_object_find_name( p_intf->p_libvlc, qtu( module ) );
494     int i_type;
495     vlc_value_t val;
496
497     if( !p_obj )
498     {
499 #if 0
500         msg_Dbg( p_intf,
501                  "Module instance %s not found, looking in config values.",
502                  qtu( module ) );
503 #endif
504         i_type = config_GetType( p_intf, qtu( option ) ) & VLC_VAR_CLASS;
505         switch( i_type )
506         {
507             case VLC_VAR_INTEGER:
508             case VLC_VAR_BOOL:
509                 val.i_int = config_GetInt( p_intf, qtu( option ) );
510                 break;
511             case VLC_VAR_FLOAT:
512                 val.f_float = config_GetFloat( p_intf, qtu( option ) );
513                 break;
514             case VLC_VAR_STRING:
515                 val.psz_string = config_GetPsz( p_intf, qtu( option ) );
516                 break;
517         }
518     }
519     else
520     {
521         i_type = var_Type( p_obj, qtu( option ) ) & VLC_VAR_CLASS;
522         var_Get( p_obj, qtu( option ), &val );
523         vlc_object_release( p_obj );
524     }
525
526     /* Try to cast to all the widgets we're likely to encounter. Only
527      * one of the casts is expected to work. */
528     QSlider        *slider        = qobject_cast<QSlider*>       ( widget );
529     QCheckBox      *checkbox      = qobject_cast<QCheckBox*>     ( widget );
530     QSpinBox       *spinbox       = qobject_cast<QSpinBox*>      ( widget );
531     QDoubleSpinBox *doublespinbox = qobject_cast<QDoubleSpinBox*>( widget );
532     QDial          *dial          = qobject_cast<QDial*>         ( widget );
533     QLineEdit      *lineedit      = qobject_cast<QLineEdit*>     ( widget );
534     QComboBox      *combobox      = qobject_cast<QComboBox*>     ( widget );
535
536     if( i_type == VLC_VAR_INTEGER || i_type == VLC_VAR_BOOL )
537     {
538         if( slider )        slider->setValue( val.i_int );
539         else if( checkbox ) checkbox->setCheckState( val.i_int? Qt::Checked
540                                                               : Qt::Unchecked );
541         else if( spinbox )  spinbox->setValue( val.i_int );
542         else if( dial )     dial->setValue( ( 540-val.i_int )%360 );
543         else if( lineedit )
544         {
545             char str[30];
546             snprintf( str, sizeof(str), "%06"PRIX64, val.i_int );
547             lineedit->setText( str );
548         }
549         else if( combobox ) combobox->setCurrentIndex(
550                             combobox->findData( qlonglong(val.i_int) ) );
551         else msg_Warn( p_intf, "Could not find the correct Integer widget" );
552     }
553     else if( i_type == VLC_VAR_FLOAT )
554     {
555         if( slider ) slider->setValue( ( int )( val.f_float*( double )slider->tickInterval() ) ); /* hack alert! */
556         else if( doublespinbox ) doublespinbox->setValue( val.f_float );
557         else if( dial ) dial->setValue( (540 - lroundf(val.f_float)) % 360 );
558         else msg_Warn( p_intf, "Could not find the correct Float widget" );
559     }
560     else if( i_type == VLC_VAR_STRING )
561     {
562         if( lineedit ) lineedit->setText( qfu( val.psz_string ) );
563         else if( combobox ) combobox->setCurrentIndex(
564                             combobox->findData( qfu( val.psz_string ) ) );
565         else msg_Warn( p_intf, "Could not find the correct String widget" );
566         free( val.psz_string );
567     }
568     else
569         if( p_obj )
570             msg_Err( p_intf,
571                      "Module %s's %s variable is of an unsupported type ( %d )",
572                      qtu( module ),
573                      qtu( option ),
574                      i_type );
575 }
576
577 void ExtVideo::updateFilterOptions()
578 {
579     QString module = ModuleFromWidgetName( sender()->parent() );
580     //std::cout << "Module name: " << module.toStdString() << std::endl;
581     QString option = OptionFromWidgetName( sender() );
582     //std::cout << "Option name: " << option.toStdString() << std::endl;
583
584     vlc_object_t *p_obj = ( vlc_object_t * )
585         vlc_object_find_name( p_intf->p_libvlc, qtu( module ) );
586     int i_type;
587     bool b_is_command;
588     if( !p_obj )
589     {
590         msg_Warn( p_intf, "Module %s not found. You'll need to restart the filter to take the change into account.", qtu( module ) );
591         i_type = config_GetType( p_intf, qtu( option ) );
592         b_is_command = false;
593     }
594     else
595     {
596         i_type = var_Type( p_obj, qtu( option ) );
597         if( i_type == 0 )
598             i_type = config_GetType( p_intf, qtu( option ) );
599         b_is_command = ( i_type & VLC_VAR_ISCOMMAND );
600     }
601
602     /* Try to cast to all the widgets we're likely to encounter. Only
603      * one of the casts is expected to work. */
604     QSlider        *slider        = qobject_cast<QSlider*>       ( sender() );
605     QCheckBox      *checkbox      = qobject_cast<QCheckBox*>     ( sender() );
606     QSpinBox       *spinbox       = qobject_cast<QSpinBox*>      ( sender() );
607     QDoubleSpinBox *doublespinbox = qobject_cast<QDoubleSpinBox*>( sender() );
608     QDial          *dial          = qobject_cast<QDial*>         ( sender() );
609     QLineEdit      *lineedit      = qobject_cast<QLineEdit*>     ( sender() );
610     QComboBox      *combobox      = qobject_cast<QComboBox*>     ( sender() );
611
612     i_type &= VLC_VAR_CLASS;
613     if( i_type == VLC_VAR_INTEGER || i_type == VLC_VAR_BOOL )
614     {
615         int i_int = 0;
616         if( slider )        i_int = slider->value();
617         else if( checkbox ) i_int = checkbox->checkState() == Qt::Checked;
618         else if( spinbox )  i_int = spinbox->value();
619         else if( dial )     i_int = ( 540-dial->value() )%360;
620         else if( lineedit ) i_int = lineedit->text().toInt( NULL,16 );
621         else if( combobox ) i_int = combobox->itemData( combobox->currentIndex() ).toInt();
622         else msg_Warn( p_intf, "Could not find the correct Integer widget" );
623         config_PutInt( p_intf, qtu( option ), i_int );
624         if( b_is_command )
625         {
626             if( i_type == VLC_VAR_INTEGER )
627                 var_SetInteger( p_obj, qtu( option ), i_int );
628             else
629                 var_SetBool( p_obj, qtu( option ), i_int );
630         }
631     }
632     else if( i_type == VLC_VAR_FLOAT )
633     {
634         double f_float = 0;
635         if( slider )             f_float = ( double )slider->value()
636                                          / ( double )slider->tickInterval(); /* hack alert! */
637         else if( doublespinbox ) f_float = doublespinbox->value();
638         else if( dial ) f_float = (540 - dial->value()) % 360;
639         else if( lineedit ) f_float = lineedit->text().toDouble();
640         else msg_Warn( p_intf, "Could not find the correct Float widget" );
641         config_PutFloat( p_intf, qtu( option ), f_float );
642         if( b_is_command )
643             var_SetFloat( p_obj, qtu( option ), f_float );
644     }
645     else if( i_type == VLC_VAR_STRING )
646     {
647         QString val;
648         if( lineedit )
649             val = lineedit->text();
650         else if( combobox )
651             val = combobox->itemData( combobox->currentIndex() ).toString();
652         else
653             msg_Warn( p_intf, "Could not find the correct String widget" );
654         config_PutPsz( p_intf, qtu( option ), qtu( val ) );
655         if( b_is_command )
656             var_SetString( p_obj, qtu( option ), qtu( val ) );
657     }
658     else
659         msg_Err( p_intf,
660                  "Module %s's %s variable is of an unsupported type ( %d )",
661                  qtu( module ),
662                  qtu( option ),
663                  i_type );
664
665     if( !b_is_command )
666     {
667         msg_Warn( p_intf, "Module %s's %s variable isn't a command. Brute-restarting the filter.",
668                  qtu( module ),
669                  qtu( option ) );
670         ChangeVFiltersString( p_intf, qtu( module ), false );
671         ChangeVFiltersString( p_intf, qtu( module ), true );
672     }
673
674     if( p_obj ) vlc_object_release( p_obj );
675 }
676
677 #if 0
678 void ExtVideo::gotoConf( QObject* src )
679 {
680 #define SHOWCONF( module ) \
681     if( src->objectName().contains( module ) ) \
682     { \
683         PrefsDialog::getInstance( p_intf )->showModulePrefs( module ); \
684         return; \
685     }
686     SHOWCONF( "clone" );
687     SHOWCONF( "magnify" );
688     SHOWCONF( "wave" );
689     SHOWCONF( "ripple" );
690     SHOWCONF( "invert" );
691     SHOWCONF( "puzzle" );
692     SHOWCONF( "wall" );
693     SHOWCONF( "gradient" );
694     SHOWCONF( "colorthres" );
695     SHOWCONF( "anaglyph" )
696 }
697 #endif
698
699 /**********************************************************************
700  * v4l2 controls
701  **********************************************************************/
702
703 ExtV4l2::ExtV4l2( intf_thread_t *_p_intf, QWidget *_parent )
704     : QWidget( _parent ), p_intf( _p_intf ), box( NULL )
705 {
706     QVBoxLayout *layout = new QVBoxLayout( this );
707     help = new QLabel( qtr("No v4l2 instance found.\n"
708       "Please check that the device has been opened with VLC and is playing.\n\n"
709       "Controls will automatically appear here.")
710       , this );
711     help->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
712     layout->addWidget( help );
713     setLayout( layout );
714 }
715
716 void ExtV4l2::showEvent( QShowEvent *event )
717 {
718     QWidget::showEvent( event );
719     Refresh();
720 }
721
722 void ExtV4l2::Refresh( void )
723 {
724     vlc_object_t *p_obj = (vlc_object_t*)vlc_object_find_name( pl_Get(p_intf), "v4l2" );
725     help->hide();
726     if( box )
727     {
728         layout()->removeWidget( box );
729         delete box;
730         box = NULL;
731     }
732     if( p_obj )
733     {
734         vlc_value_t val, text;
735         int i_ret = var_Change( p_obj, "controls", VLC_VAR_GETCHOICES,
736                                 &val, &text );
737         if( i_ret < 0 )
738         {
739             msg_Err( p_intf, "Oops, v4l2 object doesn't have a 'controls' variable." );
740             help->show();
741             vlc_object_release( p_obj );
742             return;
743         }
744
745         box = new QGroupBox( this );
746         layout()->addWidget( box );
747         QVBoxLayout *layout = new QVBoxLayout( box );
748         box->setLayout( layout );
749
750         for( int i = 0; i < val.p_list->i_count; i++ )
751         {
752             vlc_value_t vartext;
753             const char *psz_var = text.p_list->p_values[i].psz_string;
754
755             if( var_Change( p_obj, psz_var, VLC_VAR_GETTEXT, &vartext, NULL ) )
756                 continue;
757
758             QString name = qtr( vartext.psz_string );
759             free( vartext.psz_string );
760             msg_Dbg( p_intf, "v4l2 control \"%"PRIx64"\": %s (%s)",
761                      val.p_list->p_values[i].i_int, psz_var, qtu( name ) );
762
763             int i_type = var_Type( p_obj, psz_var );
764             switch( i_type & VLC_VAR_TYPE )
765             {
766                 case VLC_VAR_INTEGER:
767                 {
768                     QLabel *label = new QLabel( name, box );
769                     QHBoxLayout *hlayout = new QHBoxLayout();
770                     hlayout->addWidget( label );
771                     int i_val = var_GetInteger( p_obj, psz_var );
772                     if( i_type & VLC_VAR_HASCHOICE )
773                     {
774                         QComboBox *combobox = new QComboBox( box );
775                         combobox->setObjectName( qfu( psz_var ) );
776
777                         vlc_value_t val2, text2;
778                         var_Change( p_obj, psz_var, VLC_VAR_GETCHOICES,
779                                     &val2, &text2 );
780                         for( int j = 0; j < val2.p_list->i_count; j++ )
781                         {
782                             combobox->addItem(
783                                        text2.p_list->p_values[j].psz_string,
784                                        qlonglong( val2.p_list->p_values[j].i_int) );
785                             if( i_val == val2.p_list->p_values[j].i_int )
786                                 combobox->setCurrentIndex( j );
787                         }
788                         var_FreeList( &val2, &text2 );
789
790                         CONNECT( combobox, currentIndexChanged( int ), this,
791                                  ValueChange( int ) );
792                         hlayout->addWidget( combobox );
793                     }
794                     else
795                     if( (i_type & VLC_VAR_HASMIN) && (i_type & VLC_VAR_HASMAX) )
796                     {
797                         QSlider *slider = new QSlider( box );
798                         slider->setObjectName( qfu( psz_var ) );
799                         slider->setOrientation( Qt::Horizontal );
800                         vlc_value_t val2;
801                         var_Change( p_obj, psz_var, VLC_VAR_GETMIN,
802                                     &val2, NULL );
803                         if( val2.i_int < INT_MIN )
804                             val2.i_int = INT_MIN; /* FIXME */
805                         slider->setMinimum( val2.i_int );
806                         var_Change( p_obj, psz_var, VLC_VAR_GETMAX,
807                                     &val2, NULL );
808                         if( val2.i_int > INT_MAX )
809                             val2.i_int = INT_MAX; /* FIXME */
810                         slider->setMaximum( val2.i_int );
811                         if( !var_Change( p_obj, psz_var, VLC_VAR_GETSTEP,
812                                          &val2, NULL ) )
813                             slider->setSingleStep( val2.i_int );
814                         slider->setValue( i_val );
815                         CONNECT( slider, valueChanged( int ), this,
816                                  ValueChange( int ) );
817                         hlayout->addWidget( slider );
818                     }
819                     else
820                     {
821                         QSpinBox *spinBox = new QSpinBox( box );
822                         spinBox->setObjectName( qfu( psz_var ) );
823                         spinBox->setMinimum( INT_MIN );
824                         spinBox->setMaximum( INT_MAX );
825                         spinBox->setValue( i_val );
826                         CONNECT( spinBox, valueChanged( int ), this,
827                                  ValueChange( int ) );
828                         hlayout->addWidget( spinBox );
829                     }
830                     layout->addLayout( hlayout );
831                     break;
832                 }
833                 case VLC_VAR_BOOL:
834                 {
835                     QCheckBox *button = new QCheckBox( name, box );
836                     button->setObjectName( qfu( psz_var ) );
837                     button->setChecked( var_GetBool( p_obj, psz_var ) );
838
839                     CONNECT( button, clicked( bool ), this,
840                              ValueChange( bool ) );
841                     layout->addWidget( button );
842                     break;
843                 }
844                 case VLC_VAR_VOID:
845                 {
846                     if( i_type & VLC_VAR_ISCOMMAND )
847                     {
848                         QPushButton *button = new QPushButton( name, box );
849                         button->setObjectName( qfu( psz_var ) );
850
851                         CONNECT( button, clicked( bool ), this,
852                                  ValueChange( bool ) );
853                         layout->addWidget( button );
854                     }
855                     else
856                     {
857                         QLabel *label = new QLabel( name, box );
858                         layout->addWidget( label );
859                     }
860                     break;
861                 }
862                 default:
863                     msg_Warn( p_intf, "Unhandled var type for %s", psz_var );
864                     break;
865             }
866         }
867         var_FreeList( &val, &text );
868         vlc_object_release( p_obj );
869     }
870     else
871     {
872         msg_Dbg( p_intf, "Couldn't find v4l2 instance" );
873         help->show();
874         if ( isVisible() )
875             QTimer::singleShot( 2000, this, SLOT(Refresh()) );
876     }
877 }
878
879 void ExtV4l2::ValueChange( bool value )
880 {
881     ValueChange( (int)value );
882 }
883
884 void ExtV4l2::ValueChange( int value )
885 {
886     QObject *s = sender();
887     vlc_object_t *p_obj = (vlc_object_t*)vlc_object_find_name( pl_Get(p_intf), "v4l2" );
888     if( p_obj )
889     {
890         QString var = s->objectName();
891         int i_type = var_Type( p_obj, qtu( var ) );
892         switch( i_type & VLC_VAR_TYPE )
893         {
894             case VLC_VAR_INTEGER:
895                 if( i_type & VLC_VAR_HASCHOICE )
896                 {
897                     QComboBox *combobox = qobject_cast<QComboBox*>( s );
898                     value = combobox->itemData( value ).toInt();
899                 }
900                 var_SetInteger( p_obj, qtu( var ), value );
901                 break;
902             case VLC_VAR_BOOL:
903                 var_SetBool( p_obj, qtu( var ), value );
904                 break;
905             case VLC_VAR_VOID:
906                 var_TriggerCallback( p_obj, qtu( var ) );
907                 break;
908         }
909         vlc_object_release( p_obj );
910     }
911     else
912     {
913         msg_Warn( p_intf, "Oops, v4l2 object isn't available anymore" );
914         Refresh();
915     }
916 }
917
918 /**********************************************************************
919  * Sliders
920  **********************************************************************/
921
922 FilterSliderData::FilterSliderData( QObject *parent, QSlider *_slider ) :
923     QObject( parent ), slider( _slider )
924 {
925     b_save_to_config = false;
926 }
927
928 FilterSliderData::FilterSliderData( QObject *parent,
929                                     intf_thread_t *_p_intf,
930                                     QSlider *_slider,
931                                     QLabel *_label, QLabel *_nameLabel,
932                                     const slider_data_t *_p_data ):
933     QObject( parent ), slider( _slider ), valueLabel( _label ),
934     nameLabel( _nameLabel ), p_data( _p_data ), p_intf( _p_intf )
935 {
936     b_save_to_config = false;
937     slider->setMinimum( p_data->f_min / p_data->f_resolution );
938     slider->setMaximum( p_data->f_max / p_data->f_resolution );
939     nameLabel->setText( p_data->descs );
940     CONNECT( slider, valueChanged( int ), this, updateText( int ) );
941     setValue( initialValue() );
942     /* In case current == min|max text would not be first updated */
943     if ( slider->value() == slider->maximum() ||
944          slider->value() == slider->minimum() )
945         updateText( slider->value() );
946     CONNECT( slider, valueChanged( int ), this, onValueChanged( int ) );
947 }
948
949 void FilterSliderData::setValue( float f )
950 {
951     slider->setValue( f / p_data->f_resolution );
952 }
953
954 void FilterSliderData::updateText( int i )
955 {
956     float f = ((float) i) * p_data->f_resolution * p_data->f_visual_multiplier;
957     valueLabel->setText( QString( p_data->units )
958                     .prepend( "%1 " )
959                     .arg( QString::number( f, 'f', 1 ) ) );
960 }
961
962 float FilterSliderData::initialValue()
963 {
964     vlc_object_t *p_aout = (vlc_object_t *) THEMIM->getAout();
965     float f = p_data->f_value;
966     if( p_aout )
967     {
968         if ( var_Type( p_aout, qtu(p_data->name) ) == 0 )
969         {
970             vlc_object_release( p_aout );
971             /* Not found, will try in config */
972         }
973         else
974         {
975             f = var_GetFloat( p_aout, qtu(p_data->name) );
976             vlc_object_release( p_aout );
977             return f;
978         }
979     }
980
981     if ( ! config_FindConfig( VLC_OBJECT(p_intf), qtu(p_data->name) ) )
982         return f;
983
984     f = config_GetFloat( p_intf, qtu(p_data->name) );
985     return f;
986 }
987
988 void FilterSliderData::onValueChanged( int i ) const
989 {
990     float f = ((float) i) * p_data->f_resolution;
991     vlc_object_t *p_aout = (vlc_object_t *) THEMIM->getAout();
992     if ( p_aout )
993     {
994         var_SetFloat( p_aout, qtu(p_data->name), f );
995         vlc_object_release( p_aout );
996     }
997     writeToConfig();
998 }
999
1000 void FilterSliderData::writeToConfig() const
1001 {
1002     if ( !b_save_to_config ) return;
1003     float f = ((float) slider->value()) * p_data->f_resolution;
1004     config_PutFloat( p_intf, qtu(p_data->name), f );
1005 }
1006
1007 void FilterSliderData::setSaveToConfig( bool b )
1008 {
1009     b_save_to_config = b;
1010 }
1011
1012 AudioFilterControlWidget::AudioFilterControlWidget
1013 ( intf_thread_t *_p_intf, QWidget *parent, const char *_name ) :
1014     QWidget( parent ), p_intf( _p_intf ), name( _name ), i_smallfont(0)
1015 {}
1016
1017 void AudioFilterControlWidget::build()
1018 {
1019     QFont smallFont = QApplication::font();
1020     smallFont.setPointSize( smallFont.pointSize() + i_smallfont );
1021
1022     QVBoxLayout *layout = new QVBoxLayout( this );
1023     slidersBox = new QGroupBox( qtr( "Enable" ) );
1024     slidersBox->setCheckable( true );
1025     layout->addWidget( slidersBox );
1026
1027     QGridLayout *ctrlLayout = new QGridLayout( slidersBox );
1028
1029     int i = 0;
1030     foreach( const FilterSliderData::slider_data_t &data, controls )
1031     {
1032         QSlider *slider = new QSlider( Qt::Vertical );
1033         QLabel *valueLabel = new QLabel();
1034         valueLabel->setFont( smallFont );
1035         valueLabel->setAlignment( Qt::AlignHCenter );
1036         QLabel *nameLabel = new QLabel();
1037         nameLabel->setFont( smallFont );
1038         nameLabel->setAlignment( Qt::AlignHCenter );
1039         FilterSliderData *filter =
1040             new FilterSliderData( this, p_intf,
1041                                   slider, valueLabel, nameLabel, & data );
1042         ctrlLayout->addWidget( slider, 0, i, Qt::AlignHCenter );
1043         ctrlLayout->addWidget( valueLabel, 1, i, Qt::AlignHCenter );
1044         ctrlLayout->addWidget( nameLabel, 2, i, Qt::AlignHCenter );
1045         i++;
1046         sliderDatas << filter;
1047     }
1048
1049     vlc_object_t *p_aout = (vlc_object_t *)THEMIM->getAout();
1050     char *psz_af;
1051     if( p_aout )
1052     {
1053         psz_af = var_GetNonEmptyString( p_aout, "audio-filter" );
1054         vlc_object_release( p_aout );
1055     }
1056     else
1057         psz_af = config_GetPsz( p_intf, "audio-filter" );
1058
1059     if( psz_af && strstr( psz_af, qtu(name) ) != NULL )
1060         slidersBox->setChecked( true );
1061     else
1062         slidersBox->setChecked( false );
1063     CONNECT( slidersBox, toggled(bool), this, enable(bool) );
1064
1065     free( psz_af );
1066 }
1067
1068 AudioFilterControlWidget::~AudioFilterControlWidget()
1069 {
1070
1071 }
1072
1073 void AudioFilterControlWidget::enable( bool b_enable ) const
1074 {
1075     playlist_EnableAudioFilter( THEPL, qtu(name), b_enable );
1076 }
1077
1078 void AudioFilterControlWidget::setSaveToConfig( bool b_save )
1079 {
1080     foreach( FilterSliderData *f, sliderDatas )
1081         f->setSaveToConfig( b_save );
1082 }
1083
1084 /**********************************************************************
1085  * Equalizer
1086  **********************************************************************/
1087
1088 EqualizerSliderData::EqualizerSliderData( QObject *parent, intf_thread_t *_p_intf,
1089                                           QSlider *slider, QLabel *_label,
1090                                           QLabel *_nameLabel, const slider_data_t *_p_data,
1091                                           int _index )
1092     : FilterSliderData( parent, slider ), index( _index )
1093 {
1094     p_intf = _p_intf;
1095     valueLabel = _label;
1096     nameLabel = _nameLabel;
1097     p_data = _p_data;
1098
1099     slider->setMinimum( p_data->f_min / p_data->f_resolution );
1100     slider->setMaximum( p_data->f_max / p_data->f_resolution );
1101     nameLabel->setText( p_data->descs );
1102     CONNECT( slider, valueChanged( int ), this, updateText( int ) );
1103     setValue( initialValue() );
1104     updateText( slider->value() );
1105     CONNECT( slider, valueChanged( int ), this, onValueChanged( int ) );
1106 }
1107
1108 QStringList EqualizerSliderData::getBandsFromAout() const
1109 {
1110     vlc_object_t *p_aout = (vlc_object_t *) THEMIM->getAout();
1111     QStringList bands;
1112     if( p_aout )
1113     {
1114         if ( var_Type( p_aout, qtu(p_data->name) ) == VLC_VAR_STRING )
1115         {
1116             char *psz_bands = var_GetString( p_aout, qtu(p_data->name) );
1117             if ( psz_bands )
1118             {
1119                 bands = QString( psz_bands ).split( " ", QString::SkipEmptyParts );
1120                 free( psz_bands );
1121             }
1122         }
1123         vlc_object_release( p_aout );
1124     }
1125
1126     if ( bands.count() ) return bands;
1127     /* Or try config then */
1128
1129     if ( ! config_FindConfig( VLC_OBJECT(p_intf), qtu(p_data->name) ) )
1130         return bands;
1131
1132     char *psz_bands = config_GetPsz( p_intf, qtu(p_data->name) );
1133     if ( psz_bands )
1134     {
1135         bands = QString( psz_bands ).split( " ", QString::SkipEmptyParts );
1136         free( psz_bands );
1137     }
1138
1139     return bands;
1140 }
1141
1142 float EqualizerSliderData::initialValue()
1143 {
1144     float f = p_data->f_value;
1145     QStringList bands = getBandsFromAout();
1146
1147     if ( bands.count() > index )
1148         f = QLocale( QLocale::C ).toFloat( bands[ index ] );
1149
1150     return f;
1151 }
1152
1153 void EqualizerSliderData::onValueChanged( int i ) const
1154 {
1155     QStringList bands = getBandsFromAout();
1156     if ( bands.count() > index )
1157     {
1158         float f = ((float) i) * p_data->f_resolution;
1159         bands[ index ] = QLocale( QLocale::C ).toString( f );
1160         vlc_object_t *p_aout = (vlc_object_t *) THEMIM->getAout();
1161         if ( p_aout )
1162         {
1163             var_SetString( p_aout, qtu(p_data->name), qtu(bands.join( " " )) );
1164             vlc_object_release( p_aout );
1165         }
1166         writeToConfig();
1167     }
1168 }
1169
1170 void EqualizerSliderData::writeToConfig() const
1171 {
1172     if ( !b_save_to_config ) return;
1173     QStringList bands = getBandsFromAout();
1174     if ( bands.count() > index )
1175     {
1176         float f = (float) slider->value() * p_data->f_resolution;
1177         bands[ index ] = QLocale( QLocale::C ).toString( f );
1178         config_PutPsz( p_intf, qtu(p_data->name), qtu(bands.join( " " )) );
1179     }
1180 }
1181
1182 Equalizer::Equalizer( intf_thread_t *p_intf, QWidget *parent )
1183     : AudioFilterControlWidget( p_intf, parent, "equalizer" )
1184 {
1185     i_smallfont = -3;
1186     bool b_vlcBands = var_InheritBool( p_intf, "equalizer-vlcfreqs" );
1187
1188     const FilterSliderData::slider_data_t vlc_bands[10] =
1189     {
1190         { "equalizer-bands", qtr("60 Hz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1191         { "equalizer-bands", qtr("170 Hz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1192         { "equalizer-bands", qtr("310 Hz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1193         { "equalizer-bands", qtr("600 Hz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1194         { "equalizer-bands", qtr("1 KHz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1195         { "equalizer-bands", qtr("3 KHz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1196         { "equalizer-bands", qtr("6 KHz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1197         { "equalizer-bands", qtr("12 KHz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1198         { "equalizer-bands", qtr("14 KHz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1199         { "equalizer-bands", qtr("16 KHz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1200     };
1201     const FilterSliderData::slider_data_t iso_bands[10] =
1202     {
1203         { "equalizer-bands", qtr("31 Hz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1204         { "equalizer-bands", qtr("63 Hz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1205         { "equalizer-bands", qtr("125 Hz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1206         { "equalizer-bands", qtr("250 Hz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1207         { "equalizer-bands", qtr("500 Hz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1208         { "equalizer-bands", qtr("1 KHz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1209         { "equalizer-bands", qtr("2 KHz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1210         { "equalizer-bands", qtr("4 KHz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1211         { "equalizer-bands", qtr("8 KHz"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1212         { "equalizer-bands", qtr("16 KHz"), qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 },
1213     };
1214     const FilterSliderData::slider_data_t preamp_vals =
1215         { "equalizer-preamp", qtr("Preamp"),  qtr("dB"), -20.0f, 20.0f, 0.0f, 0.1f, 1.0 };
1216
1217     for( int i=0; i<10 ;i++ ) controls.append( (b_vlcBands) ? vlc_bands[i] : iso_bands[i] );
1218     preamp_values = preamp_vals;
1219     build();
1220 }
1221
1222 void Equalizer::build()
1223 {
1224     QFont smallFont = QApplication::font();
1225     smallFont.setPointSize( smallFont.pointSize() + i_smallfont );
1226
1227     Ui::EqualizerWidget ui;
1228     ui.setupUi( this );
1229
1230     QGridLayout *ctrlLayout = new QGridLayout( ui.slidersPlaceholder );
1231
1232     /* set up preamp control */
1233     ui.preampLabel->setFont( smallFont );
1234     ui.preampValue->setFont( smallFont );
1235     preamp = new FilterSliderData( this, p_intf,
1236         ui.preampSlider, ui.preampValue, ui.preampLabel, & preamp_values );
1237
1238     /* fix sliders spacing accurately */
1239     int i_width = qMax( QFontMetrics( smallFont ).width( "500 Hz" ),
1240                         QFontMetrics( smallFont ).width( "-20.0 dB" ) );
1241     int i = 0;
1242     foreach( const FilterSliderData::slider_data_t &data, controls )
1243     {
1244         QSlider *slider = new QSlider( Qt::Vertical );
1245         slider->setMinimumWidth( i_width );
1246         QLabel *valueLabel = new QLabel();
1247         valueLabel->setFont( smallFont );
1248         valueLabel->setAlignment( Qt::AlignHCenter );
1249         QLabel *nameLabel = new QLabel();
1250         nameLabel->setFont( smallFont );
1251         nameLabel->setAlignment( Qt::AlignHCenter );
1252         EqualizerSliderData *filter =
1253             new EqualizerSliderData( this, p_intf,
1254                                      slider, valueLabel, nameLabel, & data, i );
1255         ctrlLayout->addWidget( slider, 0, i, Qt::AlignHCenter );
1256         ctrlLayout->addWidget( valueLabel, 2, i, Qt::AlignHCenter );
1257         ctrlLayout->addWidget( nameLabel, 1, i, Qt::AlignHCenter );
1258         sliderDatas << filter; /* keep track for applying presets */
1259         i++;
1260     }
1261
1262     /* Add the listed presets */
1263     ui.presetsCombo->addItem( "", QVariant() ); /* 1st entry = custom/modified */
1264     for( i = 0 ; i < NB_PRESETS ; i ++ )
1265     {
1266         QGraphicsScene scene;
1267         QPixmap icon( 40, 40 );
1268         icon.fill( Qt::transparent );
1269         QPainter painter( &icon );
1270         for ( int j = 0; j < eqz_preset_10b[i].i_band; j++ )
1271         {
1272             float f_value = eqz_preset_10b[i].f_amp[j];
1273             if ( f_value > 20.0 ) f_value = 20.0;
1274             if ( f_value < -20.0 ) f_value = -20.0;
1275             QRectF shape( j, 20.0 - f_value, 1, f_value );
1276             scene.addRect( shape, QPen(), palette().brush( QPalette::WindowText ) );
1277         }
1278         scene.addLine( 0.0, 20.0, eqz_preset_10b[i].i_band, 20.0,
1279                        palette().color( QPalette::WindowText ) );
1280         scene.setSceneRect( 0.0, 0.0, eqz_preset_10b[i].i_band , 40.0 );
1281         scene.render( &painter, icon.rect(), scene.sceneRect(), Qt::IgnoreAspectRatio );
1282         ui.presetsCombo->addItem( icon, qtr( preset_list_text[i] ),
1283                                      QVariant( preset_list[i] ) );
1284     }
1285     CONNECT( ui.presetsCombo, activated(int), this, setCorePreset(int) );
1286
1287     /* Set enable checkbox */
1288     vlc_object_t *p_aout = (vlc_object_t *)THEMIM->getAout();
1289     char *psz_af;
1290     if( p_aout )
1291     {
1292         psz_af = var_GetNonEmptyString( p_aout, "audio-filter" );
1293         vlc_object_release( p_aout );
1294     }
1295     else
1296         psz_af = config_GetPsz( p_intf, "audio-filter" );
1297
1298     /* To enable or disable subwidgets */
1299     /* If that list grows, better iterate over layout's childs */
1300     CONNECT( ui.enableCheck, toggled(bool), ui.presetsCombo, setEnabled(bool) );
1301     CONNECT( ui.enableCheck, toggled(bool), ui.presetLabel, setEnabled(bool) );
1302     CONNECT( ui.enableCheck, toggled(bool), ui.eq2PassCheck, setEnabled(bool) );
1303     CONNECT( ui.enableCheck, toggled(bool), ui.slidersPlaceholder, setEnabled(bool) );
1304     CONNECT( ui.enableCheck, toggled(bool), ui.preampSlider, setEnabled(bool) );
1305     CONNECT( ui.enableCheck, toggled(bool), ui.preampValue, setEnabled(bool) );
1306     CONNECT( ui.enableCheck, toggled(bool), ui.preampLabel, setEnabled(bool) );
1307
1308     if( psz_af && strstr( psz_af, qtu(name) ) != NULL )
1309         ui.enableCheck->setChecked( true );
1310     else
1311         ui.enableCheck->setChecked( false );
1312
1313     /* workaround for non emitted toggle() signal */
1314     ui.enableCheck->toggle(); ui.enableCheck->toggle();
1315
1316     free( psz_af );
1317     CONNECT( ui.enableCheck, toggled(bool), this, enable(bool) );
1318
1319     /* Connect and set 2 Pass checkbox */
1320     ui.eq2PassCheck->setChecked( var_InheritBool( p_aout, "equalizer-2pass" ) );
1321     CONNECT( ui.eq2PassCheck, toggled(bool), this, enable2Pass(bool) );
1322 }
1323
1324 void Equalizer::setSaveToConfig( bool b_save )
1325 {
1326     AudioFilterControlWidget::setSaveToConfig( b_save );
1327     preamp->setSaveToConfig( b_save );
1328 }
1329
1330 void Equalizer::setCorePreset( int i_preset )
1331 {
1332     if( i_preset < 1 )
1333         return;
1334
1335     i_preset--;/* 1st in index was an empty entry */
1336
1337     preamp->setValue( eqz_preset_10b[i_preset].f_preamp );
1338     for ( int i=0; i< qMin( eqz_preset_10b[i_preset].i_band,
1339                             sliderDatas.count() ) ; i++ )
1340         sliderDatas[i]->setValue( eqz_preset_10b[i_preset].f_amp[i] );
1341
1342     vlc_object_t *p_aout = (vlc_object_t *)THEMIM->getAout();
1343     if( p_aout )
1344     {
1345         var_SetString( p_aout , "equalizer-preset" , preset_list[i_preset] );
1346         vlc_object_release( p_aout );
1347     }
1348     config_PutPsz( p_intf, "equalizer-preset", preset_list[i_preset] );
1349 }
1350
1351 /* Function called when the set2Pass button is activated */
1352 void Equalizer::enable2Pass( bool b_enable ) const
1353 {
1354     vlc_object_t *p_aout= (vlc_object_t *)THEMIM->getAout();
1355
1356     if( p_aout )
1357     {
1358         var_SetBool( p_aout, "equalizer-2pass", b_enable );
1359         vlc_object_release( p_aout );
1360     }
1361     config_PutInt( p_intf, "equalizer-2pass", b_enable );
1362 }
1363
1364 /**********************************************************************
1365  * Audio filters
1366  **********************************************************************/
1367
1368 /**********************************************************************
1369  * Dynamic range compressor
1370  **********************************************************************/
1371
1372 Compressor::Compressor( intf_thread_t *p_intf, QWidget *parent )
1373     : AudioFilterControlWidget( p_intf, parent, "compressor" )
1374 {
1375     i_smallfont = -2;
1376     const FilterSliderData::slider_data_t a[7] =
1377     {
1378         { "compressor-rms-peak",    qtr("RMS/peak"),         "",       0.0f,   1.0f,   0.00f, 0.001f, 1.0 },
1379         { "compressor-attack",      qtr("Attack"),       qtr("ms"),   1.5f, 400.0f,  25.00f, 0.100f, 1.0 },
1380         { "compressor-release",     qtr("Release"),      qtr("ms"),   2.0f, 800.0f, 100.00f, 0.100f, 1.0 },
1381         { "compressor-threshold",   qtr("Threshold"),    qtr("dB"), -30.0f,   0.0f, -11.00f, 0.010f, 1.0 },
1382         { "compressor-ratio",       qtr("Ratio"),            ":1",     1.0f,  20.0f,   8.00f, 0.010f, 1.0 },
1383         { "compressor-knee",        qtr("Knee\nradius"), qtr("dB"),   1.0f,  10.0f,   2.50f, 0.010f, 1.0 },
1384         { "compressor-makeup-gain", qtr("Makeup\ngain"), qtr("dB"),   0.0f,  24.0f,   7.00f, 0.010f, 1.0 },
1385     };
1386     for( int i=0; i<7 ;i++ ) controls.append( a[i] );
1387     build();
1388 }
1389
1390 /**********************************************************************
1391  * Spatializer
1392  **********************************************************************/
1393
1394 Spatializer::Spatializer( intf_thread_t *p_intf, QWidget *parent )
1395     : AudioFilterControlWidget( p_intf, parent, "spatializer" )
1396 {
1397     i_smallfont = -1;
1398     const FilterSliderData::slider_data_t a[5] =
1399     {
1400         { "spatializer-roomsize",   qtr("Size"),    "", 0.0f, 1.1f, 0.85f, 0.1f, 10.0 },
1401         { "spatializer-width",      qtr("Width"),   "", 0.0f, 1.0f, 1.0f, 0.1f, 10.0 },
1402         { "spatializer-wet",        qtr("Wet"),     "", 0.0f, 1.0f, 0.4f, 0.1f, 10.0 },
1403         { "spatializer-dry",        qtr("Dry"),     "", 0.0f, 1.0f, 0.5f, 0.1f, 10.0 },
1404         { "spatializer-damp",       qtr("Damp"),    "", 0.0f, 1.0f, 0.5f, 0.1f, 10.0 },
1405     };
1406     for( int i=0; i<5 ;i++ ) controls.append( a[i] );
1407     build();
1408 }
1409
1410 #include <QToolButton>
1411 #include <QGridLayout>
1412
1413 #define SUBSDELAY_CFG_MODE                     "subsdelay-mode"
1414 #define SUBSDELAY_CFG_FACTOR                   "subsdelay-factor"
1415 #define SUBSDELAY_MODE_ABSOLUTE                0
1416 #define SUBSDELAY_MODE_RELATIVE_SOURCE_DELAY   1
1417 #define SUBSDELAY_MODE_RELATIVE_SOURCE_CONTENT 2
1418
1419 SyncWidget::SyncWidget( QWidget *_parent ) : QWidget( _parent )
1420 {
1421     QHBoxLayout *layout = new QHBoxLayout;
1422     spinBox.setAlignment( Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter );
1423     spinBox.setDecimals( 3 );
1424     spinBox.setMinimum( -600.0 );
1425     spinBox.setMaximum( 600.0 );
1426     spinBox.setSingleStep( 0.1 );
1427     spinBox.setSuffix( " s" );
1428     spinBox.setButtonSymbols( QDoubleSpinBox::PlusMinus );
1429     CONNECT( &spinBox, valueChanged( double ), this, valueChangedHandler( double ) );
1430     layout->addWidget( &spinBox );
1431     layout->addWidget( &spinLabel );
1432     layout->setContentsMargins( 0, 0, 0, 0 );
1433     setLayout( layout );
1434 }
1435
1436 void SyncWidget::valueChangedHandler( double d )
1437 {
1438     if ( d < 0 )
1439         spinLabel.setText( qtr("(Hastened)") );
1440     else if ( d > 0 )
1441         spinLabel.setText( qtr("(Delayed)") );
1442     else
1443         spinLabel.setText( "" );
1444     emit valueChanged( d );
1445 }
1446
1447 void SyncWidget::setValue( double d )
1448 {
1449     spinBox.setValue( d );
1450 }
1451
1452 SyncControls::SyncControls( intf_thread_t *_p_intf, QWidget *_parent ) :
1453                             QWidget( _parent ) , p_intf( _p_intf )
1454 {
1455     QGroupBox *AVBox, *subsBox;
1456     QToolButton *updateButton;
1457
1458     b_userAction = true;
1459
1460     QGridLayout *mainLayout = new QGridLayout( this );
1461
1462     /* AV sync */
1463     AVBox = new QGroupBox( qtr( "Audio/Video" ) );
1464     QGridLayout *AVLayout = new QGridLayout( AVBox );
1465
1466     QLabel *AVLabel = new QLabel;
1467     AVLabel->setText( qtr( "Audio track synchronization:" ) );
1468     AVLayout->addWidget( AVLabel, 0, 0, 1, 1 );
1469
1470     AVSpin = new SyncWidget( this );
1471     AVLayout->addWidget( AVSpin, 0, 2, 1, 1 );
1472     mainLayout->addWidget( AVBox, 1, 0, 1, 5 );
1473
1474     /* Subs */
1475     subsBox = new QGroupBox( qtr( "Subtitles/Video" ) );
1476     QGridLayout *subsLayout = new QGridLayout( subsBox );
1477
1478     QLabel *subsLabel = new QLabel;
1479     subsLabel->setText( qtr( "Subtitle track synchronization:" ) );
1480     subsLayout->addWidget( subsLabel, 0, 0, 1, 1 );
1481
1482     subsSpin = new SyncWidget( this );
1483     subsLayout->addWidget( subsSpin, 0, 2, 1, 1 );
1484
1485     QLabel *subSpeedLabel = new QLabel;
1486     subSpeedLabel->setText( qtr( "Subtitle speed:" ) );
1487     subsLayout->addWidget( subSpeedLabel, 1, 0, 1, 1 );
1488
1489     subSpeedSpin = new QDoubleSpinBox;
1490     subSpeedSpin->setAlignment( Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter );
1491     subSpeedSpin->setDecimals( 3 );
1492     subSpeedSpin->setMinimum( 1 );
1493     subSpeedSpin->setMaximum( 100 );
1494     subSpeedSpin->setSingleStep( 0.2 );
1495     subSpeedSpin->setSuffix( " fps" );
1496     subSpeedSpin->setButtonSymbols( QDoubleSpinBox::PlusMinus );
1497     subsLayout->addWidget( subSpeedSpin, 1, 2, 1, 1 );
1498
1499     QLabel *subDurationLabel = new QLabel;
1500     subDurationLabel->setText( qtr( "Subtitle duration factor:" ) );
1501     subsLayout->addWidget( subDurationLabel, 2, 0, 1, 1 );
1502
1503     subDurationSpin = new QDoubleSpinBox;
1504     subDurationSpin->setAlignment( Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter );
1505     subDurationSpin->setDecimals( 3 );
1506     subDurationSpin->setMinimum( 0 );
1507     subDurationSpin->setMaximum( 20 );
1508     subDurationSpin->setSingleStep( 0.2 );
1509     subDurationSpin->setButtonSymbols( QDoubleSpinBox::PlusMinus );
1510     subsLayout->addWidget( subDurationSpin, 2, 2, 1, 1 );
1511
1512     mainLayout->addWidget( subsBox, 2, 0, 2, 5 );
1513
1514     updateButton = new QToolButton;
1515     updateButton->setAutoRaise( true );
1516     mainLayout->addWidget( updateButton, 0, 4, 1, 1 );
1517
1518     /* Various Connects */
1519     CONNECT( AVSpin, valueChanged ( double ), this, advanceAudio( double ) ) ;
1520     CONNECT( subsSpin, valueChanged ( double ), this, advanceSubs( double ) ) ;
1521     CONNECT( subSpeedSpin, valueChanged ( double ),
1522              this, adjustSubsSpeed( double ) );
1523     CONNECT( subDurationSpin, valueChanged ( double ),
1524              this, adjustSubsDuration( double ) );
1525
1526     CONNECT( THEMIM->getIM(), synchroChanged(), this, update() );
1527     BUTTON_SET_ACT_I( updateButton, "", update,
1528             qtr( "Force update of this dialog's values" ), update() );
1529
1530     initSubsDuration();
1531
1532     /* Set it */
1533     update();
1534 }
1535
1536 SyncControls::~SyncControls()
1537 {
1538     subsdelayClean();
1539 }
1540
1541 void SyncControls::clean()
1542 {
1543     b_userAction = false;
1544     AVSpin->setValue( 0.0 );
1545     subsSpin->setValue( 0.0 );
1546     subSpeedSpin->setValue( 1.0 );
1547     subsdelayClean();
1548     b_userAction = true;
1549 }
1550
1551 void SyncControls::update()
1552 {
1553     b_userAction = false;
1554
1555     int64_t i_delay;
1556     if( THEMIM->getInput() )
1557     {
1558         i_delay = var_GetTime( THEMIM->getInput(), "audio-delay" );
1559         AVSpin->setValue( ( (double)i_delay ) / 1000000 );
1560         i_delay = var_GetTime( THEMIM->getInput(), "spu-delay" );
1561         subsSpin->setValue( ( (double)i_delay ) / 1000000 );
1562         subSpeedSpin->setValue( var_GetFloat( THEMIM->getInput(), "sub-fps" ) );
1563         subDurationSpin->setValue( var_InheritFloat( p_intf, SUBSDELAY_CFG_FACTOR ) );
1564     }
1565     b_userAction = true;
1566 }
1567
1568 void SyncControls::advanceAudio( double f_advance )
1569 {
1570     if( THEMIM->getInput() && b_userAction )
1571     {
1572         int64_t i_delay = f_advance * 1000000;
1573         var_SetTime( THEMIM->getInput(), "audio-delay", i_delay );
1574     }
1575 }
1576
1577 void SyncControls::advanceSubs( double f_advance )
1578 {
1579     if( THEMIM->getInput() && b_userAction )
1580     {
1581         int64_t i_delay = f_advance * 1000000;
1582         var_SetTime( THEMIM->getInput(), "spu-delay", i_delay );
1583     }
1584 }
1585
1586 void SyncControls::adjustSubsSpeed( double f_fps )
1587 {
1588     if( THEMIM->getInput() && b_userAction )
1589     {
1590         var_SetFloat( THEMIM->getInput(), "sub-fps", f_fps );
1591     }
1592 }
1593
1594 void SyncControls::adjustSubsDuration( double f_factor )
1595 {
1596     if( THEMIM->getInput() && b_userAction )
1597     {
1598         subsdelaySetFactor( f_factor );
1599         ChangeVFiltersString( p_intf, "subsdelay", f_factor > 0 );
1600     }
1601 }
1602
1603 void SyncControls::initSubsDuration()
1604 {
1605     int i_mode = var_InheritInteger( p_intf, SUBSDELAY_CFG_MODE );
1606
1607     switch (i_mode)
1608     {
1609     default:
1610     case SUBSDELAY_MODE_ABSOLUTE:
1611         subDurationSpin->setToolTip( qtr( "Extend subtitle duration by this value.\n"
1612                                           "Set 0 to disable." ) );
1613         subDurationSpin->setSuffix( " s" );
1614         break;
1615     case SUBSDELAY_MODE_RELATIVE_SOURCE_DELAY:
1616         subDurationSpin->setToolTip( qtr( "Multiply subtitle duration by this value.\n"
1617                                           "Set 0 to disable." ) );
1618         subDurationSpin->setSuffix( "" );
1619         break;
1620     case SUBSDELAY_MODE_RELATIVE_SOURCE_CONTENT:
1621         subDurationSpin->setToolTip( qtr( "Recalculate subtitle duration according\n"
1622                                           "to their content and this value.\n"
1623                                           "Set 0 to disable." ) );
1624         subDurationSpin->setSuffix( "" );
1625         break;
1626     }
1627 }
1628
1629 void SyncControls::subsdelayClean()
1630 {
1631     /* Remove subsdelay filter */
1632     ChangeVFiltersString( p_intf, "subsdelay", false );
1633 }
1634
1635 void SyncControls::subsdelaySetFactor( double f_factor )
1636 {
1637     /* Set the factor in the preferences */
1638     config_PutFloat( p_intf, SUBSDELAY_CFG_FACTOR, f_factor );
1639
1640     /* Try to find an instance of subsdelay, and set its factor */
1641     vlc_object_t *p_obj = ( vlc_object_t * ) vlc_object_find_name( p_intf->p_libvlc, "subsdelay" );
1642     if( p_obj )
1643     {
1644         var_SetFloat( p_obj, SUBSDELAY_CFG_FACTOR, f_factor );
1645         vlc_object_release( p_obj );
1646     }
1647 }
1648
1649
1650 /**********************************************************************
1651  * Video filters / Adjust
1652  **********************************************************************/
1653
1654 /**********************************************************************
1655  * Extended playbak controls
1656  **********************************************************************/