interface_widgets.cpp 20.8 KB
Newer Older
1
/*****************************************************************************
2
 * interface_widgets.cpp : Custom widgets for the main interface
3
 ****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2006-2010 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
 *
 * 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

27 28 29
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
30

31
#include "qt4.hpp"
32
#include "components/interface_widgets.hpp"
33 34
#include "dialogs_provider.hpp"
#include "util/customwidgets.hpp"               // qtEventToVLCKey, QVLCStackedWidget
35 36 37 38

#include "menus.hpp"             /* Popup menu on bgWidget */

#include <vlc_vout.h>
39

Clément Stenac's avatar
Clément Stenac committed
40
#include <QLabel>
41
#include <QToolButton>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
42
#include <QPalette>
43
#include <QEvent>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
44
#include <QResizeEvent>
45
#include <QDate>
46 47
#include <QMenu>
#include <QWidgetAction>
48
#include <QDesktopWidget>
49
#include <QPainter>
50
#include <QTimer>
51
#include <QSlider>
François Cartegnie's avatar
François Cartegnie committed
52
#include <QBitmap>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
53

54
#ifdef Q_WS_X11
55 56
#   include <X11/Xlib.h>
#   include <qx11info_x11.h>
57
#endif
58

59
#include <math.h>
60
#include <assert.h>
61

62 63 64 65
/**********************************************************************
 * Video Widget. A simple frame on which video is drawn
 * This class handles resize issues
 **********************************************************************/
66

67
VideoWidget::VideoWidget( intf_thread_t *_p_i )
68
            : QFrame( NULL ) , p_intf( _p_i )
69
{
70
    /* Set the policy to expand in both directions */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
71
    // setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
72

73 74
    layout = new QHBoxLayout( this );
    layout->setContentsMargins( 0, 0, 0, 0 );
75
    stable = NULL;
76
    show();
77 78 79 80
}

VideoWidget::~VideoWidget()
{
81
    /* Ensure we are not leaking the video output. This would crash. */
82 83 84 85 86 87 88 89 90 91 92
    assert( !stable );
}

void VideoWidget::sync( void )
{
#ifdef Q_WS_X11
    /* Make sure the X server has processed all requests.
     * This protects other threads using distinct connections from getting
     * the video widget window in an inconsistent states. */
    XSync( QX11Info::display(), False );
#endif
93 94
}

95
/**
96
 * Request the video to avoid the conflicts
97
 **/
98
WId VideoWidget::request( int *pi_x, int *pi_y,
99 100
                          unsigned int *pi_width, unsigned int *pi_height,
                          bool b_keep_size )
101
{
102
    msg_Dbg( p_intf, "Video was requested %i, %i", *pi_x, *pi_y );
103

104
    if( stable )
105 106
    {
        msg_Dbg( p_intf, "embedded video already in use" );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
107
        return 0;
108
    }
109 110 111 112 113 114
    if( b_keep_size )
    {
        *pi_width  = size().width();
        *pi_height = size().height();
    }

115 116 117
    /* The owner of the video window needs a stable handle (WinId). Reparenting
     * in Qt4-X11 changes the WinId of the widget, so we need to create another
     * dummy widget that stays within the reparentable widget. */
118
    stable = new QWidget();
119 120 121 122
    QPalette plt = palette();
    plt.setColor( QPalette::Window, Qt::black );
    stable->setPalette( plt );
    stable->setAutoFillBackground(true);
123 124 125
    /* Indicates that the widget wants to draw directly onto the screen.
       Widgets with this attribute set do not participate in composition
       management */
126 127 128
    /* This is currently disabled on X11 as it does not seem to improve
     * performance, but causes the video widget to be transparent... */
#ifndef Q_WS_X11
129
    stable->setAttribute( Qt::WA_PaintOnScreen, true );
130
#endif
131

132
    layout->addWidget( stable );
133

134
#ifdef Q_WS_X11
135
    /* HACK: Only one X11 client can subscribe to mouse button press events.
136
     * VLC currently handles those in the video display.
137
     * Force Qt4 to unsubscribe from mouse press and release events. */
138 139 140 141 142
    Display *dpy = QX11Info::display();
    Window w = stable->winId();
    XWindowAttributes attr;

    XGetWindowAttributes( dpy, w, &attr );
143 144
    attr.your_event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
    XSelectInput( dpy, w, attr.your_event_mask );
145
#endif
146
    sync();
147
    return stable->winId();
148 149
}

