interface_widgets.cpp 38.2 KB
Newer Older
1
/*****************************************************************************
2
 * interface_widgets.cpp : Custom widgets for the main interface
3
 ****************************************************************************
4
 * Copyright ( C ) 2006 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

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
31 32
#include <vlc_vout.h>

33
#include "dialogs_provider.hpp"
34
#include "components/interface_widgets.hpp"
35
#include "main_interface.hpp"
36
#include "input_manager.hpp"
37
#include "menus.hpp"
38
#include "util/input_slider.hpp"
39
#include "util/customwidgets.hpp"
40

Clément Stenac's avatar
Clément Stenac committed
41 42
#include <QLabel>
#include <QSpacerItem>
Clément Stenac's avatar
Clément Stenac committed
43
#include <QCursor>
Clément Stenac's avatar
Clément Stenac committed
44
#include <QPushButton>
45
#include <QToolButton>
46
#include <QHBoxLayout>
Clément Stenac's avatar
Clément Stenac committed
47
#include <QMenu>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
48 49
#include <QPalette>
#include <QResizeEvent>
50
#include <QDate>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
51

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

57 58
#include <math.h>

59 60 61 62
/**********************************************************************
 * Video Widget. A simple frame on which video is drawn
 * This class handles resize issues
 **********************************************************************/
63

64
VideoWidget::VideoWidget( intf_thread_t *_p_i ) : QFrame( NULL ), p_intf( _p_i )
65
{
66
    /* Init */
67
    i_vout = 0;
68
    hide(); setMinimumSize( 16, 16 );
69 70
    videoSize.rwidth() = -1;
    videoSize.rheight() = -1;
71
    setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
72

73 74 75 76 77
    /* Black background is more coherent for a Video Widget IMVHO */
    QPalette plt =  palette();
    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
    setPalette( plt );
78
    setAttribute( Qt::WA_PaintOnScreen, true );
79

80
    /* The core can ask through a callback to show the video. */
81
#if HAS_QT43
82 83 84
    connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)),
             this, SLOT(SetSizing(unsigned int, unsigned int )),
             Qt::BlockingQueuedConnection );
85 86 87 88 89
#else
#error This is broken. Fix it with a QEventLoop with a processEvents () 
    connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)),
             this, SLOT(SetSizing(unsigned int, unsigned int )) );
#endif
90 91
}

92 93 94
void VideoWidget::paintEvent(QPaintEvent *ev)
{
    QFrame::paintEvent(ev);
95 96 97
#ifdef Q_WS_X11
    XFlush( QX11Info::display() );
#endif
98 99
}

100 101
VideoWidget::~VideoWidget()
{
102 103 104
    vout_thread_t *p_vout = i_vout
        ? (vout_thread_t *)vlc_object_get( i_vout ) : NULL;

105 106 107 108 109 110 111 112 113 114 115 116
    if( p_vout )
    {
        if( !p_intf->psz_switch_intf )
        {
            if( vout_Control( p_vout, VOUT_CLOSE ) != VLC_SUCCESS )
                vout_Control( p_vout, VOUT_REPARENT );
        }
        else
        {
            if( vout_Control( p_vout, VOUT_REPARENT ) != VLC_SUCCESS )
                vout_Control( p_vout, VOUT_CLOSE );
        }
117
        vlc_object_release( p_vout );
118 119 120
    }
}

121
/**
122
 * Request the video to avoid the conflicts
123
 **/
124
void *VideoWidget::request( vout_thread_t *p_nvout, int *pi_x, int *pi_y,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
125
                            unsigned int *pi_width, unsigned int *pi_height )
126
{
127
    msg_Dbg( p_intf, "Video was requested %i, %i", *pi_x, *pi_y );
128
    emit askVideoWidgetToShow( *pi_width, *pi_height );
129
    if( i_vout )
130 131 132 133
    {
        msg_Dbg( p_intf, "embedded video already in use" );
        return NULL;
    }
134
    i_vout = p_nvout->i_object_id;
135
    msg_Dbg( p_intf, "embedded video ready (handle %p)", winId() );
136
    return ( void* )winId();
137 138
}

