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 }