toolbar.cpp 28.1 KB
Newer Older
1
/*****************************************************************************
Pere Orga's avatar
Pere Orga committed
2
 * toolbar.cpp : ToolbarEdit dialog
3
 ****************************************************************************
4
 * Copyright (C) 2008-2009 the VideoLAN team
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 * $Id$
 *
 * Authors: Jean-Baptiste Kempf <jb (at) videolan.org>
 *
 * 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
 * (at your option) any later version.
 *
 * 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.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "dialogs/toolbar.hpp"

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
30
/* Widgets */
31
32
33
#include "util/input_slider.hpp"
#include "util/customwidgets.hpp"
#include "components/interface_widgets.hpp"
34
35
36
#include "util/buttons/DeckButtonsLayout.hpp"
#include "util/buttons/BrowseButton.hpp"
#include "util/buttons/RoundButton.hpp"
37

38
39
40
41
#include "qt4.hpp"
#include "input_manager.hpp"
#include <vlc_vout.h>                       /* vout_thread_t for aspect ratio combobox */

42
43
44
45
#include <QGroupBox>
#include <QLabel>
#include <QComboBox>
#include <QListWidget>
46
#include <QSpinBox>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
47
#include <QRubberBand>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
48
#include <QDrag>
49
#include <QDragEnterEvent>
50
#include <QDialogButtonBox>
51
#include <QInputDialog>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
52
#include <QMimeData>
53

54
55
#include <assert.h>

56
57
ToolbarEditDialog::ToolbarEditDialog( QWidget *_w, intf_thread_t *_p_intf)
                  : QVLCDialog( _w,  _p_intf )
