interface_widgets.cpp 39.9 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
#define I_PLAY_TOOLTIP N_("Play\nIf the playlist is empty, open a media")
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
60

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

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

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

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

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

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

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

Clément Stenac's avatar
Clément Stenac committed
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 );
    }
}
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
290
#endif
Clément Stenac's avatar
Clément Stenac committed
291 292

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

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

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
301 302 303 304
/* init static variables in advanced controls */
mtime_t AdvControlsWidget::timeA = 0;
mtime_t AdvControlsWidget::timeB = 0;

305
AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i, bool b_fsCreation = false ) :
Clément Stenac's avatar
Clément Stenac committed
306 307
                                           QFrame( NULL ), p_intf( _p_i )
{
308 309 310
    QHBoxLayout *advLayout = new QHBoxLayout( this );
    advLayout->setMargin( 0 );
    advLayout->setSpacing( 0 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
311
    advLayout->setAlignment( Qt::AlignBottom );
Clément Stenac's avatar
Clément Stenac committed
312

313
    /* A to B Button */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
314
    ABButton = new QPushButton;
Lukas Durfina's avatar
Lukas Durfina committed
315
    setupSmallButton( ABButton );
316
    advLayout->addWidget( ABButton );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
317
    BUTTON_SET_ACT_I( ABButton, "", atob_nob,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
318 319
      qtr( "Loop from point A to point B continuously.\nClick to set point A" ),
      fromAtoB() );
320
    timeA = timeB = 0;
321 322 323 324 325 326 327 328 329
    /* in FS controller we skip this, because we dont want to have it double
       controlled */
    if( !b_fsCreation )
        CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
                 this, AtoBLoop( float, int, int ) );
    /* set up synchronization between main controller and fs controller */
    CONNECT( THEMIM->getIM(), advControlsSetIcon(), this, setIcon() );
    connect( this, SIGNAL( timeChanged() ),
        THEMIM->getIM(), SIGNAL( advControlsSetIcon()));
330
#if 0
331 332 333 334
    frameButton = new QPushButton( "Fr" );
    frameButton->setMaximumSize( QSize( 26, 26 ) );
    frameButton->setIconSize( QSize( 20, 20 ) );
    advLayout->addWidget( frameButton );
335
    BUTTON_SET_ACT( frameButton, "Fr", qtr( "Frame by frame" ), frame() );
336
#endif
337

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
338
    recordButton = new QPushButton;
Lukas Durfina's avatar
Lukas Durfina committed
339
    setupSmallButton( recordButton );
340
    advLayout->addWidget( recordButton );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
341
    BUTTON_SET_ACT_I( recordButton, "", record,
342
            qtr( "Record" ), record() );
343

344
    /* Snapshot Button */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
345
    snapshotButton = new QPushButton;
Lukas Durfina's avatar
Lukas Durfina committed
346
    setupSmallButton( snapshotButton );
347
    advLayout->addWidget( snapshotButton );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
348 349
    BUTTON_SET_ACT_I( snapshotButton, "", snapshot,
            qtr( "Take a snapshot" ), snapshot() );
Clément Stenac's avatar
Clément Stenac committed
350 351
}

352
AdvControlsWidget::~AdvControlsWidget()
353
{}
Clément Stenac's avatar
Clément Stenac committed
354

355
void AdvControlsWidget::enableInput( bool enable )
Clément Stenac's avatar
Clément Stenac committed
356
{
357 358
    ABButton->setEnabled( enable );
    recordButton->setEnabled( enable );
Clément Stenac's avatar
Clément Stenac committed
359
}
360

361
void AdvControlsWidget::enableVideo( bool enable )
Clément Stenac's avatar
Clément Stenac committed
362 363
{
    snapshotButton->setEnabled( enable );
364
#if 0
365
    frameButton->setEnabled( enable );
366
#endif
Clément Stenac's avatar
Clément Stenac committed
367 368
}

