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 <QToolButton>
46 #include <QHBoxLayout>
49 #include <QResizeEvent>
51 #include <QSignalMapper>
54 #define I_PLAY_TOOLTIP N_("Play\nIf the playlist is empty, open a media")
56 /**********************************************************************
58 **********************************************************************/
61 * This is an abstract Toolbar/Controller
62 * This has helper to create any toolbar, any buttons and to manage the actions
65 AbstractController::AbstractController( intf_thread_t * _p_i ) : QFrame( NULL )
69 /* We need one layout. An controller without layout is stupid with
70 current architecture */
71 controlLayout = new QGridLayout( this );
73 /* Main action provider */
74 toolbarActionsMapper = new QSignalMapper( this );
75 CONNECT( toolbarActionsMapper, mapped( int ),
76 this, doAction( int ) );
77 CONNECT( THEMIM->getIM(), statusChanged( int ), this, setStatus( int ) );
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 void AbstractController::setupButton( QAbstractButton *aButton )
94 static QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
95 sizePolicy.setHorizontalStretch( 0 );
96 sizePolicy.setVerticalStretch( 0 );
98 aButton->setSizePolicy( sizePolicy );
99 aButton->setFixedSize( QSize( 26, 26 ) );
100 aButton->setIconSize( QSize( 20, 20 ) );
101 aButton->setFocusPolicy( Qt::NoFocus );
104 #define CONNECT_MAP( a ) CONNECT( a, clicked(), toolbarActionsMapper, map() )
105 #define SET_MAPPING( a, b ) toolbarActionsMapper->setMapping( a , b )
106 #define CONNECT_MAP_SET( a, b ) \
109 #define BUTTON_SET_BAR( button, image, tooltip ) \
110 button->setToolTip( tooltip ); \
111 button->setIcon( QIcon( ":/"#image ) );
113 #define ENABLE_ON_VIDEO( a ) \
114 CONNECT( THEMIM->getIM(), voutChanged( bool ), a, setEnabled( bool ) ); \
115 a->setEnabled( THEMIM->getIM()->hasVideo() ); /* TODO: is this necessary? when input is started before the interface? */
117 #define ENABLE_ON_INPUT( a ) \
118 CONNECT( this, inputExists( bool ), a, setEnabled( bool ) ); \
119 a->setEnabled( THEMIM->getIM()->hasInput() ); /* TODO: is this necessary? when input is started before the interface? */
121 QWidget *AbstractController::createWidget( buttonType_e button, bool b_flat,
122 bool b_big, bool b_shiny )
124 QWidget *widget = NULL;
128 PlayButton *playButton = new PlayButton;
129 setupButton( playButton );
130 BUTTON_SET_BAR( playButton, play_b, qtr( I_PLAY_TOOLTIP ) );
131 CONNECT_MAP_SET( playButton, PLAY_ACTION );
132 CONNECT( this, inputPlaying( bool ),
133 playButton, updateButton( bool ));
138 QToolButton *stopButton = new QToolButton;
139 setupButton( stopButton );
140 CONNECT_MAP_SET( stopButton, STOP_ACTION );
141 BUTTON_SET_BAR( stopButton, stop_b, qtr( "Stop playback" ) );
145 case PREVIOUS_BUTTON:{
146 QToolButton *prevButton = new QToolButton;
147 setupButton( prevButton );
148 CONNECT_MAP_SET( prevButton, PREVIOUS_ACTION );
149 BUTTON_SET_BAR( prevButton, previous_b,
150 qtr( "Previous media in the playlist" ) );
156 QToolButton *nextButton = new QToolButton;
157 setupButton( nextButton );
158 CONNECT_MAP_SET( nextButton, NEXT_ACTION );
159 BUTTON_SET_BAR( nextButton, next_b,
160 qtr( "Next media in the playlist" ) );
165 QToolButton *slowerButton = new QToolButton;
166 setupButton( slowerButton );
167 CONNECT_MAP_SET( slowerButton, SLOWER_ACTION );
168 BUTTON_SET_BAR( slowerButton, slower, qtr( "Slower" ) );
169 ENABLE_ON_INPUT( slowerButton );
170 widget = slowerButton;
174 QToolButton *fasterButton = new QToolButton;
175 setupButton( fasterButton );
176 CONNECT_MAP_SET( fasterButton, FASTER_ACTION );
177 BUTTON_SET_BAR( fasterButton, faster, qtr( "Faster" ) );
178 ENABLE_ON_INPUT( fasterButton );
179 widget = fasterButton;
184 QToolButton *frameButton = new QToolButton( "Fr" );
185 setupButton( frameButton );
186 BUTTON_SET_BAR( frameButton, "", qtr( "Frame by frame" ) );
187 ENABLE_ON_INPUT( frameButton );
188 widget = frameButton;
192 case FULLSCREEN_BUTTON:{
193 QToolButton *fullscreenButton = new QToolButton;
194 setupButton( fullscreenButton );
195 CONNECT_MAP_SET( fullscreenButton, FULLSCREEN_ACTION );
196 BUTTON_SET_BAR( fullscreenButton, fullscreen,
197 qtr( "Toggle the video in fullscreen" ) );
198 ENABLE_ON_VIDEO( fullscreenButton );
199 widget = fullscreenButton;
202 case EXTENDED_BUTTON:{
203 QToolButton *extSettingsButton = new QToolButton;
204 setupButton( extSettingsButton );
205 CONNECT_MAP_SET( extSettingsButton, EXTENDED_ACTION );
206 BUTTON_SET_BAR( extSettingsButton, extended,
207 qtr( "Show extended settings" ) );
208 widget = extSettingsButton;
211 case PLAYLIST_BUTTON:{
212 QToolButton *playlistButton = new QToolButton;
213 setupButton( playlistButton );
214 CONNECT_MAP_SET( playlistButton, PLAYLIST_ACTION );
215 BUTTON_SET_BAR( playlistButton, playlist,
216 qtr( "Show playlist" ) );
217 widget = playlistButton;
220 case SNAPSHOT_BUTTON:{
221 QToolButton *snapshotButton = new QToolButton;
222 setupButton( snapshotButton );
223 CONNECT_MAP_SET( snapshotButton, SNAPSHOT_ACTION );
224 BUTTON_SET_BAR( snapshotButton, snapshot, qtr( "Take a snapshot" ) );
225 ENABLE_ON_VIDEO( snapshotButton );
226 widget = snapshotButton;
230 QToolButton *recordButton = new QToolButton;
231 setupButton( recordButton );
232 CONNECT_MAP_SET( recordButton, RECORD_ACTION );
233 BUTTON_SET_BAR( recordButton, record, qtr( "Record" ) );
234 ENABLE_ON_INPUT( recordButton );
235 widget = recordButton;
239 AtoB_Button *ABButton = new AtoB_Button;
240 setupButton( ABButton );
241 BUTTON_SET_BAR( ABButton, atob_nob, qtr( "Loop from point A to point "
242 "B continuously.\nClick to set point A" ) );
243 ENABLE_ON_INPUT( ABButton );
244 CONNECT_MAP_SET( ABButton, ATOB_ACTION );
245 CONNECT( THEMIM->getIM(), AtoBchanged( bool, bool),
246 ABButton, setIcons( bool, bool ) );
251 InputSlider *slider = new InputSlider( Qt::Horizontal, NULL );
252 /* Update the position when the IM has changed */
253 CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
254 slider, setPosition( float, int, int ) );
255 /* And update the IM, when the position has changed */
256 CONNECT( slider, sliderDragged( float ),
257 THEMIM->getIM(), sliderUpdate( float ) );
262 widget = discFrame();
265 case TELETEXT_BUTTONS:
266 widget = telexFrame();
271 SoundWidget *snd = new SoundWidget( p_intf, b_shiny );
276 msg_Warn( p_intf, "This should not happen" );
280 /* Customize Buttons */
281 if( b_flat || b_big )
283 QToolButton *tmpButton = qobject_cast<QToolButton *>(widget);
287 tmpButton->setAutoRaise( b_flat );
290 tmpButton->setFixedSize( QSize( 32, 32 ) );
291 tmpButton->setIconSize( QSize( 26, 26 ) );
298 QWidget *AbstractController::discFrame()
300 /** Disc and Menus handling */
301 QWidget *discFrame = new QWidget( this );
303 QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
304 discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
306 QToolButton *prevSectionButton = new QToolButton( discFrame );
307 setupButton( prevSectionButton );
308 BUTTON_SET_BAR( prevSectionButton, dvd_prev,
309 qtr("Previous Chapter/Title" ) );
310 discLayout->addWidget( prevSectionButton );
312 QToolButton *menuButton = new QToolButton( discFrame );
313 setupButton( menuButton );
314 discLayout->addWidget( menuButton );
315 BUTTON_SET_BAR( menuButton, dvd_menu, qtr( "Menu" ) );
317 QToolButton *nextSectionButton = new QToolButton( discFrame );
318 setupButton( nextSectionButton );
319 discLayout->addWidget( nextSectionButton );
320 BUTTON_SET_BAR( nextSectionButton, dvd_next,
321 qtr("Next Chapter/Title" ) );
324 /* Change the navigation button display when the IM
325 navigation changes */
326 CONNECT( THEMIM->getIM(), titleChanged( bool ),
327 discFrame, setVisible( bool ) );
328 CONNECT( THEMIM->getIM(), chapterChanged( bool ),
329 menuButton, setVisible( bool ) );
330 /* Changes the IM navigation when triggered on the nav buttons */
331 CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
333 CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
335 CONNECT( menuButton, clicked(), THEMIM->getIM(),
341 QWidget *AbstractController::telexFrame()
346 TeletextController *telexFrame = new TeletextController;
347 QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
348 telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
349 CONNECT( THEMIM->getIM(), teletextPossible( bool ),
350 telexFrame, setVisible( bool ) );
353 QToolButton *telexOn = new QToolButton;
354 telexFrame->telexOn = telexOn;
355 setupButton( telexOn );
356 BUTTON_SET_BAR( telexOn, tv, qtr( "Teletext Activation" ) );
357 telexLayout->addWidget( telexOn );
359 /* Teletext Activation and set */
360 CONNECT( telexOn, clicked( bool ),
361 THEMIM->getIM(), activateTeletext( bool ) );
362 CONNECT( THEMIM->getIM(), teletextActivated( bool ),
363 telexFrame, enableTeletextButtons( bool ) );
366 /* Transparency button */
367 QToolButton *telexTransparent = new QToolButton;
368 telexFrame->telexTransparent = telexTransparent;
369 setupButton( telexTransparent );
370 BUTTON_SET_BAR( telexTransparent, tvtelx,
371 qtr( "Toggle Transparency " ) );
372 telexTransparent->setEnabled( false );
373 telexLayout->addWidget( telexTransparent );
375 /* Transparency change and set */
376 CONNECT( telexTransparent, clicked( bool ),
377 THEMIM->getIM(), telexSetTransparency( bool ) );
378 CONNECT( THEMIM->getIM(), teletextTransparencyActivated( bool ),
379 telexFrame, toggleTeletextTransparency( bool ) );
383 QSpinBox *telexPage = new QSpinBox;
384 telexFrame->telexPage = telexPage;
385 telexPage->setRange( 0, 999 );
386 telexPage->setValue( 100 );
387 telexPage->setAccelerated( true );
388 telexPage->setWrapping( true );
389 telexPage->setAlignment( Qt::AlignRight );
390 telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
391 telexPage->setEnabled( false );
392 telexLayout->addWidget( telexPage );
394 /* Page change and set */
395 CONNECT( telexPage, valueChanged( int ),
396 THEMIM->getIM(), telexSetPage( int ) );
397 CONNECT( THEMIM->getIM(), newTelexPageSet( int ),
398 telexPage, setValue( int ) );
404 #undef BUTTON_SET_BAR
406 SoundWidget::SoundWidget( intf_thread_t * _p_intf, bool b_shiny )
407 : b_my_volume( false )
410 QHBoxLayout *layout = new QHBoxLayout( this );
411 layout->setSpacing( 0 ); layout->setMargin( 0 );
412 hVolLabel = new VolumeClickHandler( p_intf, this );
414 volMuteLabel = new QLabel;
415 volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
416 volMuteLabel->installEventFilter( hVolLabel );
417 layout->addWidget( volMuteLabel );
421 volumeSlider = new SoundSlider( this,
422 config_GetInt( p_intf, "volume-step" ),
423 config_GetInt( p_intf, "qt-volume-complete" ),
424 config_GetPsz( p_intf, "qt-slider-colours" ) );
428 volumeSlider = new QSlider( this );
429 volumeSlider->setOrientation( Qt::Horizontal );
431 volumeSlider->setMaximumSize( QSize( 200, 40 ) );
432 volumeSlider->setMinimumSize( QSize( 85, 30 ) );
433 volumeSlider->setFocusPolicy( Qt::NoFocus );
434 layout->addWidget( volumeSlider );
436 /* Set the volume from the config */
437 volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
438 VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
440 /* Force the update at build time in order to have a muted icon if needed */
441 updateVolume( volumeSlider->value() );
443 /* Volume control connection */
444 CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
445 CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
448 void SoundWidget::updateVolume( int i_sliderVolume )
452 int i_res = i_sliderVolume * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
453 aout_VolumeSet( p_intf, i_res );
455 if( i_sliderVolume == 0 )
457 volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
458 volMuteLabel->setToolTip( qtr( "Unmute" ) );
462 if( i_sliderVolume < VOLUME_MAX / 3 )
463 volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
464 else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
465 volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
466 else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
467 volMuteLabel->setToolTip( qtr( "Mute" ) );
470 void SoundWidget::updateVolume()
473 audio_volume_t i_volume;
474 aout_VolumeGet( p_intf, &i_volume );
475 i_volume = ( i_volume * VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
476 int i_gauge = volumeSlider->value();
478 if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
481 volumeSlider->setValue( i_volume );
486 void TeletextController::toggleTeletextTransparency( bool b_transparent )
488 telexTransparent->setIcon( b_transparent ? QIcon( ":/tvtelx" )
489 : QIcon( ":/tvtelx-trans" ) );
492 void TeletextController::enableTeletextButtons( bool b_enabled )
494 telexOn->setChecked( b_enabled );
495 telexTransparent->setEnabled( b_enabled );
496 telexPage->setEnabled( b_enabled );
499 void PlayButton::updateButton( bool b_playing )
501 setIcon( b_playing ? QIcon( ":/pause_b" ) : QIcon( ":/play_b" ) );
502 setToolTip( b_playing ? qtr( "Pause the playback" )
503 : qtr( I_PLAY_TOOLTIP ) );
506 void AtoB_Button::setIcons( bool timeA, bool timeB )
508 if( !timeA && !timeB)
510 setIcon( QIcon( ":/atob_nob" ) );
511 setToolTip( qtr( "Loop from point A to point B continuously\n"
512 "Click to set point A" ) );
514 else if( timeA && !timeB )
516 setIcon( QIcon( ":/atob_noa" ) );
517 setToolTip( qtr( "Click to set point B" ) );
519 else if( timeA && timeB )
521 setIcon( QIcon( ":/atob" ) );
522 setToolTip( qtr( "Stop the A to B loop" ) );
528 void AbstractController::doAction( int id_action )
534 case PREVIOUS_ACTION:
544 case FULLSCREEN_ACTION:
546 case EXTENDED_ACTION:
547 extSettings(); break;
548 case PLAYLIST_ACTION:
550 case SNAPSHOT_ACTION:
555 THEMIM->getIM()->setAtoB(); break;
557 msg_Dbg( p_intf, "Action: %i", id_action );
562 void AbstractController::stop()
567 void AbstractController::play()
569 if( THEPL->current.i_size == 0 )
571 /* The playlist is empty, open a file requester */
572 THEDP->openFileDialog();
575 THEMIM->togglePlayPause();
578 void AbstractController::prev()
583 void AbstractController::next()
590 * This functions toggle the fullscreen mode
591 * If there is no video, it should first activate Visualisations...
592 * This has also to be fixed in enableVideo()
594 void AbstractController::fullscreen()
596 vout_thread_t *p_vout =
597 (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
600 var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
601 vlc_object_release( p_vout );
605 void AbstractController::snapshot()
607 vout_thread_t *p_vout =
608 (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
611 vout_Control( p_vout, VOUT_SNAPSHOT );
612 vlc_object_release( p_vout );
617 void AbstractController::extSettings()
619 THEDP->extendedDialog();
622 void AbstractController::slower()
624 THEMIM->getIM()->slower();
627 void AbstractController::faster()
629 THEMIM->getIM()->faster();
632 void AbstractController::playlist()
634 if( p_intf->p_sys->p_mi ) p_intf->p_sys->p_mi->togglePlaylist();
637 void AbstractController::record()
639 input_thread_t *p_input = THEMIM->getInput();
642 /* This method won't work fine if the stream can't be cut anywhere */
643 const bool b_recording = var_GetBool( p_input, "record" );
644 var_SetBool( p_input, "record", !b_recording );
648 /* 'record' access-filter is not loaded, we open Save dialog */
649 input_item_t *p_item = input_GetItem( p_input );
653 char *psz = input_item_GetURI( p_item );
655 THEDP->streamingDialog( NULL, psz, true );
662 //TODO Frame by frame function
663 void AbstractController::frame(){}
667 /*****************************
668 * DA Control Widget !
669 *****************************/
670 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
671 bool b_advControls ) :
672 AbstractController( _p_i )
674 setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
676 /* advanced Controls handling */
677 b_advancedVisible = b_advControls;
679 advControls = new AdvControlsWidget( p_intf );
680 if( !b_advancedVisible ) advControls->hide();
682 controlLayout->setSpacing( 0 );
683 controlLayout->setLayoutMargins( 7, 5, 7, 3, 6 );
685 controlLayout->addWidget( createWidget( INPUT_SLIDER ), 0, 1, 1, 18 );
686 controlLayout->addWidget( createWidget( SLOWER_BUTTON, true ), 0, 0 );
687 controlLayout->addWidget( createWidget( FASTER_BUTTON, true ), 0, 19 );
689 controlLayout->addWidget( createWidget( MENU_BUTTONS ), 1, 8, 2, 3 );
690 controlLayout->addWidget( createWidget( TELETEXT_BUTTONS ), 1, 8, 2, 5, Qt::AlignBottom );
692 controlLayout->addWidget( createWidget( PLAY_BUTTON, false, true ), 2, 0, 2, 2, Qt::AlignBottom );
693 controlLayout->setColumnMinimumWidth( 2, 10 );
694 controlLayout->setColumnStretch( 2, 0 );
696 controlLayout->addWidget( createWidget( PREVIOUS_BUTTON ), 3, 3, Qt::AlignBottom );
697 controlLayout->addWidget( createWidget( STOP_BUTTON ), 3, 4, Qt::AlignBottom );
698 controlLayout->addWidget( createWidget( NEXT_BUTTON ), 3, 5, Qt::AlignBottom );
700 /* Column 6 is unused */
701 controlLayout->setColumnStretch( 6, 0 );
702 controlLayout->setColumnStretch( 7, 0 );
703 controlLayout->setColumnMinimumWidth( 7, 10 );
705 controlLayout->addWidget( createWidget( FULLSCREEN_BUTTON ), 3, 8, Qt::AlignBottom );
706 controlLayout->addWidget( createWidget( PLAYLIST_BUTTON ), 3, 9, Qt::AlignBottom );
707 controlLayout->addWidget( createWidget( EXTENDED_BUTTON ), 3, 10, Qt::AlignBottom );
708 controlLayout->setColumnStretch( 11, 0 ); /* telex alignment */
710 controlLayout->setColumnStretch( 12, 0 );
711 controlLayout->setColumnMinimumWidth( 12, 10 );
713 controlLayout->addWidget( advControls, 3, 13, 1, 3, Qt::AlignBottom );
715 controlLayout->setColumnStretch( 16, 10 );
716 controlLayout->setColumnMinimumWidth( 16, 10 );
718 controlLayout->addWidget( createWidget( VOLUME, false, false, true ),
719 3, 17, 1, 3, Qt::AlignBottom );
722 ControlsWidget::~ControlsWidget()
725 void ControlsWidget::toggleAdvanced()
727 if( advControls && !b_advancedVisible )
730 b_advancedVisible = true;
735 b_advancedVisible = false;
737 emit advancedControlsToggled( b_advancedVisible );
740 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
741 AbstractController( _p_i )
743 controlLayout->setMargin( 0 );
744 controlLayout->setSpacing( 0 );
746 controlLayout->addWidget( createWidget( RECORD_BUTTON ), 0, 0 );
747 controlLayout->addWidget( createWidget( SNAPSHOT_BUTTON ), 0, 1 );
748 controlLayout->addWidget( createWidget( ATOB_BUTTON ), 0, 2 );
751 AdvControlsWidget::~AdvControlsWidget()
755 /**********************************************************************
756 * Fullscrenn control widget
757 **********************************************************************/
758 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i )
759 : AbstractController( _p_i )
763 b_mouse_over = false;
764 i_mouse_last_move_x = -1;
765 i_mouse_last_move_y = -1;
766 #if HAVE_TRANSPARENCY
767 b_slow_hide_begin = false;
768 i_slow_hide_timeout = 1;
770 b_fullscreen = false;
775 setWindowFlags( Qt::ToolTip );
776 setMinimumWidth( 600 );
778 setFrameShape( QFrame::StyledPanel );
779 setFrameStyle( QFrame::Sunken );
780 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
782 controlLayout->setLayoutMargins( 5, 2, 5, 2, 5 );
785 controlLayout->addWidget( createWidget( SLOWER_BUTTON, true ), 0, 0 );
786 controlLayout->addWidget( createWidget( INPUT_SLIDER ), 0, 1, 1, 13 );
787 controlLayout->addWidget( createWidget( FASTER_BUTTON, true ), 0, 14 );
790 controlLayout->addWidget( createWidget( PLAY_BUTTON, false, true ), 1, 0, 1, 2 );
791 controlLayout->addWidget( createWidget( PREVIOUS_BUTTON ), 1, 2 );
792 controlLayout->addWidget( createWidget( STOP_BUTTON ), 1, 3 );
793 controlLayout->addWidget( createWidget( NEXT_BUTTON ), 1, 4 );
795 controlLayout->addWidget( createWidget( MENU_BUTTONS ), 1, 5 );
796 controlLayout->addWidget( createWidget( TELETEXT_BUTTONS ), 1, 6 );
797 QToolButton *fullscreenButton =
798 qobject_cast<QToolButton *>(createWidget( FULLSCREEN_BUTTON ) );
799 fullscreenButton->setIcon( QIcon( ":/defullscreen" ) );
800 controlLayout->addWidget( fullscreenButton, 1, 7 );
802 controlLayout->setColumnStretch( 9, 10 );
804 TimeLabel *timeLabel = new TimeLabel( p_intf );
806 controlLayout->addWidget( timeLabel, 1, 10 );
807 controlLayout->addWidget( createWidget( VOLUME, false, false, true ),
811 p_hideTimer = new QTimer( this );
812 CONNECT( p_hideTimer, timeout(), this, hideFSC() );
813 p_hideTimer->setSingleShot( true );
815 /* slow hiding timer */
816 #if HAVE_TRANSPARENCY
817 p_slowHideTimer = new QTimer( this );
818 CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
821 adjustSize (); /* need to get real width and height for moving */
824 setWindowOpacity( 0.0 );
830 vlc_mutex_init_recursive( &lock );
833 FullscreenControllerWidget::~FullscreenControllerWidget()
835 getSettings()->beginGroup( "FullScreen" );
836 getSettings()->setValue( "pos", pos() );
837 getSettings()->endGroup();
839 vlc_mutex_destroy( &lock );
843 * Show fullscreen controller
845 void FullscreenControllerWidget::showFSC()
849 int number = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
850 if( number != i_screennumber )
852 msg_Dbg( p_intf, "Calculation fullscreen controllers center");
853 /* screen has changed, calculate new position */
854 QRect screenRes = QApplication::desktop()->screenGeometry(number);
855 QPoint pos = QPoint( screenRes.x() + (screenRes.width() / 2) - (width() / 2),
856 screenRes.y() + screenRes.height() - height());
858 i_screennumber = number;
861 // after quiting and going to fs, we need to call show()
867 setWindowOpacity( 1.0 );
873 #if HAVE_TRANSPARENCY
874 setWindowOpacity( DEFAULT_OPACITY );
879 * Hide fullscreen controller
880 * FIXME: under windows it have to be done by moving out of screen
881 * because hide() doesnt work
883 void FullscreenControllerWidget::hideFSC()
887 setWindowOpacity( 0.0 ); // simulate hidding
894 * Plane to hide fullscreen controller
896 void FullscreenControllerWidget::planHideFSC()
898 vlc_mutex_lock( &lock );
899 int i_timeout = i_hide_timeout;
900 vlc_mutex_unlock( &lock );
902 p_hideTimer->start( i_timeout );
904 #if HAVE_TRANSPARENCY
905 b_slow_hide_begin = true;
906 i_slow_hide_timeout = i_timeout;
907 p_slowHideTimer->start( i_slow_hide_timeout / 2 );
912 * Hidding fullscreen controller slowly
913 * Linux: need composite manager
914 * Windows: it is blinking, so it can be enabled by define TRASPARENCY
916 void FullscreenControllerWidget::slowHideFSC()
918 #if HAVE_TRANSPARENCY
919 if( b_slow_hide_begin )
921 b_slow_hide_begin = false;
923 p_slowHideTimer->stop();
924 /* the last part of time divided to 100 pieces */
925 p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
931 if ( windowOpacity() > 0.0 && !b_fscHidden )
933 if ( windowOpacity() > 0.0 )
936 /* we should use 0.01 because of 100 pieces ^^^
937 but than it cannt be done in time */
938 setWindowOpacity( windowOpacity() - 0.02 );
941 if ( windowOpacity() <= 0.0 )
942 p_slowHideTimer->stop();
949 * events: show, hide, start timer for hidding
951 void FullscreenControllerWidget::customEvent( QEvent *event )
955 switch( event->type() )
957 case FullscreenControlToggle_Type:
958 vlc_mutex_lock( &lock );
960 vlc_mutex_unlock( &lock );
974 case FullscreenControlShow_Type:
975 vlc_mutex_lock( &lock );
977 vlc_mutex_unlock( &lock );
980 if( b_fs && b_fscHidden )
982 if( b_fs && !isVisible() )
986 case FullscreenControlHide_Type:
989 case FullscreenControlPlanHide_Type:
990 if( !b_mouse_over ) // Only if the mouse is not over FSC
1000 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1002 if ( event->buttons() == Qt::LeftButton )
1004 int i_moveX = event->globalX() - i_mouse_last_x;
1005 int i_moveY = event->globalY() - i_mouse_last_y;
1007 move( x() + i_moveX, y() + i_moveY );
1009 i_mouse_last_x = event->globalX();
1010 i_mouse_last_y = event->globalY();
1016 * store position of cursor
1018 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1020 i_mouse_last_x = event->globalX();
1021 i_mouse_last_y = event->globalY();
1025 * On mouse go above FSC
1027 void FullscreenControllerWidget::enterEvent( QEvent *event )
1029 b_mouse_over = true;
1031 p_hideTimer->stop();
1032 #if HAVE_TRANSPARENCY
1033 p_slowHideTimer->stop();
1038 * On mouse go out from FSC
1040 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1044 b_mouse_over = false;
1048 * When you get pressed key, send it to video output
1049 * FIXME: clearing focus by clearFocus() to not getting
1050 * key press events didnt work
1052 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1054 int i_vlck = qtEventToVLCKey( event );
1057 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1065 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
1066 const char *variable, vlc_value_t old_val,
1067 vlc_value_t new_val, void *data )
1069 vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1070 msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
1071 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1073 p_fs->fullscreenChanged( p_vout, new_val.b_bool,
1074 var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1079 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1080 vlc_value_t old_val, vlc_value_t new_val,
1083 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1085 int i_mousex, i_mousey;
1086 bool b_toShow = false;
1088 /* Get the value from the Vout - Trust the vout more than Qt */
1089 i_mousex = var_GetInteger( p_fs->p_vout, "mouse-x" );
1090 i_mousey = var_GetInteger( p_fs->p_vout, "mouse-y" );
1093 if( p_fs->i_mouse_last_move_x == -1 || p_fs->i_mouse_last_move_y == -1 )
1095 p_fs->i_mouse_last_move_x = i_mousex;
1096 p_fs->i_mouse_last_move_y = i_mousey;
1099 /* All other times */
1102 /* Trigger only if move > 3 px dans une direction */
1103 if( abs( p_fs->i_mouse_last_move_x - i_mousex ) > 2 ||
1104 abs( p_fs->i_mouse_last_move_y - i_mousey ) > 2 )
1107 p_fs->i_mouse_last_move_x = i_mousex;
1108 p_fs->i_mouse_last_move_y = i_mousey;
1115 IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1116 QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1118 /* Plan hide event */
1119 IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1120 QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1128 * It is called when video start
1130 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1132 assert( p_nvout && !p_vout );
1136 msg_Dbg( p_vout, "Qt FS: Attaching Vout" );
1137 vlc_mutex_lock( &lock );
1139 var_AddCallback( p_vout, "fullscreen",
1140 FullscreenControllerWidgetFullscreenChanged, this );
1141 /* I miss a add and fire */
1142 fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1143 var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1144 vlc_mutex_unlock( &lock );
1147 * It is called after turn off video.
1149 void FullscreenControllerWidget::detachVout()
1153 msg_Dbg( p_vout, "Qt FS: Detaching Vout" );
1154 var_DelCallback( p_vout, "fullscreen",
1155 FullscreenControllerWidgetFullscreenChanged, this );
1156 vlc_mutex_lock( &lock );
1157 fullscreenChanged( p_vout, false, 0 );
1158 vlc_mutex_unlock( &lock );
1164 * Register and unregister callback for mouse moving
1166 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1167 bool b_fs, int i_timeout )
1169 msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1171 vlc_mutex_lock( &lock );
1172 /* Entering fullscreen, register callback */
1173 if( b_fs && !b_fullscreen )
1175 b_fullscreen = true;
1176 i_hide_timeout = i_timeout;
1177 var_AddCallback( p_vout, "mouse-moved",
1178 FullscreenControllerWidgetMouseMoved, this );
1180 /* Quitting fullscreen, unregistering callback */
1181 else if( !b_fs && b_fullscreen )
1183 b_fullscreen = false;
1184 i_hide_timeout = i_timeout;
1185 var_DelCallback( p_vout, "mouse-moved",
1186 FullscreenControllerWidgetMouseMoved, this );
1188 /* Force fs hidding */
1189 IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1190 QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1192 vlc_mutex_unlock( &lock );