]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/controller.cpp
Qt: Teletext handling simplifications and change of the icons to more clear ones.
[vlc] / modules / gui / qt4 / components / controller.cpp
1 /*****************************************************************************
2  * Controller.cpp : Controller for the main interface
3  ****************************************************************************
4  * Copyright (C) 2006-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jean-Baptiste Kempf <jb@videolan.org>
8  *          Ilkka Ollakka <ileoo@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * ( at your option ) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_vout.h>
30 #include <vlc_keys.h>
31
32 #include "components/controller.hpp"
33 #include "components/controller_widget.hpp"
34 #include "components/interface_widgets.hpp"
35
36 #include "dialogs_provider.hpp" /* Opening Dialogs */
37 #include "input_manager.hpp"
38 #include "actions_manager.hpp"
39
40 #include "util/input_slider.hpp" /* InputSlider */
41 #include "util/customwidgets.hpp" /* qEventToKey */
42
43 #include <QSpacerItem>
44 #include <QToolButton>
45 #include <QHBoxLayout>
46 #include <QSignalMapper>
47 #include <QTimer>
48
49 /**********************************************************************
50  * TEH controls
51  **********************************************************************/
52
53 /******
54  * This is an abstract Toolbar/Controller
55  * This has helper to create any toolbar, any buttons and to manage the actions
56  *
57  *****/
58 AbstractController::AbstractController( intf_thread_t * _p_i, QWidget *_parent )
59                    : QFrame( _parent )
60 {
61     p_intf = _p_i;
62     advControls = NULL;
63
64     /* Main action provider */
65     toolbarActionsMapper = new QSignalMapper( this );
66     CONNECT( toolbarActionsMapper, mapped( int ),
67              ActionsManager::getInstance( p_intf  ), doAction( int ) );
68     CONNECT( THEMIM->getIM(), statusChanged( int ), this, setStatus( int ) );
69 }
70
71 /* Reemit some signals on status Change to activate some buttons */
72 void AbstractController::setStatus( int status )
73 {
74     bool b_hasInput = THEMIM->getIM()->hasInput();
75     /* Activate the interface buttons according to the presence of the input */
76     emit inputExists( b_hasInput );
77
78     emit inputPlaying( status == PLAYING_S );
79
80     emit inputIsRecordable( b_hasInput &&
81                             var_GetBool( THEMIM->getInput(), "can-record" ) );
82 }
83
84 /* Generic button setup */
85 void AbstractController::setupButton( QAbstractButton *aButton )
86 {
87     static QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
88     sizePolicy.setHorizontalStretch( 0 );
89     sizePolicy.setVerticalStretch( 0 );
90
91     aButton->setSizePolicy( sizePolicy );
92     aButton->setFixedSize( QSize( 26, 26 ) );
93     aButton->setIconSize( QSize( 20, 20 ) );
94     aButton->setFocusPolicy( Qt::NoFocus );
95 }
96
97 /* Open the generic config line for the toolbar, parse it
98  * and create the widgets accordingly */
99 void AbstractController::parseAndCreate( QString config,
100                                          QBoxLayout *controlLayout )
101 {
102     QStringList list = config.split( ";", QString::SkipEmptyParts ) ;
103     for( int i = 0; i < list.size(); i++ )
104     {
105         QStringList list2 = list.at( i ).split( "-" );
106         if( list2.size() < 1 )
107         {
108             msg_Warn( p_intf, "Parsing error. Report this" );
109             continue;
110         }
111
112         bool ok;
113         int i_option = WIDGET_NORMAL;
114         buttonType_e i_type = (buttonType_e)list2.at( 0 ).toInt( &ok );
115         if( !ok )
116         {
117             msg_Warn( p_intf, "Parsing error 0. Please report this" );
118             continue;
119         }
120
121         if( list2.size() > 1 )
122         {
123             i_option = list2.at( 1 ).toInt( &ok );
124             if( !ok )
125             {
126                 msg_Warn( p_intf, "Parsing error 1. Please report this" );
127                 continue;
128             }
129         }
130
131         createAndAddWidget( controlLayout, -1, i_type, i_option );
132     }
133 }
134
135 void AbstractController::createAndAddWidget( QBoxLayout *controlLayout,
136                                              int i_index,
137                                              buttonType_e i_type,
138                                              int i_option )
139 {
140     /* Special case for SPACERS, who aren't QWidgets */
141     if( i_type == WIDGET_SPACER )
142     {
143         controlLayout->insertSpacing( i_index, 16 );
144         return;
145     }
146
147     if(  i_type == WIDGET_SPACER_EXTEND )
148     {
149         controlLayout->insertStretch( i_index, 16 );
150         return;
151     }
152
153     QWidget *widg = createWidget( i_type, i_option );
154     if( !widg ) return;
155
156     controlLayout->insertWidget( i_index, widg );
157 }
158
159
160 #define CONNECT_MAP( a ) CONNECT( a, clicked(),  toolbarActionsMapper, map() )
161 #define SET_MAPPING( a, b ) toolbarActionsMapper->setMapping( a , b )
162 #define CONNECT_MAP_SET( a, b ) \
163     CONNECT_MAP( a ); \
164     SET_MAPPING( a, b );
165 #define BUTTON_SET_BAR( a_button ) \
166     a_button->setToolTip( tooltipL[button] );          \
167     a_button->setIcon( QIcon( iconL[button] ) );
168 #define BUTTON_SET_BAR2( button, image, tooltip ) \
169     button->setToolTip( tooltip );          \
170     button->setIcon( QIcon( ":/"#image ) );
171
172
173 #define ENABLE_ON_VIDEO( a ) \
174     CONNECT( THEMIM->getIM(), voutChanged( bool ), a, setEnabled( bool ) ); \
175     a->setEnabled( THEMIM->getIM()->hasVideo() ); /* TODO: is this necessary? when input is started before the interface? */
176
177 #define ENABLE_ON_INPUT( a ) \
178     CONNECT( this, inputExists( bool ), a, setEnabled( bool ) ); \
179     a->setEnabled( THEMIM->getIM()->hasInput() ); /* TODO: is this necessary? when input is started before the interface? */
180
181 QWidget *AbstractController::createWidget( buttonType_e button, int options )
182 {
183
184     bool b_flat = options & WIDGET_FLAT;
185     bool b_big = options & WIDGET_BIG;
186     bool b_shiny = options & WIDGET_SHINY;
187
188     QWidget *widget = NULL;
189     switch( button )
190     {
191     case PLAY_BUTTON: {
192         PlayButton *playButton = new PlayButton;
193         setupButton( playButton );
194         BUTTON_SET_BAR(  playButton );
195         CONNECT_MAP_SET( playButton, PLAY_ACTION );
196         CONNECT( this, inputPlaying( bool ),
197                  playButton, updateButton( bool ));
198         widget = playButton;
199         }
200         break;
201     case STOP_BUTTON:{
202         QToolButton *stopButton = new QToolButton;
203         setupButton( stopButton );
204         CONNECT_MAP_SET( stopButton, STOP_ACTION );
205         BUTTON_SET_BAR(  stopButton );
206         widget = stopButton;
207         }
208         break;
209     case OPEN_BUTTON:{
210         QToolButton *openButton = new QToolButton;
211         setupButton( openButton );
212         CONNECT_MAP_SET( openButton, OPEN_ACTION );
213         BUTTON_SET_BAR( openButton );
214         widget = openButton;
215         }
216         break;
217     case PREVIOUS_BUTTON:{
218         QToolButton *prevButton = new QToolButton;
219         setupButton( prevButton );
220         CONNECT_MAP_SET( prevButton, PREVIOUS_ACTION );
221         BUTTON_SET_BAR( prevButton );
222         widget = prevButton;
223         }
224         break;
225     case NEXT_BUTTON:
226         {
227         QToolButton *nextButton = new QToolButton;
228         setupButton( nextButton );
229         CONNECT_MAP_SET( nextButton, NEXT_ACTION );
230         BUTTON_SET_BAR( nextButton );
231         widget = nextButton;
232         }
233         break;
234     case SLOWER_BUTTON:{
235         QToolButton *slowerButton = new QToolButton;
236         setupButton( slowerButton );
237         CONNECT_MAP_SET( slowerButton, SLOWER_ACTION );
238         BUTTON_SET_BAR(  slowerButton );
239         ENABLE_ON_INPUT( slowerButton );
240         widget = slowerButton;
241         }
242         break;
243     case FASTER_BUTTON:{
244         QToolButton *fasterButton = new QToolButton;
245         setupButton( fasterButton );
246         CONNECT_MAP_SET( fasterButton, FASTER_ACTION );
247         BUTTON_SET_BAR(  fasterButton );
248         ENABLE_ON_INPUT( fasterButton );
249         widget = fasterButton;
250         }
251         break;
252     case FRAME_BUTTON: {
253         QToolButton *frameButton = new QToolButton;
254         setupButton( frameButton );
255         CONNECT_MAP_SET( frameButton, FRAME_ACTION );
256         BUTTON_SET_BAR(  frameButton );
257         ENABLE_ON_VIDEO( frameButton );
258         widget = frameButton;
259         }
260         break;
261     case FULLSCREEN_BUTTON:{
262         QToolButton *fullscreenButton = new QToolButton;
263         setupButton( fullscreenButton );
264         CONNECT_MAP_SET( fullscreenButton, FULLSCREEN_ACTION );
265         BUTTON_SET_BAR( fullscreenButton );
266         ENABLE_ON_VIDEO( fullscreenButton );
267         widget = fullscreenButton;
268         }
269         break;
270     case DEFULLSCREEN_BUTTON:{
271         QToolButton *fullscreenButton = new QToolButton;
272         setupButton( fullscreenButton );
273         CONNECT_MAP_SET( fullscreenButton, FULLSCREEN_ACTION );
274         BUTTON_SET_BAR( fullscreenButton )
275         ENABLE_ON_VIDEO( fullscreenButton );
276         widget = fullscreenButton;
277         }
278         break;
279     case EXTENDED_BUTTON:{
280         QToolButton *extSettingsButton = new QToolButton;
281         setupButton( extSettingsButton );
282         CONNECT_MAP_SET( extSettingsButton, EXTENDED_ACTION );
283         BUTTON_SET_BAR( extSettingsButton )
284         widget = extSettingsButton;
285         }
286         break;
287     case PLAYLIST_BUTTON:{
288         QToolButton *playlistButton = new QToolButton;
289         setupButton( playlistButton );
290         CONNECT_MAP_SET( playlistButton, PLAYLIST_ACTION );
291         BUTTON_SET_BAR( playlistButton );
292         widget = playlistButton;
293         }
294         break;
295     case SNAPSHOT_BUTTON:{
296         QToolButton *snapshotButton = new QToolButton;
297         setupButton( snapshotButton );
298         CONNECT_MAP_SET( snapshotButton, SNAPSHOT_ACTION );
299         BUTTON_SET_BAR(  snapshotButton );
300         ENABLE_ON_VIDEO( snapshotButton );
301         widget = snapshotButton;
302         }
303         break;
304     case RECORD_BUTTON:{
305         QToolButton *recordButton = new QToolButton;
306         setupButton( recordButton );
307         CONNECT_MAP_SET( recordButton, RECORD_ACTION );
308         BUTTON_SET_BAR(  recordButton );
309         ENABLE_ON_INPUT( recordButton );
310         recordButton->setCheckable( true );
311         CONNECT( THEMIM->getIM(), recordingStateChanged( bool ),
312                  recordButton, setChecked( bool ) );
313         widget = recordButton;
314         }
315         break;
316     case ATOB_BUTTON: {
317         AtoB_Button *ABButton = new AtoB_Button;
318         setupButton( ABButton );
319         BUTTON_SET_BAR( ABButton );
320         ENABLE_ON_INPUT( ABButton );
321         CONNECT_MAP_SET( ABButton, ATOB_ACTION );
322         CONNECT( THEMIM->getIM(), AtoBchanged( bool, bool),
323                  ABButton, setIcons( bool, bool ) );
324         widget = ABButton;
325         }
326         break;
327     case INPUT_SLIDER: {
328         InputSlider *slider = new InputSlider( Qt::Horizontal, NULL );
329
330         /* Update the position when the IM has changed */
331         CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
332                 slider, setPosition( float, int, int ) );
333         /* And update the IM, when the position has changed */
334         CONNECT( slider, sliderDragged( float ),
335                  THEMIM->getIM(), sliderUpdate( float ) );
336         widget = slider;
337         }
338         break;
339     case MENU_BUTTONS:
340         widget = discFrame();
341         widget->hide();
342         break;
343     case TELETEXT_BUTTONS:
344         widget = telexFrame();
345         widget->hide();
346         break;
347     case VOLUME:
348         {
349             SoundWidget *snd = new SoundWidget( this, p_intf, b_shiny );
350             widget = snd;
351         }
352         break;
353     case TIME_LABEL:
354         {
355             TimeLabel *timeLabel = new TimeLabel( p_intf );
356             widget = timeLabel;
357         }
358         break;
359     case SPLITTER:
360         {
361             QFrame *line = new QFrame;
362             line->setFrameShape( QFrame::VLine );
363             line->setFrameShadow( QFrame::Raised );
364             line->setLineWidth( 0 );
365             line->setMidLineWidth( 1 );
366             widget = line;
367         }
368         break;
369     case ADVANCED_CONTROLLER:
370         {
371             advControls = new AdvControlsWidget( p_intf, this );
372             widget = advControls;
373         }
374         break;
375     case REVERSE_BUTTON:{
376         QToolButton *reverseButton = new QToolButton;
377         setupButton( reverseButton );
378         CONNECT_MAP_SET( reverseButton, REVERSE_ACTION );
379         BUTTON_SET_BAR(  reverseButton );
380         ENABLE_ON_INPUT( reverseButton );
381         widget = reverseButton;
382         }
383         break;
384     case SKIP_BACK_BUTTON: {
385         QToolButton *skipBakButton = new QToolButton;
386         setupButton( skipBakButton );
387         CONNECT_MAP_SET( skipBakButton, SKIP_BACK_ACTION );
388         BUTTON_SET_BAR(  skipBakButton );
389         ENABLE_ON_INPUT( skipBakButton );
390         widget = skipBakButton;
391         }
392         break;
393     case SKIP_FW_BUTTON: {
394         QToolButton *skipFwButton = new QToolButton;
395         setupButton( skipFwButton );
396         CONNECT_MAP_SET( skipFwButton, SKIP_FW_ACTION );
397         BUTTON_SET_BAR(  skipFwButton );
398         ENABLE_ON_INPUT( skipFwButton );
399         widget = skipFwButton;
400         }
401         break;
402     case QUIT_BUTTON: {
403         QToolButton *quitButton = new QToolButton;
404         setupButton( quitButton );
405         CONNECT_MAP_SET( quitButton, QUIT_ACTION );
406         BUTTON_SET_BAR(  quitButton );
407         widget = quitButton;
408         }
409         break;
410     default:
411         msg_Warn( p_intf, "This should not happen %i", button );
412         break;
413     }
414
415     /* Customize Buttons */
416     if( b_flat || b_big )
417     {
418         QToolButton *tmpButton = qobject_cast<QToolButton *>(widget);
419         if( tmpButton )
420         {
421             if( b_flat )
422                 tmpButton->setAutoRaise( b_flat );
423             if( b_big )
424             {
425                 tmpButton->setFixedSize( QSize( 32, 32 ) );
426                 tmpButton->setIconSize( QSize( 26, 26 ) );
427             }
428         }
429     }
430     return widget;
431 }
432
433 QFrame *AbstractController::discFrame()
434 {
435     /** Disc and Menus handling */
436     QFrame *discFrame = new QFrame( this );
437
438     QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
439     discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
440
441     QToolButton *prevSectionButton = new QToolButton( discFrame );
442     setupButton( prevSectionButton );
443     BUTTON_SET_BAR2( prevSectionButton, dvd_prev,
444             qtr("Previous Chapter/Title" ) );
445     discLayout->addWidget( prevSectionButton );
446
447     QToolButton *menuButton = new QToolButton( discFrame );
448     setupButton( menuButton );
449     discLayout->addWidget( menuButton );
450     BUTTON_SET_BAR2( menuButton, dvd_menu, qtr( "Menu" ) );
451
452     QToolButton *nextSectionButton = new QToolButton( discFrame );
453     setupButton( nextSectionButton );
454     discLayout->addWidget( nextSectionButton );
455     BUTTON_SET_BAR2( nextSectionButton, dvd_next,
456             qtr("Next Chapter/Title" ) );
457
458     /* Change the navigation button display when the IM
459        navigation changes */
460     CONNECT( THEMIM->getIM(), titleChanged( bool ),
461             discFrame, setVisible( bool ) );
462     CONNECT( THEMIM->getIM(), chapterChanged( bool ),
463             menuButton, setVisible( bool ) );
464     /* Changes the IM navigation when triggered on the nav buttons */
465     CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
466             sectionPrev() );
467     CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
468             sectionNext() );
469     CONNECT( menuButton, clicked(), THEMIM->getIM(),
470             sectionMenu() );
471
472     return discFrame;
473 }
474
475 QFrame *AbstractController::telexFrame()
476 {
477     /**
478      * Telextext QFrame
479      **/
480     TeletextController *telexFrame = new TeletextController;
481     QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
482     telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
483     CONNECT( THEMIM->getIM(), teletextPossible( bool ),
484              telexFrame, setVisible( bool ) );
485
486     /* On/Off button */
487     QToolButton *telexOn = new QToolButton;
488     telexFrame->telexOn = telexOn;
489     setupButton( telexOn );
490     BUTTON_SET_BAR2( telexOn, tv, qtr( "Teletext Activation" ) );
491     telexLayout->addWidget( telexOn );
492
493     /* Teletext Activation and set */
494     CONNECT( telexOn, clicked( bool ),
495              THEMIM->getIM(), activateTeletext( bool ) );
496     CONNECT( THEMIM->getIM(), teletextActivated( bool ),
497              telexFrame, enableTeletextButtons( bool ) );
498
499
500     /* Transparency button */
501     QToolButton *telexTransparent = new QToolButton;
502     telexFrame->telexTransparent = telexTransparent;
503     setupButton( telexTransparent );
504     BUTTON_SET_BAR2( telexTransparent, tvtelx,
505                      qtr( "Toggle Transparency " ) );
506     telexTransparent->setEnabled( false );
507     telexTransparent->setCheckable( true );
508     telexLayout->addWidget( telexTransparent );
509
510     /* Transparency change and set */
511     CONNECT( telexTransparent, clicked( bool ),
512             THEMIM->getIM(), telexSetTransparency( bool ) );
513     CONNECT( THEMIM->getIM(), teletextTransparencyActivated( bool ),
514              telexTransparent, setChecked( bool ) );
515
516
517     /* Page setting */
518     QSpinBox *telexPage = new QSpinBox;
519     telexFrame->telexPage = telexPage;
520     telexPage->setRange( 0, 999 );
521     telexPage->setValue( 100 );
522     telexPage->setAccelerated( true );
523     telexPage->setWrapping( true );
524     telexPage->setAlignment( Qt::AlignRight );
525     telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
526     telexPage->setEnabled( false );
527     telexLayout->addWidget( telexPage );
528
529     /* Page change and set */
530     CONNECT( telexPage, valueChanged( int ),
531             THEMIM->getIM(), telexSetPage( int ) );
532     CONNECT( THEMIM->getIM(), newTelexPageSet( int ),
533             telexPage, setValue( int ) );
534
535     return telexFrame;
536 }
537 #undef CONNECT_MAP
538 #undef SET_MAPPING
539 #undef CONNECT_MAP_SET
540 #undef BUTTON_SET_BAR
541 #undef ENABLE_ON_VIDEO
542 #undef ENABLE_ON_INPUT
543
544 #include <QHBoxLayout>
545 /*****************************
546  * DA Control Widget !
547  *****************************/
548 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
549                                 bool b_advControls,
550                                 QWidget *_parent ) :
551                                 AbstractController( _p_i, _parent )
552 {
553     setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
554
555     /* advanced Controls handling */
556     b_advancedVisible = b_advControls;
557
558     QVBoxLayout *controlLayout = new QVBoxLayout( this );
559     controlLayout->setLayoutMargins( 6, 4, 6, 2, 5 );
560     controlLayout->setSpacing( 0 );
561     QHBoxLayout *controlLayout1 = new QHBoxLayout;
562     controlLayout1->setSpacing( 0 );
563
564     QString line1 = getSettings()->value( "MainToolbar1", MAIN_TB1_DEFAULT )
565                                         .toString();
566     parseAndCreate( line1, controlLayout1 );
567
568     QHBoxLayout *controlLayout2 = new QHBoxLayout;
569     controlLayout2->setSpacing( 0 );
570     QString line2 = getSettings()->value( "MainToolbar2", MAIN_TB2_DEFAULT )
571                                         .toString();
572     parseAndCreate( line2, controlLayout2 );
573
574     if( !b_advancedVisible && advControls ) advControls->hide();
575
576     controlLayout->addLayout( controlLayout1 );
577     controlLayout->addLayout( controlLayout2 );
578 }
579
580 ControlsWidget::~ControlsWidget()
581 {}
582
583 void ControlsWidget::toggleAdvanced()
584 {
585     if( !advControls ) return;
586
587     if( !b_advancedVisible )
588     {
589         advControls->show();
590         b_advancedVisible = true;
591     }
592     else
593     {
594         advControls->hide();
595         b_advancedVisible = false;
596     }
597     emit advancedControlsToggled( b_advancedVisible );
598 }
599
600 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
601                                      AbstractController( _p_i, _parent )
602 {
603     controlLayout = new QHBoxLayout( this );
604     controlLayout->setMargin( 0 );
605     controlLayout->setSpacing( 0 );
606
607     QString line = getSettings()->value( "AdvToolbar", ADV_TB_DEFAULT )
608         .toString();
609     parseAndCreate( line, controlLayout );
610 }
611
612 InputControlsWidget::InputControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
613                                      AbstractController( _p_i, _parent )
614 {
615     controlLayout = new QHBoxLayout( this );
616     controlLayout->setMargin( 0 );
617     controlLayout->setSpacing( 0 );
618
619     QString line = getSettings()->value( "InputToolbar", INPT_TB_DEFAULT ).toString();
620     parseAndCreate( line, controlLayout );
621 }
622 /**********************************************************************
623  * Fullscrenn control widget
624  **********************************************************************/
625 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i )
626                            : AbstractController( _p_i )
627 {
628     i_mouse_last_x      = -1;
629     i_mouse_last_y      = -1;
630     b_mouse_over        = false;
631     i_mouse_last_move_x = -1;
632     i_mouse_last_move_y = -1;
633 #if HAVE_TRANSPARENCY
634     b_slow_hide_begin   = false;
635     i_slow_hide_timeout = 1;
636 #endif
637     b_fullscreen        = false;
638     i_hide_timeout      = 1;
639     i_screennumber      = -1;
640
641     vout.clear();
642
643     setWindowFlags( Qt::ToolTip );
644     setMinimumWidth( 600 );
645
646     setFrameShape( QFrame::StyledPanel );
647     setFrameStyle( QFrame::Sunken );
648     setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
649
650     QVBoxLayout *controlLayout2 = new QVBoxLayout( this );
651     controlLayout2->setLayoutMargins( 5, 2, 5, 2, 5 );
652
653     /* First line */
654     InputControlsWidget *inputC = new InputControlsWidget( p_intf, this );
655     controlLayout2->addWidget( inputC );
656
657     controlLayout = new QHBoxLayout;
658     QString line = getSettings()->value( "MainWindow/FSCtoolbar", FSC_TB_DEFAULT ).toString();
659     parseAndCreate( line, controlLayout );
660     controlLayout2->addLayout( controlLayout );
661
662     /* hiding timer */
663     p_hideTimer = new QTimer( this );
664     CONNECT( p_hideTimer, timeout(), this, hideFSC() );
665     p_hideTimer->setSingleShot( true );
666
667     /* slow hiding timer */
668 #if HAVE_TRANSPARENCY
669     p_slowHideTimer = new QTimer( this );
670     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
671 #endif
672
673     adjustSize ();  /* need to get real width and height for moving */
674
675 #ifdef WIN32TRICK
676     setWindowOpacity( 0.0 );
677     b_fscHidden = true;
678     adjustSize();
679     show();
680 #endif
681
682     vlc_mutex_init_recursive( &lock );
683
684     CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ), this, setVoutList( vout_thread_t **, int ) );
685 }
686
687 FullscreenControllerWidget::~FullscreenControllerWidget()
688 {
689     getSettings()->setValue( "FullScreen/pos", pos() );
690     setVoutList( NULL, 0 );
691     vlc_mutex_destroy( &lock );
692 }
693
694 /**
695  * Show fullscreen controller
696  */
697 void FullscreenControllerWidget::showFSC()
698 {
699     adjustSize();
700     /* center down */
701     int number = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
702     if( number != i_screennumber )
703     {
704         msg_Dbg( p_intf, "Calculation fullscreen controllers center");
705         /* screen has changed, calculate new position */
706         QRect screenRes = QApplication::desktop()->screenGeometry(number);
707         QPoint pos = QPoint( screenRes.x() + (screenRes.width() / 2) - (width() / 2),
708                              screenRes.y() + screenRes.height() - height());
709         move( pos );
710         i_screennumber = number;
711     }
712 #ifdef WIN32TRICK
713     // after quiting and going to fs, we need to call show()
714     if( isHidden() )
715         show();
716     if( b_fscHidden )
717     {
718         b_fscHidden = false;
719         setWindowOpacity( 1.0 );
720     }
721 #else
722     show();
723 #endif
724
725 #if HAVE_TRANSPARENCY
726     setWindowOpacity( DEFAULT_OPACITY );
727 #endif
728 }
729
730 /**
731  * Hide fullscreen controller
732  * FIXME: under windows it have to be done by moving out of screen
733  *        because hide() doesnt work
734  */
735 void FullscreenControllerWidget::hideFSC()
736 {
737 #ifdef WIN32TRICK
738     b_fscHidden = true;
739     setWindowOpacity( 0.0 );    // simulate hidding
740 #else
741     hide();
742 #endif
743 }
744
745 /**
746  * Plane to hide fullscreen controller
747  */
748 void FullscreenControllerWidget::planHideFSC()
749 {
750     vlc_mutex_lock( &lock );
751     int i_timeout = i_hide_timeout;
752     vlc_mutex_unlock( &lock );
753
754     p_hideTimer->start( i_timeout );
755
756 #if HAVE_TRANSPARENCY
757     b_slow_hide_begin = true;
758     i_slow_hide_timeout = i_timeout;
759     p_slowHideTimer->start( i_slow_hide_timeout / 2 );
760 #endif
761 }
762
763 /**
764  * Hidding fullscreen controller slowly
765  * Linux: need composite manager
766  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
767  */
768 void FullscreenControllerWidget::slowHideFSC()
769 {
770 #if HAVE_TRANSPARENCY
771     if( b_slow_hide_begin )
772     {
773         b_slow_hide_begin = false;
774
775         p_slowHideTimer->stop();
776         /* the last part of time divided to 100 pieces */
777         p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
778
779     }
780     else
781     {
782 #ifdef WIN32TRICK
783          if ( windowOpacity() > 0.0 && !b_fscHidden )
784 #else
785          if ( windowOpacity() > 0.0 )
786 #endif
787          {
788              /* we should use 0.01 because of 100 pieces ^^^
789                 but than it cannt be done in time */
790              setWindowOpacity( windowOpacity() - 0.02 );
791          }
792
793          if ( windowOpacity() <= 0.0 )
794              p_slowHideTimer->stop();
795     }
796 #endif
797 }
798
799 /**
800  * event handling
801  * events: show, hide, start timer for hidding
802  */
803 void FullscreenControllerWidget::customEvent( QEvent *event )
804 {
805     bool b_fs;
806
807     switch( event->type() )
808     {
809         case FullscreenControlToggle_Type:
810             vlc_mutex_lock( &lock );
811             b_fs = b_fullscreen;
812             vlc_mutex_unlock( &lock );
813             if( b_fs )
814             {
815 #ifdef WIN32TRICK
816                 if( b_fscHidden )
817 #else
818                 if( isHidden() )
819 #endif
820                 {
821                     p_hideTimer->stop();
822                     showFSC();
823                 }
824                 else
825                     hideFSC();
826             }
827             break;
828         case FullscreenControlShow_Type:
829             vlc_mutex_lock( &lock );
830             b_fs = b_fullscreen;
831             vlc_mutex_unlock( &lock );
832
833 #ifdef WIN32TRICK
834             if( b_fs && b_fscHidden )
835 #else
836             if( b_fs && !isVisible() )
837 #endif
838                 showFSC();
839             break;
840         case FullscreenControlHide_Type:
841             hideFSC();
842             break;
843         case FullscreenControlPlanHide_Type:
844             if( !b_mouse_over ) // Only if the mouse is not over FSC
845                 planHideFSC();
846             break;
847         default:
848             break;
849     }
850 }
851
852 /**
853  * On mouse move
854  * moving with FSC
855  */
856 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
857 {
858     if ( event->buttons() == Qt::LeftButton )
859     {
860         int i_moveX = event->globalX() - i_mouse_last_x;
861         int i_moveY = event->globalY() - i_mouse_last_y;
862
863         move( x() + i_moveX, y() + i_moveY );
864
865         i_mouse_last_x = event->globalX();
866         i_mouse_last_y = event->globalY();
867     }
868 }
869
870 /**
871  * On mouse press
872  * store position of cursor
873  */
874 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
875 {
876     i_mouse_last_x = event->globalX();
877     i_mouse_last_y = event->globalY();
878 }
879
880 /**
881  * On mouse go above FSC
882  */
883 void FullscreenControllerWidget::enterEvent( QEvent *event )
884 {
885     b_mouse_over = true;
886
887     p_hideTimer->stop();
888 #if HAVE_TRANSPARENCY
889     p_slowHideTimer->stop();
890 #endif
891     event->accept();
892 }
893
894 /**
895  * On mouse go out from FSC
896  */
897 void FullscreenControllerWidget::leaveEvent( QEvent *event )
898 {
899     planHideFSC();
900
901     b_mouse_over = false;
902     event->accept();
903 }
904
905 /**
906  * When you get pressed key, send it to video output
907  * FIXME: clearing focus by clearFocus() to not getting
908  * key press events didnt work
909  */
910 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
911 {
912     int i_vlck = qtEventToVLCKey( event );
913     if( i_vlck > 0 )
914     {
915         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
916         event->accept();
917     }
918     else
919         event->ignore();
920 }
921
922 /* */
923 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
924                 const char *variable, vlc_value_t old_val,
925                 vlc_value_t new_val,  void *data )
926 {
927     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
928
929     msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
930     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
931
932     p_fs->fullscreenChanged( p_vout, new_val.b_bool, var_GetInteger( p_vout, "mouse-hide-timeout" ) );
933
934     return VLC_SUCCESS;
935 }
936 /* */
937 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
938                                                  vlc_value_t old_val, vlc_value_t new_val,
939                                                  void *data )
940 {
941     vout_thread_t *p_vout = (vout_thread_t *)vlc_object;
942     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
943
944     /* Get the value from the Vout - Trust the vout more than Qt */
945     const int i_mousex = var_GetInteger( p_vout, "mouse-x" );
946     const int i_mousey = var_GetInteger( p_vout, "mouse-y" );
947
948     p_fs->mouseChanged( p_vout, i_mousex, i_mousey );
949
950     return VLC_SUCCESS;
951 }
952
953 /**
954  * It is call to update the list of vout handled by the fullscreen controller
955  */
956 void FullscreenControllerWidget::setVoutList( vout_thread_t **pp_vout, int i_vout )
957 {
958     QList<vout_thread_t*> del;
959     QList<vout_thread_t*> add;
960
961     QList<vout_thread_t*> set;
962
963     /* */
964     for( int i = 0; i < i_vout; i++ )
965         set += pp_vout[i];
966
967     /* Vout to remove */
968     vlc_mutex_lock( &lock );
969     foreach( vout_thread_t *p_vout, vout )
970     {
971         if( !set.contains( p_vout ) )
972             del += p_vout;
973     }
974     vlc_mutex_unlock( &lock );
975
976     foreach( vout_thread_t *p_vout, del )
977     {
978         var_DelCallback( p_vout, "fullscreen",
979                          FullscreenControllerWidgetFullscreenChanged, this );
980         vlc_mutex_lock( &lock );
981         fullscreenChanged( p_vout, false, 0 );
982         vout.removeAll( p_vout );
983         vlc_mutex_unlock( &lock );
984     }
985
986     /* Vout to track */
987     vlc_mutex_lock( &lock );
988     foreach( vout_thread_t *p_vout, set )
989     {
990         if( !vout.contains( p_vout ) )
991             add += p_vout;
992     }
993     vlc_mutex_unlock( &lock );
994
995     foreach( vout_thread_t *p_vout, add )
996     {
997         vlc_object_hold( (vlc_object_t*)p_vout );
998
999         vlc_mutex_lock( &lock );
1000         vout.append( p_vout );
1001         var_AddCallback( p_vout, "fullscreen",
1002                          FullscreenControllerWidgetFullscreenChanged, this );
1003         /* I miss a add and fire */
1004         fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1005                            var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1006         vlc_mutex_unlock( &lock );
1007     }
1008 }
1009 /**
1010  * Register and unregister callback for mouse moving
1011  */
1012 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1013         bool b_fs, int i_timeout )
1014 {
1015     /* FIXME - multiple vout (ie multiple mouse position ?) and thread safety if multiple vout ? */
1016     msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1017
1018     vlc_mutex_lock( &lock );
1019     /* Entering fullscreen, register callback */
1020     if( b_fs && !b_fullscreen )
1021     {
1022         b_fullscreen = true;
1023         i_hide_timeout = i_timeout;
1024         var_AddCallback( p_vout, "mouse-moved",
1025                 FullscreenControllerWidgetMouseMoved, this );
1026     }
1027     /* Quitting fullscreen, unregistering callback */
1028     else if( !b_fs && b_fullscreen )
1029     {
1030         b_fullscreen = false;
1031         i_hide_timeout = i_timeout;
1032         var_DelCallback( p_vout, "mouse-moved",
1033                 FullscreenControllerWidgetMouseMoved, this );
1034
1035         /* Force fs hidding */
1036         IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1037         QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1038     }
1039     vlc_mutex_unlock( &lock );
1040 }
1041 /**
1042  * Mouse change callback (show/hide the controller on mouse movement)
1043  */
1044 void FullscreenControllerWidget::mouseChanged( vout_thread_t *p_vout, int i_mousex, int i_mousey )
1045 {
1046     bool b_toShow;
1047
1048     /* FIXME - multiple vout (ie multiple mouse position ?) and thread safety if multiple vout ? */
1049
1050     b_toShow = false;
1051     if( ( i_mouse_last_move_x == -1 || i_mouse_last_move_y == -1 ) ||
1052         ( abs( i_mouse_last_move_x - i_mousex ) > 2 ||
1053           abs( i_mouse_last_move_y - i_mousey ) > 2 ) )
1054     {
1055         i_mouse_last_move_x = i_mousex;
1056         i_mouse_last_move_y = i_mousey;
1057         b_toShow = true;
1058     }
1059
1060     if( b_toShow )
1061     {
1062         /* Show event */
1063         IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1064         QApplication::postEvent( this, static_cast<QEvent *>(eShow) );
1065
1066         /* Plan hide event */
1067         IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1068         QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1069     }
1070 }
1071