File indexing completed on 2024-05-05 04:49:26

0001 /****************************************************************************************
0002 * Copyright (c) 2009 Thomas Luebking <thomas.luebking@web.de>                          *
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 "IconButton.h"
0018 #include "SvgHandler.h"
0019 
0020 #include <QMouseEvent>
0021 #include <QPainter>
0022 #include <QSizePolicy>
0023 #include <QTimerEvent>
0024 #include <QToolBar>
0025 
0026 IconButton::IconButton( QWidget *parent ) : QWidget( parent )
0027     , m_isClick( false )
0028 {
0029     m_anim.step = 0;
0030     m_anim.timer = 0;
0031     setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
0032 
0033     // cannot use paletteChanged() from the palette handler directly since the
0034     // svg handler also watches it for retinting. So upon palette change, we are
0035     // called first and the old svg icons will be used.
0036     connect( The::svgHandler(), &SvgHandler::retinted, this, &IconButton::svgRetinted );
0037 }
0038 
0039 void IconButton::setIcon( const QImage &img, int steps )
0040 {
0041     m_anim.step = 0;
0042     m_anim.steps = steps;
0043     
0044     m_icon = img;
0045     m_oldIcon = steps ? m_buffer.image : QImage();
0046 
0047     if ( m_anim.timer )
0048         killTimer( m_anim.timer );
0049     if ( steps )
0050         m_anim.timer = startTimer( 40 );
0051     else
0052         updateIconBuffer();
0053     repaint();
0054 }
0055 
0056 
0057 void IconButton::mousePressEvent( QMouseEvent *me )
0058 {
0059     me->accept();
0060     m_isClick = true;
0061 }
0062 
0063 void IconButton::mouseReleaseEvent( QMouseEvent *me )
0064 {
0065     me->accept();
0066     if ( m_isClick && rect().contains( me->pos() ) )
0067     {
0068         m_isClick = false;
0069         Q_EMIT clicked();
0070     }
0071 }
0072 
0073 void IconButton::paintEvent( QPaintEvent * )
0074 {
0075     QPainter p(this);
0076     p.setRenderHint( QPainter::SmoothPixmapTransform );
0077     p.drawPixmap( 0, 0, width(), height(), m_buffer.pixmap );
0078     p.end();
0079 }
0080 
0081 void IconButton::svgRetinted()
0082 {
0083     reloadContent( size() );
0084 }
0085 
0086 void IconButton::resizeEvent( QResizeEvent *re )
0087 {
0088     if( width() != height() )
0089         resize( height(), height() );
0090     else
0091     {
0092         reloadContent( re->size() );
0093         QWidget::resizeEvent( re );
0094     }
0095 }
0096 
0097 QSize IconButton::sizeHint() const
0098 {
0099     if ( QToolBar *toolBar = qobject_cast<QToolBar*>( parentWidget() ) )
0100         return toolBar->iconSize();
0101 
0102     return QSize( 32, 32 );
0103 }
0104 
0105 void IconButton::timerEvent( QTimerEvent *te )
0106 {
0107     if ( te->timerId() != m_anim.timer )
0108         return;
0109 
0110     ++m_anim.step;
0111     updateIconBuffer();
0112     if ( m_anim.step >= m_anim.steps )
0113     {
0114         killTimer( m_anim.timer );
0115         m_anim.timer = 0;
0116         m_oldIcon = QImage();
0117     }
0118     repaint();
0119 }
0120 
0121 static QImage adjusted( QImage img, const QSize &sz )
0122 {
0123     QSize doublesz( sz.width()*2, sz.height()*2 );
0124     if ( img.size() == doublesz ) //double size render to have better looking high-dpi toolbar
0125         return img;
0126     QImage ret( doublesz, QImage::Format_ARGB32_Premultiplied );
0127     ret.fill( Qt::transparent );
0128     QPainter p( &ret );
0129     int xcentershift=(ret.width() - img.width()) /2;
0130     int ycentershift=(ret.height() - img.height()) /2;
0131     if(xcentershift<0)
0132         xcentershift=0;
0133     if(ycentershift<0)
0134         ycentershift=0;
0135     p.drawImage( xcentershift, ycentershift, img );
0136     p.end();
0137     return ret;
0138 }
0139 
0140 static inline QImage interpolated( const QImage &img1, const QImage &img2, int a1, int a2 )
0141 {
0142     const int a = a1 + a2;
0143     if (!a)
0144         return img1.copy();
0145 
0146     QImage img( img1.size(), img1.format() );
0147 
0148     const uchar *src[2] = { img1.bits(), img2.bits() };
0149     uchar *dst = img.bits();
0150     const int n = img.width()*img.height()*4;
0151     for ( int i = 0; i < n; ++i )
0152     {
0153         *dst = ((*src[0]*a1 + *src[1]*a2)/a) & 0xff;
0154         ++dst; ++src[0]; ++src[1];
0155     }
0156     return img;
0157 }
0158 
0159 void IconButton::updateIconBuffer()
0160 {
0161     if ( m_anim.step >= m_anim.steps )
0162         m_buffer.image = adjusted( m_icon, size() );
0163     else
0164         m_buffer.image = interpolated( adjusted( m_oldIcon, size() ), adjusted( m_icon, size() ),
0165                                        m_anim.steps - m_anim.step, m_anim.step );
0166 
0167     m_buffer.pixmap = QPixmap::fromImage( m_buffer.image );
0168 }
0169 
0170