150
/* Set the Widget to the correct Size */
151
/* Function has to be called by the parent
Rémi Denis-Courmont's avatar
typo  
Rémi Denis-Courmont committed
152
   Parent has to care about resizing itself */
153
void VideoWidget::SetSizing( unsigned int w, unsigned int h )
154
{
155 156
    resize( w, h );
    emit sizeChanged( w, h );
157 158 159 160 161
    /* Work-around a bug?misconception? that would happen when vout core resize
       twice to the same size and would make the vout not centered.
       This cause a small flicker.
       See #3621
     */
162
    if( (unsigned)size().width() == w && (unsigned)size().height() == h )
163
        updateGeometry();
164
    sync();
165 166
}

167
void VideoWidget::release( void )
168
{
Rémi Denis-Courmont's avatar
Typo  
Rémi Denis-Courmont committed
169
    msg_Dbg( p_intf, "Video is not needed anymore" );
170

171 172 173 174 175 176
    if( stable )
    {
        layout->removeWidget( stable );
        stable->deleteLater();
        stable = NULL;
    }
177

178
    updateGeometry();
179
}
180

181 182
/**********************************************************************
 * Background Widget. Show a simple image background. Currently,
183
 * it's album art if present or cone.
184
 **********************************************************************/
185

186
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
187
    :QWidget( NULL ), p_intf( _p_i ), b_expandPixmap( false ), b_withart( true )
188
{
189
    /* A dark background */
Clément Stenac's avatar
Clément Stenac committed
190
    setAutoFillBackground( true );
191
    QPalette plt = palette();
192 193 194 195
    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
    setPalette( plt );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
196 197 198
    /* Init the cone art */
    updateArt( "" );

199
    CONNECT( THEMIM->getIM(), artChanged( QString ),
200
             this, updateArt( const QString& ) );
201 202
}

203
void BackgroundWidget::updateArt( const QString& url )
204
{
François Cartegnie's avatar
François Cartegnie committed
205
    if ( !url.isEmpty() )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
206
    {
François Cartegnie's avatar
François Cartegnie committed
207 208 209 210
        pixmapUrl = url;
    }
    else
    {   /* Xmas joke */
211
        if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
212
            pixmapUrl = QString( ":/logo/vlc128-xmas.png" );
213
        else
François Cartegnie's avatar
François Cartegnie committed
214
            pixmapUrl = QString( ":/logo/vlc128.png" );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
215
    }
216
    update();
François Cartegnie's avatar
François Cartegnie committed
217 218 219 220
}

