interface_widgets.cpp 26.8 KB
Newer Older
1
/*****************************************************************************
2
 * interface_widgets.cpp : Custom widgets for the main interface
3
 ****************************************************************************
4
 * Copyright ( C ) 2006 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 13 14
 *
 * 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
15
 * ( at your option ) any later version.
16 17 18 19 20 21 22 23 24 25 26
 *
 * 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.
 *****************************************************************************/

27
#include "dialogs_provider.hpp"
28
#include "components/interface_widgets.hpp"
29
#include "main_interface.hpp"
30
#include "input_manager.hpp"
31
#include "menus.hpp"
32
#include "util/input_slider.hpp"
33
#include "util/customwidgets.hpp"
Clément Stenac's avatar
Clément Stenac committed
34
#include <vlc_vout.h>
35

Clément Stenac's avatar
Clément Stenac committed
36 37
#include <QLabel>
#include <QSpacerItem>
Clément Stenac's avatar
Clément Stenac committed
38
#include <QCursor>
Clément Stenac's avatar
Clément Stenac committed
39
#include <QPushButton>
40
#include <QToolButton>
41
#include <QHBoxLayout>
Clément Stenac's avatar
Clément Stenac committed
42
#include <QMenu>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
43 44
#include <QPalette>
#include <QResizeEvent>
45

46 47 48 49
/**********************************************************************
 * Video Widget. A simple frame on which video is drawn
 * This class handles resize issues
 **********************************************************************/
50 51 52 53 54
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 );

55
VideoWidget::VideoWidget( intf_thread_t *_p_i ) : QFrame( NULL ), p_intf( _p_i )
56 57 58
{
    vlc_mutex_init( p_intf, &lock );
    p_vout = NULL;
59 60 61 62
    hide(); setMinimumSize( 16, 16 );
 
   // CONNECT( this, askResize( int, int ), this, SetSizing( int, int ) );
    CONNECT( this, askVideoWidgetToShow(), this, show() );
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
}

VideoWidget::~VideoWidget()
{
    vlc_mutex_lock( &lock );
    if( p_vout )
    {
        if( !p_intf->psz_switch_intf )
        {
            if( vout_Control( p_vout, VOUT_CLOSE ) != VLC_SUCCESS )
                vout_Control( p_vout, VOUT_REPARENT );
        }
        else
        {
            if( vout_Control( p_vout, VOUT_REPARENT ) != VLC_SUCCESS )
                vout_Control( p_vout, VOUT_CLOSE );
        }
    }
    vlc_mutex_unlock( &lock );
    vlc_mutex_destroy( &lock );
}

QSize VideoWidget::sizeHint() const
{
88
    return widgetSize;
89 90
}

91 92 93
/**
 * Request the video to avoid the conflicts 
 **/
94
void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
95 96
                           unsigned int *pi_width, unsigned int *pi_height )
{
97
    emit askVideoWidgetToShow();
98 99 100 101 102 103
    if( p_vout )
    {
        msg_Dbg( p_intf, "embedded video already in use" );
        return NULL;
    }
    p_vout = p_nvout;
104
    return ( void* )winId();
105 106
}

107 108
/* Set the Widget to the correct Size */
void VideoWidget::SetSizing( unsigned int w, unsigned int h )
109
{
110 111 112 113
    resize( w, h );
    //updateGeometry(); // Needed for deinterlace
    msg_Dbg( p_intf, "%i %i", sizeHint().height(), sizeHint().width() );
    emit askResize();
114 115
}

116
void VideoWidget::release( void *p_win )
117
{
118
    p_vout = NULL;
119
}
120 121


122 123 124 125
/**********************************************************************
 * Background Widget. Show a simple image background. Currently,
 * it's a static cone.
 **********************************************************************/
126 127 128 129
#define ICON_SIZE 128
#define MAX_BG_SIZE 400
#define MIN_BG_SIZE 64

130 131 132
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i ) :
                                        QFrame( NULL ), p_intf( _p_i )
{
133 134
    /* We should use that one to take the more size it can */
    setSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding );
135

136
    /* A dark background */
Clément Stenac's avatar
Clément Stenac committed
137
    setAutoFillBackground( true );
138 139 140 141 142
    plt =  palette();
    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
    setPalette( plt );

143
    /* A cone in the middle */
