interface_widgets.cpp 26 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 11 12 13
 *
 * 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
14
 * ( at your option ) any later version.
15 16 17 18 19 20 21 22 23 24 25
 *
 * 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.
 *****************************************************************************/

26
#include "dialogs_provider.hpp"
27
#include "qt4.hpp"
28
#include "components/interface_widgets.hpp"
29
#include "main_interface.hpp"
30
#include "input_manager.hpp"
31

32
#include "util/input_slider.hpp"
Clément Stenac's avatar
Clément Stenac committed
33
#include <vlc_vout.h>
34

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

44
#define ICON_SIZE 300
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
    CONNECT( this, askResize(), this, SetMinSize() );
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    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
{
85
    return widgetSize;
86 87
}

88
void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
89 90 91 92 93 94 95 96
                           unsigned int *pi_width, unsigned int *pi_height )
{
    if( p_vout )
    {
        msg_Dbg( p_intf, "embedded video already in use" );
        return NULL;
    }
    p_vout = p_nvout;
97
    emit askResize();
98
    return ( void* )winId();
99 100
}

101 102 103 104 105
void VideoWidget::SetMinSize()
{
    setMinimumSize( 16, 16 );
}

106
void VideoWidget::release( void *p_win )
107
{
108
    p_vout = NULL;
109
}
110 111 112 113 114 115 116
/**********************************************************************
 * Background Widget. Show a simple image background. Currently,
 * it's a static cone.
 **********************************************************************/
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i ) :
                                        QFrame( NULL ), p_intf( _p_i )
{
117

Clément Stenac's avatar
Clément Stenac committed
118
    setAutoFillBackground( true );
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    plt =  palette();
    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
    setPalette( plt );

    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 );
}

Clément Stenac's avatar
Clément Stenac committed
134
BackgroundWidget::~BackgroundWidget()
135
{
136
    backgroundLayout->takeAt( 0 );
137 138 139
    delete backgroundLayout;
}

140 141 142 143 144 145 146 147
void BackgroundWidget::setArt( QString url )
{
    if( url.isNull() )
        label->setPixmap( QPixmap( ":/vlc128.png" ) );
    else
        label->setPixmap( QPixmap( url ) );
}

148 149 150 151 152
QSize BackgroundWidget::sizeHint() const
{
    return widgetSize;
}

153 154 155 156 157 158 159
void BackgroundWidget::resizeEvent( QResizeEvent *e )
{
    if( e->size().height() < ICON_SIZE -1 )
        label->setMaximumWidth( e->size().height() );
    else
        label->setMaximumWidth( ICON_SIZE );
}
160

Clément Stenac's avatar
Clément Stenac committed
161 162 163 164 165 166 167
/**********************************************************************
 * Visualization selector panel
 **********************************************************************/
VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
                                                QFrame( NULL ), p_intf( _p_i )
{
    QHBoxLayout *layout = new QHBoxLayout( this );
168
    layout->setMargin( 0 );
Clément Stenac's avatar
Clément Stenac committed
169
    QPushButton *prevButton = new QPushButton( "Prev" );
170
    QPushButton *nextButton = new QPushButton( "Next" );
Clément Stenac's avatar
Clément Stenac committed
171 172
    layout->addWidget( prevButton );
    layout->addWidget( nextButton );
Clément Stenac's avatar
Clément Stenac committed
173 174

    layout->addItem( new QSpacerItem( 40,20,
175 176
                              QSizePolicy::Expanding, QSizePolicy::Minimum ) );
    layout->addWidget( new QLabel( qtr( "Current visualization:" ) ) );
Clément Stenac's avatar
Clément Stenac committed
177 178 179 180 181 182 183

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

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

Clément Stenac's avatar
Clément Stenac committed
184
    setLayout( layout );
185
    setMaximumHeight( 35 );
Clément Stenac's avatar
Clément Stenac committed
186 187 188 189 190 191
}

VisualSelector::~VisualSelector()
{
}

Clément Stenac's avatar
Clément Stenac committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
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 );
    }
}

/**********************************************************************
213
 * TEH controls
Clément Stenac's avatar
Clément Stenac committed
214
 **********************************************************************/
215 216 217 218 219 220

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

