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