]> git.sesse.net Git - vlc/blobdiff - modules/gui/qt4/components/interface_widgets.cpp
Fixes for fullscreen controller
[vlc] / modules / gui / qt4 / components / interface_widgets.cpp
index ee0838b4f5d28bd9f71060d2759cb43735ef12f0..4413a6e3f560452aef40cd2b74e0852555acda2a 100644 (file)
@@ -58,13 +58,23 @@ static int DoControl( intf_thread_t *, void *, int, va_list );
 
 VideoWidget::VideoWidget( intf_thread_t *_p_i ) : QFrame( NULL ), p_intf( _p_i )
 {
-    vlc_mutex_init( p_intf, &lock );
+    /* Init */
+    vlc_mutex_init( &lock );
     p_vout = NULL;
     hide(); setMinimumSize( 16, 16 );
+    videoSize.rwidth() = -1;
+    videoSize.rheight() = -1;
 
-   // CONNECT( this, askResize( int, int ), this, SetSizing( int, int ) );
+    /* Black background is more coherent for a Video Widget IMVHO */
+    QPalette plt =  palette();
+    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
+    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
+    setPalette( plt );
+
+    /* The core can ask through a callback to show the video */
     CONNECT( this, askVideoWidgetToShow(), this, show() );
-    setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
+    /* The core can ask through a callback to resize the video */
+   // CONNECT( this, askResize( int, int ), this, SetSizing( int, int ) );
 }
 
 VideoWidget::~VideoWidget()
@@ -88,11 +98,12 @@ VideoWidget::~VideoWidget()
 }
 
 /**
- * Request the video to avoid the conflicts 
+ * Request the video to avoid the conflicts
  **/
 void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
                            unsigned int *pi_width, unsigned int *pi_height )
 {
+    msg_Dbg( p_intf, "Video was requested %i, %i", *pi_x, *pi_y );
     emit askVideoWidgetToShow();
     if( p_vout )
     {
@@ -104,19 +115,30 @@ void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
 }
 
 /* Set the Widget to the correct Size */
+/* Function has to be called by the parent
+   Parent has to care about resizing himself*/
 void VideoWidget::SetSizing( unsigned int w, unsigned int h )
 {
-    resize( w, h );
-    //updateGeometry(); // Needed for deinterlace
-    msg_Dbg( p_intf, "%i %i", sizeHint().height(), sizeHint().width() );
-    //emit askResize();
+    msg_Dbg( p_intf, "Video is resizing to: %i %i", w, h );
+    videoSize.rwidth() = w;
+    videoSize.rheight() = h;
+    updateGeometry(); // Needed for deinterlace
 }
 
 void VideoWidget::release( void *p_win )
 {
+    msg_Dbg( p_intf, "Video is non needed anymore" );
     p_vout = NULL;
+    videoSize.rwidth() = 0;
+    videoSize.rheight() = 0;
+    hide();
+    updateGeometry(); // Needed for deinterlace
 }
 
+QSize VideoWidget::sizeHint() const
+{
+    return videoSize;
+}
 
 /**********************************************************************
  * Background Widget. Show a simple image background. Currently,
@@ -126,11 +148,11 @@ void VideoWidget::release( void *p_win )
 #define MAX_BG_SIZE 400
 #define MIN_BG_SIZE 64
 
-BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i ) :
-                                        QWidget( NULL ), p_intf( _p_i )
+BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
+                 :QWidget( NULL ), p_intf( _p_i )
 {
     /* We should use that one to take the more size it can */
-    setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
+//    setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
 
     /* A dark background */
     setAutoFillBackground( true );
@@ -156,17 +178,24 @@ BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i ) :
     backgroundLayout->setColumnStretch( 0, 1 );
     backgroundLayout->setColumnStretch( 2, 1 );
 
-    CONNECT( THEMIM->getIM(), artChanged( QString ), this, update( QString ) );
-    resize( 300, 150 );
+    CONNECT( THEMIM->getIM(), artChanged( QString ), this, updateArt( QString ) );
 }
 
 BackgroundWidget::~BackgroundWidget()
 {
 }
 
