]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/interface_widgets.cpp
Remove completely useless mutex
[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  *          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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include "dialogs_provider.hpp"
32 #include "components/interface_widgets.hpp"
33 #include "main_interface.hpp"
34 #include "input_manager.hpp"
35 #include "menus.hpp"
36 #include "util/input_slider.hpp"
37 #include "util/customwidgets.hpp"
38 #include <vlc_vout.h>
39
40 #include <QLabel>
41 #include <QSpacerItem>
42 #include <QCursor>
43 #include <QPushButton>
44 #include <QToolButton>
45 #include <QHBoxLayout>
46 #include <QMenu>
47 #include <QPalette>
48 #include <QResizeEvent>
49 #include <QDate>
50 #ifdef Q_WS_X11
51 # include <X11/Xlib.h>
52 # include <qx11info_x11.h>
53 #endif
54
55 /**********************************************************************
56  * Video Widget. A simple frame on which video is drawn
57  * This class handles resize issues
58  **********************************************************************/
59
60 VideoWidget::VideoWidget( intf_thread_t *_p_i ) : QFrame( NULL ), p_intf( _p_i )
61 {
62     /* Init */
63     p_vout = NULL;
64     hide(); setMinimumSize( 16, 16 );
65     videoSize.rwidth() = -1;
66     videoSize.rheight() = -1;
67     setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
68
69     /* Black background is more coherent for a Video Widget IMVHO */
70     QPalette plt =  palette();
71     plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
72     plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
73     setPalette( plt );
74     setAttribute( Qt::WA_PaintOnScreen, true );
75
76     /* The core can ask through a callback to show the video. */
77 #if HAS_QT43
78     connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)),
79              this, SLOT(SetSizing(unsigned int, unsigned int )),
80              Qt::BlockingQueuedConnection );
81 #else
82 #error This is broken. Fix it with a QEventLoop with a processEvents () 
83     connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)),
84              this, SLOT(SetSizing(unsigned int, unsigned int )) );
85 #endif
86
87
88 }
89
90 void VideoWidget::paintEvent(QPaintEvent *ev)
91 {
92     QFrame::paintEvent(ev);
93 #ifdef Q_WS_X11
94     XFlush( QX11Info::display() );
95 #endif
96 }
97
98 VideoWidget::~VideoWidget()
99 {
100     if( p_vout )
101     {
102         if( !p_intf->psz_switch_intf )
103         {
104             if( vout_Control( p_vout, VOUT_CLOSE ) != VLC_SUCCESS )
105                 vout_Control( p_vout, VOUT_REPARENT );
106         }
107         else
108         {
109             if( vout_Control( p_vout, VOUT_REPARENT ) != VLC_SUCCESS )
110                 vout_Control( p_vout, VOUT_CLOSE );
111         }
112     }
113 }
114
115 /**
116  * Request the video to avoid the conflicts
117  **/
118 void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
119                            unsigned int *pi_width, unsigned int *pi_height )
120 {
121     msg_Dbg( p_intf, "Video was requested %i, %i", *pi_x, *pi_y );
122     emit askVideoWidgetToShow( *pi_width, *pi_height );
123     if( p_vout )
124     {
125         msg_Dbg( p_intf, "embedded video already in use" );
126         return NULL;
127     }
128     p_vout = p_nvout;
129     msg_Dbg( p_intf, "embedded video ready (handle %p)", winId() );
130     return ( void* )winId();
131 }
132
133 /* Set the Widget to the correct Size */
134 /* Function has to be called by the parent
135    Parent has to care about resizing himself*/
136 void VideoWidget::SetSizing( unsigned int w, unsigned int h )
137 {
138     msg_Dbg( p_intf, "Video is resizing to: %i %i", w, h );
139     videoSize.rwidth() = w;
140     videoSize.rheight() = h;
141     if( isHidden() ) show();
142     updateGeometry(); // Needed for deinterlace
143 }
144
145 void VideoWidget::release( void *p_win )
146 {
147     msg_Dbg( p_intf, "Video is non needed anymore" );
148     p_vout = NULL;
149     videoSize.rwidth() = 0;
150     videoSize.rheight() = 0;
151     hide();
152     updateGeometry(); // Needed for deinterlace
153 }
154
155 QSize VideoWidget::sizeHint() const
156 {
157     return videoSize;
158 }
159
160 /**********************************************************************
161  * Background Widget. Show a simple image background. Currently,
162  * it's album art if present or cone.
163  **********************************************************************/
164 #define ICON_SIZE 128
165 #define MAX_BG_SIZE 400
166 #define MIN_BG_SIZE 64
167
168 BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
169                  :QWidget( NULL ), p_intf( _p_i )
170 {
171     /* We should use that one to take the more size it can */
172 //    setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
173
174     /* A dark background */
175     setAutoFillBackground( true );
176     plt =  palette();
177     plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
178     plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
179     setPalette( plt );
180
181     /* A cone in the middle */
182     label = new QLabel;
183     label->setMargin( 5 );
184     label->setMaximumHeight( MAX_BG_SIZE );
185     label->setMaximumWidth( MAX_BG_SIZE );
186     label->setMinimumHeight( MIN_BG_SIZE );
187     label->setMinimumWidth( MIN_BG_SIZE );
188     if( QDate::currentDate().dayOfYear() >= 354 )
189         label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) );
190     else
191         label->setPixmap( QPixmap( ":/vlc128.png" ) );
192
193     QGridLayout *backgroundLayout = new QGridLayout( this );
194     backgroundLayout->addWidget( label, 0, 1 );
195     backgroundLayout->setColumnStretch( 0, 1 );
196     backgroundLayout->setColumnStretch( 2, 1 );
197
198     CONNECT( THEMIM->getIM(), artChanged( QString ), this, updateArt( QString ) );
199 }
200
201 BackgroundWidget::~BackgroundWidget()
202 {
203 }
204
205 void BackgroundWidget::resizeEvent( QResizeEvent * event )
206 {
207     if( event->size().height() <= MIN_BG_SIZE )
208         label->hide();
209     else
210         label->show();
211 }
212
213 void BackgroundWidget::updateArt( QString url )
214 {
215     if( url.isEmpty() )
216     {
217         if( QDate::currentDate().dayOfYear() >= 354 )
218             label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) );
219         else
220             label->setPixmap( QPixmap( ":/vlc128.png" ) );
221         return;
222     }
223     else
224     {
225         label->setPixmap( QPixmap( url ) );
226     }
227 }
228
229 void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
230 {
231     QVLCMenu::PopupMenu( p_intf, true );
232 }
233
234 /**********************************************************************
235  * Visualization selector panel
236  **********************************************************************/
237 VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
238                                 QFrame( NULL ), p_intf( _p_i )
239 {
240     QHBoxLayout *layout = new QHBoxLayout( this );
241     layout->setMargin( 0 );
242     QPushButton *prevButton = new QPushButton( "Prev" );
243     QPushButton *nextButton = new QPushButton( "Next" );
244     layout->addWidget( prevButton );
245     layout->addWidget( nextButton );
246
247     layout->addItem( new QSpacerItem( 40,20,
248                               QSizePolicy::Expanding, QSizePolicy::Minimum ) );
249     layout->addWidget( new QLabel( qtr( "Current visualization:" ) ) );
250
251     current = new QLabel( qtr( "None" ) );
252     layout->addWidget( current );
253
254     BUTTONACT( prevButton, prev() );
255     BUTTONACT( nextButton, next() );
256
257     setLayout( layout );
258     setMaximumHeight( 35 );
259 }
260
261 VisualSelector::~VisualSelector()
262 {
263 }
264
265 void VisualSelector::prev()
266 {
267     char *psz_new = aout_VisualPrev( p_intf );
268     if( psz_new )
269     {
270         current->setText( qfu( psz_new ) );
271         free( psz_new );
272     }
273 }
274
275 void VisualSelector::next()
276 {
277     char *psz_new = aout_VisualNext( p_intf );
278     if( psz_new )
279     {
280         current->setText( qfu( psz_new ) );
281         free( psz_new );
282     }
283 }
284
285 /**********************************************************************
286  * TEH controls
287  **********************************************************************/
288
289 #define setupSmallButton( aButton ){  \
290     aButton->setMaximumSize( QSize( 26, 26 ) ); \
291     aButton->setMinimumSize( QSize( 26, 26 ) ); \
292     aButton->setIconSize( QSize( 20, 20 ) ); }
293
294 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
295                                            QFrame( NULL ), p_intf( _p_i )
296 {
297     QHBoxLayout *advLayout = new QHBoxLayout( this );
298     advLayout->setMargin( 0 );
299     advLayout->setSpacing( 0 );
300     advLayout->setAlignment( Qt::AlignBottom );
301
302     /* A to B Button */
303     ABButton = new QPushButton( "AB" );
304     setupSmallButton( ABButton );
305     advLayout->addWidget( ABButton );
306     BUTTON_SET_ACT( ABButton, "AB", qtr( "A to B" ), fromAtoB() );
307     timeA = timeB = 0;
308     CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
309              this, AtoBLoop( float, int, int ) );
310 #if 0
311     frameButton = new QPushButton( "Fr" );
312     frameButton->setMaximumSize( QSize( 26, 26 ) );
313     frameButton->setIconSize( QSize( 20, 20 ) );
314     advLayout->addWidget( frameButton );
315     BUTTON_SET_ACT( frameButton, "Fr", qtr( "Frame by Frame" ), frame() );
316 #endif
317
318     recordButton = new QPushButton( "R" );
319     setupSmallButton( recordButton );
320     advLayout->addWidget( recordButton );
321     BUTTON_SET_ACT_I( recordButton, "", record_16px.png,
322             qtr( "Record" ), record() );
323
324     /* Snapshot Button */
325     snapshotButton = new QPushButton( "S" );
326     setupSmallButton( snapshotButton );
327     advLayout->addWidget( snapshotButton );
328     BUTTON_SET_ACT( snapshotButton, "S", qtr( "Take a snapshot" ), snapshot() );
329 }
330
331 AdvControlsWidget::~AdvControlsWidget()
332 {}
333
334 void AdvControlsWidget::enableInput( bool enable )
335 {
336     ABButton->setEnabled( enable );
337     recordButton->setEnabled( enable );
338 }
339
340 void AdvControlsWidget::enableVideo( bool enable )
341 {
342     snapshotButton->setEnabled( enable );
343 #if 0
344     frameButton->setEnabled( enable );
345 #endif
346 }
347
348 void AdvControlsWidget::snapshot()
349 {
350     vout_thread_t *p_vout =
351         (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
352     if( p_vout ) vout_Control( p_vout, VOUT_SNAPSHOT );
353 }
354
355 /* Function called when the button is clicked() */
356 void AdvControlsWidget::fromAtoB()
357 {
358     if( !timeA )
359     {
360         timeA = var_GetTime( THEMIM->getInput(), "time"  );
361         ABButton->setText( "A->..." );
362         return;
363     }
364     if( !timeB )
365     {
366         timeB = var_GetTime( THEMIM->getInput(), "time"  );
367         var_SetTime( THEMIM->getInput(), "time" , timeA );
368         ABButton->setText( "A<=>B" );
369         return;
370     }
371     timeA = 0;
372     timeB = 0;
373     ABButton->setText( "AB" );
374 }
375
376 /* Function called regularly when in an AtoB loop */
377 void AdvControlsWidget::AtoBLoop( float f_pos, int i_time, int i_length )
378 {
379     if( timeB )
380     {
381         if( i_time >= (int)(timeB/1000000) )
382             var_SetTime( THEMIM->getInput(), "time" , timeA );
383     }
384 }
385
386 /* FIXME Record function */
387 void AdvControlsWidget::record(){}
388
389 #if 0
390 //FIXME Frame by frame function
391 void AdvControlsWidget::frame(){}
392 #endif
393
394 /*****************************
395  * DA Control Widget !
396  *****************************/
397 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
398                                 MainInterface *_p_mi,
399                                 bool b_advControls,
400                                 bool b_shiny,
401                                 bool b_fsCreation) :
402                                 QFrame( _p_mi ), p_intf( _p_i )
403 {
404     controlLayout = new QGridLayout( );
405
406     controlLayout->setSpacing( 0 );
407     controlLayout->setLayoutMargins( 7, 5, 7, 3, 6 );
408
409     if( !b_fsCreation )
410         setLayout( controlLayout );
411
412     setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
413
414     /** The main Slider **/
415     slider = new InputSlider( Qt::Horizontal, NULL );
416     controlLayout->addWidget( slider, 0, 1, 1, 16 );
417     /* Update the position when the IM has changed */
418     CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
419              slider, setPosition( float, int, int ) );
420     /* And update the IM, when the position has changed */
421     CONNECT( slider, sliderDragged( float ),
422              THEMIM->getIM(), sliderUpdate( float ) );
423
424     /** Slower and faster Buttons **/
425     slowerButton = new QToolButton;
426     slowerButton->setAutoRaise( true );
427     slowerButton->setMaximumSize( QSize( 26, 20 ) );
428
429     BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() );
430     controlLayout->addWidget( slowerButton, 0, 0 );
431
432     fasterButton = new QToolButton;
433     fasterButton->setAutoRaise( true );
434     fasterButton->setMaximumSize( QSize( 26, 20 ) );
435
436     BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() );
437     controlLayout->addWidget( fasterButton, 0, 17 );
438
439     /* advanced Controls handling */
440     b_advancedVisible = b_advControls;
441
442     advControls = new AdvControlsWidget( p_intf );
443     controlLayout->addWidget( advControls, 1, 3, 2, 4, Qt::AlignBottom );
444     if( !b_advancedVisible ) advControls->hide();
445
446     /** Disc and Menus handling */
447     discFrame = new QWidget( this );
448
449     QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
450     discLayout->setSpacing( 0 );
451     discLayout->setMargin( 0 );
452
453     prevSectionButton = new QPushButton( discFrame );
454     setupSmallButton( prevSectionButton );
455     discLayout->addWidget( prevSectionButton );
456
457     menuButton = new QPushButton( discFrame );
458     setupSmallButton( menuButton );
459     discLayout->addWidget( menuButton );
460
461     nextSectionButton = new QPushButton( discFrame );
462     setupSmallButton( nextSectionButton );
463     discLayout->addWidget( nextSectionButton );
464
465     controlLayout->addWidget( discFrame, 1, 10, 2, 3, Qt::AlignBottom );
466
467     BUTTON_SET_IMG( prevSectionButton, "", previous.png, "" );
468     BUTTON_SET_IMG( nextSectionButton, "", next.png, "" );
469     BUTTON_SET_IMG( menuButton, "", previous.png, qtr( "Menu" ) );
470
471     discFrame->hide();
472
473     /* Change the navigation button display when the IM navigation changes */
474     CONNECT( THEMIM->getIM(), navigationChanged( int ),
475              this, setNavigation( int ) );
476     /* Changes the IM navigation when triggered on the nav buttons */
477     CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
478              sectionPrev() );
479     CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
480              sectionNext() );
481     CONNECT( menuButton, clicked(), THEMIM->getIM(),
482              sectionMenu() );
483
484     /**
485      * Telextext QFrame
486      * TODO: Merge with upper menu in a StackLayout
487      **/
488     telexFrame = new QWidget( this );
489     QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
490     telexLayout->setSpacing( 0 );
491     telexLayout->setMargin( 0 );
492
493     telexOn = new QPushButton;
494     setupSmallButton( telexOn );
495     telexLayout->addWidget( telexOn );
496
497     telexTransparent = new QPushButton;
498     setupSmallButton( telexTransparent );
499     telexLayout->addWidget( telexTransparent );
500     b_telexTransparent = false;
501
502     telexPage = new QSpinBox;
503     telexPage->setRange( 0, 999 );
504     telexPage->setValue( 100 );
505     telexPage->setAccelerated( true );
506     telexPage->setWrapping( true );
507     telexPage->setAlignment( Qt::AlignRight );
508     telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
509     telexLayout->addWidget( telexPage );
510
511     if( !b_fsCreation )
512         controlLayout->addWidget( telexFrame, 1, 10, 2, 4, Qt::AlignBottom );
513     telexFrame->hide(); /* default hidden */
514
515     CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
516              telexGotoPage( int ) );
517     CONNECT( THEMIM->getIM(), setNewTelexPage( int ),
518               telexPage, setValue( int ) );
519
520     BUTTON_SET_IMG( telexOn, "", tv.png, qtr( "Teletext on" ) );
521
522     CONNECT( telexOn, clicked(), THEMIM->getIM(),
523              telexToggleButtons() );
524     CONNECT( telexOn, clicked( bool ), THEMIM->getIM(),
525              telexToggle( bool ) );
526     CONNECT( THEMIM->getIM(), toggleTelexButtons(),
527               this, toggleTeletext() );
528     b_telexEnabled = false;
529     telexTransparent->setEnabled( false );
530     telexPage->setEnabled( false );
531
532     BUTTON_SET_IMG( telexTransparent, "", tvtelx.png, qtr( "Teletext" ) );
533     CONNECT( telexTransparent, clicked( bool ),
534              THEMIM->getIM(), telexSetTransparency() );
535     CONNECT( THEMIM->getIM(), toggleTelexTransparency(),
536               this, toggleTeletextTransparency() );
537     CONNECT( THEMIM->getIM(), teletextEnabled( bool ),
538              telexFrame, setVisible( bool ) );
539
540     /** Play Buttons **/
541     QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
542     sizePolicy.setHorizontalStretch( 0 );
543     sizePolicy.setVerticalStretch( 0 );
544
545     /* Play */
546     playButton = new QPushButton;
547     playButton->setSizePolicy( sizePolicy );
548     playButton->setMaximumSize( QSize( 36, 36 ) );
549     playButton->setMinimumSize( QSize( 36, 36 ) );
550     playButton->setIconSize( QSize( 30, 30 ) );
551
552     controlLayout->addWidget( playButton, 2, 0, 2, 2 );
553
554     controlLayout->setColumnMinimumWidth( 2, 20 );
555     controlLayout->setColumnStretch( 2, 0 );
556
557     /** Prev + Stop + Next Block **/
558     controlButLayout = new QHBoxLayout;
559     controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */
560
561     /* Prev */
562     QPushButton *prevButton = new QPushButton;
563     prevButton->setSizePolicy( sizePolicy );
564     setupSmallButton( prevButton );
565
566     controlButLayout->addWidget( prevButton );
567
568     /* Stop */
569     QPushButton *stopButton = new QPushButton;
570     stopButton->setSizePolicy( sizePolicy );
571     setupSmallButton( stopButton );
572
573     controlButLayout->addWidget( stopButton );
574
575     /* next */
576     QPushButton *nextButton = new QPushButton;
577     nextButton->setSizePolicy( sizePolicy );
578     setupSmallButton( nextButton );
579
580     controlButLayout->addWidget( nextButton );
581
582     /* Add this block to the main layout */
583     if( !b_fsCreation )
584         controlLayout->addLayout( controlButLayout, 3, 3, 1, 3 );
585
586     BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() );
587     BUTTON_SET_ACT_I( prevButton, "" , previous.png,
588                       qtr( "Previous" ), prev() );
589     BUTTON_SET_ACT_I( nextButton, "", next.png, qtr( "Next" ), next() );
590     BUTTON_SET_ACT_I( stopButton, "", stop.png, qtr( "Stop" ), stop() );
591
592     controlLayout->setColumnMinimumWidth( 7, 20 );
593     controlLayout->setColumnStretch( 7, 0 );
594     controlLayout->setColumnStretch( 8, 0 );
595     controlLayout->setColumnStretch( 9, 0 );
596
597     /*
598      * Other first Line buttons
599      */
600     /** Fullscreen/Visualisation **/
601     fullscreenButton = new QPushButton( "F" );
602     BUTTON_SET_ACT( fullscreenButton, "F", qtr( "Fullscreen" ), fullscreen() );
603     setupSmallButton( fullscreenButton );
604     controlLayout->addWidget( fullscreenButton, 3, 10, Qt::AlignBottom );
605
606     /** Playlist Button **/
607     playlistButton = new QPushButton;
608     setupSmallButton( playlistButton );
609     controlLayout->addWidget( playlistButton, 3, 11, Qt::AlignBottom );
610     BUTTON_SET_IMG( playlistButton, "" , playlist.png, qtr( "Show playlist" ) );
611     CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
612
613     /** extended Settings **/
614     extSettingsButton = new QPushButton;
615     BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended Settings" ),
616             extSettings() );
617     setupSmallButton( extSettingsButton );
618     controlLayout->addWidget( extSettingsButton, 3, 12, Qt::AlignBottom );
619
620     controlLayout->setColumnStretch( 13, 0 );
621     controlLayout->setColumnMinimumWidth( 13, 24 );
622     controlLayout->setColumnStretch( 14, 5 );
623
624     /* Volume */
625     hVolLabel = new VolumeClickHandler( p_intf, this );
626
627     volMuteLabel = new QLabel;
628     volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) );
629     volMuteLabel->setToolTip( qtr( "Mute" ) );
630     volMuteLabel->installEventFilter( hVolLabel );
631     controlLayout->addWidget( volMuteLabel, 3, 15, Qt::AlignBottom );
632
633     if( b_shiny )
634     {
635         volumeSlider = new SoundSlider( this,
636             config_GetInt( p_intf, "volume-step" ),
637             config_GetInt( p_intf, "qt-volume-complete" ),
638             config_GetPsz( p_intf, "qt-slider-colours" ) );
639     }
640     else
641     {
642         volumeSlider = new QSlider( this );
643         volumeSlider->setOrientation( Qt::Horizontal );
644     }
645     volumeSlider->setMaximumSize( QSize( 200, 40 ) );
646     volumeSlider->setMinimumSize( QSize( 106, 30 ) );
647     volumeSlider->setFocusPolicy( Qt::NoFocus );
648     controlLayout->addWidget( volumeSlider, 2, 16, 2 , 2, Qt::AlignBottom );
649
650     /* Set the volume from the config */
651     volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
652                               VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
653
654     /* Force the update at build time in order to have a muted icon if needed */
655     updateVolume( volumeSlider->value() );
656
657     /* Volume control connection */
658     CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
659     CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
660
661     updateInput();
662 }
663
664 ControlsWidget::~ControlsWidget()
665 {}
666
667 void ControlsWidget::toggleTeletext()
668 {
669     bool b_enabled = THEMIM->teletextState();
670     if( b_telexEnabled )
671     {
672         telexTransparent->setEnabled( false );
673         telexPage->setEnabled( false );
674         b_telexEnabled = false;
675     }
676     else if( b_enabled )
677     {
678         telexTransparent->setEnabled( true );
679         telexPage->setEnabled( true );
680         b_telexEnabled = true;
681     }
682 }
683
684 void ControlsWidget::toggleTeletextTransparency()
685 {
686     if( b_telexTransparent )
687     {
688         telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx.png" ) );
689         telexTransparent->setToolTip( qtr( "Teletext" ) );
690         b_telexTransparent = false;
691     }
692     else
693     {
694         telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx-transparent.png" ) );
695         telexTransparent->setToolTip( qtr( "Transparent" ) );
696         b_telexTransparent = true;
697     }
698 }
699
700 void ControlsWidget::stop()
701 {
702     THEMIM->stop();
703 }
704
705 void ControlsWidget::play()
706 {
707     if( THEPL->current.i_size == 0 )
708     {
709         /* The playlist is empty, open a file requester */
710         THEDP->openFileDialog();
711         setStatus( 0 );
712         return;
713     }
714     THEMIM->togglePlayPause();
715 }
716
717 void ControlsWidget::prev()
718 {
719     THEMIM->prev();
720 }
721
722 void ControlsWidget::next()
723 {
724     THEMIM->next();
725 }
726
727 void ControlsWidget::setNavigation( int navigation )
728 {
729 #define HELP_PCH N_( "Previous chapter" )
730 #define HELP_NCH N_( "Next chapter" )
731
732     // 1 = chapter, 2 = title, 0 = no
733     if( navigation == 0 )
734     {
735         discFrame->hide();
736     } else if( navigation == 1 ) {
737         prevSectionButton->setToolTip( qfu( HELP_PCH ) );
738         nextSectionButton->setToolTip( qfu( HELP_NCH ) );
739         menuButton->show();
740         discFrame->show();
741     } else {
742         prevSectionButton->setToolTip( qfu( HELP_PCH ) );
743         nextSectionButton->setToolTip( qfu( HELP_NCH ) );
744         menuButton->hide();
745         discFrame->show();
746     }
747 }
748
749 static bool b_my_volume;
750 void ControlsWidget::updateVolume( int i_sliderVolume )
751 {
752     if( !b_my_volume )
753     {
754         int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
755         aout_VolumeSet( p_intf, i_res );
756     }
757     if( i_sliderVolume == 0 )
758         volMuteLabel->setPixmap( QPixmap(":/pixmaps/volume-muted.png" ) );
759     else if( i_sliderVolume < VOLUME_MAX / 3 )
760         volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) );
761     else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
762         volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
763     else volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) );
764 }
765
766 void ControlsWidget::updateVolume()
767 {
768     /* Audio part */
769     audio_volume_t i_volume;
770     aout_VolumeGet( p_intf, &i_volume );
771     i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
772     int i_gauge = volumeSlider->value();
773     b_my_volume = false;
774     if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
775     {
776         b_my_volume = true;
777         volumeSlider->setValue( i_volume );
778         b_my_volume = false;
779     }
780 }
781
782 void ControlsWidget::updateInput()
783 {
784     /* Activate the interface buttons according to the presence of the input */
785     enableInput( THEMIM->getIM()->hasInput() );
786     enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() );
787 }
788
789 void ControlsWidget::setStatus( int status )
790 {
791     if( status == PLAYING_S ) /* Playing */
792     {
793         playButton->setIcon( QIcon( ":/pixmaps/pause.png" ) );
794         playButton->setToolTip( qtr( "Pause" ) );
795     }
796     else
797     {
798         playButton->setIcon( QIcon( ":/pixmaps/play.png" ) );
799         playButton->setToolTip( qtr( "Play" ) );
800     }
801 }
802
803 /**
804  * TODO
805  * This functions toggle the fullscreen mode
806  * If there is no video, it should first activate Visualisations...
807  *  This has also to be fixed in enableVideo()
808  */
809 void ControlsWidget::fullscreen()
810 {
811     vout_thread_t *p_vout =
812         (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
813     if( p_vout)
814     {
815         var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
816         vlc_object_release( p_vout );
817     }
818 }
819
820 void ControlsWidget::extSettings()
821 {
822     THEDP->extendedDialog();
823 }
824
825 void ControlsWidget::slower()
826 {
827     THEMIM->getIM()->slower();
828 }
829
830 void ControlsWidget::faster()
831 {
832     THEMIM->getIM()->faster();
833 }
834
835 void ControlsWidget::enableInput( bool enable )
836 {
837     slowerButton->setEnabled( enable );
838     slider->setEnabled( enable );
839     fasterButton->setEnabled( enable );
840
841     /* Advanced Buttons too */
842     advControls->enableInput( enable );
843 }
844
845 void ControlsWidget::enableVideo( bool enable )
846 {
847     // TODO Later make the fullscreenButton toggle Visualisation and so on.
848     fullscreenButton->setEnabled( enable );
849
850     /* Advanced Buttons too */
851     advControls->enableVideo( enable );
852 }
853
854 void ControlsWidget::toggleAdvanced()
855 {
856     if( !VISIBLE( advControls ) )
857     {
858         advControls->show();
859         b_advancedVisible = true;
860     }
861     else
862     {
863         advControls->hide();
864         b_advancedVisible = false;
865     }
866     emit advancedControlsToggled( b_advancedVisible );
867 }
868
869
870 /**********************************************************************
871  * Fullscrenn control widget
872  **********************************************************************/
873 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i,
874         MainInterface *_p_mi, bool b_advControls, bool b_shiny )
875         : ControlsWidget( _p_i, _p_mi, b_advControls, b_shiny, true ),
876         i_lastPosX( -1 ), i_lastPosY( -1 ), i_hideTimeout( 1 ),
877         b_mouseIsOver( false ), b_isFullscreen( false )
878 {
879     setWindowFlags( Qt::ToolTip );
880
881     setFrameShape( QFrame::StyledPanel );
882     setFrameStyle( QFrame::Sunken );
883     setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
884
885     QGridLayout *fsLayout = new QGridLayout( this );
886     controlLayout->setSpacing( 0 );
887     controlLayout->setLayoutMargins( 5, 1, 5, 1, 5 );
888
889     fsLayout->addWidget( slowerButton, 0, 0 );
890     slider->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum);
891     fsLayout->addWidget( slider, 0, 1, 1, 6 );
892     fsLayout->addWidget( fasterButton, 0, 7 );
893
894     fsLayout->addWidget( volMuteLabel, 1, 0);
895     fsLayout->addWidget( volumeSlider, 1, 1 );
896
897     fsLayout->addLayout( controlButLayout, 1, 2 );
898
899     fsLayout->addWidget( playButton, 1, 3 );
900
901     fsLayout->addWidget( discFrame, 1, 4 );
902
903     fsLayout->addWidget( telexFrame, 1, 5 );
904
905     fsLayout->addWidget( advControls, 1, 6, Qt::AlignVCenter );
906
907     fsLayout->addWidget( fullscreenButton, 1, 7 );
908
909     /* hiding timer */
910     p_hideTimer = new QTimer( this );
911     CONNECT( p_hideTimer, timeout(), this, hideFSControllerWidget() );
912     p_hideTimer->setSingleShot( true );
913
914     /* slow hiding timer */
915 #if HAVE_TRANSPARENCY
916     p_slowHideTimer = new QTimer( this );
917     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
918 #endif
919
920     adjustSize ();  /* need to get real width and height for moving */
921
922     /* center down */
923     QDesktopWidget * p_desktop = QApplication::desktop();
924
925     move( p_desktop->width() / 2 - width() / 2,
926           p_desktop->height() - height() );
927
928     #ifdef WIN32TRICK
929     setWindowOpacity( 0.0 );
930     fscHidden = true;
931     show();
932     #endif
933 }
934
935 FullscreenControllerWidget::~FullscreenControllerWidget()
936 {
937 }
938
939 /**
940  * Hide fullscreen controller
941  * FIXME: under windows it have to be done by moving out of screen
942  *        because hide() doesnt work
943  */
944 void FullscreenControllerWidget::hideFSControllerWidget()
945 {
946     #ifdef WIN32TRICK
947     fscHidden = true;
948     setWindowOpacity( 0.0 );    // simulate hidding
949     #else
950     hide();
951     #endif
952 }
953
954 /**
955  * Hidding fullscreen controller slowly
956  * Linux: need composite manager
957  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
958  */
959 void FullscreenControllerWidget::slowHideFSC()
960 {
961 #if HAVE_TRANSPARENCY
962     static bool first_call = true;
963
964     if ( first_call )
965     {
966         first_call = false;
967
968         p_slowHideTimer->stop();
969         /* the last part of time divided to 100 pieces */
970         p_slowHideTimer->start(
971             (int) ( i_hideTimeout / 2 / ( windowOpacity() * 100 ) ) );
972     }
973     else
974     {
975 #ifdef WIN32TRICK
976          if ( windowOpacity() > 0.0 && !fscHidden )
977 #else
978          if ( windowOpacity() > 0.0 )
979 #endif
980          {
981              /* we should use 0.01 because of 100 pieces ^^^
982                 but than it cannt be done in time */
983              setWindowOpacity( windowOpacity() - 0.02 );
984          }
985
986          if ( windowOpacity() == 0.0 )
987          {
988              first_call = true;
989              p_slowHideTimer->stop();
990          }
991     }
992 #endif
993 }
994
995 /**
996  * Get state of visibility of FS controller on screen
997  * On windows control if it is on hidden position
998  */
999 bool FullscreenControllerWidget::isFSCHidden()
1000 {
1001     #ifdef WIN32TRICK
1002     return fscHidden;
1003     #endif
1004
1005     return isHidden();
1006 }
1007
1008 /**
1009  * event handling
1010  * events: show, hide, start timer for hidding
1011  */
1012 void FullscreenControllerWidget::customEvent( QEvent *event )
1013 {
1014     int type = event->type();
1015
1016     if ( type == FullscreenControlShow_Type && b_isFullscreen )
1017     {
1018         #ifdef WIN32TRICK
1019         // after quiting and going to fs, we need to call show()
1020         if ( isHidden() )
1021             show();
1022
1023         if ( fscHidden )
1024         {
1025             fscHidden = false;
1026             setWindowOpacity( 1.0 );
1027         }
1028         #else
1029         show();
1030         #endif
1031
1032 #if HAVE_TRANSPARENCY
1033         setWindowOpacity( DEFAULT_OPACITY );
1034 #endif
1035     }
1036     else if ( type == FullscreenControlHide_Type )
1037     {
1038         hideFSControllerWidget();
1039     }
1040     else if ( type == FullscreenControlPlanHide_Type && !b_mouseIsOver )
1041     {
1042         p_hideTimer->start( i_hideTimeout );
1043 #if HAVE_TRANSPARENCY
1044         p_slowHideTimer->start( i_hideTimeout / 2 );
1045 #endif
1046     }
1047 }
1048
1049 /**
1050  * On mouse move
1051  * moving with FSC
1052  */
1053 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1054 {
1055     if ( event->buttons() == Qt::LeftButton )
1056     {
1057         int i_moveX = event->globalX() - i_lastPosX;
1058         int i_moveY = event->globalY() - i_lastPosY;
1059
1060         move( x() + i_moveX, y() + i_moveY );
1061
1062         i_lastPosX = event->globalX();
1063         i_lastPosY = event->globalY();
1064     }
1065 }
1066
1067 /**
1068  * On mouse press
1069  * store position of cursor
1070  */
1071 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1072 {
1073     i_lastPosX = event->globalX();
1074     i_lastPosY = event->globalY();
1075 }
1076
1077 /**
1078  * On mouse go above FSC
1079  */
1080 void FullscreenControllerWidget::enterEvent( QEvent *event )
1081 {
1082     p_hideTimer->stop();
1083 #if HAVE_TRANSPARENCY
1084     p_slowHideTimer->stop();
1085 #endif
1086     b_mouseIsOver = true;
1087 }
1088
1089 /**
1090  * On mouse go out from FSC
1091  */
1092 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1093 {
1094     p_hideTimer->start( i_hideTimeout );
1095 #if HAVE_TRANSPARENCY
1096     p_slowHideTimer->start( i_hideTimeout / 2 );
1097 #endif
1098     b_mouseIsOver = false;
1099 }
1100
1101 /**
1102  * When you get pressed key, send it to video output
1103  * FIXME: clearing focus by clearFocus() to not getting
1104  * key press events didnt work
1105  */
1106 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1107 {
1108     int i_vlck = qtEventToVLCKey( event );
1109     if( i_vlck > 0 )
1110     {
1111         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1112         event->accept();
1113     }
1114     else
1115         event->ignore();
1116 }
1117
1118 /**
1119  * It is called when video start
1120  */
1121 void FullscreenControllerWidget::regFullscreenCallback( vout_thread_t *p_vout )
1122 {
1123     if ( p_vout )
1124     {
1125         var_AddCallback( p_vout, "fullscreen", regMouseMoveCallback, this );
1126     }
1127 }
1128
1129 /**
1130  * It is called after turn off video, because p_vout is NULL now
1131  * we cannt delete callback, just hide if FScontroller is visible
1132  */
1133 void FullscreenControllerWidget::unregFullscreenCallback()
1134 {
1135     if ( isVisible() )
1136         hide();
1137 }
1138
1139 /**
1140  * Register and unregister callback for mouse moving
1141  */
1142 static int regMouseMoveCallback( vlc_object_t *vlc_object, const char *variable,
1143                                  vlc_value_t old_val, vlc_value_t new_val,
1144                                  void *data )
1145 {
1146     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1147
1148     static bool b_registered = false;
1149     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *) data;
1150
1151     if ( var_GetBool( p_vout, "fullscreen" ) && !b_registered )
1152     {
1153         p_fs->setHideTimeout( var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1154         p_fs->setIsFullscreen( true );
1155         var_AddCallback( p_vout, "mouse-moved",
1156                         showFullscreenControllCallback, (void *) p_fs );
1157         b_registered = true;
1158     }
1159
1160     if ( !var_GetBool( p_vout, "fullscreen" ) && b_registered )
1161     {
1162         p_fs->setIsFullscreen( false );
1163         p_fs->hide();
1164         var_DelCallback( p_vout, "mouse-moved",
1165                         showFullscreenControllCallback, (void *) p_fs );
1166         b_registered = false;
1167     }
1168
1169     return VLC_SUCCESS;
1170 }
1171
1172 /**
1173  * Show fullscreen controller after mouse move
1174  * after show immediately plan hide event
1175  */
1176 static int showFullscreenControllCallback( vlc_object_t *vlc_object, const char *variable,
1177                                            vlc_value_t old_val, vlc_value_t new_val,
1178                                            void *data )
1179 {
1180     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *) data;
1181
1182     if ( p_fs->isFSCHidden() || p_fs->windowOpacity() < DEFAULT_OPACITY )
1183     {
1184         IMEvent *event = new IMEvent( FullscreenControlShow_Type, 0 );
1185         QApplication::postEvent( p_fs, static_cast<QEvent *>(event) );
1186     }
1187
1188     IMEvent *e = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1189     QApplication::postEvent( p_fs, static_cast<QEvent *>(e) );
1190
1191     return VLC_SUCCESS;
1192 }
1193
1194 /**********************************************************************
1195  * Speed control widget
1196  **********************************************************************/
1197 SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
1198                              QFrame( NULL ), p_intf( _p_i )
1199 {
1200     QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
1201     sizePolicy.setHorizontalStretch( 0 );
1202     sizePolicy.setVerticalStretch( 0 );
1203
1204     speedSlider = new QSlider;
1205     speedSlider->setSizePolicy( sizePolicy );
1206     speedSlider->setMaximumSize( QSize( 80, 200 ) );
1207     speedSlider->setOrientation( Qt::Vertical );
1208     speedSlider->setTickPosition( QSlider::TicksRight );
1209
1210     speedSlider->setRange( -100, 100 );
1211     speedSlider->setSingleStep( 10 );
1212     speedSlider->setPageStep( 20 );
1213     speedSlider->setTickInterval( 20 );
1214
1215     CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
1216
1217     QToolButton *normalSpeedButton = new QToolButton( this );
1218     normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
1219     normalSpeedButton->setAutoRaise( true );
1220     normalSpeedButton->setText( "N" );
1221     normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
1222
1223     CONNECT( normalSpeedButton, clicked(), this, resetRate() );
1224
1225     QVBoxLayout *speedControlLayout = new QVBoxLayout;
1226     speedControlLayout->addWidget( speedSlider );
1227     speedControlLayout->addWidget( normalSpeedButton );
1228     setLayout( speedControlLayout );
1229 }
1230
1231 SpeedControlWidget::~SpeedControlWidget()
1232 {}
1233
1234 void SpeedControlWidget::setEnable( bool b_enable )
1235 {
1236     speedSlider->setEnabled( b_enable );
1237 }
1238
1239 #define RATE_SLIDER_MAXIMUM 3.0
1240 #define RATE_SLIDER_MINIMUM 0.3
1241 #define RATE_SLIDER_LENGTH 100.0
1242
1243 void SpeedControlWidget::updateControls( int rate )
1244 {
1245     if( speedSlider->isSliderDown() )
1246     {
1247         //We don't want to change anything if the user is using the slider
1248         return;
1249     }
1250
1251     int sliderValue;
1252     double speed = INPUT_RATE_DEFAULT / (double)rate;
1253
1254     if( rate >= INPUT_RATE_DEFAULT )
1255     {
1256         if( speed < RATE_SLIDER_MINIMUM )
1257         {
1258             sliderValue = speedSlider->minimum();
1259         }
1260         else
1261         {
1262             sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
1263                                         / ( 1.0 - RATE_SLIDER_MAXIMUM ) );
1264         }
1265     }
1266     else
1267     {
1268         if( speed > RATE_SLIDER_MAXIMUM )
1269         {
1270             sliderValue = speedSlider->maximum();
1271         }
1272         else
1273         {
1274             sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
1275                                         / ( RATE_SLIDER_MAXIMUM - 1.0 ) );
1276         }
1277     }
1278
1279     //Block signals to avoid feedback loop
1280     speedSlider->blockSignals( true );
1281     speedSlider->setValue( sliderValue );
1282     speedSlider->blockSignals( false );
1283 }
1284
1285 void SpeedControlWidget::updateRate( int sliderValue )
1286 {
1287     int rate;
1288
1289     if( sliderValue < 0.0 )
1290     {
1291         rate = (int)(INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
1292             ( sliderValue * ( 1.0 - RATE_SLIDER_MINIMUM ) + RATE_SLIDER_LENGTH ));
1293     }
1294     else
1295     {
1296         rate = (int)(INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
1297             ( sliderValue * ( RATE_SLIDER_MAXIMUM - 1.0 ) + RATE_SLIDER_LENGTH ));
1298     }
1299
1300     THEMIM->getIM()->setRate(rate);
1301 }
1302
1303 void SpeedControlWidget::resetRate()
1304 {
1305     THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT);
1306 }