interface_widgets.cpp 20 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 "components/interface_widgets.hpp"
32 33 34 35

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

#include <vlc_vout.h>
36

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

50 51 52
#ifdef Q_WS_X11
# include <X11/Xlib.h>
# include <qx11info_x11.h>
53 54 55 56 57 58 59 60 61
static void videoSync( void )
{
    /* 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 );
}
#else
# define videoSync() (void)0
62
#endif
63

64
#include <math.h>
65
#include <assert.h>
66

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
class ReparentableWidget : public QWidget
{
private:
    VideoWidget *owner;
public:
    ReparentableWidget( VideoWidget *owner ) : owner( owner )
    {
    }

protected:
    void keyPressEvent( QKeyEvent *e )
    {
        emit owner->keyPressed( e );
    }
};

83 84 85 86
/**********************************************************************
 * Video Widget. A simple frame on which video is drawn
 * This class handles resize issues
 **********************************************************************/
87

88 89 90 91
VideoWidget::VideoWidget( intf_thread_t *_p_i )
    : QFrame( NULL )
      , p_intf( _p_i )
      , reparentable( NULL )
92
{
93
    /* Set the policy to expand in both directions */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
94
    // setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
95

96 97 98
    layout = new QHBoxLayout( this );
    layout->setContentsMargins( 0, 0, 0, 0 );
    setLayout( layout );
99 100 101 102
}

VideoWidget::~VideoWidget()
{
103
    /* Ensure we are not leaking the video output. This would crash. */
104
    assert( reparentable == NULL );
105 106
}

107
/**
108
 * Request the video to avoid the conflicts
109
 **/
110
WId VideoWidget::request( int *pi_x, int *pi_y,
111 112
                          unsigned int *pi_width, unsigned int *pi_height,
                          bool b_keep_size )
113
{
114
    msg_Dbg( p_intf, "Video was requested %i, %i", *pi_x, *pi_y );
115

116 117 118 119 120
    if( reparentable != NULL )
    {
        msg_Dbg( p_intf, "embedded video already in use" );
        return NULL;
    }
121 122 123 124 125 126
    if( b_keep_size )
    {
        *pi_width  = size().width();
        *pi_height = size().height();
    }

127 128 129 130 131
    /* The Qt4 UI needs a fixed a widget ("this"), so that the parent layout is
     * not messed up when we the video is reparented. Hence, we create an extra
     * reparentable widget, that will be within the VideoWidget in windowed
     * mode, and within the root window (NULL parent) in full-screen mode.
     */
132
    reparentable = new ReparentableWidget( this );
133 134 135 136 137 138 139 140 141 142 143
    QLayout *innerLayout = new QHBoxLayout( reparentable );
    innerLayout->setContentsMargins( 0, 0, 0, 0 );

    /* 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. */
    QWidget *stable = new QWidget();
    QPalette plt = palette();
    plt.setColor( QPalette::Window, Qt::black );
    stable->setPalette( plt );
    stable->setAutoFillBackground(true);
144 145 146
    /* Indicates that the widget wants to draw directly onto the screen.
       Widgets with this attribute set do not participate in composition
       management */
147 148 149 150 151 152
    stable->setAttribute( Qt::WA_PaintOnScreen, true );

    innerLayout->addWidget( stable );

    layout->addWidget( reparentable );

153
#ifdef Q_WS_X11
154
    /* HACK: Only one X11 client can subscribe to mouse button press events.
155
     * VLC currently handles those in the video display.
156
     * Force Qt4 to unsubscribe from mouse press and release events. */
157 158 159 160 161
    Display *dpy = QX11Info::display();
    Window w = stable->winId();
    XWindowAttributes attr;

    XGetWindowAttributes( dpy, w, &attr );
162 163
    attr.your_event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
    XSelectInput( dpy, w, attr.your_event_mask );
164
#endif
165
    videoSync();
166
#ifndef NDEBUG
167 168
    msg_Dbg( p_intf, "embedded video ready (handle %p)",
             (void *)stable->winId() );
169
#endif
170
    return stable->winId();
171 172
}

173
/* Set the Widget to the correct Size */
174
/* Function has to be called by the parent
Rémi Denis-Courmont's avatar
typo  
Rémi Denis-Courmont committed
175
   Parent has to care about resizing itself */
176
void VideoWidget::SetSizing( unsigned int w, unsigned int h )
177
{
178 179
    if (reparentable->windowState() & Qt::WindowFullScreen )
        return;
180
    if( !isVisible() ) show();
181 182
    resize( w, h );
    emit sizeChanged( w, h );
183
    videoSync();
184 185
}

186 187 188 189
void VideoWidget::SetFullScreen( bool b_fs )
{
    const Qt::WindowStates curstate = reparentable->windowState();
    Qt::WindowStates newstate = curstate;
190
    Qt::WindowFlags  newflags = reparentable->windowFlags();
191

192

193
    if( b_fs )
194
    {
195
        newstate |= Qt::WindowFullScreen;
196 197
        newflags |= Qt::WindowStaysOnTopHint;
    }
198
    else
199
    {
200
        newstate &= ~Qt::WindowFullScreen;
201 202
        newflags &= ~Qt::WindowStaysOnTopHint;
    }
203 204 205 206 207
    if( newstate == curstate )
        return; /* no changes needed */

    if( b_fs )
    {   /* Go full-screen */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
208
        int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
209 210 211 212 213 214 215
        /* if user hasn't defined screennumber, or screennumber that is bigger
         * than current number of screens, take screennumber where current interface
         * is
         */
        if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
            numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );

216 217 218 219 220 221 222 223
        QRect screenres = QApplication::desktop()->screenGeometry( numscreen );

        /* To be sure window is on proper-screen in xinerama */
        if( !screenres.contains( reparentable->pos() ) )
        {
            msg_Dbg( p_intf, "Moving video to correct screen");
            reparentable->move( QPoint( screenres.x(), screenres.y() ) );
        }
224 225
        reparentable->setParent( NULL, newflags );
        reparentable->setWindowState( newstate );
226 227 228 229
        reparentable->show();
    }
    else
    {   /* Go windowed */
230
        reparentable->setWindowFlags( newflags );
231
        reparentable->setWindowState( newstate );
232
        layout->addWidget( reparentable );
233
    }
234
    videoSync();
235 236
}