-void BackgroundWidget::update( QString url )
+void BackgroundWidget::resizeEvent( QResizeEvent * event )
+{
+    if( event->size().height() <= MIN_BG_SIZE )
+        label->hide();
+    else
+        label->show();
+}
+
+void BackgroundWidget::updateArt( QString url )
 {
-    if( url.isNull() )
+    if( url.isEmpty() )
     {
         if( QDate::currentDate().dayOfYear() >= 354 )
             label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) );
@@ -177,7 +206,6 @@ void BackgroundWidget::update( QString url )
     else
     {
         label->setPixmap( QPixmap( url ) );
-        msg_Dbg( p_intf, "changing input b_need_update done ");
     }
 }
 
@@ -252,11 +280,11 @@ AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
     QHBoxLayout *advLayout = new QHBoxLayout( this );
     advLayout->setMargin( 0 );
     advLayout->setSpacing( 0 );
+    advLayout->setAlignment( Qt::AlignBottom );
 
     /* A to B Button */
     ABButton = new QPushButton( "AB" );
-    ABButton->setMaximumSize( QSize( 26, 26 ) );
-    ABButton->setIconSize( QSize( 20, 20 ) );
+    setupSmallButton( ABButton );
     advLayout->addWidget( ABButton );
     BUTTON_SET_ACT( ABButton, "AB", qtr( "A to B" ), fromAtoB() );
     timeA = timeB = 0;
@@ -271,16 +299,14 @@ AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
 #endif
 
     recordButton = new QPushButton( "R" );
-    recordButton->setMaximumSize( QSize( 26, 26 ) );
-    recordButton->setIconSize( QSize( 20, 20 ) );
+    setupSmallButton( recordButton );
     advLayout->addWidget( recordButton );
     BUTTON_SET_ACT_I( recordButton, "", record_16px.png,
             qtr( "Record" ), record() );
 
     /* Snapshot Button */
     snapshotButton = new QPushButton( "S" );
-    snapshotButton->setMaximumSize( QSize( 26, 26 ) );
-    snapshotButton->setIconSize( QSize( 20, 20 ) );
+    setupSmallButton( snapshotButton );
     advLayout->addWidget( snapshotButton );
     BUTTON_SET_ACT( snapshotButton, "S", qtr( "Take a snapshot" ), snapshot() );
 }
@@ -354,10 +380,12 @@ void AdvControlsWidget::frame(){}
 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
                                 MainInterface *_p_mi,
                                 bool b_advControls,
-                                bool b_shiny ) :
-                                QFrame( NULL ), p_intf( _p_i )
+                                bool b_shiny,
+                                bool b_fsCreation) :
+                                QFrame( _p_mi ), p_intf( _p_i )
 {
-    controlLayout = new QGridLayout( this );
+    controlLayout = new QGridLayout( );
+
     controlLayout->setSpacing( 0 );
 #if QT43
     controlLayout->setContentsMargins( 9, 6, 9, 6 );
@@ -365,6 +393,9 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     controlLayout->setMargin( 6 );
 #endif
 
+    if( !b_fsCreation )
+        setLayout( controlLayout );
+
     setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
 
     /** The main Slider **/
@@ -459,7 +490,10 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     QSpinBox *telexPage = new QSpinBox;
     telexPage->setRange( 0, 999 );
     telexPage->setValue( 100 );
+    telexPage->setAccelerated( true );
+    telexPage->setWrapping( true );
     telexPage->setAlignment( Qt::AlignRight );
+    telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
     telexLayout->addWidget( telexPage );
 
     controlLayout->addWidget( telexFrame, 1, 10, 2, 3, Qt::AlignBottom );
@@ -493,7 +527,7 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     controlLayout->setColumnStretch( 2, 0 );
 
     /** Prev + Stop + Next Block **/
-    QHBoxLayout *controlButLayout = new QHBoxLayout;
+    controlButLayout = new QHBoxLayout;
     controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */
 
     /* Prev */
@@ -518,7 +552,8 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     controlButLayout->addWidget( nextButton );
 
     /* Add this block to the main layout */
-    controlLayout->addLayout( controlButLayout, 3, 3, 1, 3 );
+    if( !b_fsCreation )
+        controlLayout->addLayout( controlButLayout, 3, 3, 1, 3 );
 
     BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() );
     BUTTON_SET_ACT_I( prevButton, "" , previous.png,
@@ -548,7 +583,7 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
 
     /** extended Settings **/
-    QPushButton *extSettingsButton = new QPushButton( "F" );
+    extSettingsButton = new QPushButton;
     BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended Settings" ),
             extSettings() );
     setupSmallButton( extSettingsButton );
