]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/controller.cpp
Qt: Move code around and simplify the inclusion of headers.
[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: Clément Stenac <zorglub@videolan.org>
8  *          Jean-Baptiste Kempf <jb@videolan.org>
9  *          Rafaël Carré <funman@videolanorg>
10  *          Ilkka Ollakka <ileoo@videolan.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * ( at your option ) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_vout.h>
32 #include <vlc_keys.h>
33
34 #include "components/controller.hpp"
35 #include "components/controller_widget.hpp"
36 #include "components/interface_widgets.hpp"
37
38 #include "dialogs_provider.hpp"
39 #include "input_manager.hpp"
40
41 #include "util/input_slider.hpp" /* InputSlider */
42 #include "util/customwidgets.hpp" /* qEventToKey */
43
44 #include <QSpacerItem>
45 #include <QToolButton>
46 #include <QHBoxLayout>
47 #include <QSignalMapper>
48 #include <QTimer>
49
50 /**********************************************************************
51  * TEH controls
52  **********************************************************************/
53
54 /******
55  * This is an abstract Toolbar/Controller
56  * This has helper to create any toolbar, any buttons and to manage the actions
57  *
58  *****/
59 AbstractController::AbstractController( intf_thread_t * _p_i, QWidget *_parent )
60                    : QFrame( _parent )
61 {
62     p_intf = _p_i;
63     advControls = NULL;
64
65     /* Main action provider */
66     toolbarActionsMapper = new QSignalMapper( this );
67     CONNECT( toolbarActionsMapper, mapped( int ), this, 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         widget = recordButton;
311         }
312         break;
313     case ATOB_BUTTON: {
314         AtoB_Button *ABButton = new AtoB_Button;
315         setupButton( ABButton );
316         BUTTON_SET_BAR( ABButton );
317         ENABLE_ON_INPUT( ABButton );
318         CONNECT_MAP_SET( ABButton, ATOB_ACTION );
319         CONNECT( THEMIM->getIM(), AtoBchanged( bool, bool),
320                  ABButton, setIcons( bool, bool ) );
321         widget = ABButton;
322         }
323         break;
324     case INPUT_SLIDER: {
325         InputSlider *slider = new InputSlider( Qt::Horizontal, NULL );
326
327         /* Update the position when the IM has changed */
328         CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
329                 slider, setPosition( float, int, int ) );
330         /* And update the IM, when the position has changed */
331         CONNECT( slider, sliderDragged( float ),
332                  THEMIM->getIM(), sliderUpdate( float ) );
333         widget = slider;
334         }
335         break;
336     case MENU_BUTTONS:
337         widget = discFrame();
338         widget->hide();
339         break;
340     case TELETEXT_BUTTONS:
341         widget = telexFrame();
342         widget->hide();
343         break;
344     case VOLUME:
345         {
346             SoundWidget *snd = new SoundWidget( this, p_intf, b_shiny );
347             widget = snd;
348         }
349         break;
350     case TIME_LABEL:
351         {
352             TimeLabel *timeLabel = new TimeLabel( p_intf );
353             widget = timeLabel;
354         }
355         break;
356     case SPLITTER:
357         {
358             QFrame *line = new QFrame;
359             line->setFrameShape( QFrame::VLine );
360             line->setFrameShadow( QFrame::Raised );
361             line->setLineWidth( 0 );
362             line->setMidLineWidth( 1 );
363             widget = line;
364         }
365         break;
366     case ADVANCED_CONTROLLER:
367         {
368             advControls = new AdvControlsWidget( p_intf, this );
369             widget = advControls;
370         }
371         break;
372     case REVERSE_BUTTON:{
373         QToolButton *reverseButton = new QToolButton;
374         setupButton( reverseButton );
375         CONNECT_MAP_SET( reverseButton, REVERSE_ACTION );
376         BUTTON_SET_BAR(  reverseButton );
377         ENABLE_ON_INPUT( reverseButton );
378         widget = reverseButton;
379         }
380         break;
381     case SKIP_BACK_BUTTON: {
382         QToolButton *skipBakButton = new QToolButton;
383         setupButton( skipBakButton );
384         CONNECT_MAP_SET( skipBakButton, SKIP_BACK_ACTION );
385         BUTTON_SET_BAR(  skipBakButton );
386         ENABLE_ON_INPUT( skipBakButton );
387         widget = skipBakButton;
388         }
389         break;
390     case SKIP_FW_BUTTON: {
391         QToolButton *skipFwButton = new QToolButton;
392         setupButton( skipFwButton );
393         CONNECT_MAP_SET( skipFwButton, SKIP_FW_ACTION );
394         BUTTON_SET_BAR(  skipFwButton );
395         ENABLE_ON_INPUT( skipFwButton );
396         widget = skipFwButton;
397         }
398         break;
399     default:
400         msg_Warn( p_intf, "This should not happen %i", button );
401         break;
402     }
403
404     /* Customize Buttons */
405     if( b_flat || b_big )
406     {
407         QToolButton *tmpButton = qobject_cast<QToolButton *>(widget);
408         if( tmpButton )
409         {
410             if( b_flat )
411                 tmpButton->setAutoRaise( b_flat );
412             if( b_big )
413             {
414                 tmpButton->setFixedSize( QSize( 32, 32 ) );
415                 tmpButton->setIconSize( QSize( 26, 26 ) );
416             }
417         }
418     }
419     return widget;
420 }
421
422 QWidget *AbstractController::discFrame()
423 {
424     /** Disc and Menus handling */
425     QWidget *discFrame = new QWidget( this );
426
427     QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
428     discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
429
430     QToolButton *prevSectionButton = new QToolButton( discFrame );
431     setupButton( prevSectionButton );
432     BUTTON_SET_BAR2( prevSectionButton, dvd_prev,
433             qtr("Previous Chapter/Title" ) );
434     discLayout->addWidget( prevSectionButton );
435
436     QToolButton *menuButton = new QToolButton( discFrame );
437     setupButton( menuButton );
438     discLayout->addWidget( menuButton );
439     BUTTON_SET_BAR2( menuButton, dvd_menu, qtr( "Menu" ) );
440
441     QToolButton *nextSectionButton = new QToolButton( discFrame );
442     setupButton( nextSectionButton );
443     discLayout->addWidget( nextSectionButton );
444     BUTTON_SET_BAR2( nextSectionButton, dvd_next,
445             qtr("Next Chapter/Title" ) );
446
447     /* Change the navigation button display when the IM
448        navigation changes */
449     CONNECT( THEMIM->getIM(), titleChanged( bool ),
450             discFrame, setVisible( bool ) );
451     CONNECT( THEMIM->getIM(), chapterChanged( bool ),
452             menuButton, setVisible( bool ) );
453     /* Changes the IM navigation when triggered on the nav buttons */
454     CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
455             sectionPrev() );
456     CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
457             sectionNext() );
458     CONNECT( menuButton, clicked(), THEMIM->getIM(),
459             sectionMenu() );
460
461     return discFrame;
462 }
463
464 QWidget *AbstractController::telexFrame()
465 {
466     /**
467      * Telextext QFrame
468      **/
469     TeletextController *telexFrame = new TeletextController;
470     QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
471     telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
472     CONNECT( THEMIM->getIM(), teletextPossible( bool ),
473              telexFrame, setVisible( bool ) );
474
475     /* On/Off button */
476     QToolButton *telexOn = new QToolButton;
477     telexFrame->telexOn = telexOn;
478     setupButton( telexOn );
479     BUTTON_SET_BAR2( telexOn, tv, qtr( "Teletext Activation" ) );
480     telexLayout->addWidget( telexOn );
481
482     /* Teletext Activation and set */
483     CONNECT( telexOn, clicked( bool ),
484              THEMIM->getIM(), activateTeletext( bool ) );
485     CONNECT( THEMIM->getIM(), teletextActivated( bool ),
486              telexFrame, enableTeletextButtons( bool ) );
487
488
489     /* Transparency button */
490     QToolButton *telexTransparent = new QToolButton;
491     telexFrame->telexTransparent = telexTransparent;
492     setupButton( telexTransparent );
493     BUTTON_SET_BAR2( telexTransparent, tvtelx,
494                      qtr( "Toggle Transparency " ) );
495     telexTransparent->setEnabled( false );
496     telexLayout->addWidget( telexTransparent );
497
498     /* Transparency change and set */
499     CONNECT( telexTransparent, clicked( bool ),
500             THEMIM->getIM(), telexSetTransparency( bool ) );
501     CONNECT( THEMIM->getIM(), teletextTransparencyActivated( bool ),
502             telexFrame, toggleTeletextTransparency( bool ) );
503
504
505     /* Page setting */
506     QSpinBox *telexPage = new QSpinBox;
507     telexFrame->telexPage = telexPage;
508     telexPage->setRange( 0, 999 );
509     telexPage->setValue( 100 );
510     telexPage->setAccelerated( true );
511     telexPage->setWrapping( true );
512     telexPage->setAlignment( Qt::AlignRight );
513     telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
514     telexPage->setEnabled( false );
515     telexLayout->addWidget( telexPage );
516
517     /* Page change and set */
518     CONNECT( telexPage, valueChanged( int ),
519             THEMIM->getIM(), telexSetPage( int ) );
520     CONNECT( THEMIM->getIM(), newTelexPageSet( int ),
521             telexPage, setValue( int ) );
522
523     return telexFrame;
524 }
525 #undef CONNECT_MAP
526 #undef SET_MAPPING
527 #undef CONNECT_MAP_SET
528 #undef BUTTON_SET_BAR
529 #undef ENABLE_ON_VIDEO
530 #undef ENABLE_ON_INPUT
531
532 //* Actions */
533 void AbstractController::doAction( int id_action )
534 {
535     switch( id_action )
536     {
537         case PLAY_ACTION:
538             play(); break;
539         case PREVIOUS_ACTION:
540             prev(); break;
541         case NEXT_ACTION:
542             next(); break;
543         case STOP_ACTION:
544             stop(); break;
545         case SLOWER_ACTION:
546             slower(); break;
547         case FASTER_ACTION:
548             faster(); break;
549         case FULLSCREEN_ACTION:
550             fullscreen(); break;
551         case EXTENDED_ACTION:
552             extSettings(); break;
553         case PLAYLIST_ACTION:
554             playlist(); break;
555         case SNAPSHOT_ACTION:
556             snapshot(); break;
557         case RECORD_ACTION:
558             record(); break;
559         case ATOB_ACTION:
560             THEMIM->getIM()->setAtoB(); break;
561         case FRAME_ACTION:
562             frame(); break;
563         case REVERSE_ACTION:
564             reverse(); break;
565         case SKIP_BACK_ACTION:
566             var_SetInteger( p_intf->p_libvlc, "key-pressed",
567                     ACTIONID_JUMP_BACKWARD_SHORT );
568             break;
569         case SKIP_FW_ACTION:
570             var_SetInteger( p_intf->p_libvlc, "key-pressed",
571                     ACTIONID_JUMP_FORWARD_SHORT );
572             break;
573         default:
574             msg_Dbg( p_intf, "Action: %i", id_action );
575             break;
576     }
577 }
578
579 void AbstractController::stop()
580 {
581     THEMIM->stop();
582 }
583
584 void AbstractController::play()
585 {
586     if( THEPL->current.i_size == 0 )
587     {
588         /* The playlist is empty, open a file requester */
589         THEDP->openFileDialog();
590         return;
591     }
592     THEMIM->togglePlayPause();
593 }
594
595 void AbstractController::prev()
596 {
597     THEMIM->prev();
598 }
599
600 void AbstractController::next()
601 {
602     THEMIM->next();
603 }
604
605 /**
606   * TODO
607  * This functions toggle the fullscreen mode
608  * If there is no video, it should first activate Visualisations...
609  *  This has also to be fixed in enableVideo()
610  */
611 void AbstractController::fullscreen()
612 {
613     vout_thread_t *p_vout =
614       (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
615     if( p_vout)
616     {
617         var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
618         vlc_object_release( p_vout );
619     }
620 }
621
622 void AbstractController::snapshot()
623 {
624     vout_thread_t *p_vout =
625       (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
626     if( p_vout )
627     {
628         vout_Control( p_vout, VOUT_SNAPSHOT );
629         vlc_object_release( p_vout );
630     }
631 }
632
633 void AbstractController::extSettings()
634 {
635     THEDP->extendedDialog();
636 }
637
638 void AbstractController::reverse()
639 {
640     THEMIM->getIM()->reverse();
641 }
642
643 void AbstractController::slower()
644 {
645     THEMIM->getIM()->slower();
646 }
647
648 void AbstractController::faster()
649 {
650     THEMIM->getIM()->faster();
651 }
652
653 void AbstractController::playlist()
654 {
655     if( p_intf->p_sys->p_mi ) p_intf->p_sys->p_mi->togglePlaylist();
656 }
657
658 void AbstractController::record()
659 {
660     input_thread_t *p_input = THEMIM->getInput();
661     if( p_input )
662     {
663         /* This method won't work fine if the stream can't be cut anywhere */
664         const bool b_recording = var_GetBool( p_input, "record" );
665         var_SetBool( p_input, "record", !b_recording );
666 #if 0
667         else
668         {
669             /* 'record' access-filter is not loaded, we open Save dialog */
670             input_item_t *p_item = input_GetItem( p_input );
671             if( !p_item )
672                 return;
673
674             char *psz = input_item_GetURI( p_item );
675             if( psz )
676                 THEDP->streamingDialog( NULL, psz, true );
677         }
678 #endif
679     }
680 }
681
682 void AbstractController::frame()
683 {
684     input_thread_t *p_input = THEMIM->getInput();
685     if( p_input )
686         var_SetVoid( p_input, "frame-next" );
687 }
688
689 #include <QHBoxLayout>
690 /*****************************
691  * DA Control Widget !
692  *****************************/
693 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
694                                 bool b_advControls,
695                                 QWidget *_parent ) :
696                                 AbstractController( _p_i, _parent )
697 {
698     setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
699
700     /* advanced Controls handling */
701     b_advancedVisible = b_advControls;
702
703     QVBoxLayout *controlLayout = new QVBoxLayout( this );
704     controlLayout->setLayoutMargins( 6, 4, 6, 2, 5 );
705     controlLayout->setSpacing( 0 );
706     QHBoxLayout *controlLayout1 = new QHBoxLayout;
707     controlLayout1->setSpacing( 0 );
708
709     QString line1 = getSettings()->value( "MainWindow/MainToolbar1",
710             "64;36;37;38;65").toString();
711     parseAndCreate( line1, controlLayout1 );
712
713    /* QString line2 = QString( "%1-2;%2;%3;%4;%5;%6;%6;%7;%8;%9;%6;%10;%11-4")
714         .arg( PLAY_BUTTON )         .arg( WIDGET_SPACER )
715         .arg( PREVIOUS_BUTTON )         .arg( STOP_BUTTON )
716         .arg( NEXT_BUTTON )        .arg( WIDGET_SPACER )
717         .arg( FULLSCREEN_BUTTON )        .arg( PLAYLIST_BUTTON )
718         .arg( EXTENDED_BUTTON )        .arg( WIDGET_SPACER_EXTEND )
719         .arg( VOLUME );
720     msg_Dbg( p_intf, "%s", qtu( line2 )); */
721
722     QHBoxLayout *controlLayout2 = new QHBoxLayout;
723     controlLayout2->setSpacing( 0 );
724     QString line2 = getSettings()->value( "MainWindow/MainToolbar2",
725             "0-2;64;3;1;4;64;7;10;9;65;34-4" ).toString();
726     parseAndCreate( line2, controlLayout2 );
727
728     if( !b_advancedVisible && advControls ) advControls->hide();
729
730     controlLayout->addLayout( controlLayout1 );
731     controlLayout->addLayout( controlLayout2 );
732 }
733
734 ControlsWidget::~ControlsWidget()
735 {}
736
737 void ControlsWidget::toggleAdvanced()
738 {
739     if( !advControls ) return;
740
741     if( !b_advancedVisible )
742     {
743         advControls->show();
744         b_advancedVisible = true;
745     }
746     else
747     {
748         advControls->hide();
749         b_advancedVisible = false;
750     }
751     emit advancedControlsToggled( b_advancedVisible );
752 }
753
754 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
755                                      AbstractController( _p_i, _parent )
756 {
757     controlLayout = new QHBoxLayout( this );
758     controlLayout->setMargin( 0 );
759     controlLayout->setSpacing( 0 );
760
761     /* QString line = QString( "%1;%2;%3").arg( RECORD_BUTTON )
762         .arg( SNAPSHOT_BUTTON )
763         .arg( ATOB_BUTTON )
764         .arg( FRAME_BUTTON ); */
765
766     QString line = getSettings()->value( "MainWindow/AdvToolbar",
767             "12;11;13;14" ).toString();
768     parseAndCreate( line, controlLayout );
769 }
770
771 InputControlsWidget::InputControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
772                                      AbstractController( _p_i, _parent )
773 {
774     controlLayout = new QHBoxLayout( this );
775     controlLayout->setMargin( 0 );
776     controlLayout->setSpacing( 0 );
777
778     /*    QString line = QString( "%1-%2;%3;%4-%2")
779         .arg( SLOWER_BUTTON ).arg( WIDGET_FLAT )
780         .arg( INPUT_SLIDER )
781         .arg( FASTER_BUTTON ); */
782     QString line = getSettings()->value( "MainWindow/InputToolbar",
783                    "5-1;33;6-1" ).toString();
784     parseAndCreate( line, controlLayout );
785 }
786 /**********************************************************************
787  * Fullscrenn control widget
788  **********************************************************************/
789 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i )
790                            : AbstractController( _p_i )
791 {
792     i_mouse_last_x      = -1;
793     i_mouse_last_y      = -1;
794     b_mouse_over        = false;
795     i_mouse_last_move_x = -1;
796     i_mouse_last_move_y = -1;
797 #if HAVE_TRANSPARENCY
798     b_slow_hide_begin   = false;
799     i_slow_hide_timeout = 1;
800 #endif
801     b_fullscreen        = false;
802     i_hide_timeout      = 1;
803     p_vout              = NULL;
804     i_screennumber      = -1;
805
806     setWindowFlags( Qt::ToolTip );
807     setMinimumWidth( 600 );
808
809     setFrameShape( QFrame::StyledPanel );
810     setFrameStyle( QFrame::Sunken );
811     setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
812
813     controlLayout = new QHBoxLayout( this );
814     controlLayout->setLayoutMargins( 5, 2, 5, 2, 5 );
815
816     /* First line */
817     InputControlsWidget *inputC = new InputControlsWidget( p_intf, this );
818     controlLayout->addWidget( inputC );
819
820     /* Second line */
821 /*     QString line = QString( "%1-2;%2;%3;%4;%5;%2;%6;%2;%7;%2;%8;%9;%10-4")
822         .arg( PLAY_BUTTON )
823         .arg( WIDGET_SPACER )
824         .arg( PREVIOUS_BUTTON )
825         .arg( STOP_BUTTON )
826         .arg( NEXT_BUTTON )
827         .arg( MENU_BUTTONS )
828         .arg( TELETEXT_BUTTONS )
829         .arg( DEFULLSCREEN_BUTTON )
830         .arg( WIDGET_SPACER_EXTEND )
831         .arg( TIME_LABEL )
832         .arg( VOLUME ); */
833
834     QString line = getSettings()->value( "MainWindow/FSCtoolbar",
835             "0-2;64;3;1;4;64;36;64;37;64;8;65;35-4;34" ).toString();
836     parseAndCreate( line, controlLayout );
837
838     /* hiding timer */
839     p_hideTimer = new QTimer( this );
840     CONNECT( p_hideTimer, timeout(), this, hideFSC() );
841     p_hideTimer->setSingleShot( true );
842
843     /* slow hiding timer */
844 #if HAVE_TRANSPARENCY
845     p_slowHideTimer = new QTimer( this );
846     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
847 #endif
848
849     adjustSize ();  /* need to get real width and height for moving */
850
851 #ifdef WIN32TRICK
852     setWindowOpacity( 0.0 );
853     b_fscHidden = true;
854     adjustSize();
855     show();
856 #endif
857
858     vlc_mutex_init_recursive( &lock );
859 }
860
861 FullscreenControllerWidget::~FullscreenControllerWidget()
862 {
863     getSettings()->setValue( "FullScreen/pos", pos() );
864     detachVout();
865     vlc_mutex_destroy( &lock );
866 }
867
868 /**
869  * Show fullscreen controller
870  */
871 void FullscreenControllerWidget::showFSC()
872 {
873     adjustSize();
874     /* center down */
875     int number = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
876     if( number != i_screennumber )
877     {
878         msg_Dbg( p_intf, "Calculation fullscreen controllers center");
879         /* screen has changed, calculate new position */
880         QRect screenRes = QApplication::desktop()->screenGeometry(number);
881         QPoint pos = QPoint( screenRes.x() + (screenRes.width() / 2) - (width() / 2),
882                              screenRes.y() + screenRes.height() - height());
883         move( pos );
884         i_screennumber = number;
885     }
886 #ifdef WIN32TRICK
887     // after quiting and going to fs, we need to call show()
888     if( isHidden() )
889         show();
890     if( b_fscHidden )
891     {
892         b_fscHidden = false;
893         setWindowOpacity( 1.0 );
894     }
895 #else
896     show();
897 #endif
898
899 #if HAVE_TRANSPARENCY
900     setWindowOpacity( DEFAULT_OPACITY );
901 #endif
902 }
903
904 /**
905  * Hide fullscreen controller
906  * FIXME: under windows it have to be done by moving out of screen
907  *        because hide() doesnt work
908  */
909 void FullscreenControllerWidget::hideFSC()
910 {
911 #ifdef WIN32TRICK
912     b_fscHidden = true;
913     setWindowOpacity( 0.0 );    // simulate hidding
914 #else
915     hide();
916 #endif
917 }
918
919 /**
920  * Plane to hide fullscreen controller
921  */
922 void FullscreenControllerWidget::planHideFSC()
923 {
924     vlc_mutex_lock( &lock );
925     int i_timeout = i_hide_timeout;
926     vlc_mutex_unlock( &lock );
927
928     p_hideTimer->start( i_timeout );
929
930 #if HAVE_TRANSPARENCY
931     b_slow_hide_begin = true;
932     i_slow_hide_timeout = i_timeout;
933     p_slowHideTimer->start( i_slow_hide_timeout / 2 );
934 #endif
935 }
936
937 /**
938  * Hidding fullscreen controller slowly
939  * Linux: need composite manager
940  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
941  */
942 void FullscreenControllerWidget::slowHideFSC()
943 {
944 #if HAVE_TRANSPARENCY
945     if( b_slow_hide_begin )
946     {
947         b_slow_hide_begin = false;
948
949         p_slowHideTimer->stop();
950         /* the last part of time divided to 100 pieces */
951         p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
952
953     }
954     else
955     {
956 #ifdef WIN32TRICK
957          if ( windowOpacity() > 0.0 && !b_fscHidden )
958 #else
959          if ( windowOpacity() > 0.0 )
960 #endif
961          {
962              /* we should use 0.01 because of 100 pieces ^^^
963                 but than it cannt be done in time */
964              setWindowOpacity( windowOpacity() - 0.02 );
965          }
966
967          if ( windowOpacity() <= 0.0 )
968              p_slowHideTimer->stop();
969     }
970 #endif
971 }
972
973 /**
974  * event handling
975  * events: show, hide, start timer for hidding
976  */
977 void FullscreenControllerWidget::customEvent( QEvent *event )
978 {
979     bool b_fs;
980
981     switch( event->type() )
982     {
983         case FullscreenControlToggle_Type:
984             vlc_mutex_lock( &lock );
985             b_fs = b_fullscreen;
986             vlc_mutex_unlock( &lock );
987             if( b_fs )
988 #ifdef WIN32TRICK
989                 if( b_fscHidden )
990 #else
991                 if( isHidden() )
992 #endif
993                 {
994                     p_hideTimer->stop();
995                     showFSC();
996                 }
997                 else
998                     hideFSC();
999             break;
1000         case FullscreenControlShow_Type:
1001             vlc_mutex_lock( &lock );
1002             b_fs = b_fullscreen;
1003             vlc_mutex_unlock( &lock );
1004
1005 #ifdef WIN32TRICK
1006             if( b_fs && b_fscHidden )
1007 #else
1008             if( b_fs && !isVisible() )
1009 #endif
1010                 showFSC();
1011             break;
1012         case FullscreenControlHide_Type:
1013             hideFSC();
1014             break;
1015         case FullscreenControlPlanHide_Type:
1016             if( !b_mouse_over ) // Only if the mouse is not over FSC
1017                 planHideFSC();
1018             break;
1019     }
1020 }
1021
1022 /**
1023  * On mouse move
1024  * moving with FSC
1025  */
1026 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1027 {
1028     if ( event->buttons() == Qt::LeftButton )
1029     {
1030         int i_moveX = event->globalX() - i_mouse_last_x;
1031         int i_moveY = event->globalY() - i_mouse_last_y;
1032
1033         move( x() + i_moveX, y() + i_moveY );
1034
1035         i_mouse_last_x = event->globalX();
1036         i_mouse_last_y = event->globalY();
1037     }
1038 }
1039
1040 /**
1041  * On mouse press
1042  * store position of cursor
1043  */
1044 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1045 {
1046     i_mouse_last_x = event->globalX();
1047     i_mouse_last_y = event->globalY();
1048 }
1049
1050 /**
1051  * On mouse go above FSC
1052  */
1053 void FullscreenControllerWidget::enterEvent( QEvent *event )
1054 {
1055     b_mouse_over = true;
1056
1057     p_hideTimer->stop();
1058 #if HAVE_TRANSPARENCY
1059     p_slowHideTimer->stop();
1060 #endif
1061 }
1062
1063 /**
1064  * On mouse go out from FSC
1065  */
1066 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1067 {
1068     planHideFSC();
1069
1070     b_mouse_over = false;
1071 }
1072
1073 /**
1074  * When you get pressed key, send it to video output
1075  * FIXME: clearing focus by clearFocus() to not getting
1076  * key press events didnt work
1077  */
1078 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1079 {
1080     int i_vlck = qtEventToVLCKey( event );
1081     if( i_vlck > 0 )
1082     {
1083         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1084         event->accept();
1085     }
1086     else
1087         event->ignore();
1088 }
1089
1090 /* */
1091 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
1092                 const char *variable, vlc_value_t old_val,
1093                 vlc_value_t new_val,  void *data )
1094 {
1095     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1096     msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
1097     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1098
1099     p_fs->fullscreenChanged( p_vout, new_val.b_bool,
1100             var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1101
1102     return VLC_SUCCESS;
1103 }
1104 /* */
1105 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1106                                                  vlc_value_t old_val, vlc_value_t new_val,
1107                                                  void *data )
1108 {
1109     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1110
1111     int i_mousex, i_mousey;
1112     bool b_toShow = false;
1113
1114     /* Get the value from the Vout - Trust the vout more than Qt */
1115     i_mousex = var_GetInteger( p_fs->p_vout, "mouse-x" );
1116     i_mousey = var_GetInteger( p_fs->p_vout, "mouse-y" );
1117
1118     /* First time */
1119     if( p_fs->i_mouse_last_move_x == -1 || p_fs->i_mouse_last_move_y == -1 )
1120     {
1121         p_fs->i_mouse_last_move_x = i_mousex;
1122         p_fs->i_mouse_last_move_y = i_mousey;
1123         b_toShow = true;
1124     }
1125     /* All other times */
1126     else
1127     {
1128         /* Trigger only if move > 3 px dans une direction */
1129         if( abs( p_fs->i_mouse_last_move_x - i_mousex ) > 2 ||
1130             abs( p_fs->i_mouse_last_move_y - i_mousey ) > 2 )
1131         {
1132             b_toShow = true;
1133             p_fs->i_mouse_last_move_x = i_mousex;
1134             p_fs->i_mouse_last_move_y = i_mousey;
1135         }
1136     }
1137
1138     if( b_toShow )
1139     {
1140         /* Show event */
1141         IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1142         QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1143
1144         /* Plan hide event */
1145         IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1146         QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1147     }
1148
1149     return VLC_SUCCESS;
1150 }
1151
1152 /**
1153  * It is called when video start
1154  */
1155 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1156 {
1157     assert( p_nvout && !p_vout );
1158
1159     p_vout = p_nvout;
1160
1161     msg_Dbg( p_vout, "Qt FS: Attaching Vout" );
1162     vlc_mutex_lock( &lock );
1163
1164     var_AddCallback( p_vout, "fullscreen",
1165             FullscreenControllerWidgetFullscreenChanged, this );
1166             /* I miss a add and fire */
1167     fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1168                        var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1169     vlc_mutex_unlock( &lock );
1170 }
1171
1172 /**
1173  * It is called after turn off video.
1174  */
1175 void FullscreenControllerWidget::detachVout()
1176 {
1177     if( p_vout )
1178     {
1179         msg_Dbg( p_vout, "Qt FS: Detaching Vout" );
1180         var_DelCallback( p_vout, "fullscreen",
1181                 FullscreenControllerWidgetFullscreenChanged, this );
1182         vlc_mutex_lock( &lock );
1183         fullscreenChanged( p_vout, false, 0 );
1184         vlc_mutex_unlock( &lock );
1185         p_vout = NULL;
1186     }
1187 }
1188
1189 /**
1190  * Register and unregister callback for mouse moving
1191  */
1192 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1193         bool b_fs, int i_timeout )
1194 {
1195     msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1196
1197     vlc_mutex_lock( &lock );
1198     /* Entering fullscreen, register callback */
1199     if( b_fs && !b_fullscreen )
1200     {
1201         b_fullscreen = true;
1202         i_hide_timeout = i_timeout;
1203         var_AddCallback( p_vout, "mouse-moved",
1204                 FullscreenControllerWidgetMouseMoved, this );
1205     }
1206     /* Quitting fullscreen, unregistering callback */
1207     else if( !b_fs && b_fullscreen )
1208     {
1209         b_fullscreen = false;
1210         i_hide_timeout = i_timeout;
1211         var_DelCallback( p_vout, "mouse-moved",
1212                 FullscreenControllerWidgetMouseMoved, this );
1213
1214         /* Force fs hidding */
1215         IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1216         QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1217     }
1218     vlc_mutex_unlock( &lock );
1219 }
1220