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