File indexing completed on 2021-12-21 13:28:01

0001 /**
0002  * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org>
0003  * Copyright (c) 2008 Jeff Mitchell <kde-dev@emailgoeshere.com>
0004  * Copyright (c) 2009 Mark Kretschmann <kretschmann@kde.org>
0005  *
0006  * This program is free software; you can redistribute it and/or modify it under
0007  * the terms of the GNU General Public License as published by the Free Software
0008  * Foundation; either version 2 of the License, or (at your option) any later
0009  * version.
0010  *
0011  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0013  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License along with
0016  * this program.  If not, see <http://www.gnu.org/licenses/>.
0017  */
0018 
0019 #include "svghandler.h"
0020 #include "juk_debug.h"
0021 
0022 #include <QHash>
0023 #include <QStandardPaths>
0024 #include <QPainter>
0025 #include <QPalette>
0026 #include <QReadLocker>
0027 #include <QStringBuilder>
0028 #include <QStyleOptionSlider>
0029 #include <QSvgRenderer>
0030 #include <QWriteLocker>
0031 
0032 namespace The {
0033     static SvgHandler* s_SvgHandler_instance = 0;
0034 
0035     SvgHandler* svgHandler()
0036     {
0037         if( !s_SvgHandler_instance )
0038             s_SvgHandler_instance = new SvgHandler();
0039 
0040         return s_SvgHandler_instance;
0041     }
0042 }
0043 
0044 
0045 SvgHandler::SvgHandler( QObject* parent )
0046     : QObject( parent )
0047     , m_renderer( 0 )
0048     , m_themeFile( "juk/pics/theme.svg" )
0049 {
0050 }
0051 
0052 SvgHandler::~SvgHandler()
0053 {
0054     delete m_renderer;
0055 
0056     The::s_SvgHandler_instance = 0;
0057 }
0058 
0059 
0060 bool SvgHandler::loadSvg( const QString& name )
0061 {
0062     const QString &svgFilename =
0063         QStandardPaths::locate( QStandardPaths::GenericDataLocation, name );
0064     QSvgRenderer *renderer = new QSvgRenderer( svgFilename, this );
0065 
0066     if ( !renderer->isValid() )
0067     {
0068         delete renderer;
0069         return false;
0070     }
0071     QWriteLocker writeLocker( &m_lock );
0072 
0073     if( m_renderer )
0074         delete m_renderer;
0075 
0076     m_renderer = renderer;
0077     return true;
0078 }
0079 
0080 QSvgRenderer * SvgHandler::getRenderer()
0081 {
0082     QReadLocker readLocker( &m_lock );
0083     if( ! m_renderer )
0084     {
0085         readLocker.unlock();
0086         if( !loadSvg( m_themeFile ) )
0087         {
0088             QWriteLocker writeLocker( &m_lock );
0089             m_renderer = new QSvgRenderer( this );
0090         }
0091         readLocker.relock();
0092     }
0093     return m_renderer;
0094 }
0095 
0096 QPixmap SvgHandler::renderSvg( const QString& keyname,
0097                                int width,
0098                                int height,
0099                                const QString& element )
0100 {
0101     QString key = keyname % QChar( ':' ) % QString::number( width ) %
0102         QChar( 'x' ) % QString::number( height );
0103 
0104     QPixmap pixmap;
0105     QMap<QString, QPixmap>::const_iterator it = m_cache.constFind( key );
0106     if( it != m_cache.constEnd() )
0107     {
0108         pixmap = *it;
0109     }
0110     else
0111     {
0112         pixmap = QPixmap( width * dpr, height * dpr );
0113         pixmap.setDevicePixelRatio(dpr);
0114         pixmap.fill( Qt::transparent );
0115 
0116         QReadLocker readLocker( &m_lock );
0117         if( ! m_renderer )
0118         {
0119             readLocker.unlock();
0120             if( !loadSvg( m_themeFile ) )
0121             {
0122                 return pixmap;
0123             }
0124             readLocker.relock();
0125         }
0126 
0127         QPainter pt( &pixmap );
0128         if ( element.isEmpty() )
0129             m_renderer->render( &pt, QRectF( 0, 0, width, height ) );
0130         else {
0131             m_renderer->render( &pt, element, QRectF( 0, 0, width, height ) );
0132         }
0133 
0134         m_cache.insert( key, pixmap );
0135     }
0136 
0137     return pixmap;
0138 }
0139 
0140 void SvgHandler::reTint()
0141 {
0142     // The::svgTinter()->init();
0143     if ( !loadSvg( m_themeFile ))
0144         qCDebug(JUK_LOG) << "Unable to load theme file: " << m_themeFile;
0145     emit retinted();
0146 }
0147 
0148 QString SvgHandler::themeFile()
0149 {
0150     return m_themeFile;
0151 }
0152 
0153 QRectF SvgHandler::sliderKnobRect( const QRectF &slider, qreal percent, bool inverse ) const
0154 {
0155     if ( inverse )
0156         percent = 1.0 - percent;
0157     const int knobSize = slider.height() - 4;
0158     QRectF ret( 0, 0, knobSize, knobSize );
0159     ret.moveTo( slider.x() + qRound( ( slider.width() - knobSize ) * percent ), slider.y() + 1 );
0160     return ret;
0161 }
0162 
0163 // Experimental, using a mockup from Nuno Pinheiro (new_slider_nuno)
0164 void SvgHandler::paintCustomSlider( QPainter *p, QStyleOptionSlider *slider, qreal percentage )
0165 {
0166     qreal sliderHeight = slider->rect.height() - 6;
0167     const bool inverse = ( slider->orientation == Qt::Vertical ) ? slider->upsideDown :
0168                          ( (slider->direction == Qt::RightToLeft) != slider->upsideDown );
0169     QRectF knob = sliderKnobRect( slider->rect, percentage, inverse );
0170     QPointF pt = slider->rect.topLeft() + QPointF( 0, 2 );
0171 
0172     //debug() << "rel: " << knobRelPos << ", width: " << width << ", height:" << height << ", %: " << percentage;
0173 
0174     // Draw the slider background in 3 parts
0175 
0176     p->drawPixmap( pt, renderSvg( "progress_slider_left", sliderHeight, sliderHeight, "progress_slider_left" ) );
0177 
0178     pt.rx() += sliderHeight;
0179     QRectF midRect(pt, QSize(slider->rect.width() - sliderHeight * 2, sliderHeight) );
0180     p->drawTiledPixmap( midRect, renderSvg( "progress_slider_mid", 32, sliderHeight, "progress_slider_mid" ) );
0181 
0182     pt = midRect.topRight() + QPoint( 1, 0 );
0183     p->drawPixmap( pt, renderSvg( "progress_slider_right", sliderHeight, sliderHeight, "progress_slider_right" ) );
0184 
0185     //draw the played background.
0186 
0187     qreal playedBarHeight = sliderHeight - 6;
0188     qreal min = 0;
0189 
0190     qreal sizeOfLeftPlayed = qBound( min, inverse ? slider->rect.right() - knob.right() + 2 :
0191                                    knob.x() - 2, playedBarHeight );
0192 
0193     if( sizeOfLeftPlayed > 0 )
0194     {
0195         QPointF tl, br;
0196         if ( inverse )
0197         {
0198             tl = knob.topRight() + QPointF( -5, 5 ); // 5px x padding to avoid a "gap" between it and the top and bottom of the round knob.
0199             br = slider->rect.topRight() + QPointF( -3, 5 + playedBarHeight - 1 );
0200             QPixmap rightEnd = renderSvg( "progress_slider_played_right", playedBarHeight, playedBarHeight, "progress_slider_played_right" );
0201             p->drawPixmap( br.x() - rightEnd.width() + 1, tl.y(), rightEnd, qMax(qreal(0), rightEnd.width() - (sizeOfLeftPlayed + 3)), 0, sizeOfLeftPlayed + 3, playedBarHeight );
0202             br.rx() -= playedBarHeight;
0203         }
0204         else
0205         {
0206             tl = slider->rect.topLeft() + QPointF( 3, 5 );
0207             br = QPointF( knob.x() + 5, tl.y() + playedBarHeight - 1 );
0208             QPixmap leftEnd = renderSvg( "progress_slider_played_left", playedBarHeight, playedBarHeight, "progress_slider_played_left" );
0209             p->drawPixmap( tl.x(), tl.y(), leftEnd, 0, 0, sizeOfLeftPlayed + 3, playedBarHeight );
0210             tl.rx() += playedBarHeight;
0211         }
0212         if ( sizeOfLeftPlayed == playedBarHeight )
0213             p->drawTiledPixmap( QRectF(tl, br), renderSvg( "progress_slider_played_mid", 32, playedBarHeight, "progress_slider_played_mid" ) );
0214 
0215     }
0216 
0217     if ( slider->state & QStyle::State_Enabled )
0218     {   // Draw the knob (handle)
0219         const char *string = ( slider->activeSubControls & QStyle::SC_SliderHandle ) ?
0220                              "slider_knob_200911_active" : "slider_knob_200911";
0221         p->drawPixmap( knob.topLeft(), renderSvg( string, knob.width(), knob.height(), string ) );
0222     }
0223 }
0224 
0225 void SvgHandler::setDevicePixelRatioF(qreal dpr)
0226 {
0227     this->dpr = dpr;
0228 }