diff --git a/src/controls/BasicListItem.qml b/src/controls/BasicListItem.qml --- a/src/controls/BasicListItem.qml +++ b/src/controls/BasicListItem.qml @@ -100,7 +100,6 @@ Layout.maximumHeight: size Layout.minimumWidth: size selected: layout.indicateActiveFocus && (listItem.highlighted || listItem.checked || (listItem.pressed && listItem.supportsMouseEvents)) - color: selected ? Theme.highlightedTextColor : listItem.Theme.textColor opacity: 1 } QQC2.Label { diff --git a/src/desktopicon.h b/src/desktopicon.h --- a/src/desktopicon.h +++ b/src/desktopicon.h @@ -100,10 +100,12 @@ void handleFinished(QNetworkAccessManager* qnam, QNetworkReply* reply); void handleReadyRead(QNetworkReply* reply); QIcon::Mode iconMode() const; + bool guessMonochrome(const QImage &img); private: Kirigami::PlatformTheme *m_theme = nullptr; QPointer m_networkReply; + QHash m_monochromeHeuristics; QVariant m_source; bool m_smooth; bool m_changed; diff --git a/src/desktopicon.cpp b/src/desktopicon.cpp --- a/src/desktopicon.cpp +++ b/src/desktopicon.cpp @@ -156,6 +156,7 @@ } m_source = icon; m_changed = true; + m_monochromeHeuristics.clear(); if (!m_theme) { m_theme = static_cast(qmlAttachedPropertiesObject(this, true)); @@ -489,21 +490,10 @@ } if (!icon.isNull()) { img = icon.pixmap(size, iconMode(), QIcon::On).toImage(); - qreal ratio = 1; - if (window() && window()->screen()) { - ratio = window()->screen()->devicePixelRatio(); - } const QColor tintColor = !m_color.isValid() || m_color == Qt::transparent ? (m_selected ? m_theme->highlightedTextColor() : m_theme->textColor()) : m_color; - if (m_isMask || - //this is an heuristic to decide when to tint and when to just draw - //(fullcolor icons) in reality on basic styles the only colored icons should be -symbolic, this heuristic is the most compatible middle ground - icon.isMask() || - //if symbolic color based on tintColor - (iconSource.endsWith(QLatin1String("-symbolic")) && tintColor.isValid() && tintColor != Qt::transparent) || - //if path color based on m_color - (isPath && m_color.isValid() && m_color != Qt::transparent)) { + if (m_isMask || icon.isMask() || iconSource.endsWith(QStringLiteral("-symbolic")) || guessMonochrome(img)) { QPainter p(&img); p.setCompositionMode(QPainter::CompositionMode_SourceIn); p.fillRect(img.rect(), tintColor); @@ -526,6 +516,67 @@ return QIcon::Normal; } +bool DesktopIcon::guessMonochrome(const QImage &img) +{ + //don't try for too big images + if (img.width() > 256 || m_theme->supportsIconColoring()) { + return false; + } + // round size to a standard size. hardcode as we can't use KIconLoader + int stdSize; + if (img.width() <= 16) { + stdSize = 16; + } else if (img.width() <= 22) { + stdSize = 22; + } else if (img.width() <= 24) { + stdSize = 24; + } else if (img.width() <= 32) { + stdSize = 32; + } else if (img.width() <= 48) { + stdSize = 48; + } else if (img.width() <= 64) { + stdSize = 64; + } else { + stdSize = 128; + } + + auto findIt = m_monochromeHeuristics.constFind(stdSize); + if (findIt != m_monochromeHeuristics.constEnd()) { + return findIt.value(); + } + + QHash dist; + int transparentPixels = 0; + int saturatedPixels = 0; + for(int x=0; x 84) { + ++saturatedPixels; + } + dist[qGray(color.rgb())]++; + } + } + + QMultiMap reverseDist; + auto it = dist.constBegin(); + std::vector probabilities(dist.size()); + qreal entropy = 0; + while (it != dist.constEnd()) { + reverseDist.insertMulti(it.value(), it.key()); + qreal probability = (qreal)it.value()/(qreal)(img.size().width()*img.size().height() - transparentPixels); + entropy -= probability * log(probability)/log(255); + ++it; + } + + // Arbitrarly low values of entropy and colored pixels + m_monochromeHeuristics[stdSize] = saturatedPixels <= (img.size().width()*img.size().height() - transparentPixels)*0.3 && entropy <= 0.3; + return m_monochromeHeuristics[stdSize]; +} + QString DesktopIcon::fallback() const { return m_fallback; diff --git a/src/libkirigami/platformtheme.h b/src/libkirigami/platformtheme.h --- a/src/libkirigami/platformtheme.h +++ b/src/libkirigami/platformtheme.h @@ -214,6 +214,8 @@ //this will be used by desktopicon to fetch icons with KIconLoader virtual Q_INVOKABLE QIcon iconFromTheme(const QString &name, const QColor &customColor = Qt::transparent); + bool supportsIconColoring() const; + //foreground colors void setCustomTextColor(const QColor &color = QColor()); void setCustomDisabledTextColor(const QColor &color = QColor()); @@ -246,7 +248,8 @@ protected: //Setters, not accessible from QML but from implementations - + void setSupportsIconColoring(bool support); + //foreground colors void setTextColor(const QColor &color); void setDisabledTextColor(const QColor &color); diff --git a/src/libkirigami/platformtheme.cpp b/src/libkirigami/platformtheme.cpp --- a/src/libkirigami/platformtheme.cpp +++ b/src/libkirigami/platformtheme.cpp @@ -93,6 +93,7 @@ QFont font; bool m_inherit = true; bool m_init = true; + bool m_supportsIconColoring = false; static KirigamiPluginFactory *s_pluginFactory; }; @@ -694,12 +695,21 @@ QIcon PlatformTheme::iconFromTheme(const QString &name, const QColor &customColor) { QIcon icon = QIcon::fromTheme(name); - if (!icon.isNull() && (name.endsWith(QLatin1String("-symbolic")) || customColor != Qt::transparent)) { + if (!icon.isNull() && name.endsWith(QLatin1String("-symbolic"))) { icon.setIsMask(true); } return icon; } +bool PlatformTheme::supportsIconColoring() const +{ + return d->m_supportsIconColoring; +} + +void PlatformTheme::setSupportsIconColoring(bool support) +{ + d->m_supportsIconColoring = support; +} PlatformTheme *PlatformTheme::qmlAttachedProperties(QObject *object)