139
/* Set the Widget to the correct Size */
140 141
/* Function has to be called by the parent
   Parent has to care about resizing himself*/
142
void VideoWidget::SetSizing( unsigned int w, unsigned int h )
143
{
144 145 146
    msg_Dbg( p_intf, "Video is resizing to: %i %i", w, h );
    videoSize.rwidth() = w;
    videoSize.rheight() = h;
147
    if( isHidden() ) show();
148
    updateGeometry(); // Needed for deinterlace
149 150
}

151
void VideoWidget::release( void *p_win )
152
{
Rémi Denis-Courmont's avatar
Typo  
Rémi Denis-Courmont committed
153
    msg_Dbg( p_intf, "Video is not needed anymore" );
154
    i_vout = 0;
155 156 157 158
    videoSize.rwidth() = 0;
    videoSize.rheight() = 0;
    hide();
    updateGeometry(); // Needed for deinterlace
159
}
160

161 162 163 164
QSize VideoWidget::sizeHint() const
{
    return videoSize;
}
165

166 167
/**********************************************************************
 * Background Widget. Show a simple image background. Currently,
168
 * it's album art if present or cone.
169
 **********************************************************************/
170 171 172 173
#define ICON_SIZE 128
#define MAX_BG_SIZE 400
#define MIN_BG_SIZE 64

174 175
BackgroundWidget::BackgroundWidget( intf_thread_t *_p_i )
                 :QWidget( NULL ), p_intf( _p_i )
176
{
177
    /* We should use that one to take the more size it can */
178
    setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding);
179

180
    /* A dark background */
Clément Stenac's avatar
Clément Stenac committed
181
    setAutoFillBackground( true );
182 183 184 185 186
    plt =  palette();
    plt.setColor( QPalette::Active, QPalette::Window , Qt::black );
    plt.setColor( QPalette::Inactive, QPalette::Window , Qt::black );
    setPalette( plt );

187
    /* A cone in the middle */
188
    label = new QLabel;
189
    label->setMargin( 5 );
190 191
    label->setMaximumHeight( MAX_BG_SIZE );
    label->setMaximumWidth( MAX_BG_SIZE );
192 193
    label->setMinimumHeight( MIN_BG_SIZE );
    label->setMinimumWidth( MIN_BG_SIZE );
194 195 196 197
    if( QDate::currentDate().dayOfYear() >= 354 )
        label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) );
    else
        label->setPixmap( QPixmap( ":/vlc128.png" ) );
198

199 200 201 202
    QGridLayout *backgroundLayout = new QGridLayout( this );
    backgroundLayout->addWidget( label, 0, 1 );
    backgroundLayout->setColumnStretch( 0, 1 );
    backgroundLayout->setColumnStretch( 2, 1 );
203

204
    CONNECT( THEMIM->getIM(), artChanged( QString ), this, updateArt( QString ) );
205 206
}

Clément Stenac's avatar
Clément Stenac committed
207
BackgroundWidget::~BackgroundWidget()
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
208
{}
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
209

210 211 212 213 214 215 216 217
void BackgroundWidget::resizeEvent( QResizeEvent * event )
{
    if( event->size().height() <= MIN_BG_SIZE )
        label->hide();
    else
        label->show();
}

218
void BackgroundWidget::updateArt( QString url )
219
{
220
    if( url.isEmpty() )
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
221
    {
222 223 224 225
        if( QDate::currentDate().dayOfYear() >= 354 )
            label->setPixmap( QPixmap( ":/vlc128-christmas.png" ) );
        else
            label->setPixmap( QPixmap( ":/vlc128.png" ) );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
226 227
        return;
    }
228
    else
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
229
    {
230
        label->setPixmap( QPixmap( url ) );
Ilkka Ollakka's avatar
 
Ilkka Ollakka committed
231
    }
232 233
}