void BackgroundWidget::paintEvent( QPaintEvent *e )
{
221 222 223 224 225 226 227
    if ( !b_withart )
    {
        /* we just want background autofill */
        QWidget::paintEvent( e );
        return;
    }

François Cartegnie's avatar
François Cartegnie committed
228 229 230 231 232 233
    int i_maxwidth, i_maxheight;
    QPixmap pixmap = QPixmap( pixmapUrl );
    QPainter painter(this);
    QBitmap pMask;
    float f_alpha = 1.0;

234 235
    i_maxwidth  = __MIN( maximumWidth(), width() ) - MARGIN * 2;
    i_maxheight = __MIN( maximumHeight(), height() ) - MARGIN * 2;
François Cartegnie's avatar
François Cartegnie committed
236 237

    if ( height() > MARGIN * 2 )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
238
    {
François Cartegnie's avatar
François Cartegnie committed
239 240 241 242 243 244 245 246 247
        /* Scale down the pixmap if the widget is too small */
        if( pixmap.width() > i_maxwidth || pixmap.height() > i_maxheight )
        {
            pixmap = pixmap.scaled( i_maxwidth, i_maxheight,
                            Qt::KeepAspectRatio, Qt::SmoothTransformation );
        }
        else
        if ( b_expandPixmap &&
             pixmap.width() < width() && pixmap.height() < height() )
248
        {
François Cartegnie's avatar
François Cartegnie committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262
            /* Scale up the pixmap to fill widget's size */
            f_alpha = ( (float) pixmap.height() / (float) height() );
            pixmap = pixmap.scaled(
                    width() - MARGIN * 2,
                    height() - MARGIN * 2,
                    Qt::KeepAspectRatio,
                    ( f_alpha < .2 )? /* Don't waste cpu when not visible */
                        Qt::SmoothTransformation:
                        Qt::FastTransformation
                    );
            /* Non agressive alpha compositing when sizing up */
            pMask = QBitmap( pixmap.width(), pixmap.height() );
            pMask.fill( QColor::fromRgbF( 1.0, 1.0, 1.0, f_alpha ) );
            pixmap.setMask( pMask );
263 264
        }

François Cartegnie's avatar
François Cartegnie committed
265 266 267 268
        painter.drawPixmap(
                MARGIN + ( i_maxwidth - pixmap.width() ) /2,
                MARGIN + ( i_maxheight - pixmap.height() ) /2,
                pixmap);
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
269
    }
François Cartegnie's avatar
François Cartegnie committed
270
    QWidget::paintEvent( e );
271 272
}

273 274
void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
{
275
    VLCMenuBar::PopupMenu( p_intf, true );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
276
    event->accept();
277
}
278

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
279
#if 0
280 281 282
#include <QPushButton>
#include <QHBoxLayout>

Clément Stenac's avatar
Clément Stenac committed
283 284 285 286
/**********************************************************************
 * Visualization selector panel
 **********************************************************************/
VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
287
                                QFrame( NULL ), p_intf( _p_i )
Clément Stenac's avatar
Clément Stenac committed
288 289
{
    QHBoxLayout *layout = new QHBoxLayout( this );
290
    layout->setMargin( 0 );
Clément Stenac's avatar
Clément Stenac committed
291
    QPushButton *prevButton = new QPushButton( "Prev" );
292
    QPushButton *nextButton = new QPushButton( "Next" );
Clément Stenac's avatar
Clément Stenac committed
293 294
    layout->addWidget( prevButton );
    layout->addWidget( nextButton );
Clément Stenac's avatar
Clément Stenac committed
295

296
    layout->addStretch( 10 );
297
    layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
Clément Stenac's avatar
Clément Stenac committed
298 299 300 301 302 303 304

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

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

Clément Stenac's avatar
Clément Stenac committed
305
    setLayout( layout );
306
    setMaximumHeight( 35 );
Clément Stenac's avatar
Clément Stenac committed
307 308 309
}

VisualSelector::~VisualSelector()
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
310
{}
Clément Stenac's avatar
Clément Stenac committed
311

Clément Stenac's avatar
Clément Stenac committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
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 );
    }
}
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
331
#endif
Clément Stenac's avatar
Clément Stenac committed
332

333 334
SpeedLabel::SpeedLabel( intf_thread_t *_p_intf, QWidget *parent )
           : QLabel( parent ), p_intf( _p_intf )
335
{
336
    tooltipStringPattern = qtr( "Current playback speed: %1\nClick to adjust" );
337 338

    /* Create the Speed Control Widget */
339
    speedControl = new SpeedControlWidget( p_intf, this );
340 341 342 343 344 345
    speedControlMenu = new QMenu( this );

    QWidgetAction *widgetAction = new QWidgetAction( speedControl );
    widgetAction->setDefaultWidget( speedControl );
    speedControlMenu->addAction( widgetAction );

346
    /* Change the SpeedRate in the Label */
347
    CONNECT( THEMIM->getIM(), rateChanged( float ), this, setRate( float ) );
348

349 350
    DCONNECT( THEMIM, inputChanged( input_thread_t * ),
              speedControl, activateOnState() );
351 352 353 354

    setFrameStyle( QFrame::StyledPanel | QFrame::Raised );
    setLineWidth( 1 );

355
    setRate( var_InheritFloat( p_intf, "rate" ) );
356
}
357