144
    label = new QLabel;
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
145
    label->setScaledContents( true );
146
    label->setMargin( 5 );
147 148
    label->setMaximumHeight( MAX_BG_SIZE );
    label->setMaximumWidth( MAX_BG_SIZE );
149 150
    label->setMinimumHeight( MIN_BG_SIZE );
    label->setMinimumWidth( MIN_BG_SIZE );
151
    label->setPixmap( QPixmap( ":/vlc128.png" ) );
152

153
    QHBoxLayout *backgroundLayout = new QHBoxLayout( this );
154
    backgroundLayout->addWidget( label );
155 156

    resize( 300, 150 );
157
    updateGeometry();
158
    CONNECT( THEMIM, inputChanged( input_thread_t *), this, update( input_thread_t * ) );
159 160
}

Clément Stenac's avatar
Clément Stenac committed
161
BackgroundWidget::~BackgroundWidget()
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
162 163 164
{
}

165

166
void BackgroundWidget::update( input_thread_t *p_input )
167
{
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
168 169
    if( !p_input || p_input->b_dead )
    {
170
        label->setPixmap( QPixmap( ":/vlc128.png" ) );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
171 172 173 174
        return;
    }


175 176 177 178 179 180 181 182
    vlc_object_yield( p_input );
    char *psz_arturl = input_item_GetArtURL( input_GetItem(p_input) );
    vlc_object_release( p_input );
    QString url = qfu( psz_arturl );
    QString arturl = url.replace( "file://",QString("" ) );
    if( arturl.isNull() )
        label->setPixmap( QPixmap( ":/vlc128.png" ) );
    else
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
183
    {
184 185
        label->setPixmap( QPixmap( arturl ) );
        msg_Dbg( p_intf, "changing input b_need_update done %s", psz_arturl );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
186
    }
187
    free( psz_arturl );
188 189
}

190 191
QSize BackgroundWidget::sizeHint() const
{
192
    return label->size();
193 194
}

195 196
void BackgroundWidget::resizeEvent( QResizeEvent *e )
{
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
197 198 199 200 201 202
    if( e->size().height() < MAX_BG_SIZE -1 )
    {
        label->setMaximumWidth( e->size().height() );
        label->setMaximumHeight( e->size().width() );
    }
    else
203
    {
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
204 205
        label->setMaximumHeight( MAX_BG_SIZE );
        label->setMaximumWidth( MAX_BG_SIZE );
206
    }
207
}
208

209 210 211 212
void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
{
    QVLCMenu::PopupMenu( p_intf, true );
}
213

Clément Stenac's avatar
Clément Stenac committed
214 215 216 217
/**********************************************************************
 * Visualization selector panel
 **********************************************************************/
VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
218
                                QFrame( NULL ), p_intf( _p_i )
Clément Stenac's avatar
Clément Stenac committed
219 220
{
    QHBoxLayout *layout = new QHBoxLayout( this );
221
    layout->setMargin( 0 );
Clément Stenac's avatar
Clément Stenac committed
222
    QPushButton *prevButton = new QPushButton( "Prev" );
223
    QPushButton *nextButton = new QPushButton( "Next" );
Clément Stenac's avatar
Clément Stenac committed
224 225
    layout->addWidget( prevButton );
    layout->addWidget( nextButton );
Clément Stenac's avatar
Clément Stenac committed
226 227

    layout->addItem( new QSpacerItem( 40,20,
228 229
                              QSizePolicy::Expanding, QSizePolicy::Minimum ) );
    layout->addWidget( new QLabel( qtr( "Current visualization:" ) ) );
Clément Stenac's avatar
Clément Stenac committed
230 231 232 233 234 235 236

    current = new QLabel( qtr( "None" ) );
    layout->addWidget( current );

    BUTTONACT( prevButton, prev() );
    BUTTONACT( nextButton, next() );

Clément Stenac's avatar
Clément Stenac committed
237
    setLayout( layout );
238
    setMaximumHeight( 35 );
Clément Stenac's avatar
Clément Stenac committed
239 240 241 242 243 244
}

VisualSelector::~VisualSelector()
{
}

Clément Stenac's avatar
Clément Stenac committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
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 );
    }
}

/**********************************************************************
266
 * TEH controls
Clément Stenac's avatar
Clément Stenac committed
267
 **********************************************************************/