234 235 236 237
void BackgroundWidget::contextMenuEvent( QContextMenuEvent *event )
{
    QVLCMenu::PopupMenu( p_intf, true );
}
238

Clément Stenac's avatar
Clément Stenac committed
239 240 241 242
/**********************************************************************
 * Visualization selector panel
 **********************************************************************/
VisualSelector::VisualSelector( intf_thread_t *_p_i ) :
243
                                QFrame( NULL ), p_intf( _p_i )
Clément Stenac's avatar
Clément Stenac committed
244 245
{
    QHBoxLayout *layout = new QHBoxLayout( this );
246
    layout->setMargin( 0 );
Clément Stenac's avatar
Clément Stenac committed
247
    QPushButton *prevButton = new QPushButton( "Prev" );
248
    QPushButton *nextButton = new QPushButton( "Next" );
Clément Stenac's avatar
Clément Stenac committed
249 250
    layout->addWidget( prevButton );
    layout->addWidget( nextButton );
Clément Stenac's avatar
Clément Stenac committed
251 252

    layout->addItem( new QSpacerItem( 40,20,
253
                              QSizePolicy::Expanding, QSizePolicy::Minimum ) );
254
    layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
Clément Stenac's avatar
Clément Stenac committed
255 256 257 258 259 260 261

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

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

Clément Stenac's avatar
Clément Stenac committed
262
    setLayout( layout );
263
    setMaximumHeight( 35 );
Clément Stenac's avatar
Clément Stenac committed
264 265 266
}

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

Clément Stenac's avatar
Clément Stenac committed
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
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 );
    }
}

/**********************************************************************
290
 * TEH controls
Clément Stenac's avatar
Clément Stenac committed
291
 **********************************************************************/
292 293 294 295 296 297

#define setupSmallButton( aButton ){  \
    aButton->setMaximumSize( QSize( 26, 26 ) ); \
    aButton->setMinimumSize( QSize( 26, 26 ) ); \
    aButton->setIconSize( QSize( 20, 20 ) ); }

298
AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i ) :
Clément Stenac's avatar
Clément Stenac committed
299 300
                                           QFrame( NULL ), p_intf( _p_i )
{
301 302 303
    QHBoxLayout *advLayout = new QHBoxLayout( this );
    advLayout->setMargin( 0 );
    advLayout->setSpacing( 0 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
304
    advLayout->setAlignment( Qt::AlignBottom );
Clément Stenac's avatar
Clément Stenac committed
305

306
    /* A to B Button */
307
    ABButton = new QPushButton( "AB" );
Lukas Durfina's avatar
Lukas Durfina committed
308
    setupSmallButton( ABButton );
309
    advLayout->addWidget( ABButton );
310
    BUTTON_SET_ACT( ABButton, "AB", qtr( "A to B" ), fromAtoB() );
311
    timeA = timeB = 0;
312 313
    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
             this, AtoBLoop( float, int, int ) );
314
#if 0
315 316 317 318
    frameButton = new QPushButton( "Fr" );
    frameButton->setMaximumSize( QSize( 26, 26 ) );
    frameButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( frameButton );
319
    BUTTON_SET_ACT( frameButton, "Fr", qtr( "Frame by frame" ), frame() );
320
#endif
321 322

    recordButton = new QPushButton( "R" );
Lukas Durfina's avatar
Lukas Durfina committed
323
    setupSmallButton( recordButton );
324
    advLayout->addWidget( recordButton );
325
    BUTTON_SET_ACT_I( recordButton, "", record_16px.png,
326
            qtr( "Record" ), record() );
327

328
    /* Snapshot Button */
329
    snapshotButton = new QPushButton( "S" );
Lukas Durfina's avatar
Lukas Durfina committed
330
    setupSmallButton( snapshotButton );
331 332
    advLayout->addWidget( snapshotButton );
    BUTTON_SET_ACT( snapshotButton, "S", qtr( "Take a snapshot" ), snapshot() );
Clément Stenac's avatar
Clément Stenac committed
333 334
}