237
void VideoWidget::release( void )
238
{
Rémi Denis-Courmont's avatar
Typo  
Rémi Denis-Courmont committed
239
    msg_Dbg( p_intf, "Video is not needed anymore" );
240
    //layout->removeWidget( reparentable );
241

242
    reparentable->deleteLater();
243
    reparentable = NULL;
244
    updateGeometry();
245
    hide();
246
}
247

248 249
/**********************************************************************
 * Background Widget. Show a simple image background. Currently,
250
 * it's album art if present or cone.
251
 **********************************************************************/
252

253
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
François Cartegnie's avatar
François Cartegnie committed
254
                 :QWidget( NULL ), p_intf( _p_i ), b_expandPixmap( false )
255
{
256
    /* A dark background */
Clément Stenac's avatar
Clément Stenac committed
257
    setAutoFillBackground( true );
258
    QPalette plt = palette();
259 260 261 262
    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
263 264 265
    /* Init the cone art */
    updateArt( "" );

266
    CONNECT( THEMIM->getIM(), artChanged( QString ),
267
             this, updateArt( const QString& ) );
268 269
}

270
void BackgroundWidget::updateArt( const QString& url )
271
{
François Cartegnie's avatar
François Cartegnie committed
272
    if ( !url.isEmpty() )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
273
    {
François Cartegnie's avatar
François Cartegnie committed
274 275 276 277
        pixmapUrl = url;
    }
    else
    {   /* Xmas joke */
278
        if( QDate::currentDate().dayOfYear() >= 354 )
François Cartegnie's avatar
François Cartegnie committed
279
            pixmapUrl = QString( ":/logo/vlc128-christmas.png" );
280
        else
François Cartegnie's avatar
François Cartegnie committed
281
            pixmapUrl = QString( ":/logo/vlc128.png" );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
282
    }
283
    update();
François Cartegnie's avatar
François Cartegnie committed
284 285 286 287 288 289 290 291 292 293 294 295 296 297
}

