interface_widgets.cpp 38.6 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>

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
59 60
#define I_PLAY_TOOLTIP "Play\nIf the playlist is empty, open a media"

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

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

75 76 77 78 79
    /* 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 );
80
    setAttribute( Qt::WA_PaintOnScreen, true );
81

82
    /* The core can ask through a callback to show the video. */
83
#if HAS_QT43
84 85 86
    connect( this, SIGNAL(askVideoWidgetToShow( unsigned int, unsigned int)),
             this, SLOT(SetSizing(unsigned int, unsigned int )),
             Qt::BlockingQueuedConnection );
87 88 89 90 91
#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
92 93
}

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

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

107 108 109 110 111 112 113 114 115 116 117 118
    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 );
        }
119
        vlc_object_release( p_vout );
120 121 122
    }
}

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

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

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

163 164 165 166
QSize VideoWidget::sizeHint() const
{
    return videoSize;
}
167

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

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

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

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

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

206
    CONNECT( THEMIM->getIM(), artChanged( QString ), this, updateArt( QString ) );
207 208
}

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

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

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

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

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

254
    layout->addStretch( 10 );
255
    layout->addWidget( new QLabel( qtr( "Current visualization" ) ) );
Clément Stenac's avatar
Clément Stenac committed
256 257 258 259 260 261 262

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

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

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

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

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

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

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

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

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

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
325
    recordButton = new QPushButton;
Lukas Durfina's avatar
Lukas Durfina committed
326
    setupSmallButton( recordButton );
327
    advLayout->addWidget( recordButton );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
328
    BUTTON_SET_ACT_I( recordButton, "", record,
329
            qtr( "Record" ), record() );
330

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

339
AdvControlsWidget::~AdvControlsWidget()
340
{}
Clément Stenac's avatar
Clément Stenac committed
341

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

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

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

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

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

397
/* FIXME Record function */
398
void AdvControlsWidget::record(){}
399

400
#if 0
401
//FIXME Frame by frame function
402
void AdvControlsWidget::frame(){}
403
#endif
404

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

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

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

431
    BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() );
432

433 434
    fasterButton = new QToolButton;
    fasterButton->setAutoRaise( true );
435
    fasterButton->setMaximumSize( QSize( 26, 20 ) );
436

437
    BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() );
438

439 440 441 442 443 444
    /* advanced Controls handling */
    b_advancedVisible = b_advControls;

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

445
    /** Disc and Menus handling */
446
    discFrame = new QWidget( this );
447

448 449 450
    QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
    discLayout->setSpacing( 0 );
    discLayout->setMargin( 0 );
451

452
    prevSectionButton = new QPushButton( discFrame );
453
    setupSmallButton( prevSectionButton );
454 455
    discLayout->addWidget( prevSectionButton );

456
    menuButton = new QPushButton( discFrame );
457 458 459
    setupSmallButton( menuButton );
    discLayout->addWidget( menuButton );

460
    nextSectionButton = new QPushButton( discFrame );
461
    setupSmallButton( nextSectionButton );
462 463
    discLayout->addWidget( nextSectionButton );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
464 465 466
    BUTTON_SET_IMG( prevSectionButton, "", dvd_prev, "" );
    BUTTON_SET_IMG( nextSectionButton, "", dvd_next, "" );
    BUTTON_SET_IMG( menuButton, "", dvd_menu, qtr( "Menu" ) );
467

468
    discFrame->hide();
469 470 471

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

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

Lukas Durfina's avatar
Lukas Durfina committed
490
    telexOn = new QPushButton;
491 492 493
    setupSmallButton( telexOn );
    telexLayout->addWidget( telexOn );

494
    telexTransparent = new QPushButton;
495 496
    setupSmallButton( telexTransparent );
    telexLayout->addWidget( telexTransparent );
497
    b_telexTransparent = false;
498

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

508
    telexFrame->hide(); /* default hidden */
509 510 511

    CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
             telexGotoPage( int ) );
Lukas Durfina's avatar
Lukas Durfina committed
512 513 514
    CONNECT( THEMIM->getIM(), setNewTelexPage( int ),
              telexPage, setValue( int ) );

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

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

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

535
    /** Play Buttons **/
536
    QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
537 538 539 540
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );

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

547

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

    /* Prev */
    QPushButton *prevButton = new QPushButton;
    prevButton->setSizePolicy( sizePolicy );
555
    setupSmallButton( prevButton );
556 557 558 559 560 561

    controlButLayout->addWidget( prevButton );

    /* Stop */
    QPushButton *stopButton = new QPushButton;
    stopButton->setSizePolicy( sizePolicy );
562
    setupSmallButton( stopButton );