335
AdvControlsWidget::~AdvControlsWidget()
336
{}
Clément Stenac's avatar
Clément Stenac committed
337

338
void AdvControlsWidget::enableInput( bool enable )
Clément Stenac's avatar
Clément Stenac committed
339
{
340 341
    ABButton->setEnabled( enable );
    recordButton->setEnabled( enable );
Clément Stenac's avatar
Clément Stenac committed
342
}
343

344
void AdvControlsWidget::enableVideo( bool enable )
Clément Stenac's avatar
Clément Stenac committed
345 346
{
    snapshotButton->setEnabled( enable );
347
#if 0
348
    frameButton->setEnabled( enable );
349
#endif
Clément Stenac's avatar
Clément Stenac committed
350 351
}

352
void AdvControlsWidget::snapshot()
Clément Stenac's avatar
Clément Stenac committed
353
{
354 355
    vout_thread_t *p_vout =
        (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
356
    if( p_vout ) vout_Control( p_vout, VOUT_SNAPSHOT );
Clément Stenac's avatar
Clément Stenac committed
357 358
}

359
/* Function called when the button is clicked() */
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
void AdvControlsWidget::fromAtoB()
{
    if( !timeA )
    {
        timeA = var_GetTime( THEMIM->getInput(), "time"  );
        ABButton->setText( "A->..." );
        return;
    }
    if( !timeB )
    {
        timeB = var_GetTime( THEMIM->getInput(), "time"  );
        var_SetTime( THEMIM->getInput(), "time" , timeA );
        ABButton->setText( "A<=>B" );
        return;
    }
    timeA = 0;
    timeB = 0;
    ABButton->setText( "AB" );
}
379

380
/* Function called regularly when in an AtoB loop */
381 382 383 384
void AdvControlsWidget::AtoBLoop( float f_pos, int i_time, int i_length )
{
    if( timeB )
    {
385
        if( i_time >= (int)(timeB/1000000) )
386 387 388
            var_SetTime( THEMIM->getInput(), "time" , timeA );
    }
}
389

390
/* FIXME Record function */
391
void AdvControlsWidget::record(){}
392

393
#if 0
394
//FIXME Frame by frame function
395
void AdvControlsWidget::frame(){}
396
#endif
397

398 399 400
/*****************************
 * DA Control Widget !
 *****************************/
401
ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
402
                                MainInterface *_p_mi,
403
                                bool b_advControls,
Lukas Durfina's avatar
Lukas Durfina committed
404 405 406
                                bool b_shiny,
                                bool b_fsCreation) :
                                QFrame( _p_mi ), p_intf( _p_i )
407
{
Lukas Durfina's avatar
Lukas Durfina committed
408 409
    controlLayout = new QGridLayout( );

410
    controlLayout->setSpacing( 0 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
411
    controlLayout->setLayoutMargins( 7, 5, 7, 3, 6 );
412

Lukas Durfina's avatar
Lukas Durfina committed
413 414 415
    if( !b_fsCreation )
        setLayout( controlLayout );

416
    setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
417

418 419
    /** The main Slider **/
    slider = new InputSlider( Qt::Horizontal, NULL );
420
    controlLayout->addWidget( slider, 0, 1, 1, 16 );
421 422
    /* Update the position when the IM has changed */
    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
423
             slider, setPosition( float, int, int ) );
424 425 426 427
    /* And update the IM, when the position has changed */
    CONNECT( slider, sliderDragged( float ),
             THEMIM->getIM(), sliderUpdate( float ) );

428
    /** Slower and faster Buttons **/
429 430
    slowerButton = new QToolButton;
    slowerButton->setAutoRaise( true );
431
    slowerButton->setMaximumSize( QSize( 26, 20 ) );
432

433
    BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() );
