File indexing completed on 2025-01-19 04:24:07

0001 /****************************************************************************************
0002  * Copyright (c) 2010 Daniel Faust <hessijames@gmail.com>                               *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #include "LabelGraphicsItem.h"
0018 #include "LabelOverlayButton.h"
0019 
0020 // Amarok
0021 #include "PaletteHandler.h"
0022 
0023 // KDE
0024 #include <KIconLoader>
0025 
0026 // Qt
0027 #include <QApplication>
0028 #include <QGraphicsBlurEffect>
0029 #include <QGraphicsSceneHoverEvent>
0030 #include <QGraphicsPixmapItem>
0031 #include <QGraphicsTextItem>
0032 #include <QPainter>
0033 #include <QPixmap>
0034 #include <QPropertyAnimation>
0035 
0036 
0037 LabelGraphicsItem::LabelGraphicsItem( const QString &text, qreal deltaPointSize, QGraphicsItem *parent )
0038     : QGraphicsObject( parent ),
0039     m_selected( false )
0040 {
0041     setAcceptHoverEvents( true );
0042 
0043     m_hoverColor = PaletteHandler::highlightColor( 0.7, 1.0 );
0044 
0045     m_hoverValueAnimation = new QPropertyAnimation( this, "hoverValue", this );
0046     m_hoverValueAnimation.data()->setEasingCurve( QEasingCurve::InOutQuad );
0047 
0048     m_textItem = new QGraphicsTextItem( text, this );
0049     m_textItem->setZValue( 10 );
0050     m_textItem->setPos( qRound( m_textItem->boundingRect().height() / 4 ), 0 );
0051 
0052     m_backgroundItem = new QGraphicsPixmapItem( this );
0053     m_backgroundItem->setZValue( 0 );
0054     m_backgroundItem->setOpacity( 0.7 );
0055     m_backgroundBlurEffect = new QGraphicsBlurEffect( this );
0056     m_backgroundBlurEffect->setBlurRadius( 4.0 );
0057     m_backgroundItem->setGraphicsEffect( m_backgroundBlurEffect );
0058 
0059     {
0060     KIconLoader iconLoader;
0061     m_addLabelItem = new LabelOverlayButton( this );
0062     m_addLabelItem.data()->setZValue( 20 );
0063     m_addLabelItem.data()->setPixmap( iconLoader.loadIcon( "list-add", KIconLoader::NoGroup, KIconLoader::SizeSmallMedium ) );
0064     m_addLabelItem.data()->setToolTip( i18n( "Add label" ) );
0065     m_addLabelItem.data()->setOpacity( 0.0 );
0066     m_removeLabelItem = new LabelOverlayButton( this );
0067     m_removeLabelItem.data()->setZValue( 20 );
0068     m_removeLabelItem.data()->setPixmap( iconLoader.loadIcon( "list-remove", KIconLoader::NoGroup, KIconLoader::SizeSmallMedium ) );
0069     m_removeLabelItem.data()->setToolTip( i18n( "Remove label" ) );
0070     m_removeLabelItem.data()->setOpacity( 0.0 );
0071     m_listLabelItem = new LabelOverlayButton( this );
0072     m_listLabelItem.data()->setZValue( 20 );
0073     m_listLabelItem.data()->setPixmap( iconLoader.loadIcon( "edit-find", KIconLoader::NoGroup, KIconLoader::SizeSmallMedium ) );
0074     m_listLabelItem.data()->setToolTip( i18n( "Show in Media Sources" ) );
0075     m_listLabelItem.data()->setOpacity( 0.0 );
0076     m_blacklistLabelItem = new LabelOverlayButton( this );
0077     m_blacklistLabelItem.data()->setZValue( 20 );
0078     m_blacklistLabelItem.data()->setPixmap( iconLoader.loadIcon( "flag-black", KIconLoader::NoGroup, KIconLoader::SizeSmallMedium ) );
0079     m_blacklistLabelItem.data()->setToolTip( i18n( "Add to blacklist" ) );
0080     m_blacklistLabelItem.data()->setOpacity( 0.0 );
0081     }
0082 
0083     m_addLabelAnimation = new QPropertyAnimation( m_addLabelItem.data(), "opacity", this );
0084     m_addLabelAnimation.data()->setEasingCurve( QEasingCurve::InOutQuad );
0085     m_removeLabelAnimation = new QPropertyAnimation( m_removeLabelItem.data(), "opacity", this );
0086     m_removeLabelAnimation.data()->setEasingCurve( QEasingCurve::InOutQuad );
0087     m_listLabelAnimation = new QPropertyAnimation( m_listLabelItem.data(), "opacity", this );
0088     m_listLabelAnimation.data()->setEasingCurve( QEasingCurve::InOutQuad );
0089     m_blacklistLabelAnimation = new QPropertyAnimation( m_blacklistLabelItem.data(), "opacity", this );
0090     m_blacklistLabelAnimation.data()->setEasingCurve( QEasingCurve::InOutQuad );
0091 
0092     setDeltaPointSize( deltaPointSize );
0093 }
0094 
0095 LabelGraphicsItem::~LabelGraphicsItem()
0096 {}
0097 
0098 QString
0099 LabelGraphicsItem::text()
0100 {
0101     return m_textItem->toPlainText();
0102 }
0103 
0104 void
0105 LabelGraphicsItem::setText(const QString& text)
0106 {
0107     m_textItem->setPlainText( text );
0108 }
0109 
0110 void
0111 LabelGraphicsItem::setDeltaPointSize( qreal deltaPointSize )
0112 {
0113     QFont f = qApp->font();
0114     f.setPointSize( f.pointSizeF() + deltaPointSize );
0115     f.setBold( m_selected );
0116     m_textItem->setFont( f );
0117     updateGeometry();
0118 }
0119 
0120 void
0121 LabelGraphicsItem::setSelected( bool selected )
0122 {
0123     m_selected = selected;
0124     QFont f = m_textItem->font();
0125     f.setBold( m_selected );
0126     m_textItem->setFont( f );
0127     setHoverValue( (float)isUnderMouse() );
0128     updateGeometry();
0129 }
0130 
0131 void
0132 LabelGraphicsItem::setSelectedColor( QColor color )
0133 {
0134     m_selectedColor = color;
0135     setSelected( m_selected );
0136     update();
0137 }
0138 
0139 void
0140 LabelGraphicsItem::setBackgroundColor( QColor color )
0141 {
0142     m_backgroundColor = color;
0143     update();
0144 }
0145 
0146 void
0147 LabelGraphicsItem::showBlacklistButton( bool enabled )
0148 {
0149     m_showBlacklistButton = enabled;
0150 }
0151 
0152 void
0153 LabelGraphicsItem::updateGeometry()
0154 {
0155     const QSizeF size = boundingRect().size();
0156 
0157     m_textItem->setPos( qRound( size.height() / 4 ), 0 );
0158 
0159     const qreal radius = size.height() / 4;
0160 
0161     QPixmap pixmap( size.width(), size.height() );
0162     pixmap.fill( Qt::transparent );
0163     {
0164         QPainter painter( &pixmap );
0165         painter.setRenderHint( QPainter::Antialiasing );
0166         painter.setPen( QPen(m_backgroundColor) );
0167         painter.setBrush( QBrush(m_backgroundColor) );
0168         painter.drawRoundedRect( QRectF(2,2,size.width()-4,size.height()-4), radius, radius );
0169     }
0170     m_backgroundItem->setPixmap( pixmap );
0171 
0172 //     int iconsCount = m_selected ? 2 : 3; // don't show the blacklist flag for selected labels
0173     int iconsCount = m_showBlacklistButton ? 3 : 2;
0174     const int maxHeight = size.height() * 2 / 3;
0175     // minimum space between icnos is 2 pixels (number of spaces is iconsCount - 1)
0176     int maxWidth = ( size.width() - ( iconsCount - 1 ) * 2 ) / iconsCount;
0177     // minimum icon size is 14 pixels, hide icons until the remaining icons fit
0178     while( maxWidth < 14 && iconsCount > 0 )
0179     {
0180         iconsCount--;
0181         maxWidth = ( size.width() - ( iconsCount - 1 ) * 2 ) / iconsCount;
0182     }
0183     const int iconsSize = qMin( maxHeight, maxWidth );
0184     // maximum space between icons left
0185     const int iconsSpaceA = ( size.width() - iconsSize * iconsCount ) / ( iconsCount - 1 );
0186     // optimal space
0187     const int iconsSpaceB = iconsSize / 2;
0188     const int iconsSpace = qMin( iconsSpaceA, iconsSpaceB );
0189     // if there's enough space left, start the icons at the same position as the text
0190     // align buttons left
0191 //     const int offset = qRound( qMin( ( size.width() - iconsSize * iconsCount - iconsSpace * ( iconsCount - 1 ) ) / 2, m_textItem->boundingRect().height() / 4 ) );
0192     // align buttons centered
0193     const int offset = qRound( ( size.width() - iconsSize * iconsCount - iconsSpace * ( iconsCount - 1 ) ) / 2 );
0194 
0195     m_addLabelItem.data()->setSize( iconsSize );
0196     m_addLabelItem.data()->setPos( offset, ( size.height() - iconsSize ) / 2 );
0197     m_removeLabelItem.data()->setSize( iconsSize );
0198     m_removeLabelItem.data()->setPos( offset, ( size.height() - iconsSize ) / 2 );
0199     m_listLabelItem.data()->setSize( iconsSize );
0200     m_listLabelItem.data()->setPos( offset + iconsSize + iconsSpace, ( size.height() - iconsSize ) / 2 );
0201     m_listLabelItem.data()->setEnabled( iconsCount >= 2 );
0202     m_blacklistLabelItem.data()->setSize( iconsSize );
0203     m_blacklistLabelItem.data()->setPos( offset + iconsSize * 2 + iconsSpace * 2, ( size.height() - iconsSize ) / 2 );
0204     m_blacklistLabelItem.data()->setEnabled( iconsCount >= 3 );
0205 
0206     updateHoverStatus();
0207 }
0208 
0209 void
0210 LabelGraphicsItem::updateHoverStatus()
0211 {
0212     if( m_addLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0213         m_addLabelAnimation.data()->stop();
0214     if( m_removeLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0215         m_removeLabelAnimation.data()->stop();
0216     if( m_listLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0217         m_listLabelAnimation.data()->stop();
0218     if( m_blacklistLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0219         m_blacklistLabelAnimation.data()->stop();
0220 
0221     if( isUnderMouse() )
0222     {
0223         if( m_selected )
0224         {
0225             m_addLabelItem.data()->setOpacity( 0.0 );
0226             m_removeLabelItem.data()->setOpacity( 1.0 );
0227             m_removeLabelItem.data()->updateHoverStatus();
0228         }
0229         else
0230         {
0231             m_addLabelItem.data()->setOpacity( 1.0 );
0232             m_addLabelItem.data()->updateHoverStatus();
0233             m_removeLabelItem.data()->setOpacity( 0.0 );
0234         }
0235 
0236         if( m_listLabelItem.data()->isEnabled() )
0237         {
0238             m_listLabelItem.data()->setOpacity( 1.0 );
0239             m_listLabelItem.data()->updateHoverStatus();
0240         }
0241 
0242         if( m_blacklistLabelItem.data()->isEnabled() )
0243         {
0244             m_blacklistLabelItem.data()->setOpacity( 1.0 );
0245             m_blacklistLabelItem.data()->updateHoverStatus();
0246         }
0247 
0248         setHoverValue( 1.0 );
0249     }
0250     else
0251     {
0252         m_addLabelItem.data()->setOpacity( 0.0 );
0253         m_removeLabelItem.data()->setOpacity( 0.0 );
0254         m_listLabelItem.data()->setOpacity( 0.0 );
0255         m_blacklistLabelItem.data()->setOpacity( 0.0 );
0256 
0257         setHoverValue( 0.0 );
0258     }
0259 }
0260 
0261 void
0262 LabelGraphicsItem::hoverEnterEvent( QGraphicsSceneHoverEvent *event )
0263 {
0264     Q_UNUSED( event )
0265 
0266     m_hoverValueAnimation.data()->setEndValue( 1.0 );
0267     m_hoverValueAnimation.data()->start();
0268 
0269     if( m_addLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0270         m_addLabelAnimation.data()->stop();
0271     if( m_removeLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0272         m_removeLabelAnimation.data()->stop();
0273     if( m_listLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0274         m_listLabelAnimation.data()->stop();
0275     if( m_blacklistLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0276         m_blacklistLabelAnimation.data()->stop();
0277 
0278     if( m_selected )
0279     {
0280         m_removeLabelAnimation.data()->setEndValue( 1.0 );
0281         m_removeLabelAnimation.data()->start();
0282     }
0283     else
0284     {
0285         m_addLabelAnimation.data()->setEndValue( 1.0 );
0286         m_addLabelAnimation.data()->start();
0287     }
0288     
0289     if( m_listLabelItem.data()->isEnabled() )
0290     {
0291         m_listLabelAnimation.data()->setEndValue( 1.0 );
0292         m_listLabelAnimation.data()->start();
0293     }
0294 
0295     if( m_blacklistLabelItem.data()->isEnabled() )
0296     {
0297         m_blacklistLabelAnimation.data()->setEndValue( 1.0 );
0298         m_blacklistLabelAnimation.data()->start();
0299     }
0300     
0301     update();
0302 }
0303 
0304 void
0305 LabelGraphicsItem::hoverLeaveEvent( QGraphicsSceneHoverEvent *event )
0306 {
0307     Q_UNUSED( event )
0308     
0309     if( m_addLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0310         m_addLabelAnimation.data()->stop();
0311     if( m_removeLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0312         m_removeLabelAnimation.data()->stop();
0313     if( m_listLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0314         m_listLabelAnimation.data()->stop();
0315     if( m_blacklistLabelAnimation.data()->state() != QAbstractAnimation::Stopped )
0316         m_blacklistLabelAnimation.data()->stop();
0317 
0318     if( m_selected )
0319     {
0320         m_removeLabelAnimation.data()->setEndValue( 0.0 );
0321         m_removeLabelAnimation.data()->start();
0322     }
0323     else
0324     {
0325         m_addLabelAnimation.data()->setEndValue( 0.0 );
0326         m_addLabelAnimation.data()->start();
0327     }
0328 
0329     if( m_listLabelItem.data()->isEnabled() )
0330     {
0331         m_listLabelAnimation.data()->setEndValue( 0.0 );
0332         m_listLabelAnimation.data()->start();
0333     }
0334 
0335     if( m_blacklistLabelItem.data()->isEnabled() )
0336     {
0337         m_blacklistLabelAnimation.data()->setEndValue( 0.0 );
0338         m_blacklistLabelAnimation.data()->start();
0339     }
0340 
0341     m_hoverValueAnimation.data()->setEndValue( 0.0 );
0342     m_hoverValueAnimation.data()->start();
0343     
0344     update();
0345 }
0346 
0347 void
0348 LabelGraphicsItem::mousePressEvent( QGraphicsSceneMouseEvent *event )
0349 {
0350     if( m_addLabelItem.data()->boundingRect().contains( mapToItem( m_addLabelItem.data(), event->pos() ) ) ||
0351         m_removeLabelItem.data()->boundingRect().contains( mapToItem( m_removeLabelItem.data(), event->pos() ) ) )
0352         emit toggled( m_textItem->toPlainText() );
0353     else if( m_listLabelItem.data()->isEnabled() && m_listLabelItem.data()->boundingRect().contains( mapToItem( m_listLabelItem.data(), event->pos() ) ) )
0354         emit list( m_textItem->toPlainText() );
0355     else if( m_blacklistLabelItem.data()->isEnabled() && m_blacklistLabelItem.data()->boundingRect().contains( mapToItem( m_blacklistLabelItem.data(), event->pos() ) ) )
0356         emit blacklisted( m_textItem->toPlainText() );
0357 }
0358 
0359 qreal
0360 LabelGraphicsItem::hoverValue()
0361 {
0362     return m_hoverValue;
0363 }
0364 
0365 void
0366 LabelGraphicsItem::setHoverValue( qreal value )
0367 {
0368     m_hoverValue = value;
0369     const QPalette p;
0370     const QColor c = p.color( QPalette::WindowText );
0371     const QColor defaultColor = m_selected ? m_selectedColor : c;
0372 
0373     const int red   = defaultColor.red()   + ( m_hoverColor.red()   - defaultColor.red()   ) * m_hoverValue;
0374     const int green = defaultColor.green() + ( m_hoverColor.green() - defaultColor.green() ) * m_hoverValue;
0375     const int blue  = defaultColor.blue()  + ( m_hoverColor.blue()  - defaultColor.blue()  ) * m_hoverValue;
0376 
0377     m_textItem->setDefaultTextColor( QColor( red, green, blue ) );
0378 }
0379 
0380 QRectF
0381 LabelGraphicsItem::boundingRect() const
0382 {
0383     QRectF rect = m_textItem->boundingRect();
0384     rect.setWidth( rect.width() + qRound( rect.height() / 2 ) );
0385     return rect;
0386 }
0387 
0388 void
0389 LabelGraphicsItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
0390 {
0391     Q_UNUSED( painter )
0392     Q_UNUSED( option )
0393     Q_UNUSED( widget )
0394 }
0395 
0396