1 /*****************************************************************************
2 * Controller.cpp : Controller for the main interface
3 ****************************************************************************
4 * Copyright ( C ) 2006-2008 the VideoLAN team
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>
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.
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.
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 *****************************************************************************/
33 #include "dialogs_provider.hpp"
34 #include "components/interface_widgets.hpp"
35 #include "main_interface.hpp"
36 #include "input_manager.hpp"
38 #include "util/input_slider.hpp"
39 #include "util/customwidgets.hpp"
42 #include <QSpacerItem>
44 #include <QToolButton>
45 #include <QHBoxLayout>
48 #include <QResizeEvent>
50 #include <QSignalMapper>
53 #define I_PLAY_TOOLTIP N_("Play\nIf the playlist is empty, open a media")
55 /**********************************************************************
57 **********************************************************************/
60 * This is an abstract Toolbar/Controller
61 * This has helper to create any toolbar, any buttons and to manage the actions
64 AbstractController::AbstractController( intf_thread_t * _p_i ) : QFrame( NULL )
68 /* We need one layout. An controller without layout is stupid with
69 current architecture */
70 controlLayout = new QGridLayout( this );
72 /* Main action provider */
73 toolbarActionsMapper = new QSignalMapper( this );
74 CONNECT( toolbarActionsMapper, mapped( int ),
75 this, doAction( int ) );
76 CONNECT( THEMIM->getIM(), statusChanged( int ), this, setStatus( int ) );
79 /* Reemit some signals on status Change to activate some buttons */
80 void AbstractController::setStatus( int status )
82 bool b_hasInput = THEMIM->getIM()->hasInput();
83 /* Activate the interface buttons according to the presence of the input */
84 emit inputExists( b_hasInput );
86 emit inputPlaying( status == PLAYING_S );
88 emit inputIsRecordable( b_hasInput &&
89 var_GetBool( THEMIM->getInput(), "can-record" ) );
92 /* Generic button setup */
93 void AbstractController::setupButton( QAbstractButton *aButton )
95 static QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
96 sizePolicy.setHorizontalStretch( 0 );
97 sizePolicy.setVerticalStretch( 0 );
99 aButton->setSizePolicy( sizePolicy );
100 aButton->setFixedSize( QSize( 26, 26 ) );
101 aButton->setIconSize( QSize( 20, 20 ) );
102 aButton->setFocusPolicy( Qt::NoFocus );
105 /* Open the generic config line for the toolbar, parse it
106 * and create the widgets accordingly */
107 void AbstractController::parseAndCreateLine( QString config, int i_line )
110 QStringList list = config.split( ";" ) ;
111 for( int i = 0; i < list.size(); i++ )
113 QStringList list2 = list.at( i ).split( "-" );
114 if( list2.size() < 1 )
116 msg_Warn( p_intf, "Parsing error. Report this" );
121 int i_option = WIDGET_NORMAL;
122 buttonType_e i_type = (buttonType_e)list2.at( 0 ).toInt( &ok );
125 msg_Warn( p_intf, "Parsing error 0. Please report this" );
128 /* Special case for SPACERS, who aren't QWidgets */
129 if( i_type == WIDGET_SPACER || i_type == WIDGET_SPACER_EXTEND )
131 controlLayout->setColumnMinimumWidth( i, 10 );
133 controlLayout->setColumnStretch( i,
134 ( i_type == WIDGET_SPACER ) ? 0 : 10 );
138 if( list2.size() > 1 )
140 i_option = list2.at( 1 ).toInt( &ok );
143 msg_Warn( p_intf, "Parsing error 1. Please report this" );
149 QWidget *widg = createWidget( i_type, &i_size, i_option );
150 if( !widg ) continue;
152 if( list2.size() > 2 )
154 i_size = list.at( 2 ).toInt( &ok );
158 msg_Warn( p_intf, "Parsing error 2. Please report this" );
163 controlLayout->addWidget( widg, i_line, i_column, 1, i_size );
168 #define CONNECT_MAP( a ) CONNECT( a, clicked(), toolbarActionsMapper, map() )
169 #define SET_MAPPING( a, b ) toolbarActionsMapper->setMapping( a , b )
170 #define CONNECT_MAP_SET( a, b ) \
173 #define BUTTON_SET_BAR( button, image, tooltip ) \
174 button->setToolTip( tooltip ); \
175 button->setIcon( QIcon( ":/"#image ) );
177 #define ENABLE_ON_VIDEO( a ) \
178 CONNECT( THEMIM->getIM(), voutChanged( bool ), a, setEnabled( bool ) ); \
179 a->setEnabled( THEMIM->getIM()->hasVideo() ); /* TODO: is this necessary? when input is started before the interface? */
181 #define ENABLE_ON_INPUT( a ) \
182 CONNECT( this, inputExists( bool ), a, setEnabled( bool ) ); \
183 a->setEnabled( THEMIM->getIM()->hasInput() ); /* TODO: is this necessary? when input is started before the interface? */
185 QWidget *AbstractController::createWidget( buttonType_e button, int* i_size,
190 bool b_flat = options & WIDGET_FLAT;
191 bool b_big = options & WIDGET_BIG;
192 bool b_shiny = options & WIDGET_SHINY;
195 QWidget *widget = NULL;
199 PlayButton *playButton = new PlayButton;
200 setupButton( playButton );
201 BUTTON_SET_BAR( playButton, play_b, qtr( I_PLAY_TOOLTIP ) );
202 CONNECT_MAP_SET( playButton, PLAY_ACTION );
203 CONNECT( this, inputPlaying( bool ),
204 playButton, updateButton( bool ));
209 QToolButton *stopButton = new QToolButton;
210 setupButton( stopButton );
211 CONNECT_MAP_SET( stopButton, STOP_ACTION );
212 BUTTON_SET_BAR( stopButton, stop_b, qtr( "Stop playback" ) );
216 case PREVIOUS_BUTTON:{
217 QToolButton *prevButton = new QToolButton;
218 setupButton( prevButton );
219 CONNECT_MAP_SET( prevButton, PREVIOUS_ACTION );
220 BUTTON_SET_BAR( prevButton, previous_b,
221 qtr( "Previous media in the playlist" ) );
227 QToolButton *nextButton = new QToolButton;
228 setupButton( nextButton );
229 CONNECT_MAP_SET( nextButton, NEXT_ACTION );
230 BUTTON_SET_BAR( nextButton, next_b,
231 qtr( "Next media in the playlist" ) );
236 QToolButton *slowerButton = new QToolButton;
237 setupButton( slowerButton );
238 CONNECT_MAP_SET( slowerButton, SLOWER_ACTION );
239 BUTTON_SET_BAR( slowerButton, slower, qtr( "Slower" ) );
240 ENABLE_ON_INPUT( slowerButton );
241 widget = slowerButton;
245 QToolButton *fasterButton = new QToolButton;
246 setupButton( fasterButton );
247 CONNECT_MAP_SET( fasterButton, FASTER_ACTION );
248 BUTTON_SET_BAR( fasterButton, faster, qtr( "Faster" ) );
249 ENABLE_ON_INPUT( fasterButton );
250 widget = fasterButton;
254 QToolButton *frameButton = new QToolButton;
255 setupButton( frameButton );
256 CONNECT_MAP_SET( frameButton, FRAME_ACTION );
257 BUTTON_SET_BAR( frameButton, frame, qtr( "Frame by frame" ) );
258 ENABLE_ON_VIDEO( frameButton );
259 widget = frameButton;
262 case FULLSCREEN_BUTTON:{
263 QToolButton *fullscreenButton = new QToolButton;
264 setupButton( fullscreenButton );
265 CONNECT_MAP_SET( fullscreenButton, FULLSCREEN_ACTION );
266 BUTTON_SET_BAR( fullscreenButton, fullscreen,
267 qtr( "Toggle the video in fullscreen" ) );
268 ENABLE_ON_VIDEO( fullscreenButton );
269 widget = fullscreenButton;
272 case DEFULLSCREEN_BUTTON:{
273 QToolButton *fullscreenButton = new QToolButton;
274 setupButton( fullscreenButton );
275 CONNECT_MAP_SET( fullscreenButton, FULLSCREEN_ACTION );
276 BUTTON_SET_BAR( fullscreenButton, defullscreen,
277 qtr( "Toggle the video in fullscreen" ) );
278 ENABLE_ON_VIDEO( fullscreenButton );
279 widget = fullscreenButton;
282 case EXTENDED_BUTTON:{
283 QToolButton *extSettingsButton = new QToolButton;
284 setupButton( extSettingsButton );
285 CONNECT_MAP_SET( extSettingsButton, EXTENDED_ACTION );
286 BUTTON_SET_BAR( extSettingsButton, extended,
287 qtr( "Show extended settings" ) );
288 widget = extSettingsButton;
291 case PLAYLIST_BUTTON:{
292 QToolButton *playlistButton = new QToolButton;
293 setupButton( playlistButton );
294 CONNECT_MAP_SET( playlistButton, PLAYLIST_ACTION );
295 BUTTON_SET_BAR( playlistButton, playlist,
296 qtr( "Show playlist" ) );
297 widget = playlistButton;
300 case SNAPSHOT_BUTTON:{
301 QToolButton *snapshotButton = new QToolButton;
302 setupButton( snapshotButton );
303 CONNECT_MAP_SET( snapshotButton, SNAPSHOT_ACTION );
304 BUTTON_SET_BAR( snapshotButton, snapshot, qtr( "Take a snapshot" ) );
305 ENABLE_ON_VIDEO( snapshotButton );
306 widget = snapshotButton;
310 QToolButton *recordButton = new QToolButton;
311 setupButton( recordButton );
312 CONNECT_MAP_SET( recordButton, RECORD_ACTION );
313 BUTTON_SET_BAR( recordButton, record, qtr( "Record" ) );
314 ENABLE_ON_INPUT( recordButton );
315 widget = recordButton;
319 AtoB_Button *ABButton = new AtoB_Button;
320 setupButton( ABButton );
321 BUTTON_SET_BAR( ABButton, atob_nob, qtr( "Loop from point A to point "
322 "B continuously.\nClick to set point A" ) );
323 ENABLE_ON_INPUT( ABButton );
324 CONNECT_MAP_SET( ABButton, ATOB_ACTION );
325 CONNECT( THEMIM->getIM(), AtoBchanged( bool, bool),
326 ABButton, setIcons( bool, bool ) );
331 InputSlider *slider = new InputSlider( Qt::Horizontal, NULL );
332 /* Update the position when the IM has changed */
333 CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
334 slider, setPosition( float, int, int ) );
335 /* And update the IM, when the position has changed */
336 CONNECT( slider, sliderDragged( float ),
337 THEMIM->getIM(), sliderUpdate( float ) );
343 widget = discFrame();
347 case TELETEXT_BUTTONS:
348 widget = telexFrame();
354 SoundWidget *snd = new SoundWidget( p_intf, b_shiny );
361 TimeLabel *timeLabel = new TimeLabel( p_intf );
367 QFrame *line = new QFrame;
368 line->setFrameShape( QFrame::VLine );
369 line->setFrameShadow( QFrame::Raised );
370 line->setLineWidth( 0 );
371 line->setMidLineWidth( 1 );
375 case ADVANCED_CONTROLLER:
377 advControls = new AdvControlsWidget( p_intf );
378 widget = advControls;
379 *i_size = advControls->getWidth();
382 case REVERSE_BUTTON:{
383 QToolButton *reverseButton = new QToolButton;
384 setupButton( reverseButton );
385 CONNECT_MAP_SET( reverseButton, REVERSE_ACTION );
386 BUTTON_SET_BAR( reverseButton, reverse, qtr( "Reverse" ) );
387 ENABLE_ON_INPUT( reverseButton );
388 widget = reverseButton;
392 msg_Warn( p_intf, "This should not happen" );
396 /* Customize Buttons */
397 if( b_flat || b_big )
399 QToolButton *tmpButton = qobject_cast<QToolButton *>(widget);
403 tmpButton->setAutoRaise( b_flat );
406 tmpButton->setFixedSize( QSize( 32, 32 ) );
407 tmpButton->setIconSize( QSize( 26, 26 ) );
415 QWidget *AbstractController::discFrame()
417 /** Disc and Menus handling */
418 QWidget *discFrame = new QWidget( this );
420 QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
421 discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
423 QToolButton *prevSectionButton = new QToolButton( discFrame );
424 setupButton( prevSectionButton );
425 BUTTON_SET_BAR( prevSectionButton, dvd_prev,
426 qtr("Previous Chapter/Title" ) );
427 discLayout->addWidget( prevSectionButton );
429 QToolButton *menuButton = new QToolButton( discFrame );
430 setupButton( menuButton );
431 discLayout->addWidget( menuButton );
432 BUTTON_SET_BAR( menuButton, dvd_menu, qtr( "Menu" ) );
434 QToolButton *nextSectionButton = new QToolButton( discFrame );
435 setupButton( nextSectionButton );
436 discLayout->addWidget( nextSectionButton );
437 BUTTON_SET_BAR( nextSectionButton, dvd_next,
438 qtr("Next Chapter/Title" ) );
441 /* Change the navigation button display when the IM
442 navigation changes */
443 CONNECT( THEMIM->getIM(), titleChanged( bool ),
444 discFrame, setVisible( bool ) );
445 CONNECT( THEMIM->getIM(), chapterChanged( bool ),
446 menuButton, setVisible( bool ) );
447 /* Changes the IM navigation when triggered on the nav buttons */
448 CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
450 CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
452 CONNECT( menuButton, clicked(), THEMIM->getIM(),
458 QWidget *AbstractController::telexFrame()
463 TeletextController *telexFrame = new TeletextController;
464 QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
465 telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
466 CONNECT( THEMIM->getIM(), teletextPossible( bool ),
467 telexFrame, setVisible( bool ) );
470 QToolButton *telexOn = new QToolButton;
471 telexFrame->telexOn = telexOn;
472 setupButton( telexOn );
473 BUTTON_SET_BAR( telexOn, tv, qtr( "Teletext Activation" ) );
474 telexLayout->addWidget( telexOn );
476 /* Teletext Activation and set */
477 CONNECT( telexOn, clicked( bool ),
478 THEMIM->getIM(), activateTeletext( bool ) );
479 CONNECT( THEMIM->getIM(), teletextActivated( bool ),
480 telexFrame, enableTeletextButtons( bool ) );
483 /* Transparency button */
484 QToolButton *telexTransparent = new QToolButton;
485 telexFrame->telexTransparent = telexTransparent;
486 setupButton( telexTransparent );
487 BUTTON_SET_BAR( telexTransparent, tvtelx,
488 qtr( "Toggle Transparency " ) );
489 telexTransparent->setEnabled( false );
490 telexLayout->addWidget( telexTransparent );
492 /* Transparency change and set */
493 CONNECT( telexTransparent, clicked( bool ),
494 THEMIM->getIM(), telexSetTransparency( bool ) );
495 CONNECT( THEMIM->getIM(), teletextTransparencyActivated( bool ),
496 telexFrame, toggleTeletextTransparency( bool ) );
500 QSpinBox *telexPage = new QSpinBox;
501 telexFrame->telexPage = telexPage;
502 telexPage->setRange( 0, 999 );
503 telexPage->setValue( 100 );
504 telexPage->setAccelerated( true );
505 telexPage->setWrapping( true );
506 telexPage->setAlignment( Qt::AlignRight );
507 telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
508 telexPage->setEnabled( false );
509 telexLayout->addWidget( telexPage );
511 /* Page change and set */
512 CONNECT( telexPage, valueChanged( int ),
513 THEMIM->getIM(), telexSetPage( int ) );
514 CONNECT( THEMIM->getIM(), newTelexPageSet( int ),
515 telexPage, setValue( int ) );
521 #undef CONNECT_MAP_SET
522 #undef BUTTON_SET_BAR
523 #undef ENABLE_ON_VIDEO
524 #undef ENABLE_ON_INPUT
526 SoundWidget::SoundWidget( intf_thread_t * _p_intf, bool b_shiny )
527 : b_my_volume( false )
530 QHBoxLayout *layout = new QHBoxLayout( this );
531 layout->setSpacing( 0 ); layout->setMargin( 0 );
532 hVolLabel = new VolumeClickHandler( p_intf, this );
534 volMuteLabel = new QLabel;
535 volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
536 volMuteLabel->installEventFilter( hVolLabel );
537 layout->addWidget( volMuteLabel );
541 volumeSlider = new SoundSlider( this,
542 config_GetInt( p_intf, "volume-step" ),
543 config_GetInt( p_intf, "qt-volume-complete" ),
544 config_GetPsz( p_intf, "qt-slider-colours" ) );
548 volumeSlider = new QSlider( this );
549 volumeSlider->setOrientation( Qt::Horizontal );
551 volumeSlider->setMaximumSize( QSize( 200, 40 ) );
552 volumeSlider->setMinimumSize( QSize( 85, 30 ) );
553 volumeSlider->setFocusPolicy( Qt::NoFocus );
554 layout->addWidget( volumeSlider );
556 /* Set the volume from the config */
557 volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
558 VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
560 /* Force the update at build time in order to have a muted icon if needed */
561 updateVolume( volumeSlider->value() );
563 /* Volume control connection */
564 CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
565 CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
568 void SoundWidget::updateVolume( int i_sliderVolume )
572 int i_res = i_sliderVolume * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
573 aout_VolumeSet( p_intf, i_res );
575 if( i_sliderVolume == 0 )
577 volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
578 volMuteLabel->setToolTip( qtr( "Unmute" ) );
582 if( i_sliderVolume < VOLUME_MAX / 3 )
583 volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
584 else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
585 volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
586 else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
587 volMuteLabel->setToolTip( qtr( "Mute" ) );
590 void SoundWidget::updateVolume()
593 audio_volume_t i_volume;
594 aout_VolumeGet( p_intf, &i_volume );
595 i_volume = ( i_volume * VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
596 int i_gauge = volumeSlider->value();
598 if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
601 volumeSlider->setValue( i_volume );
606 void TeletextController::toggleTeletextTransparency( bool b_transparent )
608 telexTransparent->setIcon( b_transparent ? QIcon( ":/tvtelx" )
609 : QIcon( ":/tvtelx-trans" ) );
612 void TeletextController::enableTeletextButtons( bool b_enabled )
614 telexOn->setChecked( b_enabled );
615 telexTransparent->setEnabled( b_enabled );
616 telexPage->setEnabled( b_enabled );
619 void PlayButton::updateButton( bool b_playing )
621 setIcon( b_playing ? QIcon( ":/pause_b" ) : QIcon( ":/play_b" ) );
622 setToolTip( b_playing ? qtr( "Pause the playback" )
623 : qtr( I_PLAY_TOOLTIP ) );
626 void AtoB_Button::setIcons( bool timeA, bool timeB )
628 if( !timeA && !timeB)
630 setIcon( QIcon( ":/atob_nob" ) );
631 setToolTip( qtr( "Loop from point A to point B continuously\n"
632 "Click to set point A" ) );
634 else if( timeA && !timeB )
636 setIcon( QIcon( ":/atob_noa" ) );
637 setToolTip( qtr( "Click to set point B" ) );
639 else if( timeA && timeB )
641 setIcon( QIcon( ":/atob" ) );
642 setToolTip( qtr( "Stop the A to B loop" ) );
648 void AbstractController::doAction( int id_action )
654 case PREVIOUS_ACTION:
664 case FULLSCREEN_ACTION:
666 case EXTENDED_ACTION:
667 extSettings(); break;
668 case PLAYLIST_ACTION:
670 case SNAPSHOT_ACTION:
675 THEMIM->getIM()->setAtoB(); break;
681 msg_Dbg( p_intf, "Action: %i", id_action );
686 void AbstractController::stop()
691 void AbstractController::play()
693 if( THEPL->current.i_size == 0 )
695 /* The playlist is empty, open a file requester */
696 THEDP->openFileDialog();
699 THEMIM->togglePlayPause();
702 void AbstractController::prev()
707 void AbstractController::next()
714 * This functions toggle the fullscreen mode
715 * If there is no video, it should first activate Visualisations...
716 * This has also to be fixed in enableVideo()
718 void AbstractController::fullscreen()
720 vout_thread_t *p_vout =
721 (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
724 var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
725 vlc_object_release( p_vout );
729 void AbstractController::snapshot()
731 vout_thread_t *p_vout =
732 (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
735 vout_Control( p_vout, VOUT_SNAPSHOT );
736 vlc_object_release( p_vout );
740 void AbstractController::extSettings()
742 THEDP->extendedDialog();
745 void AbstractController::reverse()
747 THEMIM->getIM()->reverse();
750 void AbstractController::slower()
752 THEMIM->getIM()->slower();
755 void AbstractController::faster()
757 THEMIM->getIM()->faster();
760 void AbstractController::playlist()
762 if( p_intf->p_sys->p_mi ) p_intf->p_sys->p_mi->togglePlaylist();
765 void AbstractController::record()
767 input_thread_t *p_input = THEMIM->getInput();
770 /* This method won't work fine if the stream can't be cut anywhere */
771 const bool b_recording = var_GetBool( p_input, "record" );
772 var_SetBool( p_input, "record", !b_recording );
776 /* 'record' access-filter is not loaded, we open Save dialog */
777 input_item_t *p_item = input_GetItem( p_input );
781 char *psz = input_item_GetURI( p_item );
783 THEDP->streamingDialog( NULL, psz, true );
789 void AbstractController::frame()
791 input_thread_t *p_input = THEMIM->getInput();
793 var_SetVoid( p_input, "frame-next" );
796 /*****************************
797 * DA Control Widget !
798 *****************************/
799 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
800 bool b_advControls ) :
801 AbstractController( _p_i )
803 setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
805 /* advanced Controls handling */
806 b_advancedVisible = b_advControls;
809 controlLayout->setSpacing( 0 );
810 controlLayout->setLayoutMargins( 6, 4, 6, 2, 5 );
812 QString line1 = getSettings()->value( "MainWindow/Controls2",
813 "18;19;25" ).toString();
814 parseAndCreateLine( line1, 0 );
816 /* QString line2 = QString( "%1-2;%2;%3;%4;%5;%6;%6;%7;%8;%9;%6;%10;%11-4")
817 .arg( PLAY_BUTTON ) .arg( WIDGET_SPACER )
818 .arg( PREVIOUS_BUTTON ) .arg( STOP_BUTTON )
819 .arg( NEXT_BUTTON ) .arg( WIDGET_SPACER )
820 .arg( FULLSCREEN_BUTTON ) .arg( PLAYLIST_BUTTON )
821 .arg( EXTENDED_BUTTON ) .arg( WIDGET_SPACER_EXTEND )
824 QString line2 = getSettings()->value( "MainWindow/Controls2",
825 "0-2;21;21;4;2;5;21;21;8;11;10;21;22;20-4" ).toString();
826 parseAndCreateLine( line2, 1 );
828 if( !b_advancedVisible && advControls ) advControls->hide();
831 ControlsWidget::~ControlsWidget()
834 void ControlsWidget::toggleAdvanced()
836 if( !advControls ) return;
838 if( !b_advancedVisible )
841 b_advancedVisible = true;
846 b_advancedVisible = false;
848 emit advancedControlsToggled( b_advancedVisible );
851 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
852 AbstractController( _p_i )
854 controlLayout->setMargin( 0 );
855 controlLayout->setSpacing( 0 );
857 /* QString line = QString( "%1;%2;%3").arg( RECORD_BUTTON )
858 .arg( SNAPSHOT_BUTTON )
860 .arg( FRAME_BUTTON ); */
862 QString line = getSettings()->value( "MainWindow/AdvControl",
863 "12;13;14;15" ).toString();
864 parseAndCreateLine( line, 0 );
867 InputControlsWidget::InputControlsWidget( intf_thread_t *_p_i ) :
868 AbstractController( _p_i )
870 controlLayout->setMargin( 0 );
871 controlLayout->setSpacing( 0 );
873 /* QString line = QString( "%1-%2;%3;%4-%2")
874 .arg( SLOWER_BUTTON ).arg( WIDGET_FLAT )
876 .arg( FASTER_BUTTON ); */
877 QString line = getSettings()->value( "MainWindow/InputControl",
878 "6-1;16;7-1" ).toString();
879 parseAndCreateLine( line, 0 );
881 /**********************************************************************
882 * Fullscrenn control widget
883 **********************************************************************/
884 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i )
885 : AbstractController( _p_i )
889 b_mouse_over = false;
890 i_mouse_last_move_x = -1;
891 i_mouse_last_move_y = -1;
892 #if HAVE_TRANSPARENCY
893 b_slow_hide_begin = false;
894 i_slow_hide_timeout = 1;
896 b_fullscreen = false;
901 setWindowFlags( Qt::ToolTip );
902 setMinimumWidth( 600 );
904 setFrameShape( QFrame::StyledPanel );
905 setFrameStyle( QFrame::Sunken );
906 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
908 controlLayout->setLayoutMargins( 5, 2, 5, 2, 5 );
911 InputControlsWidget *inputC = new InputControlsWidget( p_intf );
912 controlLayout->addWidget( inputC, 0, 0, 1, -1 );
915 /* QString line2 = QString( "%1-2;%2;%3;%4;%5;%2;%6;%2;%7;%2;%8;%9;%10-4")
917 .arg( WIDGET_SPACER )
918 .arg( PREVIOUS_BUTTON )
922 .arg( TELETEXT_BUTTONS )
923 .arg( DEFULLSCREEN_BUTTON )
924 .arg( WIDGET_SPACER_EXTEND )
928 QString line = getSettings()->value( "MainWindow/FSCline",
929 "0-2;21;4;2;5;21;18;21;19;21;9;22;23-4" ).toString();
930 parseAndCreateLine( line, 1 );
933 p_hideTimer = new QTimer( this );
934 CONNECT( p_hideTimer, timeout(), this, hideFSC() );
935 p_hideTimer->setSingleShot( true );
937 /* slow hiding timer */
938 #if HAVE_TRANSPARENCY
939 p_slowHideTimer = new QTimer( this );
940 CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
943 adjustSize (); /* need to get real width and height for moving */
946 setWindowOpacity( 0.0 );
952 vlc_mutex_init_recursive( &lock );
955 FullscreenControllerWidget::~FullscreenControllerWidget()
957 getSettings()->setValue( "FullScreen/pos", pos() );
959 vlc_mutex_destroy( &lock );
963 * Show fullscreen controller
965 void FullscreenControllerWidget::showFSC()
969 int number = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
970 if( number != i_screennumber )
972 msg_Dbg( p_intf, "Calculation fullscreen controllers center");
973 /* screen has changed, calculate new position */
974 QRect screenRes = QApplication::desktop()->screenGeometry(number);
975 QPoint pos = QPoint( screenRes.x() + (screenRes.width() / 2) - (width() / 2),
976 screenRes.y() + screenRes.height() - height());
978 i_screennumber = number;
981 // after quiting and going to fs, we need to call show()
987 setWindowOpacity( 1.0 );
993 #if HAVE_TRANSPARENCY
994 setWindowOpacity( DEFAULT_OPACITY );
999 * Hide fullscreen controller
1000 * FIXME: under windows it have to be done by moving out of screen
1001 * because hide() doesnt work
1003 void FullscreenControllerWidget::hideFSC()
1007 setWindowOpacity( 0.0 ); // simulate hidding
1014 * Plane to hide fullscreen controller
1016 void FullscreenControllerWidget::planHideFSC()
1018 vlc_mutex_lock( &lock );
1019 int i_timeout = i_hide_timeout;
1020 vlc_mutex_unlock( &lock );
1022 p_hideTimer->start( i_timeout );
1024 #if HAVE_TRANSPARENCY
1025 b_slow_hide_begin = true;
1026 i_slow_hide_timeout = i_timeout;
1027 p_slowHideTimer->start( i_slow_hide_timeout / 2 );
1032 * Hidding fullscreen controller slowly
1033 * Linux: need composite manager
1034 * Windows: it is blinking, so it can be enabled by define TRASPARENCY
1036 void FullscreenControllerWidget::slowHideFSC()
1038 #if HAVE_TRANSPARENCY
1039 if( b_slow_hide_begin )
1041 b_slow_hide_begin = false;
1043 p_slowHideTimer->stop();
1044 /* the last part of time divided to 100 pieces */
1045 p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
1051 if ( windowOpacity() > 0.0 && !b_fscHidden )
1053 if ( windowOpacity() > 0.0 )
1056 /* we should use 0.01 because of 100 pieces ^^^
1057 but than it cannt be done in time */
1058 setWindowOpacity( windowOpacity() - 0.02 );
1061 if ( windowOpacity() <= 0.0 )
1062 p_slowHideTimer->stop();
1069 * events: show, hide, start timer for hidding
1071 void FullscreenControllerWidget::customEvent( QEvent *event )
1075 switch( event->type() )
1077 case FullscreenControlToggle_Type:
1078 vlc_mutex_lock( &lock );
1079 b_fs = b_fullscreen;
1080 vlc_mutex_unlock( &lock );
1088 p_hideTimer->stop();
1094 case FullscreenControlShow_Type:
1095 vlc_mutex_lock( &lock );
1096 b_fs = b_fullscreen;
1097 vlc_mutex_unlock( &lock );
1100 if( b_fs && b_fscHidden )
1102 if( b_fs && !isVisible() )
1106 case FullscreenControlHide_Type:
1109 case FullscreenControlPlanHide_Type:
1110 if( !b_mouse_over ) // Only if the mouse is not over FSC
1120 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1122 if ( event->buttons() == Qt::LeftButton )
1124 int i_moveX = event->globalX() - i_mouse_last_x;
1125 int i_moveY = event->globalY() - i_mouse_last_y;
1127 move( x() + i_moveX, y() + i_moveY );
1129 i_mouse_last_x = event->globalX();
1130 i_mouse_last_y = event->globalY();
1136 * store position of cursor
1138 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1140 i_mouse_last_x = event->globalX();
1141 i_mouse_last_y = event->globalY();
1145 * On mouse go above FSC
1147 void FullscreenControllerWidget::enterEvent( QEvent *event )
1149 b_mouse_over = true;
1151 p_hideTimer->stop();
1152 #if HAVE_TRANSPARENCY
1153 p_slowHideTimer->stop();
1158 * On mouse go out from FSC
1160 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1164 b_mouse_over = false;
1168 * When you get pressed key, send it to video output
1169 * FIXME: clearing focus by clearFocus() to not getting
1170 * key press events didnt work
1172 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1174 int i_vlck = qtEventToVLCKey( event );
1177 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1185 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
1186 const char *variable, vlc_value_t old_val,
1187 vlc_value_t new_val, void *data )
1189 vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1190 msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
1191 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1193 p_fs->fullscreenChanged( p_vout, new_val.b_bool,
1194 var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1199 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1200 vlc_value_t old_val, vlc_value_t new_val,
1203 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1205 int i_mousex, i_mousey;
1206 bool b_toShow = false;
1208 /* Get the value from the Vout - Trust the vout more than Qt */
1209 i_mousex = var_GetInteger( p_fs->p_vout, "mouse-x" );
1210 i_mousey = var_GetInteger( p_fs->p_vout, "mouse-y" );
1213 if( p_fs->i_mouse_last_move_x == -1 || p_fs->i_mouse_last_move_y == -1 )
1215 p_fs->i_mouse_last_move_x = i_mousex;
1216 p_fs->i_mouse_last_move_y = i_mousey;
1219 /* All other times */
1222 /* Trigger only if move > 3 px dans une direction */
1223 if( abs( p_fs->i_mouse_last_move_x - i_mousex ) > 2 ||
1224 abs( p_fs->i_mouse_last_move_y - i_mousey ) > 2 )
1227 p_fs->i_mouse_last_move_x = i_mousex;
1228 p_fs->i_mouse_last_move_y = i_mousey;
1235 IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1236 QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1238 /* Plan hide event */
1239 IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1240 QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1247 * It is called when video start
1249 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1251 assert( p_nvout && !p_vout );
1255 msg_Dbg( p_vout, "Qt FS: Attaching Vout" );
1256 vlc_mutex_lock( &lock );
1258 var_AddCallback( p_vout, "fullscreen",
1259 FullscreenControllerWidgetFullscreenChanged, this );
1260 /* I miss a add and fire */
1261 fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1262 var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1263 vlc_mutex_unlock( &lock );
1267 * It is called after turn off video.
1269 void FullscreenControllerWidget::detachVout()
1273 msg_Dbg( p_vout, "Qt FS: Detaching Vout" );
1274 var_DelCallback( p_vout, "fullscreen",
1275 FullscreenControllerWidgetFullscreenChanged, this );
1276 vlc_mutex_lock( &lock );
1277 fullscreenChanged( p_vout, false, 0 );
1278 vlc_mutex_unlock( &lock );
1284 * Register and unregister callback for mouse moving
1286 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1287 bool b_fs, int i_timeout )
1289 msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1291 vlc_mutex_lock( &lock );
1292 /* Entering fullscreen, register callback */
1293 if( b_fs && !b_fullscreen )
1295 b_fullscreen = true;
1296 i_hide_timeout = i_timeout;
1297 var_AddCallback( p_vout, "mouse-moved",
1298 FullscreenControllerWidgetMouseMoved, this );
1300 /* Quitting fullscreen, unregistering callback */
1301 else if( !b_fs && b_fullscreen )
1303 b_fullscreen = false;
1304 i_hide_timeout = i_timeout;
1305 var_DelCallback( p_vout, "mouse-moved",
1306 FullscreenControllerWidgetMouseMoved, this );
1308 /* Force fs hidding */
1309 IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1310 QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1312 vlc_mutex_unlock( &lock );