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_INPUT( 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 msg_Warn( p_intf, "This should not happen" );
386 /* Customize Buttons */
387 if( b_flat || b_big )
389 QToolButton *tmpButton = qobject_cast<QToolButton *>(widget);
393 tmpButton->setAutoRaise( b_flat );
396 tmpButton->setFixedSize( QSize( 32, 32 ) );
397 tmpButton->setIconSize( QSize( 26, 26 ) );
405 QWidget *AbstractController::discFrame()
407 /** Disc and Menus handling */
408 QWidget *discFrame = new QWidget( this );
410 QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
411 discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
413 QToolButton *prevSectionButton = new QToolButton( discFrame );
414 setupButton( prevSectionButton );
415 BUTTON_SET_BAR( prevSectionButton, dvd_prev,
416 qtr("Previous Chapter/Title" ) );
417 discLayout->addWidget( prevSectionButton );
419 QToolButton *menuButton = new QToolButton( discFrame );
420 setupButton( menuButton );
421 discLayout->addWidget( menuButton );
422 BUTTON_SET_BAR( menuButton, dvd_menu, qtr( "Menu" ) );
424 QToolButton *nextSectionButton = new QToolButton( discFrame );
425 setupButton( nextSectionButton );
426 discLayout->addWidget( nextSectionButton );
427 BUTTON_SET_BAR( nextSectionButton, dvd_next,
428 qtr("Next Chapter/Title" ) );
431 /* Change the navigation button display when the IM
432 navigation changes */
433 CONNECT( THEMIM->getIM(), titleChanged( bool ),
434 discFrame, setVisible( bool ) );
435 CONNECT( THEMIM->getIM(), chapterChanged( bool ),
436 menuButton, setVisible( bool ) );
437 /* Changes the IM navigation when triggered on the nav buttons */
438 CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
440 CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
442 CONNECT( menuButton, clicked(), THEMIM->getIM(),
448 QWidget *AbstractController::telexFrame()
453 TeletextController *telexFrame = new TeletextController;
454 QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
455 telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
456 CONNECT( THEMIM->getIM(), teletextPossible( bool ),
457 telexFrame, setVisible( bool ) );
460 QToolButton *telexOn = new QToolButton;
461 telexFrame->telexOn = telexOn;
462 setupButton( telexOn );
463 BUTTON_SET_BAR( telexOn, tv, qtr( "Teletext Activation" ) );
464 telexLayout->addWidget( telexOn );
466 /* Teletext Activation and set */
467 CONNECT( telexOn, clicked( bool ),
468 THEMIM->getIM(), activateTeletext( bool ) );
469 CONNECT( THEMIM->getIM(), teletextActivated( bool ),
470 telexFrame, enableTeletextButtons( bool ) );
473 /* Transparency button */
474 QToolButton *telexTransparent = new QToolButton;
475 telexFrame->telexTransparent = telexTransparent;
476 setupButton( telexTransparent );
477 BUTTON_SET_BAR( telexTransparent, tvtelx,
478 qtr( "Toggle Transparency " ) );
479 telexTransparent->setEnabled( false );
480 telexLayout->addWidget( telexTransparent );
482 /* Transparency change and set */
483 CONNECT( telexTransparent, clicked( bool ),
484 THEMIM->getIM(), telexSetTransparency( bool ) );
485 CONNECT( THEMIM->getIM(), teletextTransparencyActivated( bool ),
486 telexFrame, toggleTeletextTransparency( bool ) );
490 QSpinBox *telexPage = new QSpinBox;
491 telexFrame->telexPage = telexPage;
492 telexPage->setRange( 0, 999 );
493 telexPage->setValue( 100 );
494 telexPage->setAccelerated( true );
495 telexPage->setWrapping( true );
496 telexPage->setAlignment( Qt::AlignRight );
497 telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
498 telexPage->setEnabled( false );
499 telexLayout->addWidget( telexPage );
501 /* Page change and set */
502 CONNECT( telexPage, valueChanged( int ),
503 THEMIM->getIM(), telexSetPage( int ) );
504 CONNECT( THEMIM->getIM(), newTelexPageSet( int ),
505 telexPage, setValue( int ) );
511 #undef CONNECT_MAP_SET
512 #undef BUTTON_SET_BAR
513 #undef ENABLE_ON_VIDEO
514 #undef ENABLE_ON_INPUT
516 SoundWidget::SoundWidget( intf_thread_t * _p_intf, bool b_shiny )
517 : b_my_volume( false )
520 QHBoxLayout *layout = new QHBoxLayout( this );
521 layout->setSpacing( 0 ); layout->setMargin( 0 );
522 hVolLabel = new VolumeClickHandler( p_intf, this );
524 volMuteLabel = new QLabel;
525 volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
526 volMuteLabel->installEventFilter( hVolLabel );
527 layout->addWidget( volMuteLabel );
531 volumeSlider = new SoundSlider( this,
532 config_GetInt( p_intf, "volume-step" ),
533 config_GetInt( p_intf, "qt-volume-complete" ),
534 config_GetPsz( p_intf, "qt-slider-colours" ) );
538 volumeSlider = new QSlider( this );
539 volumeSlider->setOrientation( Qt::Horizontal );
541 volumeSlider->setMaximumSize( QSize( 200, 40 ) );
542 volumeSlider->setMinimumSize( QSize( 85, 30 ) );
543 volumeSlider->setFocusPolicy( Qt::NoFocus );
544 layout->addWidget( volumeSlider );
546 /* Set the volume from the config */
547 volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
548 VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
550 /* Force the update at build time in order to have a muted icon if needed */
551 updateVolume( volumeSlider->value() );
553 /* Volume control connection */
554 CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
555 CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
558 void SoundWidget::updateVolume( int i_sliderVolume )
562 int i_res = i_sliderVolume * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
563 aout_VolumeSet( p_intf, i_res );
565 if( i_sliderVolume == 0 )
567 volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
568 volMuteLabel->setToolTip( qtr( "Unmute" ) );
572 if( i_sliderVolume < VOLUME_MAX / 3 )
573 volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
574 else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
575 volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
576 else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
577 volMuteLabel->setToolTip( qtr( "Mute" ) );
580 void SoundWidget::updateVolume()
583 audio_volume_t i_volume;
584 aout_VolumeGet( p_intf, &i_volume );
585 i_volume = ( i_volume * VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
586 int i_gauge = volumeSlider->value();
588 if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
591 volumeSlider->setValue( i_volume );
596 void TeletextController::toggleTeletextTransparency( bool b_transparent )
598 telexTransparent->setIcon( b_transparent ? QIcon( ":/tvtelx" )
599 : QIcon( ":/tvtelx-trans" ) );
602 void TeletextController::enableTeletextButtons( bool b_enabled )
604 telexOn->setChecked( b_enabled );
605 telexTransparent->setEnabled( b_enabled );
606 telexPage->setEnabled( b_enabled );
609 void PlayButton::updateButton( bool b_playing )
611 setIcon( b_playing ? QIcon( ":/pause_b" ) : QIcon( ":/play_b" ) );
612 setToolTip( b_playing ? qtr( "Pause the playback" )
613 : qtr( I_PLAY_TOOLTIP ) );
616 void AtoB_Button::setIcons( bool timeA, bool timeB )
618 if( !timeA && !timeB)
620 setIcon( QIcon( ":/atob_nob" ) );
621 setToolTip( qtr( "Loop from point A to point B continuously\n"
622 "Click to set point A" ) );
624 else if( timeA && !timeB )
626 setIcon( QIcon( ":/atob_noa" ) );
627 setToolTip( qtr( "Click to set point B" ) );
629 else if( timeA && timeB )
631 setIcon( QIcon( ":/atob" ) );
632 setToolTip( qtr( "Stop the A to B loop" ) );
638 void AbstractController::doAction( int id_action )
644 case PREVIOUS_ACTION:
654 case FULLSCREEN_ACTION:
656 case EXTENDED_ACTION:
657 extSettings(); break;
658 case PLAYLIST_ACTION:
660 case SNAPSHOT_ACTION:
665 THEMIM->getIM()->setAtoB(); break;
669 msg_Dbg( p_intf, "Action: %i", id_action );
674 void AbstractController::stop()
679 void AbstractController::play()
681 if( THEPL->current.i_size == 0 )
683 /* The playlist is empty, open a file requester */
684 THEDP->openFileDialog();
687 THEMIM->togglePlayPause();
690 void AbstractController::prev()
695 void AbstractController::next()
702 * This functions toggle the fullscreen mode
703 * If there is no video, it should first activate Visualisations...
704 * This has also to be fixed in enableVideo()
706 void AbstractController::fullscreen()
708 vout_thread_t *p_vout =
709 (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
712 var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
713 vlc_object_release( p_vout );
717 void AbstractController::snapshot()
719 vout_thread_t *p_vout =
720 (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
723 vout_Control( p_vout, VOUT_SNAPSHOT );
724 vlc_object_release( p_vout );
728 void AbstractController::extSettings()
730 THEDP->extendedDialog();
733 void AbstractController::slower()
735 THEMIM->getIM()->slower();
738 void AbstractController::faster()
740 THEMIM->getIM()->faster();
743 void AbstractController::playlist()
745 if( p_intf->p_sys->p_mi ) p_intf->p_sys->p_mi->togglePlaylist();
748 void AbstractController::record()
750 input_thread_t *p_input = THEMIM->getInput();
753 /* This method won't work fine if the stream can't be cut anywhere */
754 const bool b_recording = var_GetBool( p_input, "record" );
755 var_SetBool( p_input, "record", !b_recording );
759 /* 'record' access-filter is not loaded, we open Save dialog */
760 input_item_t *p_item = input_GetItem( p_input );
764 char *psz = input_item_GetURI( p_item );
766 THEDP->streamingDialog( NULL, psz, true );
772 void AbstractController::frame()
774 input_thread_t *p_input = THEMIM->getInput();
776 var_SetVoid( p_input, "frame-next" );
779 /*****************************
780 * DA Control Widget !
781 *****************************/
782 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
783 bool b_advControls ) :
784 AbstractController( _p_i )
786 setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
788 /* advanced Controls handling */
789 b_advancedVisible = b_advControls;
792 controlLayout->setSpacing( 0 );
793 controlLayout->setLayoutMargins( 6, 4, 6, 2, 5 );
795 QString line1 = getSettings()->value( "MainWindow/Controls2",
796 "18;19;25" ).toString();
797 parseAndCreateLine( line1, 0 );
799 /* QString line2 = QString( "%1-2;%2;%3;%4;%5;%6;%6;%7;%8;%9;%6;%10;%11-4")
800 .arg( PLAY_BUTTON ) .arg( WIDGET_SPACER )
801 .arg( PREVIOUS_BUTTON ) .arg( STOP_BUTTON )
802 .arg( NEXT_BUTTON ) .arg( WIDGET_SPACER )
803 .arg( FULLSCREEN_BUTTON ) .arg( PLAYLIST_BUTTON )
804 .arg( EXTENDED_BUTTON ) .arg( WIDGET_SPACER_EXTEND )
807 QString line2 = getSettings()->value( "MainWindow/Controls2",
808 "0-2;21;21;4;2;5;21;21;8;11;10;21;22;20-4" ).toString();
809 parseAndCreateLine( line2, 1 );
811 if( !b_advancedVisible && advControls ) advControls->hide();
814 ControlsWidget::~ControlsWidget()
817 void ControlsWidget::toggleAdvanced()
819 if( !advControls ) return;
821 if( !b_advancedVisible )
824 b_advancedVisible = true;
829 b_advancedVisible = false;
831 emit advancedControlsToggled( b_advancedVisible );
834 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
835 AbstractController( _p_i )
837 controlLayout->setMargin( 0 );
838 controlLayout->setSpacing( 0 );
840 /* QString line = QString( "%1;%2;%3").arg( RECORD_BUTTON )
841 .arg( SNAPSHOT_BUTTON )
843 .arg( FRAME_BUTTON ); */
845 QString line = getSettings()->value( "MainWindow/AdvControl",
846 "12;13;14;15" ).toString();
847 parseAndCreateLine( line, 0 );
850 InputControlsWidget::InputControlsWidget( intf_thread_t *_p_i ) :
851 AbstractController( _p_i )
853 controlLayout->setMargin( 0 );
854 controlLayout->setSpacing( 0 );
856 /* QString line = QString( "%1-%2;%3;%4-%2")
857 .arg( SLOWER_BUTTON ).arg( WIDGET_FLAT )
859 .arg( FASTER_BUTTON ); */
860 QString line = getSettings()->value( "MainWindow/InputControl",
861 "6-1;16;7-1" ).toString();
862 parseAndCreateLine( line, 0 );
864 /**********************************************************************
865 * Fullscrenn control widget
866 **********************************************************************/
867 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i )
868 : AbstractController( _p_i )
872 b_mouse_over = false;
873 i_mouse_last_move_x = -1;
874 i_mouse_last_move_y = -1;
875 #if HAVE_TRANSPARENCY
876 b_slow_hide_begin = false;
877 i_slow_hide_timeout = 1;
879 b_fullscreen = false;
884 setWindowFlags( Qt::ToolTip );
885 setMinimumWidth( 600 );
887 setFrameShape( QFrame::StyledPanel );
888 setFrameStyle( QFrame::Sunken );
889 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
891 controlLayout->setLayoutMargins( 5, 2, 5, 2, 5 );
894 InputControlsWidget *inputC = new InputControlsWidget( p_intf );
895 controlLayout->addWidget( inputC, 0, 0, 1, -1 );
898 /* QString line2 = QString( "%1-2;%2;%3;%4;%5;%2;%6;%2;%7;%2;%8;%9;%10-4")
900 .arg( WIDGET_SPACER )
901 .arg( PREVIOUS_BUTTON )
905 .arg( TELETEXT_BUTTONS )
906 .arg( DEFULLSCREEN_BUTTON )
907 .arg( WIDGET_SPACER_EXTEND )
911 QString line = getSettings()->value( "MainWindow/FSCline",
912 "0-2;21;4;2;5;21;18;21;19;21;9;22;23-4" ).toString();
913 parseAndCreateLine( line, 1 );
916 p_hideTimer = new QTimer( this );
917 CONNECT( p_hideTimer, timeout(), this, hideFSC() );
918 p_hideTimer->setSingleShot( true );
920 /* slow hiding timer */
921 #if HAVE_TRANSPARENCY
922 p_slowHideTimer = new QTimer( this );
923 CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
926 adjustSize (); /* need to get real width and height for moving */
929 setWindowOpacity( 0.0 );
935 vlc_mutex_init_recursive( &lock );
938 FullscreenControllerWidget::~FullscreenControllerWidget()
940 getSettings()->setValue( "FullScreen/pos", pos() );
942 vlc_mutex_destroy( &lock );
946 * Show fullscreen controller
948 void FullscreenControllerWidget::showFSC()
952 int number = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
953 if( number != i_screennumber )
955 msg_Dbg( p_intf, "Calculation fullscreen controllers center");
956 /* screen has changed, calculate new position */
957 QRect screenRes = QApplication::desktop()->screenGeometry(number);
958 QPoint pos = QPoint( screenRes.x() + (screenRes.width() / 2) - (width() / 2),
959 screenRes.y() + screenRes.height() - height());
961 i_screennumber = number;
964 // after quiting and going to fs, we need to call show()
970 setWindowOpacity( 1.0 );
976 #if HAVE_TRANSPARENCY
977 setWindowOpacity( DEFAULT_OPACITY );
982 * Hide fullscreen controller
983 * FIXME: under windows it have to be done by moving out of screen
984 * because hide() doesnt work
986 void FullscreenControllerWidget::hideFSC()
990 setWindowOpacity( 0.0 ); // simulate hidding
997 * Plane to hide fullscreen controller
999 void FullscreenControllerWidget::planHideFSC()
1001 vlc_mutex_lock( &lock );
1002 int i_timeout = i_hide_timeout;
1003 vlc_mutex_unlock( &lock );
1005 p_hideTimer->start( i_timeout );
1007 #if HAVE_TRANSPARENCY
1008 b_slow_hide_begin = true;
1009 i_slow_hide_timeout = i_timeout;
1010 p_slowHideTimer->start( i_slow_hide_timeout / 2 );
1015 * Hidding fullscreen controller slowly
1016 * Linux: need composite manager
1017 * Windows: it is blinking, so it can be enabled by define TRASPARENCY
1019 void FullscreenControllerWidget::slowHideFSC()
1021 #if HAVE_TRANSPARENCY
1022 if( b_slow_hide_begin )
1024 b_slow_hide_begin = false;
1026 p_slowHideTimer->stop();
1027 /* the last part of time divided to 100 pieces */
1028 p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
1034 if ( windowOpacity() > 0.0 && !b_fscHidden )
1036 if ( windowOpacity() > 0.0 )
1039 /* we should use 0.01 because of 100 pieces ^^^
1040 but than it cannt be done in time */
1041 setWindowOpacity( windowOpacity() - 0.02 );
1044 if ( windowOpacity() <= 0.0 )
1045 p_slowHideTimer->stop();
1052 * events: show, hide, start timer for hidding
1054 void FullscreenControllerWidget::customEvent( QEvent *event )
1058 switch( event->type() )
1060 case FullscreenControlToggle_Type:
1061 vlc_mutex_lock( &lock );
1062 b_fs = b_fullscreen;
1063 vlc_mutex_unlock( &lock );
1071 p_hideTimer->stop();
1077 case FullscreenControlShow_Type:
1078 vlc_mutex_lock( &lock );
1079 b_fs = b_fullscreen;
1080 vlc_mutex_unlock( &lock );
1083 if( b_fs && b_fscHidden )
1085 if( b_fs && !isVisible() )
1089 case FullscreenControlHide_Type:
1092 case FullscreenControlPlanHide_Type:
1093 if( !b_mouse_over ) // Only if the mouse is not over FSC
1103 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1105 if ( event->buttons() == Qt::LeftButton )
1107 int i_moveX = event->globalX() - i_mouse_last_x;
1108 int i_moveY = event->globalY() - i_mouse_last_y;
1110 move( x() + i_moveX, y() + i_moveY );
1112 i_mouse_last_x = event->globalX();
1113 i_mouse_last_y = event->globalY();
1119 * store position of cursor
1121 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1123 i_mouse_last_x = event->globalX();
1124 i_mouse_last_y = event->globalY();
1128 * On mouse go above FSC
1130 void FullscreenControllerWidget::enterEvent( QEvent *event )
1132 b_mouse_over = true;
1134 p_hideTimer->stop();
1135 #if HAVE_TRANSPARENCY
1136 p_slowHideTimer->stop();
1141 * On mouse go out from FSC
1143 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1147 b_mouse_over = false;
1151 * When you get pressed key, send it to video output
1152 * FIXME: clearing focus by clearFocus() to not getting
1153 * key press events didnt work
1155 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1157 int i_vlck = qtEventToVLCKey( event );
1160 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1168 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
1169 const char *variable, vlc_value_t old_val,
1170 vlc_value_t new_val, void *data )
1172 vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1173 msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
1174 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1176 p_fs->fullscreenChanged( p_vout, new_val.b_bool,
1177 var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1182 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1183 vlc_value_t old_val, vlc_value_t new_val,
1186 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1188 int i_mousex, i_mousey;
1189 bool b_toShow = false;
1191 /* Get the value from the Vout - Trust the vout more than Qt */
1192 i_mousex = var_GetInteger( p_fs->p_vout, "mouse-x" );
1193 i_mousey = var_GetInteger( p_fs->p_vout, "mouse-y" );
1196 if( p_fs->i_mouse_last_move_x == -1 || p_fs->i_mouse_last_move_y == -1 )
1198 p_fs->i_mouse_last_move_x = i_mousex;
1199 p_fs->i_mouse_last_move_y = i_mousey;
1202 /* All other times */
1205 /* Trigger only if move > 3 px dans une direction */
1206 if( abs( p_fs->i_mouse_last_move_x - i_mousex ) > 2 ||
1207 abs( p_fs->i_mouse_last_move_y - i_mousey ) > 2 )
1210 p_fs->i_mouse_last_move_x = i_mousex;
1211 p_fs->i_mouse_last_move_y = i_mousey;
1218 IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1219 QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1221 /* Plan hide event */
1222 IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1223 QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1231 * It is called when video start
1233 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1235 assert( p_nvout && !p_vout );
1239 msg_Dbg( p_vout, "Qt FS: Attaching Vout" );
1240 vlc_mutex_lock( &lock );
1242 var_AddCallback( p_vout, "fullscreen",
1243 FullscreenControllerWidgetFullscreenChanged, this );
1244 /* I miss a add and fire */
1245 fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1246 var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1247 vlc_mutex_unlock( &lock );
1250 * It is called after turn off video.
1252 void FullscreenControllerWidget::detachVout()
1256 msg_Dbg( p_vout, "Qt FS: Detaching Vout" );
1257 var_DelCallback( p_vout, "fullscreen",
1258 FullscreenControllerWidgetFullscreenChanged, this );
1259 vlc_mutex_lock( &lock );
1260 fullscreenChanged( p_vout, false, 0 );
1261 vlc_mutex_unlock( &lock );
1267 * Register and unregister callback for mouse moving
1269 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1270 bool b_fs, int i_timeout )
1272 msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1274 vlc_mutex_lock( &lock );
1275 /* Entering fullscreen, register callback */
1276 if( b_fs && !b_fullscreen )
1278 b_fullscreen = true;
1279 i_hide_timeout = i_timeout;
1280 var_AddCallback( p_vout, "mouse-moved",
1281 FullscreenControllerWidgetMouseMoved, this );
1283 /* Quitting fullscreen, unregistering callback */
1284 else if( !b_fs && b_fullscreen )
1286 b_fullscreen = false;
1287 i_hide_timeout = i_timeout;
1288 var_DelCallback( p_vout, "mouse-moved",
1289 FullscreenControllerWidgetMouseMoved, this );
1291 /* Force fs hidding */
1292 IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1293 QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1295 vlc_mutex_unlock( &lock );