58
{
59
    setWindowTitle( qtr( "Toolbars Editor" ) );
Nick Pope's avatar
Nick Pope committed
60
    setWindowRole( "vlc-toolbars-editor" );
61
62
    QGridLayout *mainLayout = new QGridLayout( this );
    setMinimumWidth( 600 );
63
    setAttribute( Qt::WA_DeleteOnClose );
64
65

    /* main GroupBox */
Christophe Mutricy's avatar
i18n    
Christophe Mutricy committed
66
    QGroupBox *widgetBox = new QGroupBox( qtr( "Toolbar Elements") , this );
67
68
69
70
    widgetBox->setSizePolicy( QSizePolicy::Preferred,
                              QSizePolicy::MinimumExpanding );
    QGridLayout *boxLayout = new QGridLayout( widgetBox );

71
    QLabel *styleLabel = new QLabel( qtr( "Next widget style:" ) );
72
73
74
    flatBox = new QCheckBox( qtr( "Flat Button" ) );
    bigBox = new QCheckBox( qtr( "Big Button" ) );
    shinyBox = new QCheckBox( qtr( "Native Slider" ) );
75
76

    boxLayout->addWidget( new WidgetListing( p_intf, this ), 0, 0, 1, -1);
77
78
79
    boxLayout->addWidget( styleLabel, 1, 0 );
    boxLayout->addWidget( flatBox, 1, 1 );
    boxLayout->addWidget( bigBox, 1, 2 );
80
81
    boxLayout->addWidget( shinyBox, 2, 1 );
    mainLayout->addWidget( widgetBox, 0, 0, 5, 1 );
82
83
84


    /* Main ToolBar */
Christophe Mutricy's avatar
i18n    
Christophe Mutricy committed
85
    QGroupBox *mainToolbarBox = new QGroupBox( qtr( "Main Toolbar" ), this );
86
87
    QGridLayout *mainTboxLayout = new QGridLayout( mainToolbarBox );

Christophe Mutricy's avatar
i18n    
Christophe Mutricy committed
88
    QLabel *label = new QLabel( qtr( "Toolbar position:" ) );
89
    mainTboxLayout->addWidget(label, 0, 0, 1, 2);
90

91
92
93
    positionCombo = new QComboBox;
    positionCombo->addItem( qtr( "Under the Video" ), QVariant( 0 ) );
    positionCombo->addItem( qtr( "Above the Video" ), QVariant( 1 ) );
94
95
    positionCombo->setCurrentIndex( positionCombo->findData(
                getSettings()->value( "MainWindow/ToolbarPos", 0 ).toInt() ) );
96
    mainTboxLayout->addWidget( positionCombo, 0, 2, 1, 1 );
97

98
    QLabel *line1Label = new QLabel( qtr("Line 1:") );
99
100
    QString line1 = getSettings()->value( "MainWindow/MainToolbar1",
                                          MAIN_TB1_DEFAULT ).toString();
101
    controller1 = new DroppingController( p_intf, line1,
102
            this );
103
104
    mainTboxLayout->addWidget( line1Label, 1, 0, 1, 1 );
    mainTboxLayout->addWidget( controller1, 1, 1, 1, 2 );
105

106
    QLabel *line2Label = new QLabel( qtr("Line 2:") );
107
108
    QString line2 = getSettings()->value( "MainWindow/MainToolbar2",
                                          MAIN_TB2_DEFAULT ).toString();
109
    controller2 = new DroppingController( p_intf, line2,
110
            this );
111
112
113
114
    mainTboxLayout->addWidget( line2Label, 2, 0, 1, 1 );
    mainTboxLayout->addWidget( controller2, 2, 1, 1, 2);

    /* Advanced ToolBar */
Christophe Mutricy's avatar
i18n    
Christophe Mutricy committed
115
    QLabel *advLabel = new QLabel( qtr( "Advanced Widget toolbar:" ) );
116
117
    QString lineA = getSettings()->value( "MainWindow/AdvToolbar",
                                          ADV_TB_DEFAULT ).toString();
118
    controllerA = new DroppingController( p_intf, lineA,
119
120
121
            this );
    mainTboxLayout->addWidget( advLabel, 3, 0, 1, 2 );
    mainTboxLayout->addWidget( controllerA, 3, 2, 1, 1 );
122

123
    mainLayout->addWidget( mainToolbarBox, 0, 1, 1, -1 );
124
125

    /* TimeToolBar */
Christophe Mutricy's avatar
i18n    
Christophe Mutricy committed
126
    QGroupBox *timeToolbarBox = new QGroupBox( qtr( "Time Toolbar" ) , this );
127
128
    QGridLayout *timeTboxLayout = new QGridLayout( timeToolbarBox );

129
130
    QString line = getSettings()->value( "MainWindow/InputToolbar",
                                         INPT_TB_DEFAULT ).toString();
131
    controller = new DroppingController( p_intf, line,
132
133
134
            this );
    timeTboxLayout->addWidget( controller, 0, 0, 1, -1 );

135
    mainLayout->addWidget( timeToolbarBox, 1, 1, 1, -1 );
136
137

    /* FSCToolBar */
Christophe Mutricy's avatar
i18n    
Christophe Mutricy committed
138
139
    QGroupBox *FSCToolbarBox = new QGroupBox( qtr( "Fullscreen Controller" ),
                                              this );
140
141
    QGridLayout *FSCTboxLayout = new QGridLayout( FSCToolbarBox );

142
143
    QString lineFSC = getSettings()->value( "MainWindow/FSCtoolbar",
                                            FSC_TB_DEFAULT ).toString();
144
    controllerFSC = new DroppingController( p_intf,
145
146
147
            lineFSC, this );
    FSCTboxLayout->addWidget( controllerFSC, 0, 0, 1, -1 );

148
    mainLayout->addWidget( FSCToolbarBox, 2, 1, 1, -1 );
149

150
151
152
153
154
155
156
157
158
    /* Profile */
    QGroupBox *profileBox = new QGroupBox( qtr( "Profile" ), this );
    QGridLayout *profileBoxLayout = new QGridLayout( profileBox );

    profileCombo = new QComboBox;
    QLabel *profileLabel = new QLabel( qtr( "Select profile:" ), this );

    QToolButton *newButton = new QToolButton;
    newButton->setIcon( QIcon( ":/new" ) );
159
    newButton->setToolTip( qtr("New profile") );
160
    QToolButton *deleteButton = new QToolButton;
161
    deleteButton->setIcon( QIcon( ":/toolbar/clear" ) );
162
163
164
165
166
167
168
    deleteButton->setToolTip( qtr( "Delete the current profile" ) );

    profileBoxLayout->addWidget( profileLabel, 0, 0 );
    profileBoxLayout->addWidget( profileCombo, 0, 1 );
    profileBoxLayout->addWidget( newButton, 0, 2 );
    profileBoxLayout->addWidget( deleteButton, 0, 3 );

169
    mainLayout->addWidget( profileBox, 3, 1, 1, -1 );
170
171
172
173
174
175
176
177
178
179

    /* Fill combos */
    int i_size = getSettings()->beginReadArray( "ToolbarProfiles" );
    for( int i = 0; i < i_size; i++ )
    {
        getSettings()->setArrayIndex(i);
        profileCombo->addItem( getSettings()->value( "ProfileName" ).toString(),
                               getSettings()->value( "Value" ).toString() );
    }
    getSettings()->endArray();
180
181
182
183
184
185
186

    /* Load defaults ones if we have no combos */
    /* We could decide that we load defaults on first launch of the dialog
       or when the combo is back to 0. I choose the second solution, because some clueless
       user might hit on delete a bit too much, but discussion is opened. -- jb */
    if( i_size == 0 )
    {
187
        profileCombo->addItem( PROFILE_NAME_6, QString( VALUE_6 ) );
188
189
190
191
        profileCombo->addItem( PROFILE_NAME_1, QString( VALUE_1 ) );
        profileCombo->addItem( PROFILE_NAME_2, QString( VALUE_2 ) );
        profileCombo->addItem( PROFILE_NAME_3, QString( VALUE_3 ) );
        profileCombo->addItem( PROFILE_NAME_4, QString( VALUE_4 ) );
192
        profileCombo->addItem( PROFILE_NAME_5, QString( VALUE_5 ) );
193
    }
194
195
    profileCombo->setCurrentIndex( -1 );

196
197
198
    /* Buttons */
    QDialogButtonBox *okCancel = new QDialogButtonBox;
    QPushButton *okButton = new QPushButton( qtr( "Cl&ose" ), this );
199
    okButton->setDefault( true );
200
201
202
    QPushButton *cancelButton = new QPushButton( qtr( "&Cancel" ), this );
    okCancel->addButton( okButton, QDialogButtonBox::AcceptRole );
    okCancel->addButton( cancelButton, QDialogButtonBox::RejectRole );
203

204
205
206
    BUTTONACT( deleteButton, deleteProfile() );
    BUTTONACT( newButton, newProfile() );
    CONNECT( profileCombo, currentIndexChanged( int ), this, changeProfile( int ) );
207
208
    BUTTONACT( okButton, close() );
    BUTTONACT( cancelButton, cancel() );
209
    mainLayout->addWidget( okCancel, 5, 2 );
210
211
212
213
214
}