void BackgroundWidget::paintEvent( QPaintEvent *e )
{
    int i_maxwidth, i_maxheight;
    QPixmap pixmap = QPixmap( pixmapUrl );
    QPainter painter(this);
    QBitmap pMask;
    float f_alpha = 1.0;

    i_maxwidth = std::min( maximumWidth(), width() ) - MARGIN * 2;
    i_maxheight = std::min( maximumHeight(), height() ) - MARGIN * 2;

    if ( height() > MARGIN * 2 )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
298
    {
François Cartegnie's avatar
François Cartegnie committed
299 300 301 302 303 304 305 306 307
        /* 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() )
308
        {
François Cartegnie's avatar
François Cartegnie committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322
            /* 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 );
323 324
        }

François Cartegnie's avatar
François Cartegnie committed
325 326 327 328
        painter.drawPixmap(
                MARGIN + ( i_maxwidth - pixmap.width() ) /2,
                MARGIN + ( i_maxheight - pixmap.height() ) /2,
                pixmap);
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
329
    }
François Cartegnie's avatar
François Cartegnie committed
330
    QWidget::paintEvent( e );
331 332
}

333 334
void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
{
Erwan Tulou's avatar
Erwan Tulou committed
335
    QVLCMenu::PopupMenu( p_intf, true );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
336
    event->accept();
337
}
338

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
339
#if 0
340 341 342
#include <QPushButton>
#include <QHBoxLayout>

Clément Stenac's avatar
Clément Stenac committed
343 344 345 346
/**********************************************************************
 * Visualization selector panel
 **********************************************************************/
VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
347
                                QFrame( NULL ), p_intf( _p_i )
Clément Stenac's avatar
Clément Stenac committed
348 349
{
    QHBoxLayout *layout = new QHBoxLayout( this );
350
    layout->setMargin( 0 );
Clément Stenac's avatar
Clément Stenac committed
351
    QPushButton *prevButton = new QPushButton( "Prev" );
352
    QPushButton *nextButton = new QPushButton( "Next" );
Clément Stenac's avatar
Clément Stenac committed
353 354
    layout->addWidget( prevButton );
    layout->addWidget( nextButton );
Clément Stenac's avatar
Clément Stenac committed
355

356
    layout->addStretch( 10 );
357
    layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
Clément Stenac's avatar
Clément Stenac committed
358 359 360 361 362 363 364

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

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

Clément Stenac's avatar
Clément Stenac committed
365
    setLayout( layout );
366
    setMaximumHeight( 35 );
Clément Stenac's avatar
Clément Stenac committed
367 368 369
}

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

Clément Stenac's avatar
Clément Stenac committed
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
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
391
#endif
Clément Stenac's avatar
Clément Stenac committed
392

393 394
SpeedLabel::SpeedLabel( intf_thread_t *_p_intf, QWidget *parent )
           : QLabel( parent ), p_intf( _p_intf )
395
{
396
    tooltipStringPattern = qtr( "Current playback speed: %1\nClick to adjust" );
397 398

    /* Create the Speed Control Widget */
399
    speedControl = new SpeedControlWidget( p_intf, this );
400 401 402 403 404 405 406
    speedControlMenu = new QMenu( this );

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

    /* Change the SpeedRate in the Status Bar */
407
    CONNECT( THEMIM->getIM(), rateChanged( float ), this, setRate( float ) );
408

409 410
    DCONNECT( THEMIM, inputChanged( input_thread_t * ),
              speedControl, activateOnState() );
411
    setRate( var_InheritFloat( p_intf, "rate" ) );
412
}
413

414 415
SpeedLabel::~SpeedLabel()
{
416 417
    delete speedControl;
    delete speedControlMenu;
418
}
419

420 421 422
/****************************************************************************
 * Small right-click menu for rate control
 ****************************************************************************/
423

424 425 426 427 428 429
void SpeedLabel::showSpeedMenu( QPoint pos )
{
    speedControlMenu->exec( QCursor::pos() - pos
                          + QPoint( 0, height() ) );
}

430
void SpeedLabel::setRate( float rate )
431 432
{
    QString str;
433
    str.setNum( rate, 'f', 2 );
434 435
    str.append( "x" );
    setText( str );
436
    setToolTip( tooltipStringPattern.arg( str ) );
437 438 439
    speedControl->updateControls( rate );
}

440 441 442
/**********************************************************************
 * Speed control widget
 **********************************************************************/
443 444
SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i, QWidget *_parent )
                    : QFrame( _parent ), p_intf( _p_i )
445
{
446
    QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
447 448
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );
449

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
450
    speedSlider = new QSlider( this );
451 452 453 454 455
    speedSlider->setSizePolicy( sizePolicy );
    speedSlider->setMaximumSize( QSize( 80, 200 ) );
    speedSlider->setOrientation( Qt::Vertical );
    speedSlider->setTickPosition( QSlider::TicksRight );

456
    speedSlider->setRange( -34, 34 );
457 458
    speedSlider->setSingleStep( 1 );
    speedSlider->setPageStep( 1 );
459
    speedSlider->setTickInterval( 17 );
460

461
    CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
462

463
    QToolButton *normalSpeedButton = new QToolButton( this );
464
    normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
465
    normalSpeedButton->setAutoRaise( true );
466
    normalSpeedButton->setText( "1x" );
467
    normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
468

469
    CONNECT( normalSpeedButton, clicked(), this, resetRate() );
470

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
471
    QVBoxLayout *speedControlLayout = new QVBoxLayout( this );
472
    speedControlLayout->setContentsMargins( 4, 4, 4, 4 );
473
    speedControlLayout->setSpacing( 4 );
474 475
    speedControlLayout->addWidget( speedSlider );
    speedControlLayout->addWidget( normalSpeedButton );
476

477 478
    lastValue = 0;

479 480
    activateOnState();
}
481

