a77f726d9d9c6eac68c3427d6489263311da307b
[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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_vout.h>
32
33 #include "dialogs_provider.hpp"
34 #include "components/interface_widgets.hpp"
35 #include "main_interface.hpp"
36 #include "input_manager.hpp"
37 #include "menus.hpp"
38 #include "util/input_slider.hpp"
39 #include "util/customwidgets.hpp"
40
41 #include <QLabel>
42 #include <QSpacerItem>
43 #include <QCursor>
44 #include <QPushButton>
45 #include <QToolButton>
46 #include <QHBoxLayout>
47 #include <QMenu>
48 #include <QPalette>
49 #include <QResizeEvent>
50 #include <QDate>
51
52 #ifdef Q_WS_X11
53 # include <X11/Xlib.h>
54 # include <qx11info_x11.h>
55 #endif
56
57 #include <math.h>
58
59 #define I_PLAY_TOOLTIP N_("Play\nIf the playlist is empty, open a media")
60
61 /**********************************************************************
62  * Video Widget. A simple frame on which video is drawn
63  * This class handles resize issues
64  **********************************************************************/
65
66 VideoWidget::VideoWidget( intf_thread_t *_p_i ) : QFrame( NULL ), p_intf( _p_i )
67 {
68     /* Init */
69     p_vout = NULL;
70     videoSize.rwidth() = -1;
71     videoSize.rheight() = -1;
72
73     hide();
74
75     /* Set the policy to expand in both directions */
76 //    setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
77
78     /* Black background is more coherent for a Video Widget */
79     QPalette plt =  palette();
80     plt.setColor( QPalette::Window, Qt::black );
81     setPalette( plt );
82     setAutoFillBackground(true);
83
84     /* Indicates that the widget wants to draw directly onto the screen.
85        Widgets with this attribute set do not participate in composition
86        management */
87     setAttribute( Qt::WA_PaintOnScreen, true );
88
89     /* The core can ask through a callback to show the video. */
90 #if HAS_QT43
91     connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)),
92              this, SLOT(SetSizing(unsigned int, unsigned int )),
93              Qt::BlockingQueuedConnection );
94 #else
95 #warning This is broken. Fix it with a QEventLoop with a processEvents ()
96     connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)),
97              this, SLOT(SetSizing(unsigned int, unsigned int )) );
98 #endif
99 }
100
101 void VideoWidget::paintEvent(QPaintEvent *ev)
102 {
103     QFrame::paintEvent(ev);
104 #ifdef Q_WS_X11
105     XFlush( QX11Info::display() );
106 #endif
107 }
108
109 /* Kill the vout at Destruction */
110 VideoWidget::~VideoWidget()
111 {
112     if( !p_vout )
113         return;
114     if( vout_Control( p_vout, VOUT_CLOSE ) != VLC_SUCCESS )
115         vout_Control( p_vout, VOUT_REPARENT );
116 }
117
118 /**
119  * Request the video to avoid the conflicts
120  **/
121 void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
122                             unsigned int *pi_width, unsigned int *pi_height )
123 {
124     msg_Dbg( p_intf, "Video was requested %i, %i", *pi_x, *pi_y );
125     emit askVideoWidgetToShow( *pi_width, *pi_height );
126     if( p_vout )
127     {
128         msg_Dbg( p_intf, "embedded video already in use" );
129         return NULL;
130     }
131     p_vout = p_nvout;
132 #ifndef NDEBUG
133     msg_Dbg( p_intf, "embedded video ready (handle %p)", winId() );
134 #endif
135     return ( void* )winId();
136 }
137
138 /* Set the Widget to the correct Size */
139 /* Function has to be called by the parent
140    Parent has to care about resizing himself*/
141 void VideoWidget::SetSizing( unsigned int w, unsigned int h )
142 {
143     msg_Dbg( p_intf, "Video is resizing to: %i %i", w, h );
144     videoSize.rwidth() = w;
145     videoSize.rheight() = h;
146     if( isHidden() ) show();
147     updateGeometry(); // Needed for deinterlace
148 }
149
150 void VideoWidget::release( void *p_win )
151 {
152     msg_Dbg( p_intf, "Video is not needed anymore" );
153     p_vout = NULL;
154     videoSize.rwidth() = 0;
155     videoSize.rheight() = 0;
156     updateGeometry();
157     hide();
158 }
159
160 QSize VideoWidget::sizeHint() const
161 {
162     return videoSize;
163 }
164
165 /**********************************************************************
166  * Background Widget. Show a simple image background. Currently,
167  * it's album art if present or cone.
168  **********************************************************************/
169 #define ICON_SIZE 128
170 #define MAX_BG_SIZE 400
171 #define MIN_BG_SIZE 128
172
173 BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
174                  :QWidget( NULL ), p_intf( _p_i )
175 {
176     /* We should use that one to take the more size it can */
177     setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding);
178
179     /* A dark background */
180     setAutoFillBackground( true );
181     plt = palette();
182     plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
183     plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
184     setPalette( plt );
185
186     /* A cone in the middle */
187     label = new QLabel;
188     label->setMargin( 5 );
189     label->setMaximumHeight( MAX_BG_SIZE );
190     label->setMaximumWidth( MAX_BG_SIZE );
191     label->setMinimumHeight( MIN_BG_SIZE );
192     label->setMinimumWidth( MIN_BG_SIZE );
193     if( QDate::currentDate().dayOfYear() >= 354 )
194         label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) );
195     else
196         label->setPixmap( QPixmap( ":/vlc128.png" ) );
197
198     QGridLayout *backgroundLayout = new QGridLayout( this );
199     backgroundLayout->addWidget( label, 0, 1 );
200     backgroundLayout->setColumnStretch( 0, 1 );
201     backgroundLayout->setColumnStretch( 2, 1 );
202
203     CONNECT( THEMIM->getIM(), artChanged( input_item_t* ),
204              this, updateArt( input_item_t* ) );
205 }
206
207 BackgroundWidget::~BackgroundWidget()
208 {}
209
210 void BackgroundWidget::resizeEvent( QResizeEvent * event )
211 {
212     if( event->size().height() <= MIN_BG_SIZE )
213         label->hide();
214     else
215         label->show();
216 }
217
218 void BackgroundWidget::updateArt( input_item_t *p_item )
219 {
220     QString url;
221     if( p_item )
222     {
223         char *psz_art = input_item_GetArtURL( p_item );
224         url = psz_art;
225         free( psz_art );
226     }
227
228     if( url.isEmpty() )
229     {
230         if( QDate::currentDate().dayOfYear() >= 354 )
231             label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) );
232         else
233             label->setPixmap( QPixmap( ":/vlc128.png" ) );
234     }
235     else
236     {
237         url = url.replace( "file://", QString("" ) );
238         /* Taglib seems to define a attachment://, It won't work yet */
239         url = url.replace( "attachment://", QString("" ) );
240         label->setPixmap( QPixmap( url ) );
241     }
242 }
243
244 void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
245 {
246     QVLCMenu::PopupMenu( p_intf, true );
247 }
248
249 #if 0
250 /**********************************************************************
251  * Visualization selector panel
252  **********************************************************************/
253 VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
254                                 QFrame( NULL ), p_intf( _p_i )
255 {
256     QHBoxLayout *layout = new QHBoxLayout( this );
257     layout->setMargin( 0 );
258     QPushButton *prevButton = new QPushButton( "Prev" );
259     QPushButton *nextButton = new QPushButton( "Next" );
260     layout->addWidget( prevButton );
261     layout->addWidget( nextButton );
262
263     layout->addStretch( 10 );
264     layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
265
266     current = new QLabel( qtr( "None" ) );
267     layout->addWidget( current );
268
269     BUTTONACT( prevButton, prev() );
270     BUTTONACT( nextButton, next() );
271
272     setLayout( layout );
273     setMaximumHeight( 35 );
274 }
275
276 VisualSelector::~VisualSelector()
277 {}
278
279 void VisualSelector::prev()
280 {
281     char *psz_new = aout_VisualPrev( p_intf );
282     if( psz_new )
283     {
284         current->setText( qfu( psz_new ) );
285         free( psz_new );
286     }
287 }
288
289 void VisualSelector::next()
290 {
291     char *psz_new = aout_VisualNext( p_intf );
292     if( psz_new )
293     {
294         current->setText( qfu( psz_new ) );
295         free( psz_new );
296     }
297 }
298 #endif
299
300 /**********************************************************************
301  * TEH controls
302  **********************************************************************/
303
304 static void setupSmallButton( QPushButton *aButton )
305 {
306     aButton->setMaximumSize( QSize( 26, 26 ) );
307     aButton->setMinimumSize( QSize( 26, 26 ) );
308     aButton->setIconSize( QSize( 20, 20 ) );
309     aButton->setFocusPolicy( Qt::NoFocus );
310 }
311
312 /* init static variables in advanced controls */
313 mtime_t AdvControlsWidget::timeA = 0;
314 mtime_t AdvControlsWidget::timeB = 0;
315
316 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i, bool b_fsCreation = false ) :
317                                            QFrame( NULL ), p_intf( _p_i )
318 {
319     QHBoxLayout *advLayout = new QHBoxLayout( this );
320     advLayout->setMargin( 0 );
321     advLayout->setSpacing( 0 );
322     advLayout->setAlignment( Qt::AlignBottom );
323
324     /* A to B Button */
325     ABButton = new QPushButton;
326     setupSmallButton( ABButton );
327     advLayout->addWidget( ABButton );
328     BUTTON_SET_ACT_I( ABButton, "", atob_nob,
329       qtr( "Loop from point A to point B continuously.\nClick to set point A" ),
330       fromAtoB() );
331     timeA = timeB = 0;
332     i_last_input_id = 0;
333     /* in FS controller we skip this, because we dont want to have it double
334        controlled */
335     if( !b_fsCreation )
336         CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
337                  this, AtoBLoop( float, int, int ) );
338     /* set up synchronization between main controller and fs controller */
339     CONNECT( THEMIM->getIM(), advControlsSetIcon(), this, setIcon() );
340     connect( this, SIGNAL( timeChanged() ),
341         THEMIM->getIM(), SIGNAL( advControlsSetIcon()));
342 #if 0
343     frameButton = new QPushButton( "Fr" );
344     frameButton->setMaximumSize( QSize( 26, 26 ) );
345     frameButton->setIconSize( QSize( 20, 20 ) );
346     advLayout->addWidget( frameButton );
347     BUTTON_SET_ACT( frameButton, "Fr", qtr( "Frame by frame" ), frame() );
348 #endif
349
350     /* Record Button */
351     recordButton = new QPushButton;
352     setupSmallButton( recordButton );
353     advLayout->addWidget( recordButton );
354     BUTTON_SET_ACT_I( recordButton, "", record,
355             qtr( "Record" ), record() );
356
357     /* Snapshot Button */
358     snapshotButton = new QPushButton;
359     setupSmallButton( snapshotButton );
360     advLayout->addWidget( snapshotButton );
361     BUTTON_SET_ACT_I( snapshotButton, "", snapshot,
362             qtr( "Take a snapshot" ), snapshot() );
363 }
364
365 AdvControlsWidget::~AdvControlsWidget()
366 {}
367
368 void AdvControlsWidget::enableInput( bool enable )
369 {
370     int i_input_id = 0;
371     if( THEMIM->getInput() != NULL )
372     {
373         input_item_t *p_item = input_GetItem( THEMIM->getInput() );
374         i_input_id = p_item->i_id;
375
376         recordButton->setVisible( var_GetBool( THEMIM->getInput(), "can-record" ) );
377     }
378     else
379     {
380         recordButton->setVisible( false );
381     }
382
383     ABButton->setEnabled( enable );
384     recordButton->setEnabled( enable );
385
386     if( enable && ( i_last_input_id != i_input_id ) )
387     {
388         timeA = timeB = 0;
389         i_last_input_id = i_input_id;
390         emit timeChanged();
391     }
392 }
393
394 void AdvControlsWidget::enableVideo( bool enable )
395 {
396     snapshotButton->setEnabled( enable );
397 #if 0
398     frameButton->setEnabled( enable );
399 #endif
400 }
401
402 void AdvControlsWidget::snapshot()
403 {
404     vout_thread_t *p_vout =
405         (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
406     if( p_vout )
407     {
408         vout_Control( p_vout, VOUT_SNAPSHOT );
409         vlc_object_release( p_vout );
410     }
411 }
412
413 /* Function called when the button is clicked() */
414 void AdvControlsWidget::fromAtoB()
415 {
416     if( !timeA )
417     {
418         timeA = var_GetTime( THEMIM->getInput(), "time"  );
419         emit timeChanged();
420         return;
421     }
422     if( !timeB )
423     {
424         timeB = var_GetTime( THEMIM->getInput(), "time"  );
425         var_SetTime( THEMIM->getInput(), "time" , timeA );
426         emit timeChanged();
427         return;
428     }
429     timeA = 0;
430     timeB = 0;
431     emit timeChanged();
432 }
433
434 /* setting/synchro icons after click on main or fs controller */
435 void AdvControlsWidget::setIcon()
436 {
437     if( !timeA && !timeB)
438     {
439         ABButton->setIcon( QIcon( ":/atob_nob" ) );
440         ABButton->setToolTip( qtr( "Loop from point A to point B continuously\nClick to set point A" ) );
441     }
442     else if( timeA && !timeB )
443     {
444         ABButton->setIcon( QIcon( ":/atob_noa" ) );
445         ABButton->setToolTip( qtr( "Click to set point B" ) );
446     }
447     else if( timeA && timeB )
448     {
449         ABButton->setIcon( QIcon( ":/atob" ) );
450         ABButton->setToolTip( qtr( "Stop the A to B loop" ) );
451     }
452 }
453
454 /* Function called regularly when in an AtoB loop */
455 void AdvControlsWidget::AtoBLoop( float f_pos, int i_time, int i_length )
456 {
457     if( timeB )
458     {
459         if( ( i_time >= (int)( timeB/1000000 ) )
460             || ( i_time < (int)( timeA/1000000 ) ) )
461             var_SetTime( THEMIM->getInput(), "time" , timeA );
462     }
463 }
464
465 void AdvControlsWidget::record()
466 {
467     input_thread_t *p_input = THEMIM->getInput();
468     if( p_input )
469     {
470         /* This method won't work fine if the stream can't be cut anywhere */
471         const bool b_recording = var_GetBool( p_input, "record" );
472         var_SetBool( p_input, "record", !b_recording );
473 #if 0
474         else
475         {
476             /* 'record' access-filter is not loaded, we open Save dialog */
477             input_item_t *p_item = input_GetItem( p_input );
478             if( !p_item )
479                 return;
480
481             char *psz = input_item_GetURI( p_item );
482             if( psz )
483                 THEDP->streamingDialog( NULL, psz, true );
484         }
485 #endif
486     }
487 }
488
489 #if 0
490 //FIXME Frame by frame function
491 void AdvControlsWidget::frame(){}
492 #endif
493
494 /*****************************
495  * DA Control Widget !
496  *****************************/
497 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
498                                 MainInterface *_p_mi,
499                                 bool b_advControls,
500                                 bool b_shiny,
501                                 bool b_fsCreation) :
502                                 QFrame( _p_mi ), p_intf( _p_i )
503 {
504     setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
505
506     /** The main Slider **/
507     slider = new InputSlider( Qt::Horizontal, NULL );
508     /* Update the position when the IM has changed */
509     CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
510              slider, setPosition( float, int, int ) );
511     /* And update the IM, when the position has changed */
512     CONNECT( slider, sliderDragged( float ),
513              THEMIM->getIM(), sliderUpdate( float ) );
514
515     /** Slower and faster Buttons **/
516     slowerButton = new QToolButton;
517     slowerButton->setAutoRaise( true );
518     slowerButton->setMaximumSize( QSize( 26, 20 ) );
519     slowerButton->setFocusPolicy( Qt::NoFocus );
520
521     BUTTON_SET_ACT_I( slowerButton, "", slower, qtr( "Slower" ), slower() );
522
523     fasterButton = new QToolButton;
524     fasterButton->setAutoRaise( true );
525     fasterButton->setMaximumSize( QSize( 26, 20 ) );
526     fasterButton->setFocusPolicy( Qt::NoFocus );
527
528     BUTTON_SET_ACT_I( fasterButton, "", faster, qtr( "Faster" ), faster() );
529
530     /* advanced Controls handling */
531     b_advancedVisible = b_advControls;
532
533     advControls = new AdvControlsWidget( p_intf, b_fsCreation );
534     if( !b_advancedVisible ) advControls->hide();
535
536     /** Disc and Menus handling */
537     discFrame = new QWidget( this );
538
539     QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
540     discLayout->setSpacing( 0 );
541     discLayout->setMargin( 0 );
542
543     prevSectionButton = new QPushButton( discFrame );
544     setupSmallButton( prevSectionButton );
545     discLayout->addWidget( prevSectionButton );
546
547     menuButton = new QPushButton( discFrame );
548     setupSmallButton( menuButton );
549     discLayout->addWidget( menuButton );
550
551     nextSectionButton = new QPushButton( discFrame );
552     setupSmallButton( nextSectionButton );
553     discLayout->addWidget( nextSectionButton );
554
555     BUTTON_SET_IMG( prevSectionButton, "", dvd_prev, "" );
556     BUTTON_SET_IMG( nextSectionButton, "", dvd_next, "" );
557     BUTTON_SET_IMG( menuButton, "", dvd_menu, qtr( "Menu" ) );
558
559     discFrame->hide();
560
561     /* Change the navigation button display when the IM navigation changes */
562     CONNECT( THEMIM->getIM(), navigationChanged( int ),
563              this, setNavigation( int ) );
564     /* Changes the IM navigation when triggered on the nav buttons */
565     CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
566              sectionPrev() );
567     CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
568              sectionNext() );
569     CONNECT( menuButton, clicked(), THEMIM->getIM(),
570              sectionMenu() );
571
572     /**
573      * Telextext QFrame
574      * TODO: Merge with upper menu in a StackLayout
575      **/
576     telexFrame = new QWidget( this );
577     QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
578     telexLayout->setSpacing( 0 );
579     telexLayout->setMargin( 0 );
580
581     telexOn = new QPushButton;
582     setupSmallButton( telexOn );
583     telexLayout->addWidget( telexOn );
584
585     telexTransparent = new QPushButton;
586     setupSmallButton( telexTransparent );
587     telexLayout->addWidget( telexTransparent );
588     b_telexTransparent = false;
589
590     telexPage = new QSpinBox;
591     telexPage->setRange( 0, 999 );
592     telexPage->setValue( 100 );
593     telexPage->setAccelerated( true );
594     telexPage->setWrapping( true );
595     telexPage->setAlignment( Qt::AlignRight );
596     telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
597     telexLayout->addWidget( telexPage );
598
599     telexFrame->hide(); /* default hidden */
600
601     CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
602              telexGotoPage( int ) );
603     CONNECT( THEMIM->getIM(), setNewTelexPage( int ),
604               telexPage, setValue( int ) );
605
606     BUTTON_SET_IMG( telexOn, "", tv, qtr( "Teletext on" ) );
607
608     CONNECT( telexOn, clicked(), THEMIM->getIM(),
609              telexToggleButtons() );
610     CONNECT( telexOn, clicked( bool ), THEMIM->getIM(),
611              telexToggle( bool ) );
612     CONNECT( THEMIM->getIM(), toggleTelexButtons(),
613               this, toggleTeletext() );
614     b_telexEnabled = false;
615     telexTransparent->setEnabled( false );
616     telexPage->setEnabled( false );
617
618     BUTTON_SET_IMG( telexTransparent, "", tvtelx, qtr( "Teletext" ) );
619     CONNECT( telexTransparent, clicked( bool ),
620              THEMIM->getIM(), telexSetTransparency() );
621     CONNECT( THEMIM->getIM(), toggleTelexTransparency(),
622               this, toggleTeletextTransparency() );
623     CONNECT( THEMIM->getIM(), teletextEnabled( bool ),
624              this, enableTeletext( bool ) );
625
626     /** Play Buttons **/
627     QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
628     sizePolicy.setHorizontalStretch( 0 );
629     sizePolicy.setVerticalStretch( 0 );
630
631     /* Play */
632     playButton = new QPushButton;
633     playButton->setSizePolicy( sizePolicy );
634     playButton->setMaximumSize( QSize( 32, 32 ) );
635     playButton->setMinimumSize( QSize( 32, 32 ) );
636     playButton->setIconSize( QSize( 26, 26 ) );
637     playButton->setFocusPolicy( Qt::NoFocus );
638
639     /** Prev + Stop + Next Block **/
640     controlButLayout = new QHBoxLayout;
641     controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */
642
643     /* Prev */
644     QPushButton *prevButton = new QPushButton;
645     prevButton->setSizePolicy( sizePolicy );
646     setupSmallButton( prevButton );
647
648     controlButLayout->addWidget( prevButton );
649
650     /* Stop */
651     QPushButton *stopButton = new QPushButton;
652     stopButton->setSizePolicy( sizePolicy );
653     setupSmallButton( stopButton );
654
655     controlButLayout->addWidget( stopButton );
656
657     /* next */
658     QPushButton *nextButton = new QPushButton;
659     nextButton->setSizePolicy( sizePolicy );
660     setupSmallButton( nextButton );
661
662     controlButLayout->addWidget( nextButton );
663
664     /* Add this block to the main layout */
665
666     BUTTON_SET_ACT_I( playButton, "", play_b, qtr( I_PLAY_TOOLTIP ), play() );
667     BUTTON_SET_ACT_I( prevButton, "" , previous_b,
668                       qtr( "Previous media in the playlist" ), prev() );
669     BUTTON_SET_ACT_I( nextButton, "", next_b,
670                       qtr( "Next media in the playlist" ), next() );
671     BUTTON_SET_ACT_I( stopButton, "", stop_b, qtr( "Stop playback" ), stop() );
672
673     /*
674      * Other first Line buttons
675      */
676     /* */
677     CONNECT( THEMIM->getIM(), voutChanged(bool), this, enableVideo(bool) );
678
679     /** Fullscreen/Visualisation **/
680     fullscreenButton = new QPushButton;
681     BUTTON_SET_ACT_I( fullscreenButton, "", fullscreen,
682             qtr( "Toggle the video in fullscreen" ), fullscreen() );
683     setupSmallButton( fullscreenButton );
684
685     if( !b_fsCreation )
686     {
687         /** Playlist Button **/
688         playlistButton = new QPushButton;
689         setupSmallButton( playlistButton );
690         BUTTON_SET_IMG( playlistButton, "" , playlist, qtr( "Show playlist" ) );
691         CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
692
693         /** extended Settings **/
694         extSettingsButton = new QPushButton;
695         BUTTON_SET_ACT_I( extSettingsButton, "", extended,
696                 qtr( "Show extended settings" ), extSettings() );
697         setupSmallButton( extSettingsButton );
698     }
699
700     /* Volume */
701     hVolLabel = new VolumeClickHandler( p_intf, this );
702
703     volMuteLabel = new QLabel;
704     volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
705     volMuteLabel->installEventFilter( hVolLabel );
706
707     if( b_shiny )
708     {
709         volumeSlider = new SoundSlider( this,
710             config_GetInt( p_intf, "volume-step" ),
711             config_GetInt( p_intf, "qt-volume-complete" ),
712             config_GetPsz( p_intf, "qt-slider-colours" ) );
713     }
714     else
715     {
716         volumeSlider = new QSlider( this );
717         volumeSlider->setOrientation( Qt::Horizontal );
718     }
719     volumeSlider->setMaximumSize( QSize( 200, 40 ) );
720     volumeSlider->setMinimumSize( QSize( 85, 30 ) );
721     volumeSlider->setFocusPolicy( Qt::NoFocus );
722
723     /* Set the volume from the config */
724     volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
725                               VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
726
727     /* Force the update at build time in order to have a muted icon if needed */
728     updateVolume( volumeSlider->value() );
729
730     /* Volume control connection */
731     CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
732     CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
733
734     if( !b_fsCreation )
735     {
736         controlLayout = new QGridLayout( this );
737
738         controlLayout->setSpacing( 0 );
739         controlLayout->setLayoutMargins( 7, 5, 7, 3, 6 );
740
741         controlLayout->addWidget( slider, 0, 1, 1, 18 );
742         controlLayout->addWidget( slowerButton, 0, 0 );
743         controlLayout->addWidget( fasterButton, 0, 19 );
744
745         controlLayout->addWidget( discFrame, 1, 8, 2, 3, Qt::AlignBottom );
746         controlLayout->addWidget( telexFrame, 1, 8, 2, 5, Qt::AlignBottom );
747
748         controlLayout->addWidget( playButton, 2, 0, 2, 2, Qt::AlignBottom );
749         controlLayout->setColumnMinimumWidth( 2, 10 );
750         controlLayout->setColumnStretch( 2, 0 );
751
752         controlLayout->addLayout( controlButLayout, 3, 3, 1, 3, Qt::AlignBottom );
753         /* Column 6 is unused */
754         controlLayout->setColumnStretch( 6, 0 );
755         controlLayout->setColumnStretch( 7, 0 );
756         controlLayout->setColumnMinimumWidth( 7, 10 );
757
758         controlLayout->addWidget( fullscreenButton, 3, 8, Qt::AlignBottom );
759         controlLayout->addWidget( playlistButton, 3, 9, Qt::AlignBottom );
760         controlLayout->addWidget( extSettingsButton, 3, 10, Qt::AlignBottom );
761         controlLayout->setColumnStretch( 11, 0 ); /* telex alignment */
762
763         controlLayout->setColumnStretch( 12, 0 );
764         controlLayout->setColumnMinimumWidth( 12, 10 );
765
766         controlLayout->addWidget( advControls, 3, 13, 1, 3, Qt::AlignBottom );
767
768         controlLayout->setColumnStretch( 16, 10 );
769         controlLayout->setColumnMinimumWidth( 16, 10 );
770
771         controlLayout->addWidget( volMuteLabel, 3, 17, Qt::AlignBottom );
772         controlLayout->addWidget( volumeSlider, 3, 18, 1 , 2, Qt::AlignBottom );
773     }
774
775     updateInput();
776 }
777
778 ControlsWidget::~ControlsWidget()
779 {}
780
781 void ControlsWidget::toggleTeletext()
782 {
783     bool b_enabled = THEMIM->teletextState();
784     if( b_telexEnabled )
785     {
786         telexTransparent->setEnabled( false );
787         telexPage->setEnabled( false );
788         b_telexEnabled = false;
789     }
790     else if( b_enabled )
791     {
792         telexTransparent->setEnabled( true );
793         telexPage->setEnabled( true );
794         b_telexEnabled = true;
795     }
796 }
797
798 void ControlsWidget::enableTeletext( bool b_enable )
799 {
800     telexFrame->setVisible( b_enable );
801     bool b_on = THEMIM->teletextState();
802
803     telexOn->setChecked( b_on );
804     telexTransparent->setEnabled( b_on );
805     telexPage->setEnabled( b_on );
806     b_telexEnabled = b_on;
807 }
808
809 void ControlsWidget::toggleTeletextTransparency()
810 {
811     if( b_telexTransparent )
812     {
813         telexTransparent->setIcon( QIcon( ":/tvtelx" ) );
814         telexTransparent->setToolTip( qtr( "Teletext" ) );
815         b_telexTransparent = false;
816     }
817     else
818     {
819         telexTransparent->setIcon( QIcon( ":/tvtelx-trans" ) );
820         telexTransparent->setToolTip( qtr( "Transparent" ) );
821         b_telexTransparent = true;
822     }
823 }
824
825 void ControlsWidget::stop()
826 {
827     THEMIM->stop();
828 }
829
830 void ControlsWidget::play()
831 {
832     if( THEPL->current.i_size == 0 )
833     {
834         /* The playlist is empty, open a file requester */
835         THEDP->openFileDialog();
836         setStatus( 0 );
837         return;
838     }
839     THEMIM->togglePlayPause();
840 }
841
842 void ControlsWidget::prev()
843 {
844     THEMIM->prev();
845 }
846
847 void ControlsWidget::next()
848 {
849     THEMIM->next();
850 }
851
852 void ControlsWidget::setNavigation( int navigation )
853 {
854 #define HELP_PCH N_( "Previous chapter" )
855 #define HELP_NCH N_( "Next chapter" )
856
857     // 1 = chapter, 2 = title, 0 = no
858     if( navigation == 0 )
859     {
860         discFrame->hide();
861     } else if( navigation == 1 ) {
862         prevSectionButton->setToolTip( qtr( HELP_PCH ) );
863         nextSectionButton->setToolTip( qtr( HELP_NCH ) );
864         menuButton->show();
865         discFrame->show();
866     } else {
867         prevSectionButton->setToolTip( qtr( HELP_PCH ) );
868         nextSectionButton->setToolTip( qtr( HELP_NCH ) );
869         menuButton->hide();
870         discFrame->show();
871     }
872 }
873
874 static bool b_my_volume;
875 void ControlsWidget::updateVolume( int i_sliderVolume )
876 {
877     if( !b_my_volume )
878     {
879         int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
880         aout_VolumeSet( p_intf, i_res );
881     }
882     if( i_sliderVolume == 0 )
883     {
884         volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
885         volMuteLabel->setToolTip( qtr( "Unmute" ) );
886         return;
887     }
888
889     if( i_sliderVolume < VOLUME_MAX / 3 )
890         volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
891     else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
892         volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
893     else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
894     volMuteLabel->setToolTip( qtr( "Mute" ) );
895 }
896
897 void ControlsWidget::updateVolume()
898 {
899     /* Audio part */
900     audio_volume_t i_volume;
901     aout_VolumeGet( p_intf, &i_volume );
902     i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
903     int i_gauge = volumeSlider->value();
904     b_my_volume = false;
905     if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
906     {
907         b_my_volume = true;
908         volumeSlider->setValue( i_volume );
909         b_my_volume = false;
910     }
911 }
912
913 void ControlsWidget::updateInput()
914 {
915     /* Activate the interface buttons according to the presence of the input */
916     enableInput( THEMIM->getIM()->hasInput() );
917     enableVideo( THEMIM->getIM()->hasVideo() );
918 }
919
920 void ControlsWidget::setStatus( int status )
921 {
922     if( status == PLAYING_S ) /* Playing */
923     {
924         playButton->setIcon( QIcon( ":/pause_b" ) );
925         playButton->setToolTip( qtr( "Pause the playback" ) );
926     }
927     else
928     {
929         playButton->setIcon( QIcon( ":/play_b" ) );
930         playButton->setToolTip( qtr( I_PLAY_TOOLTIP ) );
931     }
932 }
933
934 /**
935  * TODO
936  * This functions toggle the fullscreen mode
937  * If there is no video, it should first activate Visualisations...
938  *  This has also to be fixed in enableVideo()
939  */
940 void ControlsWidget::fullscreen()
941 {
942     vout_thread_t *p_vout =
943         (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
944     if( p_vout)
945     {
946         var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
947         vlc_object_release( p_vout );
948     }
949 }
950
951 void ControlsWidget::extSettings()
952 {
953     THEDP->extendedDialog();
954 }
955
956 void ControlsWidget::slower()
957 {
958     THEMIM->getIM()->slower();
959 }
960
961 void ControlsWidget::faster()
962 {
963     THEMIM->getIM()->faster();
964 }
965
966 void ControlsWidget::enableInput( bool enable )
967 {
968     slowerButton->setEnabled( enable );
969     slider->setEnabled( enable );
970     slider->setSliderPosition ( 0 );
971     fasterButton->setEnabled( enable );
972
973     /* Advanced Buttons too */
974     advControls->enableInput( enable );
975 }
976
977 void ControlsWidget::enableVideo( bool enable )
978 {
979     // TODO Later make the fullscreenButton toggle Visualisation and so on.
980     fullscreenButton->setEnabled( enable );
981
982     /* Advanced Buttons too */
983     advControls->enableVideo( enable );
984 }
985
986 void ControlsWidget::toggleAdvanced()
987 {
988     if( advControls && !b_advancedVisible )
989     {
990         advControls->show();
991         b_advancedVisible = true;
992     }
993     else
994     {
995         advControls->hide();
996         b_advancedVisible = false;
997     }
998     emit advancedControlsToggled( b_advancedVisible );
999 }
1000
1001 /**********************************************************************
1002  * Fullscrenn control widget
1003  **********************************************************************/
1004 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i,
1005         MainInterface *_p_mi, bool b_advControls, bool b_shiny )
1006         : ControlsWidget( _p_i, _p_mi, b_advControls, b_shiny, true ),
1007           i_mouse_last_x( -1 ), i_mouse_last_y( -1 ), b_mouse_over(false),
1008           b_slow_hide_begin(false), i_slow_hide_timeout(1),
1009           b_fullscreen( false ), i_hide_timeout( 1 ), p_vout(NULL)
1010 {
1011     i_mouse_last_move_x = -1;
1012     i_mouse_last_move_y = -1;
1013
1014     setWindowFlags( Qt::ToolTip );
1015
1016     setFrameShape( QFrame::StyledPanel );
1017     setFrameStyle( QFrame::Sunken );
1018     setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1019
1020     QGridLayout *fsLayout = new QGridLayout( this );
1021     fsLayout->setLayoutMargins( 5, 2, 5, 2, 5 );
1022
1023     /* First line */
1024     slider->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum);
1025     slider->setMinimumWidth( 300 );
1026     fsLayout->addWidget( slowerButton, 0, 0 );
1027     fsLayout->addWidget( slider, 0, 1, 1, 9 );
1028     fsLayout->addWidget( fasterButton, 0, 10 );
1029
1030     fsLayout->addWidget( playButton, 1, 0, 1, 2 );
1031     fsLayout->addLayout( controlButLayout, 1, 2 );
1032
1033     fsLayout->addWidget( discFrame, 1, 3 );
1034     fsLayout->addWidget( telexFrame, 1, 4 );
1035     fsLayout->addWidget( fullscreenButton, 1, 5 );
1036     fsLayout->addWidget( advControls, 1, 6, Qt::AlignVCenter );
1037
1038     fsLayout->setColumnStretch( 7, 10 );
1039     fsLayout->addWidget( volMuteLabel, 1, 8 );
1040     fsLayout->addWidget( volumeSlider, 1, 9, 1, 2 );
1041
1042     /* hiding timer */
1043     p_hideTimer = new QTimer( this );
1044     CONNECT( p_hideTimer, timeout(), this, hideFSC() );
1045     p_hideTimer->setSingleShot( true );
1046
1047     /* slow hiding timer */
1048 #if HAVE_TRANSPARENCY
1049     p_slowHideTimer = new QTimer( this );
1050     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
1051 #endif
1052
1053     adjustSize ();  /* need to get real width and height for moving */
1054
1055     /* center down */
1056     QDesktopWidget * p_desktop = QApplication::desktop();
1057
1058     move( p_desktop->width() / 2 - width() / 2,
1059           p_desktop->height() - height() );
1060
1061 #ifdef WIN32TRICK
1062     setWindowOpacity( 0.0 );
1063     b_fscHidden = true;
1064     adjustSize();
1065     show();
1066 #endif
1067
1068     fullscreenButton->setIcon( QIcon( ":/defullscreen" ) );
1069
1070     vlc_mutex_init_recursive( &lock );
1071 }
1072
1073 FullscreenControllerWidget::~FullscreenControllerWidget()
1074 {
1075     detachVout();
1076     vlc_mutex_destroy( &lock );
1077 }
1078
1079 /**
1080  * Show fullscreen controller
1081  */
1082 void FullscreenControllerWidget::showFSC()
1083 {
1084     adjustSize();
1085 #ifdef WIN32TRICK
1086     // after quiting and going to fs, we need to call show()
1087     if( isHidden() )
1088         show();
1089
1090     if( b_fscHidden )
1091     {
1092         b_fscHidden = false;
1093         setWindowOpacity( 1.0 );
1094     }
1095 #else
1096     show();
1097 #endif
1098
1099 #if HAVE_TRANSPARENCY
1100     setWindowOpacity( DEFAULT_OPACITY );
1101 #endif
1102 }
1103
1104 /**
1105  * Hide fullscreen controller
1106  * FIXME: under windows it have to be done by moving out of screen
1107  *        because hide() doesnt work
1108  */
1109 void FullscreenControllerWidget::hideFSC()
1110 {
1111 #ifdef WIN32TRICK
1112     b_fscHidden = true;
1113     setWindowOpacity( 0.0 );    // simulate hidding
1114 #else
1115     hide();
1116 #endif
1117 }
1118
1119 /**
1120  * Plane to hide fullscreen controller
1121  */
1122 void FullscreenControllerWidget::planHideFSC()
1123 {
1124     vlc_mutex_lock( &lock );
1125     int i_timeout = i_hide_timeout;
1126     vlc_mutex_unlock( &lock );
1127
1128     p_hideTimer->start( i_timeout );
1129
1130 #if HAVE_TRANSPARENCY
1131     b_slow_hide_begin = true;
1132     i_slow_hide_timeout = i_timeout;
1133     p_slowHideTimer->start( i_slow_hide_timeout / 2 );
1134 #endif
1135 }
1136
1137 /**
1138  * Hidding fullscreen controller slowly
1139  * Linux: need composite manager
1140  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
1141  */
1142 void FullscreenControllerWidget::slowHideFSC()
1143 {
1144 #if HAVE_TRANSPARENCY
1145     if( b_slow_hide_begin )
1146     {
1147         b_slow_hide_begin = false;
1148
1149         p_slowHideTimer->stop();
1150         /* the last part of time divided to 100 pieces */
1151         p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
1152
1153     }
1154     else
1155     {
1156 #ifdef WIN32TRICK
1157          if ( windowOpacity() > 0.0 && !b_fscHidden )
1158 #else
1159          if ( windowOpacity() > 0.0 )
1160 #endif
1161          {
1162              /* we should use 0.01 because of 100 pieces ^^^
1163                 but than it cannt be done in time */
1164              setWindowOpacity( windowOpacity() - 0.02 );
1165          }
1166
1167          if ( windowOpacity() <= 0.0 )
1168              p_slowHideTimer->stop();
1169     }
1170 #endif
1171 }
1172
1173 /**
1174  * event handling
1175  * events: show, hide, start timer for hidding
1176  */
1177 void FullscreenControllerWidget::customEvent( QEvent *event )
1178 {
1179     bool b_fs;
1180
1181     switch( event->type() )
1182     {
1183         case FullscreenControlToggle_Type:
1184             vlc_mutex_lock( &lock );
1185             b_fs = b_fullscreen;
1186             vlc_mutex_unlock( &lock );
1187             if( b_fs )
1188 #ifdef WIN32TRICK
1189                 if( b_fscHidden )
1190 #else
1191                 if( isHidden() )
1192 #endif
1193                 {
1194                     p_hideTimer->stop();
1195                     showFSC();
1196                 }
1197                 else
1198                     hideFSC();
1199             break;
1200         case FullscreenControlShow_Type:
1201             vlc_mutex_lock( &lock );
1202             b_fs = b_fullscreen;
1203             vlc_mutex_unlock( &lock );
1204
1205 #ifdef WIN32TRICK
1206             if( b_fs && b_fscHidden )  // FIXME I am not sure about that one
1207 #else
1208             if( b_fs && !isVisible() )  // FIXME I am not sure about that one
1209 #endif
1210                 showFSC();
1211             break;
1212         case FullscreenControlHide_Type:
1213             hideFSC();
1214             break;
1215         case FullscreenControlPlanHide_Type:
1216             if( !b_mouse_over ) // Only if the mouse is not over FSC
1217                 planHideFSC();
1218             break;
1219     }
1220 }
1221
1222 /**
1223  * On mouse move
1224  * moving with FSC
1225  */
1226 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1227 {
1228     if ( event->buttons() == Qt::LeftButton )
1229     {
1230         int i_moveX = event->globalX() - i_mouse_last_x;
1231         int i_moveY = event->globalY() - i_mouse_last_y;
1232
1233         move( x() + i_moveX, y() + i_moveY );
1234
1235         i_mouse_last_x = event->globalX();
1236         i_mouse_last_y = event->globalY();
1237     }
1238 }
1239
1240 /**
1241  * On mouse press
1242  * store position of cursor
1243  */
1244 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1245 {
1246     i_mouse_last_x = event->globalX();
1247     i_mouse_last_y = event->globalY();
1248 }
1249
1250 /**
1251  * On mouse go above FSC
1252  */
1253 void FullscreenControllerWidget::enterEvent( QEvent *event )
1254 {
1255     b_mouse_over = true;
1256
1257     p_hideTimer->stop();
1258 #if HAVE_TRANSPARENCY
1259     p_slowHideTimer->stop();
1260 #endif
1261 }
1262
1263 /**
1264  * On mouse go out from FSC
1265  */
1266 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1267 {
1268     planHideFSC();
1269
1270     b_mouse_over = false;
1271 }
1272
1273 /**
1274  * When you get pressed key, send it to video output
1275  * FIXME: clearing focus by clearFocus() to not getting
1276  * key press events didnt work
1277  */
1278 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1279 {
1280     int i_vlck = qtEventToVLCKey( event );
1281     if( i_vlck > 0 )
1282     {
1283         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1284         event->accept();
1285     }
1286     else
1287         event->ignore();
1288 }
1289
1290 /* */
1291 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
1292                 const char *variable, vlc_value_t old_val,
1293                 vlc_value_t new_val,  void *data )
1294 {
1295     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1296     msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
1297     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1298
1299     p_fs->fullscreenChanged( p_vout, new_val.b_bool,
1300             var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1301
1302     return VLC_SUCCESS;
1303 }
1304 /* */
1305 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1306                                                  vlc_value_t old_val, vlc_value_t new_val,
1307                                                  void *data )
1308 {
1309     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1310
1311     int i_mousex, i_mousey;
1312     bool b_toShow = false;
1313
1314     /* Get the value from the Vout - Trust the vout more than Qt */
1315     i_mousex = var_GetInteger( p_fs->p_vout, "mouse-x" );
1316     i_mousey = var_GetInteger( p_fs->p_vout, "mouse-y" );
1317
1318     /* First time */
1319     if( p_fs->i_mouse_last_move_x == -1 || p_fs->i_mouse_last_move_y == -1 )
1320     {
1321         p_fs->i_mouse_last_move_x = i_mousex;
1322         p_fs->i_mouse_last_move_y = i_mousey;
1323         b_toShow = true;
1324     }
1325     /* All other times */
1326     else
1327     {
1328         /* Trigger only if move > 3 px dans une direction */
1329         if( abs( p_fs->i_mouse_last_move_x - i_mousex ) > 2 ||
1330             abs( p_fs->i_mouse_last_move_y - i_mousey ) > 2 )
1331         {
1332             b_toShow = true;
1333             p_fs->i_mouse_last_move_x = i_mousex;
1334             p_fs->i_mouse_last_move_y = i_mousey;
1335         }
1336     }
1337
1338     if( b_toShow )
1339     {
1340         /* Show event */
1341         IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1342         QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1343
1344         /* Plan hide event */
1345         IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1346         QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1347     }
1348
1349     return VLC_SUCCESS;
1350 }
1351
1352
1353 /**
1354  * It is called when video start
1355  */
1356 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1357 {
1358     assert( p_nvout && !p_vout );
1359
1360     p_vout = p_nvout;
1361
1362     msg_Dbg( p_vout, "Qt FS: Attaching Vout" );
1363     vlc_mutex_lock( &lock );
1364
1365     var_AddCallback( p_vout, "fullscreen",
1366             FullscreenControllerWidgetFullscreenChanged, this );
1367             /* I miss a add and fire */
1368     fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1369                        var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1370     vlc_mutex_unlock( &lock );
1371 }
1372 /**
1373  * It is called after turn off video.
1374  */
1375 void FullscreenControllerWidget::detachVout()
1376 {
1377     if( p_vout )
1378     {
1379         msg_Dbg( p_vout, "Qt FS: Detaching Vout" );
1380         var_DelCallback( p_vout, "fullscreen",
1381                 FullscreenControllerWidgetFullscreenChanged, this );
1382         vlc_mutex_lock( &lock );
1383         fullscreenChanged( p_vout, false, 0 );
1384         vlc_mutex_unlock( &lock );
1385         p_vout = NULL;
1386     }
1387 }
1388
1389 /**
1390  * Register and unregister callback for mouse moving
1391  */
1392 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1393         bool b_fs, int i_timeout )
1394 {
1395     msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1396
1397     vlc_mutex_lock( &lock );
1398     /* Entering fullscreen, register callback */
1399     if( b_fs && !b_fullscreen )
1400     {
1401         b_fullscreen = true;
1402         i_hide_timeout = i_timeout;
1403         var_AddCallback( p_vout, "mouse-moved",
1404                 FullscreenControllerWidgetMouseMoved, this );
1405     }
1406     /* Quitting fullscreen, unregistering callback */
1407     else if( !b_fs && b_fullscreen )
1408     {
1409         b_fullscreen = false;
1410         i_hide_timeout = i_timeout;
1411         var_DelCallback( p_vout, "mouse-moved",
1412                 FullscreenControllerWidgetMouseMoved, this );
1413
1414         /* Force fs hidding */
1415         IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1416         QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1417     }
1418     vlc_mutex_unlock( &lock );
1419 }
1420
1421 /**********************************************************************
1422  * Speed control widget
1423  **********************************************************************/
1424 SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
1425                              QFrame( NULL ), p_intf( _p_i )
1426 {
1427     QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
1428     sizePolicy.setHorizontalStretch( 0 );
1429     sizePolicy.setVerticalStretch( 0 );
1430
1431     speedSlider = new QSlider;
1432     speedSlider->setSizePolicy( sizePolicy );
1433     speedSlider->setMaximumSize( QSize( 80, 200 ) );
1434     speedSlider->setOrientation( Qt::Vertical );
1435     speedSlider->setTickPosition( QSlider::TicksRight );
1436
1437     speedSlider->setRange( -24, 24 );
1438     speedSlider->setSingleStep( 1 );
1439     speedSlider->setPageStep( 1 );
1440     speedSlider->setTickInterval( 12 );
1441
1442     CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
1443
1444     QToolButton *normalSpeedButton = new QToolButton( this );
1445     normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
1446     normalSpeedButton->setAutoRaise( true );
1447     normalSpeedButton->setText( "1x" );
1448     normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
1449
1450     CONNECT( normalSpeedButton, clicked(), this, resetRate() );
1451
1452     QVBoxLayout *speedControlLayout = new QVBoxLayout;
1453     speedControlLayout->setLayoutMargins( 4, 4, 4, 4, 4 );
1454     speedControlLayout->setSpacing( 4 );
1455     speedControlLayout->addWidget( speedSlider );
1456     speedControlLayout->addWidget( normalSpeedButton );
1457     setLayout( speedControlLayout );
1458 }
1459
1460 SpeedControlWidget::~SpeedControlWidget()
1461 {}
1462
1463 void SpeedControlWidget::setEnable( bool b_enable )
1464 {
1465     speedSlider->setEnabled( b_enable );
1466 }
1467
1468 void SpeedControlWidget::updateControls( int rate )
1469 {
1470     if( speedSlider->isSliderDown() )
1471     {
1472         //We don't want to change anything if the user is using the slider
1473         return;
1474     }
1475
1476     double value = 12 * log( (double)INPUT_RATE_DEFAULT / rate ) / log( 2 );
1477     int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 );
1478
1479     if( sliderValue < speedSlider->minimum() )
1480     {
1481         sliderValue = speedSlider->minimum();
1482     }
1483     else if( sliderValue > speedSlider->maximum() )
1484     {
1485         sliderValue = speedSlider->maximum();
1486     }
1487
1488     //Block signals to avoid feedback loop
1489     speedSlider->blockSignals( true );
1490     speedSlider->setValue( sliderValue );
1491     speedSlider->blockSignals( false );
1492 }
1493
1494 void SpeedControlWidget::updateRate( int sliderValue )
1495 {
1496     double speed = pow( 2, (double)sliderValue / 12 );
1497     int rate = INPUT_RATE_DEFAULT / speed;
1498
1499     THEMIM->getIM()->setRate(rate);
1500 }
1501
1502 void SpeedControlWidget::resetRate()
1503 {
1504     THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT);
1505 }
1506
1507
1508
1509 static int downloadCoverCallback( vlc_object_t *p_this,
1510                                   char const *psz_var,
1511                                   vlc_value_t oldvar, vlc_value_t newvar,
1512                                   void *data )
1513 {
1514     if( !strcmp( psz_var, "item-change" ) )
1515     {
1516         CoverArtLabel *art = static_cast< CoverArtLabel* >( data );
1517         if( art )
1518             art->requestUpdate();
1519     }
1520     return VLC_SUCCESS;
1521 }
1522
1523 CoverArtLabel::CoverArtLabel( QWidget *parent,
1524                               vlc_object_t *_p_this,
1525                               input_item_t *_p_input )
1526         : QLabel( parent ), p_this( _p_this), p_input( _p_input ), prevArt()
1527 {
1528     setContextMenuPolicy( Qt::ActionsContextMenu );
1529     CONNECT( this, updateRequested(), this, doUpdate() );
1530
1531     playlist_t *p_playlist = pl_Hold( p_this );
1532     var_AddCallback( p_playlist, "item-change",
1533                      downloadCoverCallback, this );
1534     pl_Release( p_this );
1535
1536     setMinimumHeight( 128 );
1537     setMinimumWidth( 128 );
1538     setMaximumHeight( 128 );
1539     setMaximumWidth( 128 );
1540     setScaledContents( true );
1541
1542     doUpdate();
1543 }
1544
1545 void CoverArtLabel::downloadCover()
1546 {
1547     if( p_input )
1548     {
1549         playlist_t *p_playlist = pl_Hold( p_this );
1550         playlist_AskForArtEnqueue( p_playlist, p_input );
1551         pl_Release( p_this );
1552     }
1553 }
1554
1555 void CoverArtLabel::doUpdate()
1556 {
1557     if( !p_input )
1558     {
1559         setPixmap( QPixmap( ":/noart.png" ) );
1560         QList< QAction* > artActions = actions();
1561         if( !artActions.isEmpty() )
1562             foreach( QAction *act, artActions )
1563                 removeAction( act );
1564         prevArt = "";
1565     }
1566     else
1567     {
1568         char *psz_meta = input_item_GetArtURL( p_input );
1569         if( psz_meta && !strncmp( psz_meta, "file://", 7 ) )
1570         {
1571             QString artUrl = qfu( psz_meta ).replace( "file://", "" );
1572             if( artUrl != prevArt )
1573             {
1574                 QPixmap pix;
1575                 if( pix.load( artUrl ) )
1576                     setPixmap( pix );
1577                 else
1578                 {
1579                     msg_Dbg( p_this, "Qt could not load image '%s'",
1580                              qtu( artUrl ) );
1581                     setPixmap( QPixmap( ":/noart.png" ) );
1582                 }
1583             }
1584             QList< QAction* > artActions = actions();
1585             if( !artActions.isEmpty() )
1586             {
1587                 foreach( QAction *act, artActions )
1588                     removeAction( act );
1589             }
1590             prevArt = artUrl;
1591         }
1592         else
1593         {
1594             if( prevArt != "" )
1595                 setPixmap( QPixmap( ":/noart.png" ) );
1596             prevArt = "";
1597             QList< QAction* > artActions = actions();
1598             if( artActions.isEmpty() )
1599             {
1600                 QAction *action = new QAction( qtr( "Download cover art" ),
1601                                                this );
1602                 addAction( action );
1603                 CONNECT( action, triggered(),
1604                          this, downloadCover() );
1605             }
1606         }
1607         free( psz_meta );
1608     }
1609 }
1610