ToolbarEditDialog::~ToolbarEditDialog()
{
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
    getSettings()->beginWriteArray( "ToolbarProfiles" );
    for( int i = 0; i < profileCombo->count(); i++ )
    {
        getSettings()->setArrayIndex(i);
        getSettings()->setValue( "ProfileName", profileCombo->itemText( i ) );
        getSettings()->setValue( "Value", profileCombo->itemData( i ) );
    }
    getSettings()->endArray();
}

void ToolbarEditDialog::newProfile()
{
    bool ok;
    QString name =  QInputDialog::getText( this, qtr( "Profile Name" ),
                 qtr( "Please enter the new profile name." ), QLineEdit::Normal, 0, &ok );
    if( !ok ) return;

    QString temp = QString::number( positionCombo->currentIndex() );
    temp += "|" + controller1->getValue();
    temp += "|" + controller2->getValue();
    temp += "|" + controllerA->getValue();
    temp += "|" + controller->getValue();
    temp += "|" + controllerFSC->getValue();

    profileCombo->addItem( name, temp );
    profileCombo->setCurrentIndex( profileCombo->count() - 1 );
}

void ToolbarEditDialog::deleteProfile()
{
    profileCombo->removeItem( profileCombo->currentIndex() );
}

void ToolbarEditDialog::changeProfile( int i )
{
    QStringList qs_list = profileCombo->itemData( i ).toString().split( "|" );
    if( qs_list.count() < 6 )
        return;

    positionCombo->setCurrentIndex( positionCombo->findData( qs_list[0].toInt() ) );
    controller1->resetLine( qs_list[1] );
    controller2->resetLine( qs_list[2] );
    controllerA->resetLine( qs_list[3] );
    controller->resetLine( qs_list[4] );
    controllerFSC->resetLine( qs_list[5] );
260
261
}

