]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/interface_widgets.cpp
ec1391d2515f20b3800f151f2594d6d9e0736f42
[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 <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( slowerButton, "-", 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( fasterButton, "+", 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     setWindowFlags( Qt::ToolTip );
1012
1013     setFrameShape( QFrame::StyledPanel );
1014     setFrameStyle( QFrame::Sunken );
1015     setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1016
1017     QGridLayout *fsLayout = new QGridLayout( this );
1018     fsLayout->setLayoutMargins( 5, 2, 5, 2, 5 );
1019
1020     /* First line */
1021     slider->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum);
1022     slider->setMinimumWidth( 300 );
1023     fsLayout->addWidget( slowerButton, 0, 0 );
1024     fsLayout->addWidget( slider, 0, 1, 1, 9 );
1025     fsLayout->addWidget( fasterButton, 0, 10 );
1026
1027     fsLayout->addWidget( playButton, 1, 0, 1, 2 );
1028     fsLayout->addLayout( controlButLayout, 1, 2 );
1029
1030     fsLayout->addWidget( discFrame, 1, 3 );
1031     fsLayout->addWidget( telexFrame, 1, 4 );
1032     fsLayout->addWidget( fullscreenButton, 1, 5 );
1033     fsLayout->addWidget( advControls, 1, 6, Qt::AlignVCenter );
1034
1035     fsLayout->setColumnStretch( 7, 10 );
1036     fsLayout->addWidget( volMuteLabel, 1, 8 );
1037     fsLayout->addWidget( volumeSlider, 1, 9, 1, 2 );
1038
1039     /* hiding timer */
1040     p_hideTimer = new QTimer( this );
1041     CONNECT( p_hideTimer, timeout(), this, hideFSC() );
1042     p_hideTimer->setSingleShot( true );
1043
1044     /* slow hiding timer */
1045 #if HAVE_TRANSPARENCY
1046     p_slowHideTimer = new QTimer( this );
1047     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
1048 #endif
1049
1050     adjustSize ();  /* need to get real width and height for moving */
1051
1052     /* center down */
1053     QDesktopWidget * p_desktop = QApplication::desktop();
1054
1055     move( p_desktop->width() / 2 - width() / 2,
1056           p_desktop->height() - height() );
1057
1058 #ifdef WIN32TRICK
1059     setWindowOpacity( 0.0 );
1060     b_fscHidden = true;
1061     adjustSize();
1062     show();
1063 #endif
1064
1065     fullscreenButton->setIcon( QIcon( ":/defullscreen" ) );
1066
1067     vlc_mutex_init_recursive( &lock );
1068 }
1069
1070 FullscreenControllerWidget::~FullscreenControllerWidget()
1071 {
1072     detachVout();
1073     vlc_mutex_destroy( &lock );
1074 }
1075
1076 /**
1077  * Show fullscreen controller
1078  */
1079 void FullscreenControllerWidget::showFSC()
1080 {
1081     adjustSize();
1082 #ifdef WIN32TRICK
1083     msg_Dbg( p_intf, "showFSC() was called" );
1084     // after quiting and going to fs, we need to call show()
1085     if( isHidden() )
1086         show();
1087
1088     if( b_fscHidden )
1089     {
1090         b_fscHidden = false;
1091         setWindowOpacity( 1.0 );
1092     }
1093 #else
1094     show();
1095 #endif
1096
1097 #if HAVE_TRANSPARENCY
1098     setWindowOpacity( DEFAULT_OPACITY );
1099 #endif
1100 }
1101
1102 /**
1103  * Hide fullscreen controller
1104  * FIXME: under windows it have to be done by moving out of screen
1105  *        because hide() doesnt work
1106  */
1107 void FullscreenControllerWidget::hideFSC()
1108 {
1109 #ifdef WIN32TRICK
1110     msg_Dbg( p_intf, "hideFSC() was called" );
1111     b_fscHidden = true;
1112     setWindowOpacity( 0.0 );    // simulate hidding
1113 #else
1114     hide();
1115 #endif
1116 }
1117
1118 /**
1119  * Plane to hide fullscreen controller
1120  */
1121 void FullscreenControllerWidget::planHideFSC()
1122 {
1123     vlc_mutex_lock( &lock );
1124     int i_timeout = i_hide_timeout;
1125     vlc_mutex_unlock( &lock );
1126
1127     p_hideTimer->start( i_timeout );
1128
1129 #if HAVE_TRANSPARENCY
1130     b_slow_hide_begin = true;
1131     i_slow_hide_timeout = i_timeout;
1132     p_slowHideTimer->start( i_slow_hide_timeout / 2 );
1133 #endif
1134 }
1135
1136 /**
1137  * Hidding fullscreen controller slowly
1138  * Linux: need composite manager
1139  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
1140  */
1141 void FullscreenControllerWidget::slowHideFSC()
1142 {
1143 #if HAVE_TRANSPARENCY
1144     if( b_slow_hide_begin )
1145     {
1146         b_slow_hide_begin = false;
1147
1148         p_slowHideTimer->stop();
1149         /* the last part of time divided to 100 pieces */
1150         p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
1151
1152     }
1153     else
1154     {
1155 #ifdef WIN32TRICK
1156         msg_Dbg( p_intf, "slowHideFSC() was called" );
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 #ifndef NDEBUG
1182     msg_Dbg( p_intf, "New FSC event: %i", event->type() );
1183 #endif
1184
1185     switch( event->type() )
1186     {
1187         case FullscreenControlToggle_Type:
1188             vlc_mutex_lock( &lock );
1189             b_fs = b_fullscreen;
1190             vlc_mutex_unlock( &lock );
1191             if( b_fs )
1192 #ifdef WIN32TRICK
1193                 if( b_fscHidden )
1194 #else
1195                 if( isHidden() )
1196 #endif
1197                 {
1198                     p_hideTimer->stop();
1199                     showFSC();
1200                 }
1201                 else
1202                     hideFSC();
1203             break;
1204         case FullscreenControlShow_Type:
1205             vlc_mutex_lock( &lock );
1206             b_fs = b_fullscreen;
1207             vlc_mutex_unlock( &lock );
1208
1209             if( b_fs )  // FIXME I am not sure about that one
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, const char *variable,
1292                                                         vlc_value_t old_val, vlc_value_t new_val,
1293                                                         void *data )
1294 {
1295     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1296     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1297
1298     p_fs->fullscreenChanged( p_vout, new_val.b_bool, var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1299
1300     return VLC_SUCCESS;
1301 }
1302 /* */
1303 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1304                                                  vlc_value_t old_val, vlc_value_t new_val,
1305                                                  void *data )
1306 {
1307     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1308
1309     /* Show event */
1310     IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1311     QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1312
1313     /* Plan hide event */
1314     IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1315     QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1316
1317     return VLC_SUCCESS;
1318 }
1319
1320
1321 /**
1322  * It is called when video start
1323  */
1324 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1325 {
1326     assert( p_nvout && !p_vout );
1327
1328     p_vout = p_nvout;
1329
1330     vlc_mutex_lock( &lock );
1331     var_AddCallback( p_vout, "fullscreen", FullscreenControllerWidgetFullscreenChanged, this ); /* I miss a add and fire */
1332     fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ), var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1333     vlc_mutex_unlock( &lock );
1334 }
1335 /**
1336  * It is called after turn off video.
1337  */
1338 void FullscreenControllerWidget::detachVout()
1339 {
1340     if( p_vout )
1341     {
1342         var_DelCallback( p_vout, "fullscreen", FullscreenControllerWidgetFullscreenChanged, this );
1343         vlc_mutex_lock( &lock );
1344         fullscreenChanged( p_vout, false, 0 );
1345         vlc_mutex_unlock( &lock );
1346         p_vout = NULL;
1347     }
1348 }
1349
1350 /**
1351  * Register and unregister callback for mouse moving
1352  */
1353 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout, bool b_fs, int i_timeout )
1354 {
1355     vlc_mutex_lock( &lock );
1356     if( b_fs && !b_fullscreen )
1357     {
1358         b_fullscreen = true;
1359         i_hide_timeout = i_timeout;
1360         var_AddCallback( p_vout, "mouse-moved", FullscreenControllerWidgetMouseMoved, this );
1361     }
1362     else if( !b_fs && b_fullscreen )
1363     {
1364         b_fullscreen = false;
1365         i_hide_timeout = i_timeout;
1366         var_DelCallback( p_vout, "mouse-moved", FullscreenControllerWidgetMouseMoved, this );
1367
1368         /* Force fs hidding */
1369         IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1370         QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1371     }
1372     vlc_mutex_unlock( &lock );
1373 }
1374
1375 /**********************************************************************
1376  * Speed control widget
1377  **********************************************************************/
1378 SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
1379                              QFrame( NULL ), p_intf( _p_i )
1380 {
1381     QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
1382     sizePolicy.setHorizontalStretch( 0 );
1383     sizePolicy.setVerticalStretch( 0 );
1384
1385     speedSlider = new QSlider;
1386     speedSlider->setSizePolicy( sizePolicy );
1387     speedSlider->setMaximumSize( QSize( 80, 200 ) );
1388     speedSlider->setOrientation( Qt::Vertical );
1389     speedSlider->setTickPosition( QSlider::TicksRight );
1390
1391     speedSlider->setRange( -24, 24 );
1392     speedSlider->setSingleStep( 1 );
1393     speedSlider->setPageStep( 1 );
1394     speedSlider->setTickInterval( 12 );
1395
1396     CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
1397
1398     QToolButton *normalSpeedButton = new QToolButton( this );
1399     normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
1400     normalSpeedButton->setAutoRaise( true );
1401     normalSpeedButton->setText( "1x" );
1402     normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
1403
1404     CONNECT( normalSpeedButton, clicked(), this, resetRate() );
1405
1406     QVBoxLayout *speedControlLayout = new QVBoxLayout;
1407     speedControlLayout->setLayoutMargins( 4, 4, 4, 4, 4 );
1408     speedControlLayout->setSpacing( 4 );
1409     speedControlLayout->addWidget( speedSlider );
1410     speedControlLayout->addWidget( normalSpeedButton );
1411     setLayout( speedControlLayout );
1412 }
1413
1414 SpeedControlWidget::~SpeedControlWidget()
1415 {}
1416
1417 void SpeedControlWidget::setEnable( bool b_enable )
1418 {
1419     speedSlider->setEnabled( b_enable );
1420 }
1421
1422 void SpeedControlWidget::updateControls( int rate )
1423 {
1424     if( speedSlider->isSliderDown() )
1425     {
1426         //We don't want to change anything if the user is using the slider
1427         return;
1428     }
1429
1430     double value = 12 * log( (double)INPUT_RATE_DEFAULT / rate ) / log( 2 );
1431     int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 );
1432
1433     if( sliderValue < speedSlider->minimum() )
1434     {
1435         sliderValue = speedSlider->minimum();
1436     }
1437     else if( sliderValue > speedSlider->maximum() )
1438     {
1439         sliderValue = speedSlider->maximum();
1440     }
1441
1442     //Block signals to avoid feedback loop
1443     speedSlider->blockSignals( true );
1444     speedSlider->setValue( sliderValue );
1445     speedSlider->blockSignals( false );
1446 }
1447
1448 void SpeedControlWidget::updateRate( int sliderValue )
1449 {
1450     double speed = pow( 2, (double)sliderValue / 12 );
1451     int rate = INPUT_RATE_DEFAULT / speed;
1452
1453     THEMIM->getIM()->setRate(rate);
1454 }
1455
1456 void SpeedControlWidget::resetRate()
1457 {
1458     THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT);
1459 }
1460
1461
1462
1463 static int downloadCoverCallback( vlc_object_t *p_this,
1464                                   char const *psz_var,
1465                                   vlc_value_t oldvar, vlc_value_t newvar,
1466                                   void *data )
1467 {
1468     if( !strcmp( psz_var, "item-change" ) )
1469     {
1470         CoverArtLabel *art = static_cast< CoverArtLabel* >( data );
1471         if( art )
1472             art->requestUpdate();
1473     }
1474     return VLC_SUCCESS;
1475 }
1476
1477 CoverArtLabel::CoverArtLabel( QWidget *parent,
1478                               vlc_object_t *_p_this,
1479                               input_item_t *_p_input )
1480         : QLabel( parent ), p_this( _p_this), p_input( _p_input ), prevArt()
1481 {
1482     setContextMenuPolicy( Qt::ActionsContextMenu );
1483     CONNECT( this, updateRequested(), this, doUpdate() );
1484
1485     playlist_t *p_playlist = pl_Yield( p_this );
1486     var_AddCallback( p_playlist, "item-change",
1487                      downloadCoverCallback, this );
1488     pl_Release( p_this );
1489
1490     setMinimumHeight( 128 );
1491     setMinimumWidth( 128 );
1492     setMaximumHeight( 128 );
1493     setMaximumWidth( 128 );
1494     setScaledContents( true );
1495
1496     doUpdate();
1497 }
1498
1499 void CoverArtLabel::downloadCover()
1500 {
1501     if( p_input )
1502     {
1503         playlist_t *p_playlist = pl_Yield( p_this );
1504         playlist_AskForArtEnqueue( p_playlist, p_input );
1505         pl_Release( p_this );
1506     }
1507 }
1508
1509 void CoverArtLabel::doUpdate()
1510 {
1511     if( !p_input )
1512     {
1513         setPixmap( QPixmap( ":/noart.png" ) );
1514         QList< QAction* > artActions = actions();
1515         if( !artActions.isEmpty() )
1516             foreach( QAction *act, artActions )
1517                 removeAction( act );
1518         prevArt = "";
1519     }
1520     else
1521     {
1522         char *psz_meta = input_item_GetArtURL( p_input );
1523         if( psz_meta && !strncmp( psz_meta, "file://", 7 ) )
1524         {
1525             QString artUrl = qfu( psz_meta ).replace( "file://", "" );
1526             if( artUrl != prevArt )
1527             {
1528                 QPixmap pix;
1529                 if( pix.load( artUrl ) )
1530                     setPixmap( pix );
1531                 else
1532                 {
1533                     msg_Dbg( p_this, "Qt could not load image '%s'",
1534                              qtu( artUrl ) );
1535                     setPixmap( QPixmap( ":/noart.png" ) );
1536                 }
1537             }
1538             QList< QAction* > artActions = actions();
1539             if( !artActions.isEmpty() )
1540             {
1541                 foreach( QAction *act, artActions )
1542                     removeAction( act );
1543             }
1544             prevArt = artUrl;
1545         }
1546         else
1547         {
1548             if( prevArt != "" )
1549                 setPixmap( QPixmap( ":/noart.png" ) );
1550             prevArt = "";
1551             QList< QAction* > artActions = actions();
1552             if( artActions.isEmpty() )
1553             {
1554                 QAction *action = new QAction( qtr( "Download cover art" ),
1555                                                this );
1556                 addAction( action );
1557                 CONNECT( action, triggered(),
1558                          this, downloadCover() );
1559             }
1560         }
1561         free( psz_meta );
1562     }
1563 }
1564