X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fqt4%2Fcomponents%2Finterface_widgets.cpp;h=172554589663c6da2bd5236bd57454379e7d5b0d;hb=b00904493e3d8a24c2612a16c19348dcc16ca60c;hp=96f42774037dd8903644d6679bacd60ac86077f3;hpb=c340ebcb432a17840571af513eeb87897acbb8db;p=vlc diff --git a/modules/gui/qt4/components/interface_widgets.cpp b/modules/gui/qt4/components/interface_widgets.cpp index 96f4277403..2df4c51b64 100644 --- a/modules/gui/qt4/components/interface_widgets.cpp +++ b/modules/gui/qt4/components/interface_widgets.cpp @@ -1,15 +1,18 @@ /***************************************************************************** * interface_widgets.cpp : Custom widgets for the main interface **************************************************************************** - * Copyright (C) 2006 the VideoLAN team + * Copyright ( C ) 2006 the VideoLAN team * $Id$ * * Authors: Clément Stenac + * Jean-Baptiste Kempf + * Rafaël Carré + * Ilkka Ollakka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * ( at your option ) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,41 +24,84 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + #include "dialogs_provider.hpp" -#include "qt4.hpp" #include "components/interface_widgets.hpp" #include "main_interface.hpp" #include "input_manager.hpp" +#include "menus.hpp" +#include "util/input_slider.hpp" +#include "util/customwidgets.hpp" -#include "pixmaps/art.xpm" -#include - +#include +#include +#include #include +#include #include +#include +#include +#include +#include -#define ICON_SIZE 128 +#ifdef Q_WS_X11 +# include +# include +#endif + +#include /********************************************************************** * Video Widget. A simple frame on which video is drawn * This class handles resize issues **********************************************************************/ -static void *DoRequest( intf_thread_t *, vout_thread_t *, int*,int*, - unsigned int *, unsigned int * ); -static void DoRelease( intf_thread_t *, void * ); -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 ); - p_vout = NULL; - setFrameStyle(QFrame::Panel | QFrame::Raised); + /* Init */ + i_vout = 0; + hide(); setMinimumSize( 16, 16 ); + videoSize.rwidth() = -1; + videoSize.rheight() = -1; + setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); - setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + /* 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 ); + setAttribute( Qt::WA_PaintOnScreen, true ); + + /* The core can ask through a callback to show the video. */ +#if HAS_QT43 + connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)), + this, SLOT(SetSizing(unsigned int, unsigned int )), + Qt::BlockingQueuedConnection ); +#else +#error This is broken. Fix it with a QEventLoop with a processEvents () + connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)), + this, SLOT(SetSizing(unsigned int, unsigned int )) ); +#endif +} + +void VideoWidget::paintEvent(QPaintEvent *ev) +{ + QFrame::paintEvent(ev); +#ifdef Q_WS_X11 + XFlush( QX11Info::display() ); +#endif } VideoWidget::~VideoWidget() { - vlc_mutex_lock( &lock ); + vout_thread_t *p_vout = i_vout + ? (vout_thread_t *)vlc_object_get( i_vout ) : NULL; + if( p_vout ) { if( !p_intf->psz_switch_intf ) @@ -68,145 +114,1199 @@ VideoWidget::~VideoWidget() if( vout_Control( p_vout, VOUT_REPARENT ) != VLC_SUCCESS ) vout_Control( p_vout, VOUT_CLOSE ); } + vlc_object_release( p_vout ); } - vlc_mutex_unlock( &lock ); - vlc_mutex_destroy( &lock ); -} - -QSize VideoWidget::sizeHint() const -{ - fprintf( stderr, "Video Size %ix%i\n", widgetSize.width(), widgetSize.height() ); - return widgetSize; } +/** + * 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 ) + unsigned int *pi_width, unsigned int *pi_height ) { - if( p_vout ) + msg_Dbg( p_intf, "Video was requested %i, %i", *pi_x, *pi_y ); + emit askVideoWidgetToShow( *pi_width, *pi_height ); + if( i_vout ) { msg_Dbg( p_intf, "embedded video already in use" ); return NULL; } - p_vout = p_nvout; - setMinimumSize( 1,1 ); - return (void*)winId(); + i_vout = p_nvout->i_object_id; + msg_Dbg( p_intf, "embedded video ready (handle %p)", winId() ); + return ( void* )winId(); +} + +/* 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 ) +{ + msg_Dbg( p_intf, "Video is resizing to: %i %i", w, h ); + videoSize.rwidth() = w; + videoSize.rheight() = h; + if( isHidden() ) show(); + updateGeometry(); // Needed for deinterlace } void VideoWidget::release( void *p_win ) { - p_vout = NULL; + msg_Dbg( p_intf, "Video is not needed anymore" ); + i_vout = 0; + 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, - * it's a static cone. + * it's album art if present or cone. **********************************************************************/ -BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i ) : - QFrame( NULL ), p_intf( _p_i ) +#define ICON_SIZE 128 +#define MAX_BG_SIZE 400 +#define MIN_BG_SIZE 64 + +BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i ) + :QWidget( NULL ), p_intf( _p_i ) { - setFrameStyle(QFrame::StyledPanel | QFrame::Raised); - DrawBackground(); + /* We should use that one to take the more size it can */ + setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding); + + /* A dark background */ + setAutoFillBackground( true ); + plt = palette(); + plt.setColor( QPalette::Active, QPalette::Window , Qt::black ); + plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black ); + setPalette( plt ); + + /* A cone in the middle */ + label = new QLabel; + label->setMargin( 5 ); + label->setMaximumHeight( MAX_BG_SIZE ); + label->setMaximumWidth( MAX_BG_SIZE ); + label->setMinimumHeight( MIN_BG_SIZE ); + label->setMinimumWidth( MIN_BG_SIZE ); + if( QDate::currentDate().dayOfYear() >= 354 ) + label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) ); + else + label->setPixmap( QPixmap( ":/vlc128.png" ) ); + + QGridLayout *backgroundLayout = new QGridLayout( this ); + backgroundLayout->addWidget( label, 0, 1 ); + backgroundLayout->setColumnStretch( 0, 1 ); + backgroundLayout->setColumnStretch( 2, 1 ); + + CONNECT( THEMIM->getIM(), artChanged( QString ), this, updateArt( QString ) ); } BackgroundWidget::~BackgroundWidget() +{} + +void BackgroundWidget::resizeEvent( QResizeEvent * event ) { - CleanBackground(); + if( event->size().height() <= MIN_BG_SIZE ) + label->hide(); + else + label->show(); } -int BackgroundWidget::DrawBackground() +void BackgroundWidget::updateArt( QString url ) { - setAutoFillBackground( true ); - plt = palette(); - plt.setColor( QPalette::Active, QPalette::Window , Qt::black ); - plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black ); - setPalette( plt ); + if( url.isEmpty() ) + { + if( QDate::currentDate().dayOfYear() >= 354 ) + label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) ); + else + label->setPixmap( QPixmap( ":/vlc128.png" ) ); + return; + } + else + { + label->setPixmap( QPixmap( url ) ); + } +} + +void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event ) +{ + QVLCMenu::PopupMenu( p_intf, true ); +} + +/********************************************************************** + * Visualization selector panel + **********************************************************************/ +VisualSelector::VisualSelector( intf_thread_t *_p_i ) : + QFrame( NULL ), p_intf( _p_i ) +{ + QHBoxLayout *layout = new QHBoxLayout( this ); + layout->setMargin( 0 ); + QPushButton *prevButton = new QPushButton( "Prev" ); + QPushButton *nextButton = new QPushButton( "Next" ); + layout->addWidget( prevButton ); + layout->addWidget( nextButton ); + + layout->addStretch( 10 ); + layout->addWidget( new QLabel( qtr( "Current visualization" ) ) ); + + current = new QLabel( qtr( "None" ) ); + layout->addWidget( current ); + + BUTTONACT( prevButton, prev() ); + BUTTONACT( nextButton, next() ); + + setLayout( layout ); + setMaximumHeight( 35 ); +} + +VisualSelector::~VisualSelector() +{} + +void VisualSelector::prev() +{ + char *psz_new = aout_VisualPrev( p_intf ); + if( psz_new ) + { + current->setText( qfu( psz_new ) ); + free( psz_new ); + } +} + +void VisualSelector::next() +{ + char *psz_new = aout_VisualNext( p_intf ); + if( psz_new ) + { + current->setText( qfu( psz_new ) ); + free( psz_new ); + } +} + +/********************************************************************** + * TEH controls + **********************************************************************/ + +#define setupSmallButton( aButton ){ \ + aButton->setMaximumSize( QSize( 26, 26 ) ); \ + aButton->setMinimumSize( QSize( 26, 26 ) ); \ + aButton->setIconSize( QSize( 20, 20 ) ); } + +AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) : + QFrame( NULL ), p_intf( _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" ); + setupSmallButton( ABButton ); + advLayout->addWidget( ABButton ); + BUTTON_SET_ACT( ABButton, "AB", qtr( "A to B" ), fromAtoB() ); + timeA = timeB = 0; + CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ), + this, AtoBLoop( float, int, int ) ); +#if 0 + frameButton = new QPushButton( "Fr" ); + frameButton->setMaximumSize( QSize( 26, 26 ) ); + frameButton->setIconSize( QSize( 20, 20 ) ); + advLayout->addWidget( frameButton ); + BUTTON_SET_ACT( frameButton, "Fr", qtr( "Frame by frame" ), frame() ); +#endif + + recordButton = new QPushButton( "R" ); + setupSmallButton( recordButton ); + advLayout->addWidget( recordButton ); + BUTTON_SET_ACT_I( recordButton, "", record_16px.png, + qtr( "Record" ), record() ); + + /* Snapshot Button */ + snapshotButton = new QPushButton( "S" ); + setupSmallButton( snapshotButton ); + advLayout->addWidget( snapshotButton ); + BUTTON_SET_ACT( snapshotButton, "S", qtr( "Take a snapshot" ), snapshot() ); +} + +AdvControlsWidget::~AdvControlsWidget() +{} + +void AdvControlsWidget::enableInput( bool enable ) +{ + ABButton->setEnabled( enable ); + recordButton->setEnabled( enable ); +} + +void AdvControlsWidget::enableVideo( bool enable ) +{ + snapshotButton->setEnabled( enable ); +#if 0 + frameButton->setEnabled( enable ); +#endif +} + +void AdvControlsWidget::snapshot() +{ + vout_thread_t *p_vout = + (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + if( p_vout ) vout_Control( p_vout, VOUT_SNAPSHOT ); +} + +/* Function called when the button is clicked() */ +void AdvControlsWidget::fromAtoB() +{ + if( !timeA ) + { + timeA = var_GetTime( THEMIM->getInput(), "time" ); + ABButton->setText( "A->..." ); + return; + } + if( !timeB ) + { + timeB = var_GetTime( THEMIM->getInput(), "time" ); + var_SetTime( THEMIM->getInput(), "time" , timeA ); + ABButton->setText( "A<=>B" ); + return; + } + timeA = 0; + timeB = 0; + ABButton->setText( "AB" ); +} + +/* Function called regularly when in an AtoB loop */ +void AdvControlsWidget::AtoBLoop( float f_pos, int i_time, int i_length ) +{ + if( timeB ) + { + if( i_time >= (int)(timeB/1000000) ) + var_SetTime( THEMIM->getInput(), "time" , timeA ); + } +} + +/* FIXME Record function */ +void AdvControlsWidget::record(){} + +#if 0 +//FIXME Frame by frame function +void AdvControlsWidget::frame(){} +#endif + +/***************************** + * DA Control Widget ! + *****************************/ +ControlsWidget::ControlsWidget( intf_thread_t *_p_i, + MainInterface *_p_mi, + bool b_advControls, + bool b_shiny, + bool b_fsCreation) : + QFrame( _p_mi ), p_intf( _p_i ) +{ + setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum ); + + /** The main Slider **/ + slider = new InputSlider( Qt::Horizontal, NULL ); + /* Update the position when the IM has changed */ + CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ), + slider, setPosition( float, int, int ) ); + /* And update the IM, when the position has changed */ + CONNECT( slider, sliderDragged( float ), + THEMIM->getIM(), sliderUpdate( float ) ); + + /** Slower and faster Buttons **/ + slowerButton = new QToolButton; + slowerButton->setAutoRaise( true ); + slowerButton->setMaximumSize( QSize( 26, 20 ) ); + + BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() ); + + fasterButton = new QToolButton; + fasterButton->setAutoRaise( true ); + fasterButton->setMaximumSize( QSize( 26, 20 ) ); + + BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() ); + + /* advanced Controls handling */ + b_advancedVisible = b_advControls; + + advControls = new AdvControlsWidget( p_intf ); + if( !b_advancedVisible ) advControls->hide(); + + /** Disc and Menus handling */ + discFrame = new QWidget( this ); + + QHBoxLayout *discLayout = new QHBoxLayout( discFrame ); + discLayout->setSpacing( 0 ); + discLayout->setMargin( 0 ); + + prevSectionButton = new QPushButton( discFrame ); + setupSmallButton( prevSectionButton ); + discLayout->addWidget( prevSectionButton ); + + menuButton = new QPushButton( discFrame ); + setupSmallButton( menuButton ); + discLayout->addWidget( menuButton ); + + nextSectionButton = new QPushButton( discFrame ); + setupSmallButton( nextSectionButton ); + discLayout->addWidget( nextSectionButton ); + + BUTTON_SET_IMG( prevSectionButton, "", previous.png, "" ); + BUTTON_SET_IMG( nextSectionButton, "", next.png, "" ); + BUTTON_SET_IMG( menuButton, "", previous.png, qtr( "Menu" ) ); + + discFrame->hide(); + + /* Change the navigation button display when the IM navigation changes */ + CONNECT( THEMIM->getIM(), navigationChanged( int ), + this, setNavigation( int ) ); + /* Changes the IM navigation when triggered on the nav buttons */ + CONNECT( prevSectionButton, clicked(), THEMIM->getIM(), + sectionPrev() ); + CONNECT( nextSectionButton, clicked(), THEMIM->getIM(), + sectionNext() ); + CONNECT( menuButton, clicked(), THEMIM->getIM(), + sectionMenu() ); + + /** + * Telextext QFrame + * TODO: Merge with upper menu in a StackLayout + **/ + telexFrame = new QWidget( this ); + QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame ); + telexLayout->setSpacing( 0 ); + telexLayout->setMargin( 0 ); + + telexOn = new QPushButton; + setupSmallButton( telexOn ); + telexLayout->addWidget( telexOn ); + + telexTransparent = new QPushButton; + setupSmallButton( telexTransparent ); + telexLayout->addWidget( telexTransparent ); + b_telexTransparent = false; + + 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 ); + + telexFrame->hide(); /* default hidden */ + + CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(), + telexGotoPage( int ) ); + CONNECT( THEMIM->getIM(), setNewTelexPage( int ), + telexPage, setValue( int ) ); + + BUTTON_SET_IMG( telexOn, "", tv.png, qtr( "Teletext on" ) ); + + CONNECT( telexOn, clicked(), THEMIM->getIM(), + telexToggleButtons() ); + CONNECT( telexOn, clicked( bool ), THEMIM->getIM(), + telexToggle( bool ) ); + CONNECT( THEMIM->getIM(), toggleTelexButtons(), + this, toggleTeletext() ); + b_telexEnabled = false; + telexTransparent->setEnabled( false ); + telexPage->setEnabled( false ); + + BUTTON_SET_IMG( telexTransparent, "", tvtelx.png, qtr( "Teletext" ) ); + CONNECT( telexTransparent, clicked( bool ), + THEMIM->getIM(), telexSetTransparency() ); + CONNECT( THEMIM->getIM(), toggleTelexTransparency(), + this, toggleTeletextTransparency() ); + CONNECT( THEMIM->getIM(), teletextEnabled( bool ), + this, enableTeletext( bool ) ); + + /** Play Buttons **/ + QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + sizePolicy.setHorizontalStretch( 0 ); + sizePolicy.setVerticalStretch( 0 ); + + /* Play */ + playButton = new QPushButton; + playButton->setSizePolicy( sizePolicy ); + playButton->setMaximumSize( QSize( 36, 36 ) ); + playButton->setMinimumSize( QSize( 36, 36 ) ); + playButton->setIconSize( QSize( 30, 30 ) ); + + + /** Prev + Stop + Next Block **/ + controlButLayout = new QHBoxLayout; + controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */ + + /* Prev */ + QPushButton *prevButton = new QPushButton; + prevButton->setSizePolicy( sizePolicy ); + setupSmallButton( prevButton ); + + controlButLayout->addWidget( prevButton ); + + /* Stop */ + QPushButton *stopButton = new QPushButton; + stopButton->setSizePolicy( sizePolicy ); + setupSmallButton( stopButton ); + + controlButLayout->addWidget( stopButton ); + + /* next */ + QPushButton *nextButton = new QPushButton; + nextButton->setSizePolicy( sizePolicy ); + setupSmallButton( nextButton ); + + controlButLayout->addWidget( nextButton ); + + /* Add this block to the main layout */ + + BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() ); + BUTTON_SET_ACT_I( prevButton, "" , previous.png, + qtr( "Previous" ), prev() ); + BUTTON_SET_ACT_I( nextButton, "", next.png, qtr( "Next" ), next() ); + BUTTON_SET_ACT_I( stopButton, "", stop.png, qtr( "Stop" ), stop() ); + + /* + * Other first Line buttons + */ + /** Fullscreen/Visualisation **/ + fullscreenButton = new QPushButton( "F" ); + BUTTON_SET_ACT( fullscreenButton, "F", qtr( "Fullscreen" ), fullscreen() ); + setupSmallButton( fullscreenButton ); + + /** Playlist Button **/ + playlistButton = new QPushButton; + setupSmallButton( playlistButton ); + BUTTON_SET_IMG( playlistButton, "" , playlist.png, qtr( "Show playlist" ) ); + CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() ); + + /** extended Settings **/ + extSettingsButton = new QPushButton; + BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended settings" ), + extSettings() ); + setupSmallButton( extSettingsButton ); + + + /* Volume */ + hVolLabel = new VolumeClickHandler( p_intf, this ); + + volMuteLabel = new QLabel; + volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) ); + volMuteLabel->setToolTip( qtr( "Mute" ) ); + volMuteLabel->installEventFilter( hVolLabel ); + + if( b_shiny ) + { + volumeSlider = new SoundSlider( this, + config_GetInt( p_intf, "volume-step" ), + config_GetInt( p_intf, "qt-volume-complete" ), + config_GetPsz( p_intf, "qt-slider-colours" ) ); + } + else + { + volumeSlider = new QSlider( this ); + volumeSlider->setOrientation( Qt::Horizontal ); + } + volumeSlider->setMaximumSize( QSize( 200, 40 ) ); + volumeSlider->setMinimumSize( QSize( 106, 30 ) ); + volumeSlider->setFocusPolicy( Qt::NoFocus ); + + /* Set the volume from the config */ + 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 ) ); + + if( !b_fsCreation ) + { + controlLayout = new QGridLayout( this ); + + controlLayout->setSpacing( 0 ); + controlLayout->setLayoutMargins( 7, 5, 7, 3, 6 ); + + controlLayout->addWidget( slider, 0, 1, 1, 16 ); + controlLayout->addWidget( slowerButton, 0, 0 ); + controlLayout->addWidget( fasterButton, 0, 17 ); + + controlLayout->addWidget( advControls, 1, 3, 2, 4, Qt::AlignBottom ); + controlLayout->addWidget( discFrame, 1, 10, 2, 3, Qt::AlignBottom ); + controlLayout->addWidget( telexFrame, 1, 10, 2, 4, Qt::AlignBottom ); + + controlLayout->addWidget( playButton, 2, 0, 2, 2 ); + controlLayout->setColumnMinimumWidth( 2, 20 ); + controlLayout->setColumnStretch( 2, 0 ); + + controlLayout->addLayout( controlButLayout, 3, 3, 1, 3 ); + controlLayout->setColumnMinimumWidth( 7, 20 ); + controlLayout->setColumnStretch( 7, 0 ); + controlLayout->setColumnStretch( 8, 0 ); + controlLayout->setColumnStretch( 9, 0 ); + + controlLayout->addWidget( fullscreenButton, 3, 10, Qt::AlignBottom ); + controlLayout->addWidget( playlistButton, 3, 11, Qt::AlignBottom ); + controlLayout->addWidget( extSettingsButton, 3, 12, Qt::AlignBottom ); + + controlLayout->setColumnStretch( 13, 0 ); + controlLayout->setColumnMinimumWidth( 13, 24 ); + controlLayout->setColumnStretch( 14, 5 ); + + controlLayout->addWidget( volMuteLabel, 3, 15, Qt::AlignBottom ); + controlLayout->addWidget( volumeSlider, 2, 16, 2 , 2, Qt::AlignBottom ); + } + + updateInput(); +} + +ControlsWidget::~ControlsWidget() +{} + +void ControlsWidget::toggleTeletext() +{ + bool b_enabled = THEMIM->teletextState(); + if( b_telexEnabled ) + { + telexTransparent->setEnabled( false ); + telexPage->setEnabled( false ); + b_telexEnabled = false; + } + else if( b_enabled ) + { + telexTransparent->setEnabled( true ); + telexPage->setEnabled( true ); + b_telexEnabled = true; + } +} + +void ControlsWidget::enableTeletext( bool b_enable ) +{ + telexFrame->setVisible( b_enable ); + bool b_on = THEMIM->teletextState(); + + telexOn->setChecked( b_on ); + telexTransparent->setEnabled( b_on ); + telexPage->setEnabled( b_on ); + b_telexEnabled = b_on; +} + +void ControlsWidget::toggleTeletextTransparency() +{ + if( b_telexTransparent ) + { + telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx.png" ) ); + telexTransparent->setToolTip( qtr( "Teletext" ) ); + b_telexTransparent = false; + } + else + { + telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx-transparent.png" ) ); + telexTransparent->setToolTip( qtr( "Transparent" ) ); + b_telexTransparent = true; + } +} + +void ControlsWidget::stop() +{ + THEMIM->stop(); +} + +void ControlsWidget::play() +{ + if( THEPL->current.i_size == 0 ) + { + /* The playlist is empty, open a file requester */ + THEDP->openFileDialog(); + setStatus( 0 ); + return; + } + THEMIM->togglePlayPause(); +} + +void ControlsWidget::prev() +{ + THEMIM->prev(); +} + +void ControlsWidget::next() +{ + THEMIM->next(); +} + +void ControlsWidget::setNavigation( int navigation ) +{ +#define HELP_PCH N_( "Previous chapter" ) +#define HELP_NCH N_( "Next chapter" ) + + // 1 = chapter, 2 = title, 0 = no + if( navigation == 0 ) + { + discFrame->hide(); + } else if( navigation == 1 ) { + prevSectionButton->setToolTip( qfu( HELP_PCH ) ); + nextSectionButton->setToolTip( qfu( HELP_NCH ) ); + menuButton->show(); + discFrame->show(); + } else { + prevSectionButton->setToolTip( qfu( HELP_PCH ) ); + nextSectionButton->setToolTip( qfu( HELP_NCH ) ); + menuButton->hide(); + discFrame->show(); + } +} + +static bool b_my_volume; +void ControlsWidget::updateVolume( int i_sliderVolume ) +{ + if( !b_my_volume ) + { + int i_res = i_sliderVolume * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX; + aout_VolumeSet( p_intf, i_res ); + } + if( i_sliderVolume == 0 ) + volMuteLabel->setPixmap( QPixmap(":/pixmaps/volume-muted.png" ) ); + else if( i_sliderVolume < VOLUME_MAX / 3 ) + volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) ); + else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) ) + volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) ); + else volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) ); +} + +void ControlsWidget::updateVolume() +{ + /* Audio part */ + audio_volume_t i_volume; + aout_VolumeGet( p_intf, &i_volume ); + i_volume = ( i_volume * VOLUME_MAX )/ (AOUT_VOLUME_MAX/2); + int i_gauge = volumeSlider->value(); + b_my_volume = false; + if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 ) + { + b_my_volume = true; + volumeSlider->setValue( i_volume ); + b_my_volume = false; + } +} + +void ControlsWidget::updateInput() +{ + /* Activate the interface buttons according to the presence of the input */ + enableInput( THEMIM->getIM()->hasInput() ); + enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() ); +} + +void ControlsWidget::setStatus( int status ) +{ + 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" ) ); + } +} + +/** + * TODO + * This functions toggle the fullscreen mode + * If there is no video, it should first activate Visualisations... + * This has also to be fixed in enableVideo() + */ +void ControlsWidget::fullscreen() +{ + vout_thread_t *p_vout = + (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + if( p_vout) + { + var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) ); + vlc_object_release( p_vout ); + } +} + +void ControlsWidget::extSettings() +{ + THEDP->extendedDialog(); +} + +void ControlsWidget::slower() +{ + THEMIM->getIM()->slower(); +} - backgroundLayout = new QHBoxLayout; - label = new QLabel( "" ); - label->setMaximumHeight( ICON_SIZE ); - label->setMaximumWidth( ICON_SIZE ); - label->setScaledContents( true ); - label->setPixmap( QPixmap( ":/vlc128.png" ) ); - backgroundLayout = new QHBoxLayout; - backgroundLayout->addWidget( label ); - setLayout( backgroundLayout ); - return 0; +void ControlsWidget::faster() +{ + THEMIM->getIM()->faster(); } -int BackgroundWidget::CleanBackground() +void ControlsWidget::enableInput( bool enable ) { - backgroundLayout->takeAt(0); - delete backgroundLayout; - return 0; + slowerButton->setEnabled( enable ); + slider->setEnabled( enable ); + fasterButton->setEnabled( enable ); + + /* Advanced Buttons too */ + advControls->enableInput( enable ); } -QSize BackgroundWidget::sizeHint() const +void ControlsWidget::enableVideo( bool enable ) { - fprintf( stderr, "BG %ix%i\n", widgetSize.width(), widgetSize.height() ); - return widgetSize; + // TODO Later make the fullscreenButton toggle Visualisation and so on. + fullscreenButton->setEnabled( enable ); + + /* Advanced Buttons too */ + advControls->enableVideo( enable ); } -void BackgroundWidget::resizeEvent( QResizeEvent *e ) +void ControlsWidget::toggleAdvanced() { - if( e->size().height() < ICON_SIZE -1 ) - label->setMaximumWidth( e->size().height() ); + if( !VISIBLE( advControls ) ) + { + advControls->show(); + b_advancedVisible = true; + } else - label->setMaximumWidth( ICON_SIZE ); + { + advControls->hide(); + b_advancedVisible = false; + } + emit advancedControlsToggled( b_advancedVisible ); } + /********************************************************************** - * Playlist Widget. The embedded playlist + * Fullscrenn control widget **********************************************************************/ -#include "components/playlist/panels.hpp" -#include "components/playlist/selector.hpp" - -PlaylistWidget::PlaylistWidget( intf_thread_t *_p_intf ) : QFrame(NULL), - p_intf( _p_intf ) -{ - QVBoxLayout *left = new QVBoxLayout( ); - QHBoxLayout *middle = new QHBoxLayout; - - setFrameStyle(QFrame::StyledPanel | QFrame::Sunken ); - selector = new PLSelector( this, p_intf, THEPL ); - selector->setMaximumWidth( 130 ); - left->addWidget( selector ); - - QPushButton *undockButton = new QPushButton( "UN", this ); - undockButton->setMaximumWidth( 25 ); - undockButton->setToolTip( qtr( "Undock playlist for main interface" ) ); - QPushButton *sourcesButton = new QPushButton( "Sources", this ); - sourcesButton->setToolTip( qtr( "Select additional stream sources" ) ); - middle->addWidget( undockButton ); - middle->addWidget( sourcesButton ); - left->addLayout( middle ); - - QLabel *art = new QLabel( "" ); - art->setMaximumHeight( 128 ); - art->setMaximumWidth( 128 ); - art->setScaledContents( true ); - art->setPixmap( QPixmap( art_xpm ) ); //":/vlc128.png" ) ); - left->addWidget( art ); - - playlist_item_t *p_root = playlist_GetPreferredNode( THEPL, - THEPL->p_local_category ); - - rightPanel = qobject_cast(new StandardPLPanel( this, - p_intf, THEPL, p_root ) ); - - CONNECT( selector, activated( int ), rightPanel, setRoot( int ) ); - - QHBoxLayout *layout = new QHBoxLayout(this); - layout->addLayout( left, 0 ); - layout->addWidget( rightPanel, 10 ); - setLayout( layout ); +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_mouse_last_x( -1 ), i_mouse_last_y( -1 ), b_mouse_over(false), + b_slow_hide_begin(false), i_slow_hide_timeout(1), + b_fullscreen( false ), i_hide_timeout( 1 ) +{ + setWindowFlags( Qt::ToolTip ); + + setFrameShape( QFrame::StyledPanel ); + setFrameStyle( QFrame::Sunken ); + setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); + + QGridLayout *fsLayout = new QGridLayout( this ); + fsLayout->setLayoutMargins( 5, 1, 5, 1, 5 ); + + 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 ); + + fsLayout->addWidget( telexFrame, 1, 5 ); + + fsLayout->addWidget( advControls, 1, 6, Qt::AlignVCenter ); + + fsLayout->addWidget( fullscreenButton, 1, 7 ); + + /* hiding timer */ + p_hideTimer = new QTimer( this ); + CONNECT( p_hideTimer, timeout(), this, hideFSC() ); + p_hideTimer->setSingleShot( true ); + + /* slow hiding timer */ +#if HAVE_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 + + vlc_mutex_init_recursive( &lock ); } -PlaylistWidget::~PlaylistWidget() +FullscreenControllerWidget::~FullscreenControllerWidget() { + vlc_mutex_destroy( &lock ); } -QSize PlaylistWidget::sizeHint() const +/** + * Show fullscreen controller + */ +void FullscreenControllerWidget::showFSC() { - fprintf( stderr, "PL Size %ix%i\n", widgetSize.width(), widgetSize.height() ); - return widgetSize; +#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 + +#if HAVE_TRANSPARENCY + setWindowOpacity( DEFAULT_OPACITY ); +#endif } +/** + * Hide fullscreen controller + * FIXME: under windows it have to be done by moving out of screen + * because hide() doesnt work + */ +void FullscreenControllerWidget::hideFSC() +{ +#ifdef WIN32TRICK + fscHidden = true; + setWindowOpacity( 0.0 ); // simulate hidding +#else + hide(); +#endif +} + +/** + * Plane to hide fullscreen controller + */ +void FullscreenControllerWidget::planHideFSC() +{ + vlc_mutex_lock( &lock ); + int i_timeout = i_hide_timeout; + vlc_mutex_unlock( &lock ); + + p_hideTimer->start( i_timeout ); + +#if HAVE_TRANSPARENCY + b_slow_hide_begin = true; + i_slow_hide_timeout = i_timeout; + p_slowHideTimer->start( i_slow_hide_timeout / 2 ); +#endif +} + +/** + * Hidding fullscreen controller slowly + * Linux: need composite manager + * Windows: it is blinking, so it can be enabled by define TRASPARENCY + */ +void FullscreenControllerWidget::slowHideFSC() +{ +#if HAVE_TRANSPARENCY + if( b_slow_hide_begin ) + { + b_slow_hide_begin = false; + + p_slowHideTimer->stop(); + /* the last part of time divided to 100 pieces */ + p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) ); + + } + else + { +#ifdef WIN32TRICK + if ( windowOpacity() > 0.0 && !fscHidden ) +#else + if ( windowOpacity() > 0.0 ) +#endif + { + /* 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 ) + p_slowHideTimer->stop(); + } +#endif +} + +/** + * event handling + * events: show, hide, start timer for hidding + */ +void FullscreenControllerWidget::customEvent( QEvent *event ) +{ + bool b_fs; + + switch( event->type() ) + { + case FullscreenControlShow_Type: + vlc_mutex_lock( &lock ); + b_fs = b_fullscreen; + vlc_mutex_unlock( &lock ); + + if( b_fs ) // FIXME I am not sure about that one + showFSC(); + break; + case FullscreenControlHide_Type: + hideFSC(); + break; + case FullscreenControlPlanHide_Type: + if( !b_mouse_over ) // Only if the mouse is not over FSC + planHideFSC(); + break; + } +} + +/** + * On mouse move + * moving with FSC + */ +void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event ) +{ + if ( event->buttons() == Qt::LeftButton ) + { + int i_moveX = event->globalX() - i_mouse_last_x; + int i_moveY = event->globalY() - i_mouse_last_y; + + move( x() + i_moveX, y() + i_moveY ); + + i_mouse_last_x = event->globalX(); + i_mouse_last_y = event->globalY(); + } +} + +/** + * On mouse press + * store position of cursor + */ +void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event ) +{ + i_mouse_last_x = event->globalX(); + i_mouse_last_y = event->globalY(); +} + +/** + * On mouse go above FSC + */ +void FullscreenControllerWidget::enterEvent( QEvent *event ) +{ + b_mouse_over = true; + + p_hideTimer->stop(); +#if HAVE_TRANSPARENCY + p_slowHideTimer->stop(); +#endif +} + +/** + * On mouse go out from FSC + */ +void FullscreenControllerWidget::leaveEvent( QEvent *event ) +{ + planHideFSC(); + + b_mouse_over = 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(); +} + +/* */ +static int FullscreenControllerWidgetFullscreenChanged( 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; + FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data; + + p_fs->fullscreenChanged( p_vout, new_val.b_bool, var_GetInteger( p_vout, "mouse-hide-timeout" ) ); + + return VLC_SUCCESS; +} +/* */ +static int FullscreenControllerWidgetMouseMoved( 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; + + /* Show event */ + IMEvent *eShow = new IMEvent( FullscreenControlShow_Type, 0 ); + QApplication::postEvent( p_fs, static_cast(eShow) ); + + /* Plan hide event */ + IMEvent *eHide = new IMEvent( FullscreenControlPlanHide_Type, 0 ); + QApplication::postEvent( p_fs, static_cast(eHide) ); + + return VLC_SUCCESS; +} + + +/** + * It is called when video start + */ +void FullscreenControllerWidget::attachVout( vout_thread_t *p_vout ) +{ + assert( p_vout ); + + vlc_mutex_lock( &lock ); + var_AddCallback( p_vout, "fullscreen", FullscreenControllerWidgetFullscreenChanged, this ); /* I miss a add and fire */ + fullscreenChanged( p_vout, var_GetBool( p_vout, "fullscreen" ), var_GetInteger( p_vout, "mouse-hide-timeout" ) ); + vlc_mutex_unlock( &lock ); +} +/** + * It is called after turn off video. + */ +void FullscreenControllerWidget::detachVout( vout_thread_t *p_vout ) +{ + assert( p_vout ); + + var_DelCallback( p_vout, "fullscreen", FullscreenControllerWidgetFullscreenChanged, this ); + vlc_mutex_lock( &lock ); + fullscreenChanged( p_vout, false, 0 ); + vlc_mutex_unlock( &lock ); +} + +/** + * Register and unregister callback for mouse moving + */ +void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout, bool b_fs, int i_timeout ) +{ + vlc_mutex_lock( &lock ); + if( b_fs && !b_fullscreen ) + { + b_fullscreen = true; + i_hide_timeout = i_timeout; + var_AddCallback( p_vout, "mouse-moved", FullscreenControllerWidgetMouseMoved, this ); + } + else if( !b_fs && b_fullscreen ) + { + b_fullscreen = false; + i_hide_timeout = i_timeout; + var_DelCallback( p_vout, "mouse-moved", FullscreenControllerWidgetMouseMoved, this ); + + /* Force fs hidding */ + IMEvent *eHide = new IMEvent( FullscreenControlHide_Type, 0 ); + QApplication::postEvent( this, static_cast(eHide) ); + } + vlc_mutex_unlock( &lock ); +} + +/********************************************************************** + * Speed control widget + **********************************************************************/ +SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) : + QFrame( NULL ), p_intf( _p_i ) +{ + QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed ); + sizePolicy.setHorizontalStretch( 0 ); + sizePolicy.setVerticalStretch( 0 ); + + speedSlider = new QSlider; + speedSlider->setSizePolicy( sizePolicy ); + speedSlider->setMaximumSize( QSize( 80, 200 ) ); + speedSlider->setOrientation( Qt::Vertical ); + speedSlider->setTickPosition( QSlider::TicksRight ); + + speedSlider->setRange( -24, 24 ); + speedSlider->setSingleStep( 1 ); + speedSlider->setPageStep( 1 ); + speedSlider->setTickInterval( 12 ); + + CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) ); + + QToolButton *normalSpeedButton = new QToolButton( this ); + normalSpeedButton->setMaximumSize( QSize( 26, 20 ) ); + normalSpeedButton->setAutoRaise( true ); + normalSpeedButton->setText( "1x" ); + normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) ); + + CONNECT( normalSpeedButton, clicked(), this, resetRate() ); + + QVBoxLayout *speedControlLayout = new QVBoxLayout; + speedControlLayout->setLayoutMargins( 4, 4, 4, 4, 4 ); + speedControlLayout->setSpacing( 4 ); + speedControlLayout->addWidget( speedSlider ); + speedControlLayout->addWidget( normalSpeedButton ); + setLayout( speedControlLayout ); +} + +SpeedControlWidget::~SpeedControlWidget() +{} + +void SpeedControlWidget::setEnable( bool b_enable ) +{ + speedSlider->setEnabled( b_enable ); +} + +void SpeedControlWidget::updateControls( int rate ) +{ + if( speedSlider->isSliderDown() ) + { + //We don't want to change anything if the user is using the slider + return; + } + + double value = 12 * log( (double)INPUT_RATE_DEFAULT / rate ) / log( 2 ); + int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 ); + + if( sliderValue < speedSlider->minimum() ) + { + sliderValue = speedSlider->minimum(); + } + else if( sliderValue > speedSlider->maximum() ) + { + sliderValue = speedSlider->maximum(); + } + + //Block signals to avoid feedback loop + speedSlider->blockSignals( true ); + speedSlider->setValue( sliderValue ); + speedSlider->blockSignals( false ); +} + +void SpeedControlWidget::updateRate( int sliderValue ) +{ + double speed = pow( 2, (double)sliderValue / 12 ); + int rate = INPUT_RATE_DEFAULT / speed; + + THEMIM->getIM()->setRate(rate); +} + +void SpeedControlWidget::resetRate() +{ + THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT); +}