File indexing completed on 2025-01-05 04:25:41

0001 /****************************************************************************************
0002  * Copyright (c) 2003-2005 Max Howell <max.howell@methylblue.com>                       *
0003  * Copyright (c) 2005-2013 Mark Kretschmann <kretschmann@kde.org>                       *
0004  *                                                                                      *
0005  * This program is free software; you can redistribute it and/or modify it under        *
0006  * the terms of the GNU General Public License as published by the Free Software        *
0007  * Foundation; either version 2 of the License, or (at your option) any later           *
0008  * version.                                                                             *
0009  *                                                                                      *
0010  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0011  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0012  * PARTICULAR PURPOSE. See the GNU General Pulic License for more details.              *
0013  *                                                                                      *
0014  * You should have received a copy of the GNU General Public License along with         *
0015  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0016  ****************************************************************************************/
0017 
0018 #include "BlockAnalyzer.h"
0019 
0020 #include "AnalyzerWorker.h"
0021 #include "BlockRenderer.h"
0022 #include "BlockWorker.h"
0023 #include "PaletteHandler.h"
0024 #include "core/support/Debug.h"
0025 
0026 #include <cmath>
0027 
0028 #include <QPainter>
0029 #include <QQuickWindow>
0030 #include <QScreen>
0031 #include <QSGTexture>
0032 
0033 
0034 BlockAnalyzer::BlockAnalyzer( QQuickItem *parent )
0035     : Analyzer::Base( parent )
0036     , m_columns( 0 )         //int
0037     , m_rows( 0 )            //int
0038     , m_fadeBarsPixmaps( FADE_SIZE ) //vector<QPixmap>
0039 {
0040     setTextureFollowsItemSize( true );
0041     setObjectName( "Blocky" );
0042 
0043     m_columnWidth = config().readEntry( "columnWidth", 4 );
0044     m_fallSpeed = (FallSpeed) config().readEntry( "fallSpeed", (int) Medium );
0045     m_showFadebars = config().readEntry( "showFadebars", true );
0046 
0047     paletteChange( The::paletteHandler()->palette() );
0048     connect( The::paletteHandler(), &PaletteHandler::newPalette, this, &BlockAnalyzer::paletteChange );
0049     connect( this, &QQuickItem::windowChanged, this, &BlockAnalyzer::newWindow );
0050 }
0051 
0052 QQuickFramebufferObject::Renderer*
0053 BlockAnalyzer::createRenderer() const
0054 {
0055     return new BlockRenderer;
0056 }
0057 
0058 Analyzer::Worker * BlockAnalyzer::createWorker() const
0059 {
0060     auto worker = new BlockWorker( m_rows, m_columns, m_step, m_showFadebars );
0061     if( window() )
0062         worker->setRefreshRate( window()->screen()->refreshRate() );
0063     connect( worker, &BlockWorker::finished, this, &QQuickFramebufferObject::update, Qt::QueuedConnection );
0064     connect( this, &BlockAnalyzer::stepChanged, worker, &BlockWorker::setStep, Qt::QueuedConnection );
0065     connect( this, &BlockAnalyzer::rowsChanged, worker, &BlockWorker::setRows, Qt::QueuedConnection );
0066     connect( this, &BlockAnalyzer::columnsChanged, worker, &BlockWorker::setColumns, Qt::QueuedConnection );
0067     connect( this, &BlockAnalyzer::refreshRateChanged, worker, &BlockWorker::setRefreshRate, Qt::QueuedConnection );
0068     connect( this, &BlockAnalyzer::showFadebarsChanged, worker, &BlockWorker::setShowFadebars, Qt::QueuedConnection );
0069     return worker;
0070 }
0071 
0072 void
0073 BlockAnalyzer::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
0074 {
0075     QQuickFramebufferObject::geometryChanged( newGeometry, oldGeometry );
0076 
0077     if( !newGeometry.isValid() )
0078         return;
0079 
0080     const int oldRows = m_rows;
0081 
0082     // Rounded up so that the last column/line is covered if partially visible
0083     m_columns = std::lround( std::ceil( (double)newGeometry.width() / ( m_columnWidth + 1 ) ) );
0084     Q_EMIT columnsChanged( m_columns );
0085     m_rows    = std::ceil( (double)newGeometry.height() / ( BLOCK_HEIGHT + 1 ) );
0086     Q_EMIT rowsChanged( m_rows );
0087 
0088     setScopeSize( m_columns );
0089 
0090     if( m_rows != oldRows )
0091     {
0092         m_barPixmap = QPixmap( m_columnWidth, m_rows * ( BLOCK_HEIGHT + 1 ) );
0093 
0094         determineStep();
0095         paletteChange( The::paletteHandler()->palette() );
0096     }
0097     else
0098         drawBackground( The::paletteHandler()->palette() );
0099 }
0100 
0101 void
0102 BlockAnalyzer::determineStep()
0103 {
0104     // falltime is dependent on rowcount due to our digital resolution (ie we have boxes/blocks of pixels)
0105 
0106     const qreal fallTime = 1.0 / pow( 1.5, m_fallSpeed );  // time to fall from top to bottom
0107     m_step = qreal( m_rows ) / fallTime;  // the amount of rows to fall per second
0108     Q_EMIT stepChanged( m_step );
0109 }
0110 
0111 void
0112 BlockAnalyzer::paletteChange( const QPalette& palette ) //virtual
0113 {
0114     const QColor bg = palette.color( QPalette::Active, QPalette::Base );
0115     const QColor abg = palette.color( QPalette::Active, QPalette::AlternateBase );
0116     const QColor highlight = palette.color( QPalette::Active, QPalette::Highlight );
0117 
0118     m_topBarPixmap = QPixmap( m_columnWidth, BLOCK_HEIGHT );
0119     m_topBarPixmap.fill( highlight );
0120 
0121     m_barPixmap.fill( QColor( ( highlight.red() + bg.red() ) / 2, ( highlight.green() + bg.green() ) / 2, ( highlight.blue() + bg.blue() ) / 2 ) );
0122 
0123     QPainter p( &m_barPixmap );
0124 
0125     int h, s, v;
0126     palette.color( QPalette::Active, QPalette::Dark ).getHsv( &h, &s, &v );
0127     const QColor fade = QColor::fromHsv( h + 30, s, v );
0128 
0129     const double dr = fade.red() - abg.red();
0130     const double dg = fade.green() - abg.green();
0131     const double db = fade.blue() - abg.blue();
0132     const int r = abg.red(), g = abg.green(), b = abg.blue();
0133 
0134     // Precalculate all fade-bar pixmaps
0135     for( int y = 0; y < FADE_SIZE; ++y )
0136     {
0137         m_fadeBarsPixmaps[y] = QPixmap( m_columnWidth, m_rows * ( BLOCK_HEIGHT + 1 ) );
0138 
0139         m_fadeBarsPixmaps[y].fill( palette.color( QPalette::Active, QPalette::Base ) );
0140         const double Y = 1.0 - ( log10( ( FADE_SIZE ) - y ) / log10( ( FADE_SIZE ) ) );
0141         QPainter f( &m_fadeBarsPixmaps[y] );
0142         for( int z = 0; z < m_rows; ++z )
0143             f.fillRect( 0,
0144                         z * ( BLOCK_HEIGHT + 1 ),
0145                         m_columnWidth, BLOCK_HEIGHT,
0146                         QColor( r + int( dr * Y ), g + int( dg * Y ), b + int( db * Y ) ) );
0147     }
0148 
0149     m_pixmapsChanged = true;
0150     drawBackground( palette );
0151 }
0152 
0153 void
0154 BlockAnalyzer::drawBackground( const QPalette &palette )
0155 {
0156     const QColor bg = palette.color( QPalette::Active, QPalette::Base );
0157     const QColor abg = palette.color( QPalette::Active, QPalette::AlternateBase );
0158 
0159     // background gets stretched if it is too big
0160     m_backgroundPixmap = QPixmap( width(), height() );
0161     m_backgroundPixmap.fill( bg );
0162 
0163     QPainter p( &m_backgroundPixmap );
0164     for( int x = 0; x < m_columns; ++x )
0165         for( int y = 0; y < m_rows; ++y )
0166             p.fillRect( x * ( m_columnWidth + 1 ), y * ( BLOCK_HEIGHT + 1 ), m_columnWidth, BLOCK_HEIGHT, abg );
0167 
0168     m_pixmapsChanged = true;
0169 
0170     update();
0171 }
0172 
0173 void
0174 BlockAnalyzer::setFallSpeed( FallSpeed fallSpeed )
0175 {
0176     DEBUG_BLOCK
0177 
0178     debug() << "Fall speed set to:" << fallSpeed;
0179 
0180     if( m_fallSpeed == fallSpeed )
0181         return;
0182 
0183     m_fallSpeed = fallSpeed;
0184     config().writeEntry( "fallSpeed", (int) m_fallSpeed );
0185     Q_EMIT fallSpeedChanged();
0186 
0187     determineStep();
0188 }
0189 
0190 void
0191 BlockAnalyzer::setColumnWidth( int columnWidth )
0192 {
0193     DEBUG_BLOCK
0194 
0195     debug() << "Column width set to:" << columnWidth;
0196 
0197     if( columnWidth < 1 )
0198     {
0199         warning() << "Column width can not be smaller than one!";
0200         columnWidth = 1;
0201     }
0202 
0203     if( m_columnWidth == columnWidth )
0204         return;
0205 
0206     m_columnWidth = columnWidth;
0207     config().writeEntry( "columnWidth", m_columnWidth );
0208     Q_EMIT columnWidthChanged();
0209 
0210     m_columns = std::lround( std::ceil( (double)width() / ( m_columnWidth + 1 ) ) );
0211     Q_EMIT columnsChanged( m_columns );
0212     setScopeSize( m_columns );
0213     m_barPixmap = QPixmap( m_columnWidth, m_rows * ( BLOCK_HEIGHT + 1 ) );
0214     paletteChange( The::paletteHandler()->palette() );
0215 }
0216 
0217 void
0218 BlockAnalyzer::setShowFadebars( bool showFadebars )
0219 {
0220     DEBUG_BLOCK
0221 
0222     debug() << "Show fadebars:" << showFadebars;
0223 
0224     if( m_showFadebars == showFadebars )
0225         return;
0226 
0227     m_showFadebars = showFadebars;
0228     Q_EMIT showFadebarsChanged( m_showFadebars );
0229 }
0230 
0231 void
0232 BlockAnalyzer::newWindow( QQuickWindow* window )
0233 {
0234     if( window )
0235         Q_EMIT refreshRateChanged( window->screen()->refreshRate() );
0236 }