434 435
    controlLayout->addWidget( slowerButton, 0, 0 );

436 437
    fasterButton = new QToolButton;
    fasterButton->setAutoRaise( true );
438
    fasterButton->setMaximumSize( QSize( 26, 20 ) );
439

440
    BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() );
441
    controlLayout->addWidget( fasterButton, 0, 17 );
442

443 444 445 446
    /* advanced Controls handling */
    b_advancedVisible = b_advControls;

    advControls = new AdvControlsWidget( p_intf );
447
    controlLayout->addWidget( advControls, 1, 3, 2, 4, Qt::AlignBottom );
448 449
    if( !b_advancedVisible ) advControls->hide();

450
    /** Disc and Menus handling */
451
    discFrame = new QWidget( this );
452

453 454 455
    QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
    discLayout->setSpacing( 0 );
    discLayout->setMargin( 0 );
456

457
    prevSectionButton = new QPushButton( discFrame );
458
    setupSmallButton( prevSectionButton );
459 460
    discLayout->addWidget( prevSectionButton );

461
    menuButton = new QPushButton( discFrame );
462 463 464
    setupSmallButton( menuButton );
    discLayout->addWidget( menuButton );

465
    nextSectionButton = new QPushButton( discFrame );
466
    setupSmallButton( nextSectionButton );
467 468
    discLayout->addWidget( nextSectionButton );

469
    controlLayout->addWidget( discFrame, 1, 10, 2, 3, Qt::AlignBottom );
470 471 472

    BUTTON_SET_IMG( prevSectionButton, "", previous.png, "" );
    BUTTON_SET_IMG( nextSectionButton, "", next.png, "" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
473
    BUTTON_SET_IMG( menuButton, "", previous.png, qtr( "Menu" ) );
474

475
    discFrame->hide();
476 477 478

    /* Change the navigation button display when the IM navigation changes */
    CONNECT( THEMIM->getIM(), navigationChanged( int ),
479
             this, setNavigation( int ) );
480 481 482 483 484 485 486
    /* Changes the IM navigation when triggered on the nav buttons */
    CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
             sectionPrev() );
    CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
             sectionNext() );
    CONNECT( menuButton, clicked(), THEMIM->getIM(),
             sectionMenu() );
487

488
    /**
489
     * Telextext QFrame
490
     * TODO: Merge with upper menu in a StackLayout
491
     **/
492 493 494 495 496
    telexFrame = new QWidget( this );
    QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
    telexLayout->setSpacing( 0 );
    telexLayout->setMargin( 0 );

Lukas Durfina's avatar
Lukas Durfina committed
497
    telexOn = new QPushButton;
498 499 500
    setupSmallButton( telexOn );
    telexLayout->addWidget( telexOn );

501
    telexTransparent = new QPushButton;
502 503
    setupSmallButton( telexTransparent );
    telexLayout->addWidget( telexTransparent );
504
    b_telexTransparent = false;
505

506
    telexPage = new QSpinBox;
507
    telexPage->setRange( 0, 999 );
508
    telexPage->setValue( 100 );
509 510
    telexPage->setAccelerated( true );
    telexPage->setWrapping( true );
511
    telexPage->setAlignment( Qt::AlignRight );
512
    telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
513 514
    telexLayout->addWidget( telexPage );

Lukas Durfina's avatar
Lukas Durfina committed
515 516
    if( !b_fsCreation )
        controlLayout->addWidget( telexFrame, 1, 10, 2, 4, Qt::AlignBottom );
517
    telexFrame->hide(); /* default hidden */
518 519 520

    CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
             telexGotoPage( int ) );
Lukas Durfina's avatar
Lukas Durfina committed
521 522 523 524
    CONNECT( THEMIM->getIM(), setNewTelexPage( int ),
              telexPage, setValue( int ) );

    BUTTON_SET_IMG( telexOn, "", tv.png, qtr( "Teletext on" ) );