262
263
void ToolbarEditDialog::close()
{
264
265
    getSettings()->setValue( "MainWindow/ToolbarPos",
            positionCombo->itemData( positionCombo->currentIndex() ).toInt() );
266
267
268
269
270
    getSettings()->setValue( "MainWindow/MainToolbar1", controller1->getValue() );
    getSettings()->setValue( "MainWindow/MainToolbar2", controller2->getValue() );
    getSettings()->setValue( "MainWindow/AdvToolbar", controllerA->getValue() );
    getSettings()->setValue( "MainWindow/InputToolbar", controller->getValue() );
    getSettings()->setValue( "MainWindow/FSCtoolbar", controllerFSC->getValue() );
271
272
    getSettings()->sync();
    accept();
273
274
275
276
}

void ToolbarEditDialog::cancel()
{
277
    reject();
278
279
}

280
281
282
283
/************************************************
 *  Widget Listing:
 * Creation of the list of drawed lovely buttons
 ************************************************/
284
285
286
287
288
289
290
291
292
WidgetListing::WidgetListing( intf_thread_t *p_intf, QWidget *_parent )
              : QListWidget( _parent )
{
    /* We need the parent to know the options checked */
    parent = qobject_cast<ToolbarEditDialog *>(_parent);
    assert( parent );

    /* Normal options */
    setViewMode( QListView::IconMode );
293
294
295
296
297
    setSpacing( 8 );
    setGridSize( QSize(90, 50) );
    setWrapping( true );
    setWordWrap( true );
    setTextElideMode( Qt::ElideNone );
298
299
300
301
302
303
    setDragEnabled( true );

    /* All the buttons do not need a special rendering */
    for( int i = 0; i < BUTTON_MAX; i++ )
    {
        QListWidgetItem *widgetItem = new QListWidgetItem( this );
Christophe Mutricy's avatar
Christophe Mutricy committed
304
        widgetItem->setText( qtr( nameL[i] ) );
305
306
        QPixmap pix( iconL[i] );
        widgetItem->setIcon( pix.scaled( 16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
307
        widgetItem->setData( Qt::UserRole, QVariant( i ) );
308
        widgetItem->setToolTip( widgetItem->text() );
309
310
311
312
        addItem( widgetItem );
    }

    /* Spacers are yet again a different thing */
313
    QListWidgetItem *widgetItem = new QListWidgetItem( QIcon( ":/toolbar/space" ),
314
315
            qtr( "Spacer" ), this );
    widgetItem->setData( Qt::UserRole, WIDGET_SPACER );
316
    widgetItem->setToolTip( widgetItem->text() );
317
318
    addItem( widgetItem );

319
    widgetItem = new QListWidgetItem( QIcon( ":/toolbar/space" ),
320
321
            qtr( "Expanding Spacer" ), this );
    widgetItem->setData( Qt::UserRole, WIDGET_SPACER_EXTEND );
322
    widgetItem->setToolTip( widgetItem->text() );
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
    addItem( widgetItem );

    /**
     * For all other widgets, we create then, do a pseudo rendering in
     * a pixmaps for the view, and delete the object
     *
     * A lot of code is retaken from the Abstract, but not exactly...
     * So, rewrite.
     * They are better ways to deal with this, but I doubt that this is
     * necessary. If you feel like you have the time, be my guest.
     * --
     * jb
     **/
    for( int i = SPLITTER; i < SPECIAL_MAX; i++ )
    {
        QWidget *widget = NULL;
        QListWidgetItem *widgetItem = new QListWidgetItem( this );
        switch( i )
        {
        case SPLITTER:
            {
                QFrame *line = new QFrame( this );
                line->setFrameShape( QFrame::VLine );
                line->setFrameShadow( QFrame::Raised );
                line->setLineWidth( 0 ); line->setMidLineWidth( 1 );
                widget = line;
            }
            widgetItem->setText( qtr("Splitter") );
            break;
        case INPUT_SLIDER:
            {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
354
                SeekSlider *slider = new SeekSlider( Qt::Horizontal, this );
355
356
357
358
359
360
                widget = slider;
            }
            widgetItem->setText( qtr("Time Slider") );
            break;
        case VOLUME:
            {
361
362
                SoundWidget *snd = new SoundWidget( this, p_intf,
                        parent->getOptions() & WIDGET_SHINY );
363
364
365
366
                widget = snd;
            }
            widgetItem->setText( qtr("Volume") );
            break;
367
368
369
        case VOLUME_SPECIAL:
            {
                QListWidgetItem *widgetItem = new QListWidgetItem( this );
Eric Lassauge's avatar
Eric Lassauge committed
370
                widgetItem->setText( qtr("Small Volume") );
371
                widgetItem->setIcon( QIcon( ":/toolbar/volume-medium" ) );
372
373
374
375
                widgetItem->setData( Qt::UserRole, QVariant( i ) );
                addItem( widgetItem );
            }
            continue;
376
377
378
379
380
381
382
383
384
385
        case TIME_LABEL:
            {
                QLabel *timeLabel = new QLabel( "12:42/2:12:42", this );
                widget = timeLabel;
            }
            widgetItem->setText( qtr("Time") );
            break;
        case MENU_BUTTONS:
            {
                QWidget *discFrame = new QWidget( this );
386
                //discFrame->setLineWidth( 1 );
387
388
389
390
                QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
                discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );

                QToolButton *prevSectionButton = new QToolButton( discFrame );
391
                prevSectionButton->setIcon( QIcon( ":/toolbar/dvd_prev" ) );
392
                prevSectionButton->setToolTip( qtr("Previous chapter") );
393
394
395
                discLayout->addWidget( prevSectionButton );

                QToolButton *menuButton = new QToolButton( discFrame );
396
                menuButton->setIcon( QIcon( ":/toolbar/dvd_menu" ) );
397
                menuButton->setToolTip( qtr("Go to the DVD menu") );
398
399
400
                discLayout->addWidget( menuButton );

                QToolButton *nextButton = new QToolButton( discFrame );
401
                nextButton->setIcon( QIcon( ":/toolbar/dvd_next" ) );
402
                nextButton->setToolTip( qtr("Next chapter") );
403
404
405
406
407
408
409
410
411
412
413
414
415
                discLayout->addWidget( nextButton );

                widget = discFrame;
            }
            widgetItem->setText( qtr("DVD menus") );
            break;
        case TELETEXT_BUTTONS:
            {
                QWidget *telexFrame = new QWidget( this );
                QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
                telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );

                QToolButton *telexOn = new QToolButton( telexFrame );
416
                telexOn->setIcon( QIcon( ":/toolbar/tv" ) );
417
418
419
                telexLayout->addWidget( telexOn );

                QToolButton *telexTransparent = new QToolButton;
420
421
                telexTransparent->setIcon( QIcon( ":/toolbar/tvtelx" ) );
                telexTransparent->setToolTip( qtr("Teletext transparency") );
422
423
424
425
426
427
428
429
430
431
432
                telexLayout->addWidget( telexTransparent );

                QSpinBox *telexPage = new QSpinBox;
                telexLayout->addWidget( telexPage );

                widget = telexFrame;
            }
            widgetItem->setText( qtr("Teletext") );
            break;
        case ADVANCED_CONTROLLER:
            {
433
                AdvControlsWidget *advControls = new AdvControlsWidget( p_intf, this );
434
435
436
437
                widget = advControls;
            }
            widgetItem->setText( qtr("Advanced Buttons") );
            break;
438
439
440
441
442
443
444
445
446
447
448
        case PLAYBACK_BUTTONS:
            {
                widget = new QWidget;
                DeckButtonsLayout *layout = new DeckButtonsLayout( widget );
                BrowseButton *prev = new BrowseButton( widget, BrowseButton::Backward );
                BrowseButton *next = new BrowseButton( widget );
                RoundButton *play = new RoundButton( widget );
                layout->setBackwardButton( prev );
                layout->setForwardButton( next );
                layout->setRoundButton( play );
            }
449
            widgetItem->setText( qtr("Playback Buttons") );
450
            break;
451
452
453
454
        case ASPECT_RATIO_COMBOBOX:
            widget = new AspectRatioComboBox( p_intf );
            widgetItem->setText( qtr("Aspect ratio selector") );
            break;
455
456
457
458
        case SPEED_LABEL:
            widget = new SpeedLabel( p_intf, this );
            widgetItem->setText( qtr("Speed selector") );
            break;
459
460
        case TIME_LABEL_ELAPSED:
            widget = new QLabel( "2:42", this );
461
            widgetItem->setText( qtr("Elapsed time") );
462
463
464
465
466
            break;
        case TIME_LABEL_REMAINING:
            widget = new QLabel( "-2:42", this );
            widgetItem->setText( qtr("Total/Remaining time") );
            break;
467
468
469
470
471
472
473
474
475
        default:
            msg_Warn( p_intf, "This should not happen %i", i );
            break;
        }

        if( widget == NULL ) continue;


        widgetItem->setIcon( QIcon( QPixmap::grabWidget( widget ) ) );
476
        widgetItem->setToolTip( widgetItem->text() );
477
478
479
480
481
482
483
484
485
486
        widget->hide();
        widgetItem->setData( Qt::UserRole, QVariant( i ) );

        addItem( widgetItem );
        delete widget;
    }
}

