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