482
void SpeedControlWidget::activateOnState()
483
{
484
    speedSlider->setEnabled( THEMIM->getIM()->hasInput() );
485 486
}

487
void SpeedControlWidget::updateControls( float rate )
488
{
489 490 491 492 493
    if( speedSlider->isSliderDown() )
    {
        //We don't want to change anything if the user is using the slider
        return;
    }
494

495
    double value = 17 * log( rate ) / log( 2 );
496
    int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 );
497

498
    if( sliderValue < speedSlider->minimum() )
499
    {
500
        sliderValue = speedSlider->minimum();
501
    }
502
    else if( sliderValue > speedSlider->maximum() )
503
    {
504
        sliderValue = speedSlider->maximum();
505
    }
506
    lastValue = sliderValue;
507

508
    speedSlider->setValue( sliderValue );
509 510 511 512
}

void SpeedControlWidget::updateRate( int sliderValue )
{
513 514 515
    if( sliderValue == lastValue )
        return;

516
    double speed = pow( 2, (double)sliderValue / 17 );
517
    int rate = INPUT_RATE_DEFAULT / speed;
518

519
    THEMIM->getIM()->setRate(rate);
520 521 522 523
}

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

527
CoverArtLabel::CoverArtLabel( QWidget *parent, intf_thread_t *_p_i )
528
              : QLabel( parent ), p_intf( _p_i )
529 530
{
    setContextMenuPolicy( Qt::ActionsContextMenu );
531
    CONNECT( this, updateRequested(), this, askForUpdate() );
532

533
    setMinimumHeight( 128 );
534 535
    setMinimumWidth( 128 );
    setMaximumHeight( 128 );
536
    setMaximumWidth( 128 );
537 538
    setScaledContents( false );
    setAlignment( Qt::AlignCenter );
539

540 541
    QList< QAction* > artActions = actions();
    QAction *action = new QAction( qtr( "Download cover art" ), this );
542
    CONNECT( action, triggered(), this, askForUpdate() );
543
    addAction( action );
544

545
    showArtUpdate( "" );
546 547
}