void WidgetListing::startDrag( Qt::DropActions /*supportedActions*/ )
{
487
    QListWidgetItem *item = currentItem();
488
489
490
491
492
493
494
495

    QByteArray itemData;
    QDataStream dataStream( &itemData, QIODevice::WriteOnly );

    int i_type = item->data( Qt::UserRole ).toInt();
    int i_option = parent->getOptions();
    dataStream << i_type << i_option;

496
497
498
499
    /* Create a new dragging event */
    QDrag *drag = new QDrag( this );

    /* With correct mimedata */
500
501
502
    QMimeData *mimeData = new QMimeData;
    mimeData->setData( "vlc/button-bar", itemData );
    drag->setMimeData( mimeData );
503
504

    /* And correct pixmap */
505
506
507
    QPixmap aPixmap = item->icon().pixmap( QSize( 22, 22 ) );
    drag->setPixmap( aPixmap );
    drag->setHotSpot( QPoint( 20, 20 ) );
508

509
510
511
    /* We want to keep a copy */
    drag->exec( Qt::CopyAction | Qt::MoveAction );
}
512

513
514
515
516
517
518
/*
 * The special controller with drag'n drop abilities.
 * We don't do this in the main controller, since we don't want the OverHead
 * to propagate there too
 */
DroppingController::DroppingController( intf_thread_t *_p_intf,
519
                                        const QString& line,
520
                                        QWidget *_parent )
