/src/serenity/Userland/Libraries/LibGfx/SystemTheme.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org> |
4 | | * Copyright (c) 2022, Filiph Sandström <filiph.sandstrom@filfatstudios.com> |
5 | | * |
6 | | * SPDX-License-Identifier: BSD-2-Clause |
7 | | */ |
8 | | |
9 | | #pragma once |
10 | | |
11 | | #include <AK/ByteString.h> |
12 | | #include <AK/Forward.h> |
13 | | #include <AK/Types.h> |
14 | | #include <AK/Vector.h> |
15 | | #include <LibCore/AnonymousBuffer.h> |
16 | | #include <LibCore/ConfigFile.h> |
17 | | #include <LibGfx/Color.h> |
18 | | #include <LibGfx/TextAlignment.h> |
19 | | |
20 | | namespace Gfx { |
21 | | |
22 | | #define ENUMERATE_COLOR_ROLES(C) \ |
23 | | C(Accent) \ |
24 | | C(ActiveLink) \ |
25 | | C(ActiveWindowBorder1) \ |
26 | | C(ActiveWindowBorder2) \ |
27 | | C(ActiveWindowTitle) \ |
28 | | C(ActiveWindowTitleShadow) \ |
29 | | C(ActiveWindowTitleStripes) \ |
30 | | C(Base) \ |
31 | | C(BaseText) \ |
32 | | C(Black) \ |
33 | | C(Blue) \ |
34 | | C(BrightBlack) \ |
35 | | C(BrightBlue) \ |
36 | | C(BrightCyan) \ |
37 | | C(BrightGreen) \ |
38 | | C(BrightMagenta) \ |
39 | | C(BrightRed) \ |
40 | | C(BrightWhite) \ |
41 | | C(BrightYellow) \ |
42 | | C(Button) \ |
43 | | C(ButtonText) \ |
44 | | C(ColorSchemeBackground) \ |
45 | | C(ColorSchemeForeground) \ |
46 | | C(Cyan) \ |
47 | | C(DisabledTextFront) \ |
48 | | C(DisabledTextBack) \ |
49 | | C(DesktopBackground) \ |
50 | | C(FocusOutline) \ |
51 | | C(Green) \ |
52 | | C(Gutter) \ |
53 | | C(GutterBorder) \ |
54 | | C(HighlightWindowBorder1) \ |
55 | | C(HighlightWindowBorder2) \ |
56 | | C(HighlightWindowTitle) \ |
57 | | C(HighlightWindowTitleShadow) \ |
58 | | C(HighlightWindowTitleStripes) \ |
59 | | C(HighlightSearching) \ |
60 | | C(HighlightSearchingText) \ |
61 | | C(HoverHighlight) \ |
62 | | C(InactiveSelection) \ |
63 | | C(InactiveSelectionText) \ |
64 | | C(InactiveWindowBorder1) \ |
65 | | C(InactiveWindowBorder2) \ |
66 | | C(InactiveWindowTitle) \ |
67 | | C(InactiveWindowTitleShadow) \ |
68 | | C(InactiveWindowTitleStripes) \ |
69 | | C(Link) \ |
70 | | C(Magenta) \ |
71 | | C(MenuBase) \ |
72 | | C(MenuBaseText) \ |
73 | | C(MenuSelection) \ |
74 | | C(MenuSelectionText) \ |
75 | | C(MenuStripe) \ |
76 | | C(MovingWindowBorder1) \ |
77 | | C(MovingWindowBorder2) \ |
78 | | C(MovingWindowTitle) \ |
79 | | C(MovingWindowTitleShadow) \ |
80 | | C(MovingWindowTitleStripes) \ |
81 | | C(OverlayText) \ |
82 | | C(OverlayBackground) \ |
83 | | C(PlaceholderText) \ |
84 | | C(Red) \ |
85 | | C(RubberBandBorder) \ |
86 | | C(RubberBandFill) \ |
87 | | C(Ruler) \ |
88 | | C(RulerActiveText) \ |
89 | | C(RulerBorder) \ |
90 | | C(RulerInactiveText) \ |
91 | | C(Selection) \ |
92 | | C(SelectionText) \ |
93 | | C(SyntaxComment) \ |
94 | | C(SyntaxControlKeyword) \ |
95 | | C(SyntaxIdentifier) \ |
96 | | C(SyntaxKeyword) \ |
97 | | C(SyntaxNumber) \ |
98 | | C(SyntaxOperator) \ |
99 | | C(SyntaxPreprocessorStatement) \ |
100 | | C(SyntaxPreprocessorValue) \ |
101 | | C(SyntaxPunctuation) \ |
102 | | C(SyntaxString) \ |
103 | | C(SyntaxType) \ |
104 | | C(SyntaxFunction) \ |
105 | | C(SyntaxVariable) \ |
106 | | C(SyntaxCustomType) \ |
107 | | C(SyntaxNamespace) \ |
108 | | C(SyntaxMember) \ |
109 | | C(SyntaxParameter) \ |
110 | | C(TextCursor) \ |
111 | | C(ThreedHighlight) \ |
112 | | C(ThreedShadow1) \ |
113 | | C(ThreedShadow2) \ |
114 | | C(Tooltip) \ |
115 | | C(TooltipText) \ |
116 | | C(Tray) \ |
117 | | C(TrayText) \ |
118 | | C(VisitedLink) \ |
119 | | C(White) \ |
120 | | C(Window) \ |
121 | | C(WindowText) \ |
122 | | C(Yellow) |
123 | | |
124 | | #define ENUMERATE_ALIGNMENT_ROLES(C) \ |
125 | | C(TitleAlignment) |
126 | | |
127 | | #define ENUMERATE_WINDOW_THEME_ROLES(C) \ |
128 | | C(WindowTheme) |
129 | | |
130 | | #define ENUMERATE_FLAG_ROLES(C) \ |
131 | | C(BoldTextAsBright) \ |
132 | | C(IsDark) \ |
133 | | C(TitleButtonsIconOnly) |
134 | | |
135 | | #define ENUMERATE_METRIC_ROLES(C) \ |
136 | | C(BorderThickness) \ |
137 | | C(BorderRadius) \ |
138 | | C(TitleHeight) \ |
139 | | C(TitleButtonWidth) \ |
140 | | C(TitleButtonHeight) \ |
141 | | C(TitleButtonInactiveAlpha) |
142 | | |
143 | | #define ENUMERATE_PATH_ROLES(C) \ |
144 | | C(TitleButtonIcons) \ |
145 | | C(InactiveWindowShadow) \ |
146 | | C(ActiveWindowShadow) \ |
147 | | C(TaskbarShadow) \ |
148 | | C(MenuShadow) \ |
149 | | C(TooltipShadow) \ |
150 | | C(ColorScheme) \ |
151 | | C(OverlayRectShadow) |
152 | | |
153 | | enum class ColorRole { |
154 | | NoRole, |
155 | | |
156 | | #undef __ENUMERATE_COLOR_ROLE |
157 | | #define __ENUMERATE_COLOR_ROLE(role) role, |
158 | | ENUMERATE_COLOR_ROLES(__ENUMERATE_COLOR_ROLE) |
159 | | #undef __ENUMERATE_COLOR_ROLE |
160 | | |
161 | | __Count, |
162 | | |
163 | | Background = Window, |
164 | | DisabledText = ThreedShadow1, |
165 | | }; |
166 | | |
167 | | inline StringView to_string(ColorRole role) |
168 | 0 | { |
169 | 0 | switch (role) { |
170 | 0 | case ColorRole::NoRole: |
171 | 0 | return "NoRole"sv; |
172 | 0 | #undef __ENUMERATE_COLOR_ROLE |
173 | 0 | #define __ENUMERATE_COLOR_ROLE(role) \ |
174 | 0 | case ColorRole::role: \ |
175 | 0 | return #role##sv; |
176 | 0 | ENUMERATE_COLOR_ROLES(__ENUMERATE_COLOR_ROLE) |
177 | 0 | #undef __ENUMERATE_COLOR_ROLE |
178 | 0 | default: |
179 | 0 | VERIFY_NOT_REACHED(); |
180 | 0 | } |
181 | 0 | } |
182 | | |
183 | | enum class AlignmentRole { |
184 | | NoRole, |
185 | | |
186 | | #undef __ENUMERATE_ALIGNMENT_ROLE |
187 | | #define __ENUMERATE_ALIGNMENT_ROLE(role) role, |
188 | | ENUMERATE_ALIGNMENT_ROLES(__ENUMERATE_ALIGNMENT_ROLE) |
189 | | #undef __ENUMERATE_ALIGNMENT_ROLE |
190 | | |
191 | | __Count, |
192 | | }; |
193 | | |
194 | | inline StringView to_string(AlignmentRole role) |
195 | 0 | { |
196 | 0 | switch (role) { |
197 | 0 | case AlignmentRole::NoRole: |
198 | 0 | return "NoRole"sv; |
199 | 0 | #undef __ENUMERATE_ALIGNMENT_ROLE |
200 | 0 | #define __ENUMERATE_ALIGNMENT_ROLE(role) \ |
201 | 0 | case AlignmentRole::role: \ |
202 | 0 | return #role##sv; |
203 | 0 | ENUMERATE_ALIGNMENT_ROLES(__ENUMERATE_ALIGNMENT_ROLE) |
204 | 0 | #undef __ENUMERATE_ALIGNMENT_ROLE |
205 | 0 | default: |
206 | 0 | VERIFY_NOT_REACHED(); |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | | enum class WindowThemeRole { |
211 | | NoRole, |
212 | | |
213 | | #undef __ENUMERATE_WINDOW_THEME_ROLE |
214 | | #define __ENUMERATE_WINDOW_THEME_ROLE(role) role, |
215 | | ENUMERATE_WINDOW_THEME_ROLES(__ENUMERATE_WINDOW_THEME_ROLE) |
216 | | #undef __ENUMERATE_WINDOW_THEME_ROLE |
217 | | |
218 | | __Count, |
219 | | }; |
220 | | |
221 | | inline StringView to_string(WindowThemeRole role) |
222 | 0 | { |
223 | 0 | switch (role) { |
224 | 0 | case WindowThemeRole::NoRole: |
225 | 0 | return "NoRole"sv; |
226 | 0 | #undef __ENUMERATE_ALIGNMENT_ROLE |
227 | 0 | #define __ENUMERATE_ALIGNMENT_ROLE(role) \ |
228 | 0 | case WindowThemeRole::role: \ |
229 | 0 | return #role##sv; |
230 | 0 | ENUMERATE_WINDOW_THEME_ROLES(__ENUMERATE_ALIGNMENT_ROLE) |
231 | 0 | #undef __ENUMERATE_ALIGNMENT_ROLE |
232 | 0 | default: |
233 | 0 | VERIFY_NOT_REACHED(); |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | enum class FlagRole { |
238 | | NoRole, |
239 | | |
240 | | #undef __ENUMERATE_FLAG_ROLE |
241 | | #define __ENUMERATE_FLAG_ROLE(role) role, |
242 | | ENUMERATE_FLAG_ROLES(__ENUMERATE_FLAG_ROLE) |
243 | | #undef __ENUMERATE_FLAG_ROLE |
244 | | |
245 | | __Count, |
246 | | }; |
247 | | |
248 | | inline StringView to_string(FlagRole role) |
249 | 0 | { |
250 | 0 | switch (role) { |
251 | 0 | case FlagRole::NoRole: |
252 | 0 | return "NoRole"sv; |
253 | 0 | #undef __ENUMERATE_FLAG_ROLE |
254 | 0 | #define __ENUMERATE_FLAG_ROLE(role) \ |
255 | 0 | case FlagRole::role: \ |
256 | 0 | return #role##sv; |
257 | 0 | ENUMERATE_FLAG_ROLES(__ENUMERATE_FLAG_ROLE) |
258 | 0 | #undef __ENUMERATE_FLAG_ROLE |
259 | 0 | default: |
260 | 0 | VERIFY_NOT_REACHED(); |
261 | 0 | } |
262 | 0 | } |
263 | | |
264 | | enum class MetricRole { |
265 | | NoRole, |
266 | | |
267 | | #undef __ENUMERATE_METRIC_ROLE |
268 | | #define __ENUMERATE_METRIC_ROLE(role) role, |
269 | | ENUMERATE_METRIC_ROLES(__ENUMERATE_METRIC_ROLE) |
270 | | #undef __ENUMERATE_METRIC_ROLE |
271 | | |
272 | | __Count, |
273 | | }; |
274 | | |
275 | | inline StringView to_string(MetricRole role) |
276 | 0 | { |
277 | 0 | switch (role) { |
278 | 0 | case MetricRole::NoRole: |
279 | 0 | return "NoRole"sv; |
280 | 0 | #undef __ENUMERATE_METRIC_ROLE |
281 | 0 | #define __ENUMERATE_METRIC_ROLE(role) \ |
282 | 0 | case MetricRole::role: \ |
283 | 0 | return #role##sv; |
284 | 0 | ENUMERATE_METRIC_ROLES(__ENUMERATE_METRIC_ROLE) |
285 | 0 | #undef __ENUMERATE_METRIC_ROLE |
286 | 0 | default: |
287 | 0 | VERIFY_NOT_REACHED(); |
288 | 0 | } |
289 | 0 | } |
290 | | |
291 | | enum class PathRole { |
292 | | NoRole, |
293 | | |
294 | | #undef __ENUMERATE_PATH_ROLE |
295 | | #define __ENUMERATE_PATH_ROLE(role) role, |
296 | | ENUMERATE_PATH_ROLES(__ENUMERATE_PATH_ROLE) |
297 | | #undef __ENUMERATE_PATH_ROLE |
298 | | |
299 | | __Count, |
300 | | }; |
301 | | |
302 | | inline StringView to_string(PathRole role) |
303 | 0 | { |
304 | 0 | switch (role) { |
305 | 0 | case PathRole::NoRole: |
306 | 0 | return "NoRole"sv; |
307 | 0 | #undef __ENUMERATE_PATH_ROLE |
308 | 0 | #define __ENUMERATE_PATH_ROLE(role) \ |
309 | 0 | case PathRole::role: \ |
310 | 0 | return #role##sv; |
311 | 0 | ENUMERATE_PATH_ROLES(__ENUMERATE_PATH_ROLE) |
312 | 0 | #undef __ENUMERATE_PATH_ROLE |
313 | 0 | default: |
314 | 0 | VERIFY_NOT_REACHED(); |
315 | 0 | } |
316 | 0 | } |
317 | | |
318 | | #define ENUMERATE_WINDOW_THEMES(M) \ |
319 | | M(Classic) \ |
320 | | M(RedmondGlass) \ |
321 | | M(RedmondPlastic) |
322 | | |
323 | | enum class WindowThemeProvider { |
324 | | #define __ENUMERATE(x) x, |
325 | | ENUMERATE_WINDOW_THEMES(__ENUMERATE) |
326 | | #undef __ENUMERATE |
327 | | }; |
328 | | |
329 | | inline Optional<WindowThemeProvider> window_theme_provider_from_string(StringView string) |
330 | 0 | { |
331 | 0 | #define __ENUMERATE(x) \ |
332 | 0 | if (string == #x) \ |
333 | 0 | return WindowThemeProvider::x; |
334 | 0 | ENUMERATE_WINDOW_THEMES(__ENUMERATE) |
335 | 0 | #undef __ENUMERATE |
336 | 0 | return {}; |
337 | 0 | } |
338 | | |
339 | | inline char const* to_string(WindowThemeProvider window_theme_provider) |
340 | 0 | { |
341 | 0 | #define __ENUMERATE(x) \ |
342 | 0 | if (window_theme_provider == WindowThemeProvider::x) \ |
343 | 0 | return #x; |
344 | 0 | ENUMERATE_WINDOW_THEMES(__ENUMERATE) |
345 | 0 | #undef __ENUMERATE |
346 | 0 | return {}; |
347 | 0 | } |
348 | | |
349 | | struct SystemTheme { |
350 | | ARGB32 color[(int)ColorRole::__Count]; |
351 | | Gfx::TextAlignment alignment[(int)AlignmentRole::__Count]; |
352 | | WindowThemeProvider window_theme[(int)WindowThemeRole::__Count]; |
353 | | bool flag[(int)FlagRole::__Count]; |
354 | | int metric[(int)MetricRole::__Count]; |
355 | | char path[(int)PathRole::__Count][256]; // TODO: PATH_MAX? |
356 | | }; |
357 | | |
358 | | Core::AnonymousBuffer& current_system_theme_buffer(); |
359 | | void set_system_theme(Core::AnonymousBuffer); |
360 | | ErrorOr<Core::AnonymousBuffer> load_system_theme(Core::ConfigFile const&, Optional<ByteString> const& color_scheme = OptionalNone()); |
361 | | ErrorOr<Core::AnonymousBuffer> load_system_theme(ByteString const& path, Optional<ByteString> const& color_scheme = OptionalNone()); |
362 | | |
363 | | struct SystemThemeMetaData { |
364 | | ByteString name; |
365 | | ByteString menu_name; |
366 | | ByteString path; |
367 | | }; |
368 | | |
369 | | ErrorOr<Vector<SystemThemeMetaData>> list_installed_system_themes(); |
370 | | |
371 | | } |
372 | | |
373 | | using Gfx::ColorRole; |