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

48 49 50
#ifdef Q_WS_X11
# include <X11/Xlib.h>
# include <qx11info_x11.h>
51 52 53 54 55 56 57 58 59
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
60
#endif
61

62 63
#include <math.h>

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

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

80 81 82 83
/**********************************************************************
 * Video Widget. A simple frame on which video is drawn
 * This class handles resize issues
 **********************************************************************/
84

85 86 87 88
VideoWidget::VideoWidget( intf_thread_t *_p_i )
    : QFrame( NULL )
      , p_intf( _p_i )
      , reparentable( NULL )
89
{
90
    /* Set the policy to expand in both directions */
91
//    setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
92

93 94 95
    layout = new QHBoxLayout( this );
    layout->setContentsMargins( 0, 0, 0, 0 );
    setLayout( layout );
96 97 98 99
}

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

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

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

124 125 126 127 128
    /* 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.
     */
129
    reparentable = new ReparentableWidget( this );
130 131 132 133 134 135 136 137 138 139 140
    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);
141 142 143
    /* Indicates that the widget wants to draw directly onto the screen.
       Widgets with this attribute set do not participate in composition
       management */
144 145 146 147 148 149
    stable->setAttribute( Qt::WA_PaintOnScreen, true );

    innerLayout->addWidget( stable );

    layout->addWidget( reparentable );

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

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

170
/* Set the Widget to the correct Size */
171
/* Function has to be called by the parent
Rémi Denis-Courmont's avatar
typo  
Rémi Denis-Courmont committed
172
   Parent has to care about resizing itself */
173
void VideoWidget::SetSizing( unsigned int w, unsigned int h )
174
{
175 176
    if (reparentable->windowState() & Qt::WindowFullScreen )
        return;
177
    msg_Dbg( p_intf, "Video is resizing to: %i %i", w, h );
178 179
    videoSize.setWidth( w );
    videoSize.setHeight( h );
180
    if( !isVisible() ) show();
181
    updateGeometry(); // Needed for deinterlace
182
    videoSync();
183 184
}

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

191

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

    if( b_fs )
    {   /* Go full-screen */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
207
        int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
208 209 210 211 212 213 214
        /* 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 );

215 216
        QRect screenres = QApplication::desktop()->screenGeometry( numscreen );

217
        reparentable->setParent( NULL, newflags );
218
        reparentable->setWindowState( newstate );
219 220 221 222 223 224
        /* 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() ) );
        }
225 226 227 228
        reparentable->show();
    }
    else
    {   /* Go windowed */
229
        reparentable->setWindowFlags( newflags );
230
        reparentable->setWindowState( newstate );
231
        layout->addWidget( reparentable );
232
    }
233
    videoSync();
234 235
}

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

#ifdef WIN32
    /* Come back to default thumbnail for Windows 7 taskbar */
    LPTASKBARLIST3 p_taskbl;

245 246 247 248 249 250 251 252
    CoInitialize( 0 );

    if( S_OK == CoCreateInstance( &clsid_ITaskbarList,
                NULL, CLSCTX_INPROC_SERVER,
                &IID_ITaskbarList3,
                (void **)&p_taskbl) )
    {
        p_taskbl->vt->HrInit(p_taskbl);
253

254
        HWND hroot = GetAncestor(reparentable->winId(),GA_ROOT);
255

256 257 258 259
        if (S_OK != p_taskbl->vt->SetThumbnailClip(p_taskbl, hroot, NULL))
            msg_Err(p_intf, "SetThumbNailClip failed");
        msg_Err(p_intf, "Releasing taskbar | root handle = %08x", hroot);
        p_taskbl->vt->Release(p_taskbl);
260
    }
261 262
    CoUninitialize();

263 264
#endif

265 266
    delete reparentable;
    reparentable = NULL;
267
    videoSize = QSize();
268
    updateGeometry();
269
    hide();
270
}
271

272

273 274 275 276
QSize VideoWidget::sizeHint() const
{
    return videoSize;
}
277