521
                   : AbstractController( _p_intf, _parent )
522
{
523
    RTL_UNAFFECTED_WIDGET
524
    rubberband = NULL;
525
    b_draging = false;
526
527
    setAcceptDrops( true );
    controlLayout = new QHBoxLayout( this );
528
    controlLayout->setSpacing( 5 );
529
530
531
    controlLayout->setMargin( 0 );
    setFrameShape( QFrame::StyledPanel );
    setFrameShadow( QFrame::Raised );
532
    setMinimumHeight( 20 );
533

534
    parseAndCreate( line, controlLayout );
535
536
}

537
void DroppingController::resetLine( const QString& line )
538
539
540
541
542
543
544
545
546
547
548
549
550
{
    hide();
    QLayoutItem *child;
    while( (child = controlLayout->takeAt( 0 ) ) != 0 )
    {
        child->widget()->hide();
        delete child;
    }

    parseAndCreate( line, controlLayout );
    show();
}

551
/* Overloading the AbstractController one, because we don't manage the
552
   Spacing items in the same ways */
553
void DroppingController::createAndAddWidget( QBoxLayout *newControlLayout,
554
555
556
557
558
559
560
                                             int i_index,
                                             buttonType_e i_type,
                                             int i_option )
{
    /* Special case for SPACERS, who aren't QWidgets */
    if( i_type == WIDGET_SPACER || i_type == WIDGET_SPACER_EXTEND )
    {
561
        QLabel *label = new QLabel( this );
562
        label->setPixmap( QPixmap( ":/toolbar/space" ) );
563
564
565
566
        if( i_type == WIDGET_SPACER_EXTEND )
        {
            label->setSizePolicy( QSizePolicy::MinimumExpanding,
                    QSizePolicy::Preferred );
567
568
569
570
571

            /* Create a box around it */
            label->setFrameStyle( QFrame::Panel | QFrame::Sunken );
            label->setLineWidth ( 1 );
            label->setAlignment( Qt::AlignCenter );
572
573
574
575
576
        }
        else
            label->setSizePolicy( QSizePolicy::Fixed,
                    QSizePolicy::Preferred );

577
578
        /* Install event Filter for drag'n drop */
        label->installEventFilter( this );
579
        newControlLayout->insertWidget( i_index, label );
580
    }
581
582

    /* Normal Widgets */
583
584
585
586
587
    else
    {
        QWidget *widg = createWidget( i_type, i_option );
        if( !widg ) return;

588
        /* Install the Event Filter in order to catch the drag */
589
        widg->setParent( this );
590
591
592
593
594
595
596
597
598
599
600
        widg->installEventFilter( this );

        /* We are in a complex widget, we need to stop events on children too */
        if( i_type >= VOLUME && i_type < SPECIAL_MAX )
        {
            QList<QObject *>children = widg->children();

            QObject *child;
            foreach( child, children )
            {
                QWidget *childWidg;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
601
                if( ( childWidg = qobject_cast<QWidget *>( child ) ) )
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
                {
                    child->installEventFilter( this );
                    childWidg->setEnabled( true );
                }
            }

            /* Decorating the frames when possible */
            QFrame *frame;
            if( i_type >= MENU_BUTTONS  /* Don't bother to check for volume */
                && ( frame = qobject_cast<QFrame *>( widg ) ) != NULL )
            {
                frame->setFrameStyle( QFrame::Panel | QFrame::Raised );
                frame->setLineWidth ( 1 );
            }
        }

618
619
        /* Some Widgets are deactivated at creation */
        widg->setEnabled( true );
620
        widg->show();
621
        newControlLayout->insertWidget( i_index, widg );
622
    }
623

624
    /* QList and QBoxLayout don't act the same with insert() */
625
    if( i_index < 0 ) i_index = newControlLayout->count() - 1;
626

627
628
629
630
    doubleInt *value = new doubleInt;
    value->i_type = i_type;
    value->i_option = i_option;

631
632
633
    widgetList.insert( i_index, value );
}