525

Lukas Durfina's avatar
Lukas Durfina committed
526 527
    CONNECT( telexOn, clicked(), THEMIM->getIM(),
             telexToggleButtons() );
528 529
    CONNECT( telexOn, clicked( bool ), THEMIM->getIM(),
             telexToggle( bool ) );
Lukas Durfina's avatar
Lukas Durfina committed
530 531 532
    CONNECT( THEMIM->getIM(), toggleTelexButtons(),
              this, toggleTeletext() );
    b_telexEnabled = false;
533 534 535
    telexTransparent->setEnabled( false );
    telexPage->setEnabled( false );

Lukas Durfina's avatar
Lukas Durfina committed
536
    BUTTON_SET_IMG( telexTransparent, "", tvtelx.png, qtr( "Teletext" ) );
537
    CONNECT( telexTransparent, clicked( bool ),
538
             THEMIM->getIM(), telexSetTransparency() );
Lukas Durfina's avatar
Lukas Durfina committed
539 540
    CONNECT( THEMIM->getIM(), toggleTelexTransparency(),
              this, toggleTeletextTransparency() );
541
    CONNECT( THEMIM->getIM(), teletextEnabled( bool ),
542
             this, enableTeletext( bool ) );
543

544
    /** Play Buttons **/
545
    QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
546 547 548 549
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );

    /* Play */
550
    playButton = new QPushButton;
551
    playButton->setSizePolicy( sizePolicy );
552 553
    playButton->setMaximumSize( QSize( 36, 36 ) );
    playButton->setMinimumSize( QSize( 36, 36 ) );
554
    playButton->setIconSize( QSize( 30, 30 ) );
555

556
    controlLayout->addWidget( playButton, 2, 0, 2, 2 );
557

558 559
    controlLayout->setColumnMinimumWidth( 2, 20 );
    controlLayout->setColumnStretch( 2, 0 );
560 561

    /** Prev + Stop + Next Block **/
Lukas Durfina's avatar
Lukas Durfina committed
562
    controlButLayout = new QHBoxLayout;
563 564 565 566 567
    controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */

    /* Prev */
    QPushButton *prevButton = new QPushButton;
    prevButton->setSizePolicy( sizePolicy );
568
    setupSmallButton( prevButton );
569 570 571 572 573 574

    controlButLayout->addWidget( prevButton );

    /* Stop */
    QPushButton *stopButton = new QPushButton;
    stopButton->setSizePolicy( sizePolicy );
575
    setupSmallButton( stopButton );
576 577 578 579 580 581

    controlButLayout->addWidget( stopButton );

    /* next */
    QPushButton *nextButton = new QPushButton;
    nextButton->setSizePolicy( sizePolicy );
582
    setupSmallButton( nextButton );
583 584 585 586

    controlButLayout->addWidget( nextButton );

    /* Add this block to the main layout */
Lukas Durfina's avatar
Lukas Durfina committed
587 588
    if( !b_fsCreation )
        controlLayout->addLayout( controlButLayout, 3, 3, 1, 3 );
589

590
    BUTTON_SET_ACT_I( playButton, "", play.png, qtr( "Play" ), play() );
591
    BUTTON_SET_ACT_I( prevButton, "" , previous.png,
592 593 594
                      qtr( "Previous" ), prev() );
    BUTTON_SET_ACT_I( nextButton, "", next.png, qtr( "Next" ), next() );
    BUTTON_SET_ACT_I( stopButton, "", stop.png, qtr( "Stop" ), stop() );
595

596 597 598 599
    controlLayout->setColumnMinimumWidth( 7, 20 );
    controlLayout->setColumnStretch( 7, 0 );
    controlLayout->setColumnStretch( 8, 0 );
    controlLayout->setColumnStretch( 9, 0 );
600

601 602 603
    /*
     * Other first Line buttons
     */
