interface_widgets.cpp 38.4 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->addStretch( 10 );
253
    layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
Clément Stenac's avatar
Clément Stenac committed
254 255 256 257 258 259 260

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

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

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

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

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

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

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

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

305
    /* A to B Button */
306
    ABButton = new QPushButton( "AB" );
Lukas Durfina's avatar
Lukas Durfina committed
307
    setupSmallButton( ABButton );
308
    advLayout->addWidget( ABButton );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
309 310
    BUTTON_SET_ACT_I( ABButton, "", atob_nob,
        qtr( "Loop from point A to point B continuously\nClick to set point A" ), 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 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
325
    BUTTON_SET_ACT_I( recordButton, "", record,
326
            qtr( "Record" ), record() );
327

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

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

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

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

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

360
/* Function called when the button is clicked() */
361 362 363 364 365
void AdvControlsWidget::fromAtoB()
{
    if( !timeA )
    {
        timeA = var_GetTime( THEMIM->getInput(), "time"  );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
366 367
        ABButton->setToolTip( "Click to set point B" );
        ABButton->setIcon( QIcon( ":/atob_noa" ) );
368 369 370 371 372 373
        return;
    }
    if( !timeB )
    {
        timeB = var_GetTime( THEMIM->getInput(), "time"  );
        var_SetTime( THEMIM->getInput(), "time" , timeA );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
374 375
        ABButton->setIcon( QIcon( ":/atob" ) );
        ABButton->setToolTip( "Stop the A to B loop" );
376 377 378 379
        return;
    }
    timeA = 0;
    timeB = 0;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
380 381
    ABButton->setToolTip( qtr( "Loop from point A to point B continuously\nClick to set point A" ) );
    ABButton->setIcon( QIcon( ":/atob_nob" ) );
382
}
383

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

394
/* FIXME Record function */
395
void AdvControlsWidget::record(){}
396

397
#if 0
398
//FIXME Frame by frame function
399
void AdvControlsWidget::frame(){}
400
#endif
401

402 403 404
/*****************************
 * DA Control Widget !
 *****************************/
405
ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
406
                                MainInterface *_p_mi,
407
                                bool b_advControls,
Lukas Durfina's avatar
Lukas Durfina committed
408 409 410
                                bool b_shiny,
                                bool b_fsCreation) :
                                QFrame( _p_mi ), p_intf( _p_i )
411
{
412
    setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
413

414 415 416 417
    /** The main Slider **/
    slider = new InputSlider( Qt::Horizontal, NULL );
    /* Update the position when the IM has changed */
    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
418
             slider, setPosition( float, int, int ) );
419 420 421 422
    /* And update the IM, when the position has changed */
    CONNECT( slider, sliderDragged( float ),
             THEMIM->getIM(), sliderUpdate( float ) );

423
    /** Slower and faster Buttons **/
424 425
    slowerButton = new QToolButton;
    slowerButton->setAutoRaise( true );
426
    slowerButton->setMaximumSize( QSize( 26, 20 ) );
427

428
    BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() );
429

430 431
    fasterButton = new QToolButton;
    fasterButton->setAutoRaise( true );
432
    fasterButton->setMaximumSize( QSize( 26, 20 ) );
433

434
    BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() );
435

436 437 438 439 440 441
    /* advanced Controls handling */
    b_advancedVisible = b_advControls;

    advControls = new AdvControlsWidget( p_intf );
    if( !b_advancedVisible ) advControls->hide();

442
    /** Disc and Menus handling */
443
    discFrame = new QWidget( this );
444

445 446 447
    QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
    discLayout->setSpacing( 0 );
    discLayout->setMargin( 0 );
448

449
    prevSectionButton = new QPushButton( discFrame );
450
    setupSmallButton( prevSectionButton );
451 452
    discLayout->addWidget( prevSectionButton );

453
    menuButton = new QPushButton( discFrame );
454 455 456
    setupSmallButton( menuButton );
    discLayout->addWidget( menuButton );

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

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
461 462 463
    BUTTON_SET_IMG( prevSectionButton, "", dvd_prev, "" );
    BUTTON_SET_IMG( nextSectionButton, "", dvd_next, "" );
    BUTTON_SET_IMG( menuButton, "", dvd_menu, qtr( "Menu" ) );
464

465
    discFrame->hide();