221
AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
Clément Stenac's avatar
Clément Stenac committed
222 223
                                           QFrame( NULL ), p_intf( _p_i )
{
224 225 226
    QHBoxLayout *advLayout = new QHBoxLayout( this );
    advLayout->setMargin( 0 );
    advLayout->setSpacing( 0 );
Clément Stenac's avatar
Clément Stenac committed
227

228 229 230 231 232
/* FIXME A to B function */
    ABButton = new QPushButton( "AB" );
    ABButton->setMaximumSize( QSize( 26, 26 ) );
    ABButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( ABButton );
233
    BUTTON_SET_ACT( ABButton, "AB", qtr( "A to B" ), fromAtoB() );
Clément Stenac's avatar
Clément Stenac committed
234 235

    snapshotButton = new QPushButton( "S" );
236 237 238
    snapshotButton->setMaximumSize( QSize( 26, 26 ) );
    snapshotButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( snapshotButton );
239
    BUTTON_SET_ACT( snapshotButton, "S", qtr( "Take a snapshot" ), snapshot() );
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260

//FIXME Frame by frame function
    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() );

/* FIXME Record function */
    recordButton = new QPushButton( "R" );
    recordButton->setMaximumSize( QSize( 26, 26 ) );
    recordButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( recordButton );
    BUTTON_SET_ACT( recordButton, "R", qtr( "Record" ), record() );

    normalButton = new QPushButton( "N" );
    normalButton->setMaximumSize( QSize( 26, 26 ) );
    normalButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( normalButton );
    BUTTON_SET_ACT( normalButton, "N", qtr( "Normal rate" ), normal() );

Clément Stenac's avatar
Clément Stenac committed
261 262
}

263
AdvControlsWidget::~AdvControlsWidget()
Clément Stenac's avatar
Clément Stenac committed
264 265 266
{
}

267
void AdvControlsWidget::enableInput( bool enable )
Clément Stenac's avatar
Clément Stenac committed
268
{
269 270
    ABButton->setEnabled( enable );
    recordButton->setEnabled( enable );
Clément Stenac's avatar
Clément Stenac committed
271 272
    normalButton->setEnabled( enable );
}
273
void AdvControlsWidget::enableVideo( bool enable )
Clément Stenac's avatar
Clément Stenac committed
274 275
{
    snapshotButton->setEnabled( enable );
276
    frameButton->setEnabled( enable );
Clément Stenac's avatar
Clément Stenac committed
277 278
}

279
void AdvControlsWidget::normal()
Clément Stenac's avatar
Clément Stenac committed
280 281 282 283
{
    THEMIM->getIM()->normalRate();
}

284
void AdvControlsWidget::snapshot()
Clément Stenac's avatar
Clément Stenac committed
285
{
286 287
    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 );
Clément Stenac's avatar
Clément Stenac committed
288 289
}

290
void AdvControlsWidget::frame(){}
291
void AdvControlsWidget::fromAtoB(){}
292 293 294 295 296 297
void AdvControlsWidget::record(){}

/*****************************
 * DA Control Widget !
 *****************************/
