userstatusselectormodel.cpp
emojimodel.cpp
fileactivitylistmodel.cpp
+ tray/svgimageprovider.cpp
tray/syncstatussummary.cpp
tray/activitydata.cpp
tray/activitylistmodel.cpp
+/*
+ * Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
#include "iconutils.h"
#include <theme.h>
#include <QFile>
+#include <QLoggingCategory>
#include <QPainter>
#include <QPixmapCache>
#include <QSvgRenderer>
+namespace {
+QString findSvgFilePath(const QString &fileName, const QStringList &possibleColors)
+{
+ const QString baseSvgNoColor{QString{OCC::Theme::themePrefix} + fileName};
+ if (QFile::exists(baseSvgNoColor)) {
+ return baseSvgNoColor;
+ }
+
+ for (const auto &color : possibleColors) {
+ const QString baseSVG{QString{OCC::Theme::themePrefix} + color + QLatin1Char('/') + fileName};
+
+ if (QFile::exists(baseSVG)) {
+ return baseSVG;
+ }
+ }
+
+ return {};
+}
+}
+
namespace OCC {
namespace Ui {
-namespace IconUtils {
-QPixmap pixmapForBackground(const QString &fileName, const QColor &backgroundColor)
-{
- Q_ASSERT(!fileName.isEmpty());
+ Q_LOGGING_CATEGORY(lcIconUtils, "nextcloud.gui.iconutils", QtInfoMsg)
+ namespace IconUtils {
+ QPixmap pixmapForBackground(const QString &fileName, const QColor &backgroundColor)
+ {
+ Q_ASSERT(!fileName.isEmpty());
+
+ const auto pixmapColor = backgroundColor.isValid()
+ && !Theme::isDarkColor(backgroundColor)
+ ? QColorConstants::Svg::black
+ : QColorConstants::Svg::white;
+
+ return createSvgPixmapWithCustomColor(fileName, pixmapColor);
+ }
+
+ QPixmap createSvgPixmapWithCustomColor(const QString &fileName, const QColor &customColor, const QSize &size)
+ {
+ Q_ASSERT(!fileName.isEmpty());
+ Q_ASSERT(customColor.isValid());
+
+ if (fileName.isEmpty()) {
+ qWarning(lcIconUtils) << "fileName is empty";
+ }
+
+ if (!customColor.isValid()) {
+ qWarning(lcIconUtils) << "customColor is invalid";
+ }
+
+ const auto customColorName = customColor.name();
+
+ const QString cacheKey = fileName + QLatin1Char(',') + customColorName;
- // some icons are present in white or black only, so, we need to check both when needed
- const auto iconBaseColors = QStringList({ QStringLiteral("black"), QStringLiteral("white") });
+ QPixmap cachedPixmap;
- const QString pixmapColor = backgroundColor.isValid() && !Theme::isDarkColor(backgroundColor) ? "black" : "white";
+ // check for existing QPixmap in cache
+ if (QPixmapCache::find(cacheKey, &cachedPixmap)) {
+ return cachedPixmap;
+ }
+
+ // some icons are present in white or black only, so, we need to check both when needed
+ const auto iconBaseColors = QStringList{QStringLiteral("black"), QStringLiteral("white")};
+
+ // check if there is an existing pixmap matching the custom color
+ if (iconBaseColors.contains(customColorName)) {
+ cachedPixmap = QPixmap::fromImage(QImage{QString{OCC::Theme::themePrefix} + customColorName + QLatin1Char('/') + fileName});
+ QPixmapCache::insert(cacheKey, cachedPixmap);
+ return cachedPixmap;
+ }
+
+ // find the first matching svg file
+ const auto sourceSvg = findSvgFilePath(fileName, iconBaseColors);
- const QString cacheKey = fileName + QLatin1Char(',') + pixmapColor;
+ Q_ASSERT(!sourceSvg.isEmpty());
+ if (sourceSvg.isEmpty()) {
+ qWarning(lcIconUtils) << "Failed to find base SVG file for" << cacheKey;
+ return {};
+ }
+
+ cachedPixmap = drawSvgWithCustomFillColor(sourceSvg, customColor, size);
- QPixmap cachedPixmap;
+ Q_ASSERT(!cachedPixmap.isNull());
+ if (cachedPixmap.isNull()) {
+ qWarning(lcIconUtils) << "Failed to load pixmap for" << cacheKey;
+ return {};
+ }
- if (!QPixmapCache::find(cacheKey, &cachedPixmap)) {
- if (iconBaseColors.contains(pixmapColor)) {
- cachedPixmap = QPixmap::fromImage(QImage(QString(Theme::themePrefix) + pixmapColor + QLatin1Char('/') + fileName));
QPixmapCache::insert(cacheKey, cachedPixmap);
+
return cachedPixmap;
}
- const auto drawSvgWithCustomFillColor = [](const QString &sourceSvgPath, const QString &fillColor) {
+ QPixmap drawSvgWithCustomFillColor(const QString &sourceSvgPath, const QColor &fillColor, const QSize &size)
+ {
QSvgRenderer svgRenderer;
if (!svgRenderer.load(sourceSvgPath)) {
- return QPixmap();
+ qCWarning(lcIconUtils) << "Could no load initial SVG image";
+ return {};
}
+ const auto requestedSize = size.isValid() ? size : svgRenderer.defaultSize();
+
// render source image
- QImage svgImage(svgRenderer.defaultSize(), QImage::Format_ARGB32);
+ QImage svgImage(requestedSize, QImage::Format_ARGB32);
{
QPainter svgImagePainter(&svgImage);
svgImage.fill(Qt::GlobalColor::transparent);
}
// draw target image with custom fillColor
- QImage image(svgRenderer.defaultSize(), QImage::Format_ARGB32);
+ QImage image(requestedSize, QImage::Format_ARGB32);
image.fill(QColor(fillColor));
{
QPainter imagePainter(&image);
}
return QPixmap::fromImage(image);
- };
-
- // find the first matching svg among base colors, if any
- const QString sourceSvg = [&]() {
- for (const auto &color : iconBaseColors) {
- const QString baseSVG(QString(Theme::themePrefix) + color + QLatin1Char('/') + fileName);
-
- if (QFile(baseSVG).exists()) {
- return baseSVG;
- }
- }
- return QString();
- }();
-
- Q_ASSERT(!sourceSvg.isEmpty());
- if (sourceSvg.isEmpty()) {
- qWarning("Failed to find base svg for %s", qPrintable(cacheKey));
- return {};
- }
-
- cachedPixmap = drawSvgWithCustomFillColor(sourceSvg, pixmapColor);
- QPixmapCache::insert(cacheKey, cachedPixmap);
-
- Q_ASSERT(!cachedPixmap.isNull());
- if (cachedPixmap.isNull()) {
- qWarning("Failed to load pixmap for %s", qPrintable(cacheKey));
- return {};
}
}
-
- return cachedPixmap;
-}
-}
}
}
namespace Ui {
namespace IconUtils {
QPixmap pixmapForBackground(const QString &fileName, const QColor &backgroundColor);
+QPixmap createSvgPixmapWithCustomColor(const QString &fileName, const QColor &customColor, const QSize &size = {});
+QPixmap drawSvgWithCustomFillColor(const QString &sourceSvgPath, const QColor &fillColor, const QSize &size = {});
}
}
}
#include "theme.h"
#include "config.h"
#include "common/utility.h"
+#include "tray/svgimageprovider.h"
#include "tray/usermodel.h"
#include "tray/unifiedsearchresultimageprovider.h"
#include "configfile.h"
_trayEngine->addImportPath("qrc:/qml/theme");
_trayEngine->addImageProvider("avatars", new ImageProvider);
+ _trayEngine->addImageProvider(QLatin1String("svgimage-custom-color"), new OCC::Ui::SvgImageProvider);
_trayEngine->addImageProvider(QLatin1String("unified-search-result-icon"), new UnifiedSearchResultImageProvider);
}
smooth: true;
antialiasing: true
mipmap: true
-
- source: "qrc:///client/theme/black/search.svg"
+ source: "image://svgimage-custom-color/search.svg" + "/" + trayWindowUnifiedSearchTextField.textFieldIconsColor
sourceSize: Qt.size(parent.height * parent.textFieldIconsScaleFactor, parent.height * parent.textFieldIconsScaleFactor)
-
- ColorOverlay {
- anchors.fill: parent
- source: parent
- cached: true
- color: parent.parent.textFieldIconsColor
- }
}
BusyIndicator {
mipmap: true
visible: parent.text
-
- source: "qrc:///client/theme/black/clear.svg"
+ source: "image://svgimage-custom-color/clear.svg" + "/" + trayWindowUnifiedSearchTextField.textFieldIconsColor
sourceSize: Qt.size(parent.height * parent.textFieldIconsScaleFactor, parent.height * parent.textFieldIconsScaleFactor)
- ColorOverlay {
- anchors.fill: parent
- cached: true
- source: parent
- color: parent.parent.textFieldIconsColor
- }
-
MouseArea {
id: trayWindowUnifiedSearchTextFieldClearTextButtonMouseArea
--- /dev/null
+/*
+ * Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "svgimageprovider.h"
+#include "iconutils.h"
+
+#include <QLoggingCategory>
+
+namespace OCC {
+namespace Ui {
+ Q_LOGGING_CATEGORY(lcSvgImageProvider, "nextcloud.gui.svgimageprovider", QtInfoMsg)
+
+ SvgImageProvider::SvgImageProvider()
+ : QQuickImageProvider(QQuickImageProvider::Image)
+ {
+ }
+
+ QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
+ {
+ Q_UNUSED(size)
+
+ Q_ASSERT(!id.isEmpty());
+
+ const auto idSplit = id.split(QLatin1Char('/'), Qt::SkipEmptyParts);
+
+ if (idSplit.isEmpty()) {
+ qCWarning(lcSvgImageProvider) << "Image id is incorrect!";
+ return {};
+ }
+
+ const auto pixmapName = idSplit.at(0);
+ const auto pixmapColor = idSplit.size() > 1 ? QColor(idSplit.at(1)) : QColorConstants::Svg::black;
+
+ if (pixmapName.isEmpty() || !pixmapColor.isValid()) {
+ qCWarning(lcSvgImageProvider) << "Image id is incorrect!";
+ return {};
+ }
+
+ return IconUtils::createSvgPixmapWithCustomColor(pixmapName, pixmapColor, requestedSize).toImage();
+ }
+}
+}
--- /dev/null
+/*
+ * Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#pragma once
+
+#include <QQuickImageProvider>
+
+namespace OCC {
+namespace Ui {
+ class SvgImageProvider : public QQuickImageProvider
+ {
+ public:
+ SvgImageProvider();
+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
+ };
+}
+}
}
private slots:
+ void testDrawSvgWithCustomFillColor()
+ {
+ const QString blackSvgDirPath{QString{OCC::Theme::themePrefix} + QStringLiteral("black")};
+ const QDir blackSvgDir(blackSvgDirPath);
+ const QStringList blackImages = blackSvgDir.entryList(QStringList("*.svg"));
+
+ if (!blackImages.isEmpty()) {
+ QVERIFY(!OCC::Ui::IconUtils::drawSvgWithCustomFillColor(blackSvgDirPath + QLatin1Char('/') + blackImages.at(0), QColorConstants::Svg::red).isNull());
+ }
+
+ if (!blackImages.isEmpty()) {
+ QVERIFY(!OCC::Ui::IconUtils::drawSvgWithCustomFillColor(blackSvgDirPath + QLatin1Char('/') + blackImages.at(0), QColorConstants::Svg::green).isNull());
+ }
+
+ const QString whiteSvgDirPath{QString{OCC::Theme::themePrefix} + QStringLiteral("white")};
+ const QDir whiteSvgDir(whiteSvgDirPath);
+ const QStringList whiteImages = whiteSvgDir.entryList(QStringList("*.svg"));
+
+ if (!whiteImages.isEmpty()) {
+ QVERIFY(!OCC::Ui::IconUtils::drawSvgWithCustomFillColor(whiteSvgDirPath + QLatin1Char('/') + whiteImages.at(0), QColorConstants::Svg::blue).isNull());
+ }
+ }
+
+ void testCreateSvgPixmapWithCustomColor()
+ {
+ const QDir blackSvgDir(QString(QString{OCC::Theme::themePrefix}) + QStringLiteral("black"));
+ const QStringList blackImages = blackSvgDir.entryList(QStringList("*.svg"));
+
+ if (!blackImages.isEmpty()) {
+ QVERIFY(!OCC::Ui::IconUtils::createSvgPixmapWithCustomColor(blackImages.at(0), QColorConstants::Svg::red).isNull());
+ }
+
+ if (!blackImages.isEmpty()) {
+ QVERIFY(!OCC::Ui::IconUtils::createSvgPixmapWithCustomColor(blackImages.at(0), QColorConstants::Svg::green).isNull());
+ }
+
+ const QDir whiteSvgDir(QString(QString{OCC::Theme::themePrefix}) + QStringLiteral("white"));
+ const QStringList whiteImages = whiteSvgDir.entryList(QStringList("*.svg"));
+
+ if (!whiteImages.isEmpty()) {
+ QVERIFY(!OCC::Ui::IconUtils::createSvgPixmapWithCustomColor(whiteImages.at(0), QColorConstants::Svg::blue).isNull());
+ }
+ }
+
void testPixmapForBackground()
{
- const QDir blackSvgDir(QString(OCC::Theme::themePrefix) + QStringLiteral("black"));
+ const QDir blackSvgDir(QString(QString{OCC::Theme::themePrefix}) + QStringLiteral("black"));
const QStringList blackImages = blackSvgDir.entryList(QStringList("*.svg"));
- const QDir whiteSvgDir(QString(OCC::Theme::themePrefix) + QStringLiteral("white"));
+ const QDir whiteSvgDir(QString(QString{OCC::Theme::themePrefix}) + QStringLiteral("white"));
const QStringList whiteImages = whiteSvgDir.entryList(QStringList("*.svg"));
if (blackImages.size() > 0) {
// black pixmap for bright background - should not fail
QVERIFY(!OCC::Ui::IconUtils::pixmapForBackground(blackImages.at(0), QColor("yellow")).isNull());
}
-
- const auto blackImagesExclusive = QSet<QString>(blackImages.begin(), blackImages.end()).subtract(QSet<QString>(whiteImages.begin(), whiteImages.end()));
- const auto whiteImagesExclusive = QSet<QString>(whiteImages.begin(), whiteImages.end()).subtract(QSet<QString>(blackImages.begin(), blackImages.end()));
-
- if (blackImagesExclusive != whiteImagesExclusive) {
- // black pixmap for dark background - should fail as we don't have this image in black
- QVERIFY(OCC::Ui::IconUtils::pixmapForBackground(blackImagesExclusive.values().at(0), QColor("blue")).isNull());
-
- // white pixmap for bright background - should fail as we don't have this image in white
- QVERIFY(OCC::Ui::IconUtils::pixmapForBackground(whiteImagesExclusive.values().at(0), QColor("yellow")).isNull());
- }
}
};