Krita Source Code Documentation
Loading...
Searching...
No Matches
thememanager.cpp
Go to the documentation of this file.
1/* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2004-08-02
7 * Description : theme manager
8 *
9 * SPDX-FileCopyrightText: 2006-2011 Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 *
13 * ============================================================ */
14
15#include "thememanager.h"
16// Qt includes
17
18#include <QStringList>
19#include <QFileInfo>
20#include <QFile>
21#include <QApplication>
22#include <QPalette>
23#include <QColor>
24#include <QActionGroup>
25#include <QBitmap>
26#include <QPainter>
27#include <QPixmap>
28#include <QDate>
29#include <QScreen>
30#include <QMenu>
31#include <QMenuBar>
32#include <QStatusBar>
33#include <QDebug>
34#include <QAction>
35#include <QMessageBox>
36
37// KDE includes
38
39#include <klocalizedstring.h>
40#include <kcolorscheme.h>
41#include <kactioncollection.h>
42#include <KoResourcePaths.h>
43#include <kactionmenu.h>
44#include <kconfig.h>
45#include <kconfiggroup.h>
46
47// Calligra
48#include <kis_icon.h>
49#include <kis_config_notifier.h>
50
51#ifdef __APPLE__
52#include <QStyle>
53#endif
54
55namespace Digikam
56{
57
58// ---------------------------------------------------------------
59
60
62{
63public:
64
70
72 QMap<QString, QString> themeMap; // map<theme name, theme config path>
73
74 QActionGroup* themeMenuActionGroup;
75 KActionMenu* themeMenuAction;
76};
77
78ThemeManager::ThemeManager(const QString &theme, QObject *parent)
79 : QObject(parent)
80 , d(new ThemeManagerPriv)
81{
82 //qDebug() << "Creating theme manager with theme" << theme;
83 d->currentThemeName = theme;
85}
86
88{
89 delete d;
90}
91
93{
94 //qDebug() << "getting current themename";
95 QString themeName;
97
98 QAction* action = d->themeMenuActionGroup->checkedAction();
99 if (action) {
100 themeName = action->text().remove('&');
101 }
102
103 //qDebug() << "\tthemename from action" << themeName;
104 }
105 else if (!d->currentThemeName.isEmpty()) {
106
107 //qDebug() << "\tcurrent themename" << d->currentThemeName;
108 themeName = d->currentThemeName;
109 }
110 if (themeName.isEmpty()) {
111 //qDebug() << "\tfallback";
112 themeName = "Krita dark";
113 }
114 //qDebug() << "\tresult" << themeName;
115 return themeName;
116}
117
118void ThemeManager::setCurrentTheme(const QString& name)
119{
120 //qDebug() << "setCurrentTheme();" << d->currentThemeName << "to" << name;
121 d->currentThemeName = name;
122
124 QList<QAction*> list = d->themeMenuActionGroup->actions();
125 Q_FOREACH (QAction* action, list) {
126 if (action->text().remove('&') == name) {
127 action->setChecked(true);
128 }
129 }
130 }
132}
133
135{
136 if (currentThemeName() == "System") {
137 qApp->setPalette(QPalette());
138 Q_EMIT signalThemeChanged();
139 return;
140 }
141
142 //qDebug() << "slotChangePalette" << sender();
143
144 // We must clear the icon cache before the palette is changed. That way
145 // The widgets can change the icons properly when they receive the
146 // PaletteChange event if needed.
148
149 QString theme(currentThemeName());
150 QString filename = d->themeMap.value(theme);
151 KSharedConfigPtr config = KSharedConfig::openConfig(filename);
152
153 QPalette palette = qApp->palette();
154 QPalette::ColorGroup states[3] = { QPalette::Active, QPalette::Inactive, QPalette::Disabled };
155 // TT thinks tooltips shouldn't use active, so we use our active colors for all states
156 KColorScheme schemeTooltip(QPalette::Active, KColorScheme::Tooltip, config);
157
158 for ( int i = 0; i < 3 ; ++i ) {
159
160 QPalette::ColorGroup state = states[i];
161 KColorScheme schemeView(state, KColorScheme::View, config);
162 KColorScheme schemeWindow(state, KColorScheme::Window, config);
163 KColorScheme schemeButton(state, KColorScheme::Button, config);
164 KColorScheme schemeSelection(state, KColorScheme::Selection, config);
165
166 palette.setBrush(state, QPalette::WindowText, schemeWindow.foreground());
167 palette.setBrush(state, QPalette::Window, schemeWindow.background());
168 palette.setBrush(state, QPalette::Base, schemeView.background());
169 palette.setBrush(state, QPalette::Text, schemeView.foreground());
170 palette.setBrush(state, QPalette::Button, schemeButton.background());
171 palette.setBrush(state, QPalette::ButtonText, schemeButton.foreground());
172 palette.setBrush(state, QPalette::Highlight, schemeSelection.background());
173 palette.setBrush(state, QPalette::HighlightedText, schemeSelection.foreground());
174 palette.setBrush(state, QPalette::ToolTipBase, schemeTooltip.background());
175 palette.setBrush(state, QPalette::ToolTipText, schemeTooltip.foreground());
176
177 palette.setColor(state, QPalette::Light, schemeWindow.shade(KColorScheme::LightShade));
178 palette.setColor(state, QPalette::Midlight, schemeWindow.shade(KColorScheme::MidlightShade));
179 palette.setColor(state, QPalette::Mid, schemeWindow.shade(KColorScheme::MidShade));
180 palette.setColor(state, QPalette::Dark, schemeWindow.shade(KColorScheme::DarkShade));
181 palette.setColor(state, QPalette::Shadow, schemeWindow.shade(KColorScheme::ShadowShade));
182
183 palette.setBrush(state, QPalette::AlternateBase, schemeView.background(KColorScheme::AlternateBackground));
184 palette.setBrush(state, QPalette::Link, schemeView.foreground(KColorScheme::LinkText));
185 palette.setBrush(state, QPalette::LinkVisited, schemeView.foreground(KColorScheme::VisitedText));
186 }
187
188 //qDebug() << ">>>>>>>>>>>>>>>>>> going to set palette on app" << theme;
189 // hint for the style to synchronize the color scheme with the window manager/compositor
190 qApp->setProperty("KDE_COLOR_SCHEME_PATH", filename);
191 qApp->setPalette(palette);
193
194 Q_EMIT signalThemeChanged();
195}
196
197void ThemeManager::setThemeMenuAction(KActionMenu* const action)
198{
199 d->themeMenuAction = action;
201}
202
204{
205 if (!d->themeMenuAction) return;
206 actionCollection->addAction("theme_menu", d->themeMenuAction);
207}
208
210{
211 if (!d->themeMenuAction) return;
212
213 d->themeMenuAction->menu()->clear();
214 delete d->themeMenuActionGroup;
215
216 d->themeMenuActionGroup = new QActionGroup(d->themeMenuAction);
217 connect(d->themeMenuActionGroup, SIGNAL(triggered(QAction*)),
218 this, SLOT(slotChangePalette()));
219
220 QAction * action;
221 QStringList schemeFiles = KoResourcePaths::findAllAssets("data", "color-schemes/*.colors");
222 schemeFiles += KoResourcePaths::findAllAssets("genericdata", "color-schemes/*.colors");
223
224 QMap<QString, QAction*> actionMap;
225 for (int i = 0; i < schemeFiles.size(); ++i) {
226 const QString filename = schemeFiles.at(i);
227 const QFileInfo info(filename);
228 KSharedConfigPtr config = KSharedConfig::openConfig(filename);
229 QIcon icon = createSchemePreviewIcon(config);
230 KConfigGroup group(config, "General");
231 const QString name = group.readEntry("Name", info.completeBaseName());
232 action = new QAction(name, d->themeMenuActionGroup);
233 action->setIcon(icon);
234 action->setCheckable(true);
235 actionMap.insert(name, action);
236 }
237
238#ifdef Q_OS_MAC
239 // Add a "System" theme, which resets the palette to system colors
240 // It only seems to work as expected on macOS.
241 action = new QAction("System", d->themeMenuActionGroup);
242 action->setCheckable(true);
243 actionMap.insert("System", action);
244#endif
245
246 // sort the list
247 QStringList actionMapKeys = actionMap.keys();
248 actionMapKeys.sort();
249
250 Q_FOREACH (const QString& name, actionMapKeys) {
251 if ( name == currentThemeName()) {
252 actionMap.value(name)->setChecked(true);
253 }
254 d->themeMenuAction->addAction(actionMap.value(name));
255 }
256}
257
258QPixmap ThemeManager::createSchemePreviewIcon(const KSharedConfigPtr& config)
259{
260 // code taken from kdebase/workspace/kcontrol/colors/colorscm.cpp
261 const uchar bits1[] = { 0xff, 0xff, 0xff, 0x2c, 0x16, 0x0b };
262 const uchar bits2[] = { 0x68, 0x34, 0x1a, 0xff, 0xff, 0xff };
263 const QSize bitsSize(24, 2);
264 const QBitmap b1 = QBitmap::fromData(bitsSize, bits1);
265 const QBitmap b2 = QBitmap::fromData(bitsSize, bits2);
266
267 QPixmap pixmap(23, 16);
268 pixmap.fill(Qt::black); // FIXME use some color other than black for borders?
269
270 KConfigGroup group(config, "WM");
271 QPainter p(&pixmap);
272 KColorScheme windowScheme(QPalette::Active, KColorScheme::Window, config);
273 p.fillRect(1, 1, 7, 7, windowScheme.background());
274 p.fillRect(2, 2, 5, 2, QBrush(windowScheme.foreground().color(), b1));
275
276 KColorScheme buttonScheme(QPalette::Active, KColorScheme::Button, config);
277 p.fillRect(8, 1, 7, 7, buttonScheme.background());
278 p.fillRect(9, 2, 5, 2, QBrush(buttonScheme.foreground().color(), b1));
279
280 p.fillRect(15, 1, 7, 7, group.readEntry("activeBackground", QColor(96, 148, 207)));
281 p.fillRect(16, 2, 5, 2, QBrush(group.readEntry("activeForeground", QColor(255, 255, 255)), b1));
282
283 KColorScheme viewScheme(QPalette::Active, KColorScheme::View, config);
284 p.fillRect(1, 8, 7, 7, viewScheme.background());
285 p.fillRect(2, 12, 5, 2, QBrush(viewScheme.foreground().color(), b2));
286
287 KColorScheme selectionScheme(QPalette::Active, KColorScheme::Selection, config);
288 p.fillRect(8, 8, 7, 7, selectionScheme.background());
289 p.fillRect(9, 12, 5, 2, QBrush(selectionScheme.foreground().color(), b2));
290
291 p.fillRect(15, 8, 7, 7, group.readEntry("inactiveBackground", QColor(224, 223, 222)));
292 p.fillRect(16, 12, 5, 2, QBrush(group.readEntry("inactiveForeground", QColor(20, 19, 18)), b2));
293
294 p.end();
295 return pixmap;
296}
297
299{
300 QStringList schemeFiles = KoResourcePaths::findAllAssets("data", "color-schemes/*.colors");
301 schemeFiles += KoResourcePaths::findAllAssets("genericdata", "color-schemes/*.colors");
302
303 for (int i = 0; i < schemeFiles.size(); ++i) {
304 const QString filename = schemeFiles.at(i);
305 const QFileInfo info(filename);
306 KSharedConfigPtr config = KSharedConfig::openConfig(filename);
307 KConfigGroup group(config, "General");
308 const QString name = group.readEntry("Name", info.completeBaseName());
309 d->themeMap.insert(name, filename);
310 }
311
312
313}
314
315} // namespace Digikam
const Params2D p
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
ThemeManagerPriv *const d
void setThemeMenuAction(KActionMenu *const action)
void setCurrentTheme(const QString &name)
QPixmap createSchemePreviewIcon(const KSharedConfigPtr &config)
QString currentThemeName() const
ThemeManager(const QString &theme="", QObject *parent=0)
ThemeManager.
void registerThemeActions(KisKActionCollection *actionCollection)
QBrush background(BackgroundRole=NormalBackground) const
QColor shade(ShadeRole) const
QBrush foreground(ForegroundRole=NormalText) const
static KisConfigNotifier * instance()
void notifyColorThemeChanged(const QString &filename)
A container for a set of QAction objects.
Q_INVOKABLE QAction * addAction(const QString &name, QAction *action)
static QStringList findAllAssets(const QString &type, const QString &filter=QString(), SearchOptions options=NoSearchOptions)
rgba palette[MAX_PALETTE]
Definition palette.c:35