563 564 565 566 567 568

    controlButLayout->addWidget( stopButton );

    /* next */
    QPushButton *nextButton = new QPushButton;
    nextButton->setSizePolicy( sizePolicy );
569
    setupSmallButton( nextButton );
570 571 572 573 574

    controlButLayout->addWidget( nextButton );

    /* Add this block to the main layout */

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
575
    BUTTON_SET_ACT_I( playButton, "", play_b, qtr( I_PLAY_TOOLTIP ), play() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
576
    BUTTON_SET_ACT_I( prevButton, "" , previous_b,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
577 578 579 580
                      qtr( "Previous media in the playlist" ), prev() );
    BUTTON_SET_ACT_I( nextButton, "", next_b,
                      qtr( "Next media in the playlist" ), next() );
    BUTTON_SET_ACT_I( stopButton, "", stop_b, qtr( "Stop playback" ), stop() );
581 582 583 584

    /*
     * Other first Line buttons
     */
585
    /** Fullscreen/Visualisation **/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
586
    fullscreenButton = new QPushButton;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
587 588
    BUTTON_SET_ACT_I( fullscreenButton, "", fullscreen,
            qtr( "Toggle the video in fullscreen" ), fullscreen() );
589
    setupSmallButton( fullscreenButton );
590

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

        /** extended Settings **/
        extSettingsButton = new QPushButton;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
601
        BUTTON_SET_ACT_I( extSettingsButton, "", extended,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
602
                qtr( "Show extended settings" ), extSettings() );
603 604
        setupSmallButton( extSettingsButton );
    }
605

606
    /* Volume */
Lukas Durfina's avatar
Lukas Durfina committed
607
    hVolLabel = new VolumeClickHandler( p_intf, this );
608

609
    volMuteLabel = new QLabel;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
610
    volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
611
    volMuteLabel->installEventFilter( hVolLabel );
612

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

629
    /* Set the volume from the config */
630 631
    volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
                              VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
632

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

636 637
    /* Volume control connection */
    CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
638
    CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
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 674 675 676
    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 );
    }

677
    updateInput();
678
}
679

680
ControlsWidget::~ControlsWidget()
681
{}
682

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

700 701 702 703 704 705 706 707 708 709
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;
}
710 711 712 713 714

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

727 728 729 730 731 732 733
void ControlsWidget::stop()
{
    THEMIM->stop();
}

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

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

static bool b_my_volume;
777
void ControlsWidget::updateVolume( int i_sliderVolume )
778 779 780
{
    if( !b_my_volume )
    {
781
        int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
782 783
        aout_VolumeSet( p_intf, i_res );
    }
784
    if( i_sliderVolume == 0 )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
785
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
786
        volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
787 788 789 790 791
        volMuteLabel->setToolTip( qtr( "Unmute" ) );
        return;
    }

    if( i_sliderVolume < VOLUME_MAX / 3 )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
792
        volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
793
    else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
794 795
        volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
    else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
796
    volMuteLabel->setToolTip( qtr( "Mute" ) );
797 798
}

799
void ControlsWidget::updateVolume()
800
{
801
    /* Audio part */
802 803
    audio_volume_t i_volume;
    aout_VolumeGet( p_intf, &i_volume );
804
    i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
805 806 807 808 809 810 811 812
    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;
    }
813
}
814

815 816
void ControlsWidget::updateInput()
{
817
    /* Activate the interface buttons according to the presence of the input */
818
    enableInput( THEMIM->getIM()->hasInput() );
819
    enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() );
820
}
821

822 823
void ControlsWidget::setStatus( int status )
{
824 825
    if( status == PLAYING_S ) /* Playing */
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
826
        playButton->setIcon( QIcon( ":/pause_b" ) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
827
        playButton->setToolTip( qtr( "Pause the playback" ) );
828
    }
829
    else
830
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
831
        playButton->setIcon( QIcon( ":/play_b" ) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
832
        playButton->setToolTip( qtr( I_PLAY_TOOLTIP ) );
833
    }
834
}
835

836 837
/**
 * TODO
838
 * This functions toggle the fullscreen mode
839
 * If there is no video, it should first activate Visualisations...
840
 *  This has also to be fixed in enableVideo()
841
 */
Clément Stenac's avatar
Clément Stenac committed
842 843
void ControlsWidget::fullscreen()
{
844 845
    vout_thread_t *p_vout =
        (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
846
    if( p_vout)
847
    {
848
        var_SetBool( p_vout, "fullscreen", !var_GetBool( p_vout, "fullscreen" ) );
849
        vlc_object_release( p_vout );
850
    }
851 852 853 854 855 856
}

void ControlsWidget::extSettings()
{
    THEDP->extendedDialog();
}