278 279
/**********************************************************************
 * Background Widget. Show a simple image background. Currently,
280
 * it's album art if present or cone.
281
 **********************************************************************/
282 283
#define ICON_SIZE 128
#define MAX_BG_SIZE 400
284
#define MIN_BG_SIZE 128
285

286 287
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
                 :QWidget( NULL ), p_intf( _p_i )
288
{
289
    /* We should use that one to take the more size it can */
290
    setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding);
291

292
    /* A dark background */
Clément Stenac's avatar
Clément Stenac committed
293
    setAutoFillBackground( true );
294
    QPalette plt = palette();
295 296 297 298
    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
    setPalette( plt );

299
    /* A cone in the middle */
300
    label = new QLabel;
301
    label->setMargin( 5 );
302
/*    label->setMaximumHeight( MAX_BG_SIZE );
303
    label->setMaximumWidth( MAX_BG_SIZE );
304
    label->setMinimumHeight( MIN_BG_SIZE );
305
    label->setMinimumWidth( MIN_BG_SIZE );*/
306
    label->setAlignment( Qt::AlignCenter );
307
    if( QDate::currentDate().dayOfYear() >= 354 )
308
        label->setPixmap( QPixmap( ":/logo/vlc128-christmas.png" ) );
309
    else
310
        label->setPixmap( QPixmap( ":/logo/vlc128.png" ) );
311

312 313 314 315
    QGridLayout *backgroundLayout = new QGridLayout( this );
    backgroundLayout->addWidget( label, 0, 1 );
    backgroundLayout->setColumnStretch( 0, 1 );
    backgroundLayout->setColumnStretch( 2, 1 );
316

317
    CONNECT( THEMIM->getIM(), artChanged( QString ),
318
             this, updateArt( const QString& ) );
319 320
}

Clément Stenac's avatar
Clément Stenac committed
321
BackgroundWidget::~BackgroundWidget()
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
322
{}
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
323

324 325 326 327 328 329 330 331
void BackgroundWidget::resizeEvent( QResizeEvent * event )
{
    if( event->size().height() <= MIN_BG_SIZE )
        label->hide();
    else
        label->show();
}

332
void BackgroundWidget::updateArt( const QString& url )
333
{
334
    if( url.isEmpty() )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
335
    {
336
        if( QDate::currentDate().dayOfYear() >= 354 )
337
            label->setPixmap( QPixmap( ":/logo/vlc128-christmas.png" ) );
338
        else
339
            label->setPixmap( QPixmap( ":/logo/vlc128.png" ) );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
340
    }
341
    else
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
342
    {
343 344 345 346 347 348 349 350 351
        QPixmap pixmap( url );
        if( pixmap.width() > label->maximumWidth() ||
            pixmap.height() > label->maximumHeight() )
        {
            pixmap = pixmap.scaled( label->maximumWidth(),
                          label->maximumHeight(), Qt::KeepAspectRatio );
        }

        label->setPixmap( pixmap );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
352
    }
353 354
}

355 356 357
void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
{
    QVLCMenu::PopupMenu( p_intf, true );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
358
    event->accept();
359
}
360

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
361
#if 0
362 363 364
#include <QPushButton>
#include <QHBoxLayout>

Clément Stenac's avatar
Clément Stenac committed
365 366 367 368
/**********************************************************************
 * Visualization selector panel
 **********************************************************************/
VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
369
                                QFrame( NULL ), p_intf( _p_i )
Clément Stenac's avatar
Clément Stenac committed
370 371
{
    QHBoxLayout *layout = new QHBoxLayout( this );
372
    layout->setMargin( 0 );
Clément Stenac's avatar
Clément Stenac committed
373
    QPushButton *prevButton = new QPushButton( "Prev" );
374
    QPushButton *nextButton = new QPushButton( "Next" );
Clément Stenac's avatar
Clément Stenac committed
375 376
    layout->addWidget( prevButton );
    layout->addWidget( nextButton );
Clément Stenac's avatar
Clément Stenac committed
377

378
    layout->addStretch( 10 );
379
    layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
Clément Stenac's avatar
Clément Stenac committed
380 381 382 383 384 385 386

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

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

Clément Stenac's avatar
Clément Stenac committed
387
    setLayout( layout );
388
    setMaximumHeight( 35 );
Clément Stenac's avatar
Clément Stenac committed
389 390 391
}

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

