diff --git a/autotests/iconitemtest.cpp b/autotests/iconitemtest.cpp index 0ec4616af..393af9f0f 100644 --- a/autotests/iconitemtest.cpp +++ b/autotests/iconitemtest.cpp @@ -441,5 +441,44 @@ void IconItemTest::windowChanged() QCOMPARE(grabImage(item), img); } +void IconItemTest::paintedSize() +{ + QQuickItem *item = createIconItem(); + + QCOMPARE(item->property("paintedWidth").toInt(), item->property("implicitWidth").toInt()); + QCOMPARE(item->property("paintedHeight").toInt(), item->property("implicitHeight").toInt()); + + item->setWidth(40); + item->setHeight(40); + + QCOMPARE(item->property("paintedWidth").toInt(), 32); + QCOMPARE(item->property("paintedHeight").toInt(), 32); + + QIcon landscapeIcon(QPixmap(40, 35)); + item->setProperty("source", landscapeIcon); + grabImage(item); // basically just to force loading the pixmap + + // expanded to fit IconItem size whilst keeping aspect ratio + // width should be rounded to icon size, ie. 32 is next smallest + QCOMPARE(item->property("paintedWidth").toInt(), 32); + // height should still match aspect ratio, so *not* 24! + QCOMPARE(item->property("paintedHeight").toInt(), 28); + + QIcon portraitIcon(QPixmap(15, 40)); + item->setProperty("source", portraitIcon); + grabImage(item); + + QCOMPARE(item->property("paintedWidth").toInt(), 12); + QCOMPARE(item->property("paintedHeight").toInt(), 32); + + item->setWidth(400); + item->setHeight(400); + + grabImage(item); + + QCOMPARE(item->property("paintedWidth").toInt(), 150); + QCOMPARE(item->property("paintedHeight").toInt(), 400); +} + QTEST_MAIN(IconItemTest) diff --git a/autotests/iconitemtest.h b/autotests/iconitemtest.h index afa708290..7dbaf554b 100644 --- a/autotests/iconitemtest.h +++ b/autotests/iconitemtest.h @@ -54,6 +54,7 @@ private Q_SLOTS: void animatingActiveChange(); void animatingEnabledChange(); void windowChanged(); + void paintedSize(); private: QQuickItem *createIconItem(); diff --git a/src/declarativeimports/core/iconitem.cpp b/src/declarativeimports/core/iconitem.cpp index 8f29ee2d1..1d9d53e82 100644 --- a/src/declarativeimports/core/iconitem.cpp +++ b/src/declarativeimports/core/iconitem.cpp @@ -309,12 +309,37 @@ bool IconItem::isValid() const int IconItem::paintedWidth() const { - return Units::roundToIconSize(qMin(boundingRect().size().width(), boundingRect().size().height())); + return paintedSize(boundingRect().size()).width(); } int IconItem::paintedHeight() const { - return Units::roundToIconSize(qMin(boundingRect().size().width(), boundingRect().size().height())); + return paintedSize(boundingRect().size()).height(); +} + +QSize IconItem::paintedSize(const QSizeF &containerSize) const +{ + const QSize &actualContainerSize = (containerSize.isValid() ? containerSize : boundingRect().size()).toSize(); + + const QSize paintedSize = m_iconPixmap.size().scaled(actualContainerSize, Qt::KeepAspectRatio); + + const int width = paintedSize.width(); + const int height = paintedSize.height(); + + if (width == height) { + return QSize(Units::roundToIconSize(width), Units::roundToIconSize(height)); + } + + // if we don't have a square image, we still want it to be rounded to icon size + // but we cannot just blindly round both as we might erroneously change a 50x45 image to be 48x32 + // instead, round the bigger of the two and then downscale the smaller with the ratio + if (width > height) { + const int roundedWidth = Units::roundToIconSize(width); + return QSize(roundedWidth, qRound(height * (roundedWidth / static_cast(width)))); + } else { + const int roundedHeight = Units::roundToIconSize(height); + return QSize(qRound(width * (roundedHeight / static_cast(height))), roundedHeight); + } } void IconItem::setStatus(Plasma::Svg::Status status) @@ -366,10 +391,8 @@ QSGNode* IconItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *update animatingNode->setProgress(m_animValue); if (m_sizeChanged) { - const int iconSize = Units::roundToIconSize(qMin(boundingRect().size().width(), boundingRect().size().height())); - const QRect destRect(QPointF(boundingRect().center() - QPointF(iconSize/2, iconSize/2)).toPoint(), - QSize(iconSize, iconSize)); - + const QSize newSize = paintedSize(); + const QRect destRect(QPointF(boundingRect().center() - QPointF(newSize.width(), newSize.height()) / 2).toPoint(), newSize); animatingNode->setRect(destRect); m_sizeChanged = false; } @@ -387,10 +410,8 @@ QSGNode* IconItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *update } if (m_sizeChanged) { - const int iconSize = Units::roundToIconSize(qMin(boundingRect().size().width(), boundingRect().size().height())); - const QRect destRect(QPointF(boundingRect().center() - QPointF(iconSize/2, iconSize/2)).toPoint(), - QSize(iconSize, iconSize)); - + const QSize newSize = paintedSize(); + const QRect destRect(QPointF(boundingRect().center() - QPointF(newSize.width(), newSize.height()) / 2).toPoint(), newSize); textureNode->setRect(destRect); m_sizeChanged = false; } @@ -489,10 +510,16 @@ void IconItem::loadPixmap() result = KIconLoader::global()->iconEffect()->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState); } + const QSize oldPaintedSize = paintedSize(); + m_oldIconPixmap = m_iconPixmap; m_iconPixmap = result; m_textureChanged = true; + if (oldPaintedSize != paintedSize()) { + emit paintedSizeChanged(); + } + //don't animate initial setting if ((m_animated || m_allowNextAnimation) && !m_oldIconPixmap.isNull() && !m_sizeChanged && !m_blockNextAnimation) { m_animValue = 0.0; @@ -528,8 +555,7 @@ void IconItem::geometryChanged(const QRectF &newGeometry, update(); } - if (Units::roundToIconSize(qMin(oldGeometry.size().width(), oldGeometry.size().height())) != - Units::roundToIconSize(qMin(newGeometry.size().width(), newGeometry.size().height()))) { + if (paintedSize(oldGeometry.size()) != paintedSize(newGeometry.size())) { emit paintedSizeChanged(); } } diff --git a/src/declarativeimports/core/iconitem.h b/src/declarativeimports/core/iconitem.h index 7ffaf8173..11d98bd40 100644 --- a/src/declarativeimports/core/iconitem.h +++ b/src/declarativeimports/core/iconitem.h @@ -176,6 +176,7 @@ private Q_SLOTS: private: void loadPixmap(); + QSize paintedSize(const QSizeF &containerSize = QSizeF()) const; //all the ways we can set an source. Only one of them will be valid QIcon m_icon;