634
635
636
637
638
639
DroppingController::~DroppingController()
{
    qDeleteAll( widgetList );
    widgetList.clear();
}

640
641
642
643
644
645
646
647
648
649
650
651
652
653
QString DroppingController::getValue()
{
    QString qs = "";

    for( int i = 0; i < controlLayout->count(); i++ )
    {
        doubleInt *dI = widgetList.at( i );
        assert( dI );

        qs.append( QString::number( dI->i_type ) );
        if( dI->i_option ) qs.append( "-" + QString::number( dI->i_option ) );
        qs.append( ';' );
    }
    return qs;
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
}

void DroppingController::dragEnterEvent( QDragEnterEvent * event )
{
    if( event->mimeData()->hasFormat( "vlc/button-bar" ) )
        event->accept();
    else
        event->ignore();
}

void DroppingController::dragMoveEvent( QDragMoveEvent *event )
{
    QPoint origin = event->pos();

    int i_pos = getParentPosInLayout( origin );
    bool b_end = false;

    /* Both sides of the frame */
    if( i_pos == -1 )
    {
        if( rubberband ) rubberband->hide();
        return;
    }

    /* Last item is special because of underlying items */
    if( i_pos >= controlLayout->count() )
    {
        i_pos--;
        b_end = true;
    }

    /* Query the underlying item for size && middles */
    QLayoutItem *tempItem = controlLayout->itemAt( i_pos ); assert( tempItem );
    QWidget *temp = tempItem->widget(); assert( temp );

    /* Position assignment */
    origin.ry() = 0;
    origin.rx() = temp->x() - 2;

    if( b_end ) origin.rx() += temp->width();

    if( !rubberband )
        rubberband = new QRubberBand( QRubberBand::Line, this );
    rubberband->setGeometry( origin.x(), origin.y(), 4, height() );
    rubberband->show();
}

