]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/controller.cpp
3cd0583ed33384ecb64387328936802e2a24f944
[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
33 #include "dialogs_provider.hpp"
34 #include "components/interface_widgets.hpp"
35 #include "main_interface.hpp"
36 #include "input_manager.hpp"
37 #include "menus.hpp"
38 #include "util/input_slider.hpp"
39 #include "util/customwidgets.hpp"
40
41 #include <QLabel>
42 #include <QSpacerItem>
43 #include <QCursor>
44 #include <QToolButton>
45 #include <QHBoxLayout>
46 #include <QMenu>
47 #include <QPalette>
48 #include <QResizeEvent>
49 #include <QDate>
50 #include <QSignalMapper>
51 #include <QTimer>
52
53 /**********************************************************************
54  * TEH controls
55  **********************************************************************/
56
57 /******
58  * This is an abstract Toolbar/Controller
59  * This has helper to create any toolbar, any buttons and to manage the actions
60  *
61  *****/
62 AbstractController::AbstractController( intf_thread_t * _p_i, QWidget *_parent )
63                    : QFrame( _parent )
64 {
65     p_intf = _p_i;
66     advControls = NULL;
67
68     /* Main action provider */
69     toolbarActionsMapper = new QSignalMapper( this );
70     CONNECT( toolbarActionsMapper, mapped( int ), this, doAction( int ) );
71     CONNECT( THEMIM->getIM(), statusChanged( int ), this, setStatus( int ) );
72 }
73
74 /* Reemit some signals on status Change to activate some buttons */
75 void AbstractController::setStatus( int status )
76 {
77     bool b_hasInput = THEMIM->getIM()->hasInput();
78     /* Activate the interface buttons according to the presence of the input */
79     emit inputExists( b_hasInput );
80
81     emit inputPlaying( status == PLAYING_S );
82
83     emit inputIsRecordable( b_hasInput &&
84                             var_GetBool( THEMIM->getInput(), "can-record" ) );
85 }
86
87 /* Generic button setup */
88 void AbstractController::setupButton( QAbstractButton *aButton )
89 {
90     static QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
91     sizePolicy.setHorizontalStretch( 0 );
92     sizePolicy.setVerticalStretch( 0 );
93
94     aButton->setSizePolicy( sizePolicy );
95     aButton->setFixedSize( QSize( 26, 26 ) );
96     aButton->setIconSize( QSize( 20, 20 ) );
97     aButton->setFocusPolicy( Qt::NoFocus );
98 }
99
100 /* Open the generic config line for the toolbar, parse it
101  * and create the widgets accordingly */
102 void AbstractController::parseAndCreate( QString config,
103                                          QBoxLayout *controlLayout )
104 {
105     QStringList list = config.split( ";", QString::SkipEmptyParts ) ;
106     for( int i = 0; i < list.size(); i++ )
107     {
108         QStringList list2 = list.at( i ).split( "-" );
109         if( list2.size() < 1 )
110         {
111             msg_Warn( p_intf, "Parsing error. Report this" );
112             continue;
113         }
114
115         bool ok;
116         int i_option = WIDGET_NORMAL;
117         buttonType_e i_type = (buttonType_e)list2.at( 0 ).toInt( &ok );
118         if( !ok )
119         {
120             msg_Warn( p_intf, "Parsing error 0. Please report this" );
121             continue;
122         }
123
124         if( list2.size() > 1 )
125         {
126             i_option = list2.at( 1 ).toInt( &ok );
127             if( !ok )
128             {
129                 msg_Warn( p_intf, "Parsing error 1. Please report this" );
130                 continue;
131             }
132         }
133
134         createAndAddWidget( controlLayout, -1, i_type, i_option );
135     }
136 }
137
138 void AbstractController::createAndAddWidget( QBoxLayout *controlLayout,
139                                              int i_index,
140                                              buttonType_e i_type,
141                                              int i_option )
142 {
143     /* Special case for SPACERS, who aren't QWidgets */
144     if( i_type == WIDGET_SPACER )
145     {
146         controlLayout->insertSpacing( i_index, 16 );
147         return;
148     }
149
150     if(  i_type == WIDGET_SPACER_EXTEND )
151     {
152         controlLayout->insertSpacing( i_index, 10 );
153         return;
154     }
155
156     QWidget *widg = createWidget( i_type, i_option );
157     if( !widg ) return;
158
159     controlLayout->insertWidget( i_index, widg );
160 }
161
162
163 #define CONNECT_MAP( a ) CONNECT( a, clicked(),  toolbarActionsMapper, map() )
164 #define SET_MAPPING( a, b ) toolbarActionsMapper->setMapping( a , b )
165 #define CONNECT_MAP_SET( a, b ) \
166     CONNECT_MAP( a ); \
167     SET_MAPPING( a, b );
168 #define BUTTON_SET_BAR( a_button ) \
169     a_button->setToolTip( tooltipL[button] );          \
170     a_button->setIcon( QIcon( iconL[button] ) );
171 #define BUTTON_SET_BAR2( button, image, tooltip ) \
172     button->setToolTip( tooltip );          \
173     button->setIcon( QIcon( ":/"#image ) );
174
175
176 #define ENABLE_ON_VIDEO( a ) \
177     CONNECT( THEMIM->getIM(), voutChanged( bool ), a, setEnabled( bool ) ); \
178     a->setEnabled( THEMIM->getIM()->hasVideo() ); /* TODO: is this necessary? when input is started before the interface? */
179
180 #define ENABLE_ON_INPUT( a ) \
181     CONNECT( this, inputExists( bool ), a, setEnabled( bool ) ); \
182     a->setEnabled( THEMIM->getIM()->hasInput() ); /* TODO: is this necessary? when input is started before the interface? */
183
184 QWidget *AbstractController::createWidget( buttonType_e button, int options )
185 {
186
187     bool b_flat = options & WIDGET_FLAT;
188     bool b_big = options & WIDGET_BIG;
189     bool b_shiny = options & WIDGET_SHINY;
190
191     QWidget *widget = NULL;
192     switch( button )
193     {
194     case PLAY_BUTTON: {
195         PlayButton *playButton = new PlayButton;
196         setupButton( playButton );
197         BUTTON_SET_BAR(  playButton );
198         CONNECT_MAP_SET( playButton, PLAY_ACTION );
199         CONNECT( this, inputPlaying( bool ),
200                  playButton, updateButton( bool ));
201         widget = playButton;
202         }
203         break;
204     case STOP_BUTTON:{
205         QToolButton *stopButton = new QToolButton;
206         setupButton( stopButton );
207         CONNECT_MAP_SET( stopButton, STOP_ACTION );
208         BUTTON_SET_BAR(  stopButton );
209         widget = stopButton;
210         }
211         break;
212     case PREVIOUS_BUTTON:{
213         QToolButton *prevButton = new QToolButton;
214         setupButton( prevButton );
215         CONNECT_MAP_SET( prevButton, PREVIOUS_ACTION );
216         BUTTON_SET_BAR( prevButton );
217         widget = prevButton;
218         }
219         break;
220     case NEXT_BUTTON:
221         {
222         QToolButton *nextButton = new QToolButton;
223         setupButton( nextButton );
224         CONNECT_MAP_SET( nextButton, NEXT_ACTION );
225         BUTTON_SET_BAR( nextButton );
226         widget = nextButton;
227         }
228         break;
229     case SLOWER_BUTTON:{
230         QToolButton *slowerButton = new QToolButton;
231         setupButton( slowerButton );
232         CONNECT_MAP_SET( slowerButton, SLOWER_ACTION );
233         BUTTON_SET_BAR(  slowerButton );
234         ENABLE_ON_INPUT( slowerButton );
235         widget = slowerButton;
236         }
237         break;
238     case FASTER_BUTTON:{
239         QToolButton *fasterButton = new QToolButton;
240         setupButton( fasterButton );
241         CONNECT_MAP_SET( fasterButton, FASTER_ACTION );
242         BUTTON_SET_BAR(  fasterButton );
243         ENABLE_ON_INPUT( fasterButton );
244         widget = fasterButton;
245         }
246         break;
247     case FRAME_BUTTON: {
248         QToolButton *frameButton = new QToolButton;
249         setupButton( frameButton );
250         CONNECT_MAP_SET( frameButton, FRAME_ACTION );
251         BUTTON_SET_BAR(  frameButton );
252         ENABLE_ON_VIDEO( frameButton );
253         widget = frameButton;
254         }
255         break;
256     case FULLSCREEN_BUTTON:{
257         QToolButton *fullscreenButton = new QToolButton;
258         setupButton( fullscreenButton );
259         CONNECT_MAP_SET( fullscreenButton, FULLSCREEN_ACTION );
260         BUTTON_SET_BAR( fullscreenButton );
261         ENABLE_ON_VIDEO( fullscreenButton );
262         widget = fullscreenButton;
263         }
264         break;
265     case DEFULLSCREEN_BUTTON:{
266         QToolButton *fullscreenButton = new QToolButton;
267         setupButton( fullscreenButton );
268         CONNECT_MAP_SET( fullscreenButton, FULLSCREEN_ACTION );
269         BUTTON_SET_BAR( fullscreenButton )
270         ENABLE_ON_VIDEO( fullscreenButton );
271         widget = fullscreenButton;
272         }
273         break;
274     case EXTENDED_BUTTON:{
275         QToolButton *extSettingsButton = new QToolButton;
276         setupButton( extSettingsButton );
277         CONNECT_MAP_SET( extSettingsButton, EXTENDED_ACTION );
278         BUTTON_SET_BAR( extSettingsButton )
279         widget = extSettingsButton;
280         }
281         break;
282     case PLAYLIST_BUTTON:{
283         QToolButton *playlistButton = new QToolButton;
284         setupButton( playlistButton );
285         CONNECT_MAP_SET( playlistButton, PLAYLIST_ACTION );
286         BUTTON_SET_BAR( playlistButton );
287         widget = playlistButton;
288         }
289         break;
290     case SNAPSHOT_BUTTON:{
291         QToolButton *snapshotButton = new QToolButton;
292         setupButton( snapshotButton );
293         CONNECT_MAP_SET( snapshotButton, SNAPSHOT_ACTION );
294         BUTTON_SET_BAR(  snapshotButton );
295         ENABLE_ON_VIDEO( snapshotButton );
296         widget = snapshotButton;
297         }
298         break;
299     case RECORD_BUTTON:{
300         QToolButton *recordButton = new QToolButton;
301         setupButton( recordButton );
302         CONNECT_MAP_SET( recordButton, RECORD_ACTION );
303         BUTTON_SET_BAR(  recordButton );
304         ENABLE_ON_INPUT( recordButton );
305         widget = recordButton;
306         }
307         break;
308     case ATOB_BUTTON: {
309         AtoB_Button *ABButton = new AtoB_Button;
310         setupButton( ABButton );
311         BUTTON_SET_BAR( ABButton );
312         ENABLE_ON_INPUT( ABButton );
313         CONNECT_MAP_SET( ABButton, ATOB_ACTION );
314         CONNECT( THEMIM->getIM(), AtoBchanged( bool, bool),
315                  ABButton, setIcons( bool, bool ) );
316         widget = ABButton;
317         }
318         break;
319     case INPUT_SLIDER: {
320         InputSlider *slider = new InputSlider( Qt::Horizontal, NULL );
321
322         /* Update the position when the IM has changed */
323         CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
324                 slider, setPosition( float, int, int ) );
325         /* And update the IM, when the position has changed */
326         CONNECT( slider, sliderDragged( float ),
327                  THEMIM->getIM(), sliderUpdate( float ) );
328         widget = slider;
329         }
330         break;
331     case MENU_BUTTONS:
332         widget = discFrame();
333         widget->hide();
334         break;
335     case TELETEXT_BUTTONS:
336         widget = telexFrame();
337         widget->hide();
338         break;
339     case VOLUME:
340         {
341             SoundWidget *snd = new SoundWidget( this, p_intf, b_shiny );
342             widget = snd;
343         }
344         break;
345     case TIME_LABEL:
346         {
347             TimeLabel *timeLabel = new TimeLabel( p_intf );
348             widget = timeLabel;
349         }
350         break;
351     case SPLITTER:
352         {
353             QFrame *line = new QFrame;
354             line->setFrameShape( QFrame::VLine );
355             line->setFrameShadow( QFrame::Raised );
356             line->setLineWidth( 0 );
357             line->setMidLineWidth( 1 );
358             widget = line;
359         }
360         break;
361     case ADVANCED_CONTROLLER:
362         {
363             advControls = new AdvControlsWidget( p_intf, this );
364             widget = advControls;
365         }
366         break;
367     case REVERSE_BUTTON:{
368         QToolButton *reverseButton = new QToolButton;
369         setupButton( reverseButton );
370         CONNECT_MAP_SET( reverseButton, REVERSE_ACTION );
371         BUTTON_SET_BAR(  reverseButton );
372         ENABLE_ON_INPUT( reverseButton );
373         widget = reverseButton;
374         }
375         break;
376     default:
377         msg_Warn( p_intf, "This should not happen %i", button );
378         break;
379     }
380
381     /* Customize Buttons */
382     if( b_flat || b_big )
383     {
384         QToolButton *tmpButton = qobject_cast<QToolButton *>(widget);
385         if( tmpButton )
386         {
387             if( b_flat )
388                 tmpButton->setAutoRaise( b_flat );
389             if( b_big )
390             {
391                 tmpButton->setFixedSize( QSize( 32, 32 ) );
392                 tmpButton->setIconSize( QSize( 26, 26 ) );
393             }
394         }
395     }
396     return widget;
397 }
398
399 QWidget *AbstractController::discFrame()
400 {
401     /** Disc and Menus handling */
402     QWidget *discFrame = new QWidget( this );
403
404     QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
405     discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
406
407     QToolButton *prevSectionButton = new QToolButton( discFrame );
408     setupButton( prevSectionButton );
409     BUTTON_SET_BAR2( prevSectionButton, dvd_prev,
410             qtr("Previous Chapter/Title" ) );
411     discLayout->addWidget( prevSectionButton );
412
413     QToolButton *menuButton = new QToolButton( discFrame );
414     setupButton( menuButton );
415     discLayout->addWidget( menuButton );
416     BUTTON_SET_BAR2( menuButton, dvd_menu, qtr( "Menu" ) );
417
418     QToolButton *nextSectionButton = new QToolButton( discFrame );
419     setupButton( nextSectionButton );
420     discLayout->addWidget( nextSectionButton );
421     BUTTON_SET_BAR2( nextSectionButton, dvd_next,
422             qtr("Next Chapter/Title" ) );
423
424     /* Change the navigation button display when the IM
425        navigation changes */
426     CONNECT( THEMIM->getIM(), titleChanged( bool ),
427             discFrame, setVisible( bool ) );
428     CONNECT( THEMIM->getIM(), chapterChanged( bool ),
429             menuButton, setVisible( bool ) );
430     /* Changes the IM navigation when triggered on the nav buttons */
431     CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
432             sectionPrev() );
433     CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
434             sectionNext() );
435     CONNECT( menuButton, clicked(), THEMIM->getIM(),
436             sectionMenu() );
437
438     return discFrame;
439 }
440
441 QWidget *AbstractController::telexFrame()
442 {
443     /**
444      * Telextext QFrame
445      **/
446     TeletextController *telexFrame = new TeletextController;
447     QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
448     telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
449     CONNECT( THEMIM->getIM(), teletextPossible( bool ),
450              telexFrame, setVisible( bool ) );
451
452     /* On/Off button */
453     QToolButton *telexOn = new QToolButton;
454     telexFrame->telexOn = telexOn;
455     setupButton( telexOn );
456     BUTTON_SET_BAR2( telexOn, tv, qtr( "Teletext Activation" ) );
457     telexLayout->addWidget( telexOn );
458
459     /* Teletext Activation and set */
460     CONNECT( telexOn, clicked( bool ),
461              THEMIM->getIM(), activateTeletext( bool ) );
462     CONNECT( THEMIM->getIM(), teletextActivated( bool ),
463              telexFrame, enableTeletextButtons( bool ) );
464
465
466     /* Transparency button */
467     QToolButton *telexTransparent = new QToolButton;
468     telexFrame->telexTransparent = telexTransparent;
469     setupButton( telexTransparent );
470     BUTTON_SET_BAR2( telexTransparent, tvtelx,
471                      qtr( "Toggle Transparency " ) );
472     telexTransparent->setEnabled( false );
473     telexLayout->addWidget( telexTransparent );
474
475     /* Transparency change and set */
476     CONNECT( telexTransparent, clicked( bool ),
477             THEMIM->getIM(), telexSetTransparency( bool ) );
478     CONNECT( THEMIM->getIM(), teletextTransparencyActivated( bool ),
479             telexFrame, toggleTeletextTransparency( bool ) );
480
481
482     /* Page setting */
483     QSpinBox *telexPage = new QSpinBox;
484     telexFrame->telexPage = telexPage;
485     telexPage->setRange( 0, 999 );
486     telexPage->setValue( 100 );
487     telexPage->setAccelerated( true );
488     telexPage->setWrapping( true );
489     telexPage->setAlignment( Qt::AlignRight );
490     telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
491     telexPage->setEnabled( false );
492     telexLayout->addWidget( telexPage );
493
494     /* Page change and set */
495     CONNECT( telexPage, valueChanged( int ),
496             THEMIM->getIM(), telexSetPage( int ) );
497     CONNECT( THEMIM->getIM(), newTelexPageSet( int ),
498             telexPage, setValue( int ) );
499
500     return telexFrame;
501 }
502 #undef CONNECT_MAP
503 #undef SET_MAPPING
504 #undef CONNECT_MAP_SET
505 #undef BUTTON_SET_BAR
506 #undef ENABLE_ON_VIDEO
507 #undef ENABLE_ON_INPUT
508
509 SoundWidget::SoundWidget( QWidget *_parent, intf_thread_t * _p_intf,
510                           bool b_shiny )
511                          : b_my_volume( false ), QWidget( _parent )
512 {
513     p_intf = _p_intf;
514     QHBoxLayout *layout = new QHBoxLayout( this );
515     layout->setSpacing( 0 ); layout->setMargin( 0 );
516     hVolLabel = new VolumeClickHandler( p_intf, this );
517
518     volMuteLabel = new QLabel;
519     volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
520     volMuteLabel->installEventFilter( hVolLabel );
521     layout->addWidget( volMuteLabel );
522
523     if( b_shiny )
524     {
525         volumeSlider = new SoundSlider( this,
526             config_GetInt( p_intf, "volume-step" ),
527             config_GetInt( p_intf, "qt-volume-complete" ),
528             config_GetPsz( p_intf, "qt-slider-colours" ) );
529     }
530     else
531     {
532         volumeSlider = new QSlider( this );
533         volumeSlider->setOrientation( Qt::Horizontal );
534     }
535     volumeSlider->setMaximumSize( QSize( 200, 40 ) );
536     volumeSlider->setMinimumSize( QSize( 85, 30 ) );
537     volumeSlider->setFocusPolicy( Qt::NoFocus );
538     layout->addWidget( volumeSlider );
539
540     /* Set the volume from the config */
541     volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
542                               VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
543
544     /* Force the update at build time in order to have a muted icon if needed */
545     updateVolume( volumeSlider->value() );
546
547     /* Volume control connection */
548     CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
549     CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
550 }
551
552 void SoundWidget::updateVolume( int i_sliderVolume )
553 {
554     if( !b_my_volume )
555     {
556         int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
557         aout_VolumeSet( p_intf, i_res );
558     }
559     if( i_sliderVolume == 0 )
560     {
561         volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
562         volMuteLabel->setToolTip( qtr( "Unmute" ) );
563         return;
564     }
565
566     if( i_sliderVolume < VOLUME_MAX / 3 )
567         volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
568     else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
569         volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
570     else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
571     volMuteLabel->setToolTip( qtr( "Mute" ) );
572 }
573
574 void SoundWidget::updateVolume()
575 {
576     /* Audio part */
577     audio_volume_t i_volume;
578     aout_VolumeGet( p_intf, &i_volume );
579     i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
580     int i_gauge = volumeSlider->value();
581     b_my_volume = false;
582     if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
583     {
584         b_my_volume = true;
585         volumeSlider->setValue( i_volume );
586         b_my_volume = false;
587     }
588 }
589
590 void TeletextController::toggleTeletextTransparency( bool b_transparent )
591 {
592     telexTransparent->setIcon( b_transparent ? QIcon( ":/tvtelx" )
593                                              : QIcon( ":/tvtelx-trans" ) );
594 }
595
596 void TeletextController::enableTeletextButtons( bool b_enabled )
597 {
598     telexOn->setChecked( b_enabled );
599     telexTransparent->setEnabled( b_enabled );
600     telexPage->setEnabled( b_enabled );
601 }
602
603 void PlayButton::updateButton( bool b_playing )
604 {
605     setIcon( b_playing ? QIcon( ":/pause_b" ) : QIcon( ":/play_b" ) );
606     setToolTip( b_playing ? qtr( "Pause the playback" )
607                           : qtr( I_PLAY_TOOLTIP ) );
608 }
609
610 void AtoB_Button::setIcons( bool timeA, bool timeB )
611 {
612     if( !timeA && !timeB)
613     {
614         setIcon( QIcon( ":/atob_nob" ) );
615         setToolTip( qtr( "Loop from point A to point B continuously\n"
616                          "Click to set point A" ) );
617     }
618     else if( timeA && !timeB )
619     {
620         setIcon( QIcon( ":/atob_noa" ) );
621         setToolTip( qtr( "Click to set point B" ) );
622     }
623     else if( timeA && timeB )
624     {
625         setIcon( QIcon( ":/atob" ) );
626         setToolTip( qtr( "Stop the A to B loop" ) );
627     }
628 }
629
630
631 //* Actions */
632 void AbstractController::doAction( int id_action )
633 {
634     switch( id_action )
635     {
636         case PLAY_ACTION:
637             play(); break;
638         case PREVIOUS_ACTION:
639             prev(); break;
640         case NEXT_ACTION:
641             next(); break;
642         case STOP_ACTION:
643             stop(); break;
644         case SLOWER_ACTION:
645             slower(); break;
646         case FASTER_ACTION:
647             faster(); break;
648         case FULLSCREEN_ACTION:
649             fullscreen(); break;
650         case EXTENDED_ACTION:
651             extSettings(); break;
652         case PLAYLIST_ACTION:
653             playlist(); break;
654         case SNAPSHOT_ACTION:
655             snapshot(); break;
656         case RECORD_ACTION:
657             record(); break;
658         case ATOB_ACTION:
659             THEMIM->getIM()->setAtoB(); break;
660         case FRAME_ACTION:
661             frame(); break;
662         case REVERSE_ACTION:
663             reverse(); break;
664         default:
665             msg_Dbg( p_intf, "Action: %i", id_action );
666             break;
667     }
668 }
669
670 void AbstractController::stop()
671 {
672     THEMIM->stop();
673 }
674
675 void AbstractController::play()
676 {
677     if( THEPL->current.i_size == 0 )
678     {
679         /* The playlist is empty, open a file requester */
680         THEDP->openFileDialog();
681         return;
682     }
683     THEMIM->togglePlayPause();
684 }
685
686 void AbstractController::prev()
687 {
688     THEMIM->prev();
689 }
690
691 void AbstractController::next()
692 {
693     THEMIM->next();
694 }
695
696 /**
697   * TODO
698  * This functions toggle the fullscreen mode
699  * If there is no video, it should first activate Visualisations...
700  *  This has also to be fixed in enableVideo()
701  */
702 void AbstractController::fullscreen()
703 {
704     vout_thread_t *p_vout =
705       (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
706     if( p_vout)
707     {
708         var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
709         vlc_object_release( p_vout );
710     }
711 }
712
713 void AbstractController::snapshot()
714 {
715     vout_thread_t *p_vout =
716       (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
717     if( p_vout )
718     {
719         vout_Control( p_vout, VOUT_SNAPSHOT );
720         vlc_object_release( p_vout );
721     }
722 }
723
724 void AbstractController::extSettings()
725 {
726     THEDP->extendedDialog();
727 }
728
729 void AbstractController::reverse()
730 {
731     THEMIM->getIM()->reverse();
732 }
733
734 void AbstractController::slower()
735 {
736     THEMIM->getIM()->slower();
737 }
738
739 void AbstractController::faster()
740 {
741     THEMIM->getIM()->faster();
742 }
743
744 void AbstractController::playlist()
745 {
746     if( p_intf->p_sys->p_mi ) p_intf->p_sys->p_mi->togglePlaylist();
747 }
748
749 void AbstractController::record()
750 {
751     input_thread_t *p_input = THEMIM->getInput();
752     if( p_input )
753     {
754         /* This method won't work fine if the stream can't be cut anywhere */
755         const bool b_recording = var_GetBool( p_input, "record" );
756         var_SetBool( p_input, "record", !b_recording );
757 #if 0
758         else
759         {
760             /* 'record' access-filter is not loaded, we open Save dialog */
761             input_item_t *p_item = input_GetItem( p_input );
762             if( !p_item )
763                 return;
764
765             char *psz = input_item_GetURI( p_item );
766             if( psz )
767                 THEDP->streamingDialog( NULL, psz, true );
768         }
769 #endif
770     }
771 }
772
773 void AbstractController::frame()
774 {
775     input_thread_t *p_input = THEMIM->getInput();
776     if( p_input )
777         var_SetVoid( p_input, "frame-next" );
778 }
779 #include <QHBoxLayout>
780 /*****************************
781  * DA Control Widget !
782  *****************************/
783 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
784                                 bool b_advControls,
785                                 QWidget *_parent ) :
786                                 AbstractController( _p_i, _parent )
787 {
788     setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
789
790     /* advanced Controls handling */
791     b_advancedVisible = b_advControls;
792
793     QVBoxLayout *controlLayout = new QVBoxLayout( this );
794     controlLayout->setLayoutMargins( 6, 4, 6, 2, 5 );
795     controlLayout->setSpacing( 0 );
796     QHBoxLayout *controlLayout1 = new QHBoxLayout;
797     controlLayout1->setSpacing( 0 );
798
799     QString line1 = getSettings()->value( "MainWindow/Controls1",
800             "64;36;37;38;65").toString();
801     parseAndCreate( line1, controlLayout1 );
802
803    /* QString line2 = QString( "%1-2;%2;%3;%4;%5;%6;%6;%7;%8;%9;%6;%10;%11-4")
804         .arg( PLAY_BUTTON )         .arg( WIDGET_SPACER )
805         .arg( PREVIOUS_BUTTON )         .arg( STOP_BUTTON )
806         .arg( NEXT_BUTTON )        .arg( WIDGET_SPACER )
807         .arg( FULLSCREEN_BUTTON )        .arg( PLAYLIST_BUTTON )
808         .arg( EXTENDED_BUTTON )        .arg( WIDGET_SPACER_EXTEND )
809         .arg( VOLUME );
810     msg_Dbg( p_intf, "%s", qtu( line2 )); */
811
812     QHBoxLayout *controlLayout2 = new QHBoxLayout;
813     controlLayout2->setSpacing( 0 );
814     QString line2 = getSettings()->value( "MainWindow/Controls2",
815             "0-2;64;3;1;4;64;7;10;9;65;34-4" ).toString();
816     parseAndCreate( line2, controlLayout2 );
817
818     if( !b_advancedVisible && advControls ) advControls->hide();
819
820     controlLayout->addLayout( controlLayout1 );
821     controlLayout->addLayout( controlLayout2 );
822 }
823
824 ControlsWidget::~ControlsWidget()
825 {}
826
827 void ControlsWidget::toggleAdvanced()
828 {
829     if( !advControls ) return;
830
831     if( !b_advancedVisible )
832     {
833         advControls->show();
834         b_advancedVisible = true;
835     }
836     else
837     {
838         advControls->hide();
839         b_advancedVisible = false;
840     }
841     emit advancedControlsToggled( b_advancedVisible );
842 }
843
844 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
845                                      AbstractController( _p_i, _parent )
846 {
847     controlLayout = new QHBoxLayout( this );
848     controlLayout->setMargin( 0 );
849     controlLayout->setSpacing( 0 );
850
851     /* QString line = QString( "%1;%2;%3").arg( RECORD_BUTTON )
852         .arg( SNAPSHOT_BUTTON )
853         .arg( ATOB_BUTTON )
854         .arg( FRAME_BUTTON ); */
855
856     QString line = getSettings()->value( "MainWindow/AdvControl",
857             "12;11;13;14" ).toString();
858     parseAndCreate( line, controlLayout );
859 }
860
861 InputControlsWidget::InputControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
862                                      AbstractController( _p_i, _parent )
863 {
864     controlLayout = new QHBoxLayout( this );
865     controlLayout->setMargin( 0 );
866     controlLayout->setSpacing( 0 );
867
868     /*    QString line = QString( "%1-%2;%3;%4-%2")
869         .arg( SLOWER_BUTTON ).arg( WIDGET_FLAT )
870         .arg( INPUT_SLIDER )
871         .arg( FASTER_BUTTON ); */
872     QString line = getSettings()->value( "MainWindow/InputControl",
873                    "5-1;33;6-1" ).toString();
874     parseAndCreate( line, controlLayout );
875 }
876 /**********************************************************************
877  * Fullscrenn control widget
878  **********************************************************************/
879 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i )
880                            : AbstractController( _p_i )
881 {
882     i_mouse_last_x      = -1;
883     i_mouse_last_y      = -1;
884     b_mouse_over        = false;
885     i_mouse_last_move_x = -1;
886     i_mouse_last_move_y = -1;
887 #if HAVE_TRANSPARENCY
888     b_slow_hide_begin   = false;
889     i_slow_hide_timeout = 1;
890 #endif
891     b_fullscreen        = false;
892     i_hide_timeout      = 1;
893     p_vout              = NULL;
894     i_screennumber      = -1;
895
896     setWindowFlags( Qt::ToolTip );
897     setMinimumWidth( 600 );
898
899     setFrameShape( QFrame::StyledPanel );
900     setFrameStyle( QFrame::Sunken );
901     setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
902
903     controlLayout = new QHBoxLayout( this );
904     controlLayout->setLayoutMargins( 5, 2, 5, 2, 5 );
905
906     /* First line */
907     InputControlsWidget *inputC = new InputControlsWidget( p_intf, this );
908     controlLayout->addWidget( inputC );
909
910     /* Second line */
911 /*     QString line = QString( "%1-2;%2;%3;%4;%5;%2;%6;%2;%7;%2;%8;%9;%10-4")
912         .arg( PLAY_BUTTON )
913         .arg( WIDGET_SPACER )
914         .arg( PREVIOUS_BUTTON )
915         .arg( STOP_BUTTON )
916         .arg( NEXT_BUTTON )
917         .arg( MENU_BUTTONS )
918         .arg( TELETEXT_BUTTONS )
919         .arg( DEFULLSCREEN_BUTTON )
920         .arg( WIDGET_SPACER_EXTEND )
921         .arg( TIME_LABEL )
922         .arg( VOLUME ); */
923
924     QString line = getSettings()->value( "MainWindow/FSCline",
925             "0-2;64;3;1;4;64;36;64;37;64;8;65;35-4;34" ).toString();
926     parseAndCreate( line, controlLayout );
927
928     /* hiding timer */
929     p_hideTimer = new QTimer( this );
930     CONNECT( p_hideTimer, timeout(), this, hideFSC() );
931     p_hideTimer->setSingleShot( true );
932
933     /* slow hiding timer */
934 #if HAVE_TRANSPARENCY
935     p_slowHideTimer = new QTimer( this );
936     CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
937 #endif
938
939     adjustSize ();  /* need to get real width and height for moving */
940
941 #ifdef WIN32TRICK
942     setWindowOpacity( 0.0 );
943     b_fscHidden = true;
944     adjustSize();
945     show();
946 #endif
947
948     vlc_mutex_init_recursive( &lock );
949 }
950
951 FullscreenControllerWidget::~FullscreenControllerWidget()
952 {
953     getSettings()->setValue( "FullScreen/pos", pos() );
954     detachVout();
955     vlc_mutex_destroy( &lock );
956 }
957
958 /**
959  * Show fullscreen controller
960  */
961 void FullscreenControllerWidget::showFSC()
962 {
963     adjustSize();
964     /* center down */
965     int number = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
966     if( number != i_screennumber )
967     {
968         msg_Dbg( p_intf, "Calculation fullscreen controllers center");
969         /* screen has changed, calculate new position */
970         QRect screenRes = QApplication::desktop()->screenGeometry(number);
971         QPoint pos = QPoint( screenRes.x() + (screenRes.width() / 2) - (width() / 2),
972                              screenRes.y() + screenRes.height() - height());
973         move( pos );
974         i_screennumber = number;
975     }
976 #ifdef WIN32TRICK
977     // after quiting and going to fs, we need to call show()
978     if( isHidden() )
979         show();
980     if( b_fscHidden )
981     {
982         b_fscHidden = false;
983         setWindowOpacity( 1.0 );
984     }
985 #else
986     show();
987 #endif
988
989 #if HAVE_TRANSPARENCY
990     setWindowOpacity( DEFAULT_OPACITY );
991 #endif
992 }
993
994 /**
995  * Hide fullscreen controller
996  * FIXME: under windows it have to be done by moving out of screen
997  *        because hide() doesnt work
998  */
999 void FullscreenControllerWidget::hideFSC()
1000 {
1001 #ifdef WIN32TRICK
1002     b_fscHidden = true;
1003     setWindowOpacity( 0.0 );    // simulate hidding
1004 #else
1005     hide();
1006 #endif
1007 }
1008
1009 /**
1010  * Plane to hide fullscreen controller
1011  */
1012 void FullscreenControllerWidget::planHideFSC()
1013 {
1014     vlc_mutex_lock( &lock );
1015     int i_timeout = i_hide_timeout;
1016     vlc_mutex_unlock( &lock );
1017
1018     p_hideTimer->start( i_timeout );
1019
1020 #if HAVE_TRANSPARENCY
1021     b_slow_hide_begin = true;
1022     i_slow_hide_timeout = i_timeout;
1023     p_slowHideTimer->start( i_slow_hide_timeout / 2 );
1024 #endif
1025 }
1026
1027 /**
1028  * Hidding fullscreen controller slowly
1029  * Linux: need composite manager
1030  * Windows: it is blinking, so it can be enabled by define TRASPARENCY
1031  */
1032 void FullscreenControllerWidget::slowHideFSC()
1033 {
1034 #if HAVE_TRANSPARENCY
1035     if( b_slow_hide_begin )
1036     {
1037         b_slow_hide_begin = false;
1038
1039         p_slowHideTimer->stop();
1040         /* the last part of time divided to 100 pieces */
1041         p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
1042
1043     }
1044     else
1045     {
1046 #ifdef WIN32TRICK
1047          if ( windowOpacity() > 0.0 && !b_fscHidden )
1048 #else
1049          if ( windowOpacity() > 0.0 )
1050 #endif
1051          {
1052              /* we should use 0.01 because of 100 pieces ^^^
1053                 but than it cannt be done in time */
1054              setWindowOpacity( windowOpacity() - 0.02 );
1055          }
1056
1057          if ( windowOpacity() <= 0.0 )
1058              p_slowHideTimer->stop();
1059     }
1060 #endif
1061 }
1062
1063 /**
1064  * event handling
1065  * events: show, hide, start timer for hidding
1066  */
1067 void FullscreenControllerWidget::customEvent( QEvent *event )
1068 {
1069     bool b_fs;
1070
1071     switch( event->type() )
1072     {
1073         case FullscreenControlToggle_Type:
1074             vlc_mutex_lock( &lock );
1075             b_fs = b_fullscreen;
1076             vlc_mutex_unlock( &lock );
1077             if( b_fs )
1078 #ifdef WIN32TRICK
1079                 if( b_fscHidden )
1080 #else
1081                 if( isHidden() )
1082 #endif
1083                 {
1084                     p_hideTimer->stop();
1085                     showFSC();
1086                 }
1087                 else
1088                     hideFSC();
1089             break;
1090         case FullscreenControlShow_Type:
1091             vlc_mutex_lock( &lock );
1092             b_fs = b_fullscreen;
1093             vlc_mutex_unlock( &lock );
1094
1095 #ifdef WIN32TRICK
1096             if( b_fs && b_fscHidden )
1097 #else
1098             if( b_fs && !isVisible() )
1099 #endif
1100                 showFSC();
1101             break;
1102         case FullscreenControlHide_Type:
1103             hideFSC();
1104             break;
1105         case FullscreenControlPlanHide_Type:
1106             if( !b_mouse_over ) // Only if the mouse is not over FSC
1107                 planHideFSC();
1108             break;
1109     }
1110 }
1111
1112 /**
1113  * On mouse move
1114  * moving with FSC
1115  */
1116 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1117 {
1118     if ( event->buttons() == Qt::LeftButton )
1119     {
1120         int i_moveX = event->globalX() - i_mouse_last_x;
1121         int i_moveY = event->globalY() - i_mouse_last_y;
1122
1123         move( x() + i_moveX, y() + i_moveY );
1124
1125         i_mouse_last_x = event->globalX();
1126         i_mouse_last_y = event->globalY();
1127     }
1128 }
1129
1130 /**
1131  * On mouse press
1132  * store position of cursor
1133  */
1134 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1135 {
1136     i_mouse_last_x = event->globalX();
1137     i_mouse_last_y = event->globalY();
1138 }
1139
1140 /**
1141  * On mouse go above FSC
1142  */
1143 void FullscreenControllerWidget::enterEvent( QEvent *event )
1144 {
1145     b_mouse_over = true;
1146
1147     p_hideTimer->stop();
1148 #if HAVE_TRANSPARENCY
1149     p_slowHideTimer->stop();
1150 #endif
1151 }
1152
1153 /**
1154  * On mouse go out from FSC
1155  */
1156 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1157 {
1158     planHideFSC();
1159
1160     b_mouse_over = false;
1161 }
1162
1163 /**
1164  * When you get pressed key, send it to video output
1165  * FIXME: clearing focus by clearFocus() to not getting
1166  * key press events didnt work
1167  */
1168 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1169 {
1170     int i_vlck = qtEventToVLCKey( event );
1171     if( i_vlck > 0 )
1172     {
1173         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1174         event->accept();
1175     }
1176     else
1177         event->ignore();
1178 }
1179
1180 /* */
1181 static int FullscreenControllerWidgetFullscreenChanged( vlc_object_t *vlc_object,
1182                 const char *variable, vlc_value_t old_val,
1183                 vlc_value_t new_val,  void *data )
1184 {
1185     vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
1186     msg_Dbg( p_vout, "Qt4: Fullscreen state changed" );
1187     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1188
1189     p_fs->fullscreenChanged( p_vout, new_val.b_bool,
1190             var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1191
1192     return VLC_SUCCESS;
1193 }
1194 /* */
1195 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *vlc_object, const char *variable,
1196                                                  vlc_value_t old_val, vlc_value_t new_val,
1197                                                  void *data )
1198 {
1199     FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1200
1201     int i_mousex, i_mousey;
1202     bool b_toShow = false;
1203
1204     /* Get the value from the Vout - Trust the vout more than Qt */
1205     i_mousex = var_GetInteger( p_fs->p_vout, "mouse-x" );
1206     i_mousey = var_GetInteger( p_fs->p_vout, "mouse-y" );
1207
1208     /* First time */
1209     if( p_fs->i_mouse_last_move_x == -1 || p_fs->i_mouse_last_move_y == -1 )
1210     {
1211         p_fs->i_mouse_last_move_x = i_mousex;
1212         p_fs->i_mouse_last_move_y = i_mousey;
1213         b_toShow = true;
1214     }
1215     /* All other times */
1216     else
1217     {
1218         /* Trigger only if move > 3 px dans une direction */
1219         if( abs( p_fs->i_mouse_last_move_x - i_mousex ) > 2 ||
1220             abs( p_fs->i_mouse_last_move_y - i_mousey ) > 2 )
1221         {
1222             b_toShow = true;
1223             p_fs->i_mouse_last_move_x = i_mousex;
1224             p_fs->i_mouse_last_move_y = i_mousey;
1225         }
1226     }
1227
1228     if( b_toShow )
1229     {
1230         /* Show event */
1231         IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 );
1232         QApplication::postEvent( p_fs, static_cast<QEvent *>(eShow) );
1233
1234         /* Plan hide event */
1235         IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 );
1236         QApplication::postEvent( p_fs, static_cast<QEvent *>(eHide) );
1237     }
1238
1239     return VLC_SUCCESS;
1240 }
1241
1242 /**
1243  * It is called when video start
1244  */
1245 void FullscreenControllerWidget::attachVout( vout_thread_t *p_nvout )
1246 {
1247     assert( p_nvout && !p_vout );
1248
1249     p_vout = p_nvout;
1250
1251     msg_Dbg( p_vout, "Qt FS: Attaching Vout" );
1252     vlc_mutex_lock( &lock );
1253
1254     var_AddCallback( p_vout, "fullscreen",
1255             FullscreenControllerWidgetFullscreenChanged, this );
1256             /* I miss a add and fire */
1257     fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ),
1258                        var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1259     vlc_mutex_unlock( &lock );
1260 }
1261
1262 /**
1263  * It is called after turn off video.
1264  */
1265 void FullscreenControllerWidget::detachVout()
1266 {
1267     if( p_vout )
1268     {
1269         msg_Dbg( p_vout, "Qt FS: Detaching Vout" );
1270         var_DelCallback( p_vout, "fullscreen",
1271                 FullscreenControllerWidgetFullscreenChanged, this );
1272         vlc_mutex_lock( &lock );
1273         fullscreenChanged( p_vout, false, 0 );
1274         vlc_mutex_unlock( &lock );
1275         p_vout = NULL;
1276     }
1277 }
1278
1279 /**
1280  * Register and unregister callback for mouse moving
1281  */
1282 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1283         bool b_fs, int i_timeout )
1284 {
1285     msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1286
1287     vlc_mutex_lock( &lock );
1288     /* Entering fullscreen, register callback */
1289     if( b_fs && !b_fullscreen )
1290     {
1291         b_fullscreen = true;
1292         i_hide_timeout = i_timeout;
1293         var_AddCallback( p_vout, "mouse-moved",
1294                 FullscreenControllerWidgetMouseMoved, this );
1295     }
1296     /* Quitting fullscreen, unregistering callback */
1297     else if( !b_fs && b_fullscreen )
1298     {
1299         b_fullscreen = false;
1300         i_hide_timeout = i_timeout;
1301         var_DelCallback( p_vout, "mouse-moved",
1302                 FullscreenControllerWidgetMouseMoved, this );
1303
1304         /* Force fs hidding */
1305         IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 );
1306         QApplication::postEvent( this, static_cast<QEvent *>(eHide) );
1307     }
1308     vlc_mutex_unlock( &lock );
1309 }