369
void AdvControlsWidget::snapshot()
Clément Stenac's avatar
Clément Stenac committed
370
{
371 372
    vout_thread_t *p_vout =
        (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
373
    if( p_vout ) vout_Control( p_vout, VOUT_SNAPSHOT );
Clément Stenac's avatar
Clément Stenac committed
374 375
}

376
/* Function called when the button is clicked() */
377 378 379 380 381
void AdvControlsWidget::fromAtoB()
{
    if( !timeA )
    {
        timeA = var_GetTime( THEMIM->getInput(), "time"  );
382
        emit timeChanged();
383 384 385 386 387 388
        return;
    }
    if( !timeB )
    {
        timeB = var_GetTime( THEMIM->getInput(), "time"  );
        var_SetTime( THEMIM->getInput(), "time" , timeA );
389
        emit timeChanged();
390 391 392 393
        return;
    }
    timeA = 0;
    timeB = 0;
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
    emit timeChanged();
}

/* setting/synchro icons after click on main or fs controller */
void AdvControlsWidget::setIcon()
{
    if( !timeA && !timeB)
    {
        ABButton->setIcon( QIcon( ":/atob_nob" ) );
        ABButton->setToolTip( qtr( "Loop from point A to point B continuously\nClick to set point A" ) );
    }
    else if( timeA && !timeB )
    {
        ABButton->setIcon( QIcon( ":/atob_noa" ) );
        ABButton->setToolTip( qtr( "Click to set point B" ) );
    }
    else if( timeA && timeB )
    {
        ABButton->setIcon( QIcon( ":/atob" ) );
        ABButton->setToolTip( qtr( "Stop the A to B loop" ) );
    }
415
}
416

417
/* Function called regularly when in an AtoB loop */
418 419 420 421
void AdvControlsWidget::AtoBLoop( float f_pos, int i_time, int i_length )
{
    if( timeB )
    {
422
        if( i_time >= (int)(timeB/1000000) )
423 424 425
            var_SetTime( THEMIM->getInput(), "time" , timeA );
    }
}
426

427
/* FIXME Record function */
428
void AdvControlsWidget::record(){}
429

430
#if 0
431
//FIXME Frame by frame function
432
void AdvControlsWidget::frame(){}
433
#endif
434

435 436 437
/*****************************
 * DA Control Widget !
 *****************************/
438
ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
439
                                MainInterface *_p_mi,
440
                                bool b_advControls,
Lukas Durfina's avatar
Lukas Durfina committed
441 442 443
                                bool b_shiny,
                                bool b_fsCreation) :
                                QFrame( _p_mi ), p_intf( _p_i )
444
{
445
    setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Maximum );
446

447 448 449 450
    /** The main Slider **/
    slider = new InputSlider( Qt::Horizontal, NULL );
    /* Update the position when the IM has changed */
    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
451
             slider, setPosition( float, int, int ) );
452 453 454 455
    /* And update the IM, when the position has changed */
    CONNECT( slider, sliderDragged( float ),
             THEMIM->getIM(), sliderUpdate( float ) );

456
    /** Slower and faster Buttons **/
457 458
    slowerButton = new QToolButton;
    slowerButton->setAutoRaise( true );
459
    slowerButton->setMaximumSize( QSize( 26, 20 ) );
460

461
    BUTTON_SET_ACT( slowerButton, "-", qtr( "Slower" ), slower() );
462

463 464
    fasterButton = new QToolButton;
    fasterButton->setAutoRaise( true );
465
    fasterButton->setMaximumSize( QSize( 26, 20 ) );
466

467
    BUTTON_SET_ACT( fasterButton, "+", qtr( "Faster" ), faster() );
468

469 470 471
    /* advanced Controls handling */
    b_advancedVisible = b_advControls;

472
    advControls = new AdvControlsWidget( p_intf, b_fsCreation );
473 474
    if( !b_advancedVisible ) advControls->hide();

475
    /** Disc and Menus handling */
476
    discFrame = new QWidget( this );
477

478 479 480
    QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
    discLayout->setSpacing( 0 );
    discLayout->setMargin( 0 );
481

482
    prevSectionButton = new QPushButton( discFrame );
483
    setupSmallButton( prevSectionButton );
484 485
    discLayout->addWidget( prevSectionButton );

486
    menuButton = new QPushButton( discFrame );
487 488 489
    setupSmallButton( menuButton );
    discLayout->addWidget( menuButton );

490
    nextSectionButton = new QPushButton( discFrame );
491
    setupSmallButton( nextSectionButton );
492 493
    discLayout->addWidget( nextSectionButton );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
494 495 496
    BUTTON_SET_IMG( prevSectionButton, "", dvd_prev, "" );
    BUTTON_SET_IMG( nextSectionButton, "", dvd_next, "" );
    BUTTON_SET_IMG( menuButton, "", dvd_menu, qtr( "Menu" ) );