358 359
SpeedLabel::~SpeedLabel()
{
360 361
    delete speedControl;
    delete speedControlMenu;
362
}
363

364 365 366
/****************************************************************************
 * Small right-click menu for rate control
 ****************************************************************************/
367

368 369 370
void SpeedLabel::showSpeedMenu( QPoint pos )
{
    speedControlMenu->exec( QCursor::pos() - pos
371
                            + QPoint( -70 + width()/2, height() ) );
372 373
}

374
void SpeedLabel::setRate( float rate )
375 376
{
    QString str;
377
    str.setNum( rate, 'f', 2 );
378 379
    str.append( "x" );
    setText( str );
380
    setToolTip( tooltipStringPattern.arg( str ) );
381 382 383
    speedControl->updateControls( rate );
}

384 385 386
/**********************************************************************
 * Speed control widget
 **********************************************************************/
387 388
SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i, QWidget *_parent )
                    : QFrame( _parent ), p_intf( _p_i )
389
{
390
    QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Maximum );
391 392
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );
393

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
394
    speedSlider = new QSlider( this );
395
    speedSlider->setSizePolicy( sizePolicy );
396 397
    speedSlider->setMinimumSize( QSize( 140, 20 ) );
    speedSlider->setOrientation( Qt::Horizontal );
398

399
    speedSlider->setRange( -34, 34 );
400 401
    speedSlider->setSingleStep( 1 );
    speedSlider->setPageStep( 1 );
402
    speedSlider->setTickInterval( 17 );
403

404
    CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
405

406
    QToolButton *normalSpeedButton = new QToolButton( this );
407
    normalSpeedButton->setMaximumSize( QSize( 26, 16 ) );
408
    normalSpeedButton->setAutoRaise( true );
409
    normalSpeedButton->setText( "1x" );
410
    normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
411

412
    CONNECT( normalSpeedButton, clicked(), this, resetRate() );
413

414 415 416 417 418 419 420 421 422 423 424 425 426 427
    QToolButton *slowerButton = new QToolButton( this );
    slowerButton->setMaximumSize( QSize( 26, 16 ) );
    slowerButton->setAutoRaise( true );
    slowerButton->setToolTip( tooltipL[SLOWER_BUTTON] );
    slowerButton->setIcon( QIcon( iconL[SLOWER_BUTTON] ) );
    CONNECT( slowerButton, clicked(), THEMIM->getIM(), slower() );

    QToolButton *fasterButton = new QToolButton( this );
    fasterButton->setMaximumSize( QSize( 26, 16 ) );
    fasterButton->setAutoRaise( true );
    fasterButton->setToolTip( tooltipL[FASTER_BUTTON] );
    fasterButton->setIcon( QIcon( iconL[FASTER_BUTTON] ) );
    CONNECT( fasterButton, clicked(), THEMIM->getIM(), faster() );

428 429 430 431 432 433 434 435 436 437 438
/*    spinBox = new QDoubleSpinBox();
    spinBox->setDecimals( 2 );
    spinBox->setMaximum( 32 );
    spinBox->setMinimum( 0.03F );
    spinBox->setSingleStep( 0.10F );
    spinBox->setAlignment( Qt::AlignRight );

    CONNECT( spinBox, valueChanged( double ), this, updateSpinBoxRate( double ) ); */

    QGridLayout* speedControlLayout = new QGridLayout( this );
    speedControlLayout->addWidget( speedSlider, 0, 0, 1, 3 );
439 440 441
    speedControlLayout->addWidget( slowerButton, 1, 0 );
    speedControlLayout->addWidget( normalSpeedButton, 1, 1, 1, 1, Qt::AlignRight );
    speedControlLayout->addWidget( fasterButton, 1, 2, 1, 1, Qt::AlignRight );
442 443 444
    //speedControlLayout->addWidget( spinBox );
    speedControlLayout->setContentsMargins( 0, 0, 0, 0 );
    speedControlLayout->setSpacing( 0 );
445

446 447
    lastValue = 0;