268 269 270 271 272 273

#define setupSmallButton( aButton ){  \
    aButton->setMaximumSize( QSize( 26, 26 ) ); \
    aButton->setMinimumSize( QSize( 26, 26 ) ); \
    aButton->setIconSize( QSize( 20, 20 ) ); }

274
AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
Clément Stenac's avatar
Clément Stenac committed
275 276
                                           QFrame( NULL ), p_intf( _p_i )
{
277 278 279
    QHBoxLayout *advLayout = new QHBoxLayout( this );
    advLayout->setMargin( 0 );
    advLayout->setSpacing( 0 );
Clément Stenac's avatar
Clément Stenac committed
280

281
    /* A to B Button */
282 283 284 285
    ABButton = new QPushButton( "AB" );
    ABButton->setMaximumSize( QSize( 26, 26 ) );
    ABButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( ABButton );
286
    BUTTON_SET_ACT( ABButton, "AB", qtr( "A to B" ), fromAtoB() );
287
    timeA = timeB = 0;
288 289
    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
             this, AtoBLoop( float, int, int ) );
Clément Stenac's avatar
Clément Stenac committed
290

291 292 293 294 295 296 297 298 299 300
    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() );

    recordButton = new QPushButton( "R" );
    recordButton->setMaximumSize( QSize( 26, 26 ) );
    recordButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( recordButton );
301
    BUTTON_SET_ACT_I( recordButton, "", record_16px.png,
302
            qtr( "Record" ), record() );
303

304
    /* Snapshot Button */
305 306 307 308 309
    snapshotButton = new QPushButton( "S" );
    snapshotButton->setMaximumSize( QSize( 26, 26 ) );
    snapshotButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( snapshotButton );
    BUTTON_SET_ACT( snapshotButton, "S", qtr( "Take a snapshot" ), snapshot() );
Clément Stenac's avatar
Clément Stenac committed
310 311
}

312
AdvControlsWidget::~AdvControlsWidget()
313
{}
Clément Stenac's avatar
Clément Stenac committed
314

315
void AdvControlsWidget::enableInput( bool enable )
Clément Stenac's avatar
Clément Stenac committed
316
{
317 318
    ABButton->setEnabled( enable );
    recordButton->setEnabled( enable );
Clément Stenac's avatar
Clément Stenac committed
319
}
320

321
void AdvControlsWidget::enableVideo( bool enable )
Clément Stenac's avatar
Clément Stenac committed
322 323
{
    snapshotButton->setEnabled( enable );
324
    frameButton->setEnabled( enable );
Clément Stenac's avatar
Clément Stenac committed
325 326
}

327
void AdvControlsWidget::snapshot()
Clément Stenac's avatar
Clément Stenac committed
328
{
329 330
    vout_thread_t *p_vout =
        (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
331
    if( p_vout ) vout_Control( p_vout, VOUT_SNAPSHOT );
Clément Stenac's avatar
Clément Stenac committed
332 333
}

334
/* Function called when the button is clicked() */
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
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" );
}
354

355
/* Function called regularly when in an AtoB loop */
356 357 358 359
void AdvControlsWidget::AtoBLoop( float f_pos, int i_time, int i_length )
{
    if( timeB )
    {
360
        if( i_time >= (int)(timeB/1000000) )
361 362 363
            var_SetTime( THEMIM->getInput(), "time" , timeA );
    }
}
364

365
/* FIXME Record function */
366
void AdvControlsWidget::record(){}
367 368

//FIXME Frame by frame function
369 370
void AdvControlsWidget::frame(){}

371 372 373
/*****************************
 * DA Control Widget !
 *****************************/
374
ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
375
                                MainInterface *_p_mi,
376 377
                                bool b_advControls,
                                bool b_shiny ) :
378
                                QFrame( NULL ), p_intf( _p_i )
379 380
{
    controlLayout = new QGridLayout( this );
381
    controlLayout->setSpacing( 0 );
382 383 384 385 386
#if QT43
    controlLayout->setContentsMargins( 9, 6, 9, 6 );
#else
    controlLayout->setMargin( 6 );
#endif
387 388

    setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
389

390 391
    /** The main Slider **/
    slider = new InputSlider( Qt::Horizontal, NULL );
392
    controlLayout->addWidget( slider, 0, 1, 1, 16 );
393 394
    /* Update the position when the IM has changed */
    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
395
             slider, setPosition( float, int, int ) );