ControlsWidget::ControlsWidget( intf_thread_t *_p_i, bool b_advControls ) :
298 299 300 301 302
                             QFrame( NULL ), p_intf( _p_i )
{
    //QSize size( 500, 200 );
    //resize( size );
    controlLayout = new QGridLayout( this );
303

304
#if DEBUG_COLOR
305 306 307 308
    QPalette palette2;
    palette2.setColor(this->backgroundRole(), Qt::magenta);
    setPalette(palette2);
#endif
309 310 311

    /** The main Slider **/
    slider = new InputSlider( Qt::Horizontal, NULL );
312
    controlLayout->addWidget( slider, 0, 1, 1, 16 );
313 314 315 316 317 318 319
    /* 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 ) );

320 321
    /** Slower and faster Buttons **/
    slowerButton = new QPushButton( "S" );
322
    BUTTON_SET_ACT( slowerButton, "S", qtr( "Slower" ), slower() );
323
    controlLayout->addWidget( slowerButton, 0, 0 );
324
    slowerButton->setMaximumSize( QSize( 26, 20 ) );
325 326

    fasterButton = new QPushButton( "F" );
327
    BUTTON_SET_ACT( fasterButton, "F", qtr( "Faster" ), faster() );
328
    controlLayout->addWidget( fasterButton, 0, 17 );
329
    fasterButton->setMaximumSize( QSize( 26, 20 ) );
330

331 332 333
    /** TODO: Insert here the AdvControls Widget 
     * Then fix all the size issues in main_interface.cpp
     **/
334 335 336 337 338 339
    /* advanced Controls handling */
    b_advancedVisible = b_advControls;

    advControls = new AdvControlsWidget( p_intf );
    controlLayout->addWidget( advControls, 1, 3, 2, 5, Qt::AlignBottom );
    if( !b_advancedVisible ) advControls->hide();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
340
    //THIS should be removed.    need_components_update = true;
341

342 343 344
    /** Disc and Menus handling */
    discFrame = new QFrame( this );

345 346 347
    QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
    discLayout->setSpacing( 0 );
    discLayout->setMargin( 0 );
348

349
    prevSectionButton = new QPushButton( discFrame );
350
    setupSmallButton( prevSectionButton );
351 352
    discLayout->addWidget( prevSectionButton );

353
    menuButton = new QPushButton( discFrame );
354 355 356
    setupSmallButton( menuButton );
    discLayout->addWidget( menuButton );

357
    nextSectionButton = new QPushButton( discFrame );
358
    setupSmallButton( nextSectionButton );
359 360
    discLayout->addWidget( nextSectionButton );

361
    controlLayout->addWidget( discFrame, 1, 10, 2, 3, Qt::AlignBottom );
362 363 364 365 366

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

367
    discFrame->hide();
368 369 370

    /* Change the navigation button display when the IM navigation changes */
    CONNECT( THEMIM->getIM(), navigationChanged( int ),
371
             this, setNavigation( int ) );
372 373 374 375 376 377 378 379
    /* 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() );

380 381 382 383
    /** TODO
     * Telextext QFrame
     **/

384 385 386 387 388 389
    /** Play Buttons **/
    QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );

    /* Play */
390
    playButton = new QPushButton;
391
    playButton->setSizePolicy( sizePolicy );
392 393
    playButton->setMaximumSize( QSize( 45, 45 ) );
    playButton->setIconSize( QSize( 30, 30 ) );
394

395
    controlLayout->addWidget( playButton, 2, 0, 2, 2, Qt::AlignBottom );
396 397 398
    
    controlLayout->setColumnMinimumWidth( 2, 20 );
    controlLayout->setColumnStretch( 2, 0 );
399 400 401 402 403 404 405 406

    /** 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 );
407
    setupSmallButton( prevButton );
408 409 410 411 412 413

    controlButLayout->addWidget( prevButton );

    /* Stop */
    QPushButton *stopButton = new QPushButton;
    stopButton->setSizePolicy( sizePolicy );
414
    setupSmallButton( stopButton );
415 416 417 418 419 420

    controlButLayout->addWidget( stopButton );

    /* next */
    QPushButton *nextButton = new QPushButton;
    nextButton->setSizePolicy( sizePolicy );
421
    setupSmallButton( nextButton );
422 423 424 425 426 427

    controlButLayout->addWidget( nextButton );

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

428
    BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() );
429
    BUTTON_SET_ACT_I( prevButton, "" , previous.png,
430 431 432
                      qtr( "Previous" ), prev() );
    BUTTON_SET_ACT_I( nextButton, "", next.png, qtr( "Next" ), next() );
    BUTTON_SET_ACT_I( stopButton, "", stop.png, qtr( "Stop" ), stop() );
433

434 435 436
    controlLayout->setColumnStretch( 8 , 10 );
    controlLayout->setColumnStretch( 9, 0 );
    
437 438 439 440 441
    /*
     * Other first Line buttons
     * Might need to be inside a frame to avoid a few resizing pb
     * FIXME
     */
442 443 444
    /** Fullscreen/Visualisation **/
    fullscreenButton = new QPushButton( "F" );
    BUTTON_SET_ACT( fullscreenButton, "F", qtr( "Fullscreen" ), fullscreen() );
445
    setupSmallButton( fullscreenButton );
446
    controlLayout->addWidget( fullscreenButton, 3, 10 );
447

448 449
    /** Playlist Button **/
    playlistButton = new QPushButton;