Clément Stenac's avatar
Clément Stenac committed
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
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
413
#endif
Clément Stenac's avatar
Clément Stenac committed
414

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
415 416 417
SpeedLabel::SpeedLabel( intf_thread_t *_p_intf, const QString& text,
                        QWidget *parent )
           : QLabel( text, parent ), p_intf( _p_intf )
418
{
419
    setToolTip( qtr( "Current playback speed.\nClick to adjust" ) );
420 421

    /* Create the Speed Control Widget */
422
    speedControl = new SpeedControlWidget( p_intf, this );
423 424 425 426 427 428 429 430 431
    speedControlMenu = new QMenu( this );

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

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

432
    CONNECT( THEMIM, inputChanged( input_thread_t * ),
433 434
             speedControl, activateOnState() );
}
435

436 437
SpeedLabel::~SpeedLabel()
{
438 439
    delete speedControl;
    delete speedControlMenu;
440
}
441

442 443 444
/****************************************************************************
 * Small right-click menu for rate control
 ****************************************************************************/
445

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
void SpeedLabel::showSpeedMenu( QPoint pos )
{
    speedControlMenu->exec( QCursor::pos() - pos
                          + QPoint( 0, height() ) );
}

void SpeedLabel::setRate( int rate )
{
    QString str;
    str.setNum( ( 1000 / (double)rate ), 'f', 2 );
    str.append( "x" );
    setText( str );
    setToolTip( str );
    speedControl->updateControls( rate );
}

462 463 464
/**********************************************************************
 * Speed control widget
 **********************************************************************/
465 466
SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i, QWidget *_parent )
                    : QFrame( _parent ), p_intf( _p_i )
467
{
468
    QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
469 470
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );
471

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
472
    speedSlider = new QSlider( this );
473 474 475 476 477
    speedSlider->setSizePolicy( sizePolicy );
    speedSlider->setMaximumSize( QSize( 80, 200 ) );
    speedSlider->setOrientation( Qt::Vertical );
    speedSlider->setTickPosition( QSlider::TicksRight );

478
    speedSlider->setRange( -34, 34 );
479 480
    speedSlider->setSingleStep( 1 );
    speedSlider->setPageStep( 1 );
481
    speedSlider->setTickInterval( 17 );
482

483
    CONNECT( speedSlider, sliderMoved( int ), this, updateRate( int ) );
484

485
    QToolButton *normalSpeedButton = new QToolButton( this );
486
    normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
487
    normalSpeedButton->setAutoRaise( true );
488
    normalSpeedButton->setText( "1x" );
489
    normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
490

491
    CONNECT( normalSpeedButton, clicked(), this, resetRate() );
492

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
493
    QVBoxLayout *speedControlLayout = new QVBoxLayout( this );
494
    speedControlLayout->setContentsMargins( 4, 4, 4, 4 );
495
    speedControlLayout->setSpacing( 4 );
496 497
    speedControlLayout->addWidget( speedSlider );
    speedControlLayout->addWidget( normalSpeedButton );
498

499 500
    activateOnState();
}
501

502
void SpeedControlWidget::activateOnState()
503
{
504
    speedSlider->setEnabled( THEMIM->getIM()->hasInput() );
505 506
}

507 508
void SpeedControlWidget::updateControls( int rate )
{
509 510 511 512 513
    if( speedSlider->isSliderDown() )
    {
        //We don't want to change anything if the user is using the slider
        return;
    }
514

515
    double value = 17 * log( (double)INPUT_RATE_DEFAULT / rate ) / log( 2 );
516
    int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 );
517

518
    if( sliderValue < speedSlider->minimum() )
519
    {
520
        sliderValue = speedSlider->minimum();
521
    }
522
    else if( sliderValue > speedSlider->maximum() )
523
    {
524
        sliderValue = speedSlider->maximum();
525
    }
526

527
    speedSlider->setValue( sliderValue );
528 529 530 531
}

void SpeedControlWidget::updateRate( int sliderValue )
{
532
    double speed = pow( 2, (double)sliderValue / 17 );
533
    int rate = INPUT_RATE_DEFAULT / speed;
534

535
    THEMIM->getIM()->setRate(rate);
536 537 538 539
}

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

543
CoverArtLabel::CoverArtLabel( QWidget *parent, intf_thread_t *_p_i )
544
              : QLabel( parent ), p_intf( _p_i )
545 546
{
    setContextMenuPolicy( Qt::ActionsContextMenu );
547
    CONNECT( this, updateRequested(), this, askForUpdate() );
548

549
    setMinimumHeight( 128 );
550 551
    setMinimumWidth( 128 );
    setMaximumHeight( 128 );
552
    setMaximumWidth( 128 );
553 554
    setScaledContents( false );
    setAlignment( Qt::AlignCenter );
555

556 557
    QList< QAction* > artActions = actions();
    QAction *action = new QAction( qtr( "Download cover art" ), this );
558
    CONNECT( action, triggered(), this, askForUpdate() );
559
    addAction( action );
560

561
    showArtUpdate( "" );
562 563
}

564 565 566 567 568 569 570
CoverArtLabel::~CoverArtLabel()
{
    QList< QAction* > artActions = actions();
    foreach( QAction *act, artActions )
        removeAction( act );
}

571
void CoverArtLabel::showArtUpdate( const QString& url )
572
{
573
    QPixmap pix;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
574
    if( !url.isEmpty() && pix.load( url ) )
575
    {
576 577
        pix = pix.scaled( maximumWidth(), maximumHeight(),
                          Qt::KeepAspectRatioByExpanding );
578 579 580
    }
    else
    {
581
        pix = QPixmap( ":/noart.png" );
582
    }
583
    setPixmap( pix );
584 585
}

586
void CoverArtLabel::askForUpdate()
587
{
588
    THEMIM->getIM()->requestArtUpdate();
589 590
}

591 592 593
TimeLabel::TimeLabel( intf_thread_t *_p_intf  )
    : QLabel(), p_intf( _p_intf ), bufTimer( new QTimer(this) ),
      buffering( false ), showBuffering(false), bufVal( -1 )
594
{
595 596 597 598 599
    b_remainingTime = false;
    setText( " --:--/--:-- " );
    setAlignment( Qt::AlignRight | Qt::AlignVCenter );
    setToolTip( qtr( "Toggle between elapsed and remaining time" ) );
    bufTimer->setSingleShot( true );
600

601 602 603 604 605
    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() );
606 607
}

608
void TimeLabel::setDisplayPosition( float pos, int64_t t, int length )
609
{
610 611 612
    showBuffering = false;
    bufTimer->stop();

613
    if( pos == -1.f )
614 615 616 617
    {
        setText( " --:--/--:-- " );
        return;
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
618

619
    int time = t / 1000000;
620

621 622 623 624 625
    secstotimestr( psz_length, length );
    secstotimestr( psz_time, ( b_remainingTime && length ) ? length - time
                                                           : time );

    QString timestr;
JP Dinger's avatar
JP Dinger committed
626 627
    timestr.sprintf( " %s%s/%s ", (b_remainingTime && length) ? "-" : "",
                     psz_time, ( !length && time ) ? "--:--" : psz_length );
628

JP Dinger's avatar
JP Dinger committed
629
    setText( timestr );
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650

    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 ) );
    QString timestr;
    timestr.sprintf( " %s%s/%s ", (b_remainingTime && cachedLength) ? "-" : "",
                     psz_time, ( !cachedLength && time ) ? "--:--" : psz_length );

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