396 397 398 399
    /* And update the IM, when the position has changed */
    CONNECT( slider, sliderDragged( float ),
             THEMIM->getIM(), sliderUpdate( float ) );

400
    /** Slower and faster Buttons **/
401
    slowerButton = new QPushButton;
402
    slowerButton->setFlat( true );
403
    slowerButton->setMaximumSize( QSize( 26, 20 ) );
404

405
    BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() );
406 407
    controlLayout->addWidget( slowerButton, 0, 0 );

408
    fasterButton = new QPushButton;
409
    fasterButton->setFlat( true );
410
    fasterButton->setMaximumSize( QSize( 26, 20 ) );
411

412
    BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() );
413
    controlLayout->addWidget( fasterButton, 0, 17 );
414

415 416 417 418
    /* advanced Controls handling */
    b_advancedVisible = b_advControls;

    advControls = new AdvControlsWidget( p_intf );
419
    controlLayout->addWidget( advControls, 1, 3, 2, 4, Qt::AlignBottom );
420 421
    if( !b_advancedVisible ) advControls->hide();

422
    /** Disc and Menus handling */
423
    discFrame = new QWidget( this );
424

425 426 427
    QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
    discLayout->setSpacing( 0 );
    discLayout->setMargin( 0 );
428

429
    prevSectionButton = new QPushButton( discFrame );
430
    setupSmallButton( prevSectionButton );
431 432
    discLayout->addWidget( prevSectionButton );

433
    menuButton = new QPushButton( discFrame );
434 435 436
    setupSmallButton( menuButton );
    discLayout->addWidget( menuButton );

437
    nextSectionButton = new QPushButton( discFrame );
438
    setupSmallButton( nextSectionButton );
439 440
    discLayout->addWidget( nextSectionButton );

441
    controlLayout->addWidget( discFrame, 1, 10, 2, 3, Qt::AlignBottom );
442 443 444 445 446

    BUTTON_SET_IMG( prevSectionButton, "", previous.png, "" );
    BUTTON_SET_IMG( nextSectionButton, "", next.png, "" );
    BUTTON_SET_IMG( menuButton, "", previous.png, "" );

447
    discFrame->hide();
448 449 450

    /* Change the navigation button display when the IM navigation changes */
    CONNECT( THEMIM->getIM(), navigationChanged( int ),
451
             this, setNavigation( int ) );
452 453 454 455 456 457 458
    /* 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() );
459 460
    /** TODO
     * Telextext QFrame
461
     * Merge with upper menu in a StackLayout
462
     **/
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    telexFrame = new QWidget( this );
    QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
    telexLayout->setSpacing( 0 );
    telexLayout->setMargin( 0 );

    QToolButton *telexOn = new QToolButton;
    telexOn->setText( qtr( "On" ) );
    setupSmallButton( telexOn );
    telexLayout->addWidget( telexOn );

    QToolButton *telexTransparent = new QToolButton;
    telexTransparent->setText( qtr( "Transparent" ) );
    setupSmallButton( telexTransparent );
    telexLayout->addWidget( telexTransparent );

    QSpinBox *telexPage = new QSpinBox;
    telexPage->setRange( 0, 999 );
    telexPage->setAlignment( Qt::AlignRight );
    telexLayout->addWidget( telexPage );

    controlLayout->addWidget( telexFrame, 1, 10, 2, 3, Qt::AlignBottom );
    telexFrame->hide();

    CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
             telexGotoPage( int ) );
    CONNECT( telexOn, clicked( bool ), THEMIM->getIM(),
             telexToggle( bool ) );
    CONNECT( telexTransparent, clicked( bool ),
             THEMIM->getIM(), telexSetTransparency( bool ) );
    CONNECT( THEMIM->getIM(), teletextEnabled( bool ),
             telexFrame, setVisible( bool ) );
494

495
    /** Play Buttons **/
496
    QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
497 498 499 500
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );

    /* Play */
501
    playButton = new QPushButton;
502
    playButton->setSizePolicy( sizePolicy );
503 504
    playButton->setMaximumSize( QSize( 36, 36 ) );
    playButton->setMinimumSize( QSize( 36, 36 ) );