466 467 468

    /* Change the navigation button display when the IM navigation changes */
    CONNECT( THEMIM->getIM(), navigationChanged( int ),
469
             this, setNavigation( int ) );
470 471 472 473 474 475 476
    /* 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() );
477

478
    /**
479
     * Telextext QFrame
480
     * TODO: Merge with upper menu in a StackLayout
481
     **/
482 483 484 485 486
    telexFrame = new QWidget( this );
    QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
    telexLayout->setSpacing( 0 );
    telexLayout->setMargin( 0 );

Lukas Durfina's avatar
Lukas Durfina committed
487
    telexOn = new QPushButton;
488 489 490
    setupSmallButton( telexOn );
    telexLayout->addWidget( telexOn );

491
    telexTransparent = new QPushButton;
492 493
    setupSmallButton( telexTransparent );
    telexLayout->addWidget( telexTransparent );
494
    b_telexTransparent = false;
495

496
    telexPage = new QSpinBox;
497
    telexPage->setRange( 0, 999 );
498
    telexPage->setValue( 100 );
499 500
    telexPage->setAccelerated( true );
    telexPage->setWrapping( true );
501
    telexPage->setAlignment( Qt::AlignRight );
502
    telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
503 504
    telexLayout->addWidget( telexPage );

505
    telexFrame->hide(); /* default hidden */
506 507 508

    CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
             telexGotoPage( int ) );
Lukas Durfina's avatar
Lukas Durfina committed
509 510 511
    CONNECT( THEMIM->getIM(), setNewTelexPage( int ),
              telexPage, setValue( int ) );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
512
    BUTTON_SET_IMG( telexOn, "", tv, qtr( "Teletext on" ) );
513

Lukas Durfina's avatar
Lukas Durfina committed
514 515
    CONNECT( telexOn, clicked(), THEMIM->getIM(),
             telexToggleButtons() );
516 517
    CONNECT( telexOn, clicked( bool ), THEMIM->getIM(),
             telexToggle( bool ) );
Lukas Durfina's avatar
Lukas Durfina committed
518 519 520
    CONNECT( THEMIM->getIM(), toggleTelexButtons(),
              this, toggleTeletext() );
    b_telexEnabled = false;
521 522 523
    telexTransparent->setEnabled( false );
    telexPage->setEnabled( false );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
524
    BUTTON_SET_IMG( telexTransparent, "", tvtelx, qtr( "Teletext" ) );
525
    CONNECT( telexTransparent, clicked( bool ),
526
             THEMIM->getIM(), telexSetTransparency() );
Lukas Durfina's avatar
Lukas Durfina committed
527 528
    CONNECT( THEMIM->getIM(), toggleTelexTransparency(),
              this, toggleTeletextTransparency() );
529
    CONNECT( THEMIM->getIM(), teletextEnabled( bool ),
530
             this, enableTeletext( bool ) );
531

532
    /** Play Buttons **/
533
    QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
534 535 536 537
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );

    /* Play */
538
    playButton = new QPushButton;
539
    playButton->setSizePolicy( sizePolicy );
540 541
    playButton->setMaximumSize( QSize( 36, 36 ) );
    playButton->setMinimumSize( QSize( 36, 36 ) );
542
    playButton->setIconSize( QSize( 30, 30 ) );
543

544

545
    /** Prev + Stop + Next Block **/
Lukas Durfina's avatar
Lukas Durfina committed
546
    controlButLayout = new QHBoxLayout;
547 548 549 550 551
    controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */

    /* Prev */
    QPushButton *prevButton = new QPushButton;
    prevButton->setSizePolicy( sizePolicy );
552
    setupSmallButton( prevButton );
553 554 555 556 557 558

    controlButLayout->addWidget( prevButton );

    /* Stop */
    QPushButton *stopButton = new QPushButton;
    stopButton->setSizePolicy( sizePolicy );
559
    setupSmallButton( stopButton );
560 561 562 563 564 565

    controlButLayout->addWidget( stopButton );

    /* next */
    QPushButton *nextButton = new QPushButton;
    nextButton->setSizePolicy( sizePolicy );
566
    setupSmallButton( nextButton );
