Qt4: Really split the TimeLabel into its own class.
[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     /* Second line */
1031     fsLayout->addWidget( playButton, 1, 0, 1, 2 );
1032     fsLayout->addLayout( controlButLayout, 1, 2 );
1033
1034     fsLayout->addWidget( discFrame, 1, 3 );
1035     fsLayout->addWidget( telexFrame, 1, 4 );
1036     fsLayout->addWidget( fullscreenButton, 1, 5 );
1037     fsLayout->addWidget( advControls, 1, 6, Qt::AlignVCenter );
1038
1039     fsLayout->setColumnStretch( 7, 10 );
1040
1041     TimeLabel *timeLabel = new TimeLabel( p_intf );
1042
1043     fsLayout->addWidget( timeLabel, 1, 8 );
1044     fsLayout->addWidget( volMuteLabel, 1, 9 );
1045     fsLayout->addWidget( volumeSlider, 1, 10,1, 2 );
1046
1047     /* hiding timer */
1048     p_hideTimer = new QTimer( this );
1049     CONNECT( p_hideTimer, timeout(), this, hideFSC() );
1050     p_hideTimer->setSingleShot( true );
1051
1052     /* slow hiding timer */
1053 #if HAVE_TRANSPARENCY
1054     p_slowHideTimer = new QTimer( this );
1055     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
1056 #endif
1057
1058     adjustSize ();  /* need to get real width and height for moving */
1059
1060     /* center down */
1061     QDesktopWidget * p_desktop = QApplication::desktop();
1062
1063     move( p_desktop->width() / 2 - width() / 2,
1064           p_desktop->height() - height() );
1065
1066 #ifdef WIN32TRICK
1067     setWindowOpacity( 0.0 );
1068     b_fscHidden = true;
1069     adjustSize();
1070     show();
1071 #endif
1072
1073     fullscreenButton->setIcon( QIcon( ":/defullscreen" ) );
1074
1075     vlc_mutex_init_recursive( &lock );
1076     setMinimumWidth( 450 );
1077 }
1078
1079 FullscreenControllerWidget::~FullscreenControllerWidget()
1080 {
1081     detachVout();
1082     vlc_mutex_destroy( &lock );
1083 }
1084
1085 /**
1086  * Show fullscreen controller
1087  */
1088 void FullscreenControllerWidget::showFSC()
1089 {
1090     adjustSize();
1091 #ifdef WIN32TRICK
1092     // after quiting and going to fs, we need to call show()
1093     if( isHidden() )
1094         show();
1095
1096     if( b_fscHidden )
1097     {
1098         b_fscHidden = false;
1099         setWindowOpacity( 1.0 );
1100     }
1101 #else
1102     show();
1103 #endif
1104
1105 #if HAVE_TRANSPARENCY
1106     setWindowOpacity( DEFAULT_OPACITY );
1107 #endif
1108 }
1109
1110 /**
1111  * Hide fullscreen controller
1112  * FIXME: under windows it have to be done by moving out of screen
1113  *        because hide() doesnt work
1114  */
1115 void FullscreenControllerWidget::hideFSC()
1116 {
1117 #ifdef WIN32TRICK
1118     b_fscHidden = true;
1119     setWindowOpacity( 0.0 );    // simulate hidding
1120 #else
1121     hide();
1122 #endif
1123 }
1124
1125 /**
1126  * Plane to hide fullscreen controller
1127  */
1128 void FullscreenControllerWidget::planHideFSC()
1129 {
1130     vlc_mutex_lock( &lock );
1131     int i_timeout = i_hide_timeout;
1132     vlc_mutex_unlock( &lock );
1133
1134     p_hideTimer->start( i_timeout );
1135
1136 #if HAVE_TRANSPARENCY
1137     b_slow_hide_begin = true;
1138     i_slow_hide_timeout = i_timeout;
1139     p_slowHideTimer->start( i_slow_hide_timeout / 2 );
1140 #endif
1141 }
1142
1143 /**
1144  * Hidding fullscreen controller slowly
1145  * Linux: need composite manager
1146  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
1147  */
1148 void FullscreenControllerWidget::slowHideFSC()
1149 {
1150 #if HAVE_TRANSPARENCY
1151     if( b_slow_hide_begin )
1152     {
1153         b_slow_hide_begin = false;
1154
1155         p_slowHideTimer->stop();
1156         /* the last part of time divided to 100 pieces */
1157         p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
1158
1159     }
1160     else
1161     {
1162 #ifdef WIN32TRICK
1163          if ( windowOpacity() > 0.0 && !b_fscHidden )
1164 #else
1165          if ( windowOpacity() > 0.0 )
1166 #endif
1167          {
1168              /* we should use 0.01 because of 100 pieces ^^^
1169                 but than it cannt be done in time */
1170              setWindowOpacity( windowOpacity() - 0.02 );
1171          }
1172
1173          if ( windowOpacity() <= 0.0 )
1174              p_slowHideTimer->stop();
1175     }
1176 #endif
1177 }
1178
1179 /**
1180  * event handling
1181  * events: show, hide, start timer for hidding
1182  */
1183 void FullscreenControllerWidget::customEvent( QEvent *event )
1184 {
1185     bool b_fs;
1186
1187     switch( event->type() )
1188     {
1189         case FullscreenControlToggle_Type:
1190             vlc_mutex_lock( &lock );
1191             b_fs = b_fullscreen;
1192             vlc_mutex_unlock( &lock );
1193             if( b_fs )
1194 #ifdef WIN32TRICK
1195                 if( b_fscHidden )
1196 #else
1197                 if( isHidden() )
1198 #endif
1199                 {
1200                     p_hideTimer->stop();
1201                     showFSC();
1202                 }
1203                 else
1204                     hideFSC();
1205             break;
1206         case FullscreenControlShow_Type:
1207             vlc_mutex_lock( &lock );
1208             b_fs = b_fullscreen;
1209             vlc_mutex_unlock( &lock );
1210
1211 #ifdef WIN32TRICK
1212             if( b_fs && b_fscHidden )  // FIXME I am not sure about that one
1213 #else
1214             if( b_fs && !isVisible() )  // FIXME I am not sure about that one
1215 #endif
1216                 showFSC();
1217             break;
1218         case FullscreenControlHide_Type:
1219             hideFSC();
1220             break;
1221         case FullscreenControlPlanHide_Type:
1222             if( !b_mouse_over ) // Only if the mouse is not over FSC
1223                 planHideFSC();
1224             break;
1225     }
1226 }
1227
1228 /**
1229  * On mouse move
1230  * moving with FSC
1231  */
1232 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1233 {
1234     if ( event->buttons() == Qt::LeftButton )
1235     {
1236         int i_moveX = event->globalX() - i_mouse_last_x;
1237         int i_moveY = event->globalY() - i_mouse_last_y;
1238
1239         move( x() + i_moveX, y() + i_moveY );
1240
1241         i_mouse_last_x = event->globalX();
1242         i_mouse_last_y = event->globalY();
1243     }
1244 }
1245
1246 /**
1247  * On mouse press
1248  * store position of cursor
1249  */
1250 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1251 {
1252     i_mouse_last_x = event->globalX();
1253     i_mouse_last_y = event->globalY();
1254 }
1255
1256 /**
1257  * On mouse go above FSC
1258  */
1259 void FullscreenControllerWidget::enterEvent( QEvent *event )
1260 {
1261     b_mouse_over = true;
1262
1263     p_hideTimer->stop();
1264 #if HAVE_TRANSPARENCY
1265     p_slowHideTimer->stop();
1266 #endif
1267 }
1268
1269 /**
1270  * On mouse go out from FSC
1271  */
1272 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1273 {
1274     planHideFSC();
1275
1276     b_mouse_over = false;
1277 }
1278
1279 /**
1280  * When you get pressed key, send it to video output
1281  * FIXME: clearing focus by clearFocus() to not getting
1282  * key press events didnt work
1283  */
1284 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1285 {
1286     int i_vlck = qtEventToVLCKey( event );
1287     if( i_vlck > 0 )
1288     {
1289         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1290         event->accept();
1291     }
1292     else
1293         event->ignore();
1294 }
1295
1296 /* */
1297 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
1298                 const char *variable, vlc_value_t old_val,
1299                 vlc_value_t new_val,  void *data )
1300 {
1301     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1302     msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
1303     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1304
1305     p_fs->fullscreenChanged( p_vout, new_val.b_bool,
1306             var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1307
1308     return VLC_SUCCESS;
1309 }
1310 /* */
1311 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1312                                                  vlc_value_t old_val, vlc_value_t new_val,
1313                                                  void *data )
1314 {
1315     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1316
1317     int i_mousex, i_mousey;
1318     bool b_toShow = false;
1319
1320     /* Get the value from the Vout - Trust the vout more than Qt */
1321     i_mousex = var_GetInteger( p_fs->p_vout, "mouse-x" );
1322     i_mousey = var_GetInteger( p_fs->p_vout, "mouse-y" );
1323
1324     /* First time */
1325     if( p_fs->i_mouse_last_move_x == -1 || p_fs->i_mouse_last_move_y == -1 )
1326     {
1327         p_fs->i_mouse_last_move_x = i_mousex;
1328         p_fs->i_mouse_last_move_y = i_mousey;
1329         b_toShow = true;
1330     }
1331     /* All other times */
1332     else
1333     {
1334         /* Trigger only if move > 3 px dans une direction */
1335         if( abs( p_fs->i_mouse_last_move_x - i_mousex ) > 2 ||
1336             abs( p_fs->i_mouse_last_move_y - i_mousey ) > 2 )
1337         {
1338             b_toShow = true;
1339             p_fs->i_mouse_last_move_x = i_mousex;
1340             p_fs->i_mouse_last_move_y = i_mousey;
1341         }
1342     }
1343
1344     if( b_toShow )
1345     {
1346         /* Show event */
1347         IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1348         QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1349
1350         /* Plan hide event */
1351         IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1352         QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1353     }
1354
1355     return VLC_SUCCESS;
1356 }
1357
1358
1359 /**
1360  * It is called when video start
1361  */
1362 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1363 {
1364     assert( p_nvout && !p_vout );
1365
1366     p_vout = p_nvout;
1367
1368     msg_Dbg( p_vout, "Qt FS: Attaching Vout" );
1369     vlc_mutex_lock( &lock );
1370
1371     var_AddCallback( p_vout, "fullscreen",
1372             FullscreenControllerWidgetFullscreenChanged, this );
1373             /* I miss a add and fire */
1374     fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1375                        var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1376     vlc_mutex_unlock( &lock );
1377 }
1378 /**
1379  * It is called after turn off video.
1380  */
1381 void FullscreenControllerWidget::detachVout()
1382 {
1383     if( p_vout )
1384     {
1385         msg_Dbg( p_vout, "Qt FS: Detaching Vout" );
1386         var_DelCallback( p_vout, "fullscreen",
1387                 FullscreenControllerWidgetFullscreenChanged, this );
1388         vlc_mutex_lock( &lock );
1389         fullscreenChanged( p_vout, false, 0 );
1390         vlc_mutex_unlock( &lock );
1391         p_vout = NULL;
1392     }
1393 }
1394
1395 /**
1396  * Register and unregister callback for mouse moving
1397  */
1398 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1399         bool b_fs, int i_timeout )
1400 {
1401     msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1402
1403     vlc_mutex_lock( &lock );
1404     /* Entering fullscreen, register callback */
1405     if( b_fs && !b_fullscreen )
1406     {
1407         b_fullscreen = true;
1408         i_hide_timeout = i_timeout;
1409         var_AddCallback( p_vout, "mouse-moved",
1410                 FullscreenControllerWidgetMouseMoved, this );
1411     }
1412     /* Quitting fullscreen, unregistering callback */
1413     else if( !b_fs && b_fullscreen )
1414     {
1415         b_fullscreen = false;
1416         i_hide_timeout = i_timeout;
1417         var_DelCallback( p_vout, "mouse-moved",
1418                 FullscreenControllerWidgetMouseMoved, this );
1419
1420         /* Force fs hidding */
1421         IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1422         QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1423     }
1424     vlc_mutex_unlock( &lock );
1425 }
1426
1427 /**********************************************************************
1428  * Speed control widget
1429  **********************************************************************/
1430 SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
1431                              QFrame( NULL ), p_intf( _p_i )
1432 {
1433     QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
1434     sizePolicy.setHorizontalStretch( 0 );
1435     sizePolicy.setVerticalStretch( 0 );
1436
1437     speedSlider = new QSlider;
1438     speedSlider->setSizePolicy( sizePolicy );
1439     speedSlider->setMaximumSize( QSize( 80, 200 ) );
1440     speedSlider->setOrientation( Qt::Vertical );
1441     speedSlider->setTickPosition( QSlider::TicksRight );
1442
1443     speedSlider->setRange( -24, 24 );
1444     speedSlider->setSingleStep( 1 );
1445     speedSlider->setPageStep( 1 );
1446     speedSlider->setTickInterval( 12 );
1447
1448     CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
1449
1450     QToolButton *normalSpeedButton = new QToolButton( this );
1451     normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
1452     normalSpeedButton->setAutoRaise( true );
1453     normalSpeedButton->setText( "1x" );
1454     normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
1455
1456     CONNECT( normalSpeedButton, clicked(), this, resetRate() );
1457
1458     QVBoxLayout *speedControlLayout = new QVBoxLayout;
1459     speedControlLayout->setLayoutMargins( 4, 4, 4, 4, 4 );
1460     speedControlLayout->setSpacing( 4 );
1461     speedControlLayout->addWidget( speedSlider );
1462     speedControlLayout->addWidget( normalSpeedButton );
1463     setLayout( speedControlLayout );
1464 }
1465
1466 SpeedControlWidget::~SpeedControlWidget()
1467 {}
1468
1469 void SpeedControlWidget::setEnable( bool b_enable )
1470 {
1471     speedSlider->setEnabled( b_enable );
1472 }
1473
1474 void SpeedControlWidget::updateControls( int rate )
1475 {
1476     if( speedSlider->isSliderDown() )
1477     {
1478         //We don't want to change anything if the user is using the slider
1479         return;
1480     }
1481
1482     double value = 12 * log( (double)INPUT_RATE_DEFAULT / rate ) / log( 2 );
1483     int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 );
1484
1485     if( sliderValue < speedSlider->minimum() )
1486     {
1487         sliderValue = speedSlider->minimum();
1488     }
1489     else if( sliderValue > speedSlider->maximum() )
1490     {
1491         sliderValue = speedSlider->maximum();
1492     }
1493
1494     //Block signals to avoid feedback loop
1495     speedSlider->blockSignals( true );
1496     speedSlider->setValue( sliderValue );
1497     speedSlider->blockSignals( false );
1498 }
1499
1500 void SpeedControlWidget::updateRate( int sliderValue )
1501 {
1502     double speed = pow( 2, (double)sliderValue / 12 );
1503     int rate = INPUT_RATE_DEFAULT / speed;
1504
1505     THEMIM->getIM()->setRate(rate);
1506 }
1507
1508 void SpeedControlWidget::resetRate()
1509 {
1510     THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT);
1511 }
1512
1513
1514
1515 static int downloadCoverCallback( vlc_object_t *p_this,
1516                                   char const *psz_var,
1517                                   vlc_value_t oldvar, vlc_value_t newvar,
1518                                   void *data )
1519 {
1520     if( !strcmp( psz_var, "item-change" ) )
1521     {
1522         CoverArtLabel *art = static_cast< CoverArtLabel* >( data );
1523         if( art )
1524             art->requestUpdate();
1525     }
1526     return VLC_SUCCESS;
1527 }
1528
1529 CoverArtLabel::CoverArtLabel( QWidget *parent,
1530                               vlc_object_t *_p_this,
1531                               input_item_t *_p_input )
1532         : QLabel( parent ), p_this( _p_this), p_input( _p_input ), prevArt()
1533 {
1534     setContextMenuPolicy( Qt::ActionsContextMenu );
1535     CONNECT( this, updateRequested(), this, doUpdate() );
1536
1537     playlist_t *p_playlist = pl_Hold( p_this );
1538     var_AddCallback( p_playlist, "item-change",
1539                      downloadCoverCallback, this );
1540     pl_Release( p_this );
1541
1542     setMinimumHeight( 128 );
1543     setMinimumWidth( 128 );
1544     setMaximumHeight( 128 );
1545     setMaximumWidth( 128 );
1546     setScaledContents( true );
1547
1548     doUpdate();
1549 }
1550
1551 void CoverArtLabel::downloadCover()
1552 {
1553     if( p_input )
1554     {
1555         playlist_t *p_playlist = pl_Hold( p_this );
1556         playlist_AskForArtEnqueue( p_playlist, p_input );
1557         pl_Release( p_this );
1558     }
1559 }
1560
1561 void CoverArtLabel::doUpdate()
1562 {
1563     if( !p_input )
1564     {
1565         setPixmap( QPixmap( ":/noart.png" ) );
1566         QList< QAction* > artActions = actions();
1567         if( !artActions.isEmpty() )
1568             foreach( QAction *act, artActions )
1569                 removeAction( act );
1570         prevArt = "";
1571     }
1572     else
1573     {
1574         char *psz_meta = input_item_GetArtURL( p_input );
1575         if( psz_meta && !strncmp( psz_meta, "file://", 7 ) )
1576         {
1577             QString artUrl = qfu( psz_meta ).replace( "file://", "" );
1578             if( artUrl != prevArt )
1579             {
1580                 QPixmap pix;
1581                 if( pix.load( artUrl ) )
1582                     setPixmap( pix );
1583                 else
1584                 {
1585                     msg_Dbg( p_this, "Qt could not load image '%s'",
1586                              qtu( artUrl ) );
1587                     setPixmap( QPixmap( ":/noart.png" ) );
1588                 }
1589             }
1590             QList< QAction* > artActions = actions();
1591             if( !artActions.isEmpty() )
1592             {
1593                 foreach( QAction *act, artActions )
1594                     removeAction( act );
1595             }
1596             prevArt = artUrl;
1597         }
1598         else
1599         {
1600             if( prevArt != "" )
1601                 setPixmap( QPixmap( ":/noart.png" ) );
1602             prevArt = "";
1603             QList< QAction* > artActions = actions();
1604             if( artActions.isEmpty() )
1605             {
1606                 QAction *action = new QAction( qtr( "Download cover art" ),
1607                                                this );
1608                 addAction( action );
1609                 CONNECT( action, triggered(),
1610                          this, downloadCover() );
1611             }
1612         }
1613         free( psz_meta );
1614     }
1615 }
1616
1617 TimeLabel::TimeLabel( intf_thread_t *_p_intf  ) :QLabel(), p_intf( _p_intf )
1618 {
1619    b_remainingTime = false;
1620    setText( " --:--/--:-- " );
1621    setAlignment( Qt::AlignRight | Qt::AlignVCenter );
1622    setToolTip( qtr( "Toggle between elapsed and remaining time" ) );
1623
1624
1625    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
1626              this, setDisplayPosition( float, int, int ) );
1627 }
1628
1629 void TimeLabel::setDisplayPosition( float pos, int time, int length )
1630 {
1631     char psz_length[MSTRTIME_MAX_SIZE], psz_time[MSTRTIME_MAX_SIZE];
1632     secstotimestr( psz_length, length );
1633     secstotimestr( psz_time, ( b_remainingTime && length ) ? length - time
1634                                                            : time );
1635
1636     QString timestr;
1637     timestr.sprintf( "%s/%s", psz_time,
1638                             ( !length && time ) ? "--:--" : psz_length );
1639
1640     /* Add a minus to remaining time*/
1641     if( b_remainingTime && length ) setText( " -"+timestr+" " );
1642     else setText( " "+timestr+" " );
1643 }
1644
1645 void TimeLabel::toggleTimeDisplay()
1646 {
1647     b_remainingTime = !b_remainingTime;
1648 }
1649
1650