450
    setupSmallButton( playlistButton );
451
    controlLayout->addWidget( playlistButton, 3, 11 );
452 453 454

    /** extended Settings **/
    QPushButton *extSettingsButton = new QPushButton( "F" );
455
    BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended Settings" ),
456
            extSettings() );
457
    setupSmallButton( extSettingsButton );
458 459 460 461
    controlLayout->addWidget( extSettingsButton, 3, 12 );

    /** Preferences **/
    QPushButton *prefsButton = new QPushButton( "P" );
462 463 464
    BUTTON_SET_ACT( prefsButton, "P", qtr( "Preferences / Settings" ),
            prefs() );
    setupSmallButton( prefsButton );
465
    controlLayout->addWidget( prefsButton, 3, 13 );
466

467
    controlLayout->setColumnStretch( 14, 5 );
468 469 470 471

    /* Volume */
    VolumeClickHandler *h = new VolumeClickHandler( p_intf, this );

472
    volMuteLabel = new QLabel;
473
    volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
474
    volMuteLabel->setToolTip( qtr( "Mute" ) );
475
    volMuteLabel->installEventFilter( h );
476

477
    /** TODO:
478 479 480 481 482 483 484
     * Change this slider to use a nice Amarok-like one 
     * Add a Context menu to change to the most useful %
     * **/
    /** FIXME
     *  THis percerntage thing has to be handled correctly
     *  This has to match to the OSD
     **/
485 486
    volumeSlider = new QSlider;
    volumeSlider->setSizePolicy( sizePolicy );
487
    volumeSlider->setMaximumSize( QSize( 80, 200 ) );
488 489
    volumeSlider->setOrientation( Qt::Horizontal );

490
    volumeSlider->setMaximum( VOLUME_MAX );
491
    volumeSlider->setFocusPolicy( Qt::NoFocus );
492 493
    controlLayout->addWidget( volMuteLabel, 3, 15 );
    controlLayout->addWidget( volumeSlider, 3, 16, 1, 2 );
494 495 496 497 498 499 500 501 502 503 504 505 506 507

    /* Volume control connection */
    CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
}
ControlsWidget::~ControlsWidget()
{
}
void ControlsWidget::stop()
{
    THEMIM->stop();
}

void ControlsWidget::play()
{
508
    if( THEPL )
509
        msg_Dbg( p_intf, "There is %i playlist items", THEPL->items.i_size ); /* FIXME: remove me */
510
    if( playlist_IsEmpty( THEPL ) )
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
    {
        /* 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 )
{
532 533 534 535 536
#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" )
537 538 539 540 541 542

    // 1 = chapter, 2 = title, 0 = no
    if( navigation == 0 )
    {
        discFrame->hide();
    } else if( navigation == 1 ) {
543 544
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
545 546 547
        menuButton->show();
        discFrame->show();
    } else {
548 549
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
550 551 552 553 554 555
        menuButton->hide();
        discFrame->show();
    }
}

static bool b_my_volume;
556
void ControlsWidget::updateVolume( int i_sliderVolume )
557 558 559
{
    if( !b_my_volume )
    {
560
        int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
561 562
        aout_VolumeSet( p_intf, i_res );
    }
563 564
    if( i_sliderVolume == 0 )
        volMuteLabel->setPixmap( QPixmap(":/pixmaps/volume-muted.png" ) );
565
    else if( i_sliderVolume < VOLUME_MAX / 2 )
566 567
        volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) );
    else volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
568 569 570 571
}

void ControlsWidget::updateOnTimer()
{
572
    /* Audio part */
573 574
    audio_volume_t i_volume;
    aout_VolumeGet( p_intf, &i_volume );
575
    i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2) ;
576 577 578 579 580 581 582 583
    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;
    }
584
    
585
    /* Activate the interface buttons according to the presence of the input */
586
    enableInput( THEMIM->getIM()->hasInput() );
587
    //enableVideo( THEMIM->getIM()->hasVideo() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
588
    enableVideo( true );
589
}
590

591 592
void ControlsWidget::setStatus( int status )
{
593 594
    if( status == PLAYING_S ) // Playing
        playButton->setIcon( QIcon( ":/pixmaps/pause.png" ) );
595
    else
596
        playButton->setIcon( QIcon( ":/pixmaps/play.png" ) );
597
}
598

