Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "themeapi.h"
24 :
25 : #include <QFontMetrics>
26 :
27 : using namespace muse::ui;
28 : using namespace muse::api;
29 :
30 : struct FontConfig
31 : {
32 : QFont::Weight weight = QFont::Normal;
33 : FontSizeType sizeType = FontSizeType::BODY;
34 : };
35 :
36 0 : ThemeApi::ThemeApi(IApiEngine* e)
37 0 : : api::ApiObject(e)
38 : {
39 0 : setObjectName("UiTheme");
40 0 : }
41 :
42 0 : void ThemeApi::init()
43 : {
44 0 : configuration()->currentThemeChanged().onNotify(this, [this]() {
45 0 : update();
46 0 : });
47 :
48 0 : initThemeValues();
49 :
50 0 : initUiFonts();
51 0 : initIconsFont();
52 0 : initMusicalFont();
53 0 : initMusicalTextFont();
54 0 : calculateDefaultButtonSize();
55 0 : }
56 :
57 0 : void ThemeApi::initThemeValues()
58 : {
59 0 : QMap<ThemeStyleKey, QVariant> themeValues = configuration()->currentTheme().values;
60 :
61 0 : m_backgroundPrimaryColor = themeValues[BACKGROUND_PRIMARY_COLOR].toString();
62 0 : m_backgroundSecondaryColor = themeValues[BACKGROUND_SECONDARY_COLOR].toString();
63 0 : m_backgroundTertiaryColor = themeValues[BACKGROUND_TERTIARY_COLOR].toString();
64 0 : m_backgroundQuarternaryColor = themeValues[BACKGROUND_QUARTERNARY_COLOR].toString();
65 0 : m_popupBackgroundColor = themeValues[POPUP_BACKGROUND_COLOR].toString();
66 0 : m_textFieldColor = themeValues[TEXT_FIELD_COLOR].toString();
67 0 : m_accentColor = themeValues[ACCENT_COLOR].toString();
68 0 : m_strokeColor = themeValues[STROKE_COLOR].toString();
69 0 : m_buttonColor = themeValues[BUTTON_COLOR].toString();
70 0 : m_fontPrimaryColor = themeValues[FONT_PRIMARY_COLOR].toString();
71 0 : m_fontSecondaryColor = themeValues[FONT_SECONDARY_COLOR].toString();
72 0 : m_linkColor = themeValues[LINK_COLOR].toString();
73 0 : m_focusColor = themeValues[FOCUS_COLOR].toString();
74 :
75 0 : m_borderWidth = themeValues[BORDER_WIDTH].toReal();
76 0 : m_navCtrlBorderWidth = themeValues[NAVIGATION_CONTROL_BORDER_WIDTH].toReal();
77 0 : m_accentOpacityNormal = themeValues[ACCENT_OPACITY_NORMAL].toReal();
78 0 : m_accentOpacityHover = themeValues[ACCENT_OPACITY_HOVER].toReal();
79 0 : m_accentOpacityHit = themeValues[ACCENT_OPACITY_HIT].toReal();
80 0 : m_buttonOpacityNormal = themeValues[BUTTON_OPACITY_NORMAL].toReal();
81 0 : m_buttonOpacityHover = themeValues[BUTTON_OPACITY_HOVER].toReal();
82 0 : m_buttonOpacityHit = themeValues[BUTTON_OPACITY_HIT].toReal();
83 0 : m_itemOpacityDisabled = themeValues[ITEM_OPACITY_DISABLED].toReal();
84 :
85 0 : m_extra = configuration()->currentTheme().extra;
86 0 : }
87 :
88 0 : void ThemeApi::update()
89 : {
90 0 : calculateDefaultButtonSize();
91 0 : initThemeValues();
92 0 : notifyAboutThemeChanged();
93 0 : }
94 :
95 0 : bool ThemeApi::isDark() const
96 : {
97 0 : return configuration()->isDarkMode();
98 : }
99 :
100 0 : QColor ThemeApi::backgroundPrimaryColor() const
101 : {
102 0 : return m_backgroundPrimaryColor;
103 : }
104 :
105 0 : QColor ThemeApi::backgroundSecondaryColor() const
106 : {
107 0 : return m_backgroundSecondaryColor;
108 : }
109 :
110 0 : QColor ThemeApi::backgroundTertiaryColor() const
111 : {
112 0 : return m_backgroundTertiaryColor;
113 : }
114 :
115 0 : QColor ThemeApi::backgroundQuarternaryColor() const
116 : {
117 0 : return m_backgroundQuarternaryColor;
118 : }
119 :
120 0 : QColor ThemeApi::popupBackgroundColor() const
121 : {
122 0 : return m_popupBackgroundColor;
123 : }
124 :
125 0 : QColor ThemeApi::textFieldColor() const
126 : {
127 0 : return m_textFieldColor;
128 : }
129 :
130 0 : QColor ThemeApi::accentColor() const
131 : {
132 0 : return m_accentColor;
133 : }
134 :
135 0 : QColor ThemeApi::strokeColor() const
136 : {
137 0 : return m_strokeColor;
138 : }
139 :
140 0 : QColor ThemeApi::buttonColor() const
141 : {
142 0 : return m_buttonColor;
143 : }
144 :
145 0 : QColor ThemeApi::fontPrimaryColor() const
146 : {
147 0 : return m_fontPrimaryColor;
148 : }
149 :
150 0 : QColor ThemeApi::fontSecondaryColor() const
151 : {
152 0 : return m_fontSecondaryColor;
153 : }
154 :
155 0 : QColor ThemeApi::linkColor() const
156 : {
157 0 : return m_linkColor;
158 : }
159 :
160 0 : QColor ThemeApi::focusColor() const
161 : {
162 0 : return m_focusColor;
163 : }
164 :
165 0 : QFont ThemeApi::bodyFont() const
166 : {
167 0 : return m_bodyFont;
168 : }
169 :
170 0 : QFont ThemeApi::bodyBoldFont() const
171 : {
172 0 : return m_bodyBoldFont;
173 : }
174 :
175 0 : QFont ThemeApi::largeBodyFont() const
176 : {
177 0 : return m_largeBodyFont;
178 : }
179 :
180 0 : QFont ThemeApi::largeBodyBoldFont() const
181 : {
182 0 : return m_largeBodyBoldFont;
183 : }
184 :
185 0 : QFont ThemeApi::tabFont() const
186 : {
187 0 : return m_tabFont;
188 : }
189 :
190 0 : QFont ThemeApi::tabBoldFont() const
191 : {
192 0 : return m_tabBoldFont;
193 : }
194 :
195 0 : QFont ThemeApi::headerFont() const
196 : {
197 0 : return m_headerFont;
198 : }
199 :
200 0 : QFont ThemeApi::headerBoldFont() const
201 : {
202 0 : return m_headerBoldFont;
203 : }
204 :
205 0 : QFont ThemeApi::titleBoldFont() const
206 : {
207 0 : return m_titleBoldFont;
208 : }
209 :
210 0 : QFont ThemeApi::iconsFont() const
211 : {
212 0 : return m_iconsFont;
213 : }
214 :
215 0 : QFont ThemeApi::toolbarIconsFont() const
216 : {
217 0 : return m_toolbarIconsFont;
218 : }
219 :
220 0 : QFont ThemeApi::musicalFont() const
221 : {
222 0 : return m_musicalFont;
223 : }
224 :
225 0 : QFont ThemeApi::musicalTextFont() const
226 : {
227 0 : return m_musicalTextFont;
228 : }
229 :
230 0 : qreal ThemeApi::defaultButtonSize() const
231 : {
232 0 : return m_defaultButtonSize;
233 : }
234 :
235 0 : qreal ThemeApi::borderWidth() const
236 : {
237 0 : return m_borderWidth;
238 : }
239 :
240 0 : qreal ThemeApi::navCtrlBorderWidth() const
241 : {
242 0 : return m_navCtrlBorderWidth;
243 : }
244 :
245 0 : qreal ThemeApi::accentOpacityNormal() const
246 : {
247 0 : return m_accentOpacityNormal;
248 : }
249 :
250 0 : qreal ThemeApi::accentOpacityHover() const
251 : {
252 0 : return m_accentOpacityHover;
253 : }
254 :
255 0 : qreal ThemeApi::accentOpacityHit() const
256 : {
257 0 : return m_accentOpacityHit;
258 : }
259 :
260 0 : qreal ThemeApi::buttonOpacityNormal() const
261 : {
262 0 : return m_buttonOpacityNormal;
263 : }
264 :
265 0 : qreal ThemeApi::buttonOpacityHover() const
266 : {
267 0 : return m_buttonOpacityHover;
268 : }
269 :
270 0 : qreal ThemeApi::buttonOpacityHit() const
271 : {
272 0 : return m_buttonOpacityHit;
273 : }
274 :
275 0 : qreal ThemeApi::itemOpacityDisabled() const
276 : {
277 0 : return m_itemOpacityDisabled;
278 : }
279 :
280 0 : int ThemeApi::flickableMaxVelocity() const
281 : {
282 0 : return configuration()->flickableMaxVelocity();
283 : }
284 :
285 0 : int ThemeApi::tooltipDelay() const
286 : {
287 0 : return configuration()->tooltipDelay();
288 : }
289 :
290 0 : void ThemeApi::initUiFonts()
291 : {
292 0 : setupUiFonts();
293 :
294 0 : configuration()->fontChanged().onNotify(this, [this]() {
295 0 : setupUiFonts();
296 0 : update();
297 0 : });
298 0 : }
299 :
300 0 : void ThemeApi::initIconsFont()
301 : {
302 0 : setupIconsFont();
303 :
304 0 : configuration()->iconsFontChanged().onNotify(this, [this]() {
305 0 : setupIconsFont();
306 0 : update();
307 0 : });
308 0 : }
309 :
310 0 : void ThemeApi::initMusicalFont()
311 : {
312 0 : setupMusicFont();
313 :
314 0 : configuration()->musicalFontChanged().onNotify(this, [this]() {
315 0 : setupMusicFont();
316 0 : update();
317 0 : });
318 0 : }
319 :
320 0 : void ThemeApi::initMusicalTextFont()
321 : {
322 0 : setupMusicTextFont();
323 :
324 0 : configuration()->musicalTextFontChanged().onNotify(this, [this]() {
325 0 : setupMusicTextFont();
326 0 : update();
327 0 : });
328 0 : }
329 :
330 0 : void ThemeApi::setupUiFonts()
331 : {
332 : const std::vector<std::pair<QFont*, FontConfig> > fonts {
333 0 : { &m_bodyFont, { QFont::Normal, FontSizeType::BODY } },
334 0 : { &m_bodyBoldFont, { QFont::DemiBold, FontSizeType::BODY } },
335 0 : { &m_largeBodyFont, { QFont::Normal, FontSizeType::BODY_LARGE } },
336 0 : { &m_largeBodyBoldFont, { QFont::DemiBold, FontSizeType::BODY_LARGE } },
337 0 : { &m_tabFont, { QFont::Normal, FontSizeType::TAB } },
338 0 : { &m_tabBoldFont, { QFont::DemiBold, FontSizeType::TAB } },
339 0 : { &m_headerFont, { QFont::Normal, FontSizeType::HEADER } },
340 0 : { &m_headerBoldFont, { QFont::DemiBold, FontSizeType::HEADER } },
341 0 : { &m_titleBoldFont, { QFont::DemiBold, FontSizeType::TITLE } },
342 0 : };
343 :
344 0 : for (const auto& [font, fontConfig] : fonts) {
345 0 : std::string family = configuration()->fontFamily();
346 0 : int size = configuration()->fontSize(fontConfig.sizeType);
347 :
348 0 : font->setPixelSize(size);
349 0 : font->setFamily(QString::fromStdString(family));
350 0 : font->setWeight(fontConfig.weight);
351 0 : }
352 0 : }
353 :
354 0 : void ThemeApi::setupIconsFont()
355 : {
356 0 : QString family = QString::fromStdString(configuration()->iconsFontFamily());
357 :
358 0 : m_iconsFont.setFamily(family);
359 0 : m_iconsFont.setPixelSize(configuration()->iconsFontSize(IconSizeType::Regular));
360 :
361 0 : m_toolbarIconsFont.setFamily(family);
362 0 : m_toolbarIconsFont.setPixelSize(configuration()->iconsFontSize(IconSizeType::Toolbar));
363 0 : }
364 :
365 0 : void ThemeApi::setupMusicFont()
366 : {
367 0 : m_musicalFont.setFamily(QString::fromStdString(configuration()->musicalFontFamily()));
368 0 : m_musicalFont.setPixelSize(configuration()->musicalFontSize());
369 0 : }
370 :
371 0 : void ThemeApi::setupMusicTextFont()
372 : {
373 0 : m_musicalTextFont.setFamily(QString::fromStdString(configuration()->musicalTextFontFamily()));
374 0 : m_musicalTextFont.setPixelSize(configuration()->musicalTextFontSize());
375 0 : }
376 :
377 0 : void ThemeApi::calculateDefaultButtonSize()
378 : {
379 0 : constexpr qreal MINIMUM_BUTTON_SIZE = 30.0;
380 0 : constexpr qreal BUTTON_PADDING = 8.0;
381 :
382 0 : QFontMetricsF bodyFontMetrics(m_bodyFont);
383 0 : QFontMetricsF iconFontMetrics(m_iconsFont);
384 :
385 0 : qreal requiredSize = std::max(bodyFontMetrics.height(), iconFontMetrics.height()) + BUTTON_PADDING;
386 0 : m_defaultButtonSize = std::max(requiredSize, MINIMUM_BUTTON_SIZE);
387 0 : }
388 :
389 0 : void ThemeApi::notifyAboutThemeChanged()
390 : {
391 0 : emit themeChanged();
392 0 : }
393 :
394 0 : QVariantMap ThemeApi::extra() const
395 : {
396 0 : return m_extra;
397 : }
|