From ef488d334ea9fe55d821c9a400bbe325981cd856 Mon Sep 17 00:00:00 2001 From: David Hurka Date: Sun, 19 Apr 2020 00:27:55 +0000 Subject: [PATCH] Generate presentation drawing tool icons in a custom QIconEngine, so checkboxes can be sharp on hidpi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The checkboxes in the drawing tool icons in the presentation toolbar were not sharp on hiDPI, this fixes it. The toolbar buttons are QActions with QIcons, and the icons were created from 25x25 pixmaps. That is usually smaller than the toolbar’s icon size, so the icons had a nice size. But at hiDPI, the icons were scaled up, so the checkmarks looked blurry. Now the icons are generated in the correct resolution on the fly, because the painting code from ColorAction::setColor() is moved to a custom QIconEngine inside ColorAction. --- ui/drawingtoolactions.cpp | 75 ++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/ui/drawingtoolactions.cpp b/ui/drawingtoolactions.cpp index c12171502..ef4e5d98c 100644 --- a/ui/drawingtoolactions.cpp +++ b/ui/drawingtoolactions.cpp @@ -17,6 +17,7 @@ #include #include +#include #include class ColorAction : public QAction @@ -31,28 +32,70 @@ public: void setColor( const QColor &color ) { - QPixmap pm( 25, 25 ); - pm.fill( color ); + setIcon( QIcon( new ColorActionIconEngine( color ) ) ); + } - QIcon icon; +protected: + class ColorActionIconEngine : public QIconEngine + { + public: + explicit ColorActionIconEngine( const QColor &color ) + : m_color( color ) + { + } - icon.addPixmap( pm, QIcon::Normal, QIcon::Off ); + ColorActionIconEngine( const ColorActionIconEngine& ) = delete; + ColorActionIconEngine &operator=( const ColorActionIconEngine& ) = delete; - QPixmap pmSel( pm ); - QPainter p( &pmSel ); - QFont font = p.font(); - font.setPixelSize( pmSel.height() * 0.9 ); - p.setFont( font ); + // No one needs clone(), but it’s pure virtual + QIconEngine* clone() const override + { + return nullptr; + } - // draw check mark - const int lightness = ((color.red() * 299) + (color.green() * 587) + (color.blue() * 114)) / 1000; - p.setPen( lightness < 128 ? Qt::white : Qt::black ); - p.drawText( QRect( QPoint( 0, 0 ), pmSel.size() ), Qt::AlignCenter, QStringLiteral("\u2713") ); + QPixmap pixmap( const QSize &size, QIcon::Mode mode, QIcon::State state ) override + { + QPixmap pixmap( size ); + pixmap.fill( Qt::transparent ); + Q_ASSERT( pixmap.hasAlphaChannel() ); - icon.addPixmap( pmSel, QIcon::Normal, QIcon::On ); + QPainter painter( &pixmap ); + paint( &painter, QRect( QPoint( 0, 0), size ), mode, state ); + return pixmap; + } - setIcon( icon ); - } + void paint( QPainter * painter, + const QRect &rect, + QIcon::Mode mode, + QIcon::State state ) override + { + Q_UNUSED( mode ) + + // Assume that rect is square and at position (0, 0) + int squareSize = rect.height() * 0.8; + int squareOffset = ( rect.height() - squareSize ) / 2; + + painter->fillRect( squareOffset, squareOffset, squareSize, squareSize, m_color ); + + if ( state == QIcon::On ) { + QFont checkmarkFont = painter->font(); + checkmarkFont.setPixelSize( squareSize * 0.9 ); + painter->setFont( checkmarkFont ); + + const int lightness = ( ( m_color.red() * 299 ) + + ( m_color.green() * 587 ) + + ( m_color.blue() * 114 ) ) / 1000; + painter->setPen( lightness < 128 ? Qt::white : Qt::black ); + + painter->drawText( QRect( squareOffset, squareOffset, squareSize, squareSize ), + Qt::AlignCenter, + QStringLiteral("\u2713") ); + } + } + + protected: + QColor m_color; + }; }; DrawingToolActions::DrawingToolActions( KActionCollection *parent )