Wireshark 4.7.2
The Wireshark network protocol analyzer
Loading...
Searching...
No Matches
theme_manager.h
Go to the documentation of this file.
1
9
10#ifndef THEME_MANAGER_H
11#define THEME_MANAGER_H
12
13#include <QColor>
14#include <QFont>
15#include <QHash>
16#include <QMutex>
17#include <QObject>
18#include <QPalette>
19#include <QString>
20
22
26struct ThemeInfo {
27 QString name;
28 QString internalName;
29 int version = 0;
30 QString description;
31 QString author;
32};
33
35 bool required;
36 QStringList tokens;
37};
38
40 QColor light;
41 QColor dark;
42};
43
74class ThemeManager : public QObject {
75 Q_OBJECT
76public:
77
87 enum class ThemeMode {
88 System,
89 Dark,
90 Light
91 };
92 Q_ENUM(ThemeMode)
93
94
109 enum class PreviewScheme {
110 Default,
111 PreferLight,
112 PreferDark
113 };
114 Q_ENUM(PreviewScheme)
115
116 enum ThemeToken {
117 // Brand
118 BrandPrimary,
119 BrandDeep,
120
121 // Accent
122 AccentSuccess,
123 AccentWarning,
124 AccentError,
125 AccentInfo,
126
127 // Expert
128 ExpertComment,
129 ExpertChat,
130 ExpertNote,
131 ExpertWarn,
132 ExpertError,
133 ExpertForeground,
134
135 // Packets — for each state, <Name> is the row background tint and
136 // <Name>Text is the foreground. Hidden is text-only by design (it
137 // dims an item that otherwise renders with the normal row bg).
138 // When a theme omits a Text token, ThemeTokenHandler derives it
139 // from contrastingText(<Name>) or PaletteText as appropriate.
140 PacketsSelection,
141 PacketsSelectionText,
142 PacketsInactive,
143 PacketsInactiveText,
144 PacketsMarked,
145 PacketsMarkedText,
146 PacketsIgnored,
147 PacketsIgnoredText,
148 PacketsHidden,
149
150 // Conversation — same fg/bg convention as Packets.
151 ConversationClient,
152 ConversationClientText,
153 ConversationServer,
154 ConversationServerText,
155
156 // Filter state (single color per state — use as bg tint; pair
157 // with QPalette::Text for foreground). Derived from accent
158 // when no explicit theme.filter override is set; the JSONC
159 // "filter" section lets a theme pin saturated/historical values
160 // that alpha-tinting the accent can't reach. FilterBusy and
161 // FilterBusyText carry the "I'm working" look used while a
162 // capture filter compiles off-thread.
163 FilterValid,
164 FilterInvalid,
165 FilterDeprecated,
166 FilterBusy,
167 FilterBusyText,
168
169 // Inline filter-affordance glyph colours (icon fills, not bg tints):
170 // the bookmark / clear / apply buttons inside the filter line. Each
171 // derives from the matching accent when a theme omits it (so every
172 // theme has them defined), and theme.filter.<name> overrides per-token.
173 // Display and capture bookmarks differ on purpose (blue vs green); the
174 // match colour marks a filter already saved.
175 FilterBookmark, // display-filter bookmark (← AccentInfo, blue)
176 FilterBookmarkCapture, // capture-filter bookmark (← AccentSuccess, green)
177 FilterBookmarkMatch, // current filter is saved (← AccentWarning, yellow)
178 FilterClear, // clear affordance (active) (← AccentError, red)
179 FilterApply, // apply affordance (← AccentInfo, blue)
180 FilterHistory, // recent-filters arrow, dimmed at rest (← PaletteMid);
181 // the default theme pins the classic Tango grays
182 // (#555753 / #d3d7cf) via theme.filter.history.
183
184 // Syntax highlighting — foreground text colours for code- and
185 // data-viewers (JSON, hex, Lua debugger, etc.). Derived so
186 // the variant is darker in light mode and lighter in dark
187 // mode, keeping enough contrast against PaletteBase.
188 SyntaxKey,
189 SyntaxString,
190 SyntaxNumber,
191
192 // Palette Overrides
193 PaletteWindow,
194 PaletteBase,
195 PaletteText,
196 PaletteWindowText,
197 PaletteAlternateBase,
198 PaletteMid,
199 PaletteMidLight,
200 // Selection foreground — when omitted, builder picks via
201 // contrastingText(brand.primary). Themes whose brand colour
202 // sits on the WCAG luminance threshold (e.g. saturated mid-tone
203 // teals/blues where contrastingText flips to black even though
204 // white reads better) can pin this explicitly to white.
205 PaletteHighlightedText,
206#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
207 PaletteAccent,
208#endif
209
210 // Header (derived from brand)
211 HeaderGradientStart,
212 HeaderGradientEnd,
213
214 // Section headers (derived from brand + QPalette)
215 SectionHeader,
216 SectionHeaderHover,
217
218 // Structural form chrome — borders, dividers, muted text.
219 // FieldBorder is the WCAG-enforced derivation of palette.mid
220 // against palette.base (≥ 3.0:1 ratio), used to frame
221 // interactive controls without overshooting like palette.shadow
222 // does in light mode. Separator is a softer mix of base + mid
223 // for hairlines between cards / sections; themes can override
224 // it via the JSONC "separator" top-level key when the derived
225 // value is too pronounced (Stratoshark uses an explicit value
226 // matching its midlight). MutedText is reserved for future
227 // use — no consumer in tree today, but kept in the enum so
228 // themes can grow into it without a binary-compat break.
229 FieldBorder,
230 Separator,
231 MutedText,
232
233 // Text on dark surfaces (derived from brand)
234 TextOnDark,
235 TextOnDarkMuted,
236
237 // Update bar (derived from accent.success)
238 UpdateGradientStart,
239 UpdateGradientEnd,
240 UpdateBorder,
241 UpdateText,
242 UpdateTextHighlight,
243 UpdateLink,
244 UpdateLinkHover,
245 UpdateLinkPressed,
246 UpdateButtonBg,
247 UpdateButtonHover,
248 UpdateButtonPressed,
249 UpdateButtonDisabledBg,
250 UpdateButtonDisabledText,
251 UpdateDismissHoverBg,
252 UpdateDismissPressedBg,
253
254 // Accent aliases (derived)
255 HighlightColorOrange,
256 HighlightColorGreen,
257
258 // Foreground colors for solid accent backgrounds — derived via
259 // contrastingText() so they pick black or white depending on
260 // the accent's WCAG luminance. Use these when a QSS rule
261 // paints text on top of an accent-coloured surface (the
262 // "Development Build" badge, the "Download Update" button,
263 // etc.) so the text stays readable across themes whose
264 // accents fall on different sides of the contrast threshold.
265 //
266 // NOTE: these are intentionally named `TextOn*` rather than
267 // `Accent*Text`. ThemeManager's section auto-grouping treats
268 // any enum name starting with "accent" as a required input in
269 // the "accent" JSONC section (theme_manager.cpp section loop),
270 // so `Accent*Text` derived tokens would make the parser demand
271 // them from every theme file. Following the existing
272 // `TextOnDark` precedent keeps them ungrouped.
273 TextOnSuccess,
274 TextOnWarning,
275 TextOnError,
276 TextOnInfo,
277
278 // None
279 NoRole
280 };
281 Q_ENUM(ThemeToken)
282
283 static ThemeManager* instance();
284
303 static QString defaultThemeName();
304
316 static QString resolveThemeName(const QString &name);
317
323 static void init(const QString &theme = QString());
324
325 void cleanup();
326
330 ThemeInfo info() const;
331
343 static QList<ThemeInfo> availableThemes();
344
353 QColor color(ThemeToken role) const;
354
355 bool colorIsAvailable(ThemeToken role) const;
356
380 QHash<ThemeToken, QColor> previewTheme(const QString &internalName,
381 PreviewScheme scheme) const;
382
397 bool validateThemeFile(const QString &filePath) const;
398
417 QString loadStyleSheet(const QString &name) const;
418
432 static QString styleSheet(const QString &name);
433
445 static void setValidationState(QWidget *w, const QString &state);
446
452 static bool isDark();
453
474 bool isDarkMode() const;
475
482 ThemeMode mode() const;
483
490 void setMode(ThemeMode mode);
491
502 QColor graphColor(int idx) const;
503
504 QColor graphDefaultColor() const;
505
511 qsizetype graphColorCount() const;
512
513signals:
514 void themeChanged();
515
516protected:
517 explicit ThemeManager(QObject *parent = nullptr);
519
520private:
521 static ThemeManager* instance_;
522 static QMutex mutex_;
523
524 ThemeInfo info_;
525
526 // Flattened token -> color value, one map per mode
527 QHash<ThemeManager::ThemeToken, ThemeColorPair> themeColors_;
528 QList<ThemeColorPair> graphColors_;
529
530 QHash<QString, ThemeSectionInfo> sections_;
531
532 // mapping caches for role and palette resolution
533 QHash<QString, ThemeToken> colorRoleCache_;
534 QHash<QString, QPalette::ColorRole> paletteRoleCache_;
535
536 // Light/dark selection: user's explicit choice plus the detector
537 // that tracks the OS preference when mode == System. The detector
538 // is a private member — external code never sees it. Lifetime is
539 // managed via Qt's parent-child ownership: constructed with `this`
540 // as parent, destroyed automatically with the ThemeManager.
541 ThemeMode mode_ = ThemeMode::System;
542 SystemThemeDetector *detector_ = nullptr;
543
544 // Pristine OS palette snapshot used as the baseline when the palette
545 // builder constructs a new theme palette. Captured once at ctor
546 // entry (before any setPalette() call could pollute QApplication's
547 // live palette), and refreshed from `qApp->style()->standardPalette()`
548 // whenever the effective light/dark scheme changes (mode flip or OS
549 // notification). Using this snapshot instead of
550 // QApplication::palette() prevents the previous theme's palette
551 // overrides from leaking into the next theme's baseline — without it,
552 // switching from a theme with palette overrides (e.g. "inverted") to
553 // one without (e.g. "default") would leave the prior overrides
554 // visible. Only consulted on platforms where the OS palette is
555 // trusted (macOS, Windows Qt ≥ 6.8); ignored elsewhere.
556 QPalette osBaseline_;
557
568 QPalette baselineForBuild() const;
569
576 void reapplyForSchemeChange();
577
583 static ThemeMode modeFromPrefs(int gui_color_scheme);
584
591 void applyToStyleHints();
592
599 void applyApplicationStyleSheet();
600
614 bool loadTheme(const QString &themeName = QString());
615
616};
617
618#endif /* THEME_MANAGER_H */
Definition system_theme_detector.h:38
static bool isDark()
Definition theme_manager.cpp:366
static void init(const QString &theme=QString())
Definition theme_manager.cpp:256
void setMode(ThemeMode mode)
Definition theme_manager.cpp:411
QColor graphColor(int idx) const
Returns the graph color for the given index, cycling through available graph colors if necessary.
Definition theme_manager.cpp:805
static QString styleSheet(const QString &name)
Definition theme_manager.cpp:604
PreviewScheme
Definition theme_manager.h:109
QString loadStyleSheet(const QString &name) const
Definition theme_manager.cpp:596
ThemeMode
Definition theme_manager.h:87
ThemeMode mode() const
Definition theme_manager.cpp:406
static QString defaultThemeName()
Definition theme_manager.cpp:228
QHash< ThemeToken, QColor > previewTheme(const QString &internalName, PreviewScheme scheme) const
Definition theme_manager.cpp:620
qsizetype graphColorCount() const
Returns the number of graph colors defined in the theme.
Definition theme_manager.cpp:832
bool isDarkMode() const
Definition theme_manager.cpp:371
static void setValidationState(QWidget *w, const QString &state)
Definition theme_manager.cpp:609
static QList< ThemeInfo > availableThemes()
Definition theme_manager.cpp:292
static QString resolveThemeName(const QString &name)
Definition theme_manager.cpp:244
bool validateThemeFile(const QString &filePath) const
Definition theme_manager.cpp:707
ThemeManager(QObject *parent=nullptr)
Definition theme_manager.cpp:88
ThemeInfo info() const
Definition theme_manager.cpp:287
QColor color(ThemeToken role) const
Definition theme_manager.cpp:518
Definition theme_manager.h:39
Definition theme_manager.h:26
int version
Schema version (currently 1).
Definition theme_manager.h:29
QString name
Display name, e.g. "Wireshark Default".
Definition theme_manager.h:27
QString author
Theme author or organization.
Definition theme_manager.h:31
QString description
One-line description shown in preferences.
Definition theme_manager.h:30
QString internalName
Internal name, e.g. "default".
Definition theme_manager.h:28
Definition theme_manager.h:34