]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/interface_widgets.cpp
remove that kludge to use playlistwidget for getting art for
[vlc] / modules / gui / qt4 / components / interface_widgets.cpp
1 /*****************************************************************************
2  * interface_widgets.cpp : Custom widgets for the main interface
3  ****************************************************************************
4  * Copyright ( C ) 2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Clément Stenac <zorglub@videolan.org>
8  *          Jean-Baptiste Kempf <jb@videolan.org>
9  *          Rafaël Carré <funman@videolanorg>
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 #include "dialogs_provider.hpp"
27 #include "components/interface_widgets.hpp"
28 #include "main_interface.hpp"
29 #include "input_manager.hpp"
30 #include "menus.hpp"
31 #include "util/input_slider.hpp"
32 #include "util/customwidgets.hpp"
33 #include <vlc_vout.h>
34
35 #include <QLabel>
36 #include <QSpacerItem>
37 #include <QCursor>
38 #include <QPushButton>
39 #include <QHBoxLayout>
40 #include <QMenu>
41 #include <QPalette>
42 #include <QResizeEvent>
43
44 /**********************************************************************
45  * Video Widget. A simple frame on which video is drawn
46  * This class handles resize issues
47  **********************************************************************/
48 static void *DoRequest( intf_thread_t *, vout_thread_t *, int*,int*,
49                         unsigned int *, unsigned int * );
50 static void DoRelease( intf_thread_t *, void * );
51 static int DoControl( intf_thread_t *, void *, int, va_list );
52 static int ItemChanged( vlc_object_t *, const char *,
53                         vlc_value_t, vlc_value_t, void * );
54
55 VideoWidget::VideoWidget( intf_thread_t *_p_i ) : QFrame( NULL ), p_intf( _p_i )
56 {
57     vlc_mutex_init( p_intf, &lock );
58     p_vout = NULL;
59
60     CONNECT( this, askResize(), this, SetMinSize() );
61     CONNECT( this, askVideoToShow(), this, show() );
62     setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
63 }
64
65 VideoWidget::~VideoWidget()
66 {
67     vlc_mutex_lock( &lock );
68     if( p_vout )
69     {
70         if( !p_intf->psz_switch_intf )
71         {
72             if( vout_Control( p_vout, VOUT_CLOSE ) != VLC_SUCCESS )
73                 vout_Control( p_vout, VOUT_REPARENT );
74         }
75         else
76         {
77             if( vout_Control( p_vout, VOUT_REPARENT ) != VLC_SUCCESS )
78                 vout_Control( p_vout, VOUT_CLOSE );
79         }
80     }
81     vlc_mutex_unlock( &lock );
82     vlc_mutex_destroy( &lock );
83 }
84
85 QSize VideoWidget::sizeHint() const
86 {
87     return widgetSize;
88 }
89
90 void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
91                            unsigned int *pi_width, unsigned int *pi_height )
92 {
93     emit askVideoToShow();
94     if( p_vout )
95     {
96         msg_Dbg( p_intf, "embedded video already in use" );
97         return NULL;
98     }
99     p_vout = p_nvout;
100     emit askResize();
101     return ( void* )winId();
102 }
103
104 void VideoWidget::SetMinSize()
105 {
106     setMinimumSize( 16, 16 );
107 }
108
109 void VideoWidget::release( void *p_win )
110 {
111     p_vout = NULL;
112 }
113
114
115 /**********************************************************************
116  * Background Widget. Show a simple image background. Currently,
117  * it's a static cone.
118  **********************************************************************/
119 #define ICON_SIZE 128
120 #define MAX_BG_SIZE 400
121 #define MIN_BG_SIZE 64
122
123 BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i ) :
124                                         QFrame( NULL ), p_intf( _p_i )
125 {
126     /* We should use that one to take the more size it can */
127     setSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding );
128
129     /* A dark background */
130     setAutoFillBackground( true );
131     plt =  palette();
132     plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
133     plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
134     setPalette( plt );
135
136     /* A cone in the middle */
137     label = new QLabel;
138     label->setScaledContents( true );
139     label->setMargin( 5 );
140     label->setMaximumHeight( MAX_BG_SIZE );
141     label->setMaximumWidth( MAX_BG_SIZE );
142     label->setMinimumHeight( MIN_BG_SIZE );
143     label->setMinimumWidth( MIN_BG_SIZE );
144     label->setPixmap( QPixmap( ":/vlc128.png" ) );
145
146     QHBoxLayout *backgroundLayout = new QHBoxLayout( this );
147     backgroundLayout->addWidget( label );
148
149     resize( 300, 150 );
150     updateGeometry();
151     i_runs = 0;
152     b_need_update = VLC_FALSE;
153     var_AddCallback( THEPL, "item-change", ItemChanged, this );
154     ON_TIMEOUT( update() );
155 }
156
157 BackgroundWidget::~BackgroundWidget()
158 {
159     var_DelCallback( THEPL, "item-change", ItemChanged, this );
160 }
161
162 static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
163         vlc_value_t oldval, vlc_value_t newval, void *param )
164 {
165     BackgroundWidget *p_d = (BackgroundWidget*)param;
166     p_d->b_need_update = VLC_TRUE;
167     return VLC_SUCCESS;
168 }
169
170 void BackgroundWidget::update()
171 {
172     /* Timer runs at 150 ms, dont' update more than once every 750ms */
173     i_runs++;
174     if( i_runs % 6 != 0 ) return;
175
176     /* Get Input and clear if non-existant */
177     input_thread_t *p_input =
178                      MainInputManager::getInstance( p_intf )->getInput();
179     if( !p_input || p_input->b_dead )
180     {
181         label->setPixmap( QPixmap( ":/vlc128.png" ) );
182         return;
183     }
184
185
186     if( b_need_update )
187     {
188         vlc_object_yield( p_input );
189         char *psz_arturl = input_item_GetArtURL( input_GetItem(p_input) );
190         vlc_object_release( p_input );
191         QString url = qfu( psz_arturl );
192         QString arturl = url.replace( "file://",QString("" ) );
193         if( arturl.isNull() )
194             label->setPixmap( QPixmap( ":/vlc128.png" ) );
195         else
196         {
197             label->setPixmap( QPixmap( arturl ) );
198             msg_Dbg( p_intf, "changing input b_need_update done %s", psz_arturl );
199         }
200         free( psz_arturl );
201     }
202     b_need_update = false;
203 }
204
205 QSize BackgroundWidget::sizeHint() const
206 {
207     return label->size();
208 }
209
210 void BackgroundWidget::resizeEvent( QResizeEvent *e )
211 {
212     if( e->size().height() < MAX_BG_SIZE -1 )
213     {
214         label->setMaximumWidth( e->size().height() );
215         label->setMaximumHeight( e->size().width() );
216     }
217     else
218     {
219         label->setMaximumHeight( MAX_BG_SIZE );
220         label->setMaximumWidth( MAX_BG_SIZE );
221     }
222 }
223
224 void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
225 {
226     QVLCMenu::PopupMenu( p_intf, true );
227 }
228
229 /**********************************************************************
230  * Visualization selector panel
231  **********************************************************************/
232 VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
233                                 QFrame( NULL ), p_intf( _p_i )
234 {
235     QHBoxLayout *layout = new QHBoxLayout( this );
236     layout->setMargin( 0 );
237     QPushButton *prevButton = new QPushButton( "Prev" );
238     QPushButton *nextButton = new QPushButton( "Next" );
239     layout->addWidget( prevButton );
240     layout->addWidget( nextButton );
241
242     layout->addItem( new QSpacerItem( 40,20,
243                               QSizePolicy::Expanding, QSizePolicy::Minimum ) );
244     layout->addWidget( new QLabel( qtr( "Current visualization:" ) ) );
245
246     current = new QLabel( qtr( "None" ) );
247     layout->addWidget( current );
248
249     BUTTONACT( prevButton, prev() );
250     BUTTONACT( nextButton, next() );
251
252     setLayout( layout );
253     setMaximumHeight( 35 );
254 }
255
256 VisualSelector::~VisualSelector()
257 {
258 }
259
260 void VisualSelector::prev()
261 {
262     char *psz_new = aout_VisualPrev( p_intf );
263     if( psz_new )
264     {
265         current->setText( qfu( psz_new ) );
266         free( psz_new );
267     }
268 }
269
270 void VisualSelector::next()
271 {
272     char *psz_new = aout_VisualNext( p_intf );
273     if( psz_new )
274     {
275         current->setText( qfu( psz_new ) );
276         free( psz_new );
277     }
278 }
279
280 /**********************************************************************
281  * TEH controls
282  **********************************************************************/
283
284 #define setupSmallButton( aButton ){  \
285     aButton->setMaximumSize( QSize( 26, 26 ) ); \
286     aButton->setMinimumSize( QSize( 26, 26 ) ); \
287     aButton->setIconSize( QSize( 20, 20 ) ); }
288
289 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
290                                            QFrame( NULL ), p_intf( _p_i )
291 {
292     QHBoxLayout *advLayout = new QHBoxLayout( this );
293     advLayout->setMargin( 0 );
294     advLayout->setSpacing( 0 );
295
296     /* A to B Button */
297     ABButton = new QPushButton( "AB" );
298     ABButton->setMaximumSize( QSize( 26, 26 ) );
299     ABButton->setIconSize( QSize( 20, 20 ) );
300     advLayout->addWidget( ABButton );
301     BUTTON_SET_ACT( ABButton, "AB", qtr( "A to B" ), fromAtoB() );
302     timeA = timeB = 0;
303     CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
304              this, AtoBLoop( float, int, int ) );
305
306     frameButton = new QPushButton( "Fr" );
307     frameButton->setMaximumSize( QSize( 26, 26 ) );
308     frameButton->setIconSize( QSize( 20, 20 ) );
309     advLayout->addWidget( frameButton );
310     BUTTON_SET_ACT( frameButton, "Fr", qtr( "Frame by Frame" ), frame() );
311
312     recordButton = new QPushButton( "R" );
313     recordButton->setMaximumSize( QSize( 26, 26 ) );
314     recordButton->setIconSize( QSize( 20, 20 ) );
315     advLayout->addWidget( recordButton );
316     BUTTON_SET_ACT_I( recordButton, "", record_16px.png,
317             qtr( "Record" ), record() );
318
319     /* Snapshot Button */
320     snapshotButton = new QPushButton( "S" );
321     snapshotButton->setMaximumSize( QSize( 26, 26 ) );
322     snapshotButton->setIconSize( QSize( 20, 20 ) );
323     advLayout->addWidget( snapshotButton );
324     BUTTON_SET_ACT( snapshotButton, "S", qtr( "Take a snapshot" ), snapshot() );
325 }
326
327 AdvControlsWidget::~AdvControlsWidget()
328 {}
329
330 void AdvControlsWidget::enableInput( bool enable )
331 {
332     ABButton->setEnabled( enable );
333     recordButton->setEnabled( enable );
334 }
335
336 void AdvControlsWidget::enableVideo( bool enable )
337 {
338     snapshotButton->setEnabled( enable );
339     frameButton->setEnabled( enable );
340 }
341
342 void AdvControlsWidget::snapshot()
343 {
344     vout_thread_t *p_vout =
345         (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
346     if( p_vout ) vout_Control( p_vout, VOUT_SNAPSHOT );
347 }
348
349 /* Function called when the button is clicked() */
350 void AdvControlsWidget::fromAtoB()
351 {
352     if( !timeA )
353     {
354         timeA = var_GetTime( THEMIM->getInput(), "time"  );
355         ABButton->setText( "A->..." );
356         return;
357     }
358     if( !timeB )
359     {
360         timeB = var_GetTime( THEMIM->getInput(), "time"  );
361         var_SetTime( THEMIM->getInput(), "time" , timeA );
362         ABButton->setText( "A<=>B" );
363         return;
364     }
365     timeA = 0;
366     timeB = 0;
367     ABButton->setText( "AB" );
368 }
369
370 /* Function called regularly when in an AtoB loop */
371 void AdvControlsWidget::AtoBLoop( float f_pos, int i_time, int i_length )
372 {
373     if( timeB )
374     {
375         if( i_time >= (int)(timeB/1000000) )
376             var_SetTime( THEMIM->getInput(), "time" , timeA );
377     }
378 }
379
380 /* FIXME Record function */
381 void AdvControlsWidget::record(){}
382
383 //FIXME Frame by frame function
384 void AdvControlsWidget::frame(){}
385
386 /*****************************
387  * DA Control Widget !
388  *****************************/
389 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
390                                 MainInterface *_p_mi,
391                                 bool b_advControls,
392                                 bool b_shiny ) :
393                                 QFrame( NULL ), p_intf( _p_i )
394 {
395     controlLayout = new QGridLayout( this );
396     controlLayout->setSpacing( 0 );
397     setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Minimum );
398
399     /** The main Slider **/
400     slider = new InputSlider( Qt::Horizontal, NULL );
401     controlLayout->addWidget( slider, 0, 1, 1, 16 );
402     /* Update the position when the IM has changed */
403     CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
404              slider, setPosition( float, int, int ) );
405     /* And update the IM, when the position has changed */
406     CONNECT( slider, sliderDragged( float ),
407              THEMIM->getIM(), sliderUpdate( float ) );
408
409     /** Slower and faster Buttons **/
410     slowerButton = new QPushButton;
411     slowerButton->setFlat( true );
412     slowerButton->setMaximumSize( QSize( 26, 20 ) );
413
414     BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() );
415     controlLayout->addWidget( slowerButton, 0, 0 );
416
417     fasterButton = new QPushButton;
418     fasterButton->setFlat( true );
419     fasterButton->setMaximumSize( QSize( 26, 20 ) );
420
421     BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() );
422     controlLayout->addWidget( fasterButton, 0, 17 );
423
424     /* advanced Controls handling */
425     b_advancedVisible = b_advControls;
426
427     advControls = new AdvControlsWidget( p_intf );
428     controlLayout->addWidget( advControls, 1, 3, 2, 4, Qt::AlignBottom );
429     if( !b_advancedVisible ) advControls->hide();
430
431     /** Disc and Menus handling */
432     discFrame = new QFrame( this );
433
434     QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
435     discLayout->setSpacing( 0 );
436     discLayout->setMargin( 0 );
437
438     prevSectionButton = new QPushButton( discFrame );
439     setupSmallButton( prevSectionButton );
440     discLayout->addWidget( prevSectionButton );
441
442     menuButton = new QPushButton( discFrame );
443     setupSmallButton( menuButton );
444     discLayout->addWidget( menuButton );
445
446     nextSectionButton = new QPushButton( discFrame );
447     setupSmallButton( nextSectionButton );
448     discLayout->addWidget( nextSectionButton );
449
450     controlLayout->addWidget( discFrame, 1, 10, 2, 3, Qt::AlignBottom );
451
452     BUTTON_SET_IMG( prevSectionButton, "", previous.png, "" );
453     BUTTON_SET_IMG( nextSectionButton, "", next.png, "" );
454     BUTTON_SET_IMG( menuButton, "", previous.png, "" );
455
456     discFrame->hide();
457
458     /* Change the navigation button display when the IM navigation changes */
459     CONNECT( THEMIM->getIM(), navigationChanged( int ),
460              this, setNavigation( int ) );
461     /* Changes the IM navigation when triggered on the nav buttons */
462     CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
463              sectionPrev() );
464     CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
465              sectionNext() );
466     CONNECT( menuButton, clicked(), THEMIM->getIM(),
467              sectionMenu() );
468
469     /** TODO
470      * Telextext QFrame
471      * Merge with upper menu in a StackLayout
472      **/
473
474     /** Play Buttons **/
475     QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
476     sizePolicy.setHorizontalStretch( 0 );
477     sizePolicy.setVerticalStretch( 0 );
478
479     /* Play */
480     playButton = new QPushButton;
481     playButton->setSizePolicy( sizePolicy );
482     playButton->setMaximumSize( QSize( 38, 38 ) );
483     playButton->setMinimumSize( QSize( 45, 45 ) );
484     playButton->setIconSize( QSize( 30, 30 ) );
485
486     controlLayout->addWidget( playButton, 2, 0, 2, 2 );
487
488     controlLayout->setColumnMinimumWidth( 2, 20 );
489     controlLayout->setColumnStretch( 2, 0 );
490
491     /** Prev + Stop + Next Block **/
492     QHBoxLayout *controlButLayout = new QHBoxLayout;
493     controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */
494
495     /* Prev */
496     QPushButton *prevButton = new QPushButton;
497     prevButton->setSizePolicy( sizePolicy );
498     setupSmallButton( prevButton );
499
500     controlButLayout->addWidget( prevButton );
501
502     /* Stop */
503     QPushButton *stopButton = new QPushButton;
504     stopButton->setSizePolicy( sizePolicy );
505     setupSmallButton( stopButton );
506
507     controlButLayout->addWidget( stopButton );
508
509     /* next */
510     QPushButton *nextButton = new QPushButton;
511     nextButton->setSizePolicy( sizePolicy );
512     setupSmallButton( nextButton );
513
514     controlButLayout->addWidget( nextButton );
515
516     /* Add this block to the main layout */
517     controlLayout->addLayout( controlButLayout, 3, 3, 1, 3, Qt::AlignBottom );
518
519     BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() );
520     BUTTON_SET_ACT_I( prevButton, "" , previous.png,
521                       qtr( "Previous" ), prev() );
522     BUTTON_SET_ACT_I( nextButton, "", next.png, qtr( "Next" ), next() );
523     BUTTON_SET_ACT_I( stopButton, "", stop.png, qtr( "Stop" ), stop() );
524
525     controlLayout->setColumnStretch( 7 , 2 );
526
527     /*
528      * Other first Line buttons
529      */
530     /** Fullscreen/Visualisation **/
531     fullscreenButton = new QPushButton( "F" );
532     BUTTON_SET_ACT( fullscreenButton, "F", qtr( "Fullscreen" ), fullscreen() );
533     setupSmallButton( fullscreenButton );
534     controlLayout->addWidget( fullscreenButton, 3, 10, Qt::AlignBottom );
535
536     /** Playlist Button **/
537     playlistButton = new QPushButton;
538     setupSmallButton( playlistButton );
539     controlLayout->addWidget( playlistButton, 3, 11, Qt::AlignBottom );
540     BUTTON_SET_IMG( playlistButton, "" , playlist.png, qtr( "Show playlist" ) );
541     CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
542
543     /** extended Settings **/
544     QPushButton *extSettingsButton = new QPushButton( "F" );
545     BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended Settings" ),
546             extSettings() );
547     setupSmallButton( extSettingsButton );
548     controlLayout->addWidget( extSettingsButton, 3, 12, Qt::AlignBottom );
549
550     controlLayout->setColumnStretch( 14, 5 );
551
552     /* Volume */
553     VolumeClickHandler *hVolLabel = new VolumeClickHandler( p_intf, this );
554
555     volMuteLabel = new QLabel;
556     volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
557     volMuteLabel->setToolTip( qtr( "Mute" ) );
558     volMuteLabel->installEventFilter( hVolLabel );
559     controlLayout->addWidget( volMuteLabel, 3, 15, Qt::AlignBottom );
560
561     if( b_shiny )
562     {
563         volumeSlider = new SoundSlider( this,
564             config_GetInt( p_intf, "volume-step" ),
565             config_GetInt( p_intf, "qt-volume-complete" ) );
566     }
567     else
568     {
569         volumeSlider = new QSlider( this );
570         volumeSlider->setOrientation( Qt::Horizontal );
571     }
572     volumeSlider->setMaximumSize( QSize( 200, 40 ) );
573     volumeSlider->setMinimumSize( QSize( 106, 30 ) );
574     volumeSlider->setFocusPolicy( Qt::NoFocus );
575     controlLayout->addWidget( volumeSlider, 2, 16, 2 , 2, Qt::AlignBottom );
576
577     /* Set the volume from the config */
578     volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
579                               VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
580
581     /* Volume control connection */
582     resize( QSize( 400, 60 ) );
583     CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
584     msg_Dbg( p_intf, "controls size: %i - %i", size().width(), size().height() );
585 }
586
587 ControlsWidget::~ControlsWidget()
588 {
589 }
590
591 /*
592 QSize ControlsWidget::sizeHint() const
593 {
594     return QSize( 300, 50 );
595 }
596 */
597
598 void ControlsWidget::stop()
599 {
600     THEMIM->stop();
601 }
602
603 void ControlsWidget::play()
604 {
605     if( THEPL->current.i_size == 0 )
606     {
607         /* The playlist is empty, open a file requester */
608         THEDP->openFileDialog();
609         setStatus( 0 );
610         return;
611     }
612     THEMIM->togglePlayPause();
613 }
614
615 void ControlsWidget::prev()
616 {
617     THEMIM->prev();
618 }
619
620 void ControlsWidget::next()
621 {
622     THEMIM->next();
623 }
624
625 void ControlsWidget::setNavigation( int navigation )
626 {
627 #define HELP_MENU N_( "Menu" )
628 #define HELP_PCH N_( "Previous chapter" )
629 #define HELP_NCH N_( "Next chapter" )
630 #define HELP_PTR N_( "Previous track" )
631 #define HELP_NTR N_( "Next track" )
632
633     // 1 = chapter, 2 = title, 0 = no
634     if( navigation == 0 )
635     {
636         discFrame->hide();
637     } else if( navigation == 1 ) {
638         prevSectionButton->setToolTip( qfu( HELP_PCH ) );
639         nextSectionButton->setToolTip( qfu( HELP_NCH ) );
640         menuButton->show();
641         discFrame->show();
642     } else {
643         prevSectionButton->setToolTip( qfu( HELP_PCH ) );
644         nextSectionButton->setToolTip( qfu( HELP_NCH ) );
645         menuButton->hide();
646         discFrame->show();
647     }
648 }
649
650 static bool b_my_volume;
651 void ControlsWidget::updateVolume( int i_sliderVolume )
652 {
653     if( !b_my_volume )
654     {
655         int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
656         aout_VolumeSet( p_intf, i_res );
657     }
658     if( i_sliderVolume == 0 )
659         volMuteLabel->setPixmap( QPixmap(":/pixmaps/volume-muted.png" ) );
660     else if( i_sliderVolume < VOLUME_MAX / 2 )
661         volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) );
662     else volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
663 }
664
665 void ControlsWidget::updateOnTimer()
666 {
667     /* Audio part */
668     audio_volume_t i_volume;
669     aout_VolumeGet( p_intf, &i_volume );
670     i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
671     int i_gauge = volumeSlider->value();
672     b_my_volume = false;
673     if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
674     {
675         b_my_volume = true;
676         volumeSlider->setValue( i_volume );
677         b_my_volume = false;
678     }
679
680     /* Activate the interface buttons according to the presence of the input */
681     enableInput( THEMIM->getIM()->hasInput() );
682     //enableVideo( THEMIM->getIM()->hasVideo() );
683     enableVideo( true );
684 }
685
686 void ControlsWidget::setStatus( int status )
687 {
688     if( status == PLAYING_S ) // Playing
689         playButton->setIcon( QIcon( ":/pixmaps/pause.png" ) );
690     else
691         playButton->setIcon( QIcon( ":/pixmaps/play.png" ) );
692 }
693
694 /**
695  * TODO
696  * This functions toggle the fullscreen mode
697  * If there is no video, it should first activate Visualisations...
698  *  This has also to be fixed in enableVideo()
699  */
700 void ControlsWidget::fullscreen()
701 {
702     vout_thread_t *p_vout =
703         (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
704     if( p_vout)
705     {
706         var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
707         vlc_object_release( p_vout );
708     }
709 }
710
711 void ControlsWidget::extSettings()
712 {
713     THEDP->extendedDialog();
714 }
715
716 void ControlsWidget::slower()
717 {
718     THEMIM->getIM()->slower();
719 }
720
721 void ControlsWidget::faster()
722 {
723     THEMIM->getIM()->faster();
724 }
725
726 void ControlsWidget::enableInput( bool enable )
727 {
728     slowerButton->setEnabled( enable );
729     slider->setEnabled( enable );
730     fasterButton->setEnabled( enable );
731
732     /* Advanced Buttons too */
733     advControls->enableInput( enable );
734 }
735
736 void ControlsWidget::enableVideo( bool enable )
737 {
738     // TODO Later make the fullscreenButton toggle Visualisation and so on.
739     fullscreenButton->setEnabled( enable );
740
741     /* Advanced Buttons too */
742     advControls->enableVideo( enable );
743 }
744
745 void ControlsWidget::toggleAdvanced()
746 {
747     if( !VISIBLE( advControls ) )
748     {
749         advControls->show();
750         b_advancedVisible = true;
751     }
752     else
753     {
754         advControls->hide();
755         b_advancedVisible = false;
756     }
757     emit advancedControlsToggled( b_advancedVisible );
758 }
759
760
761 /**********************************************************************
762  * Speed control widget
763  **********************************************************************/
764 SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
765                              QFrame( NULL ), p_intf( _p_i )
766 {
767     QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
768     sizePolicy.setHorizontalStretch( 0 );
769     sizePolicy.setVerticalStretch( 0 );
770
771     speedSlider = new QSlider;
772     speedSlider->setSizePolicy( sizePolicy );
773     speedSlider->setMaximumSize( QSize( 80, 200 ) );
774     speedSlider->setOrientation( Qt::Vertical );
775     speedSlider->setTickPosition( QSlider::TicksRight );
776
777     speedSlider->setRange( -100, 100 );
778     speedSlider->setSingleStep( 10 );
779     speedSlider->setPageStep( 20 );
780     speedSlider->setTickInterval( 20 );
781
782     CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
783
784     normalSpeedButton = new QPushButton( "N" );
785     normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
786     normalSpeedButton->setFlat( true );
787     normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
788
789     CONNECT( normalSpeedButton, clicked(), this, resetRate() );
790
791     QVBoxLayout *speedControlLayout = new QVBoxLayout;
792     speedControlLayout->addWidget(speedSlider);
793     speedControlLayout->addWidget(normalSpeedButton);
794     setLayout(speedControlLayout);
795 }
796
797 SpeedControlWidget::~SpeedControlWidget()
798 {}
799
800 #define RATE_SLIDER_MAXIMUM 3.0
801 #define RATE_SLIDER_MINIMUM 0.3
802 #define RATE_SLIDER_LENGTH 100.0
803
804 void SpeedControlWidget::updateControls( int rate )
805 {
806     if( speedSlider->isSliderDown() )
807     {
808         //We don't want to change anything if the user is using the slider
809         return;
810     }
811
812     int sliderValue;
813     double speed = INPUT_RATE_DEFAULT / (double)rate;
814
815     if( rate >= INPUT_RATE_DEFAULT )
816     {
817         if( speed < RATE_SLIDER_MINIMUM )
818         {
819             sliderValue = speedSlider->minimum();
820         }
821         else
822         {
823             sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
824                                         / ( 1.0 - RATE_SLIDER_MAXIMUM ) );
825         }
826     }
827     else
828     {
829         if( speed > RATE_SLIDER_MAXIMUM )
830         {
831             sliderValue = speedSlider->maximum();
832         }
833         else
834         {
835             sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
836                                         / ( RATE_SLIDER_MAXIMUM - 1.0 ) );
837         }
838     }
839
840     //Block signals to avoid feedback loop
841     speedSlider->blockSignals( true );
842     speedSlider->setValue( sliderValue );
843     speedSlider->blockSignals( false );
844 }
845
846 void SpeedControlWidget::updateRate( int sliderValue )
847 {
848     int rate;
849
850     if( sliderValue < 0.0 )
851     {
852         rate = INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
853             ( sliderValue * ( 1.0 - RATE_SLIDER_MINIMUM ) + RATE_SLIDER_LENGTH );
854     }
855     else
856     {
857         rate = INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
858             ( sliderValue * ( RATE_SLIDER_MAXIMUM - 1.0 ) + RATE_SLIDER_LENGTH );
859     }
860
861     THEMIM->getIM()->setRate(rate);
862 }
863
864 void SpeedControlWidget::resetRate()
865 {
866     THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT);
867 }