File indexing completed on 2024-05-19 04:48:56

0001 /***************************************************************************
0002  *   Copyright (c) 2008  Jeff Mitchell <mitchell@kde.org>                  *
0003  *                                                                         *
0004  *   This program is free software; you can redistribute it and/or modify  *
0005  *   it under the terms of the GNU General Public License as published by  *
0006  *   the Free Software Foundation; either version 2 of the License, or     *
0007  *   (at your option) any later version.                                   *
0008  *                                                                         *
0009  *   This program is distributed in the hope that it will be useful,       *
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0012  *   GNU General Public License for more details.                          *
0013  *                                                                         *
0014  *   You should have received a copy of the GNU General Public License     *
0015  *   along with this program; if not, write to the                         *
0016  *   Free Software Foundation, Inc.,                                       *
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0018  ***************************************************************************/
0019 
0020 #include "PopupDropper.h"
0021 #include "PopupDropper_p.h"
0022 #include "PopupDropperItem.h"
0023 
0024 #include <QtDebug>
0025 #include <QGraphicsItem>
0026 #include <QGraphicsScene>
0027 #include <QSvgRenderer>
0028 #include <QAction>
0029 #include <QMenu>
0030 #include <QPalette>
0031 #include <QTimeLine>
0032 #include <QWidget>
0033 
0034 PopupDropperPrivate::PopupDropperPrivate( PopupDropper* parent, bool sa, QWidget* widget )
0035     : QObject( parent )
0036     , standalone( sa )
0037     , widget( widget )
0038     , scene( nullptr )
0039     , view( nullptr )
0040     , fade( PopupDropper::FadeInOut )
0041     , fadeHideTimer()
0042     , fadeShowTimer()
0043     , fadeInTime( 800 )
0044     , fadeOutTime( 300 )
0045     , deleteTimer()
0046     , deleteTimeout( 1000 )
0047     , frameMax( 30 )
0048     , windowColor( 0, 0, 0, 64 )
0049     , windowBackgroundBrush()
0050     , baseTextColor( Qt::white )
0051     , hoveredTextColor( Qt::blue )
0052     , hoveredBorderPen()
0053     , hoveredFillBrush()
0054     , file()
0055     , sharedRenderer( nullptr )
0056     , horizontalOffset( 30 )
0057     , pdiItems()
0058     , overlayLevel( 1 )
0059     , entered( false )
0060     , submenuMap()
0061     , submenu( false )
0062     , allItems()
0063     , quitOnDragLeave( false )
0064     , onTop( true )
0065     , widgetRect()
0066     , queuedHide( false )
0067     , q( parent )
0068 {
0069     if( widget )
0070         widgetRect = widget->rect();
0071 
0072     windowBackgroundBrush.setColor( windowColor );
0073     hoveredBorderPen.setColor( Qt::blue );
0074     hoveredBorderPen.setWidth( 2 );
0075     hoveredBorderPen.setStyle( Qt::SolidLine );
0076     QColor hoveredFillColor = QColor( Qt::blue );
0077     hoveredFillColor.setAlpha( 32 );
0078     hoveredFillBrush.setColor( hoveredFillColor );
0079     hoveredFillBrush.setStyle( Qt::SolidPattern );
0080     scene = new QGraphicsScene( ( sa ? nullptr : parent ) );
0081     view = new PopupDropperView( parent, scene, ( sa ? nullptr : widget ) );
0082     //qDebug() << "on create, view size = " << view->size();
0083     deleteTimer.setSingleShot( true );
0084     fadeHideTimer.setDirection( QTimeLine::Backward );
0085     connect( &fadeHideTimer, &QTimeLine::frameChanged, this, &PopupDropperPrivate::fadeHideTimerFrameChanged );
0086     connect( &fadeShowTimer, &QTimeLine::frameChanged, this, &PopupDropperPrivate::fadeShowTimerFrameChanged );
0087     connect( &fadeHideTimer, &QTimeLine::finished, this, &PopupDropperPrivate::fadeHideTimerFinished );
0088     connect( &fadeShowTimer, &QTimeLine::finished, this, &PopupDropperPrivate::fadeShowTimerFinished );
0089     connect( &deleteTimer, &QTimer::timeout, this, &PopupDropperPrivate::deleteTimerFinished );
0090 }
0091 
0092 PopupDropperPrivate::~PopupDropperPrivate()
0093 {
0094 }
0095 
0096 void PopupDropperPrivate::newSceneView( PopupDropper* pud )
0097 {
0098     scene->deleteLater();
0099     scene = new QGraphicsScene( pud );
0100     //qDebug() << "new scene width in newSceneView = " << scene->width();
0101     view = new PopupDropperView( pud, scene, widget );
0102     //qDebug() << "on create, view size = " << view->size();
0103 }
0104 
0105 void PopupDropperPrivate::setParent( QObject* parent )
0106 {
0107     QObject::setParent( parent );
0108     q = static_cast<PopupDropper*>( parent );
0109 }
0110 
0111 void PopupDropperPrivate::fadeHideTimerFrameChanged( int frame ) //SLOT
0112 {
0113     if( fadeHideTimer.state() == QTimeLine::Running )
0114     {
0115         qreal val = ( frame * 1.0 ) / frameMax;
0116         QColor color = windowColor;
0117         int alpha = (int)( color.alpha() * val );
0118         color.setAlpha( alpha );
0119         q->setPalette( color );
0120         foreach( PopupDropperItem* pdi, pdiItems )
0121             pdi->setSubitemOpacity( val );
0122     }
0123 }
0124 
0125 void PopupDropperPrivate::fadeShowTimerFrameChanged( int frame ) //SLOT
0126 {
0127     if( fadeShowTimer.state() == QTimeLine::Running )
0128     {
0129         qreal val = ( frame * 1.0 ) / frameMax;
0130         QColor color = windowColor;
0131         int alpha = (int)( color.alpha() * val );
0132         color.setAlpha( alpha );
0133         q->setPalette( color );
0134         foreach( PopupDropperItem* pdi, pdiItems )
0135             pdi->setSubitemOpacity( val );
0136     }
0137 }
0138 
0139 void PopupDropperPrivate::fadeHideTimerFinished() //SLOT
0140 {
0141     view->hide();
0142     //qDebug() << "Emitting fadeHideFinished in d pointer " << this;
0143     Q_EMIT q->fadeHideFinished();
0144 }
0145 
0146 void PopupDropperPrivate::fadeShowTimerFinished() //SLOT
0147 {
0148     q->setPalette( windowColor ); 
0149     queuedHide = false;
0150     foreach( PopupDropperItem* pdi, pdiItems )
0151         pdi->setSubitemOpacity( 1.0 );
0152 }
0153 
0154 void PopupDropperPrivate::dragEntered()
0155 {
0156     //qDebug() << "PopupDropperPrivate::dragEntered";
0157     q->updateAllOverlays();
0158 }
0159 
0160 void PopupDropperPrivate::dragLeft()
0161 {
0162     //qDebug() << "PopupDropperPrivate::dragLeft()";
0163     //qDebug() << "PUD to be hidden or not hidden = " << q;
0164     if( view->entered() && quitOnDragLeave )
0165     {
0166         view->setAcceptDrops( false );
0167         //qDebug() << "View entered, hiding";
0168         connect( q, &PopupDropper::fadeHideFinished, q, &PopupDropper::subtractOverlay );
0169         q->hide();
0170     }
0171     q->updateAllOverlays();
0172 }
0173 
0174 void PopupDropperPrivate::startDeleteTimer()
0175 {
0176     if( deleteTimeout == 0 )
0177         return;
0178     view->setEntered( false );
0179     //qDebug() << "Starting delete timer";
0180     deleteTimer.start( deleteTimeout );
0181 }
0182 
0183 void PopupDropperPrivate::deleteTimerFinished() //SLOT
0184 {
0185     //qDebug() << "Delete Timer Finished";
0186     if( !view->entered() && quitOnDragLeave )
0187     {
0188         connect( q, &PopupDropper::fadeHideFinished, q, &PopupDropper::subtractOverlay );
0189         q->hide();
0190     }
0191 }
0192 
0193 void PopupDropperPrivate::reposItems()
0194 {
0195     qreal partitionsize, my_min, my_max;
0196     //qDebug() << "allItems.size() = " << allItems.size();
0197     int counter = 0;
0198     for( int i = 0; i < allItems.size(); i++ )
0199     {
0200         //qDebug() << "item " << i;
0201         int verticalmargin = 5;
0202         partitionsize = scene->height() / pdiItems.size(); //gives partition size...now center in this area
0203         my_min = ( counter * partitionsize ) + verticalmargin;
0204         my_max = ( ( counter + 1 ) * partitionsize ) - verticalmargin;
0205         //qDebug() << "my_min = " << my_min << ", my_max = " << my_max;
0206         PopupDropperItem* pItem = dynamic_cast<PopupDropperItem*>( allItems.at( i ) );
0207         QGraphicsLineItem* qglItem = nullptr;
0208         if( pItem )
0209         {
0210             pItem->setPopupDropper( q ); //safety
0211             //qDebug() << "item " << i << " is a PDI ";
0212             //If the svgElementRect is too high, resize it to fit
0213             pItem->svgElementRect().setHeight( my_max - my_min - ( 2 * verticalmargin ) );
0214             pItem->setPos( 0, my_min );
0215             pItem->borderRectItem()->setRect( 0 - pItem->borderWidth(), 0, scene->width() + 2*pItem->borderWidth(), my_max - my_min );
0216             pItem->scaleAndReposSvgItem();
0217             pItem->reposTextItem();
0218             pItem->reposHoverFillRects();
0219             pItem->update();
0220             //qDebug() << "size of view frame = " << view->size();
0221             ++counter;
0222         }
0223         else if( ( qglItem = dynamic_cast<QGraphicsLineItem*>( allItems.at( i ) ) ) )
0224         {
0225             //qDebug() << "item " << i << " is a QGLI";
0226             qglItem->setLine( horizontalOffset, (my_max-partitionsize), scene->width() - horizontalOffset, (my_max-partitionsize) );
0227         }
0228     }
0229 }
0230 
0231 bool PopupDropperPrivate::amIOnTop( PopupDropperView* pdv )
0232 {
0233     if( onTop && pdv == view )
0234         return true;
0235     return false;
0236 }
0237 
0238 //////////////////////////////////////////////////////////////
0239 
0240 PopupDropper::PopupDropper( QWidget *parent, bool standalone )
0241     : QObject( parent )
0242     , d( new PopupDropperPrivate( this, standalone, parent ) )
0243 {
0244     if( !parent )
0245     {
0246         parent = d->view;
0247         d->widget = parent;
0248     }
0249     QObject::setParent( parent );
0250     initOverlay( parent );
0251     setColors( d->windowColor, d->baseTextColor, d->hoveredTextColor, d->hoveredBorderPen.color(), d->hoveredFillBrush.color() );
0252     d->sharedRenderer = new QSvgRenderer( this );
0253     d->overlayLevel = 1;
0254     //qDebug() << "Popup Dropper created!";
0255 }
0256 
0257 PopupDropper::~PopupDropper()
0258 {
0259     //qDebug() << "Popup Dropper destroyed!";
0260 }
0261 
0262 int PopupDropper::overlayLevel() const
0263 {
0264     return d->overlayLevel;
0265 }
0266 
0267 void PopupDropper::initOverlay( QWidget* parent, PopupDropperPrivate* priv )
0268 {
0269     PopupDropperPrivate *pdp = priv ? priv : d;
0270     //qDebug() << "PUD Overlay being created, d pointer is " << d;
0271     pdp->scene->setSceneRect( QRectF( parent->rect() ) );
0272     //qDebug() << "Scene width = " << pdp->scene->width();
0273     pdp->scene->setItemIndexMethod( QGraphicsScene::NoIndex );
0274     pdp->view->setFixedSize( parent->size() );
0275     pdp->view->setLineWidth( 0 );
0276     pdp->view->setFrameStyle( QFrame::NoFrame );
0277     pdp->view->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
0278     pdp->view->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
0279     pdp->view->setBackgroundRole( QPalette::Window );
0280     pdp->view->setAutoFillBackground( true );
0281     pdp->fadeHideTimer.setFrameRange( 0, pdp->frameMax );
0282     pdp->fadeHideTimer.setUpdateInterval( 20 ); // 50 fps
0283     pdp->fadeShowTimer.setFrameRange( 0, pdp->frameMax );
0284     pdp->fadeShowTimer.setUpdateInterval( 20 ); // 50 fps
0285 }
0286 
0287 void PopupDropper::addOverlay()
0288 {
0289     d->onTop = false;
0290     m_viewStack.push( d );
0291     PopupDropperPrivate* old_d = d;
0292     d = new PopupDropperPrivate( this, false, old_d->view );
0293     d->sharedRenderer = old_d->sharedRenderer;
0294     //qDebug() << "Adding overlay: ";
0295     initOverlay( old_d->view );
0296     setColors( d->windowColor, d->baseTextColor, d->hoveredTextColor, d->hoveredBorderPen.color(), d->hoveredFillBrush.color() );
0297     d->quitOnDragLeave = true;
0298     d->overlayLevel = old_d->overlayLevel + 1;
0299     old_d->view->deactivateHover();
0300 }
0301 
0302 //note: Used when activating a submenu; does not set default colors, should have done that when creating submenu
0303 void PopupDropper::addOverlay( PopupDropperPrivate* newD )
0304 {
0305     d->onTop = false;
0306     //qDebug() << "right before push, m_viewStack.size() is " << m_viewStack.size();
0307     m_viewStack.push( d );
0308     //qDebug() << "right after push, m_viewStack.size() is " << m_viewStack.size();
0309     PopupDropperPrivate* old_d = d;
0310     d = newD;
0311     d->onTop = true;
0312     d->sharedRenderer = old_d->sharedRenderer;
0313     d->quitOnDragLeave = true;
0314     d->overlayLevel = old_d->overlayLevel + 1;
0315     //qDebug() << "new d d->overlayLevel = " << d->overlayLevel;
0316     //qDebug() << "in PopupDropper " << this;
0317 }
0318 
0319 //NOTE: just like you have to show the overlay when adding, this function does not hide the overlay; you must do that yourself
0320 //with hide() (which will hide just one level)
0321 bool PopupDropper::subtractOverlay()
0322 {
0323     //qDebug() << "subtractOverlay, with d pointer " << d;
0324     disconnect( this, &PopupDropper::fadeHideFinished, this, &PopupDropper::subtractOverlay );
0325     while( !isHidden() && d->fadeHideTimer.state() == QTimeLine::Running )
0326     {
0327         //qDebug() << "singleshotting subtractOverlay";
0328         QTimer::singleShot( 0, this, &PopupDropper::subtractOverlay );
0329         return false;
0330     }
0331     //qDebug() << "in PopupDropper " << this;
0332     //qDebug() << "overlay d->overlayLevel = " << d->overlayLevel;
0333     if( d->overlayLevel == 1 )
0334         return false;
0335     PopupDropper::Fading currFadeValue = d->fade;
0336     d->fade = PopupDropper::NoFade;
0337     d->onTop = false;
0338     PopupDropperPrivate* old_d = d;
0339     //qDebug() << "right before pop, m_viewStack.size() is " << m_viewStack.size();
0340     d = m_viewStack.pop();
0341     d->onTop = true;
0342     if( !old_d->submenu )
0343     {
0344         //qDebug() << "not submenu, deleting";
0345         old_d->deleteLater();
0346     }
0347     else
0348     {
0349         foreach( QGraphicsItem* item, old_d->pdiItems )
0350             old_d->scene->removeItem( item );
0351         //qDebug() << "not deleting, submenu";
0352         old_d->fade = currFadeValue;
0353         old_d->view->resetView();
0354     }
0355     d->startDeleteTimer();
0356     return true;
0357 }
0358 
0359 PopupDropperItem* PopupDropper::addSubmenu( PopupDropper** pd, const QString &text )
0360 {
0361     //qDebug() << "addSubmenu, this is " << this << " and passed-in PopupDropper is " << (*pd);
0362     if( !(*pd) )
0363     {
0364         qWarning() << "Did not pass in a valid PUD!";
0365         return nullptr;
0366     }
0367     PopupDropperPrivate* newD = (*pd)->d;
0368     newD->submenu = true;
0369     newD->widget = d->widget;
0370     newD->setParent( this );
0371     foreach( PopupDropperItem* item, newD->pdiItems )
0372         newD->scene->removeItem( item );
0373     newD->newSceneView( this );
0374     initOverlay( d->widget, newD );
0375     PopupDropperItem* pdi = new PopupDropperItem();
0376 
0377     QAction* action = new QAction( text, this );
0378 
0379     connect( action, &QAction::hovered, this, &PopupDropper::activateSubmenu );
0380     pdi->setAction( action );
0381     pdi->setSubmenuTrigger( true );
0382     pdi->setHoverIndicatorShowStyle( PopupDropperItem::OnHover );
0383     d->submenuMap[action] = newD;
0384     delete (*pd);
0385     (*pd) = nullptr;
0386     foreach( PopupDropperItem* item, newD->pdiItems )
0387         item->setPopupDropper( this );
0388     //qDebug() << "d->submenuMap[pda] = " << d->submenuMap[pda];
0389     addItem( pdi );
0390     return pdi;
0391 }
0392 
0393 void PopupDropper::activateSubmenu()
0394 {
0395     //qDebug() << "Sender is " << QObject::sender();
0396     if( isHidden() || d->fadeHideTimer.state() == QTimeLine::Running )
0397         return;
0398     PopupDropperPrivate* oldd = d;
0399     addOverlay( d->submenuMap[static_cast<QAction*>(QObject::sender())] );
0400     //qDebug() << "d->pdiItems.size() = " << d->pdiItems.size() << " for " << d;
0401     foreach( PopupDropperItem* item, d->pdiItems )
0402         addItem( item, false, false );
0403     oldd->view->deactivateHover();
0404     show();
0405 }
0406 
0407 bool PopupDropper::addMenu( const QMenu *menu )
0408 {
0409     Q_UNUSED(menu)
0410     if( !menu )
0411         return false;
0412         
0413     if( menu->actions().isEmpty() )
0414         return true;
0415 
0416     PopupDropperItem *pdi = nullptr;
0417     foreach( QAction *action, menu->actions() )
0418     {
0419         if( !action->menu() )
0420         {
0421             pdi = new PopupDropperItem();
0422             pdi->setAction( action );
0423             addItem( pdi );
0424         }
0425         else
0426         {
0427             PopupDropper *pd = new PopupDropper( nullptr );
0428             bool success = pd->addMenu( action->menu() );
0429             if( success )
0430                 pdi = addSubmenu( &pd, action->text() );
0431         }
0432         pdi = nullptr;
0433     }
0434     
0435     return true;
0436 }
0437 
0438 bool PopupDropper::standalone() const
0439 {
0440     return d->standalone;
0441 }
0442 
0443 void PopupDropper::show()
0444 {
0445     if( !d->sharedRenderer )
0446     {
0447         //qDebug() << "No shared renderer set!";
0448         return;
0449     }
0450     if( d->widget && d->widget->rect() != d->widgetRect )
0451     {
0452         d->widgetRect = d->widget->rect();
0453         d->scene->setSceneRect( d->widget->rect() );
0454         d->view->setFixedSize( d->widget->size() );
0455         update();
0456     }
0457     //qDebug() << "Showing PopupDropper";
0458     d->fadeShowTimer.stop();
0459     if( ( d->fade == PopupDropper::FadeIn || d->fade == PopupDropper::FadeInOut ) && d->fadeInTime > 0 )
0460     {
0461         //qDebug() << "Animating!";
0462         d->fadeShowTimer.setDuration( d->fadeInTime );
0463         d->fadeShowTimer.setCurrentTime( 0 );
0464         d->fadeShowTimer.setEasingCurve( QEasingCurve::OutCurve );
0465         QColor color = d->windowColor;
0466         color.setAlpha( 0 );
0467         setPalette( color );
0468         foreach( PopupDropperItem* pdi, d->pdiItems )
0469             pdi->setSubitemOpacity( 0.0 );
0470         d->fadeShowTimer.start();
0471         //qDebug() << "Timer started";
0472     }
0473     d->view->show();
0474 }
0475 
0476 void PopupDropper::showAllOverlays()
0477 {
0478     show();
0479     for( int i = m_viewStack.size() - 1; i >= 0; --i )
0480     {
0481         PopupDropperPrivate* pdi = m_viewStack.at( i );
0482         if( pdi != d )
0483             d->view->show();
0484     }
0485 }
0486 
0487 //returns immediately! 
0488 void PopupDropper::hide()
0489 {
0490     //qDebug() << "PopupDropper::hide entered, d pointer is = " << d;
0491 
0492     //if hide is called and the view is already hidden, it's likely spurious
0493     if( isHidden() )
0494     {
0495         //qDebug() << "ishidden, returning";
0496         return;
0497     }
0498 
0499     //queuedHide is to make sure that fadeShowTimerFinished executes before this next hide()
0500     if( d->fadeShowTimer.state() == QTimeLine::Running )
0501     {
0502         //qDebug() << "show timer running, queueing hide";
0503         d->fadeShowTimer.stop();
0504         d->queuedHide = true;
0505         QTimer::singleShot( 0, d, &PopupDropperPrivate::fadeShowTimerFinished );
0506         QTimer::singleShot( 0, this, &PopupDropper::hide );
0507         return;
0508     }
0509 
0510     //queuedHide will be set to false from fadeShowTimerFinished...so if this came up first,
0511     //then wait
0512     if( d->fadeHideTimer.state() == QTimeLine::Running || d->queuedHide )
0513     {
0514         //qDebug() << "hide timer running or queued hide";
0515         QTimer::singleShot( 0, this, &PopupDropper::hide );
0516         return;
0517     }
0518 
0519     if( ( d->fade == PopupDropper::FadeOut || d->fade == PopupDropper::FadeInOut ) && d->fadeOutTime > 0 )
0520     {
0521         //qDebug() << "Starting fade out";
0522         d->fadeHideTimer.setDuration( d->fadeOutTime );
0523         d->fadeHideTimer.setEasingCurve( QEasingCurve::Linear );
0524         d->fadeHideTimer.start();
0525         //qDebug() << "Timer started";
0526         return;
0527     }
0528     else  //time is zero, or no fade
0529     {
0530         //qDebug() << "time is zero, or no fade";
0531         QTimer::singleShot( 0, d, &PopupDropperPrivate::fadeHideTimerFinished );
0532         return;
0533     }
0534 }
0535 
0536 void PopupDropper::hideAllOverlays()
0537 {
0538     //qDebug() << "Entered hideAllOverlays";
0539     connect( this, &PopupDropper::fadeHideFinished, this, &PopupDropper::slotHideAllOverlays );
0540     hide();
0541     //qDebug() << "Leaving hideAllOverlays";
0542 }
0543 
0544 void PopupDropper::slotHideAllOverlays()
0545 {
0546     //qDebug() << "Entered slotHideAllOverlays()";
0547     disconnect( this, &PopupDropper::fadeHideFinished, this, &PopupDropper::slotHideAllOverlays );
0548     //qDebug() << "m_viewStack.size() = " << m_viewStack.size();
0549     for( int i = m_viewStack.size() - 1; i >= 0; --i )
0550     {
0551         PopupDropperPrivate* pdp = m_viewStack.at( i );
0552         //qDebug() << "checking pdp = " << (QObject*)pdp << ", d is " << (QObject*)d;
0553         if( pdp != d )
0554             pdp->view->hide();
0555     }
0556     //qDebug() << "Leaving slotHideAllOverlays";
0557 }
0558 
0559 void PopupDropper::update()
0560 {
0561     d->reposItems();
0562     d->view->update();
0563 }
0564 
0565 void PopupDropper::updateAllOverlays()
0566 {
0567     for( int i = m_viewStack.size() - 1; i >= 0; --i )
0568     {
0569         PopupDropperPrivate* pdp = m_viewStack.at( i );
0570         pdp->view->update();
0571     }
0572     d->view->update();
0573 }
0574 
0575 bool PopupDropper::isHidden() const
0576 {
0577     return d->view->isHidden();
0578 }
0579 
0580 void PopupDropper::clear()
0581 {
0582     while( !isHidden() && d->fadeHideTimer.state() == QTimeLine::Running )
0583     {
0584         QTimer::singleShot(0, this, &PopupDropper::clear );
0585         return;
0586     }
0587     //qDebug() << "Clear happening!";
0588 //     disconnect( this, 0, this, &PopupDropper::clear ); Unused at this point.
0589     do
0590     {
0591         foreach( QGraphicsItem* item, d->allItems )
0592         {
0593             if( dynamic_cast<PopupDropperItem*>(item) )
0594             {
0595                 if( dynamic_cast<PopupDropperItem*>(item)->isSubmenuTrigger() )
0596                 {
0597                     //qDebug() << "Disconnecting action";
0598                     disconnect( dynamic_cast<PopupDropperItem*>(item)->action(), &QAction::hovered, this, &PopupDropper::activateSubmenu );
0599                 }
0600                 dynamic_cast<PopupDropperItem*>(item)->deleteLater();
0601             }
0602             else
0603                 delete item;
0604         }
0605         d->pdiItems.clear();
0606         d->allItems.clear();
0607         //qDebug() << "Size of pdiItems is now " << d->pdiItems.size();
0608         //qDebug() << "Size of allItems is now " << d->allItems.size();
0609         d->view->hide();
0610         d->view->resetView();
0611     } while ( subtractOverlay() );
0612 }
0613 
0614 bool PopupDropper::isEmpty( bool allItems ) const
0615 {
0616     if( allItems )
0617         return d->allItems.empty();
0618     else
0619         return d->pdiItems.empty();
0620 }
0621 
0622 bool PopupDropper::quitOnDragLeave() const
0623 {
0624     return d->quitOnDragLeave;
0625 }
0626 
0627 void PopupDropper::setQuitOnDragLeave( bool quit )
0628 {
0629     d->quitOnDragLeave = quit;
0630 }
0631 
0632 int PopupDropper::fadeInTime() const
0633 {
0634     return d->fadeInTime;
0635 }
0636 
0637 void PopupDropper::setFadeInTime( const int msecs )
0638 {
0639     d->fadeInTime = msecs;
0640 }
0641 
0642 int PopupDropper::fadeOutTime() const
0643 {
0644     return d->fadeOutTime;
0645 }
0646 
0647 void PopupDropper::setFadeOutTime( const int msecs )
0648 {
0649     d->fadeOutTime = msecs;
0650 }
0651 
0652 PopupDropper::Fading PopupDropper::fading() const
0653 {
0654     return d->fade;
0655 }
0656 
0657 void PopupDropper::setFading( PopupDropper::Fading fade )
0658 {
0659     d->fade = fade;
0660 }
0661 
0662 const QTimeLine* PopupDropper::fadeHideTimer() const
0663 {
0664     return &d->fadeHideTimer;
0665 }
0666 
0667 const QTimeLine* PopupDropper::fadeShowTimer() const
0668 {
0669     return &d->fadeShowTimer;
0670 }
0671 
0672 int PopupDropper::deleteTimeout() const
0673 {
0674     return d->deleteTimeout;
0675 }
0676 
0677 void PopupDropper::setDeleteTimeout( int msecs )
0678 {
0679     d->deleteTimeout = msecs;
0680 }
0681 
0682 QColor PopupDropper::windowColor() const
0683 {
0684     return d->windowColor;
0685 }
0686 
0687 void PopupDropper::setWindowColor( const QColor &window )
0688 {
0689     d->windowColor = window;
0690     setPalette( window );
0691 }
0692 
0693 QBrush PopupDropper::windowBackgroundBrush() const
0694 {
0695     return d->windowBackgroundBrush;
0696 }
0697 
0698 void PopupDropper::setWindowBackgroundBrush( const QBrush &window )
0699 {
0700     d->windowBackgroundBrush = window;
0701     d->view->setBackgroundBrush( window );
0702 }
0703 
0704 QColor PopupDropper::baseTextColor() const
0705 {
0706     return d->baseTextColor;
0707 }
0708 
0709 void PopupDropper::setBaseTextColor( const QColor &text )
0710 {
0711     d->baseTextColor = text;
0712     foreach( PopupDropperItem *item, d->pdiItems )
0713         item->setBaseTextColor( text );
0714 }
0715 
0716 QColor PopupDropper::hoveredTextColor() const
0717 {
0718     return d->hoveredTextColor;
0719 }
0720 
0721 void PopupDropper::setHoveredTextColor( const QColor &text )
0722 {
0723     d->hoveredTextColor = text;
0724     foreach( PopupDropperItem *item, d->pdiItems )
0725         item->setHoveredTextColor( text );
0726 }
0727 
0728 QPen PopupDropper::hoveredBorderPen() const
0729 {
0730     return d->hoveredBorderPen;
0731 }
0732 
0733 void PopupDropper::setHoveredBorderPen( const QPen &border )
0734 {
0735     d->hoveredBorderPen = border;
0736     foreach( PopupDropperItem *item, d->pdiItems )
0737         item->setHoveredBorderPen( border );
0738 }
0739 
0740 QBrush PopupDropper::hoveredFillBrush() const
0741 {
0742     return d->hoveredFillBrush;
0743 }
0744 
0745 void PopupDropper::setHoveredFillBrush( const QBrush &fill )
0746 {
0747     d->hoveredFillBrush = fill;
0748     foreach( PopupDropperItem *item, d->pdiItems )
0749         item->setHoveredFillBrush( fill );
0750 }
0751 
0752 void PopupDropper::setColors( const QColor &window, const QColor &baseText, const QColor &hoveredText, const QColor &hoveredBorder, const QColor &hoveredFill )
0753 {
0754     d->windowColor = window;
0755     d->baseTextColor = baseText;
0756     d->hoveredTextColor = hoveredText;
0757     d->hoveredBorderPen.setColor( hoveredBorder );
0758     d->hoveredFillBrush.setColor( hoveredFill );
0759     setPalette( window, baseText, hoveredText, hoveredBorder, hoveredFill );
0760 }
0761 
0762 void PopupDropper::setPalette( const QColor &window )
0763 {
0764     QPalette p = d->view->palette();
0765     p.setColor( QPalette::Window, window );
0766     d->view->setPalette( p );
0767     updateAllOverlays();
0768 }
0769 
0770 void PopupDropper::setPalette( const QColor &window, const QColor &baseText, const QColor &hoveredText, const QColor &hoveredBorder, const QColor &hoveredFill )
0771 {
0772     QPalette p = d->view->palette();
0773     p.setColor( QPalette::Window, window );
0774     d->view->setPalette( p );
0775     QPen pen;
0776     QBrush brush;
0777     foreach( PopupDropperItem *item, d->pdiItems )
0778     {
0779         item->setBaseTextColor( baseText );
0780         item->setHoveredTextColor( hoveredText );
0781         pen = item->hoveredBorderPen();
0782         pen.setColor( hoveredBorder );
0783         item->setHoveredBorderPen( pen );
0784         brush = item->hoveredFillBrush();
0785         brush.setColor( hoveredFill );
0786         item->setHoveredFillBrush( brush );
0787     } 
0788     updateAllOverlays();
0789 }
0790 
0791 QString PopupDropper::windowTitle() const
0792 {
0793     return d->view->windowTitle();
0794 }
0795 
0796 void PopupDropper::setWindowTitle( const QString &title )
0797 {
0798     d->view->setWindowTitle( title );
0799     d->view->update();
0800 }
0801 
0802 QString PopupDropper::svgFile() const
0803 {
0804     return d->file;
0805 }
0806 
0807 void PopupDropper::setSvgFile( const QString &file )
0808 {
0809     if( d->sharedRenderer )
0810     {
0811         if( !d->sharedRenderer->load( file ) )
0812             qWarning() << "Could not load SVG file " << file;
0813         else
0814         {
0815             d->file = file;
0816             //qDebug() << "Loaded SVG file!";
0817         }
0818     }
0819     else
0820         qWarning() << "No shared renderer!";
0821 }
0822 
0823 QSvgRenderer* PopupDropper::svgRenderer()
0824 {
0825     return d->sharedRenderer;
0826 }
0827 
0828 void PopupDropper::setSvgRenderer( QSvgRenderer *renderer )
0829 {
0830     d->sharedRenderer = renderer;
0831 }
0832 
0833 int PopupDropper::horizontalOffset() const
0834 {
0835     return d->horizontalOffset;
0836 }
0837 
0838 void PopupDropper::setHorizontalOffset( int pixels )
0839 {
0840     d->horizontalOffset = pixels;
0841 }
0842 
0843 const QSize PopupDropper::viewSize() const
0844 {
0845     if( d && d->view )
0846         return d->view->size();
0847     else
0848         return QSize( 0, 0 );
0849 }
0850 
0851 void PopupDropper::addItem( PopupDropperItem *item, bool useSharedRenderer )
0852 {
0853     addItem( item, useSharedRenderer, true );
0854 }
0855 
0856 void PopupDropper::addItem( PopupDropperItem *item, bool useSharedRenderer, bool appendToList )
0857 {
0858     //qDebug() << "adding item";
0859     //FIXME: Make separators do something graphical instead of just ignoring them
0860     PopupDropperItem *pItem = static_cast<PopupDropperItem*>( item );
0861     if( pItem->isSeparator() )
0862         return;
0863     if( useSharedRenderer )
0864         pItem->setSharedRenderer( d->sharedRenderer );
0865     //qDebug() << "Checking appendToList";
0866     if( appendToList )
0867     {
0868         d->pdiItems.append( pItem );
0869         d->allItems.append( pItem );
0870         //qDebug() << "pdiItems list is now size " << d->pdiItems.size() << " for " << d;
0871         //qDebug() << "allItems list is now size " << d->allItems.size() << " for " << d;
0872     }
0873     if( !pItem->textItem() )
0874     {
0875         QGraphicsTextItem *textItem = new QGraphicsTextItem( pItem->text(), pItem );
0876         pItem->setTextItem( textItem );
0877         if( !pItem->customBaseTextColor() || !pItem->baseTextColor().isValid() )
0878         {
0879             pItem->setBaseTextColor( d->baseTextColor );
0880             //qDebug() << "Using PD's base text color";
0881         }
0882         else
0883         {
0884             //qDebug() << "Using the item's base text color";
0885             pItem->textItem()->setDefaultTextColor( pItem->baseTextColor() );
0886         }
0887         if( !pItem->customHoveredTextColor() )
0888             pItem->setHoveredTextColor( d->hoveredTextColor );
0889     }
0890     if( !pItem->borderRectItem() )
0891     {
0892         QGraphicsRectItem *borderRectItem = new QGraphicsRectItem( pItem );
0893         borderRectItem->setZValue( -5 );
0894         pItem->setBorderRectItem( borderRectItem );
0895         if( !pItem->customHoveredBorderPen() )
0896             pItem->setHoveredBorderPen( d->hoveredBorderPen );
0897         if( !pItem->customHoveredFillBrush() )
0898             pItem->setHoveredFillBrush( d->hoveredFillBrush );
0899     }
0900     d->reposItems();
0901     pItem->setPopupDropper( this );
0902     d->scene->addItem( pItem );
0903 }
0904 
0905 QList<PopupDropperItem*> PopupDropper::items() const
0906 {
0907     QList<PopupDropperItem*> list;
0908     foreach( PopupDropperItem *item, d->pdiItems )
0909         list.append( item );
0910 
0911     return list;
0912 }
0913 
0914 //Won't currently work for > 1 level of submenu!
0915 //TODO: Figure out a better way. (Does anything else work > 1 level?)
0916 QList<PopupDropperItem*> PopupDropper::submenuItems( const PopupDropperItem *item ) const
0917 {
0918     QList<PopupDropperItem*> list;
0919     if( !item || !item->isSubmenuTrigger() || !d->submenuMap.contains( item->action() ) )
0920         return list;
0921 
0922     PopupDropperPrivate *pdp = d->submenuMap[item->action()];
0923     list.reserve(pdp->pdiItems.count());
0924     foreach( PopupDropperItem *pdi, pdp->pdiItems )
0925         list.append( pdi );
0926 
0927     return list;
0928 }
0929 
0930 //Goes through and calls the callback on all items, including submenuItems
0931 //which can be adjusted differently by checking isSubmenuTrigger()
0932 void PopupDropper::forEachItem( void callback(void*) )
0933 {
0934     forEachItemPrivate( d, callback );
0935 }
0936 
0937 void PopupDropper::forEachItemPrivate( PopupDropperPrivate *pdp, void callback(void* item) )
0938 {
0939     foreach( PopupDropperItem *item, pdp->pdiItems )
0940         callback( item );
0941     foreach( QAction *action, pdp->submenuMap.keys() )
0942         forEachItemPrivate( pdp->submenuMap[action], callback );
0943 }
0944 
0945 void PopupDropper::addSeparator( PopupDropperItem* separator )
0946 {
0947 
0948     if( !separator )
0949     {
0950         //qDebug() << "Action is not a separator!";
0951         return;
0952     }
0953 
0954     separator->setSeparator( true );
0955 
0956     if( separator->separatorStyle() == PopupDropperItem::TextSeparator )
0957     {
0958         //qDebug() << "Separator style is text";
0959         addItem( separator );
0960     }
0961 
0962     //qDebug() << "Separator style is line";
0963     QPen linePen;
0964     if( separator && separator->hasLineSeparatorPen() )
0965         linePen = separator->lineSeparatorPen();
0966     else
0967     {
0968         linePen.setWidth( 2 );
0969         linePen.setCapStyle( Qt::RoundCap );
0970         linePen.setStyle( Qt::DotLine );
0971         linePen.setColor( QColor( 255, 255, 255 ) );
0972     }
0973 
0974     //qDebug() << "scene width = " << d->scene->width() << ", horizontalOffset = " << d->horizontalOffset;
0975     //qDebug() << "right side = " << qreal(d->scene->width() - d->horizontalOffset);
0976     QGraphicsLineItem* lineItem = new QGraphicsLineItem( 0, 0, 0, 0 );
0977     d->allItems.append( lineItem );
0978     lineItem->setPen( linePen );
0979     d->reposItems();
0980     d->scene->addItem( lineItem );
0981 }