505
    playButton->setIconSize( QSize( 30, 30 ) );
506

507
    controlLayout->addWidget( playButton, 2, 0, 2, 2 );
508

509 510
    controlLayout->setColumnMinimumWidth( 2, 20 );
    controlLayout->setColumnStretch( 2, 0 );
511 512 513 514 515 516 517 518

    /** Prev + Stop + Next Block **/
    QHBoxLayout *controlButLayout = new QHBoxLayout;
    controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */

    /* Prev */
    QPushButton *prevButton = new QPushButton;
    prevButton->setSizePolicy( sizePolicy );
519
    setupSmallButton( prevButton );
520 521 522 523 524 525

    controlButLayout->addWidget( prevButton );

    /* Stop */
    QPushButton *stopButton = new QPushButton;
    stopButton->setSizePolicy( sizePolicy );
526
    setupSmallButton( stopButton );
527 528 529 530 531 532

    controlButLayout->addWidget( stopButton );

    /* next */
    QPushButton *nextButton = new QPushButton;
    nextButton->setSizePolicy( sizePolicy );
533
    setupSmallButton( nextButton );
534 535 536 537

    controlButLayout->addWidget( nextButton );

    /* Add this block to the main layout */
538
    controlLayout->addLayout( controlButLayout, 3, 3, 1, 3, Qt::AlignBottom );
539

540
    BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() );
541
    BUTTON_SET_ACT_I( prevButton, "" , previous.png,
542 543 544
                      qtr( "Previous" ), prev() );
    BUTTON_SET_ACT_I( nextButton, "", next.png, qtr( "Next" ), next() );
    BUTTON_SET_ACT_I( stopButton, "", stop.png, qtr( "Stop" ), stop() );
545

546 547 548 549
    controlLayout->setColumnMinimumWidth( 7, 20 );
    controlLayout->setColumnStretch( 7, 0 );
    controlLayout->setColumnStretch( 8, 0 );
    controlLayout->setColumnStretch( 9, 0 );
550

551 552 553
    /*
     * Other first Line buttons
     */
554 555 556
    /** Fullscreen/Visualisation **/
    fullscreenButton = new QPushButton( "F" );
    BUTTON_SET_ACT( fullscreenButton, "F", qtr( "Fullscreen" ), fullscreen() );
557
    setupSmallButton( fullscreenButton );
558
    controlLayout->addWidget( fullscreenButton, 3, 10, Qt::AlignBottom );
559

560 561
    /** Playlist Button **/
    playlistButton = new QPushButton;
562
    setupSmallButton( playlistButton );
563
    controlLayout->addWidget( playlistButton, 3, 11, Qt::AlignBottom );
564
    BUTTON_SET_IMG( playlistButton, "" , playlist.png, qtr( "Show playlist" ) );
565
    CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
566 567 568

    /** extended Settings **/
    QPushButton *extSettingsButton = new QPushButton( "F" );
569
    BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended Settings" ),
570
            extSettings() );
571
    setupSmallButton( extSettingsButton );
572
    controlLayout->addWidget( extSettingsButton, 3, 12, Qt::AlignBottom );
573

574
    controlLayout->setColumnStretch( 13, 0 );
575
    controlLayout->setColumnMinimumWidth( 13, 24 );
576
    controlLayout->setColumnStretch( 14, 5 );
577

578
    /* Volume */
579
    VolumeClickHandler *hVolLabel = new VolumeClickHandler( p_intf, this );
580

581
    volMuteLabel = new QLabel;
582
    volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
583
    volMuteLabel->setToolTip( qtr( "Mute" ) );
584
    volMuteLabel->installEventFilter( hVolLabel );
585
    controlLayout->addWidget( volMuteLabel, 3, 15, Qt::AlignBottom );
586

587 588 589
    if( b_shiny )
    {
        volumeSlider = new SoundSlider( this,
590 591
            config_GetInt( p_intf, "volume-step" ),
            config_GetInt( p_intf, "qt-volume-complete" ) );
592 593 594 595 596 597
    }
    else
    {
        volumeSlider = new QSlider( this );
        volumeSlider->setOrientation( Qt::Horizontal );
    }
598
    volumeSlider->setMaximumSize( QSize( 200, 40 ) );