497

498
    discFrame->hide();
499 500 501

    /* Change the navigation button display when the IM navigation changes */
    CONNECT( THEMIM->getIM(), navigationChanged( int ),
502
             this, setNavigation( int ) );
503 504 505 506 507 508 509
    /* 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() );
510

511
    /**
512
     * Telextext QFrame
513
     * TODO: Merge with upper menu in a StackLayout
514
     **/
515 516 517 518 519
    telexFrame = new QWidget( this );
    QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
    telexLayout->setSpacing( 0 );
    telexLayout->setMargin( 0 );

Lukas Durfina's avatar
Lukas Durfina committed
520
    telexOn = new QPushButton;
521 522 523
    setupSmallButton( telexOn );
    telexLayout->addWidget( telexOn );

524
    telexTransparent = new QPushButton;
525 526
    setupSmallButton( telexTransparent );
    telexLayout->addWidget( telexTransparent );
527
    b_telexTransparent = false;
528

529
    telexPage = new QSpinBox;
530
    telexPage->setRange( 0, 999 );
531
    telexPage->setValue( 100 );
532 533
    telexPage->setAccelerated( true );
    telexPage->setWrapping( true );
534
    telexPage->setAlignment( Qt::AlignRight );
535
    telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
536 537
    telexLayout->addWidget( telexPage );

538
    telexFrame->hide(); /* default hidden */
539 540 541

    CONNECT( telexPage, valueChanged( int ), THEMIM->getIM(),
             telexGotoPage( int ) );
Lukas Durfina's avatar
Lukas Durfina committed
542 543 544
    CONNECT( THEMIM->getIM(), setNewTelexPage( int ),
              telexPage, setValue( int ) );

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

Lukas Durfina's avatar
Lukas Durfina committed
547 548
    CONNECT( telexOn, clicked(), THEMIM->getIM(),
             telexToggleButtons() );
549 550
    CONNECT( telexOn, clicked( bool ), THEMIM->getIM(),
             telexToggle( bool ) );
Lukas Durfina's avatar
Lukas Durfina committed
551 552 553
    CONNECT( THEMIM->getIM(), toggleTelexButtons(),
              this, toggleTeletext() );
    b_telexEnabled = false;
554 555 556
    telexTransparent->setEnabled( false );
    telexPage->setEnabled( false );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
557
    BUTTON_SET_IMG( telexTransparent, "", tvtelx, qtr( "Teletext" ) );
558
    CONNECT( telexTransparent, clicked( bool ),
559
             THEMIM->getIM(), telexSetTransparency() );
Lukas Durfina's avatar
Lukas Durfina committed
560 561
    CONNECT( THEMIM->getIM(), toggleTelexTransparency(),
              this, toggleTeletextTransparency() );
562
    CONNECT( THEMIM->getIM(), teletextEnabled( bool ),
563
             this, enableTeletext( bool ) );
564

565
    /** Play Buttons **/
566
    QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
567 568 569 570
    sizePolicy.setHorizontalStretch( 0 );
    sizePolicy.setVerticalStretch( 0 );

    /* Play */
571
    playButton = new QPushButton;
572
    playButton->setSizePolicy( sizePolicy );
573 574
    playButton->setMaximumSize( QSize( 36, 36 ) );
    playButton->setMinimumSize( QSize( 36, 36 ) );
575
    playButton->setIconSize( QSize( 30, 30 ) );
576

577

578
    /** Prev + Stop + Next Block **/
Lukas Durfina's avatar
Lukas Durfina committed
579
    controlButLayout = new QHBoxLayout;
580 581 582 583 584
    controlButLayout->setSpacing( 0 ); /* Don't remove that, will be useful */

    /* Prev */
    QPushButton *prevButton = new QPushButton;
    prevButton->setSizePolicy( sizePolicy );
585
    setupSmallButton( prevButton );
586 587 588 589 590 591

    controlButLayout->addWidget( prevButton );

    /* Stop */
    QPushButton *stopButton = new QPushButton;
    stopButton->setSizePolicy( sizePolicy );
592
    setupSmallButton( stopButton );