701
inline int DroppingController::getParentPosInLayout( QPoint point )
702
703
704
705
706
{
    point.ry() = height() / 2 ;
    QPoint origin = mapToGlobal ( point );

    QWidget *tempWidg = QApplication::widgetAt( origin );
707
708
    if( tempWidg == NULL )
        return -1;
709

710
711
    int i = controlLayout->indexOf( tempWidg );
    if( i == -1 )
712
    {
713
714
        i = controlLayout->indexOf( tempWidg->parentWidget() );
        tempWidg = tempWidg->parentWidget();
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
    }

    /* Return the nearest position */
    if( ( point.x() - tempWidg->x()  > tempWidg->width() / 2 ) && i != -1 )
        i++;

    //    msg_Dbg( p_intf, "%i", i);
    return i;
}

void DroppingController::dropEvent( QDropEvent *event )
{
    int i = getParentPosInLayout( event->pos() );

    QByteArray data = event->mimeData()->data( "vlc/button-bar" );
    QDataStream dataStream(&data, QIODevice::ReadOnly);

    int i_option = 0, i_type = 0;
    dataStream >> i_type >> i_option;

    createAndAddWidget( controlLayout, i, (buttonType_e)i_type, i_option );

    /* Hide by precaution, you don't exactly know what could have happened in
       between */
    if( rubberband ) rubberband->hide();
}

void DroppingController::dragLeaveEvent ( QDragLeaveEvent * event )
{
    if( rubberband ) rubberband->hide();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
745
    event->accept();
746
747
748
749
750
}

/**
 * Overloading doAction to block any action
 **/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
751
752
753
754
void DroppingController::doAction( int i )
{
    VLC_UNUSED( i );
}
755

756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
bool DroppingController::eventFilter( QObject *obj, QEvent *event )
{
    switch( event->type() )
    {
        case QEvent::MouseButtonPress:
            b_draging = true;
            return true;
        case QEvent::MouseButtonRelease:
            b_draging = false;
            return true;
        case QEvent::MouseMove:
            {
            if( !b_draging ) return true;
            QWidget *widg = static_cast<QWidget*>(obj);

            QByteArray itemData;
            QDataStream dataStream( &itemData, QIODevice::WriteOnly );

            int i = -1;
            i = controlLayout->indexOf( widg );
            if( i == -1 )
            {
                i = controlLayout->indexOf( widg->parentWidget() );
                widg = widg->parentWidget();
                /* NOTE: be extra-careful Now with widg access */
            }

            if( i == -1 ) return true;
784
785
            i_dragIndex = i;

786
787
788
789
790
791
792
793
794
795
796
797
798
            doubleInt *dI = widgetList.at( i );

            int i_type = dI->i_type;
            int i_option = dI->i_option;
            dataStream << i_type << i_option;

            /* With correct mimedata */
            QMimeData *mimeData = new QMimeData;
            mimeData->setData( "vlc/button-bar", itemData );

            QDrag *drag = new QDrag( widg );
            drag->setMimeData( mimeData );

799
800
801
            /* Remove before the drag to not mess DropEvent,
               that will createAndAddWidget */
            widgetList.removeAt( i );
802
803
            controlLayout->removeWidget( widg );
            widg->hide();
804

805
806
807
808
809
810
            /* Start the effective drag */
            drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction);
            b_draging = false;
            }
            return true;

811
        case QEvent::MouseButtonDblClick:
812
813
814
815
816
817
818
819
820
821
        case QEvent::EnabledChange:
        case QEvent::Hide:
        case QEvent::HideToParent:
        case QEvent::Move:
        case QEvent::ZOrderChange:
            return true;
        default:
            return false;
    }
}