2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
4 * Copyright (C) 2019, 2021 Prince Gupta <jagannatharjun11@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * In addition, as a special exception, the copyright holders give permission to
22 * link this program with the OpenSSL project's "OpenSSL" library (or with
23 * modified versions of it that use the same license as the "OpenSSL" library),
24 * and distribute the linked executables. You must obey the GNU General Public
25 * License in all respects for all of the code used other than "OpenSSL". If
26 * you modify file(s), you may extend this exception to your version of the
27 * file(s), but you are not obligated to do so. If you do not wish to do so,
28 * delete this exception statement from your version.
31 #include "uithememanager.h"
34 #include <QPixmapCache>
37 #include "base/global.h"
38 #include "base/logger.h"
39 #include "base/path.h"
40 #include "base/preferences.h"
41 #include "uithemecommon.h"
47 const QPalette palette
= qApp
->palette();
48 const QColor
&color
= palette
.color(QPalette::Active
, QPalette::Base
);
49 return (color
.lightness() < 127);
53 UIThemeManager
*UIThemeManager::m_instance
= nullptr;
55 void UIThemeManager::freeInstance()
61 void UIThemeManager::initInstance()
64 m_instance
= new UIThemeManager
;
67 UIThemeManager::UIThemeManager()
68 : m_useCustomTheme
{Preferences::instance()->useCustomUITheme()}
69 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
70 , m_useSystemIcons
{Preferences::instance()->useSystemIcons()}
75 const Path themePath
= Preferences::instance()->customUIThemePath();
77 if (themePath
.hasExtension(u
".qbtheme"_s
))
79 if (QResource::registerResource(themePath
.data(), u
"/uitheme"_s
))
80 m_themeSource
= std::make_unique
<QRCThemeSource
>();
82 LogMsg(tr("Failed to load UI theme from file: \"%1\"").arg(themePath
.toString()), Log::WARNING
);
84 else if (themePath
.filename() == CONFIG_FILE_NAME
)
86 m_themeSource
= std::make_unique
<FolderThemeSource
>(themePath
.parentPath());
91 m_themeSource
= std::make_unique
<DefaultThemeSource
>();
100 UIThemeManager
*UIThemeManager::instance()
105 void UIThemeManager::applyStyleSheet() const
107 qApp
->setStyleSheet(QString::fromUtf8(m_themeSource
->readStyleSheet()));
110 QIcon
UIThemeManager::getIcon(const QString
&iconId
, [[maybe_unused
]] const QString
&fallback
) const
112 const auto colorMode
= isDarkTheme() ? ColorMode::Dark
: ColorMode::Light
;
113 auto &icons
= (colorMode
== ColorMode::Dark
) ? m_darkModeIcons
: m_icons
;
115 const auto iter
= icons
.find(iconId
);
116 if (iter
!= icons
.end())
119 #if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
120 // Don't cache system icons because users might change them at run time
121 if (m_useSystemIcons
)
123 auto icon
= QIcon::fromTheme(iconId
);
124 if (icon
.isNull() || icon
.availableSizes().isEmpty())
125 icon
= QIcon::fromTheme(fallback
, QIcon(m_themeSource
->getIconPath(iconId
, colorMode
).data()));
130 const QIcon icon
{m_themeSource
->getIconPath(iconId
, colorMode
).data()};
131 icons
[iconId
] = icon
;
135 QIcon
UIThemeManager::getFlagIcon(const QString
&countryIsoCode
) const
137 if (countryIsoCode
.isEmpty())
140 const QString key
= countryIsoCode
.toLower();
141 const auto iter
= m_flags
.find(key
);
142 if (iter
!= m_flags
.end())
145 const QIcon icon
{u
":/icons/flags/" + key
+ u
".svg"};
150 QPixmap
UIThemeManager::getScaledPixmap(const QString
&iconId
, const int height
) const
152 // (workaround) svg images require the use of `QIcon()` to load and scale losslessly,
153 // otherwise other image classes will convert it to pixmap first and follow-up scaling will become lossy.
155 Q_ASSERT(height
> 0);
157 const QString cacheKey
= iconId
+ u
'@' + QString::number(height
);
160 if (!QPixmapCache::find(cacheKey
, &pixmap
))
162 pixmap
= getIcon(iconId
).pixmap(height
);
163 QPixmapCache::insert(cacheKey
, pixmap
);
169 QColor
UIThemeManager::getColor(const QString
&id
) const
171 const QColor color
= m_themeSource
->getColor(id
, (isDarkTheme() ? ColorMode::Dark
: ColorMode::Light
));
172 Q_ASSERT(color
.isValid());
177 void UIThemeManager::applyPalette() const
179 struct ColorDescriptor
182 QPalette::ColorRole colorRole
;
183 QPalette::ColorGroup colorGroup
;
186 const ColorDescriptor paletteColorDescriptors
[] =
188 {u
"Palette.Window"_s
, QPalette::Window
, QPalette::Normal
},
189 {u
"Palette.WindowText"_s
, QPalette::WindowText
, QPalette::Normal
},
190 {u
"Palette.Base"_s
, QPalette::Base
, QPalette::Normal
},
191 {u
"Palette.AlternateBase"_s
, QPalette::AlternateBase
, QPalette::Normal
},
192 {u
"Palette.Text"_s
, QPalette::Text
, QPalette::Normal
},
193 {u
"Palette.ToolTipBase"_s
, QPalette::ToolTipBase
, QPalette::Normal
},
194 {u
"Palette.ToolTipText"_s
, QPalette::ToolTipText
, QPalette::Normal
},
195 {u
"Palette.BrightText"_s
, QPalette::BrightText
, QPalette::Normal
},
196 {u
"Palette.Highlight"_s
, QPalette::Highlight
, QPalette::Normal
},
197 {u
"Palette.HighlightedText"_s
, QPalette::HighlightedText
, QPalette::Normal
},
198 {u
"Palette.Button"_s
, QPalette::Button
, QPalette::Normal
},
199 {u
"Palette.ButtonText"_s
, QPalette::ButtonText
, QPalette::Normal
},
200 {u
"Palette.Link"_s
, QPalette::Link
, QPalette::Normal
},
201 {u
"Palette.LinkVisited"_s
, QPalette::LinkVisited
, QPalette::Normal
},
202 {u
"Palette.Light"_s
, QPalette::Light
, QPalette::Normal
},
203 {u
"Palette.Midlight"_s
, QPalette::Midlight
, QPalette::Normal
},
204 {u
"Palette.Mid"_s
, QPalette::Mid
, QPalette::Normal
},
205 {u
"Palette.Dark"_s
, QPalette::Dark
, QPalette::Normal
},
206 {u
"Palette.Shadow"_s
, QPalette::Shadow
, QPalette::Normal
},
207 {u
"Palette.WindowTextDisabled"_s
, QPalette::WindowText
, QPalette::Disabled
},
208 {u
"Palette.TextDisabled"_s
, QPalette::Text
, QPalette::Disabled
},
209 {u
"Palette.ToolTipTextDisabled"_s
, QPalette::ToolTipText
, QPalette::Disabled
},
210 {u
"Palette.BrightTextDisabled"_s
, QPalette::BrightText
, QPalette::Disabled
},
211 {u
"Palette.HighlightedTextDisabled"_s
, QPalette::HighlightedText
, QPalette::Disabled
},
212 {u
"Palette.ButtonTextDisabled"_s
, QPalette::ButtonText
, QPalette::Disabled
}
215 QPalette palette
= qApp
->palette();
216 for (const ColorDescriptor
&colorDescriptor
: paletteColorDescriptors
)
218 // For backward compatibility, the palette color overrides are read from the section of the "light mode" colors
219 const QColor newColor
= m_themeSource
->getColor(colorDescriptor
.id
, ColorMode::Light
);
220 if (newColor
.isValid())
221 palette
.setColor(colorDescriptor
.colorGroup
, colorDescriptor
.colorRole
, newColor
);
224 qApp
->setPalette(palette
);