Commit b1c512dc authored by Jean-Baptiste Kempf's avatar Jean-Baptiste Kempf

Qt4: Split the controllers from the rest of the interface widgets.

parent 9e43b17d
......@@ -38,6 +38,7 @@ nodist_SOURCES_qt4 = \
components/simple_preferences.moc.cpp \
components/open_panels.moc.cpp \
components/interface_widgets.moc.cpp \
components/controller.moc.cpp \
components/playlist/playlist_model.moc.cpp \
components/playlist/playlist_item.moc.cpp \
components/playlist/playlist.moc.cpp \
......@@ -191,6 +192,7 @@ SOURCES_qt4 = qt4.cpp \
components/simple_preferences.cpp \
components/open_panels.cpp \
components/interface_widgets.cpp \
components/controller.cpp \
components/playlist/playlist_model.cpp \
components/playlist/playlist_item.cpp \
components/playlist/standardpanel.cpp \
......@@ -227,6 +229,7 @@ noinst_HEADERS = \
components/simple_preferences.hpp \
components/open_panels.hpp \
components/interface_widgets.hpp \
components/controller.hpp \
components/playlist/playlist_model.hpp \
components/playlist/playlist_item.hpp \
components/playlist/panels.hpp \
......
/*****************************************************************************
* interface_widgets.cpp : Custom widgets for the main interface
****************************************************************************
* Copyright ( C ) 2006 the VideoLAN team
* $Id$
*
* Authors: Clément Stenac <zorglub@videolan.org>
* Jean-Baptiste Kempf <jb@videolan.org>
* Rafaël Carré <funman@videolanorg>
* Ilkka Ollakka <ileoo@videolan.org>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_vout.h>
#include "dialogs_provider.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 <QLabel>
#include <QSpacerItem>
#include <QCursor>
#include <QPushButton>
#include <QToolButton>
#include <QHBoxLayout>
#include <QMenu>
#include <QPalette>
#include <QResizeEvent>
#include <QDate>
#define I_PLAY_TOOLTIP N_("Play\nIf the playlist is empty, open a media")
/**********************************************************************
* TEH controls
**********************************************************************/
static void setupSmallButton( QPushButton *aButton )
{
aButton->setMaximumSize( QSize( 26, 26 ) );
aButton->setMinimumSize( QSize( 26, 26 ) );
aButton->setIconSize( QSize( 20, 20 ) );
aButton->setFocusPolicy( Qt::NoFocus );
}
/* init static variables in advanced controls */
mtime_t AdvControlsWidget::timeA = 0;
mtime_t AdvControlsWidget::timeB = 0;
AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i, bool b_fsCreation = false ) :
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;
setupSmallButton( ABButton );
advLayout->addWidget( ABButton );
BUTTON_SET_ACT_I( ABButton, "", atob_nob,
qtr( "Loop from point A to point B continuously.\nClick to set point A" ),
fromAtoB() );
timeA = timeB = 0;
i_last_input_id = 0;
/* in FS controller we skip this, because we dont want to have it double
controlled */
if( !b_fsCreation )
CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
this, AtoBLoop( float, int, int ) );
/* set up synchronization between main controller and fs controller */
CONNECT( THEMIM->getIM(), advControlsSetIcon(), this, setIcon() );
connect( this, SIGNAL( timeChanged() ),
THEMIM->getIM(), SIGNAL( advControlsSetIcon()));
#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
/* Record Button */
recordButton = new QPushButton;
setupSmallButton( recordButton );
advLayout->addWidget( recordButton );
BUTTON_SET_ACT_I( recordButton, "", record,
qtr( "Record" ), record() );
/* Snapshot Button */
snapshotButton = new QPushButton;
setupSmallButton( snapshotButton );
advLayout->addWidget( snapshotButton );
BUTTON_SET_ACT_I( snapshotButton, "", snapshot,
qtr( "Take a snapshot" ), snapshot() );
}
AdvControlsWidget::~AdvControlsWidget()
{}
void AdvControlsWidget::enableInput( bool enable )
{
int i_input_id = 0;
if( THEMIM->getInput() != NULL )
{
input_item_t *p_item = input_GetItem( THEMIM->getInput() );
i_input_id = p_item->i_id;
recordButton->setVisible( var_GetBool( THEMIM->getInput(), "can-record" ) );
}
else
{
recordButton->setVisible( false );
}
ABButton->setEnabled( enable );
recordButton->setEnabled( enable );
if( enable && ( i_last_input_id != i_input_id ) )
{
timeA = timeB = 0;
i_last_input_id = i_input_id;
emit timeChanged();
}
}
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 );
vlc_object_release( p_vout );
}
}
/* Function called when the button is clicked() */
void AdvControlsWidget::fromAtoB()
{
if( !timeA )
{
timeA = var_GetTime( THEMIM->getInput(), "time" );
emit timeChanged();
return;
}
if( !timeB )
{
timeB = var_GetTime( THEMIM->getInput(), "time" );
var_SetTime( THEMIM->getInput(), "time" , timeA );
emit timeChanged();
return;
}
timeA = 0;
timeB = 0;
emit timeChanged();
}
/* setting/synchro icons after click on main or fs controller */
void AdvControlsWidget::setIcon()
{
if( !timeA && !timeB)
{
ABButton->setIcon( QIcon( ":/atob_nob" ) );
ABButton->setToolTip( qtr( "Loop from point A to point B continuously\nClick to set point A" ) );
}
else if( timeA && !timeB )
{
ABButton->setIcon( QIcon( ":/atob_noa" ) );
ABButton->setToolTip( qtr( "Click to set point B" ) );
}
else if( timeA && timeB )
{
ABButton->setIcon( QIcon( ":/atob" ) );
ABButton->setToolTip( qtr( "Stop the A to B loop" ) );
}
}
/* 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 ) )
|| ( i_time < (int)( timeA/1000000 ) ) )
var_SetTime( THEMIM->getInput(), "time" , timeA );
}
}
void AdvControlsWidget::record()
{
input_thread_t *p_input = THEMIM->getInput();
if( p_input )
{
/* This method won't work fine if the stream can't be cut anywhere */
const bool b_recording = var_GetBool( p_input, "record" );
var_SetBool( p_input, "record", !b_recording );
#if 0
else
{
/* 'record' access-filter is not loaded, we open Save dialog */
input_item_t *p_item = input_GetItem( p_input );
if( !p_item )
return;
char *psz = input_item_GetURI( p_item );
if( psz )
THEDP->streamingDialog( NULL, psz, true );
}
#endif
}
}
#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 ) );
slowerButton->setFocusPolicy( Qt::NoFocus );
BUTTON_SET_ACT_I( slowerButton, "", slower, qtr( "Slower" ), slower() );
fasterButton = new QToolButton;
fasterButton->setAutoRaise( true );
fasterButton->setMaximumSize( QSize( 26, 20 ) );
fasterButton->setFocusPolicy( Qt::NoFocus );
BUTTON_SET_ACT_I( fasterButton, "", faster, qtr( "Faster" ), faster() );
/* advanced Controls handling */
b_advancedVisible = b_advControls;
advControls = new AdvControlsWidget( p_intf, b_fsCreation );
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, "", dvd_prev, "" );
BUTTON_SET_IMG( nextSectionButton, "", dvd_next, "" );
BUTTON_SET_IMG( menuButton, "", dvd_menu, 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, 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, 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( 32, 32 ) );
playButton->setMinimumSize( QSize( 32, 32 ) );
playButton->setIconSize( QSize( 26, 26 ) );
playButton->setFocusPolicy( Qt::NoFocus );
/** 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_b, qtr( I_PLAY_TOOLTIP ), play() );
BUTTON_SET_ACT_I( prevButton, "" , previous_b,
qtr( "Previous media in the playlist" ), prev() );
BUTTON_SET_ACT_I( nextButton, "", next_b,
qtr( "Next media in the playlist" ), next() );
BUTTON_SET_ACT_I( stopButton, "", stop_b, qtr( "Stop playback" ), stop() );
/*
* Other first Line buttons
*/
/* */
CONNECT( THEMIM->getIM(), voutChanged(bool), this, enableVideo(bool) );
/** Fullscreen/Visualisation **/
fullscreenButton = new QPushButton;
BUTTON_SET_ACT_I( fullscreenButton, "", fullscreen,
qtr( "Toggle the video in fullscreen" ), fullscreen() );
setupSmallButton( fullscreenButton );
if( !b_fsCreation )
{
/** Playlist Button **/
playlistButton = new QPushButton;
setupSmallButton( playlistButton );
BUTTON_SET_IMG( playlistButton, "" , playlist, qtr( "Show playlist" ) );
CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
/** extended Settings **/
extSettingsButton = new QPushButton;
BUTTON_SET_ACT_I( extSettingsButton, "", extended,
qtr( "Show extended settings" ), extSettings() );
setupSmallButton( extSettingsButton );
}
/* Volume */
hVolLabel = new VolumeClickHandler( p_intf, this );
volMuteLabel = new QLabel;
volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
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( 85, 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, 18 );
controlLayout->addWidget( slowerButton, 0, 0 );
controlLayout->addWidget( fasterButton, 0, 19 );
controlLayout->addWidget( discFrame, 1, 8, 2, 3, Qt::AlignBottom );
controlLayout->addWidget( telexFrame, 1, 8, 2, 5, Qt::AlignBottom );
controlLayout->addWidget( playButton, 2, 0, 2, 2, Qt::AlignBottom );
controlLayout->setColumnMinimumWidth( 2, 10 );
controlLayout->setColumnStretch( 2, 0 );
controlLayout->addLayout( controlButLayout, 3, 3, 1, 3, Qt::AlignBottom );
/* Column 6 is unused */
controlLayout->setColumnStretch( 6, 0 );
controlLayout->setColumnStretch( 7, 0 );
controlLayout->setColumnMinimumWidth( 7, 10 );
controlLayout->addWidget( fullscreenButton, 3, 8, Qt::AlignBottom );
controlLayout->addWidget( playlistButton, 3, 9, Qt::AlignBottom );
controlLayout->addWidget( extSettingsButton, 3, 10, Qt::AlignBottom );
controlLayout->setColumnStretch( 11, 0 ); /* telex alignment */
controlLayout->setColumnStretch( 12, 0 );
controlLayout->setColumnMinimumWidth( 12, 10 );
controlLayout->addWidget( advControls, 3, 13, 1, 3, Qt::AlignBottom );
controlLayout->setColumnStretch( 16, 10 );
controlLayout->setColumnMinimumWidth( 16, 10 );
controlLayout->addWidget( volMuteLabel, 3, 17, Qt::AlignBottom );
controlLayout->addWidget( volumeSlider, 3, 18, 1 , 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( ":/tvtelx" ) );
telexTransparent->setToolTip( qtr( "Teletext" ) );
b_telexTransparent = false;
}
else
{
telexTransparent->setIcon( QIcon( ":/tvtelx-trans" ) );
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( qtr( HELP_PCH ) );
nextSectionButton->setToolTip( qtr( HELP_NCH ) );
menuButton->show();
discFrame->show();
} else {
prevSectionButton->setToolTip( qtr( HELP_PCH ) );
nextSectionButton->setToolTip( qtr( 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(":/volume-muted" ) );
volMuteLabel->setToolTip( qtr( "Unmute" ) );
return;
}
if( i_sliderVolume < VOLUME_MAX / 3 )
volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
volMuteLabel->setToolTip( qtr( "Mute" ) );