File indexing completed on 2024-12-08 10:16:05
0001 /* 0002 SPDX-FileCopyrightText: 2020-2022 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "styledframesvgitem.h" 0008 0009 #include <QBuffer> 0010 #include <QDebug> 0011 #include <QFile> 0012 #include <QImageReader> 0013 #include <QPainter> 0014 #include <QQuickWindow> 0015 #include <QUrlQuery> 0016 #include <QXmlStreamReader> 0017 #include <QXmlStreamWriter> 0018 0019 using namespace KPublicTransport; 0020 0021 StyledFrameSvgItem::StyledFrameSvgItem(QQuickItem *parent) 0022 : QQuickPaintedItem(parent) 0023 { 0024 const auto updateFunc = [this]() { update(); }; 0025 connect(this, &StyledFrameSvgItem::borderTopChanged, this, updateFunc); 0026 connect(this, &StyledFrameSvgItem::borderBottomChanged, this, updateFunc); 0027 connect(this, &StyledFrameSvgItem::borderLeftChanged, this, updateFunc); 0028 connect(this, &StyledFrameSvgItem::borderRightChanged, this, updateFunc); 0029 connect(this, &StyledFrameSvgItem::colorChanged, this, &StyledFrameSvgItem::invalidateImage); 0030 connect(this, &StyledFrameSvgItem::sourceChanged, this, &StyledFrameSvgItem::invalidateImage); 0031 0032 setImplicitSize(48, 48); 0033 } 0034 0035 StyledFrameSvgItem::~StyledFrameSvgItem() = default; 0036 0037 void StyledFrameSvgItem::paint(QPainter *painter) 0038 { 0039 loadImage(); 0040 if (m_image.isNull()) { 0041 return; 0042 } 0043 0044 const auto dpr = window()->devicePixelRatio(); 0045 const double xSrcOffsets[4] = { 0.0, m_borderLeft * dpr, m_image.width() - m_borderRight * dpr, (double)m_image.width() }; 0046 const double ySrcOffsets[4] = { 0.0, m_borderTop * dpr, m_image.height() - m_borderBottom * dpr, (double)m_image.height() }; 0047 const double xDestOffsets[4] = { 0.0, m_borderLeft, width() - m_borderRight, width() }; 0048 const double yDestOffsets[4] = { 0.0, m_borderTop, height() - m_borderBottom, height() }; 0049 0050 for (int xi = 0; xi < 3; ++xi) { 0051 for (int yi = 0; yi < 3; ++yi) { 0052 QRectF srcRect(QPointF(xSrcOffsets[xi], ySrcOffsets[yi]), QPointF(xSrcOffsets[xi + 1], ySrcOffsets[yi + 1])); 0053 QRectF destRect(QPointF(xDestOffsets[xi], yDestOffsets[yi]), QPointF(xDestOffsets[xi + 1], yDestOffsets[yi + 1])); 0054 if (srcRect.width() <= 0 || srcRect.height() <= 0) { 0055 continue; 0056 } 0057 painter->drawImage(destRect, m_image, srcRect); 0058 } 0059 } 0060 } 0061 0062 void StyledFrameSvgItem::invalidateImage() 0063 { 0064 m_image = {}; 0065 update(); 0066 } 0067 0068 void StyledFrameSvgItem::loadImage() 0069 { 0070 if (!m_image.isNull() || m_source.isEmpty()) { 0071 return; 0072 } 0073 0074 // find SVG 0075 QFile svgFile(m_source); 0076 if (!svgFile.open(QFile::ReadOnly)) { 0077 qWarning() << "Failed to open SVG file:" << svgFile.fileName() << svgFile.errorString(); 0078 return; 0079 } 0080 0081 // prepare CSS 0082 QFile cssFile(QStringLiteral(":/org.kde.kpublictransport/ui/assets/style.css")); 0083 if (!cssFile.open(QFile::ReadOnly)) { 0084 qWarning() << "Failed to open CSS file:" << cssFile.fileName() << cssFile.errorString(); 0085 return; 0086 } 0087 auto css = QString::fromUtf8(cssFile.readAll()); 0088 css.replace(QLatin1String("{{fillColor}}"), m_fillColor.name(QColor::HexArgb)); 0089 css.replace(QLatin1String("{{lineColor}}"), m_lineColor.name(QColor::HexArgb)); 0090 0091 // inject CSS (inspired by KIconLoader) 0092 QByteArray processedContents; 0093 QXmlStreamReader reader(&svgFile); 0094 QBuffer buffer(&processedContents); 0095 buffer.open(QIODevice::WriteOnly); 0096 QXmlStreamWriter writer(&buffer); 0097 while (!reader.atEnd()) { 0098 if (reader.readNext() == QXmlStreamReader::StartElement && 0099 reader.qualifiedName() == QLatin1String("style") && 0100 reader.attributes().value(QLatin1String("id")) == QLatin1String("current-color-scheme")) { 0101 writer.writeStartElement(QStringLiteral("style")); 0102 writer.writeAttributes(reader.attributes()); 0103 writer.writeCharacters(css); 0104 writer.writeEndElement(); 0105 while (reader.tokenType() != QXmlStreamReader::EndElement) { 0106 reader.readNext(); 0107 } 0108 } else if (reader.tokenType() != QXmlStreamReader::Invalid) { 0109 writer.writeCurrentToken(reader); 0110 } 0111 } 0112 buffer.close(); 0113 0114 // render SVG 0115 buffer.open(QIODevice::ReadOnly); 0116 buffer.seek(0); 0117 QImageReader imgReader(&buffer, "svg"); 0118 imgReader.setScaledSize(imgReader.size() * window()->devicePixelRatio()); 0119 m_image = imgReader.read(); 0120 m_image.setDevicePixelRatio(window()->devicePixelRatio()); 0121 setImplicitSize(imgReader.size().width(), m_image.size().height()); 0122 }