567 568 569 570 571

    controlButLayout->addWidget( nextButton );

    /* Add this block to the main layout */

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
572 573
    BUTTON_SET_ACT_I( playButton, "", play_b, qtr( "Play" ), play() );
    BUTTON_SET_ACT_I( prevButton, "" , previous_b,
574
                      qtr( "Previous" ), prev() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
575 576
    BUTTON_SET_ACT_I( nextButton, "", next_b, qtr( "Next" ), next() );
    BUTTON_SET_ACT_I( stopButton, "", stop_b, qtr( "Stop" ), stop() );
577 578 579 580

    /*
     * Other first Line buttons
     */
581
    /** Fullscreen/Visualisation **/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
582 583 584
    fullscreenButton = new QPushButton;
    BUTTON_SET_ACT_I( fullscreenButton, "", fullscreen, qtr( "Fullscreen" ),
            fullscreen() );
585
    setupSmallButton( fullscreenButton );
586

587 588 589 590 591
    if( !b_fsCreation )
    {
        /** Playlist Button **/
        playlistButton = new QPushButton;
        setupSmallButton( playlistButton );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
592
        BUTTON_SET_IMG( playlistButton, "" , playlist, qtr( "Show playlist" ) );
593 594 595 596
        CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );

        /** extended Settings **/
        extSettingsButton = new QPushButton;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
597 598
        BUTTON_SET_ACT_I( extSettingsButton, "", extended,
                qtr( "Extended settings" ), extSettings() );
599 600
        setupSmallButton( extSettingsButton );
    }
601

602
    /* Volume */
Lukas Durfina's avatar
Lukas Durfina committed
603
    hVolLabel = new VolumeClickHandler( p_intf, this );
604

605
    volMuteLabel = new QLabel;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
606
    volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
607
    volMuteLabel->setToolTip( qtr( "Mute" ) );
608
    volMuteLabel->installEventFilter( hVolLabel );
609

610 611 612
    if( b_shiny )
    {
        volumeSlider = new SoundSlider( this,
613
            config_GetInt( p_intf, "volume-step" ),
614 615
            config_GetInt( p_intf, "qt-volume-complete" ),
            config_GetPsz( p_intf, "qt-slider-colours" ) );
616 617 618 619 620 621
    }
    else
    {
        volumeSlider = new QSlider( this );
        volumeSlider->setOrientation( Qt::Horizontal );
    }
622
    volumeSlider->setMaximumSize( QSize( 200, 40 ) );
623
    volumeSlider->setMinimumSize( QSize( 106, 30 ) );
624
    volumeSlider->setFocusPolicy( Qt::NoFocus );
625

626
    /* Set the volume from the config */
627 628
    volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
                              VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
629

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

633 634
    /* Volume control connection */
    CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
635
    CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
636

637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
    if( !b_fsCreation )
    {
        controlLayout = new QGridLayout( this );

        controlLayout->setSpacing( 0 );
        controlLayout->setLayoutMargins( 7, 5, 7, 3, 6 );

        controlLayout->addWidget( slider, 0, 1, 1, 16 );
        controlLayout->addWidget( slowerButton, 0, 0 );
        controlLayout->addWidget( fasterButton, 0, 17 );

        controlLayout->addWidget( advControls, 1, 3, 2, 4, Qt::AlignBottom );
        controlLayout->addWidget( discFrame, 1, 10, 2, 3, Qt::AlignBottom );
        controlLayout->addWidget( telexFrame, 1, 10, 2, 4, Qt::AlignBottom );

        controlLayout->addWidget( playButton, 2, 0, 2, 2 );
        controlLayout->setColumnMinimumWidth( 2, 20 );
        controlLayout->setColumnStretch( 2, 0 );

        controlLayout->addLayout( controlButLayout, 3, 3, 1, 3 );
        controlLayout->setColumnMinimumWidth( 7, 20 );
        controlLayout->setColumnStretch( 7, 0 );
        controlLayout->setColumnStretch( 8, 0 );
        controlLayout->setColumnStretch( 9, 0 );

        controlLayout->addWidget( fullscreenButton, 3, 10, Qt::AlignBottom );
        controlLayout->addWidget( playlistButton, 3, 11, Qt::AlignBottom );
        controlLayout->addWidget( extSettingsButton, 3, 12, Qt::AlignBottom );

        controlLayout->setColumnStretch( 13, 0 );
        controlLayout->setColumnMinimumWidth( 13, 24 );
        controlLayout->setColumnStretch( 14, 5 );

        controlLayout->addWidget( volMuteLabel, 3, 15, Qt::AlignBottom );
        controlLayout->addWidget( volumeSlider, 2, 16, 2 , 2, Qt::AlignBottom );
    }