593 594 595 596 597 598

    controlButLayout->addWidget( stopButton );

    /* next */
    QPushButton *nextButton = new QPushButton;
    nextButton->setSizePolicy( sizePolicy );
599
    setupSmallButton( nextButton );
600 601 602 603 604

    controlButLayout->addWidget( nextButton );

    /* Add this block to the main layout */

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
605
    BUTTON_SET_ACT_I( playButton, "", play_b, qtr( I_PLAY_TOOLTIP ), play() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
606
    BUTTON_SET_ACT_I( prevButton, "" , previous_b,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
607 608 609 610
                      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() );
611 612 613 614

    /*
     * Other first Line buttons
     */
615
    /** Fullscreen/Visualisation **/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
616
    fullscreenButton = new QPushButton;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
617 618
    BUTTON_SET_ACT_I( fullscreenButton, "", fullscreen,
            qtr( "Toggle the video in fullscreen" ), fullscreen() );
619
    setupSmallButton( fullscreenButton );
620

621 622 623 624 625
    if( !b_fsCreation )
    {
        /** Playlist Button **/
        playlistButton = new QPushButton;
        setupSmallButton( playlistButton );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
626
        BUTTON_SET_IMG( playlistButton, "" , playlist, qtr( "Show playlist" ) );
627 628 629 630
        CONNECT( playlistButton, clicked(), _p_mi, togglePlaylist() );

        /** extended Settings **/
        extSettingsButton = new QPushButton;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
631
        BUTTON_SET_ACT_I( extSettingsButton, "", extended,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
632
                qtr( "Show extended settings" ), extSettings() );
633 634
        setupSmallButton( extSettingsButton );
    }
635

636
    /* Volume */
Lukas Durfina's avatar
Lukas Durfina committed
637
    hVolLabel = new VolumeClickHandler( p_intf, this );
638

639
    volMuteLabel = new QLabel;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
640
    volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
641
    volMuteLabel->installEventFilter( hVolLabel );
642

643 644 645
    if( b_shiny )
    {
        volumeSlider = new SoundSlider( this,
646
            config_GetInt( p_intf, "volume-step" ),
647 648
            config_GetInt( p_intf, "qt-volume-complete" ),
            config_GetPsz( p_intf, "qt-slider-colours" ) );
649 650 651 652 653 654
    }
    else
    {
        volumeSlider = new QSlider( this );
        volumeSlider->setOrientation( Qt::Horizontal );
    }
655
    volumeSlider->setMaximumSize( QSize( 200, 40 ) );
656
    volumeSlider->setMinimumSize( QSize( 85, 30 ) );
657
    volumeSlider->setFocusPolicy( Qt::NoFocus );
658

659
    /* Set the volume from the config */
660 661
    volumeSlider->setValue( ( config_GetInt( p_intf, "volume" ) ) *
                              VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
662

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

666 667
    /* Volume control connection */
    CONNECT( volumeSlider, valueChanged( int ), this, updateVolume( int ) );
668
    CONNECT( THEMIM, volumeChanged( void ), this, updateVolume( void ) );
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 );

677
        controlLayout->addWidget( slider, 0, 1, 1, 18 );
678
        controlLayout->addWidget( slowerButton, 0, 0 );
679
        controlLayout->addWidget( fasterButton, 0, 19 );
680

681 682
        controlLayout->addWidget( discFrame, 1, 8, 2, 3, Qt::AlignBottom );
        controlLayout->addWidget( telexFrame, 1, 8, 2, 5, Qt::AlignBottom );
683

684 685
        controlLayout->addWidget( playButton, 2, 0, 2, 2, Qt::AlignBottom );
        controlLayout->setColumnMinimumWidth( 2, 10 );
686 687
        controlLayout->setColumnStretch( 2, 0 );

688 689 690
        controlLayout->addLayout( controlButLayout, 3, 3, 1, 3, Qt::AlignBottom );
        /* Column 6 is unused */
        controlLayout->setColumnStretch( 6, 0 );
691
        controlLayout->setColumnStretch( 7, 0 );
692
        controlLayout->setColumnMinimumWidth( 7, 10 );
693

694 695 696 697
        controlLayout->addWidget( fullscreenButton, 3, 8, Qt::AlignBottom );
        controlLayout->addWidget( playlistButton, 3, 9, Qt::AlignBottom );
        controlLayout->addWidget( extSettingsButton, 3, 10, Qt::AlignBottom );
        controlLayout->setColumnStretch( 11, 0 ); /* telex alignment */
698

699 700
        controlLayout->setColumnStretch( 12, 0 );
        controlLayout->setColumnMinimumWidth( 12, 10 );
701

702 703 704 705 706 707 708
        controlLayout->addWidget( advControls, 3, 13, 1, 3, Qt::AlignBottom );

        controlLayout->setColumnStretch( 16, 10 );
        controlLayout->setColumnMinimumWidth( 16, 10 );

        controlLayout->addWidget( volMuteLabel, 3, 17, Qt::AlignBottom );
        controlLayout->addWidget( volumeSlider, 3, 18, 1 , 2, Qt::AlignBottom );
709 710
    }

