interface_widgets.cpp 19.7 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>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
48

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

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

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

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

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

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

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

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

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

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

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

    innerLayout->addWidget( stable );

    layout->addWidget( reparentable );

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

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

172
/* Set the Widget to the correct Size */
173
/* Function has to be called by the parent
Rémi Denis-Courmont's avatar
typo  
Rémi Denis-Courmont committed
174
   Parent has to care about resizing itself */
175
void VideoWidget::SetSizing( unsigned int w, unsigned int h )
176
{
177 178
    if (reparentable->windowState() & Qt::WindowFullScreen )
        return;
179
    if( !isVisible() ) show();
180 181
    resize( w, h );
    emit sizeChanged( w, h );
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
    updateGeometry();
268
    hide();
269
}
270

271 272
/**********************************************************************
 * Background Widget. Show a simple image background. Currently,
273
 * it's album art if present or cone.
274
 **********************************************************************/
275 276
#define ICON_SIZE 128
#define MAX_BG_SIZE 400
277
#define MIN_BG_SIZE 128
278
#define MARGIN 5
279

280 281
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
                 :QWidget( NULL ), p_intf( _p_i )
282
{
283
    /* We should use that one to take the more size it can */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
284
    //setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding);
285

286
    /* A dark background */
Clément Stenac's avatar
Clément Stenac committed
287
    setAutoFillBackground( true );
288
    QPalette plt = palette();
289 290 291 292
    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
    setPalette( plt );

293
    /* A cone in the middle */
294
    label = new QLabel;
295
    label->setMargin( MARGIN );
296
    label->setAlignment( Qt::AlignCenter );
297

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
298 299 300 301
    /* Init the cone art */
    updateArt( "" );

    /* Grid, because of the visual selector */
302
    QGridLayout *backgroundLayout = new QGridLayout( this );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
303
    backgroundLayout->setMargin( 0 );
304 305 306
    backgroundLayout->addWidget( label, 0, 1 );
    backgroundLayout->setColumnStretch( 0, 1 );
    backgroundLayout->setColumnStretch( 2, 1 );
307

308
    CONNECT( THEMIM->getIM(), artChanged( QString ),
309
             this, updateArt( const QString& ) );
310 311 312

    /* Start Hidden */
    label->hide();
313 314
}

315 316
void BackgroundWidget::resizeEvent( QResizeEvent * event )
{
317
    if( event->size().height() <= MIN_BG_SIZE + MARGIN * 2 + 2 )
318 319 320 321 322
        label->hide();
    else
        label->show();
}

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

347 348 349
void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
{
    QVLCMenu::PopupMenu( p_intf, true );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
350
    event->accept();
351
}
352

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
353
#if 0
354 355 356
#include <QPushButton>
#include <QHBoxLayout>

Clément Stenac's avatar
Clément Stenac committed
357 358 359 360
/**********************************************************************
 * Visualization selector panel
 **********************************************************************/
VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
361
                                QFrame( NULL ), p_intf( _p_i )
Clément Stenac's avatar
Clément Stenac committed
362 363
{
    QHBoxLayout *layout = new QHBoxLayout( this );
364
    layout->setMargin( 0 );
Clément Stenac's avatar
Clément Stenac committed
365
    QPushButton *prevButton = new QPushButton( "Prev" );
366
    QPushButton *nextButton = new QPushButton( "Next" );
Clément Stenac's avatar
Clément Stenac committed
367 368
    layout->addWidget( prevButton );
    layout->addWidget( nextButton );
Clément Stenac's avatar
Clément Stenac committed
369

370
    layout->addStretch( 10 );
371
    layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
Clément Stenac's avatar
Clément Stenac committed
372 373 374 375 376 377 378

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

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

Clément Stenac's avatar
Clément Stenac committed
379
    setLayout( layout );
380
    setMaximumHeight( 35 );
Clément Stenac's avatar
Clément Stenac committed
381 382 383
}

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

Clément Stenac's avatar
Clément Stenac committed
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
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
405
#endif
Clément Stenac's avatar
Clément Stenac committed
406

407 408
SpeedLabel::SpeedLabel( intf_thread_t *_p_intf, QWidget *parent )
           : QLabel( parent ), p_intf( _p_intf )
409
{
410
    setToolTip( qtr( "Current playback speed.\nClick to adjust" ) );
411 412

    /* Create the Speed Control Widget */
413
    speedControl = new SpeedControlWidget( p_intf, this );
414 415 416 417 418 419 420
    speedControlMenu = new QMenu( this );

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

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

423 424
    DCONNECT( THEMIM, inputChanged( input_thread_t * ),
              speedControl, activateOnState() );
425
    setRate( var_InheritFloat( p_intf, "rate" ) );
426
}
427

428 429
SpeedLabel::~SpeedLabel()
{
430 431
    delete speedControl;
    delete speedControlMenu;
432
}
433

434 435 436
/****************************************************************************
 * Small right-click menu for rate control
 ****************************************************************************/
437

438 439 440 441 442 443
void SpeedLabel::showSpeedMenu( QPoint pos )
{
    speedControlMenu->exec( QCursor::pos() - pos
                          + QPoint( 0, height() ) );
}

444
void SpeedLabel::setRate( float rate )
445 446
{
    QString str;
447
    str.setNum( rate, 'f', 2 );
448 449 450 451 452 453
    str.append( "x" );
    setText( str );
    setToolTip( str );
    speedControl->updateControls( rate );
}

454 455 456
/**********************************************************************
 * Speed control widget
 **********************************************************************/
457 458
SpeedControlWidget::SpeedControlWidget( intf_thread_t *_p_i, QWidget *_parent )
                    : QFrame( _parent ), p_intf( _p_i )
459
{
460
    QSizePolicy sizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed );
461 462
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );
463

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
464
    speedSlider = new QSlider( this );
465 466 467 468 469
    speedSlider->setSizePolicy( sizePolicy );
    speedSlider->setMaximumSize( QSize( 80, 200 ) );
    speedSlider->setOrientation( Qt::Vertical );
    speedSlider->setTickPosition( QSlider::TicksRight );

470
    speedSlider->setRange( -34, 34 );
471 472
    speedSlider->setSingleStep( 1 );
    speedSlider->setPageStep( 1 );
473
    speedSlider->setTickInterval( 17 );
474

475
    CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
476

477
    QToolButton *normalSpeedButton = new QToolButton( this );
478
    normalSpeedButton->setMaximumSize( QSize( 26, 20 ) );
479
    normalSpeedButton->setAutoRaise( true );
480
    normalSpeedButton->setText( "1x" );
481
    normalSpeedButton->setToolTip( qtr( "Revert to normal play speed" ) );
482

483
    CONNECT( normalSpeedButton, clicked(), this, resetRate() );
484

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
485
    QVBoxLayout *speedControlLayout = new QVBoxLayout( this );
486
    speedControlLayout->setContentsMargins( 4, 4, 4, 4 );
487
    speedControlLayout->setSpacing( 4 );
488 489
    speedControlLayout->addWidget( speedSlider );
    speedControlLayout->addWidget( normalSpeedButton );
490

491 492
    activateOnState();
}
493

494
void SpeedControlWidget::activateOnState()
495
{
496
    speedSlider->setEnabled( THEMIM->getIM()->hasInput() );
497 498
}

499
void SpeedControlWidget::updateControls( float rate )
500
{
501 502 503 504 505
    if( speedSlider->isSliderDown() )
    {
        //We don't want to change anything if the user is using the slider
        return;
    }
506

507
    double value = 17 * log( rate ) / log( 2 );
508
    int sliderValue = (int) ( ( value > 0 ) ? value + .5 : value - .5 );
509

510
    if( sliderValue < speedSlider->minimum() )
511
    {
512
        sliderValue = speedSlider->minimum();
513
    }
514
    else if( sliderValue > speedSlider->maximum() )
515
    {
516
        sliderValue = speedSlider->maximum();
517
    }
518

519
    speedSlider->setValue( sliderValue );
520 521 522 523
}

void SpeedControlWidget::updateRate( int sliderValue )
{
524
    double speed = pow( 2, (double)sliderValue / 17 );
525
    int rate = INPUT_RATE_DEFAULT / speed;
526

527
    THEMIM->getIM()->setRate(rate);
528 529 530 531
}

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

535
CoverArtLabel::CoverArtLabel( QWidget *parent, intf_thread_t *_p_i )
536
              : QLabel( parent ), p_intf( _p_i )
537 538
{
    setContextMenuPolicy( Qt::ActionsContextMenu );
539
    CONNECT( this, updateRequested(), this, askForUpdate() );
540

541
    setMinimumHeight( 128 );
542 543
    setMinimumWidth( 128 );
    setMaximumHeight( 128 );
544
    setMaximumWidth( 128 );
545 546
    setScaledContents( false );
    setAlignment( Qt::AlignCenter );
547

548 549
    QList< QAction* > artActions = actions();
    QAction *action = new QAction( qtr( "Download cover art" ), this );
550
    CONNECT( action, triggered(), this, askForUpdate() );
551
    addAction( action );
552

553
    showArtUpdate( "" );
554 555
}

556 557 558 559 560 561 562
CoverArtLabel::~CoverArtLabel()
{
    QList< QAction* > artActions = actions();
    foreach( QAction *act, artActions )
        removeAction( act );
}

563
void CoverArtLabel::showArtUpdate( const QString& url )
564
{
565
    QPixmap pix;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
566
    if( !url.isEmpty() && pix.load( url ) )
567
    {
568 569
        pix = pix.scaled( maximumWidth(), maximumHeight(),
                          Qt::KeepAspectRatioByExpanding );
570 571 572
    }
    else
    {
573
        pix = QPixmap( ":/noart.png" );
574
    }
575
    setPixmap( pix );
576 577
}

578
void CoverArtLabel::askForUpdate()
579
{
580
    THEMIM->getIM()->requestArtUpdate();
581 582
}

583 584 585
TimeLabel::TimeLabel( intf_thread_t *_p_intf  )
    : QLabel(), p_intf( _p_intf ), bufTimer( new QTimer(this) ),
      buffering( false ), showBuffering(false), bufVal( -1 )
586
{
587 588 589 590 591
    b_remainingTime = false;
    setText( " --:--/--:-- " );
    setAlignment( Qt::AlignRight | Qt::AlignVCenter );
    setToolTip( qtr( "Toggle between elapsed and remaining time" ) );
    bufTimer->setSingleShot( true );
592

593 594 595 596 597
    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() );
598 599
}

600
void TimeLabel::setDisplayPosition( float pos, int64_t t, int length )
601
{
602 603 604
    showBuffering = false;
    bufTimer->stop();

605
    if( pos == -1.f )
606 607 608 609
    {
        setText( " --:--/--:-- " );
        return;
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
610

611
    int time = t / 1000000;
612

613 614 615 616 617
    secstotimestr( psz_length, length );
    secstotimestr( psz_time, ( b_remainingTime && length ) ? length - time
                                                           : time );

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

JP Dinger's avatar
JP Dinger committed
621
    setText( timestr );
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642

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

645

646 647 648 649
void TimeLabel::toggleTimeDisplay()
{
    b_remainingTime = !b_remainingTime;
}
650 651


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

669
void TimeLabel::updateBuffering()
670
{
671 672
    showBuffering = true;
    update();
673 674
}

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