File indexing completed on 2025-02-23 04:34:22
0001 /** 0002 * \file taggedfileiconprovider.cpp 0003 * Provides icons for tagged files. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 13 Jul 2019 0008 * 0009 * Copyright (C) 2019-2024 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "taggedfileiconprovider.h" 0028 #include <QGuiApplication> 0029 #include <QPalette> 0030 #include <QIcon> 0031 #include <QPixmap> 0032 #include <QColor> 0033 #include <QPainter> 0034 #include "taggedfile.h" 0035 #include "tagconfig.h" 0036 0037 /** 0038 * Constructor. 0039 */ 0040 TaggedFileIconProvider::TaggedFileIconProvider() 0041 : m_requestedSize(16, 16), m_markedColor(QBrush(Qt::gray)) 0042 { 0043 if (qobject_cast<QGuiApplication*>(QCoreApplication::instance()) != nullptr) { 0044 QPalette palette = QGuiApplication::palette(); 0045 int h1, s1, l1, h2, s2, l2; 0046 palette.window().color().getHsl(&h1, &s1, &l1); 0047 palette.windowText().color().getHsl(&h2, &s2, &l2); 0048 m_markedColor = QColor::fromHsl((h1 + h2) / 2, (s1 + s2) / 2, (l1 + l2) / 2); 0049 } 0050 } 0051 0052 /** 0053 * Set icon to be used for modified files. 0054 * @param icon modified icon 0055 */ 0056 void TaggedFileIconProvider::setModifiedIcon(const QVariant& icon) { 0057 m_modifiedIcon = icon; 0058 } 0059 0060 /** 0061 * Set the requested size for icons. 0062 * 0063 * The size set with this method will be used to create icons. 0064 * 0065 * @param size icon size, the default is 16x16. 0066 */ 0067 void TaggedFileIconProvider::setRequestedSize(const QSize& size) 0068 { 0069 if (size.isValid() && size.height() > m_requestedSize.height()) { 0070 m_requestedSize = size; 0071 m_iconMap.clear(); 0072 m_pixmapMap.clear(); 0073 } 0074 } 0075 0076 /** 0077 * Create icons using requested size. 0078 */ 0079 void TaggedFileIconProvider::createIcons() 0080 { 0081 static const struct { 0082 const char* id; 0083 const char* text1; 0084 const char* text2; 0085 } idTexts[] = { 0086 {"null", nullptr, nullptr}, 0087 {"notag", "NO", "TAG" }, 0088 {"v1v2", "V1", "V2"}, 0089 {"v1", "V1", nullptr}, 0090 {"v2", nullptr, "V2"}, 0091 {"v3", nullptr, "V3"}, 0092 {"v1v3", "V1", "V3"}, 0093 {"v2v3", "V2", "V3"}, 0094 {"v1v2v3", "V1", "23"} 0095 }; 0096 0097 const int height = m_requestedSize.height(); 0098 const int halfHeight = height / 2; 0099 QFont font(QLatin1String("helvetica")); 0100 font.setPixelSize(halfHeight); 0101 QFont smallFont(font); 0102 smallFont.setStretch(QFont::Condensed); 0103 for (const auto& [id, text1, text2] : idTexts) { 0104 QPixmap pixmap(m_requestedSize); 0105 pixmap.fill(Qt::transparent); 0106 QPainter painter(&pixmap); 0107 painter.setFont(font); 0108 if (text1) { 0109 painter.setPen(Qt::white); 0110 painter.drawText(QPoint(2, halfHeight - 1), QLatin1String(text1)); 0111 painter.setPen(Qt::black); 0112 painter.drawText(QPoint(3, halfHeight), QLatin1String(text1)); 0113 } 0114 if (text2) { 0115 if (qstrlen(text2) > 2) { 0116 painter.setFont(smallFont); 0117 } 0118 painter.setPen(Qt::white); 0119 painter.drawText(QPoint(2, height - 2), QLatin1String(text2)); 0120 painter.setPen(Qt::black); 0121 painter.drawText(QPoint(3, height - 1), QLatin1String(text2)); 0122 } 0123 0124 m_pixmapMap.insert(id, pixmap); 0125 } 0126 0127 for (auto it = m_pixmapMap.constBegin(); it != m_pixmapMap.constEnd(); ++it) { 0128 m_iconMap.insert(it.key(), QIcon(it.value().value<QPixmap>())); 0129 } 0130 0131 if (m_modifiedIcon.isNull()) { 0132 // Some KDE styles do not provide a QStyle::SP_DriveFDIcon icon. 0133 // Create a fallback icon for such cases. 0134 static const char* const modifiedXpm[] = { 0135 "16 16 33 1", 0136 ". c None", 0137 "B c None", 0138 "A c None", 0139 "C c None", 0140 "D c None", 0141 "E c None", 0142 "# c #000000", 0143 "b c #006562", 0144 "j c #414041", 0145 "x c #525552", 0146 "f c #529594", 0147 "e c #52959c", 0148 "w c #5a555a", 0149 "v c #626162", 0150 "u c #626562", 0151 "r c #737173", 0152 "p c #737573", 0153 "q c #7b757b", 0154 "o c #838183", 0155 "m c #838583", 0156 "z c #8b8d8b", 0157 "l c #949194", 0158 "k c #9c959c", 0159 "i c #a4a1a4", 0160 "h c #a4a5a4", 0161 "y c #b4b6b4", 0162 "g c #bdb6bd", 0163 "a c #c5c2c5", 0164 "s c #c5c6c5", 0165 "c c #cdc6cd", 0166 "t c #dedade", 0167 "n c #eeeaee", 0168 "d c #ffffff", 0169 ".......##.......", 0170 "......#ab#......", 0171 ".....#cbde#.....", 0172 "....#abdddf#....", 0173 "...#gbddddde#...", 0174 "..#hijddddddf#..", 0175 ".#kjkljdddddd##.", 0176 "#mjnjmojddddjma#", 0177 "#jnpnjqrjddjqs#.", 0178 "#drtttjuvjjua#..", 0179 ".#dasajjwxws#...", 0180 "..#dyjzljxa#...A", 0181 "...#jrrjws#...AB", 0182 "....#cjxa#...ACB", 0183 ".....#cs#...ADE.", 0184 "......##...ABB.." 0185 }; 0186 m_modifiedIcon = QIcon(QPixmap(modifiedXpm)); 0187 } 0188 if (!m_modifiedIcon.isNull()) { 0189 m_iconMap.insert("modified", m_modifiedIcon); 0190 m_pixmapMap.insert("modified", 0191 m_modifiedIcon.value<QIcon>().pixmap(m_requestedSize)); 0192 } 0193 } 0194 0195 /** 0196 * Get an icon for a tagged file. 0197 * 0198 * @param taggedFile tagged file 0199 * 0200 * @return icon for tagged file 0201 */ 0202 QVariant TaggedFileIconProvider::iconForTaggedFile(const TaggedFile* taggedFile) 0203 { 0204 if (taggedFile) { 0205 if (m_iconMap.isEmpty()) { 0206 createIcons(); 0207 } 0208 return m_iconMap.value(iconIdForTaggedFile(taggedFile)); 0209 } 0210 return QVariant(); 0211 } 0212 0213 /** 0214 * Get pixmap for an icon ID. 0215 * @param id icon ID as returned by iconIdForTaggedFile(), or data for image 0216 * set with setImageData() 0217 * @return pixmap for @a id. 0218 */ 0219 QVariant TaggedFileIconProvider::pixmapForIconId(const QByteArray& id) 0220 { 0221 if (m_pixmapMap.isEmpty()) { 0222 createIcons(); 0223 } 0224 return m_pixmapMap.value(id); 0225 } 0226 0227 /** 0228 * Get background color for a tagged file. 0229 * 0230 * @param taggedFile tagged file 0231 * 0232 * @return background color for tagged file, invalid color if background 0233 * should not be set 0234 */ 0235 QVariant TaggedFileIconProvider::backgroundForTaggedFile( 0236 const TaggedFile* taggedFile) { 0237 if (taggedFile && 0238 ((TagConfig::instance().markTruncations() && 0239 taggedFile->getTruncationFlags(Frame::Tag_Id3v1) != 0) || 0240 taggedFile->isMarked())) 0241 return QColor(Qt::red); 0242 return QVariant(); 0243 } 0244 0245 /** 0246 * Get brush with color for a context. 0247 * @param context color context 0248 * @return brush. 0249 */ 0250 QVariant TaggedFileIconProvider::colorForContext(ColorContext context) const 0251 { 0252 switch (context) { 0253 case ColorContext::None: 0254 break; 0255 case ColorContext::Marked: 0256 return m_markedColor; 0257 case ColorContext::Error: 0258 return QBrush(Qt::red); 0259 } 0260 return QBrush(Qt::NoBrush); 0261 } 0262 0263 /** 0264 * Get context for a brush. 0265 * @param color brush 0266 * @return color context. 0267 */ 0268 ColorContext TaggedFileIconProvider::contextForColor(const QVariant& color) const 0269 { 0270 #if QT_VERSION >= 0x060000 0271 if (color.typeId() == QMetaType::QBrush) { 0272 #else 0273 if (color.type() == QVariant::Brush) { 0274 #endif 0275 if (auto brush = color.value<QBrush>(); brush == Qt::red) { 0276 return ColorContext::Error; 0277 } else if (brush != Qt::NoBrush) { 0278 return ColorContext::Marked; 0279 } 0280 } 0281 return ColorContext::None; 0282 }