]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/interface_widgets.cpp
Fix toggling of transparency on teletext pages. Keep in mind that the subpicture...
[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     /**
465      * Telextext QFrame
466      * TODO: Merge with upper menu in a StackLayout
467      **/
468     telexFrame = new QWidget( this );
469     QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
470     telexLayout->setSpacing( 0 );
471     telexLayout->setMargin( 0 );
472
473     QPushButton  *telexOn = new QPushButton;
474     setupSmallButton( telexOn );
475     telexLayout->addWidget( telexOn );
476
477     telexTransparent = new QPushButton;
478     setupSmallButton( telexTransparent );
479     telexLayout->addWidget( telexTransparent );
480     b_telexTransparent = false;
481
482     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(); /* default hidden */
493
494     CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
495              telexGotoPage( int ) );
496
497     BUTTON_SET_ACT_I( telexOn, "", tv.png, qtr( "Teletext on" ),
498                       toggleTeletext() );
499     CONNECT( telexOn, clicked( bool ), THEMIM->getIM(),
500              telexToggle( bool ) );
501     telexTransparent->setEnabled( false );
502     telexPage->setEnabled( false );
503
504     BUTTON_SET_ACT_I( telexTransparent, "", tvtelx.png, qtr( "Teletext" ),
505                       toggleTeletextTransparency() );
506     CONNECT( telexTransparent, clicked( bool ),
507              THEMIM->getIM(), telexSetTransparency() );
508     CONNECT( THEMIM->getIM(), teletextEnabled( bool ),
509              telexFrame, setVisible( bool ) );
510
511     /** Play Buttons **/
512     QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
513     sizePolicy.setHorizontalStretch( 0 );
514     sizePolicy.setVerticalStretch( 0 );
515
516     /* Play */
517     playButton = new QPushButton;
518     playButton->setSizePolicy( sizePolicy );
519     playButton->setMaximumSize( QSize( 36, 36 ) );
520     playButton->setMinimumSize( QSize( 36, 36 ) );
521     playButton->setIconSize( QSize( 30, 30 ) );
522
523     controlLayout->addWidget( playButton, 2, 0, 2, 2 );
524
525     controlLayout->setColumnMinimumWidth( 2, 20 );
526     controlLayout->setColumnStretch( 2, 0 );
527
528     /** Prev + Stop + Next Block **/
529     controlButLayout = new QHBoxLayout;
530     controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */
531
532     /* Prev */
533     QPushButton *prevButton = new QPushButton;
534     prevButton->setSizePolicy( sizePolicy );
535     setupSmallButton( prevButton );
536
537     controlButLayout->addWidget( prevButton );
538
539     /* Stop */
540     QPushButton *stopButton = new QPushButton;
541     stopButton->setSizePolicy( sizePolicy );
542     setupSmallButton( stopButton );
543
544     controlButLayout->addWidget( stopButton );
545
546     /* next */
547     QPushButton *nextButton = new QPushButton;
548     nextButton->setSizePolicy( sizePolicy );
549     setupSmallButton( nextButton );
550
551     controlButLayout->addWidget( nextButton );
552
553     /* Add this block to the main layout */
554     if( !b_fsCreation )
555         controlLayout->addLayout( controlButLayout, 3, 3, 1, 3 );
556
557     BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() );
558     BUTTON_SET_ACT_I( prevButton, "" , previous.png,
559                       qtr( "Previous" ), prev() );
560     BUTTON_SET_ACT_I( nextButton, "", next.png, qtr( "Next" ), next() );
561     BUTTON_SET_ACT_I( stopButton, "", stop.png, qtr( "Stop" ), stop() );
562
563     controlLayout->setColumnMinimumWidth( 7, 20 );
564     controlLayout->setColumnStretch( 7, 0 );
565     controlLayout->setColumnStretch( 8, 0 );
566     controlLayout->setColumnStretch( 9, 0 );
567
568     /*
569      * Other first Line buttons
570      */
571     /** Fullscreen/Visualisation **/
572     fullscreenButton = new QPushButton( "F" );
573     BUTTON_SET_ACT( fullscreenButton, "F", qtr( "Fullscreen" ), fullscreen() );
574     setupSmallButton( fullscreenButton );
575     controlLayout->addWidget( fullscreenButton, 3, 10, Qt::AlignBottom );
576
577     /** Playlist Button **/
578     playlistButton = new QPushButton;
579     setupSmallButton( playlistButton );
580     controlLayout->addWidget( playlistButton, 3, 11, Qt::AlignBottom );
581     BUTTON_SET_IMG( playlistButton, "" , playlist.png, qtr( "Show playlist" ) );
582     CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
583
584     /** extended Settings **/
585     extSettingsButton = new QPushButton;
586     BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended Settings" ),
587             extSettings() );
588     setupSmallButton( extSettingsButton );
589     controlLayout->addWidget( extSettingsButton, 3, 12, Qt::AlignBottom );
590
591     controlLayout->setColumnStretch( 13, 0 );
592     controlLayout->setColumnMinimumWidth( 13, 24 );
593     controlLayout->setColumnStretch( 14, 5 );
594
595     /* Volume */
596     hVolLabel = new VolumeClickHandler( p_intf, this );
597
598     volMuteLabel = new QLabel;
599     volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) );
600     volMuteLabel->setToolTip( qtr( "Mute" ) );
601     volMuteLabel->installEventFilter( hVolLabel );
602     controlLayout->addWidget( volMuteLabel, 3, 15, Qt::AlignBottom );
603
604     if( b_shiny )
605     {
606         volumeSlider = new SoundSlider( this,
607             config_GetInt( p_intf, "volume-step" ),
608             config_GetInt( p_intf, "qt-volume-complete" ),
609             config_GetPsz( p_intf, "qt-slider-colours" ) );
610     }
611     else
612     {
613         volumeSlider = new QSlider( this );
614         volumeSlider->setOrientation( Qt::Horizontal );
615     }
616     volumeSlider->setMaximumSize( QSize( 200, 40 ) );
617     volumeSlider->setMinimumSize( QSize( 106, 30 ) );
618     volumeSlider->setFocusPolicy( Qt::NoFocus );
619     controlLayout->addWidget( volumeSlider, 2, 16, 2 , 2, Qt::AlignBottom );
620
621     /* Set the volume from the config */
622     volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
623                               VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
624
625     /* Force the update at build time in order to have a muted icon if needed */
626     updateVolume( volumeSlider->value() );
627
628     /* Volume control connection */
629     CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
630     CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
631
632     updateInput();
633 }
634
635 ControlsWidget::~ControlsWidget()
636 {}
637
638 void ControlsWidget::toggleTeletext()
639 {
640     bool b_enabled = THEMIM->teletextState();
641     if( b_telexEnabled )
642     {
643         telexTransparent->setEnabled( false );
644         telexPage->setEnabled( false );
645         b_telexEnabled = false;
646     }
647     else if( b_enabled )
648     {
649         telexTransparent->setEnabled( true );
650         telexPage->setEnabled( true );
651         b_telexEnabled = true;
652     }
653 }
654
655 void ControlsWidget::toggleTeletextTransparency()
656 {
657     if( b_telexTransparent )
658     {
659         telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx.png" ) );
660         telexTransparent->setToolTip( qtr( "Teletext" ) );
661         b_telexTransparent = false;
662     }
663     else
664     {
665         telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx-transparent.png" ) );
666         telexTransparent->setToolTip( qtr( "Transparent" ) );
667         b_telexTransparent = true;
668     }
669 }
670
671 void ControlsWidget::stop()
672 {
673     THEMIM->stop();
674 }
675
676 void ControlsWidget::play()
677 {
678     if( THEPL->current.i_size == 0 )
679     {
680         /* The playlist is empty, open a file requester */
681         THEDP->openFileDialog();
682         setStatus( 0 );
683         return;
684     }
685     THEMIM->togglePlayPause();
686 }
687
688 void ControlsWidget::prev()
689 {
690     THEMIM->prev();
691 }
692
693 void ControlsWidget::next()
694 {
695     THEMIM->next();
696 }
697
698 void ControlsWidget::setNavigation( int navigation )
699 {
700 #define HELP_MENU N_( "Menu" )
701 #define HELP_PCH N_( "Previous chapter" )
702 #define HELP_NCH N_( "Next chapter" )
703 #define HELP_PTR N_( "Previous track" )
704 #define HELP_NTR N_( "Next track" )
705
706     // 1 = chapter, 2 = title, 0 = no
707     if( navigation == 0 )
708     {
709         discFrame->hide();
710     } else if( navigation == 1 ) {
711         prevSectionButton->setToolTip( qfu( HELP_PCH ) );
712         nextSectionButton->setToolTip( qfu( HELP_NCH ) );
713         menuButton->show();
714         discFrame->show();
715     } else {
716         prevSectionButton->setToolTip( qfu( HELP_PCH ) );
717         nextSectionButton->setToolTip( qfu( HELP_NCH ) );
718         menuButton->hide();
719         discFrame->show();
720     }
721 }
722
723 static bool b_my_volume;
724 void ControlsWidget::updateVolume( int i_sliderVolume )
725 {
726     if( !b_my_volume )
727     {
728         int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
729         aout_VolumeSet( p_intf, i_res );
730     }
731     if( i_sliderVolume == 0 )
732         volMuteLabel->setPixmap( QPixmap(":/pixmaps/volume-muted.png" ) );
733     else if( i_sliderVolume < VOLUME_MAX / 3 )
734         volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) );
735     else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
736         volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
737     else volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) );
738 }
739
740 void ControlsWidget::updateVolume()
741 {
742     /* Audio part */
743     audio_volume_t i_volume;
744     aout_VolumeGet( p_intf, &i_volume );
745     i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
746     int i_gauge = volumeSlider->value();
747     b_my_volume = false;
748     if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
749     {
750         b_my_volume = true;
751         volumeSlider->setValue( i_volume );
752         b_my_volume = false;
753     }
754 }
755
756 void ControlsWidget::updateInput()
757 {
758     /* Activate the interface buttons according to the presence of the input */
759     enableInput( THEMIM->getIM()->hasInput() );
760     enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() );
761 }
762
763 void ControlsWidget::setStatus( int status )
764 {
765     if( status == PLAYING_S ) /* Playing */
766     {
767         playButton->setIcon( QIcon( ":/pixmaps/pause.png" ) );
768         playButton->setToolTip( qtr( "Pause" ) );
769     }
770     else
771     {
772         playButton->setIcon( QIcon( ":/pixmaps/play.png" ) );
773         playButton->setToolTip( qtr( "Play" ) );
774     }
775 }
776
777 /**
778  * TODO
779  * This functions toggle the fullscreen mode
780  * If there is no video, it should first activate Visualisations...
781  *  This has also to be fixed in enableVideo()
782  */
783 void ControlsWidget::fullscreen()
784 {
785     vout_thread_t *p_vout =
786         (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
787     if( p_vout)
788     {
789         var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
790         vlc_object_release( p_vout );
791     }
792 }
793
794 void ControlsWidget::extSettings()
795 {
796     THEDP->extendedDialog();
797 }
798
799 void ControlsWidget::slower()
800 {
801     THEMIM->getIM()->slower();
802 }
803
804 void ControlsWidget::faster()
805 {
806     THEMIM->getIM()->faster();
807 }
808
809 void ControlsWidget::enableInput( bool enable )
810 {
811     slowerButton->setEnabled( enable );
812     slider->setEnabled( enable );
813     fasterButton->setEnabled( enable );
814
815     /* Advanced Buttons too */
816     advControls->enableInput( enable );
817 }
818
819 void ControlsWidget::enableVideo( bool enable )
820 {
821     // TODO Later make the fullscreenButton toggle Visualisation and so on.
822     fullscreenButton->setEnabled( enable );
823
824     /* Advanced Buttons too */
825     advControls->enableVideo( enable );
826 }
827
828 void ControlsWidget::toggleAdvanced()
829 {
830     if( !VISIBLE( advControls ) )
831     {
832         advControls->show();
833         b_advancedVisible = true;
834     }
835     else
836     {
837         advControls->hide();
838         b_advancedVisible = false;
839     }
840     emit advancedControlsToggled( b_advancedVisible );
841 }
842
843
844 /**********************************************************************
845  * Fullscrenn control widget
846  **********************************************************************/
847 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i,
848         MainInterface *_p_mi, bool b_advControls, bool b_shiny )
849         : ControlsWidget( _p_i, _p_mi, b_advControls, b_shiny, true ),
850         i_lastPosX( -1 ), i_lastPosY( -1 ), i_hideTimeout( 1 ),
851         b_mouseIsOver( false )
852 {
853     setWindowFlags( Qt::ToolTip );
854
855     setFrameShape( QFrame::StyledPanel );
856     setFrameStyle( QFrame::Sunken );
857     setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
858
859     QGridLayout *fsLayout = new QGridLayout( this );
860     controlLayout->setSpacing( 0 );
861     controlLayout->setLayoutMargins( 5, 1, 5, 1, 5 );
862
863     fsLayout->addWidget( slowerButton, 0, 0 );
864     slider->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum);
865     fsLayout->addWidget( slider, 0, 1, 1, 6 );
866     fsLayout->addWidget( fasterButton, 0, 7 );
867
868     fsLayout->addWidget( volMuteLabel, 1, 0);
869     fsLayout->addWidget( volumeSlider, 1, 1 );
870
871     fsLayout->addLayout( controlButLayout, 1, 2 );
872
873     fsLayout->addWidget( playButton, 1, 3 );
874
875     fsLayout->addWidget( discFrame, 1, 4 );
876
877     fsLayout->addWidget( telexFrame, 1, 5 );
878
879     fsLayout->addWidget( advControls, 1, 6, Qt::AlignVCenter );
880
881     fsLayout->addWidget( fullscreenButton, 1, 7 );
882
883     /* hiding timer */
884     p_hideTimer = new QTimer( this );
885     CONNECT( p_hideTimer, timeout(), this, hideFSControllerWidget() );
886     p_hideTimer->setSingleShot( true );
887
888     /* slow hiding timer */
889 #if HAVE_TRANSPARENCY
890     p_slowHideTimer = new QTimer( this );
891     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
892 #endif
893
894     adjustSize ();  /* need to get real width and height for moving */
895
896     /* center down */
897     QDesktopWidget * p_desktop = QApplication::desktop();
898
899     move( p_desktop->width() / 2 - width() / 2,
900           p_desktop->height() - height() );
901
902     #ifdef WIN32TRICK
903     setWindowOpacity( 0.0 );
904     fscHidden = true;
905     show();
906     #endif
907 }
908
909 FullscreenControllerWidget::~FullscreenControllerWidget()
910 {
911 }
912
913 /**
914  * Hide fullscreen controller
915  * FIXME: under windows it have to be done by moving out of screen
916  *        because hide() doesnt work
917  */
918 void FullscreenControllerWidget::hideFSControllerWidget()
919 {
920     #ifdef WIN32TRICK
921     fscHidden = true;
922     setWindowOpacity( 0.0 );    // simulate hidding
923     #else
924     hide();
925     #endif
926 }
927
928 /**
929  * Hidding fullscreen controller slowly
930  * Linux: need composite manager
931  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
932  */
933 void FullscreenControllerWidget::slowHideFSC()
934 {
935 #if HAVE_TRANSPARENCY
936     static bool first_call = true;
937
938     if ( first_call )
939     {
940         first_call = false;
941
942         p_slowHideTimer->stop();
943         /* the last part of time divided to 100 pieces */
944         p_slowHideTimer->start(
945             (int) ( i_hideTimeout / 2 / ( windowOpacity() * 100 ) ) );
946     }
947     else
948     {
949          if ( windowOpacity() > 0.0 )
950          {
951              /* we should use 0.01 because of 100 pieces ^^^
952                 but than it cannt be done in time */
953              setWindowOpacity( windowOpacity() - 0.02 );
954          }
955
956          if ( windowOpacity() == 0.0 )
957          {
958              first_call = true;
959              p_slowHideTimer->stop();
960          }
961     }
962 #endif
963 }
964
965 /**
966  * Get state of visibility of FS controller on screen
967  * On windows control if it is on hidden position
968  */
969 bool FullscreenControllerWidget::isFSCHidden()
970 {
971     #ifdef WIN32TRICK
972     return fscHidden;
973     #endif
974
975     return isHidden();
976 }
977
978 /**
979  * event handling
980  * events: show, hide, start timer for hidding
981  */
982 void FullscreenControllerWidget::customEvent( QEvent *event )
983 {
984     int type = event->type();
985
986     if ( type == FullscreenControlShow_Type )
987     {
988         #ifdef WIN32TRICK
989         // after quiting and going to fs, we need to call show()
990         if ( isHidden() )
991             show();
992
993         if ( fscHidden )
994         {
995             fscHidden = false;
996             setWindowOpacity( 1.0 );
997         }
998         #else
999         show();
1000         #endif
1001
1002 #if HAVE_TRANSPARENCY
1003         setWindowOpacity( DEFAULT_OPACITY );
1004 #endif
1005     }
1006     else if ( type == FullscreenControlHide_Type )
1007     {
1008         hideFSControllerWidget();
1009     }
1010     else if ( type == FullscreenControlPlanHide_Type && !b_mouseIsOver )
1011     {
1012         p_hideTimer->start( i_hideTimeout );
1013 #if HAVE_TRANSPARENCY
1014         p_slowHideTimer->start( i_hideTimeout / 2 );
1015 #endif
1016     }
1017 }
1018
1019 /**
1020  * On mouse move
1021  * moving with FSC
1022  */
1023 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1024 {
1025     if ( event->buttons() == Qt::LeftButton )
1026     {
1027         int i_moveX = event->globalX() - i_lastPosX;
1028         int i_moveY = event->globalY() - i_lastPosY;
1029
1030         move( x() + i_moveX, y() + i_moveY );
1031
1032         i_lastPosX = event->globalX();
1033         i_lastPosY = event->globalY();
1034     }
1035 }
1036
1037 /**
1038  * On mouse press
1039  * store position of cursor
1040  */
1041 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1042 {
1043     i_lastPosX = event->globalX();
1044     i_lastPosY = event->globalY();
1045 }
1046
1047 /**
1048  * On mouse go above FSC
1049  */
1050 void FullscreenControllerWidget::enterEvent( QEvent *event )
1051 {
1052     p_hideTimer->stop();
1053 #if HAVE_TRANSPARENCY
1054     p_slowHideTimer->stop();
1055 #endif
1056     b_mouseIsOver = true;
1057 }
1058
1059 /**
1060  * On mouse go out from FSC
1061  */
1062 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1063 {
1064     p_hideTimer->start( i_hideTimeout );
1065 #if HAVE_TRANSPARENCY
1066     p_slowHideTimer->start( i_hideTimeout / 2 );
1067 #endif
1068     b_mouseIsOver = false;
1069 }
1070
1071 /**
1072  * When you get pressed key, send it to video output
1073  * FIXME: clearing focus by clearFocus() to not getting
1074  * key press events didnt work
1075  */
1076 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1077 {
1078     int i_vlck = qtEventToVLCKey( event );
1079     if( i_vlck > 0 )
1080     {
1081         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1082         event->accept();
1083     }
1084     else
1085         event->ignore();
1086 }
1087
1088 /**
1089  * It is called when video start
1090  */
1091 void FullscreenControllerWidget::regFullscreenCallback( vout_thread_t *p_vout )
1092 {
1093     if ( p_vout )
1094     {
1095         var_AddCallback( p_vout, "fullscreen", regMouseMoveCallback, this );
1096     }
1097 }
1098
1099 /**
1100  * It is called after turn off video, because p_vout is NULL now
1101  * we cannt delete callback, just hide if FScontroller is visible
1102  */
1103 void FullscreenControllerWidget::unregFullscreenCallback()
1104 {
1105     if ( isVisible() )
1106         hide();
1107 }
1108
1109 /**
1110  * Register and unregister callback for mouse moving
1111  */
1112 static int regMouseMoveCallback( vlc_object_t *vlc_object, const char *variable,
1113                                  vlc_value_t old_val, vlc_value_t new_val,
1114                                  void *data )
1115 {
1116     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1117
1118     static bool b_registered = false;
1119     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *) data;
1120
1121     if ( var_GetBool( p_vout, "fullscreen" ) && !b_registered )
1122     {
1123         p_fs->SetHideTimeout( var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1124         var_AddCallback( p_vout, "mouse-moved",
1125                         showFullscreenControllCallback, (void *) p_fs );
1126         b_registered = true;
1127     }
1128
1129     if ( !var_GetBool( p_vout, "fullscreen" ) && b_registered )
1130     {
1131         var_DelCallback( p_vout, "mouse-moved",
1132                         showFullscreenControllCallback, (void *) p_fs );
1133         b_registered = false;
1134         p_fs->hide();
1135     }
1136
1137     return VLC_SUCCESS;
1138 }
1139
1140 /**
1141  * Show fullscreen controller after mouse move
1142  * after show immediately plan hide event
1143  */
1144 static int showFullscreenControllCallback( vlc_object_t *vlc_object, const char *variable,
1145                                            vlc_value_t old_val, vlc_value_t new_val,
1146                                            void *data )
1147 {
1148     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *) data;
1149
1150     if ( p_fs->isFSCHidden() || p_fs->windowOpacity() < DEFAULT_OPACITY )
1151     {
1152         IMEvent *event = new IMEvent( FullscreenControlShow_Type, 0 );
1153         QApplication::postEvent( p_fs, static_cast<QEvent *>(event) );
1154     }
1155
1156     IMEvent *e = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1157     QApplication::postEvent( p_fs, static_cast<QEvent *>(e) );
1158
1159     return VLC_SUCCESS;
1160 }
1161
1162 /**********************************************************************
1163  * Speed control widget
1164  **********************************************************************/
1165 SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
1166                              QFrame( NULL ), p_intf( _p_i )
1167 {
1168     QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
1169     sizePolicy.setHorizontalStretch( 0 );
1170     sizePolicy.setVerticalStretch( 0 );
1171
1172     speedSlider = new QSlider;
1173     speedSlider->setSizePolicy( sizePolicy );
1174     speedSlider->setMaximumSize( QSize( 80, 200 ) );
1175     speedSlider->setOrientation( Qt::Vertical );
1176     speedSlider->setTickPosition( QSlider::TicksRight );
1177
1178     speedSlider->setRange( -100, 100 );
1179     speedSlider->setSingleStep( 10 );
1180     speedSlider->setPageStep( 20 );
1181     speedSlider->setTickInterval( 20 );
1182
1183     CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
1184
1185     QToolButton *normalSpeedButton = new QToolButton( this );
1186     normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
1187     normalSpeedButton->setAutoRaise( true );
1188     normalSpeedButton->setText( "N" );
1189     normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
1190
1191     CONNECT( normalSpeedButton, clicked(), this, resetRate() );
1192
1193     QVBoxLayout *speedControlLayout = new QVBoxLayout;
1194     speedControlLayout->addWidget( speedSlider );
1195     speedControlLayout->addWidget( normalSpeedButton );
1196     setLayout( speedControlLayout );
1197 }
1198
1199 SpeedControlWidget::~SpeedControlWidget()
1200 {}
1201
1202 void SpeedControlWidget::setEnable( bool b_enable )
1203 {
1204     speedSlider->setEnabled( b_enable );
1205 }
1206
1207 #define RATE_SLIDER_MAXIMUM 3.0
1208 #define RATE_SLIDER_MINIMUM 0.3
1209 #define RATE_SLIDER_LENGTH 100.0
1210
1211 void SpeedControlWidget::updateControls( int rate )
1212 {
1213     if( speedSlider->isSliderDown() )
1214     {
1215         //We don't want to change anything if the user is using the slider
1216         return;
1217     }
1218
1219     int sliderValue;
1220     double speed = INPUT_RATE_DEFAULT / (double)rate;
1221
1222     if( rate >= INPUT_RATE_DEFAULT )
1223     {
1224         if( speed < RATE_SLIDER_MINIMUM )
1225         {
1226             sliderValue = speedSlider->minimum();
1227         }
1228         else
1229         {
1230             sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
1231                                         / ( 1.0 - RATE_SLIDER_MAXIMUM ) );
1232         }
1233     }
1234     else
1235     {
1236         if( speed > RATE_SLIDER_MAXIMUM )
1237         {
1238             sliderValue = speedSlider->maximum();
1239         }
1240         else
1241         {
1242             sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
1243                                         / ( RATE_SLIDER_MAXIMUM - 1.0 ) );
1244         }
1245     }
1246
1247     //Block signals to avoid feedback loop
1248     speedSlider->blockSignals( true );
1249     speedSlider->setValue( sliderValue );
1250     speedSlider->blockSignals( false );
1251 }
1252
1253 void SpeedControlWidget::updateRate( int sliderValue )
1254 {
1255     int rate;
1256
1257     if( sliderValue < 0.0 )
1258     {
1259         rate = (int)(INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
1260             ( sliderValue * ( 1.0 - RATE_SLIDER_MINIMUM ) + RATE_SLIDER_LENGTH ));
1261     }
1262     else
1263     {
1264         rate = (int)(INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
1265             ( sliderValue * ( RATE_SLIDER_MAXIMUM - 1.0 ) + RATE_SLIDER_LENGTH ));
1266     }
1267
1268     THEMIM->getIM()->setRate(rate);
1269 }
1270
1271 void SpeedControlWidget::resetRate()
1272 {
1273     THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT);
1274 }