@@ -559,7 +594,7 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     controlLayout->setColumnStretch( 14, 5 );
 
     /* Volume */
-    VolumeClickHandler *hVolLabel = new VolumeClickHandler( p_intf, this );
+    hVolLabel = new VolumeClickHandler( p_intf, this );
 
     volMuteLabel = new QLabel;
     volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) );
@@ -571,7 +606,8 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     {
         volumeSlider = new SoundSlider( this,
             config_GetInt( p_intf, "volume-step" ),
-            config_GetInt( p_intf, "qt-volume-complete" ) );
+            config_GetInt( p_intf, "qt-volume-complete" ),
+            config_GetPsz( p_intf, "qt-slider-colours" ) );
     }
     else
     {
@@ -587,12 +623,13 @@ ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
     volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
                               VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
 
+    /* Force the update at build time in order to have a muted icon if needed */
+    updateVolume( volumeSlider->value() );
+
     /* Volume control connection */
     CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
     CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
 
-    CONNECT( THEMIM->getIM(), statusChanged( int ), this, updateInput() );
-
     updateInput();
 }
 
@@ -688,15 +725,21 @@ void ControlsWidget::updateInput()
 {
     /* Activate the interface buttons according to the presence of the input */
     enableInput( THEMIM->getIM()->hasInput() );
-    enableVideo( THEMIM->getIM()->hasVideo() );
+    enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() );
 }
 
 void ControlsWidget::setStatus( int status )
 {
-    if( status == PLAYING_S ) // Playing
+    if( status == PLAYING_S ) /* Playing */
+    {
         playButton->setIcon( QIcon( ":/pixmaps/pause.png" ) );
+        playButton->setToolTip( qtr( "Pause" ) );
+    }
     else
+    {
         playButton->setIcon( QIcon( ":/pixmaps/play.png" ) );
+        playButton->setToolTip( qtr( "Play" ) );
+    }
 }
 
 /**
@@ -766,6 +809,330 @@ void ControlsWidget::toggleAdvanced()
 }
 
 
+/**********************************************************************
+ * Fullscrenn control widget
+ **********************************************************************/
+FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i,
+        MainInterface *_p_mi, bool b_advControls, bool b_shiny )
+        : ControlsWidget( _p_i, _p_mi, b_advControls, b_shiny, true ),
+        i_lastPosX( -1 ), i_lastPosY( -1 ), i_hideTimeout( 1 ),
+        b_mouseIsOver( false )
+{
+    setWindowFlags( Qt::ToolTip );
+
+    setFrameShape( QFrame::StyledPanel );
+    setFrameStyle( QFrame::Sunken );
+    setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
+
+    QGridLayout *fsLayout = new QGridLayout( this );
+    controlLayout->setSpacing( 0 );
+    #if QT43
+    controlLayout->setContentsMargins( 5, 1, 5, 1 );
+    #else
+    controlLayout->setMargin( 5 );
+    #endif
+
+    fsLayout->addWidget( slowerButton, 0, 0 );
+    slider->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum);
+    fsLayout->addWidget( slider, 0, 1, 1, 6 );
+    fsLayout->addWidget( fasterButton, 0, 7 );
+
+    fsLayout->addWidget( volMuteLabel, 1, 0);
+    fsLayout->addWidget( volumeSlider, 1, 1 );
+
+    fsLayout->addLayout( controlButLayout, 1, 2 );
+
+    fsLayout->addWidget( playButton, 1, 3 );
+
+    fsLayout->addWidget( discFrame, 1, 4 );
+
+    #ifdef ZVBI_COMPILED
+    fsLayout->addWidget( telexFrame, 1, 5 );
+    #endif
+
+    fsLayout->addWidget( advControls, 1, 6, Qt::AlignVCenter );
+
+    fsLayout->addWidget( fullscreenButton, 1, 7 );
+
+    /* hiding timer */
+    p_hideTimer = new QTimer( this );
+    CONNECT( p_hideTimer, timeout(), this, hideFSControllerWidget() );
+    p_hideTimer->setSingleShot( true );
+
+    /* slow hiding timer */
+    #ifdef TRANSPARENCY
+    p_slowHideTimer = new QTimer( this );
+    CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
+    #endif
+
+    adjustSize ();  /* need to get real width and height for moving */
+
+    /* center down */
+    QDesktopWidget * p_desktop = QApplication::desktop();
+
+    move( p_desktop->width() / 2 - width() / 2,
+          p_desktop->height() - height() );
+
+    #ifdef WIN32TRICK
+    setWindowOpacity( 0.0 );
+    fscHidden = true;
+    show();
+    #endif
+}
+
+FullscreenControllerWidget::~FullscreenControllerWidget()
+{
+}
+
+/**
+ * Hide fullscreen controller
+ * FIXME: under windows it have to be done by moving out of screen
+ *        because hide() doesnt work
+ */
+void FullscreenControllerWidget::hideFSControllerWidget()
+{
+    #ifdef WIN32TRICK
+    fscHidden = true;
+    setWindowOpacity( 0.0 );    // simulate hidding
+    #else
+    hide();
+    #endif
+}
+
+#ifdef TRANSPARENCY
+/**
+ * Hidding fullscreen controller slowly
+ * Linux: need composite manager
+ * Windows: it is blinking, so it can be enabled by define TRASPARENCY
+ */
+void FullscreenControllerWidget::slowHideFSC()
+{
+    static bool first_call = true;
+
+    if ( first_call )
+    {
+        first_call = false;
+
+        p_slowHideTimer->stop();
+        /* the last part of time divided to 100 pieces */
+        p_slowHideTimer->start(
+            (int) ( i_hideTimeout / 2 / ( windowOpacity() * 100 ) ) );
+    }
+    else
+    {
+         if ( windowOpacity() > 0.0 )
+         {
+             /* we should use 0.01 because of 100 pieces ^^^
+                but than it cannt be done in time */
+             setWindowOpacity( windowOpacity() - 0.02 );
+         }
+
+         if ( windowOpacity() == 0.0 )
+         {
+             first_call = true;
+             p_slowHideTimer->stop();
+         }
+    }
+}
+#endif
+
+/**
+ * Get state of visibility of FS controller on screen
+ * On windows control if it is on hidden position
+ */
+bool FullscreenControllerWidget::isFSCHidden()
+{
+    #ifdef WIN32TRICK
+    return fscHidden;
+    #endif
+
+    return isHidden();
+}
+
+/**
+ * event handling
+ * events: show, hide, start timer for hidding
+ */
+void FullscreenControllerWidget::customEvent( QEvent *event )
+{
+    int type = event->type();
+
+    if ( type == FullscreenControlShow_Type )
+    {
+        #ifdef WIN32TRICK
+        // after quiting and going to fs, we need to call show()
+        if ( isHidden() )
+            show();
+
+        if ( fscHidden )
+        {
+            fscHidden = false;
+            setWindowOpacity( 1.0 );
+        }
+        #else
+        show();
+        #endif
+
+        #ifdef TRANSPARENCY
+        setWindowOpacity( 0.75 );
+        #endif
+    }
+    else if ( type == FullscreenControlHide_Type )
+    {
+        hideFSControllerWidget();
+    }
+    else if ( type == FullscreenControlPlanHide_Type && !b_mouseIsOver )
+    {
+        p_hideTimer->start( i_hideTimeout );
+        #ifdef TRANSPARENCY
+        p_slowHideTimer->start( i_hideTimeout / 2 );
+        #endif
+    }
+}
+
+/**
+ * On mouse move
+ * moving with FSC
+ */
+void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
+{
+    if ( event->buttons() == Qt::LeftButton )
+    {
+        int i_moveX = event->globalX() - i_lastPosX;
+        int i_moveY = event->globalY() - i_lastPosY;
+
+        move( x() + i_moveX, y() + i_moveY );
+
+        i_lastPosX = event->globalX();
+        i_lastPosY = event->globalY();
+    }
+}
+
+/**
+ * On mouse press
+ * store position of cursor
+ */
+void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
+{
+    i_lastPosX = event->globalX();
+    i_lastPosY = event->globalY();
+}
+
+/**
+ * On mouse go above FSC
+ */
+void FullscreenControllerWidget::enterEvent( QEvent *event )
+{
+    p_hideTimer->stop();
+    #ifdef TRANSPARENCY
+    p_slowHideTimer->stop();
+    #endif
+    b_mouseIsOver = true;
+}
+
+/**
+ * On mouse go out from FSC
+ */
+void FullscreenControllerWidget::leaveEvent( QEvent *event )
+{
+    p_hideTimer->start( i_hideTimeout );
+    #ifdef TRANSPARENCY
+    p_slowHideTimer->start( i_hideTimeout / 2 );
+    #endif
+    b_mouseIsOver = false;
+}
+
+/**
+ * When you get pressed key, send it to video output
+ * FIXME: clearing focus by clearFocus() to not getting
+ * key press events didnt work
+ */
+void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
+{
+    int i_vlck = qtEventToVLCKey( event );
+    if( i_vlck > 0 )
+    {
+        var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+/**
+ * It is called when video start
+ */
+void FullscreenControllerWidget::regFullscreenCallback( vout_thread_t *p_vout )
+{
+    if ( p_vout )
+    {
+        var_AddCallback( p_vout, "fullscreen", regMouseMoveCallback, this );
+    }
+}
+
+/**
+ * It is called after turn off video, because p_vout is NULL now
+ * we cannt delete callback, just hide if FScontroller is visible
+ */
+void FullscreenControllerWidget::unregFullscreenCallback()
+{
+    if ( isVisible() )
+        hide();
+}
+
+/**
+ * Register and unregister callback for mouse moving
+ */
+static int regMouseMoveCallback( vlc_object_t *vlc_object, const char *variable,
+                                 vlc_value_t old_val, vlc_value_t new_val,
+                                 void *data )
+{
+    vout_thread_t *p_vout = (vout_thread_t *) vlc_object;
+
+    static bool b_registered = false;
+    FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *) data;
+
+    if ( var_GetBool( p_vout, "fullscreen" ) && !b_registered )
+    {
+        p_fs->SetHideTimeout( var_GetInteger( p_vout, "mouse-hide-timeout" ) );
+        var_AddCallback( p_vout, "mouse-moved",
+                        showFullscreenControllCallback, (void *) p_fs );
+        b_registered = true;
+    }
+
+    if ( !var_GetBool( p_vout, "fullscreen" ) && b_registered )
+    {
+        var_DelCallback( p_vout, "mouse-moved",
+                        showFullscreenControllCallback, (void *) p_fs );
+        b_registered = false;
+        p_fs->hide();
+    }
+
+    return VLC_SUCCESS;
+}
+
+/**
+ * Show fullscreen controller after mouse move
+ * after show immediately plan hide event
+ */
+static int showFullscreenControllCallback( vlc_object_t *vlc_object, const char *variable,
+                                           vlc_value_t old_val, vlc_value_t new_val,
+                                           void *data )
+{
+    FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *) data;
+
+    if ( p_fs->isFSCHidden() )
+    {
+        IMEvent *event = new IMEvent( FullscreenControlShow_Type, 0 );
+        QApplication::postEvent( p_fs, static_cast<QEvent *>(event) );
+    }
+
+    IMEvent *e = new IMEvent( FullscreenControlPlanHide_Type, 0 );
+    QApplication::postEvent( p_fs, static_cast<QEvent *>(e) );
+
+    return VLC_SUCCESS;
+}
+
 /**********************************************************************
  * Speed control widget
  **********************************************************************/
@@ -806,6 +1173,11 @@ SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
 SpeedControlWidget::~SpeedControlWidget()
 {}
 
+void SpeedControlWidget::setEnable( bool b_enable )
+{
+    speedSlider->setEnabled( b_enable );
+}
+
 #define RATE_SLIDER_MAXIMUM 3.0
 #define RATE_SLIDER_MINIMUM 0.3
 #define RATE_SLIDER_LENGTH 100.0