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 }