674
    updateInput();
675
}
676

677
ControlsWidget::~ControlsWidget()
678
{}
679

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
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;
    }
}
696

697 698 699 700 701 702 703 704 705 706
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;
}
707 708 709 710 711

void ControlsWidget::toggleTeletextTransparency()
{
    if( b_telexTransparent )
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
712
        telexTransparent->setIcon( QIcon( ":/tvtelx" ) );
713 714 715 716 717
        telexTransparent->setToolTip( qtr( "Teletext" ) );
        b_telexTransparent = false;
    }
    else
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
718
        telexTransparent->setIcon( QIcon( ":/tvtelx-transparent" ) );
719 720 721 722 723
        telexTransparent->setToolTip( qtr( "Transparent" ) );
        b_telexTransparent = true;
    }
}

724 725 726 727 728 729 730
void ControlsWidget::stop()
{
    THEMIM->stop();
}

void ControlsWidget::play()
{
731
    if( THEPL->current.i_size == 0 )
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
    {
        /* 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 )
{
753 754
#define HELP_PCH N_( "Previous chapter" )
#define HELP_NCH N_( "Next chapter" )
755 756 757 758 759 760

    // 1 = chapter, 2 = title, 0 = no
    if( navigation == 0 )
    {
        discFrame->hide();
    } else if( navigation == 1 ) {
761 762
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
763 764 765
        menuButton->show();
        discFrame->show();
    } else {
766 767
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
768 769 770 771 772 773
        menuButton->hide();
        discFrame->show();
    }
}

static bool b_my_volume;
774
void ControlsWidget::updateVolume( int i_sliderVolume )
775 776 777
{
    if( !b_my_volume )
    {
778
        int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
779 780
        aout_VolumeSet( p_intf, i_res );
    }
781
    if( i_sliderVolume == 0 )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
782
        volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
783
    else if( i_sliderVolume < VOLUME_MAX / 3 )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
784
        volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
785
    else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
786 787
        volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
    else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
788 789
}

790
void ControlsWidget::updateVolume()
791
{
792
    /* Audio part */
793 794
    audio_volume_t i_volume;
    aout_VolumeGet( p_intf, &i_volume );
795
    i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
796 797 798 799 800 801 802 803
    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;
    }
804
}
805

806 807
void ControlsWidget::updateInput()
{
808
    /* Activate the interface buttons according to the presence of the input */
809
    enableInput( THEMIM->getIM()->hasInput() );
810
    enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() );
811
}
812

813 814
void ControlsWidget::setStatus( int status )
{
815 816
    if( status == PLAYING_S ) /* Playing */
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
817
        playButton->setIcon( QIcon( ":/pause_b" ) );
818 819
        playButton->setToolTip( qtr( "Pause" ) );
    }
820
    else
821
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
822
        playButton->setIcon( QIcon( ":/play_b" ) );
823 824
        playButton->setToolTip( qtr( "Play" ) );
    }
825
}
826

827 828
/**
 * TODO
829
 * This functions toggle the fullscreen mode
830
 * If there is no video, it should first activate Visualisations...
831
 *  This has also to be fixed in enableVideo()
832
 */
Clément Stenac's avatar
Clément Stenac committed
833 834
void ControlsWidget::fullscreen()
{
835 836
    vout_thread_t *p_vout =
        (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
837
    if( p_vout)
838
    {
839
        var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
840
        vlc_object_release( p_vout );
841
    }
842 843 844 845 846 847
}

void ControlsWidget::extSettings()
{
    THEDP->extendedDialog();
}
Clément Stenac's avatar
Clément Stenac committed
848

849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
void ControlsWidget::slower()
{
    THEMIM->getIM()->slower();
}

void ControlsWidget::faster()
{
    THEMIM->getIM()->faster();
}

void ControlsWidget::enableInput( bool enable )
{
    slowerButton->setEnabled( enable );
    slider->setEnabled( enable );
    fasterButton->setEnabled( enable );
864 865 866

    /* Advanced Buttons too */
    advControls->enableInput( enable );
867 868
}