]> git.sesse.net Git - vlc/blob - modules/gui/qt4/dialogs/toolbar.cpp
93401ac3b3f0427d9d3249429b9575eee298a68f
[vlc] / modules / gui / qt4 / dialogs / toolbar.cpp
1 /*****************************************************************************
2  * toolbar.cpp : ToolbarEdit dialog
3  ****************************************************************************
4  * Copyright (C) 2008-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jean-Baptiste Kempf <jb (at) videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include "dialogs/toolbar.hpp"
29
30 /* Widgets */
31 #include "util/input_slider.hpp"
32 #include "util/customwidgets.hpp"
33 #include "components/interface_widgets.hpp"
34 #include "util/buttons/DeckButtonsLayout.hpp"
35 #include "util/buttons/BrowseButton.hpp"
36 #include "util/buttons/RoundButton.hpp"
37
38 #include <QScrollArea>
39 #include <QGroupBox>
40 #include <QLabel>
41 #include <QComboBox>
42 #include <QListWidget>
43 #include <QSpinBox>
44 #include <QRubberBand>
45
46 #include <QDragEnterEvent>
47 #include <QDialogButtonBox>
48 #include <QInputDialog>
49
50 #include <assert.h>
51
52 ToolbarEditDialog::ToolbarEditDialog( QWidget *_w, intf_thread_t *_p_intf)
53                   : QVLCDialog( _w,  _p_intf )
54 {
55     setWindowTitle( qtr( "Toolbars Editor" ) );
56     setWindowRole( "vlc-toolbars-editor" );
57     QGridLayout *mainLayout = new QGridLayout( this );
58     setMinimumWidth( 600 );
59     setAttribute( Qt::WA_DeleteOnClose );
60
61     /* main GroupBox */
62     QGroupBox *widgetBox = new QGroupBox( qtr( "Toolbar Elements") , this );
63     widgetBox->setSizePolicy( QSizePolicy::Preferred,
64                               QSizePolicy::MinimumExpanding );
65     QGridLayout *boxLayout = new QGridLayout( widgetBox );
66
67     QLabel *styleLabel = new QLabel( qtr( "Next widget style:" ) );
68     flatBox = new QCheckBox( qtr( "Flat Button" ) );
69     bigBox = new QCheckBox( qtr( "Big Button" ) );
70     shinyBox = new QCheckBox( qtr( "Native Slider" ) );
71
72     boxLayout->addWidget( new WidgetListing( p_intf, this ), 0, 0, 1, -1);
73     boxLayout->addWidget( styleLabel, 1, 0 );
74     boxLayout->addWidget( flatBox, 1, 1 );
75     boxLayout->addWidget( bigBox, 1, 2 );
76     boxLayout->addWidget( shinyBox, 2, 1 );
77     mainLayout->addWidget( widgetBox, 0, 0, 5, 1 );
78
79
80     /* Main ToolBar */
81     QGroupBox *mainToolbarBox = new QGroupBox( qtr( "Main Toolbar" ), this );
82     QGridLayout *mainTboxLayout = new QGridLayout( mainToolbarBox );
83
84     QLabel *label = new QLabel( qtr( "Toolbar position:" ) );
85     mainTboxLayout->addWidget(label, 0, 0, 1, 2);
86
87     positionCombo = new QComboBox;
88     positionCombo->addItem( qtr( "Under the Video" ), QVariant( 0 ) );
89     positionCombo->addItem( qtr( "Above the Video" ), QVariant( 1 ) );
90     positionCombo->setCurrentIndex( positionCombo->findData(
91                 getSettings()->value( "MainWindow/ToolbarPos", 0 ).toInt() ) );
92     mainTboxLayout->addWidget( positionCombo, 0, 2, 1, 1 );
93
94     QLabel *line1Label = new QLabel( qtr("Line 1:") );
95     QString line1 = getSettings()->value( "MainWindow/MainToolbar1",
96                                           MAIN_TB1_DEFAULT ).toString();
97     controller1 = new DroppingController( p_intf, line1,
98             this );
99     mainTboxLayout->addWidget( line1Label, 1, 0, 1, 1 );
100     mainTboxLayout->addWidget( controller1, 1, 1, 1, 2 );
101
102     QLabel *line2Label = new QLabel( qtr("Line 2:") );
103     QString line2 = getSettings()->value( "MainWindow/MainToolbar2",
104                                           MAIN_TB2_DEFAULT ).toString();
105     controller2 = new DroppingController( p_intf, line2,
106             this );
107     mainTboxLayout->addWidget( line2Label, 2, 0, 1, 1 );
108     mainTboxLayout->addWidget( controller2, 2, 1, 1, 2);
109
110     /* Advanced ToolBar */
111     QLabel *advLabel = new QLabel( qtr( "Advanced Widget toolbar:" ) );
112     QString lineA = getSettings()->value( "MainWindow/AdvToolbar",
113                                           ADV_TB_DEFAULT ).toString();
114     controllerA = new DroppingController( p_intf, lineA,
115             this );
116     mainTboxLayout->addWidget( advLabel, 3, 0, 1, 2 );
117     mainTboxLayout->addWidget( controllerA, 3, 2, 1, 1 );
118
119     mainLayout->addWidget( mainToolbarBox, 0, 1, 1, -1 );
120
121     /* TimeToolBar */
122     QGroupBox *timeToolbarBox = new QGroupBox( qtr( "Time Toolbar" ) , this );
123     QGridLayout *timeTboxLayout = new QGridLayout( timeToolbarBox );
124
125     QString line = getSettings()->value( "MainWindow/InputToolbar",
126                                          INPT_TB_DEFAULT ).toString();
127     controller = new DroppingController( p_intf, line,
128             this );
129     timeTboxLayout->addWidget( controller, 0, 0, 1, -1 );
130
131     mainLayout->addWidget( timeToolbarBox, 1, 1, 1, -1 );
132
133     /* FSCToolBar */
134     QGroupBox *FSCToolbarBox = new QGroupBox( qtr( "Fullscreen Controller" ),
135                                               this );
136     QGridLayout *FSCTboxLayout = new QGridLayout( FSCToolbarBox );
137
138     QString lineFSC = getSettings()->value( "MainWindow/FSCtoolbar",
139                                             FSC_TB_DEFAULT ).toString();
140     controllerFSC = new DroppingController( p_intf,
141             lineFSC, this );
142     FSCTboxLayout->addWidget( controllerFSC, 0, 0, 1, -1 );
143
144     mainLayout->addWidget( FSCToolbarBox, 2, 1, 1, -1 );
145
146     /* Profile */
147     QGroupBox *profileBox = new QGroupBox( qtr( "Profile" ), this );
148     QGridLayout *profileBoxLayout = new QGridLayout( profileBox );
149
150     profileCombo = new QComboBox;
151     QLabel *profileLabel = new QLabel( qtr( "Select profile:" ), this );
152
153     QToolButton *newButton = new QToolButton;
154     newButton->setIcon( QIcon( ":/new" ) );
155     newButton->setToolTip( qtr("New profile") );
156     QToolButton *deleteButton = new QToolButton;
157     deleteButton->setIcon( QIcon( ":/toolbar/clear" ) );
158     deleteButton->setToolTip( qtr( "Delete the current profile" ) );
159
160     profileBoxLayout->addWidget( profileLabel, 0, 0 );
161     profileBoxLayout->addWidget( profileCombo, 0, 1 );
162     profileBoxLayout->addWidget( newButton, 0, 2 );
163     profileBoxLayout->addWidget( deleteButton, 0, 3 );
164
165     mainLayout->addWidget( profileBox, 3, 1, 1, -1 );
166
167     /* Fill combos */
168     int i_size = getSettings()->beginReadArray( "ToolbarProfiles" );
169     for( int i = 0; i < i_size; i++ )
170     {
171         getSettings()->setArrayIndex(i);
172         profileCombo->addItem( getSettings()->value( "ProfileName" ).toString(),
173                                getSettings()->value( "Value" ).toString() );
174     }
175     getSettings()->endArray();
176
177     /* Load defaults ones if we have no combos */
178     /* We could decide that we load defaults on first launch of the dialog
179        or when the combo is back to 0. I choose the second solution, because some clueless
180        user might hit on delete a bit too much, but discussion is opened. -- jb */
181     if( i_size == 0 )
182     {
183         profileCombo->addItem( PROFILE_NAME_1, QString( VALUE_1 ) );
184         profileCombo->addItem( PROFILE_NAME_2, QString( VALUE_2 ) );
185         profileCombo->addItem( PROFILE_NAME_3, QString( VALUE_3 ) );
186         profileCombo->addItem( PROFILE_NAME_4, QString( VALUE_4 ) );
187         profileCombo->addItem( PROFILE_NAME_5, QString( VALUE_5 ) );
188     }
189     profileCombo->setCurrentIndex( -1 );
190
191     /* Buttons */
192     QDialogButtonBox *okCancel = new QDialogButtonBox;
193     QPushButton *okButton = new QPushButton( qtr( "Cl&ose" ), this );
194     okButton->setDefault( true );
195     QPushButton *cancelButton = new QPushButton( qtr( "&Cancel" ), this );
196     okCancel->addButton( okButton, QDialogButtonBox::AcceptRole );
197     okCancel->addButton( cancelButton, QDialogButtonBox::RejectRole );
198
199     BUTTONACT( deleteButton, deleteProfile() );
200     BUTTONACT( newButton, newProfile() );
201     CONNECT( profileCombo, currentIndexChanged( int ), this, changeProfile( int ) );
202     BUTTONACT( okButton, close() );
203     BUTTONACT( cancelButton, cancel() );
204     mainLayout->addWidget( okCancel, 5, 2 );
205 }
206
207
208 ToolbarEditDialog::~ToolbarEditDialog()
209 {
210     getSettings()->beginWriteArray( "ToolbarProfiles" );
211     for( int i = 0; i < profileCombo->count(); i++ )
212     {
213         getSettings()->setArrayIndex(i);
214         getSettings()->setValue( "ProfileName", profileCombo->itemText( i ) );
215         getSettings()->setValue( "Value", profileCombo->itemData( i ) );
216     }
217     getSettings()->endArray();
218 }
219
220 void ToolbarEditDialog::newProfile()
221 {
222     bool ok;
223     QString name =  QInputDialog::getText( this, qtr( "Profile Name" ),
224                  qtr( "Please enter the new profile name." ), QLineEdit::Normal, 0, &ok );
225     if( !ok ) return;
226
227     QString temp = QString::number( positionCombo->currentIndex() );
228     temp += "|" + controller1->getValue();
229     temp += "|" + controller2->getValue();
230     temp += "|" + controllerA->getValue();
231     temp += "|" + controller->getValue();
232     temp += "|" + controllerFSC->getValue();
233
234     profileCombo->addItem( name, temp );
235     profileCombo->setCurrentIndex( profileCombo->count() - 1 );
236 }
237
238 void ToolbarEditDialog::deleteProfile()
239 {
240     profileCombo->removeItem( profileCombo->currentIndex() );
241 }
242
243 void ToolbarEditDialog::changeProfile( int i )
244 {
245     QStringList qs_list = profileCombo->itemData( i ).toString().split( "|" );
246     if( qs_list.count() < 6 )
247         return;
248
249     positionCombo->setCurrentIndex( positionCombo->findData( qs_list[0].toInt() ) );
250     controller1->resetLine( qs_list[1] );
251     controller2->resetLine( qs_list[2] );
252     controllerA->resetLine( qs_list[3] );
253     controller->resetLine( qs_list[4] );
254     controllerFSC->resetLine( qs_list[5] );
255 }
256
257 void ToolbarEditDialog::close()
258 {
259     msg_Dbg( p_intf, "Close and save" );
260     getSettings()->setValue( "MainWindow/ToolbarPos",
261             positionCombo->itemData( positionCombo->currentIndex() ).toInt() );
262     getSettings()->setValue( "MainWindow/MainToolbar1", controller1->getValue() );
263     getSettings()->setValue( "MainWindow/MainToolbar2", controller2->getValue() );
264     getSettings()->setValue( "MainWindow/AdvToolbar", controllerA->getValue() );
265     getSettings()->setValue( "MainWindow/InputToolbar", controller->getValue() );
266     getSettings()->setValue( "MainWindow/FSCtoolbar", controllerFSC->getValue() );
267     getSettings()->sync();
268     accept();
269 }
270
271 void ToolbarEditDialog::cancel()
272 {
273     reject();
274 }
275
276 /************************************************
277  *  Widget Listing:
278  * Creation of the list of drawed lovely buttons
279  ************************************************/
280 WidgetListing::WidgetListing( intf_thread_t *p_intf, QWidget *_parent )
281               : QListWidget( _parent )
282 {
283     /* We need the parent to know the options checked */
284     parent = qobject_cast<ToolbarEditDialog *>(_parent);
285     assert( parent );
286
287     /* Normal options */
288     setViewMode( QListView::IconMode );
289     setSpacing( 20 );
290     setDragEnabled( true );
291
292     /* All the buttons do not need a special rendering */
293     for( int i = 0; i < BUTTON_MAX; i++ )
294     {
295         QListWidgetItem *widgetItem = new QListWidgetItem( this );
296         widgetItem->setText( qtr( nameL[i] ) );
297         widgetItem->setIcon( QIcon( iconL[i] ) );
298         widgetItem->setData( Qt::UserRole, QVariant( i ) );
299         addItem( widgetItem );
300     }
301
302     /* Spacers are yet again a different thing */
303     QListWidgetItem *widgetItem = new QListWidgetItem( QIcon( ":/toolbar/space" ),
304             qtr( "Spacer" ), this );
305     widgetItem->setData( Qt::UserRole, WIDGET_SPACER );
306     addItem( widgetItem );
307
308     widgetItem = new QListWidgetItem( QIcon( ":/toolbar/space" ),
309             qtr( "Expanding Spacer" ), this );
310     widgetItem->setData( Qt::UserRole, WIDGET_SPACER_EXTEND );
311     addItem( widgetItem );
312
313     /**
314      * For all other widgets, we create then, do a pseudo rendering in
315      * a pixmaps for the view, and delete the object
316      *
317      * A lot of code is retaken from the Abstract, but not exactly...
318      * So, rewrite.
319      * They are better ways to deal with this, but I doubt that this is
320      * necessary. If you feel like you have the time, be my guest.
321      * --
322      * jb
323      **/
324     for( int i = SPLITTER; i < SPECIAL_MAX; i++ )
325     {
326         QWidget *widget = NULL;
327         QListWidgetItem *widgetItem = new QListWidgetItem( this );
328         switch( i )
329         {
330         case SPLITTER:
331             {
332                 QFrame *line = new QFrame( this );
333                 line->setFrameShape( QFrame::VLine );
334                 line->setFrameShadow( QFrame::Raised );
335                 line->setLineWidth( 0 ); line->setMidLineWidth( 1 );
336                 widget = line;
337             }
338             widgetItem->setText( qtr("Splitter") );
339             break;
340         case INPUT_SLIDER:
341             {
342                 SeekSlider *slider = new SeekSlider( Qt::Horizontal, this );
343                 widget = slider;
344             }
345             widgetItem->setText( qtr("Time Slider") );
346             break;
347         case VOLUME:
348             {
349                 SoundWidget *snd = new SoundWidget( this, p_intf,
350                         parent->getOptions() & WIDGET_SHINY );
351                 widget = snd;
352             }
353             widgetItem->setText( qtr("Volume") );
354             break;
355         case VOLUME_SPECIAL:
356             {
357                 QListWidgetItem *widgetItem = new QListWidgetItem( this );
358                 widgetItem->setText( qtr("Small Volume") );
359                 widgetItem->setIcon( QIcon( ":/toolbar/volume-medium" ) );
360                 widgetItem->setData( Qt::UserRole, QVariant( i ) );
361                 addItem( widgetItem );
362             }
363             continue;
364         case TIME_LABEL:
365             {
366                 QLabel *timeLabel = new QLabel( "12:42/2:12:42", this );
367                 widget = timeLabel;
368             }
369             widgetItem->setText( qtr("Time") );
370             break;
371         case MENU_BUTTONS:
372             {
373                 QWidget *discFrame = new QWidget( this );
374                 //discFrame->setLineWidth( 1 );
375                 QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
376                 discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
377
378                 QToolButton *prevSectionButton = new QToolButton( discFrame );
379                 prevSectionButton->setIcon( QIcon( ":/toolbar/dvd_prev" ) );
380                 prevSectionButton->setToolTip( qtr("Previous chapter") );
381                 discLayout->addWidget( prevSectionButton );
382
383                 QToolButton *menuButton = new QToolButton( discFrame );
384                 menuButton->setIcon( QIcon( ":/toolbar/dvd_menu" ) );
385                 menuButton->setToolTip( qtr("Go to the DVD menu") );
386                 discLayout->addWidget( menuButton );
387
388                 QToolButton *nextButton = new QToolButton( discFrame );
389                 nextButton->setIcon( QIcon( ":/toolbar/dvd_next" ) );
390                 nextButton->setToolTip( qtr("Next chapter") );
391                 discLayout->addWidget( nextButton );
392
393                 widget = discFrame;
394             }
395             widgetItem->setText( qtr("DVD menus") );
396             break;
397         case TELETEXT_BUTTONS:
398             {
399                 QWidget *telexFrame = new QWidget( this );
400                 QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
401                 telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
402
403                 QToolButton *telexOn = new QToolButton( telexFrame );
404                 telexOn->setIcon( QIcon( ":/toolbar/tv" ) );
405                 telexLayout->addWidget( telexOn );
406
407                 QToolButton *telexTransparent = new QToolButton;
408                 telexTransparent->setIcon( QIcon( ":/toolbar/tvtelx" ) );
409                 telexTransparent->setToolTip( qtr("Teletext transparency") );
410                 telexLayout->addWidget( telexTransparent );
411
412                 QSpinBox *telexPage = new QSpinBox;
413                 telexLayout->addWidget( telexPage );
414
415                 widget = telexFrame;
416             }
417             widgetItem->setText( qtr("Teletext") );
418             break;
419         case ADVANCED_CONTROLLER:
420             {
421                 AdvControlsWidget *advControls = new AdvControlsWidget( p_intf, this );
422                 widget = advControls;
423             }
424             widgetItem->setText( qtr("Advanced Buttons") );
425             break;
426         case PLAYBACK_BUTTONS:
427             {
428                 widget = new QWidget;
429                 DeckButtonsLayout *layout = new DeckButtonsLayout( widget );
430                 BrowseButton *prev = new BrowseButton( widget, BrowseButton::Backward );
431                 BrowseButton *next = new BrowseButton( widget );
432                 RoundButton *play = new RoundButton( widget );
433                 layout->setBackwardButton( prev );
434                 layout->setForwardButton( next );
435                 layout->setRoundButton( play );
436             }
437             break;
438         default:
439             msg_Warn( p_intf, "This should not happen %i", i );
440             break;
441         }
442
443         if( widget == NULL ) continue;
444
445
446         widgetItem->setIcon( QIcon( QPixmap::grabWidget( widget ) ) );
447         widget->hide();
448         widgetItem->setData( Qt::UserRole, QVariant( i ) );
449
450         addItem( widgetItem );
451         delete widget;
452     }
453 }
454
455 void WidgetListing::startDrag( Qt::DropActions /*supportedActions*/ )
456 {
457     QListWidgetItem *item = currentItem();
458
459     QByteArray itemData;
460     QDataStream dataStream( &itemData, QIODevice::WriteOnly );
461
462     int i_type = item->data( Qt::UserRole ).toInt();
463     int i_option = parent->getOptions();
464     dataStream << i_type << i_option;
465
466     /* Create a new dragging event */
467     QDrag *drag = new QDrag( this );
468
469     /* With correct mimedata */
470     QMimeData *mimeData = new QMimeData;
471     mimeData->setData( "vlc/button-bar", itemData );
472     drag->setMimeData( mimeData );
473
474     /* And correct pixmap */
475     QPixmap aPixmap = item->icon().pixmap( QSize( 22, 22 ) );
476     drag->setPixmap( aPixmap );
477     drag->setHotSpot( QPoint( 20, 20 ) );
478
479     /* We want to keep a copy */
480     drag->exec( Qt::CopyAction | Qt::MoveAction );
481 }
482
483 /*
484  * The special controller with drag'n drop abilities.
485  * We don't do this in the main controller, since we don't want the OverHead
486  * to propagate there too
487  */
488 DroppingController::DroppingController( intf_thread_t *_p_intf,
489                                         const QString& line,
490                                         QWidget *_parent )
491                    : AbstractController( _p_intf, _parent )
492 {
493     RTL_UNAFFECTED_WIDGET
494     rubberband = NULL;
495     b_draging = false;
496     setAcceptDrops( true );
497     controlLayout = new QHBoxLayout( this );
498     controlLayout->setSpacing( 5 );
499     controlLayout->setMargin( 0 );
500     setFrameShape( QFrame::StyledPanel );
501     setFrameShadow( QFrame::Raised );
502
503     parseAndCreate( line, controlLayout );
504 }
505
506 void DroppingController::resetLine( const QString& line )
507 {
508     hide();
509     QLayoutItem *child;
510     while( (child = controlLayout->takeAt( 0 ) ) != 0 )
511     {
512         child->widget()->hide();
513         delete child;
514     }
515
516     parseAndCreate( line, controlLayout );
517     show();
518 }
519
520 /* Overloading the AbstractController one, because we don't manage the
521    Spacing items in the same ways */
522 void DroppingController::createAndAddWidget( QBoxLayout *controlLayout,
523                                              int i_index,
524                                              buttonType_e i_type,
525                                              int i_option )
526 {
527     doubleInt *value = new doubleInt;
528     value->i_type = i_type;
529     value->i_option = i_option;
530
531     /* Special case for SPACERS, who aren't QWidgets */
532     if( i_type == WIDGET_SPACER || i_type == WIDGET_SPACER_EXTEND )
533     {
534         QLabel *label = new QLabel( this );
535         label->setPixmap( QPixmap( ":/toolbar/space" ) );
536         if( i_type == WIDGET_SPACER_EXTEND )
537         {
538             label->setSizePolicy( QSizePolicy::MinimumExpanding,
539                     QSizePolicy::Preferred );
540
541             /* Create a box around it */
542             label->setFrameStyle( QFrame::Panel | QFrame::Sunken );
543             label->setLineWidth ( 1 );
544             label->setAlignment( Qt::AlignCenter );
545         }
546         else
547             label->setSizePolicy( QSizePolicy::Fixed,
548                     QSizePolicy::Preferred );
549
550         /* Install event Filter for drag'n drop */
551         label->installEventFilter( this );
552         controlLayout->insertWidget( i_index, label );
553     }
554
555     /* Normal Widgets */
556     else
557     {
558         QWidget *widg = createWidget( i_type, i_option );
559         if( !widg ) return;
560
561         /* Install the Event Filter in order to catch the drag */
562         widg->setParent( this );
563         widg->installEventFilter( this );
564
565         /* We are in a complex widget, we need to stop events on children too */
566         if( i_type >= VOLUME && i_type < SPECIAL_MAX )
567         {
568             QList<QObject *>children = widg->children();
569
570             QObject *child;
571             foreach( child, children )
572             {
573                 QWidget *childWidg;
574                 if( ( childWidg = qobject_cast<QWidget *>( child ) ) )
575                 {
576                     child->installEventFilter( this );
577                     childWidg->setEnabled( true );
578                 }
579             }
580
581             /* Decorating the frames when possible */
582             QFrame *frame;
583             if( i_type >= MENU_BUTTONS  /* Don't bother to check for volume */
584                 && ( frame = qobject_cast<QFrame *>( widg ) ) != NULL )
585             {
586                 frame->setFrameStyle( QFrame::Panel | QFrame::Raised );
587                 frame->setLineWidth ( 1 );
588             }
589         }
590
591         /* Some Widgets are deactivated at creation */
592         widg->setEnabled( true );
593         widg->show();
594         controlLayout->insertWidget( i_index, widg );
595     }
596
597     /* QList and QBoxLayout don't act the same with insert() */
598     if( i_index < 0 ) i_index = controlLayout->count() - 1;
599
600     widgetList.insert( i_index, value );
601 }
602
603 DroppingController::~DroppingController()
604 {
605     qDeleteAll( widgetList );
606     widgetList.clear();
607 }
608
609 QString DroppingController::getValue()
610 {
611     QString qs = "";
612
613     for( int i = 0; i < controlLayout->count(); i++ )
614     {
615         doubleInt *dI = widgetList.at( i );
616         assert( dI );
617
618         qs.append( QString::number( dI->i_type ) );
619         if( dI->i_option ) qs.append( "-" + QString::number( dI->i_option ) );
620         qs.append( ';' );
621     }
622     return qs;
623 }
624
625 void DroppingController::dragEnterEvent( QDragEnterEvent * event )
626 {
627     if( event->mimeData()->hasFormat( "vlc/button-bar" ) )
628         event->accept();
629     else
630         event->ignore();
631 }
632
633 void DroppingController::dragMoveEvent( QDragMoveEvent *event )
634 {
635     QPoint origin = event->pos();
636
637     int i_pos = getParentPosInLayout( origin );
638     bool b_end = false;
639
640     /* Both sides of the frame */
641     if( i_pos == -1 )
642     {
643         if( rubberband ) rubberband->hide();
644         return;
645     }
646
647     /* Last item is special because of underlying items */
648     if( i_pos >= controlLayout->count() )
649     {
650         i_pos--;
651         b_end = true;
652     }
653
654     /* Query the underlying item for size && middles */
655     QLayoutItem *tempItem = controlLayout->itemAt( i_pos ); assert( tempItem );
656     QWidget *temp = tempItem->widget(); assert( temp );
657
658     /* Position assignment */
659     origin.ry() = 0;
660     origin.rx() = temp->x() - 2;
661
662     if( b_end ) origin.rx() += temp->width();
663
664     if( !rubberband )
665         rubberband = new QRubberBand( QRubberBand::Line, this );
666     rubberband->setGeometry( origin.x(), origin.y(), 4, height() );
667     rubberband->show();
668 }
669
670 inline int DroppingController::getParentPosInLayout( QPoint point )
671 {
672     point.ry() = height() / 2 ;
673     QPoint origin = mapToGlobal ( point );
674
675     QWidget *tempWidg = QApplication::widgetAt( origin );
676     if( tempWidg == NULL )
677         return -1;
678
679     int i = controlLayout->indexOf( tempWidg );
680     if( i == -1 )
681     {
682         i = controlLayout->indexOf( tempWidg->parentWidget() );
683         tempWidg = tempWidg->parentWidget();
684     }
685
686     /* Return the nearest position */
687     if( ( point.x() - tempWidg->x()  > tempWidg->width() / 2 ) && i != -1 )
688         i++;
689
690     //    msg_Dbg( p_intf, "%i", i);
691     return i;
692 }
693
694 void DroppingController::dropEvent( QDropEvent *event )
695 {
696     int i = getParentPosInLayout( event->pos() );
697
698     /* Workaround: do not let the item move to its current
699        position + 1 as it breaks the widgetList */
700     if ( i - 1 == i_dragIndex )
701         --i;
702
703     QByteArray data = event->mimeData()->data( "vlc/button-bar" );
704     QDataStream dataStream(&data, QIODevice::ReadOnly);
705
706     int i_option = 0, i_type = 0;
707     dataStream >> i_type >> i_option;
708
709     createAndAddWidget( controlLayout, i, (buttonType_e)i_type, i_option );
710
711     /* Hide by precaution, you don't exactly know what could have happened in
712        between */
713     if( rubberband ) rubberband->hide();
714 }
715
716 void DroppingController::dragLeaveEvent ( QDragLeaveEvent * event )
717 {
718     if( rubberband ) rubberband->hide();
719     event->accept();
720 }
721
722 /**
723  * Overloading doAction to block any action
724  **/
725 void DroppingController::doAction( int i )
726 {
727     VLC_UNUSED( i );
728 }
729
730 bool DroppingController::eventFilter( QObject *obj, QEvent *event )
731 {
732     switch( event->type() )
733     {
734         case QEvent::MouseButtonPress:
735             b_draging = true;
736             return true;
737         case QEvent::MouseButtonRelease:
738             b_draging = false;
739             return true;
740         case QEvent::MouseMove:
741             {
742             if( !b_draging ) return true;
743             QWidget *widg = static_cast<QWidget*>(obj);
744
745             QByteArray itemData;
746             QDataStream dataStream( &itemData, QIODevice::WriteOnly );
747
748             int i = -1;
749             i = controlLayout->indexOf( widg );
750             if( i == -1 )
751             {
752                 i = controlLayout->indexOf( widg->parentWidget() );
753                 widg = widg->parentWidget();
754                 /* NOTE: be extra-careful Now with widg access */
755             }
756
757             if( i == -1 ) return true;
758             i_dragIndex = i;
759
760             doubleInt *dI = widgetList.at( i );
761
762             int i_type = dI->i_type;
763             int i_option = dI->i_option;
764             dataStream << i_type << i_option;
765
766             /* With correct mimedata */
767             QMimeData *mimeData = new QMimeData;
768             mimeData->setData( "vlc/button-bar", itemData );
769
770             QDrag *drag = new QDrag( widg );
771             drag->setMimeData( mimeData );
772
773             /* Remove before the drag to not mess DropEvent,
774                that will createAndAddWidget */
775             widgetList.removeAt( i );
776
777             /* Start the effective drag */
778             drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction);
779             widg->hide();
780             controlLayout->removeWidget( widg );
781             b_draging = false;
782             }
783             return true;
784
785         case QEvent::MouseButtonDblClick:
786         case QEvent::EnabledChange:
787         case QEvent::Hide:
788         case QEvent::HideToParent:
789         case QEvent::Move:
790         case QEvent::ZOrderChange:
791             return true;
792         default:
793             return false;
794     }
795 }