599 600
/**
 * TODO
601
 * This functions toggle the fullscreen mode
602 603
 * If there is no video, it should first activate Visualisations... 
 *  This has also to be fixed in enableVideo()
604
 */
Clément Stenac's avatar
Clément Stenac committed
605 606
void ControlsWidget::fullscreen()
{
607
    vout_thread_t *p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
608
    if( p_vout)
609
    {
610
        var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
611
        vlc_object_release( p_vout );
612
    }
613 614 615 616 617 618 619 620 621
}

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

624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
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 );
639 640 641

    /* Advanced Buttons too */
    advControls->enableInput( enable );
642 643
}

644
void ControlsWidget::enableVideo( bool enable )
645
{
646 647
    // TODO Later make the fullscreenButton toggle Visualisation and so on.
    fullscreenButton->setEnabled( enable );
648 649 650

    /* Advanced Buttons too */
    advControls->enableVideo( enable );
651 652
}

653 654 655 656 657 658 659 660 661 662 663 664 665
void ControlsWidget::toggleAdvanced()
{
    if( !VISIBLE( advControls ) )
    {
        advControls->show();
        b_advancedVisible = true;
    }
    else
    {
        advControls->hide();
        b_advancedVisible = false;
    }
    //FIXME connect this one :D
666
    emit advancedControlsToggled( b_advancedVisible );  //  doComponentsUpdate();
667
}
668

669 670 671 672 673 674
/**********************************************************************
 * Playlist Widget. The embedded playlist
 **********************************************************************/
#include "components/playlist/panels.hpp"
#include "components/playlist/selector.hpp"

675 676
PlaylistWidget::PlaylistWidget( intf_thread_t *_p_i ) :
                                p_intf ( _p_i )
677
{
678 679 680
    /* Left Part and design */
    QWidget *leftW = new QWidget( this );
    QVBoxLayout *left = new QVBoxLayout( leftW );
Clément Stenac's avatar
Clément Stenac committed
681

682
    /* Source Selector */
683
    selector = new PLSelector( this, p_intf, THEPL );
Clément Stenac's avatar
Clément Stenac committed
684 685
    left->addWidget( selector );

686
    /* Art label */
687
    art = new QLabel( "" );
688 689
    art->setMinimumHeight( 128 );
    art->setMinimumWidth( 128 );
Clément Stenac's avatar
Clément Stenac committed
690 691 692
    art->setMaximumHeight( 128 );
    art->setMaximumWidth( 128 );
    art->setScaledContents( true );
693
    art->setPixmap( QPixmap( ":/noart.png" ) );
Clément Stenac's avatar
Clément Stenac committed
694
    left->addWidget( art );
695

696
    /* Initialisation of the playlist */
697 698 699
    playlist_item_t *p_root = playlist_GetPreferredNode( THEPL,
                                                THEPL->p_local_category );

700
    rightPanel = qobject_cast<PLPanel *>( new StandardPLPanel( this,
701 702
                              p_intf, THEPL, p_root ) );

703
    /* Connects */
704
    CONNECT( selector, activated( int ), rightPanel, setRoot( int ) );
705

706
    CONNECT( qobject_cast<StandardPLPanel *>( rightPanel )->model,
Clément Stenac's avatar
Clément Stenac committed
707 708
             artSet( QString ) , this, setArt( QString ) );
    /* Forward removal requests from the selector to the main panel */
709
    CONNECT( qobject_cast<PLSelector *>( selector )->model,
Clément Stenac's avatar
Clément Stenac committed
710
             shouldRemove( int ),
711
             qobject_cast<StandardPLPanel *>( rightPanel ), removeItem( int ) );
712

713
    connect( selector, SIGNAL( activated( int ) ),
714 715
             this, SIGNAL( rootChanged( int ) ) );
    emit rootChanged( p_root->i_id );
716

717 718 719 720
    /* Add the two sides of the QSplitter */
    addWidget( leftW );
    addWidget( rightPanel );

721 722 723 724 725 726
    leftW->setMaximumWidth( 250 );
    setCollapsible( 1, false );

    QList<int> sizeList;
    sizeList << 180 << 520 ;
    setSizes( sizeList );
727 728
}