448 449
    activateOnState();
}
450

451
void SpeedControlWidget::activateOnState()
452
{
453
    speedSlider->setEnabled( THEMIM->getIM()->hasInput() );
454
    //spinBox->setEnabled( THEMIM->getIM()->hasInput() );
455 456
}

457
void SpeedControlWidget::updateControls( float rate )
458
{
459 460 461 462 463
    if( speedSlider->isSliderDown() )
    {
        //We don't want to change anything if the user is using the slider
        return;
    }
464

465
    double value = 17 * log( rate ) / log( 2. );
466
    int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 );
467

468
    if( sliderValue < speedSlider->minimum() )
469
    {
470
        sliderValue = speedSlider->minimum();
471
    }
472
    else if( sliderValue > speedSlider->maximum() )
473
    {
474
        sliderValue = speedSlider->maximum();
475
    }
476
    lastValue = sliderValue;
477

478
    speedSlider->setValue( sliderValue );
479
    //spinBox->setValue( rate );
480 481 482 483
}

void SpeedControlWidget::updateRate( int sliderValue )
{
484 485 486
    if( sliderValue == lastValue )
        return;

487
    double speed = pow( 2, (double)sliderValue / 17 );
488
    int rate = INPUT_RATE_DEFAULT / speed;
489

490
    THEMIM->getIM()->setRate(rate);
491 492 493 494 495 496
    //spinBox->setValue( var_InheritFloat( THEPL, "rate" ) );
}

void SpeedControlWidget::updateSpinBoxRate( double r )
{
    var_SetFloat( THEPL, "rate", r );
497 498 499 500
}

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

504
CoverArtLabel::CoverArtLabel( QWidget *parent, intf_thread_t *_p_i )
505
              : QLabel( parent ), p_intf( _p_i )
506 507
{
    setContextMenuPolicy( Qt::ActionsContextMenu );
508
    CONNECT( this, updateRequested(), this, askForUpdate() );
509

510
    setMinimumHeight( 128 );
511 512
    setMinimumWidth( 128 );
    setMaximumHeight( 128 );
513 514
    setScaledContents( false );
    setAlignment( Qt::AlignCenter );
515

516 517
    QList< QAction* > artActions = actions();
    QAction *action = new QAction( qtr( "Download cover art" ), this );
518
    CONNECT( action, triggered(), this, askForUpdate() );
519
    addAction( action );
520

521
    showArtUpdate( "" );
522 523
}

524 525 526 527 528 529 530
CoverArtLabel::~CoverArtLabel()
{
    QList< QAction* > artActions = actions();
    foreach( QAction *act, artActions )
        removeAction( act );
}

531
void CoverArtLabel::showArtUpdate( const QString& url )
532
{
533
    QPixmap pix;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
534
    if( !url.isEmpty() && pix.load( url ) )
535
    {
536
        pix = pix.scaled( minimumWidth(), maximumHeight(),
537 538
                          Qt::KeepAspectRatioByExpanding,
                          Qt::SmoothTransformation );
539 540 541
    }
    else
    {
542
        pix = QPixmap( ":/noart.png" );
543
    }
544
    setPixmap( pix );
545 546
}

547
void CoverArtLabel::askForUpdate()
548
{
549
    THEMIM->getIM()->requestArtUpdate();
550 551
}

552
TimeLabel::TimeLabel( intf_thread_t *_p_intf, TimeLabel::Display _displayType  )
553
    : QLabel(), p_intf( _p_intf ), bufTimer( new QTimer(this) ),
554
      buffering( false ), showBuffering(false), bufVal( -1 ), displayType( _displayType )