711
    updateInput();
712
}
713

714
ControlsWidget::~ControlsWidget()
715
{}
716

717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
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;
    }
}
733

734 735 736 737 738 739 740 741 742 743
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;
}
744 745 746 747 748

void ControlsWidget::toggleTeletextTransparency()
{
    if( b_telexTransparent )
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
749
        telexTransparent->setIcon( QIcon( ":/tvtelx" ) );
750 751 752 753 754
        telexTransparent->setToolTip( qtr( "Teletext" ) );
        b_telexTransparent = false;
    }
    else
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
755
        telexTransparent->setIcon( QIcon( ":/tvtelx-transparent" ) );
756 757 758 759 760
        telexTransparent->setToolTip( qtr( "Transparent" ) );
        b_telexTransparent = true;
    }
}

761 762 763 764 765 766 767
void ControlsWidget::stop()
{
    THEMIM->stop();
}

void ControlsWidget::play()
{
768
    if( THEPL->current.i_size == 0 )
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    {
        /* 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 )
{
790 791
#define HELP_PCH N_( "Previous chapter" )
#define HELP_NCH N_( "Next chapter" )
792 793 794 795 796 797

    // 1 = chapter, 2 = title, 0 = no
    if( navigation == 0 )
    {
        discFrame->hide();
    } else if( navigation == 1 ) {
798 799
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
800 801 802
        menuButton->show();
        discFrame->show();
    } else {
803 804
        prevSectionButton->setToolTip( qfu( HELP_PCH ) );
        nextSectionButton->setToolTip( qfu( HELP_NCH ) );
805 806 807 808 809 810
        menuButton->hide();
        discFrame->show();
    }
}

static bool b_my_volume;
811
void ControlsWidget::updateVolume( int i_sliderVolume )
812 813 814
{
    if( !b_my_volume )
    {
815
        int i_res = i_sliderVolume  * (AOUT_VOLUME_MAX / 2) / VOLUME_MAX;
816 817
        aout_VolumeSet( p_intf, i_res );
    }
818
    if( i_sliderVolume == 0 )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
819
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
820
        volMuteLabel->setPixmap( QPixmap(":/volume-muted" ) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
821 822 823 824 825
        volMuteLabel->setToolTip( qtr( "Unmute" ) );
        return;
    }

    if( i_sliderVolume < VOLUME_MAX / 3 )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
826
        volMuteLabel->setPixmap( QPixmap( ":/volume-low" ) );
827
    else if( i_sliderVolume > (VOLUME_MAX * 2 / 3 ) )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
828 829
        volMuteLabel->setPixmap( QPixmap( ":/volume-high" ) );
    else volMuteLabel->setPixmap( QPixmap( ":/volume-medium" ) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
830
    volMuteLabel->setToolTip( qtr( "Mute" ) );
831 832
}

833
void ControlsWidget::updateVolume()
834
{
835
    /* Audio part */
836 837
    audio_volume_t i_volume;
    aout_VolumeGet( p_intf, &i_volume );
838
    i_volume = ( i_volume *  VOLUME_MAX )/ (AOUT_VOLUME_MAX/2);
839 840 841 842 843 844 845 846
    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;
    }
847
}
848

849 850
void ControlsWidget::updateInput()
{
851
    /* Activate the interface buttons according to the presence of the input */
852
    enableInput( THEMIM->getIM()->hasInput() );
853
    enableVideo( THEMIM->getIM()->hasVideo() && THEMIM->getIM()->hasInput() );
854
}
855

856 857
void ControlsWidget::setStatus( int status )
{
Jean-Baptiste Kempf's avatar