729 730
void PlaylistWidget::setArt( QString url )
{
731 732 733
    if( url.isNull() )
        art->setPixmap( QPixmap( ":/noart.png" ) );
    else if( prevArt != url )
Clément Stenac's avatar
Clément Stenac committed
734
        art->setPixmap( QPixmap( url ) );
735
    prevArt = url;
736
    emit artSet( url );
737 738
}

739 740 741 742 743 744 745 746 747
PlaylistWidget::~PlaylistWidget()
{
}

QSize PlaylistWidget::sizeHint() const
{
    return widgetSize;
}

748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
/**********************************************************************
 * 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->setFocusPolicy( Qt::NoFocus );

    speedSlider->setMinimum( -100 );
    speedSlider->setMaximum( 100 );
    speedSlider->setSingleStep( 10 );
    speedSlider->setPageStep( 20 );
    speedSlider->setTickInterval( 20 );
    
    CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
    
    //QWidgetAction *wa = new QWidgetAction( this );
    //wa->setDefaultWidget( playSpeedSlider );
    //menu.addAction( wa ); 
	
    normalSpeedButton = new QPushButton( "N" );
    //BUTTON_SET_ACT( revertToNormalButton, "N", qtr( "Normal" ), slower() );
    //controlLayout->addWidget( revertToNormalButton, 0, 0 );
    normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
    normalSpeedButton->setFlat(true);
    
    CONNECT( normalSpeedButton, clicked(), this, resetRate() );
    
    QLabel *volMuteLabel = new QLabel("N");
    //volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) );
    volMuteLabel->setToolTip( qtr( "Revert to normal play speed" ) );
    //volMuteLabel->installEventFilter( h );
    
    
    QVBoxLayout *speedControlLayout = new QVBoxLayout;
	speedControlLayout->addWidget(speedSlider);
	speedControlLayout->addWidget(normalSpeedButton);
	//speedControlLayout->addWidget(volMuteLabel);
	setLayout(speedControlLayout);
}

SpeedControlWidget::~SpeedControlWidget()
{
}

#define RATE_SLIDER_CONSTANT 3.0

#define SLIDER_MIN_SPEED 1.0 / RATE_SLIDER_CONSTANT
#define SLIDER_SLOW_RANGE 1.0 - SLIDER_MIN_SPEED
#define SLIDER_MAX_SPEED RATE_SLIDER_CONSTANT
#define SLIDER_FAST_RANGE 1.0 - SLIDER_MAX_SPEED

void SpeedControlWidget::updateControls( int rate )
{
	if( speedSlider->isSliderDown() )
	{
		//We don't want to change anything if the user is using the slider
		return;
	}
	
	int sliderValue;
	double speed = INPUT_RATE_DEFAULT / (double)rate;
	
	if( rate >= INPUT_RATE_DEFAULT )
	{		
		if( speed < SLIDER_MIN_SPEED )
		{
			sliderValue = speedSlider->minimum();
		}
		else
		{
			double currPos = speed / (double)(SLIDER_SLOW_RANGE);
			sliderValue = (int)( currPos * speedSlider->minimum() );
		}
	}
	else
	{
		if( speed > SLIDER_MAX_SPEED )
		{
			sliderValue = speedSlider->maximum();
		}
		else
		{
			double currPos = ( 1.0 - speed ) / (double)(SLIDER_FAST_RANGE);
			sliderValue = (int)( currPos * speedSlider->maximum() );
		}
	}
	
	//Block signals to avoid feedback loop
	speedSlider->blockSignals(true);
	speedSlider->setValue(sliderValue);
	speedSlider->blockSignals(false);
}

void SpeedControlWidget::updateRate( int sliderValue )
{
	int rate;
	double var;
	
	if( sliderValue < 0.0 )
	{
		var = 1.0 + ((-sliderValue/100.0) * RATE_SLIDER_CONSTANT-1.0);
		rate = INPUT_RATE_DEFAULT * var;
	}
	else
	{
		var = 1.0 + ((sliderValue/100.0) * RATE_SLIDER_CONSTANT-1.0);
		rate = INPUT_RATE_DEFAULT / var;
	}

    THEMIM->getIM()->setRate(rate);	
}

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