1 /* GuiUtils.cpp */ 2 3 /* Copyright (C) 2011-2020 Michael Lugmair (Lucio Carreras) 4 * 5 * This file is part of sayonara player 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 22 /* GuiUtils.cpp */ 23 24 #include "GuiUtils.h" 25 #include "Utils/Logger/Logger.h" 26 27 #include <QApplication> 28 #include <QDesktopWidget> 29 #include <QDirIterator> 30 #include <QFontMetrics> 31 #include <QIcon> 32 #include <QList> 33 #include <QPalette> 34 #include <QPixmap> 35 #include <QRegExp> 36 #include <QScreen> 37 #include <QSize> 38 #include <QString> 39 #include <QCache> 40 41 #include <algorithm> 42 43 namespace 44 { 45 using IconCache = QCache<QString, QIcon>; 46 Q_GLOBAL_STATIC_WITH_ARGS(IconCache, iconCache, (50)) 47 getCacheKey(const QString & iconName,Gui::Util::IconTheme theme)48 QString getCacheKey(const QString& iconName, Gui::Util::IconTheme theme) 49 { 50 return QString("%1-%2") 51 .arg(iconName) 52 .arg(static_cast<int>(theme)); 53 } 54 getCacheKey(const QString & iconName,const QString & systemThemeName)55 QString getCacheKey(const QString& iconName, const QString& systemThemeName) 56 { 57 return QString("%1-%2") 58 .arg(iconName) 59 .arg(systemThemeName); 60 } 61 insertIconIntoCache(const QString & key,QIcon & icon)62 bool insertIconIntoCache(const QString& key, QIcon& icon) 63 { 64 if(!key.isNull() && !icon.isNull() && !iconCache.isDestroyed()) 65 { 66 auto* iconPtr = new QIcon(std::move(icon)); 67 iconCache->insert(key, iconPtr); 68 return true; 69 } 70 71 return false; 72 } 73 fetchIconFromCache(const QString & cacheKey)74 QIcon fetchIconFromCache(const QString& cacheKey) 75 { 76 return (!iconCache.isDestroyed() && iconCache->object(cacheKey)) 77 ? *iconCache->object(cacheKey) 78 : QIcon(); 79 } 80 searchInResource(const QString & resourceName,const QString & regex)81 QStringList searchInResource(const QString& resourceName, const QString& regex) 82 { 83 const auto re = QRegExp(regex); 84 const auto themePath = QString(":/%1").arg(resourceName); 85 86 QStringList paths; 87 auto dirIterator = QDirIterator(themePath); 88 while(dirIterator.hasNext()) 89 { 90 const auto path = dirIterator.next(); 91 if(re.indexIn(path) >= 0) 92 { 93 paths << path; 94 } 95 } 96 97 return paths; 98 } 99 searchInMintYIcons(const QString & iconName)100 QStringList searchInMintYIcons(const QString& iconName) 101 { 102 const auto themeName = QStringLiteral("MintYIcons"); 103 const auto reString = QString(".*%1/%2-[0-9]+.*") 104 .arg(themeName) 105 .arg(iconName); 106 107 return searchInResource(themeName, reString); 108 } 109 searchInStandardIcons(const QString & iconName)110 QStringList searchInStandardIcons(const QString& iconName) 111 { 112 QStringList paths; 113 114 const auto reString = QString(".*/%1(\\.[a-z][a-z][a-z])*$").arg(iconName); 115 return searchInResource("Icons", reString); 116 } 117 iconPaths(const QString & iconName,Gui::Util::IconTheme iconTheme)118 QStringList iconPaths(const QString& iconName, Gui::Util::IconTheme iconTheme) 119 { 120 if(iconName.trimmed().isEmpty()) 121 { 122 return QStringList(); 123 } 124 125 QStringList paths; 126 if(iconTheme == Gui::Util::MintY) 127 { 128 paths = searchInMintYIcons(iconName); 129 } 130 131 if(paths.isEmpty()) 132 { 133 paths = searchInStandardIcons(iconName); 134 } 135 136 return paths; 137 } 138 } 139 140 namespace Gui 141 { icon(const QString & iconName,IconTheme iconTheme)142 QIcon Util::icon(const QString& iconName, IconTheme iconTheme) 143 { 144 if(iconName.isEmpty()) 145 { 146 return QIcon(); 147 } 148 149 const auto cacheKey = getCacheKey(iconName, iconTheme); 150 auto icon = fetchIconFromCache(cacheKey); 151 if(!icon.isNull()) 152 { 153 return icon; 154 } 155 156 const auto paths = iconPaths(iconName, iconTheme); 157 for(const auto& path : paths) 158 { 159 const auto pixmap = QPixmap(path); 160 if(!pixmap.isNull()) 161 { 162 icon.addPixmap(pixmap); 163 } 164 } 165 166 const auto success = insertIconIntoCache(cacheKey, icon); 167 return (success) 168 ? fetchIconFromCache(cacheKey) 169 : icon; 170 } 171 systemThemeIcon(const QString & iconName)172 QIcon Util::systemThemeIcon(const QString& iconName) 173 { 174 const auto cacheKey = getCacheKey(iconName, QIcon::themeName()); 175 auto icon = fetchIconFromCache(cacheKey); 176 if(!icon.isNull()) 177 { 178 return icon; 179 } 180 181 icon = QIcon::fromTheme(iconName); 182 const auto success = insertIconIntoCache(cacheKey, icon); 183 return success 184 ? fetchIconFromCache(cacheKey) 185 : icon; 186 } 187 image(const QString & iconName,IconTheme themeName)188 QImage Util::image(const QString& iconName, IconTheme themeName) 189 { 190 return image(iconName, themeName, QSize(32, 32)); 191 } 192 image(const QString & iconName,IconTheme themeName,const QSize & size,bool keepAspectRatio)193 QImage Util::image(const QString& iconName, IconTheme themeName, const QSize& size, bool keepAspectRatio) 194 { 195 const auto pixmap = Util::pixmap(iconName, themeName, size, keepAspectRatio); 196 return (!pixmap.isNull()) 197 ? pixmap.toImage() 198 : QImage(); 199 } 200 pixmap(const QString & iconName,IconTheme themeName)201 QPixmap Util::pixmap(const QString& iconName, IconTheme themeName) 202 { 203 return pixmap(iconName, themeName, QSize(32, 32)); 204 } 205 pixmap(const QString & iconName,IconTheme themeName,const QSize & size,bool keepAspectRatio)206 QPixmap Util::pixmap(const QString& iconName, IconTheme themeName, const QSize& size, bool keepAspectRatio) 207 { 208 const auto icon = Util::icon(iconName, themeName); 209 if(!icon.isNull()) 210 { 211 const auto pixmap = icon.pixmap(size); 212 if(!pixmap.isNull()) 213 { 214 const auto aspect = keepAspectRatio ? Qt::KeepAspectRatio : Qt::IgnoreAspectRatio; 215 return pixmap.scaled(size, aspect, Qt::SmoothTransformation); 216 } 217 } 218 219 return QPixmap(); 220 } 221 color(QPalette::ColorGroup colorGroup,QPalette::ColorRole colorRole)222 QColor Util::color(QPalette::ColorGroup colorGroup, QPalette::ColorRole colorRole) 223 { 224 return QApplication::palette().color(colorGroup, colorRole); 225 } 226 getBiggestScreen()227 QScreen* Util::getBiggestScreen() 228 { 229 const auto screens = QApplication::screens(); 230 const auto it = std::max_element(screens.cbegin(), 231 screens.cend(), 232 [](const auto* screen1, const auto* screen2) { 233 return (screen1->size().height() < screen2->size().height()); 234 }); 235 236 return (it != screens.end()) 237 ? *it 238 : nullptr; 239 } 240 placeInScreenCenter(QWidget * widget,float relativeSizeX,float relativeSizeY)241 void Util::placeInScreenCenter(QWidget* widget, float relativeSizeX, float relativeSizeY) 242 { 243 const auto* screen = getBiggestScreen(); 244 if(!screen) 245 { 246 return; 247 } 248 249 const auto width = screen->size().width(); 250 const auto height = screen->size().height(); 251 252 if(relativeSizeX < 0.1f || relativeSizeY < 0.1f) 253 { 254 relativeSizeX = 0.7f; 255 relativeSizeY = 0.7f; 256 } 257 258 const auto xRemainder = (1.0f - relativeSizeX) / 2.0f; 259 const auto yRemainder = (1.0f - relativeSizeY) / 2.0f; 260 261 const auto xAbs = std::max(0, static_cast<int>(width * xRemainder)) + screen->geometry().x(); 262 const auto yAbs = std::max(0, static_cast<int>(height * yRemainder)) + screen->geometry().y(); 263 auto wAbs = std::max(0, static_cast<int>(width * relativeSizeX)); 264 auto hAbs = std::max(0, static_cast<int>(height * relativeSizeY)); 265 266 if(wAbs == 0) 267 { 268 wAbs = 1200; 269 } 270 271 if(hAbs == 0) 272 { 273 hAbs = 800; 274 } 275 276 widget->setGeometry(xAbs, yAbs, wAbs, hAbs); 277 } 278 textWidth(const QFontMetrics & fm,const QString & text)279 int Util::textWidth(const QFontMetrics& fm, const QString& text) 280 { 281 #if QT_VERSION_MAJOR >= 5 && QT_VERSION_MINOR >= 11 282 return fm.horizontalAdvance(text); 283 #else 284 return fm.width(text); 285 #endif 286 } 287 textWidth(QWidget * widget,const QString & text)288 int Util::textWidth(QWidget* widget, const QString& text) 289 { 290 return textWidth(widget->fontMetrics(), text); 291 } 292 viewRowHeight()293 int Util::viewRowHeight() 294 { 295 return -1; 296 } 297 }