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

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

61 62
#include <math.h>

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

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

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

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

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

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

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

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

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

    innerLayout->addWidget( stable );

    layout->addWidget( reparentable );

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

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

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

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

190

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

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

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

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

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

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

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

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

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

255 256 257 258
        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);
259
    }
260 261
    CoUninitialize();

262 263
#endif

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

271

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

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

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

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

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

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

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

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

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

331
void BackgroundWidget::updateArt( const QString& url )
332
{
333
    if( url.isEmpty() )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
334
    {
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

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

    /* Create the Speed Control Widget */
421
    speedControl = new SpeedControlWidget( p_intf, this );
422 423 424 425 426 427 428 429 430
    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 ) );

431
    CONNECT( THEMIM, inputChanged( input_thread_t * ),
432
             speedControl, activateOnState() );
433

434
}
435 436 437 438 439
SpeedLabel::~SpeedLabel()
{
        delete speedControl;
        delete speedControlMenu;
}
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
/****************************************************************************
 * Small right-click menu for rate control
 ****************************************************************************/
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 );
}

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

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

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

480
    CONNECT( speedSlider, valueChanged( int ), this, updateRate( int ) );
481

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

488
    CONNECT( normalSpeedButton, clicked(), this, resetRate() );
489

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

496 497
    activateOnState();
}
498

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

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

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

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

524 525 526 527
    //Block signals to avoid feedback loop
    speedSlider->blockSignals( true );
    speedSlider->setValue( sliderValue );
    speedSlider->blockSignals( false );
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 594 595 596 597
TimeLabel::TimeLabel( intf_thread_t *_p_intf  ) :QLabel(), p_intf( _p_intf )
{
   b_remainingTime = false;
   setText( " --:--/--:-- " );
   setAlignment( Qt::AlignRight | Qt::AlignVCenter );
   setToolTip( qtr( "Toggle between elapsed and remaining time" ) );

598 599
   CONNECT( THEMIM->getIM(), positionUpdated( float, int64_t, int ),
             this, setDisplayPosition( float, int64_t, int ) );
600 601
}

602
void TimeLabel::setDisplayPosition( float pos, int64_t t, int length )
603
{
604
    if( pos == -1.f )
605 606 607 608
    {
        setText( " --:--/--:-- " );
        return;
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
609

610
    int time = t / 1000000;
611

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

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

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

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

644

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

650 651
CacheLabel::CacheLabel( intf_thread_t *_p_intf, QWidget *parent )
  : QLabel( parent ), p_intf( _p_intf ), cached( 0.f )
652
{
653 654 655 656 657 658 659 660 661
    setText( qtr( "Buffering..." ) );
    setMinimumWidth( 70 );
    setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
    setAlignment( Qt::AlignCenter );

    CONNECT( THEMIM->getIM(), cachingChanged( float ),
              this, showCaching( float ) );
    CONNECT( THEMIM->getIM(), positionUpdated( float, int64_t, int ),
              this, hideCaching() );
662 663
}

664 665 666 667 668 669
void CacheLabel::showCaching( float _cached )
{
    cached = _cached;
    show();
    update(); //in case we are already visible
}
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
void CacheLabel::hideCaching()
{
    hide();
}

void CacheLabel::paintEvent( QPaintEvent* event )
{
    QRect r( rect() );
    r.setWidth( r.width() * cached );
    QPainter p( this );
    p.setOpacity( 0.4 );
    p.fillRect( r, palette().color( QPalette::Highlight ) );

    QLabel::paintEvent( event );
}