interface_widgets.cpp 20.8 KB
Newer Older
1
/*****************************************************************************
2
 * interface_widgets.cpp : Custom widgets for the main interface
3
 ****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2006-2010 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *          Jean-Baptiste Kempf <jb@videolan.org>
9
 *          Rafaël Carré <funman@videolanorg>
10
 *          Ilkka Ollakka <ileoo@videolan.org>
11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
15
 * ( at your option ) any later version.
16 17 18 19 20 21 22 23 24 25
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
26

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

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

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

#include <vlc_vout.h>
39

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

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

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

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

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

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

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

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

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

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

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

132
    layout->addWidget( stable );
133

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

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

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

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

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

178
    updateGeometry();
179
}
180

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Clément Stenac's avatar
Clément Stenac committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
void VisualSelector::prev()
{
    char *psz_new = aout_VisualPrev( p_intf );
    if( psz_new )
    {
        current->setText( qfu( psz_new ) );
        free( psz_new );
    }
}

void VisualSelector::next()
{
    char *psz_new = aout_VisualNext( p_intf );
    if( psz_new )
    {
        current->setText( qfu( psz_new ) );
        free( psz_new );
    }
}
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
331
#endif
Clément Stenac's avatar
Clément Stenac committed
332

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

447 448
    lastValue = 0;

449 450
    activateOnState();
}
451

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

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

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

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

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

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

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

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

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

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

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

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

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

522
    showArtUpdate( "" );
523 524
}

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

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

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

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

580
    bufTimer->setSingleShot( true );
581

582 583 584 585 586
    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() );
587 588

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

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

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

605
    int time = t / 1000000;
606

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

628 629 630
            setText( timestr );
            break;
    }
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
    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 ) );
646 647 648 649
    QString timestr = QString( " %1%2/%3 " )
        .arg( QString( (b_remainingTime && cachedLength) ? "-" : "" ) )
        .arg( QString( psz_time ) )
        .arg( QString( ( !cachedLength && time ) ? "--:--" : psz_length ) );
650 651

    setText( timestr );
652 653
}

654

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


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

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

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