555
{
556
    b_remainingTime = false;
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
    switch( _displayType ) {
        case TimeLabel::Elapsed:
            setText( " --:-- " );
            setToolTip( qtr("Elapsed time") );
            break;
        case TimeLabel::Remaining:
            setText( " --:-- " );
            setToolTip( qtr("Total/Remaining time")
                        + QString("\n-")
                        + qtr("Click to toggle between total and remaining time")
                      );
            break;
        case TimeLabel::Both:
            setText( " --:--/--:-- " );
            setToolTip( QString( "- " )
                + qtr( "Click to toggle between elapsed and remaining time" )
                + QString( "\n- " )
                + qtr( "Double click to jump to a chosen time position" ) );
            break;
    }
577
    setAlignment( Qt::AlignRight | Qt::AlignVCenter );
578

579
    bufTimer->setSingleShot( true );
580

581 582 583 584 585
    CONNECT( THEMIM->getIM(), positionUpdated( float, int64_t, int ),
              this, setDisplayPosition( float, int64_t, int ) );
    CONNECT( THEMIM->getIM(), cachingChanged( float ),
              this, updateBuffering( float ) );
    CONNECT( bufTimer, timeout(), this, updateBuffering() );
586 587

    this->setContentsMargins( 4, 0, 4, 0 );
588 589
}

590
void TimeLabel::setDisplayPosition( float pos, int64_t t, int length )
591
{
592 593 594
    showBuffering = false;
    bufTimer->stop();

595
    if( pos == -1.f )
596
    {
597 598 599 600
        if( displayType == TimeLabel::Both )
            setText( " --:--/--:-- " );
        else
            setText( " --:-- " );
601 602
        return;
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
603

604
    int time = t / 1000000;
605

606 607 608
    secstotimestr( psz_length, length );
    secstotimestr( psz_time, ( b_remainingTime && length ) ? length - time
                                                           : time );
609 610 611 612 613 614 615 616 617 618 619 620 621 622
    switch( displayType )
    {
        case TimeLabel::Elapsed:
            setText( QString(" ") + QString( psz_time ) + QString(" ") );
            break;
        case TimeLabel::Remaining:
            if( b_remainingTime )
                setText( QString(" -") + QString( psz_time ) + QString(" ") );
            else
                setText( QString(" ") + QString( psz_length ) + QString(" ") );
            break;
        case TimeLabel::Both:
        default:
            QString timestr = QString( " %1%2/%3 " )
623 624 625
            .arg( QString( (b_remainingTime && length) ? "-" : "" ) )
            .arg( QString( psz_time ) )
            .arg( QString( ( !length && time ) ? "--:--" : psz_length ) );
626

627 628 629
            setText( timestr );
            break;
    }
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
    cachedLength = length;
}

void TimeLabel::setDisplayPosition( float pos )
{
    if( pos == -1.f || cachedLength == 0 )
    {
        setText( " --:--/--:-- " );
        return;
    }

    int time = pos * cachedLength;
    secstotimestr( psz_time,
                   ( b_remainingTime && cachedLength ?
                   cachedLength - time : time ) );
645 646 647 648
    QString timestr = QString( " %1%2/%3 " )
        .arg( QString( (b_remainingTime && cachedLength) ? "-" : "" ) )
        .arg( QString( psz_time ) )
        .arg( QString( ( !cachedLength && time ) ? "--:--" : psz_length ) );
649 650

    setText( timestr );
651 652
}

653

654 655 656 657
void TimeLabel::toggleTimeDisplay()
{
    b_remainingTime = !b_remainingTime;
}
658 659


660
void TimeLabel::updateBuffering( float _buffered )
661
{
662 663 664 665 666 667 668 669 670 671
    bufVal = _buffered;
    if( !buffering || bufVal == 0 )
    {
        showBuffering = false;
        buffering = true;
        bufTimer->start(200);
    }
    else if( bufVal == 1 )
    {
        showBuffering = buffering = false;
672
        bufTimer->stop();
673 674
    }
    update();
675
}
676

677
void TimeLabel::updateBuffering()
678
{
679 680
    showBuffering = true;
    update();
681 682
}

683
void TimeLabel::paintEvent( QPaintEvent* event )
684
{
685 686 687 688 689 690 691 692
    if( showBuffering )
    {
        QRect r( rect() );
        r.setLeft( r.width() * bufVal );
        QPainter p( this );
        p.setOpacity( 0.4 );
        p.fillRect( r, palette().color( QPalette::Highlight ) );
    }
693 694
    QLabel::paintEvent( event );
}