599
    volumeSlider->setMinimumSize( QSize( 106, 30 ) );
600
    volumeSlider->setFocusPolicy( Qt::NoFocus );
601
    controlLayout->addWidget( volumeSlider, 2, 16, 2 , 2, Qt::AlignBottom );
602

603
    /* Set the volume from the config */
604 605
    volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
                              VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
606 607

    /* Volume control connection */
608
    //resize( QSize( 300, 60 ) );
609
    CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
610
    msg_Dbg( p_intf, "controls size: %i - %i", size().width(), size().height() );
611
}
612

613
ControlsWidget::~ControlsWidget()
614
{}
615

616
/*
617 618 619 620
QSize ControlsWidget::sizeHint() const
{
    return QSize( 300, 50 );
}
621
*/
622

623 624 625 626 627 628 629
void ControlsWidget::stop()
{
    THEMIM->stop();
}

void ControlsWidget::play()
{
630
    if( THEPL->current.i_size == 0 )
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
    {
        /* 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 )
{
652 653 654 655 656
#define HELP_MENU N_( "Menu" )
#define HELP_PCH N_( "Previous chapter" )
#define HELP_NCH N_( "Next chapter" )
#define HELP_PTR N_( "Previous track" )
#define HELP_NTR N_( "Next track" )
657 658 659 660 661 662

    // 1 = chapter, 2 = title, 0 = no
    if( navigation == 0 )
    {
        discFrame->hide();
    } else if( navigation == 1 ) {
663 664
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
665 666 667
        menuButton->show();
        discFrame->show();
    } else {
668 669
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
670 671 672 673 674 675
        menuButton->hide();
        discFrame->show();
    }
}

static bool b_my_volume;
676
void ControlsWidget::updateVolume( int i_sliderVolume )
677 678 679
{
    if( !b_my_volume )
    {
680
        int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
681 682
        aout_VolumeSet( p_intf, i_res );
    }
683 684
    if( i_sliderVolume == 0 )
        volMuteLabel->setPixmap( QPixmap(":/pixmaps/volume-muted.png" ) );
685
    else if( i_sliderVolume < VOLUME_MAX / 2 )
686 687
        volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) );
    else volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
688 689 690 691
}

void ControlsWidget::updateOnTimer()
{
692
    /* Audio part */
693 694
    audio_volume_t i_volume;
    aout_VolumeGet( p_intf, &i_volume );
695
    i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
696 697 698 699 700 701 702 703
    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;
    }
704

705
    /* Activate the interface buttons according to the presence of the input */
706
    enableInput( THEMIM->getIM()->hasInput() );
707
    //enableVideo( THEMIM->getIM()->hasVideo() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
708
    enableVideo( true );
709
}
710

711 712
void ControlsWidget::setStatus( int status )
{
713 714
    if( status == PLAYING_S ) // Playing
        playButton->setIcon( QIcon( ":/pixmaps/pause.png" ) );
715
    else
716
        playButton->setIcon( QIcon( ":/pixmaps/play.png" ) );
717
}
718

719 720
/**
 * TODO
721
 * This functions toggle the fullscreen mode
722
 * If there is no video, it should first activate Visualisations...
723
 *  This has also to be fixed in enableVideo()
724
 */
Clément Stenac's avatar
Clément Stenac committed
725 726
void ControlsWidget::fullscreen()
{
727 728
    vout_thread_t *p_vout =
        (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
729
    if( p_vout)
730
    {
731
        var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
732
        vlc_object_release( p_vout );
733
    }
734 735 736 737 738 739
}

void ControlsWidget::extSettings()
{
    THEDP->extendedDialog();
}
Clément Stenac's avatar
Clément Stenac committed
740

741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
void ControlsWidget::slower()
{
    THEMIM->getIM()->slower();
}

void ControlsWidget::faster()
{
    THEMIM->getIM()->faster();
}

void ControlsWidget::enableInput( bool enable )
{
    slowerButton->setEnabled( enable );
    slider->setEnabled( enable );
    fasterButton->setEnabled( enable );
756 757 758

    /* Advanced Buttons too */
    advControls->enableInput( enable );
759 760
}

761
void ControlsWidget::enableVideo( bool enable )
762
{
763 764
    // TODO Later make the fullscreenButton toggle Visualisation and so on.
    fullscreenButton->setEnabled( enable );
765 766 767

    /* Advanced Buttons too */
    advControls->enableVideo( enable );
768 769
}

770 771 772 773 774 775 776 777 778 779 780 781
void ControlsWidget::toggleAdvanced()
{
    if( !VISIBLE( advControls ) )
    {
        advControls->show();
        b_advancedVisible = true;
    }
    else
    {
        advControls->hide();
        b_advancedVisible = false;
    }
782
    emit advancedControlsToggled( b_advancedVisible );
783
}
784

785

786 787 788 789 790
/**********************************************************************
 * Speed control widget
 **********************************************************************/
SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i ) :
                             QFrame( NULL ), p_intf( _p_i )