548 549 550 551 552 553 554
CoverArtLabel::~CoverArtLabel()
{
    QList< QAction* > artActions = actions();
    foreach( QAction *act, artActions )
        removeAction( act );
}

555
void CoverArtLabel::showArtUpdate( const QString& url )
556
{
557
    QPixmap pix;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
558
    if( !url.isEmpty() && pix.load( url ) )
559
    {
560 561
        pix = pix.scaled( maximumWidth(), maximumHeight(),
                          Qt::KeepAspectRatioByExpanding );
562 563 564
    }
    else
    {
565
        pix = QPixmap( ":/noart.png" );
566
    }
567
    setPixmap( pix );
568 569
}

570
void CoverArtLabel::askForUpdate()
571
{
572
    THEMIM->getIM()->requestArtUpdate();
573 574
}

575 576 577
TimeLabel::TimeLabel( intf_thread_t *_p_intf  )
    : QLabel(), p_intf( _p_intf ), bufTimer( new QTimer(this) ),
      buffering( false ), showBuffering(false), bufVal( -1 )
578
{
579 580 581
    b_remainingTime = false;
    setText( " --:--/--:-- " );
    setAlignment( Qt::AlignRight | Qt::AlignVCenter );
582 583 584 585
    setToolTip( QString( "- " )
        + qtr( "Click to toggle between elapsed and remaining time" )
        + QString( "\n- " )
        + qtr( "Double click to jump to a chosen time position" ) );
586
    bufTimer->setSingleShot( true );
587

588 589 590 591 592
    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() );
593 594
}

595
void TimeLabel::setDisplayPosition( float pos, int64_t t, int length )
596
{
597 598 599
    showBuffering = false;
    bufTimer->stop();

600
    if( pos == -1.f )
601 602 603 604
    {
        setText( " --:--/--:-- " );
        return;
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
605

606
    int time = t / 1000000;
607

608 609 610 611
    secstotimestr( psz_length, length );
    secstotimestr( psz_time, ( b_remainingTime && length ) ? length - time
                                                           : time );

612 613 614 615
    QString timestr = QString( " %1%2/%3 " )
            .arg( QString( (b_remainingTime && length) ? "-" : "" ) )
            .arg( QString( psz_time ) )
            .arg( QString( ( !length && time ) ? "--:--" : psz_length ) );
616

JP Dinger's avatar
JP Dinger committed
617
    setText( timestr );
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633

    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 ) );
634 635 636 637
    QString timestr = QString( " %1%2/%3 " )
        .arg( QString( (b_remainingTime && cachedLength) ? "-" : "" ) )
        .arg( QString( psz_time ) )
        .arg( QString( ( !cachedLength && time ) ? "--:--" : psz_length ) );
638 639

    setText( timestr );
640 641
}

642

643 644 645 646
void TimeLabel::toggleTimeDisplay()
{
    b_remainingTime = !b_remainingTime;
}
647 648


649
void TimeLabel::updateBuffering( float _buffered )
650
{
651 652 653 654 655 656 657 658 659 660
    bufVal = _buffered;
    if( !buffering || bufVal == 0 )
    {
        showBuffering = false;
        buffering = true;
        bufTimer->start(200);
    }
    else if( bufVal == 1 )
    {
        showBuffering = buffering = false;
661
        bufTimer->stop();
662 663
    }
    update();
664
}
665

666
void TimeLabel::updateBuffering()
667
{
668 669
    showBuffering = true;
    update();
670 671
}

672
void TimeLabel::paintEvent( QPaintEvent* event )
673
{
674 675 676 677 678 679 680 681
    if( showBuffering )
    {
        QRect r( rect() );
        r.setLeft( r.width() * bufVal );
        QPainter p( this );
        p.setOpacity( 0.4 );
        p.fillRect( r, palette().color( QPalette::Highlight ) );
    }
682 683
    QLabel::paintEvent( event );
}