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