791
{
792
    QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
793 794
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );
795

796 797 798 799 800 801
    speedSlider = new QSlider;
    speedSlider->setSizePolicy( sizePolicy );
    speedSlider->setMaximumSize( QSize( 80, 200 ) );
    speedSlider->setOrientation( Qt::Vertical );
    speedSlider->setTickPosition( QSlider::TicksRight );

802
    speedSlider->setRange( -100, 100 );
803 804 805
    speedSlider->setSingleStep( 10 );
    speedSlider->setPageStep( 20 );
    speedSlider->setTickInterval( 20 );
806

807
    CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
808

809 810
    normalSpeedButton = new QPushButton( "N" );
    normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
811 812
    normalSpeedButton->setFlat( true );
    normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
813

814
    CONNECT( normalSpeedButton, clicked(), this, resetRate() );
815

816
    QVBoxLayout *speedControlLayout = new QVBoxLayout;
817 818 819
    speedControlLayout->addWidget(speedSlider);
    speedControlLayout->addWidget(normalSpeedButton);
    setLayout(speedControlLayout);
820 821 822
}

SpeedControlWidget::~SpeedControlWidget()
823
{}
824

825 826 827
#define RATE_SLIDER_MAXIMUM 3.0
#define RATE_SLIDER_MINIMUM 0.3
#define RATE_SLIDER_LENGTH 100.0
828 829 830

void SpeedControlWidget::updateControls( int rate )
{
831 832 833 834 835
    if( speedSlider->isSliderDown() )
    {
        //We don't want to change anything if the user is using the slider
        return;
    }
836

837 838
    int sliderValue;
    double speed = INPUT_RATE_DEFAULT / (double)rate;
839

840
    if( rate >= INPUT_RATE_DEFAULT )
841
    {
842 843 844 845 846 847 848
        if( speed < RATE_SLIDER_MINIMUM )
        {
            sliderValue = speedSlider->minimum();
        }
        else
        {
            sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
849
                                        / ( 1.0 - RATE_SLIDER_MAXIMUM ) );
850 851 852 853 854 855 856 857 858 859 860
        }
    }
    else
    {
        if( speed > RATE_SLIDER_MAXIMUM )
        {
            sliderValue = speedSlider->maximum();
        }
        else
        {
            sliderValue = (int)( ( speed - 1.0 ) * RATE_SLIDER_LENGTH
861
                                        / ( RATE_SLIDER_MAXIMUM - 1.0 ) );
862 863
        }
    }
864

865 866 867 868
    //Block signals to avoid feedback loop
    speedSlider->blockSignals( true );
    speedSlider->setValue( sliderValue );
    speedSlider->blockSignals( false );
869 870 871 872
}

void SpeedControlWidget::updateRate( int sliderValue )
{
873
    int rate;
874

875 876 877
    if( sliderValue < 0.0 )
    {
        rate = INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
878
            ( sliderValue * ( 1.0 - RATE_SLIDER_MINIMUM ) + RATE_SLIDER_LENGTH );
879 880 881
    }
    else
    {
882
        rate = INPUT_RATE_DEFAULT* RATE_SLIDER_LENGTH /
883
            ( sliderValue * ( RATE_SLIDER_MAXIMUM - 1.0 ) + RATE_SLIDER_LENGTH );
884
    }
885

886
    THEMIM->getIM()->setRate(rate);
887 888 889 890
}

void SpeedControlWidget::resetRate()
{
891
    THEMIM->getIM()->setRate(INPUT_RATE_DEFAULT);
892
}