604 605 606
    /** Fullscreen/Visualisation **/
    fullscreenButton = new QPushButton( "F" );
    BUTTON_SET_ACT( fullscreenButton, "F", qtr( "Fullscreen" ), fullscreen() );
607
    setupSmallButton( fullscreenButton );
608
    controlLayout->addWidget( fullscreenButton, 3, 10, Qt::AlignBottom );
609

610 611
    /** Playlist Button **/
    playlistButton = new QPushButton;
612
    setupSmallButton( playlistButton );
613
    controlLayout->addWidget( playlistButton, 3, 11, Qt::AlignBottom );
614
    BUTTON_SET_IMG( playlistButton, "" , playlist.png, qtr( "Show playlist" ) );
615
    CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );
616 617

    /** extended Settings **/
Lukas Durfina's avatar
Lukas Durfina committed
618
    extSettingsButton = new QPushButton;
619
    BUTTON_SET_ACT( extSettingsButton, "Ex", qtr( "Extended settings" ),
620
            extSettings() );
621
    setupSmallButton( extSettingsButton );
622
    controlLayout->addWidget( extSettingsButton, 3, 12, Qt::AlignBottom );
623

624
    controlLayout->setColumnStretch( 13, 0 );
625
    controlLayout->setColumnMinimumWidth( 13, 24 );
626
    controlLayout->setColumnStretch( 14, 5 );
627

628
    /* Volume */
Lukas Durfina's avatar
Lukas Durfina committed
629
    hVolLabel = new VolumeClickHandler( p_intf, this );
630

631
    volMuteLabel = new QLabel;
632
    volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) );
633
    volMuteLabel->setToolTip( qtr( "Mute" ) );
634
    volMuteLabel->installEventFilter( hVolLabel );
635
    controlLayout->addWidget( volMuteLabel, 3, 15, Qt::AlignBottom );
636

637 638 639
    if( b_shiny )
    {
        volumeSlider = new SoundSlider( this,
640
            config_GetInt( p_intf, "volume-step" ),
641 642
            config_GetInt( p_intf, "qt-volume-complete" ),
            config_GetPsz( p_intf, "qt-slider-colours" ) );
643 644 645 646 647 648
    }
    else
    {
        volumeSlider = new QSlider( this );
        volumeSlider->setOrientation( Qt::Horizontal );
    }
649
    volumeSlider->setMaximumSize( QSize( 200, 40 ) );
650
    volumeSlider->setMinimumSize( QSize( 106, 30 ) );
651
    volumeSlider->setFocusPolicy( Qt::NoFocus );
652
    controlLayout->addWidget( volumeSlider, 2, 16, 2 , 2, Qt::AlignBottom );
653

654
    /* Set the volume from the config */
655 656
    volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
                              VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
657

658 659 660
    /* Force the update at build time in order to have a muted icon if needed */
    updateVolume( volumeSlider->value() );

661 662
    /* Volume control connection */
    CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
663
    CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
664 665

    updateInput();
666
}
667

668
ControlsWidget::~ControlsWidget()
669
{}
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
void ControlsWidget::toggleTeletext()
{
    bool b_enabled = THEMIM->teletextState();
    if( b_telexEnabled )
    {
        telexTransparent->setEnabled( false );
        telexPage->setEnabled( false );
        b_telexEnabled = false;
    }
    else if( b_enabled )
    {
        telexTransparent->setEnabled( true );
        telexPage->setEnabled( true );
        b_telexEnabled = true;
    }
}
687 688 689 690 691 692 693 694 695 696
void ControlsWidget::enableTeletext( bool b_enable )
{
    telexFrame->setVisible( b_enable );
    bool b_on = THEMIM->teletextState();

    telexOn->setChecked( b_on );
    telexTransparent->setEnabled( b_on );
    telexPage->setEnabled( b_on );
    b_telexEnabled = b_on;
}
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713

