1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | // |
5 | // W A R N I N G |
6 | // ------------- |
7 | // |
8 | // This file is not part of the Qt API. It exists purely as an |
9 | // implementation detail. This header file may change from version to |
10 | // version without notice, or even be removed. |
11 | // |
12 | // We mean it. |
13 | // |
14 | |
15 | #include "qgtk3json_p.h" |
16 | #include "qgtk3storage_p.h" |
17 | #include <qpa/qwindowsysteminterface.h> |
18 | |
19 | QT_BEGIN_NAMESPACE |
20 | |
21 | QGtk3Storage::QGtk3Storage() |
22 | { |
23 | m_interface.reset(p: new QGtk3Interface(this)); |
24 | #if QT_CONFIG(dbus) |
25 | m_portalInterface.reset(p: new QGtk3PortalInterface(this)); |
26 | #endif |
27 | populateMap(); |
28 | } |
29 | |
30 | /*! |
31 | \internal |
32 | \enum QGtk3Storage::SourceType |
33 | \brief This enum represents the type of a color source. |
34 | |
35 | \value Gtk Color is read from a GTK widget |
36 | \value Fixed A fixed brush is specified |
37 | \value Modified The color is a modification of another color (fixed or read from GTK) |
38 | \omitvalue Invalid |
39 | */ |
40 | |
41 | /*! |
42 | \internal |
43 | \brief Find a brush from a source. |
44 | |
45 | Returns a QBrush from a given \param source and a \param map of available brushes |
46 | to search from. |
47 | |
48 | A null QBrush is returned, if no brush corresponding to the source has been found. |
49 | */ |
50 | QBrush QGtk3Storage::brush(const Source &source, const BrushMap &map) const |
51 | { |
52 | switch (source.sourceType) { |
53 | case SourceType::Gtk: |
54 | return m_interface ? QBrush(m_interface->brush(wtype: source.gtk3.gtkWidgetType, |
55 | source: source.gtk3.source, state: source.gtk3.state)) |
56 | : QBrush(); |
57 | |
58 | case SourceType::Modified: { |
59 | // don't loop through modified sources, break if modified source not found |
60 | Source recSource = brush(brush: TargetBrush(source.rec.colorGroup, source.rec.colorRole, |
61 | source.rec.colorScheme), map); |
62 | |
63 | if (!recSource.isValid() || (recSource.sourceType == SourceType::Modified)) |
64 | return QBrush(); |
65 | |
66 | // Set brush and alter color |
67 | QBrush b = brush(source: recSource, map); |
68 | if (source.rec.width > 0 && source.rec.height > 0) |
69 | b.setTexture(QPixmap(source.rec.width, source.rec.height)); |
70 | QColor c = b.color().lighter(f: source.rec.lighter); |
71 | c = QColor((c.red() + source.rec.deltaRed), |
72 | (c.green() + source.rec.deltaGreen), |
73 | (c.blue() + source.rec.deltaBlue)); |
74 | b.setColor(c); |
75 | return b; |
76 | } |
77 | |
78 | case SourceType::Mixed: { |
79 | // check the mixing source to be valid and be a Gtk source |
80 | constexpr auto check_source = [](const Source &source) -> bool |
81 | { |
82 | return source.isValid() && (source.sourceType == SourceType::Gtk); |
83 | }; |
84 | |
85 | const Source source1 = brush(brush: TargetBrush(source.mix.sourceGroup, |
86 | source.mix.colorRole1), map); |
87 | if (!check_source(source1)) |
88 | return QBrush(); |
89 | |
90 | const Source source2 = brush(brush: TargetBrush(source.mix.sourceGroup, |
91 | source.mix.colorRole2), map); |
92 | if (!check_source(source2)) |
93 | return QBrush(); |
94 | |
95 | const QBrush brush2 = brush(source: source2, map); |
96 | // the output brush is a copy of the brush from the first source |
97 | QBrush brush1 = brush(source: source1, map); |
98 | // only color is mixed |
99 | brush1.setColor(MixSources::mixColors(color1: brush1.color(), color2: brush2.color())); |
100 | return brush1; |
101 | } |
102 | |
103 | case SourceType::Fixed: |
104 | return source.fix.fixedBrush; |
105 | |
106 | case SourceType::Invalid: |
107 | return QBrush(); |
108 | } |
109 | |
110 | // needed because of the scope after recursive |
111 | Q_UNREACHABLE(); |
112 | } |
113 | |
114 | /*! |
115 | \internal |
116 | \brief Recurse to find a source brush for modification. |
117 | |
118 | Returns the source specified by the target brush \param b in the \param map of brushes. |
119 | Takes dark/light/unknown into consideration. |
120 | Returns an empty brush if no suitable one can be found. |
121 | */ |
122 | QGtk3Storage::Source QGtk3Storage::brush(const TargetBrush &b, const BrushMap &map) const |
123 | { |
124 | #define FIND(brush) if (map.contains(brush))\ |
125 | return map.value(brush) |
126 | |
127 | // Return exact match |
128 | FIND(b); |
129 | |
130 | // unknown color scheme can find anything |
131 | if (b.colorScheme == Qt::ColorScheme::Unknown) { |
132 | FIND(TargetBrush(b, Qt::ColorScheme::Dark)); |
133 | FIND(TargetBrush(b, Qt::ColorScheme::Light)); |
134 | } |
135 | |
136 | // Color group All can always be found |
137 | if (b.colorGroup != QPalette::All) |
138 | return brush(b: TargetBrush(QPalette::All, b.colorRole, b.colorScheme), map); |
139 | |
140 | // Brush not found |
141 | return Source(); |
142 | #undef FIND |
143 | } |
144 | |
145 | /*! |
146 | \internal |
147 | \brief Returns a simple, hard coded base palette. |
148 | |
149 | Create a hard coded palette with default colors as a fallback for any color that can't be |
150 | obtained from GTK. |
151 | |
152 | \note This palette will be used as a default baseline for the system palette, which then |
153 | will be used as a default baseline for any other palette type. |
154 | */ |
155 | QPalette QGtk3Storage::standardPalette() |
156 | { |
157 | QColor backgroundColor(0xd4, 0xd0, 0xc8); |
158 | QColor lightColor(backgroundColor.lighter()); |
159 | QColor darkColor(backgroundColor.darker()); |
160 | const QBrush darkBrush(darkColor); |
161 | QColor midColor(Qt::gray); |
162 | QPalette palette(Qt::black, backgroundColor, lightColor, darkColor, |
163 | midColor, Qt::black, Qt::white); |
164 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::WindowText, brush: darkBrush); |
165 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::Text, brush: darkBrush); |
166 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::ButtonText, brush: darkBrush); |
167 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::Base, brush: QBrush(backgroundColor)); |
168 | return palette; |
169 | } |
170 | |
171 | /*! |
172 | \internal |
173 | \brief Return a GTK styled QPalette. |
174 | |
175 | Returns the pointer to a (cached) QPalette for \param type, with its brushes |
176 | populated according to the current GTK theme. |
177 | */ |
178 | const QPalette *QGtk3Storage::palette(QPlatformTheme::Palette type) const |
179 | { |
180 | if (type >= QPlatformTheme::NPalettes) |
181 | return nullptr; |
182 | |
183 | if (m_paletteCache[type].has_value()) { |
184 | qCDebug(lcQGtk3Interface) << "Returning palette from cache:" |
185 | << QGtk3Json::fromPalette(palette: type); |
186 | |
187 | return &m_paletteCache[type].value(); |
188 | } |
189 | |
190 | // Read system palette as a baseline first |
191 | if (!m_paletteCache[QPlatformTheme::SystemPalette].has_value() && type != QPlatformTheme::SystemPalette) |
192 | palette(); |
193 | |
194 | // Fall back to system palette for unknown types |
195 | if (!m_palettes.contains(key: type) && type != QPlatformTheme::SystemPalette) { |
196 | qCDebug(lcQGtk3Interface) << "Returning system palette for unknown type" |
197 | << QGtk3Json::fromPalette(palette: type); |
198 | return palette(); |
199 | } |
200 | |
201 | BrushMap brushes = m_palettes.value(key: type); |
202 | |
203 | // Standard palette is base for system palette. System palette is base for all others. |
204 | QPalette p = QPalette( type == QPlatformTheme::SystemPalette ? standardPalette() |
205 | : m_paletteCache[QPlatformTheme::SystemPalette].value()); |
206 | |
207 | qCDebug(lcQGtk3Interface) << "Creating palette:" << QGtk3Json::fromPalette(palette: type); |
208 | for (auto i = brushes.begin(); i != brushes.end(); ++i) { |
209 | Source source = i.value(); |
210 | |
211 | // Brush is set if |
212 | // - theme and source color scheme match |
213 | // - or either of them is unknown |
214 | const auto appSource = i.key().colorScheme; |
215 | const auto appTheme = colorScheme(); |
216 | const bool setBrush = (appSource == appTheme) || |
217 | (appSource == Qt::ColorScheme::Unknown) || |
218 | (appTheme == Qt::ColorScheme::Unknown); |
219 | |
220 | if (setBrush) { |
221 | p.setBrush(cg: i.key().colorGroup, cr: i.key().colorRole, brush: brush(source, map: brushes)); |
222 | } |
223 | } |
224 | |
225 | m_paletteCache[type].emplace(args&: p); |
226 | if (type == QPlatformTheme::SystemPalette) |
227 | qCDebug(lcQGtk3Interface) << "System Palette defined" << themeName() << colorScheme() << p; |
228 | |
229 | return &m_paletteCache[type].value(); |
230 | } |
231 | |
232 | /*! |
233 | \internal |
234 | \brief Return a GTK styled font. |
235 | |
236 | Returns a QFont of \param type, styled according to the current GTK theme. |
237 | */ |
238 | const QFont *QGtk3Storage::font(QPlatformTheme::Font type) const |
239 | { |
240 | if (m_fontCache[type].has_value()) |
241 | return &m_fontCache[type].value(); |
242 | |
243 | m_fontCache[type].emplace(args: m_interface->font(type)); |
244 | return &m_fontCache[type].value(); |
245 | } |
246 | |
247 | /*! |
248 | \internal |
249 | \brief Return a GTK styled standard pixmap if available. |
250 | |
251 | Returns a pixmap specified by \param standardPixmap and \param size. |
252 | Returns an empty pixmap if GTK doesn't support the requested one. |
253 | */ |
254 | QPixmap QGtk3Storage::standardPixmap(QPlatformTheme::StandardPixmap standardPixmap, |
255 | const QSizeF &size) const |
256 | { |
257 | if (m_pixmapCache.contains(key: standardPixmap)) |
258 | return QPixmap::fromImage(image: m_pixmapCache.object(key: standardPixmap)->scaled(s: size.toSize())); |
259 | |
260 | if (!m_interface) |
261 | return QPixmap(); |
262 | |
263 | QImage image = m_interface->standardPixmap(standardPixmap); |
264 | if (image.isNull()) |
265 | return QPixmap(); |
266 | |
267 | m_pixmapCache.insert(key: standardPixmap, object: new QImage(image)); |
268 | return QPixmap::fromImage(image: image.scaled(s: size.toSize())); |
269 | } |
270 | |
271 | /*! |
272 | \internal |
273 | \brief Returns a GTK styled file icon corresponding to \param fileInfo. |
274 | */ |
275 | QIcon QGtk3Storage::fileIcon(const QFileInfo &fileInfo) const |
276 | { |
277 | return m_interface ? m_interface->fileIcon(fileInfo) : QIcon(); |
278 | } |
279 | |
280 | /*! |
281 | \internal |
282 | \brief Clears all caches. |
283 | */ |
284 | void QGtk3Storage::clear() |
285 | { |
286 | m_colorScheme = Qt::ColorScheme::Unknown; |
287 | m_palettes.clear(); |
288 | for (auto &cache : m_paletteCache) |
289 | cache.reset(); |
290 | |
291 | for (auto &cache : m_fontCache) |
292 | cache.reset(); |
293 | } |
294 | |
295 | /*! |
296 | \internal |
297 | \brief Handles a theme change at runtime. |
298 | |
299 | Clear all caches, re-populate with current GTK theme and notify the window system interface. |
300 | This method is a callback for the theme change signal sent from GTK. |
301 | */ |
302 | void QGtk3Storage::handleThemeChange() |
303 | { |
304 | populateMap(); |
305 | QWindowSystemInterface::handleThemeChange(); |
306 | } |
307 | |
308 | /*! |
309 | \internal |
310 | \brief Populates a map with information about how to locate colors in GTK. |
311 | |
312 | This method creates a data structure to locate color information for each brush of a QPalette |
313 | within GTK. The structure can hold mapping information for each QPlatformTheme::Palette |
314 | enum value. If no specific mapping is stored for an enum value, the system palette is returned |
315 | instead of a specific one. If no mapping is stored for the system palette, it will fall back to |
316 | QGtk3Storage::standardPalette. |
317 | |
318 | The method will populate the data structure with a standard mapping, covering the following |
319 | palette types: |
320 | \list |
321 | \li QPlatformTheme::SystemPalette |
322 | \li QPlatformTheme::CheckBoxPalette |
323 | \li QPlatformTheme::RadioButtonPalette |
324 | \li QPlatformTheme::ComboBoxPalette |
325 | \li QPlatformTheme::GroupBoxPalette |
326 | \li QPlatformTheme::MenuPalette |
327 | \li QPlatformTheme::TextLineEditPalette |
328 | \endlist |
329 | |
330 | The method will check the environment variable {{QT_GUI_GTK_JSON_SAVE}}. If it points to a |
331 | valid path with write access, it will write the standard mapping into a Json file. |
332 | That Json file can be modified and/or extended. |
333 | The Json syntax is |
334 | - "QGtk3Palettes" (top level value) |
335 | - QPlatformTheme::Palette |
336 | - QPalette::ColorRole |
337 | - Qt::ColorScheme |
338 | - Qt::ColorGroup |
339 | - Source data |
340 | - Source Type |
341 | - [source data] |
342 | |
343 | If the environment variable {{QT_GUI_GTK_JSON_HARDCODED}} contains the keyword \c true, |
344 | all sources are converted to fixed sources. In that case, they contain the hard coded HexRGBA |
345 | values read from GTK. |
346 | |
347 | The method will also check the environment variable {{QT_GUI_GTK_JSON}}. If it points to a valid |
348 | Json file with read access, it will be parsed instead of creating a standard mapping. |
349 | Parsing errors will be printed out with qCInfo if the logging category {{qt.qpa.gtk}} is activated. |
350 | In case of a parsing error, the method will fall back to creating a standard mapping. |
351 | |
352 | \note |
353 | If a Json file contains only fixed brushes (e.g. exported with {{QT_GUI_GTK_JSON_HARDCODED=true}}), |
354 | no colors will be imported from GTK. |
355 | */ |
356 | void QGtk3Storage::populateMap() |
357 | { |
358 | static QString m_themeName; |
359 | |
360 | // Distiguish initialization, theme change or call without theme change |
361 | Qt::ColorScheme newColorScheme = Qt::ColorScheme::Unknown; |
362 | const QString newThemeName = themeName(); |
363 | |
364 | #if QT_CONFIG(dbus) |
365 | // Prefer color scheme we get from xdg-desktop-portal as this is what GNOME |
366 | // relies on these days |
367 | newColorScheme = m_portalInterface->colorScheme(); |
368 | #endif |
369 | |
370 | if (newColorScheme == Qt::ColorScheme::Unknown) { |
371 | // Derive color scheme from theme name |
372 | newColorScheme = newThemeName.contains(s: "dark"_L1 , cs: Qt::CaseInsensitive) |
373 | ? Qt::ColorScheme::Dark : m_interface->colorSchemeByColors(); |
374 | } |
375 | |
376 | if (m_themeName == newThemeName && m_colorScheme == newColorScheme) |
377 | return; |
378 | |
379 | clear(); |
380 | |
381 | if (m_themeName.isEmpty()) { |
382 | qCDebug(lcQGtk3Interface) << "GTK theme initialized:" << newThemeName << newColorScheme; |
383 | } else { |
384 | qCDebug(lcQGtk3Interface) << "GTK theme changed to:" << newThemeName << newColorScheme; |
385 | } |
386 | m_colorScheme = newColorScheme; |
387 | m_themeName = newThemeName; |
388 | |
389 | // create standard mapping or load from Json file? |
390 | const QString jsonInput = qEnvironmentVariable(varName: "QT_GUI_GTK_JSON" ); |
391 | if (!jsonInput.isEmpty()) { |
392 | if (load(filename: jsonInput)) { |
393 | return; |
394 | } else { |
395 | qWarning() << "Falling back to standard GTK mapping." ; |
396 | } |
397 | } |
398 | |
399 | createMapping(); |
400 | |
401 | const QString jsonOutput = qEnvironmentVariable(varName: "QT_GUI_GTK_JSON_SAVE" ); |
402 | if (!jsonOutput.isEmpty() && !save(filename: jsonOutput)) |
403 | qWarning() << "File" << jsonOutput << "could not be saved.\n" ; |
404 | } |
405 | |
406 | /*! |
407 | \internal |
408 | \brief Return a palette map for saving. |
409 | |
410 | This method returns the existing palette map, if the environment variable |
411 | {{QT_GUI_GTK_JSON_HARDCODED}} is not set or does not contain the keyword \c true. |
412 | If it contains the keyword \c true, it returns a palette map with all brush |
413 | sources converted to fixed sources. |
414 | */ |
415 | const QGtk3Storage::PaletteMap QGtk3Storage::savePalettes() const |
416 | { |
417 | const QString hard = qEnvironmentVariable(varName: "QT_GUI_GTK_JSON_HARDCODED" ); |
418 | if (!hard.contains(s: "true"_L1 , cs: Qt::CaseInsensitive)) |
419 | return m_palettes; |
420 | |
421 | // Json output is supposed to be readable without GTK connection |
422 | // convert palette map into hard coded brushes |
423 | PaletteMap map = m_palettes; |
424 | for (auto paletteIterator = map.begin(); paletteIterator != map.end(); |
425 | ++paletteIterator) { |
426 | QGtk3Storage::BrushMap &bm = paletteIterator.value(); |
427 | for (auto brushIterator = bm.begin(); brushIterator != bm.end(); |
428 | ++brushIterator) { |
429 | QGtk3Storage::Source &s = brushIterator.value(); |
430 | switch (s.sourceType) { |
431 | |
432 | // Read the brush and convert it into a fixed brush |
433 | case SourceType::Gtk: { |
434 | const QBrush fixedBrush = brush(source: s, map: bm); |
435 | s.fix.fixedBrush = fixedBrush; |
436 | s.sourceType = SourceType::Fixed; |
437 | } |
438 | break; |
439 | case SourceType::Fixed: |
440 | case SourceType::Modified: |
441 | case SourceType::Mixed: |
442 | case SourceType::Invalid: |
443 | break; |
444 | } |
445 | } |
446 | } |
447 | return map; |
448 | } |
449 | |
450 | /*! |
451 | \internal |
452 | \brief Saves current palette mapping to a \param filename with Json format \param f. |
453 | |
454 | Saves the current palette mapping into a QJson file, |
455 | taking {{QT_GUI_GTK_JSON_HARDCODED}} into consideration. |
456 | Returns \c true if saving was successful and \c false otherwise. |
457 | */ |
458 | bool QGtk3Storage::save(const QString &filename, QJsonDocument::JsonFormat f) const |
459 | { |
460 | return QGtk3Json::save(map: savePalettes(), fileName: filename, format: f); |
461 | } |
462 | |
463 | /*! |
464 | \internal |
465 | \brief Returns a QJsonDocument with current palette mapping. |
466 | |
467 | Saves the current palette mapping into a QJsonDocument, |
468 | taking {{QT_GUI_GTK_JSON_HARDCODED}} into consideration. |
469 | Returns \c true if saving was successful and \c false otherwise. |
470 | */ |
471 | QJsonDocument QGtk3Storage::save() const |
472 | { |
473 | return QGtk3Json::save(map: savePalettes()); |
474 | } |
475 | |
476 | /*! |
477 | \internal |
478 | \brief Loads palette mapping from Json file \param filename. |
479 | |
480 | Returns \c true if the file was successfully parsed and \c false otherwise. |
481 | */ |
482 | bool QGtk3Storage::load(const QString &filename) |
483 | { |
484 | return QGtk3Json::load(map&: m_palettes, fileName: filename); |
485 | } |
486 | |
487 | /*! |
488 | \internal |
489 | \brief Creates a standard palette mapping. |
490 | |
491 | The method creates a hard coded standard mapping, used if no external Json file |
492 | containing a valid mapping has been specified in the environment variable {{QT_GUI_GTK_JSON}}. |
493 | */ |
494 | void QGtk3Storage::createMapping() |
495 | { |
496 | // Hard code standard mapping |
497 | BrushMap map; |
498 | Source source; |
499 | |
500 | // Define a GTK source |
501 | #define GTK(wtype, colorSource, state)\ |
502 | source = Source(QGtk3Interface::QGtkWidget::gtk_ ##wtype,\ |
503 | QGtk3Interface::QGtkColorSource::colorSource, GTK_STATE_FLAG_ ##state) |
504 | |
505 | // Define a modified source |
506 | #define LIGHTER(group, role, lighter)\ |
507 | source = Source(QPalette::group, QPalette::role,\ |
508 | Qt::ColorScheme::Unknown, lighter) |
509 | #define MODIFY(group, role, red, green, blue)\ |
510 | source = Source(QPalette::group, QPalette::role,\ |
511 | Qt::ColorScheme::Unknown, red, green, blue) |
512 | |
513 | // Define fixed source |
514 | #define FIX(color) source = FixedSource(color); |
515 | |
516 | // Add the source to a target brush |
517 | // Use default Qt::ColorScheme::Unknown, if no color scheme was specified |
518 | #define ADD_2(group, role) map.insert(TargetBrush(QPalette::group, QPalette::role), source); |
519 | #define ADD_3(group, role, app) map.insert(TargetBrush(QPalette::group, QPalette::role,\ |
520 | Qt::ColorScheme::app), source); |
521 | #define ADD_X(x, group, role, app, FUNC, ...) FUNC |
522 | #define ADD(...) ADD_X(,##__VA_ARGS__, ADD_3(__VA_ARGS__), ADD_2(__VA_ARGS__)) |
523 | // Save target brushes to a palette type |
524 | #define SAVE(palette) m_palettes.insert(QPlatformTheme::palette, map) |
525 | // Clear brushes to start next palette |
526 | #define CLEAR map.clear() |
527 | |
528 | /* |
529 | Macro usage: |
530 | |
531 | 1. Define a source |
532 | GTK(QGtkWidget, QGtkColorSource, GTK_STATE_FLAG) |
533 | Fetch the color from a GtkWidget, related to a source and a state. |
534 | |
535 | LIGHTER(ColorGroup, ColorROle, lighter) |
536 | Use a color of the same QPalette related to ColorGroup and ColorRole. |
537 | Make the color lighter (if lighter >100) or darker (if lighter < 100) |
538 | |
539 | MODIFY(ColorGroup, ColorRole, red, green, blue) |
540 | Use a color of the same QPalette related to ColorGroup and ColorRole. |
541 | Modify it by adding red, green, blue. |
542 | |
543 | FIX(const QBrush &) |
544 | Use a fixed brush without querying GTK |
545 | |
546 | 2. Define the target |
547 | Use ADD(ColorGroup, ColorRole) to use the defined source for the |
548 | color group / role in the current palette. |
549 | |
550 | Use ADD(ColorGroup, ColorRole, ColorScheme) to use the defined source |
551 | only for a specific color scheme |
552 | |
553 | 3. Save mapping |
554 | Save the defined mappings for a specific palette. |
555 | If a mapping entry does not cover all color groups and roles of a palette, |
556 | the system palette will be used for the remaining values. |
557 | If the system palette does not have all combination of color groups and roles, |
558 | the remaining ones will be populated by a hard coded fusion-style like palette. |
559 | |
560 | 4. Clear mapping |
561 | Use CLEAR to clear the mapping and begin a new one. |
562 | */ |
563 | |
564 | |
565 | // System palette |
566 | { |
567 | // background color and calculate derivates |
568 | GTK(Default, Background, INSENSITIVE); |
569 | ADD(All, Window); |
570 | ADD(All, Button); |
571 | ADD(All, Base); |
572 | LIGHTER(Normal, Window, 125); |
573 | ADD(Normal, Light); |
574 | ADD(Inactive, Light); |
575 | LIGHTER(Normal, Window, 70); |
576 | ADD(Normal, Shadow); |
577 | LIGHTER(Normal, Window, 80); |
578 | ADD(Normal, Dark); |
579 | ADD(Inactive, Dark) |
580 | |
581 | GTK(button, Foreground, ACTIVE); |
582 | ADD(Inactive, WindowText); |
583 | |
584 | auto ADD_MIX = [&map](QPalette::ColorGroup targetGroup, |
585 | QPalette::ColorRole targetRole, |
586 | QPalette::ColorGroup sourceGroup, |
587 | QPalette::ColorRole role1, |
588 | QPalette::ColorRole role2) |
589 | { |
590 | const Source source{sourceGroup, role1, role2}; |
591 | map.insert(key: TargetBrush(targetGroup, targetRole), value: source); |
592 | }; |
593 | ADD_MIX(QPalette::Disabled, QPalette::Text, |
594 | QPalette::Normal, QPalette::Base, QPalette::Text); |
595 | ADD_MIX(QPalette::Disabled, QPalette::WindowText, |
596 | QPalette::Normal, QPalette::Window, QPalette::WindowText); |
597 | ADD_MIX(QPalette::Disabled, QPalette::ButtonText, |
598 | QPalette::Normal, QPalette::Button, QPalette::ButtonText); |
599 | |
600 | GTK(button, Text, NORMAL); |
601 | ADD(Inactive, ButtonText); |
602 | |
603 | // special background colors |
604 | GTK(Default, Background, SELECTED); |
605 | ADD(Disabled, Highlight); |
606 | ADD(Normal, Highlight); |
607 | ADD(Inactive, Highlight); |
608 | |
609 | GTK(entry, Foreground, SELECTED); |
610 | ADD(Normal, HighlightedText); |
611 | ADD(Inactive, HighlightedText); |
612 | |
613 | // text color and friends |
614 | GTK(entry, Text, NORMAL); |
615 | ADD(Normal, ButtonText); |
616 | ADD(Normal, WindowText); |
617 | ADD(Disabled, HighlightedText); |
618 | |
619 | GTK(Default, Text, NORMAL); |
620 | ADD(Normal, Text); |
621 | ADD(Inactive, Text); |
622 | ADD(Normal, HighlightedText); |
623 | LIGHTER(Normal, Base, 93); |
624 | ADD(All, AlternateBase); |
625 | |
626 | GTK(Default, Foreground, NORMAL); |
627 | MODIFY(Normal, Text, 100, 100, 100); |
628 | ADD(All, PlaceholderText, Light); |
629 | MODIFY(Normal, Text, -100, -100, -100); |
630 | ADD(All, PlaceholderText, Dark); |
631 | |
632 | // Light, midlight, dark, mid, shadow colors |
633 | LIGHTER(Normal, Button, 125); |
634 | ADD(All, Light) |
635 | LIGHTER(Normal, Button, 113); |
636 | ADD(All, Midlight) |
637 | LIGHTER(Normal, Button, 113); |
638 | ADD(All, Mid) |
639 | LIGHTER(Normal, Button, 87); |
640 | ADD(All, Dark) |
641 | LIGHTER(Normal, Button, 5); |
642 | ADD(All, Shadow) |
643 | |
644 | SAVE(SystemPalette); |
645 | CLEAR; |
646 | } |
647 | |
648 | // Label and TabBar Palette |
649 | { |
650 | GTK(entry, Text, NORMAL); |
651 | ADD(Normal, WindowText); |
652 | ADD(Inactive, WindowText); |
653 | |
654 | SAVE(LabelPalette); |
655 | SAVE(TabBarPalette); |
656 | CLEAR; |
657 | } |
658 | |
659 | // Checkbox and RadioButton Palette |
660 | { |
661 | GTK(button, Text, ACTIVE); |
662 | ADD(Normal, Base, Dark); |
663 | ADD(Inactive, WindowText, Dark); |
664 | |
665 | GTK(Default, Foreground, NORMAL); |
666 | ADD(All, Text); |
667 | |
668 | GTK(Default, Background, NORMAL); |
669 | ADD(All, Base); |
670 | |
671 | GTK(button, Text, NORMAL); |
672 | ADD(Normal, Base, Light); |
673 | ADD(Inactive, WindowText, Light); |
674 | |
675 | SAVE(CheckBoxPalette); |
676 | SAVE(RadioButtonPalette); |
677 | CLEAR; |
678 | } |
679 | |
680 | // ComboBox, GroupBox & Frame Palette |
681 | { |
682 | GTK(combo_box, Text, NORMAL); |
683 | ADD(Normal, ButtonText, Dark); |
684 | ADD(Normal, Text, Dark); |
685 | ADD(Inactive, WindowText, Dark); |
686 | |
687 | GTK(combo_box, Text, ACTIVE); |
688 | ADD(Normal, ButtonText, Light); |
689 | ADD(Normal, Text, Light); |
690 | ADD(Inactive, WindowText, Light); |
691 | |
692 | SAVE(ComboBoxPalette); |
693 | SAVE(GroupBoxPalette); |
694 | CLEAR; |
695 | } |
696 | |
697 | // MenuBar Palette |
698 | { |
699 | GTK(Default, Text, ACTIVE); |
700 | ADD(Normal, ButtonText); |
701 | SAVE(MenuPalette); |
702 | CLEAR; |
703 | } |
704 | |
705 | // LineEdit Palette |
706 | { |
707 | GTK(Default, Background, NORMAL); |
708 | ADD(All, Base); |
709 | SAVE(TextLineEditPalette); |
710 | CLEAR; |
711 | } |
712 | |
713 | #undef GTK |
714 | #undef REC |
715 | #undef FIX |
716 | #undef ADD |
717 | #undef ADD_2 |
718 | #undef ADD_3 |
719 | #undef ADD_X |
720 | #undef SAVE |
721 | #undef LOAD |
722 | } |
723 | |
724 | QT_END_NAMESPACE |
725 | |