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

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

60 61
#include <math.h>

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

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

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

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

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

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

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

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

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

    innerLayout->addWidget( stable );

    layout->addWidget( reparentable );

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

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

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

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

189

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

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

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

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

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

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

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

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

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

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

261 262
#endif

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

270

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

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

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

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

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

310 311 312 313
    QGridLayout *backgroundLayout = new QGridLayout( this );
    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
}

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

322 323 324 325 326 327 328 329
void BackgroundWidget::resizeEvent( QResizeEvent * event )
{
    if( event->size().height() <= MIN_BG_SIZE )
        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
    {
334
        if( QDate::currentDate().dayOfYear() >= 354 )
335
            label->setPixmap( QPixmap( ":/logo/vlc128-christmas.png" ) );
336
        else
337
            label->setPixmap( QPixmap( ":/logo/vlc128.png" ) );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
338
    }
339
    else
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
340
    {
341 342 343 344 345 346 347 348 349
        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
350
    }
351 352
}

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

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

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

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

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

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

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

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

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
413 414 415
SpeedLabel::SpeedLabel( intf_thread_t *_p_intf, const QString& text,
                        QWidget *parent )
           : QLabel( text, 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 428 429
    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 ) );

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

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

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

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

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

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

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

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

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

495 496
    activateOnState();
}
497

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

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

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

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

523 524 525 526
    //Block signals to avoid feedback loop
    speedSlider->blockSignals( true );
    speedSlider->setValue( sliderValue );
    speedSlider->blockSignals( false );
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 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(), cachingChanged( float ),
            this, setCaching( float ) );
600 601
   CONNECT( THEMIM->getIM(), positionUpdated( float, int64_t, int ),
             this, setDisplayPosition( float, int64_t, int ) );
602 603
}

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

612
    int time = t / 1000000;
613 614 615 616 617 618
    char psz_length[MSTRTIME_MAX_SIZE], psz_time[MSTRTIME_MAX_SIZE];
    secstotimestr( psz_length, length );
    secstotimestr( psz_time, ( b_remainingTime && length ) ? length - time
                                                           : time );

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

JP Dinger's avatar
JP Dinger committed
622
    setText( timestr );
623 624 625 626 627 628
}

void TimeLabel::toggleTimeDisplay()
{
    b_remainingTime = !b_remainingTime;
}
629

630 631
void TimeLabel::setCaching( float f_cache )
{
632
    QString amount;
JP Dinger's avatar
JP Dinger committed
633 634
    amount.sprintf("Buff: %i%%", (int)(100*f_cache) );
    setText( amount );
635 636
}

637