void ControlsWidget::toggleTeletextTransparency()
{
    if( b_telexTransparent )
    {
        telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx.png" ) );
        telexTransparent->setToolTip( qtr( "Teletext" ) );
        b_telexTransparent = false;
    }
    else
    {
        telexTransparent->setIcon( QIcon( ":/pixmaps/tvtelx-transparent.png" ) );
        telexTransparent->setToolTip( qtr( "Transparent" ) );
        b_telexTransparent = true;
    }
}

714 715 716 717 718 719 720
void ControlsWidget::stop()
{
    THEMIM->stop();
}

void ControlsWidget::play()
{
721
    if( THEPL->current.i_size == 0 )
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    {
        /* The playlist is empty, open a file requester */
        THEDP->openFileDialog();
        setStatus( 0 );
        return;
    }
    THEMIM->togglePlayPause();
}

void ControlsWidget::prev()
{
    THEMIM->prev();
}

void ControlsWidget::next()
{
    THEMIM->next();
}

void ControlsWidget::setNavigation( int navigation )
{
743 744
#define HELP_PCH N_( "Previous chapter" )
#define HELP_NCH N_( "Next chapter" )
745 746 747 748 749 750

    // 1 = chapter, 2 = title, 0 = no
    if( navigation == 0 )
    {
        discFrame->hide();
    } else if( navigation == 1 ) {
751 752
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
753 754 755
        menuButton->show();
        discFrame->show();
    } else {
756 757
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
758 759 760 761 762 763
        menuButton->hide();
        discFrame->show();
    }
}

static bool b_my_volume;
764
void ControlsWidget::updateVolume( int i_sliderVolume )
765 766 767
{
    if( !b_my_volume )
    {
768
        int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
769 770
        aout_VolumeSet( p_intf, i_res );
    }
771 772
    if( i_sliderVolume == 0 )
        volMuteLabel->setPixmap( QPixmap(":/pixmaps/volume-muted.png" ) );
773
    else if( i_sliderVolume < VOLUME_MAX / 3 )
774
        volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-low.png" ) );
775 776 777
    else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
        volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-high.png" ) );
    else volMuteLabel->setPixmap( QPixmap( ":/pixmaps/volume-medium.png" ) );
778 779
}

780
void ControlsWidget::updateVolume()
781
{
782
    /* Audio part */
783 784
    audio_volume_t i_volume;
    aout_VolumeGet( p_intf, &i_volume );
785
    i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
786 787 788 789 790 791 792 793
    int i_gauge = volumeSlider->value();
    b_my_volume = false;
    if( i_volume - i_gauge > 1 || i_gauge - i_volume > 1 )
    {
        b_my_volume = true;
        volumeSlider->setValue( i_volume );
        b_my_volume = false;
    }
794
}
795

796 797
void ControlsWidget::updateInput()
{
798
    /* Activate the interface buttons according to the presence of the input */
799
    enableInput( THEMIM->getIM()->hasInput() );
800
    enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() );
801
}
802

803 804
void ControlsWidget::setStatus( int status )
{
805 806
    if( status == PLAYING_S ) /* Playing */
    {
807
        playButton->setIcon( QIcon( ":/pixmaps/pause.png" ) );
808 809
        playButton->setToolTip( qtr( "Pause" ) );
    }
810
    else
811
    {
812
        playButton->setIcon( QIcon( ":/pixmaps/play.png" ) );
813 814
        playButton->setToolTip( qtr( "Play" ) );
    }
815
}
816

817 818
/**
 * TODO
819
 * This functions toggle the fullscreen mode
820
 * If there is no video, it should first activate Visualisations...
821
 *  This has also to be fixed in enableVideo()
822
 */
Clément Stenac's avatar
Clément Stenac committed
823 824
void ControlsWidget::fullscreen()
{
825 826
    vout_thread_t *p_vout =
        (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
827
    if( p_vout)
828
    {
829
        var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );