interface_widgets.cpp 19.9 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>
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 */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
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
#define MARGIN 5
286

287 288
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
                 :QWidget( NULL ), p_intf( _p_i )
289
{
290
    /* We should use that one to take the more size it can */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
291
    //setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding);
292

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

300
    /* A cone in the middle */
301
    label = new QLabel;
302
    label->setMargin( MARGIN );
303
    label->setAlignment( Qt::AlignCenter );
304

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
305 306 307 308
    /* Init the cone art */
    updateArt( "" );

    /* Grid, because of the visual selector */
309
    QGridLayout *backgroundLayout = new QGridLayout( this );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
310
    backgroundLayout->setMargin( 0 );
311 312 313
    backgroundLayout->addWidget( label, 0, 1 );
    backgroundLayout->setColumnStretch( 0, 1 );
    backgroundLayout->setColumnStretch( 2, 1 );
314

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

    /* Start Hidden */
    label->hide();
320 321
}

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

330
void BackgroundWidget::updateArt( const QString& url )
331
{
332
    if( url.isEmpty() )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
333
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
334
        /* Xmas joke */
335
        if( QDate::currentDate().dayOfYear() >= 354 )
336
            label->setPixmap( QPixmap( ":/logo/vlc128-christmas.png" ) );
337
        else
338
            label->setPixmap( QPixmap( ":/logo/vlc128.png" ) );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
339
    }
340
    else
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
341
    {
342 343 344 345 346 347 348 349 350
        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
351
    }
352 353
}

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

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

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

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

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

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

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

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

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

414 415
SpeedLabel::SpeedLabel( intf_thread_t *_p_intf, QWidget *parent )
           : QLabel( parent ), p_intf( _p_intf )
416
{
417
    setToolTip( qtr( "Current playback speed.\nClick to adjust" ) );
418 419

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

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

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

430 431
    DCONNECT( THEMIM, inputChanged( input_thread_t * ),
              speedControl, activateOnState() );
432
    setRate( var_InheritFloat( p_intf, "rate" ) );
433
}
434

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

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

445 446 447 448 449 450
void SpeedLabel::showSpeedMenu( QPoint pos )
{
    speedControlMenu->exec( QCursor::pos() - pos
                          + QPoint( 0, height() ) );
}

451
void SpeedLabel::setRate( float rate )
452 453
{
    QString str;
454
    str.setNum( rate, 'f', 2 );
455 456 457 458 459 460
    str.append( "x" );
    setText( str );
    setToolTip( str );
    speedControl->updateControls( rate );
}

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

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

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

482
    CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
483

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

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

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

498 499
    activateOnState();
}
500

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

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

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

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

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

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

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

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

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

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

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

560
    showArtUpdate( "" );
561 562
}

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

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

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

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

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

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

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

618
    int time = t / 1000000;
619

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

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

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

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

652

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


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

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

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