Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-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 : #include "engravingconfiguration.h"
23 :
24 : #include <cstdlib>
25 :
26 : #ifndef NO_QT_SUPPORT
27 : #include <QLocale>
28 : #include <QPageSize>
29 : #endif
30 :
31 : #include "global/settings.h"
32 : #include "draw/types/color.h"
33 : #include "dom/mscore.h"
34 : #include "translation.h"
35 :
36 : #include "log.h"
37 :
38 : using namespace mu;
39 : using namespace muse;
40 : using namespace muse::draw;
41 : using namespace mu::engraving;
42 :
43 : static const Settings::Key DEFAULT_STYLE_FILE_PATH("engraving", "engraving/style/defaultStyleFile");
44 : static const Settings::Key PART_STYLE_FILE_PATH("engraving", "engraving/style/partStyleFile");
45 :
46 : static const Settings::Key DISPLAYED_DEFAULT_COLOR("engraving", "engraving/colors/displayedDefaultColor");
47 : static const Settings::Key INVERTED_DISPLAYED_DEFAULT_COLOR("engraving", "engraving/colors/invertedDisplayedDefaultColor");
48 : static const Settings::Key ALL_VOICES_COLOR("engraving", "engraving/colors/allVoicesColor");
49 : static const Settings::Key FORMATTING_COLOR("engraving", "engraving/colors/formattingColor");
50 : static const Settings::Key FRAME_COLOR("engraving", "engraving/colors/frameColor");
51 : static const Settings::Key SCORE_GREY_COLOR("engraving", "engraving/color/scoreGreyColor");
52 : static const Settings::Key INVISIBLE_COLOR("engraving", "engraving/colors/invisibleColor");
53 : static const Settings::Key UNLINKED_COLOR("engraving", "engraving/colors/unlinkedColor");
54 :
55 : static const Settings::Key DYNAMICS_APPLY_TO_ALL_VOICES("engraving", "score/dynamicsApplyToAllVoices");
56 : static const Settings::Key FRETBOARD_DIAGRAMS_AUTO_UPDATE("engraving", "score/fretboardDiagramsAutoUpdate");
57 :
58 : struct VoiceColor {
59 : Settings::Key key;
60 : Color color;
61 : };
62 :
63 : static VoiceColor VOICE_COLORS[VOICES + 1];
64 :
65 : static const Color UNLINKED_ITEM_COLOR = "#FF9300";
66 : static const Color DEFAULT_DISPLAYED_INVERTED_COLOR = "#CBCBCD";
67 :
68 16 : EngravingConfiguration::EngravingConfiguration()
69 16 : : m_cachedDisplayedDefaultColor(Color::BLACK),
70 192 : m_cachedInvertedDisplayedDefaultColor(DEFAULT_DISPLAYED_INVERTED_COLOR)
71 176 : {}
72 :
73 16 : void EngravingConfiguration::init()
74 : {
75 : static const Color DEFAULT_VOICE_COLORS[VOICES + 1] {
76 : "#0065BF",
77 : "#007F00",
78 : "#C53F00",
79 : "#C31989",
80 : "#6038FC", // "all voices"
81 16 : };
82 :
83 16 : settings()->setDefaultValue(DEFAULT_STYLE_FILE_PATH, Val(muse::io::path_t()));
84 16 : settings()->valueChanged(DEFAULT_STYLE_FILE_PATH).onReceive(this, [this](const Val& val) {
85 0 : m_defaultStyleFilePathChanged.send(val.toPath());
86 0 : });
87 :
88 16 : settings()->setDefaultValue(PART_STYLE_FILE_PATH, Val(muse::io::path_t()));
89 16 : settings()->valueChanged(PART_STYLE_FILE_PATH).onReceive(this, [this](const Val& val) {
90 0 : m_partStyleFilePathChanged.send(val.toPath());
91 0 : });
92 :
93 16 : settings()->setDefaultValue(DISPLAYED_DEFAULT_COLOR, Val(defaultColor().toQColor()));
94 16 : settings()->setDescription(DISPLAYED_DEFAULT_COLOR, muse::trc("engraving", "Displayed default color"));
95 16 : settings()->setCanBeManuallyEdited(DISPLAYED_DEFAULT_COLOR, true);
96 16 : settings()->valueChanged(DISPLAYED_DEFAULT_COLOR).onReceive(this, [this](const Val& val) {
97 0 : const Color color = val.toQColor();
98 0 : m_cachedDisplayedDefaultColor = color;
99 0 : m_displayedDefaultColorChanged.send(false, color);
100 0 : });
101 16 : m_cachedDisplayedDefaultColor = settings()->value(DISPLAYED_DEFAULT_COLOR).toQColor();
102 :
103 16 : settings()->setDefaultValue(INVERTED_DISPLAYED_DEFAULT_COLOR, Val(Color(DEFAULT_DISPLAYED_INVERTED_COLOR).toQColor()));
104 32 : settings()->setDescription(INVERTED_DISPLAYED_DEFAULT_COLOR,
105 32 : muse::trc("engraving", "Displayed default color when score colors are inverted"));
106 16 : settings()->setCanBeManuallyEdited(INVERTED_DISPLAYED_DEFAULT_COLOR, true);
107 16 : settings()->valueChanged(INVERTED_DISPLAYED_DEFAULT_COLOR).onReceive(this, [this](const Val& val) {
108 0 : const Color color = val.toQColor();
109 0 : m_cachedInvertedDisplayedDefaultColor = color;
110 0 : m_displayedDefaultColorChanged.send(true, color);
111 0 : });
112 16 : m_cachedInvertedDisplayedDefaultColor = settings()->value(INVERTED_DISPLAYED_DEFAULT_COLOR).toQColor();
113 :
114 80 : for (voice_idx_t voice = 0; voice < VOICES; ++voice) {
115 192 : Settings::Key key("engraving", "engraving/colors/voice" + std::to_string(voice + 1));
116 :
117 64 : settings()->setDefaultValue(key, Val(DEFAULT_VOICE_COLORS[voice].toQColor()));
118 128 : settings()->setDescription(key, muse::qtrc("engraving", "Voice %1 color").arg(voice + 1).toStdString());
119 64 : settings()->setCanBeManuallyEdited(key, true);
120 64 : settings()->valueChanged(key).onReceive(this, [this, voice](const Val& val) {
121 0 : Color color = val.toQColor();
122 0 : VOICE_COLORS[voice].color = color;
123 0 : m_voiceColorChanged.send(voice, color);
124 0 : });
125 :
126 64 : Color currentColor = settings()->value(key).toQColor();
127 64 : VOICE_COLORS[voice] = VoiceColor { std::move(key), currentColor };
128 64 : }
129 :
130 : static constexpr int ALL_VOICES_IDX = VOICES;
131 16 : settings()->setDefaultValue(ALL_VOICES_COLOR, Val(DEFAULT_VOICE_COLORS[ALL_VOICES_IDX].toQColor()));
132 16 : settings()->setDescription(ALL_VOICES_COLOR, muse::trc("engraving", "All voices color"));
133 16 : settings()->setCanBeManuallyEdited(ALL_VOICES_COLOR, true);
134 16 : settings()->valueChanged(ALL_VOICES_COLOR).onReceive(this, [&](const Val& val) {
135 0 : Color color = val.toQColor();
136 0 : VOICE_COLORS[ALL_VOICES_IDX].color = color;
137 0 : m_voiceColorChanged.send(ALL_VOICES_IDX, color);
138 0 : });
139 16 : Color currentColor = settings()->value(ALL_VOICES_COLOR).toQColor();
140 16 : VOICE_COLORS[ALL_VOICES_IDX] = VoiceColor { std::move(ALL_VOICES_COLOR), currentColor };
141 :
142 16 : settings()->setDefaultValue(DYNAMICS_APPLY_TO_ALL_VOICES, Val(true));
143 16 : settings()->valueChanged(DYNAMICS_APPLY_TO_ALL_VOICES).onReceive(this, [this](const Val& val) {
144 0 : m_dynamicsApplyToAllVoicesChanged.send(val.toBool());
145 0 : });
146 :
147 16 : settings()->setDefaultValue(FRETBOARD_DIAGRAMS_AUTO_UPDATE, Val(true));
148 16 : settings()->valueChanged(FRETBOARD_DIAGRAMS_AUTO_UPDATE).onReceive(this, [this](const Val& val) {
149 0 : m_fretboardDiagramsAutoUpdateChanged.send(val.toBool());
150 0 : });
151 :
152 16 : settings()->setDefaultValue(FRAME_COLOR, Val(Color("#A0A0A4").toQColor()));
153 16 : settings()->setDescription(FRAME_COLOR, muse::trc("engraving", "Frame color"));
154 16 : settings()->setCanBeManuallyEdited(FRAME_COLOR, true);
155 16 : settings()->valueChanged(FRAME_COLOR).onReceive(nullptr, [this](const Val& val) {
156 0 : m_frameColorChanged.send(Color::fromQColor(val.toQColor()));
157 0 : });
158 :
159 16 : settings()->setDefaultValue(SCORE_GREY_COLOR, Val(Color("#A0A0A4").toQColor()));
160 16 : settings()->setDescription(SCORE_GREY_COLOR, muse::trc("engraving", "Score grey color"));
161 16 : settings()->setCanBeManuallyEdited(SCORE_GREY_COLOR, false);
162 :
163 16 : settings()->setDefaultValue(FORMATTING_COLOR, Val(Color("#C31989").toQColor()));
164 16 : settings()->setDescription(FORMATTING_COLOR, muse::trc("engraving", "Formatting color"));
165 16 : settings()->setCanBeManuallyEdited(FORMATTING_COLOR, true);
166 16 : settings()->valueChanged(FORMATTING_COLOR).onReceive(nullptr, [this](const Val& val) {
167 0 : m_formattingColorChanged.send(Color::fromQColor(val.toQColor()));
168 0 : });
169 :
170 16 : settings()->setDefaultValue(INVISIBLE_COLOR, Val(Color("#808080").toQColor()));
171 16 : settings()->setDescription(INVISIBLE_COLOR, muse::trc("engraving", "Invisible color"));
172 16 : settings()->setCanBeManuallyEdited(INVISIBLE_COLOR, true);
173 16 : settings()->valueChanged(INVISIBLE_COLOR).onReceive(nullptr, [this](const Val& val) {
174 0 : m_invisibleColorChanged.send(Color::fromQColor(val.toQColor()));
175 0 : });
176 :
177 16 : settings()->setDefaultValue(UNLINKED_COLOR, Val(Color(UNLINKED_ITEM_COLOR).toQColor()));
178 16 : settings()->setDescription(UNLINKED_COLOR, muse::trc("engraving", "Desynchronized color"));
179 16 : settings()->setCanBeManuallyEdited(UNLINKED_COLOR, true);
180 16 : settings()->valueChanged(UNLINKED_COLOR).onReceive(nullptr, [this](const Val& val) {
181 0 : m_unlinkedColorChanged.send(Color::fromQColor(val.toQColor()));
182 0 : });
183 16 : }
184 :
185 0 : muse::io::path_t EngravingConfiguration::appDataPath() const
186 : {
187 0 : return globalConfiguration()->appDataPath();
188 : }
189 :
190 16 : muse::io::path_t EngravingConfiguration::defaultStyleFilePath() const
191 : {
192 16 : return settings()->value(DEFAULT_STYLE_FILE_PATH).toPath();
193 : }
194 :
195 0 : void EngravingConfiguration::setDefaultStyleFilePath(const muse::io::path_t& path)
196 : {
197 0 : settings()->setSharedValue(DEFAULT_STYLE_FILE_PATH, Val(path.toStdString()));
198 0 : }
199 :
200 0 : async::Channel<muse::io::path_t> EngravingConfiguration::defaultStyleFilePathChanged() const
201 : {
202 0 : return m_defaultStyleFilePathChanged;
203 : }
204 :
205 16 : muse::io::path_t EngravingConfiguration::partStyleFilePath() const
206 : {
207 16 : return settings()->value(PART_STYLE_FILE_PATH).toPath();
208 : }
209 :
210 0 : void EngravingConfiguration::setPartStyleFilePath(const muse::io::path_t& path)
211 : {
212 0 : settings()->setSharedValue(PART_STYLE_FILE_PATH, Val(path.toStdString()));
213 0 : }
214 :
215 0 : async::Channel<muse::io::path_t> EngravingConfiguration::partStyleFilePathChanged() const
216 : {
217 0 : return m_partStyleFilePathChanged;
218 : }
219 :
220 16 : static bool defaultPageSizeIsLetter()
221 : {
222 : // try PAPERSIZE environment variable
223 16 : const char* papersize = getenv("PAPERSIZE");
224 16 : if (papersize) {
225 0 : return strcmp(papersize, "letter") == 0;
226 : }
227 : #ifndef NO_QT_SUPPORT
228 : // try locale
229 16 : switch (QLocale::system().territory()) {
230 0 : case QLocale::UnitedStates:
231 : case QLocale::Canada:
232 : case QLocale::Mexico:
233 : case QLocale::Chile:
234 : case QLocale::Colombia:
235 : case QLocale::CostaRica:
236 : case QLocale::Panama:
237 : case QLocale::Guatemala:
238 : case QLocale::DominicanRepublic:
239 : case QLocale::Philippines:
240 0 : return true;
241 16 : default:
242 16 : return false;
243 : }
244 : #else
245 : return false;
246 : #endif
247 : }
248 :
249 16 : SizeF EngravingConfiguration::defaultPageSize() const
250 : {
251 : // Needs to be determined only once, therefore static
252 16 : static SizeF size = SizeF::fromQSizeF(
253 32 : QPageSize::size(defaultPageSizeIsLetter() ? QPageSize::Letter : QPageSize::A4, QPageSize::Inch));
254 :
255 16 : return size;
256 : }
257 :
258 550 : bool EngravingConfiguration::canLayoutIcons() const
259 : {
260 550 : return uiConfiguration() != nullptr;
261 : }
262 :
263 0 : muse::String EngravingConfiguration::iconsFontFamily() const
264 : {
265 0 : return uiConfiguration() ? String::fromStdString(uiConfiguration()->iconsFontFamily()) : String();
266 : }
267 :
268 453773 : Color EngravingConfiguration::defaultColor() const
269 : {
270 453773 : return Color::BLACK;
271 : }
272 :
273 0 : Color EngravingConfiguration::displayedDefaultColor(bool inverted) const
274 : {
275 0 : if (inverted) {
276 0 : return m_cachedInvertedDisplayedDefaultColor;
277 : }
278 0 : return m_cachedDisplayedDefaultColor;
279 : }
280 :
281 0 : void EngravingConfiguration::setDisplayedDefaultColor(Color color, bool inverted)
282 : {
283 0 : if (inverted) {
284 0 : settings()->setSharedValue(INVERTED_DISPLAYED_DEFAULT_COLOR, Val(color.toQColor()));
285 : } else {
286 0 : settings()->setSharedValue(DISPLAYED_DEFAULT_COLOR, Val(color.toQColor()));
287 : }
288 0 : }
289 :
290 0 : muse::async::Channel<bool, Color> EngravingConfiguration::displayedDefaultColorChanged() const
291 : {
292 0 : return m_displayedDefaultColorChanged;
293 : }
294 :
295 0 : void EngravingConfiguration::resetDisplayedDefaultColors()
296 : {
297 0 : settings()->setSharedValue(DISPLAYED_DEFAULT_COLOR, settings()->defaultValue(DISPLAYED_DEFAULT_COLOR));
298 0 : settings()->setSharedValue(INVERTED_DISPLAYED_DEFAULT_COLOR, settings()->defaultValue(INVERTED_DISPLAYED_DEFAULT_COLOR));
299 0 : }
300 :
301 0 : Color EngravingConfiguration::indicatorIconInvertedSelectionColor() const
302 : {
303 0 : return Color::fromQColor(voiceColor(0).toQColor().lighter(135));
304 : }
305 :
306 0 : Color EngravingConfiguration::lassoColor() const
307 : {
308 0 : return "#00323200";
309 : }
310 :
311 0 : Color EngravingConfiguration::warningColor() const
312 : {
313 0 : return "#808000";
314 : }
315 :
316 0 : Color EngravingConfiguration::warningSelectedColor() const
317 : {
318 0 : return "#565600";
319 : }
320 :
321 0 : Color EngravingConfiguration::criticalColor() const
322 : {
323 0 : return Color::RED;
324 : }
325 :
326 0 : Color EngravingConfiguration::criticalBackgroundColor() const
327 : {
328 0 : return Color::RED;
329 : }
330 :
331 0 : Color EngravingConfiguration::criticalSelectedColor() const
332 : {
333 0 : return "#8B0000";
334 : }
335 :
336 0 : Color EngravingConfiguration::thumbnailBackgroundColor() const
337 : {
338 0 : return Color::WHITE;
339 : }
340 :
341 0 : Color EngravingConfiguration::noteBackgroundColor() const
342 : {
343 0 : return Color::WHITE;
344 : }
345 :
346 0 : Color EngravingConfiguration::fontPrimaryColor() const
347 : {
348 0 : return uiConfiguration()
349 0 : ? Color(uiConfiguration()->currentTheme().values[muse::ui::ThemeStyleKey::FONT_PRIMARY_COLOR].toString())
350 0 : : Color::BLACK;
351 : }
352 :
353 0 : Color EngravingConfiguration::voiceColor(voice_idx_t voiceIdx) const
354 : {
355 0 : return VOICE_COLORS[voiceIdx].color;
356 : }
357 :
358 0 : Color EngravingConfiguration::selectionColor(voice_idx_t voice, bool itemVisible, bool itemIsUnlinkedFromScore) const
359 : {
360 0 : Color color = itemIsUnlinkedFromScore ? unlinkedColor() : VOICE_COLORS[voice].color;
361 :
362 0 : if (itemVisible) {
363 0 : return color;
364 : }
365 :
366 0 : constexpr float tint = .6f; // Between 0 and 1. Higher means lighter, lower means darker
367 :
368 0 : color.applyTint(tint);
369 :
370 0 : return color;
371 : }
372 :
373 0 : void EngravingConfiguration::setSelectionColor(voice_idx_t voiceIndex, Color color)
374 : {
375 0 : settings()->setSharedValue(VOICE_COLORS[voiceIndex].key, Val(color.toQColor()));
376 0 : }
377 :
378 0 : muse::async::Channel<voice_idx_t, Color> EngravingConfiguration::selectionColorChanged() const
379 : {
380 0 : return m_voiceColorChanged;
381 : }
382 :
383 0 : Color EngravingConfiguration::highlightSelectionColor(voice_idx_t voice) const
384 : {
385 0 : return Color::fromQColor(selectionColor(voice).toQColor().lighter(135));
386 : }
387 :
388 0 : bool EngravingConfiguration::dynamicsApplyToAllVoices() const
389 : {
390 0 : return settings()->value(DYNAMICS_APPLY_TO_ALL_VOICES).toBool();
391 : }
392 :
393 0 : void EngravingConfiguration::setDynamicsApplyToAllVoices(bool v)
394 : {
395 0 : settings()->setSharedValue(DYNAMICS_APPLY_TO_ALL_VOICES, Val(v));
396 0 : }
397 :
398 0 : muse::async::Channel<bool> EngravingConfiguration::dynamicsApplyToAllVoicesChanged() const
399 : {
400 0 : return m_dynamicsApplyToAllVoicesChanged;
401 : }
402 :
403 0 : bool EngravingConfiguration::autoUpdateFretboardDiagrams() const
404 : {
405 0 : return settings()->value(FRETBOARD_DIAGRAMS_AUTO_UPDATE).toBool();
406 : }
407 :
408 0 : void EngravingConfiguration::setAutoUpdateFretboardDiagrams(bool v)
409 : {
410 0 : settings()->setSharedValue(FRETBOARD_DIAGRAMS_AUTO_UPDATE, Val(v));
411 0 : }
412 :
413 0 : muse::async::Channel<bool> EngravingConfiguration::autoUpdateFretboardDiagramsChanged() const
414 : {
415 0 : return m_fretboardDiagramsAutoUpdateChanged;
416 : }
417 :
418 0 : Color EngravingConfiguration::formattingColor() const
419 : {
420 0 : return Color::fromQColor(settings()->value(FORMATTING_COLOR).toQColor());
421 : }
422 :
423 0 : muse::async::Channel<Color> EngravingConfiguration::formattingColorChanged() const
424 : {
425 0 : return m_formattingColorChanged;
426 : }
427 :
428 0 : Color EngravingConfiguration::frameColor() const
429 : {
430 0 : return Color::fromQColor(settings()->value(FRAME_COLOR).toQColor());
431 : }
432 :
433 0 : muse::async::Channel<Color> EngravingConfiguration::frameColorChanged() const
434 : {
435 0 : return m_frameColorChanged;
436 : }
437 :
438 0 : Color EngravingConfiguration::scoreGreyColor() const
439 : {
440 0 : return Color::fromQColor(settings()->value(SCORE_GREY_COLOR).toQColor());
441 : }
442 :
443 0 : Color EngravingConfiguration::invisibleColor() const
444 : {
445 0 : return Color::fromQColor(settings()->value(INVISIBLE_COLOR).toQColor());
446 : }
447 :
448 0 : muse::async::Channel<Color> EngravingConfiguration::invisibleColorChanged() const
449 : {
450 0 : return m_invisibleColorChanged;
451 : }
452 :
453 0 : Color EngravingConfiguration::unlinkedColor() const
454 : {
455 0 : return Color::fromQColor(settings()->value(UNLINKED_COLOR).toQColor());
456 : }
457 :
458 0 : muse::async::Channel<Color> EngravingConfiguration::unlinkedColorChanged() const
459 : {
460 0 : return m_unlinkedColorChanged;
461 : }
462 :
463 1374536 : const IEngravingConfiguration::DebuggingOptions& EngravingConfiguration::debuggingOptions() const
464 : {
465 1374536 : return m_debuggingOptions.val;
466 : }
467 :
468 0 : void EngravingConfiguration::setDebuggingOptions(const DebuggingOptions& options)
469 : {
470 0 : m_debuggingOptions.set(options);
471 0 : }
472 :
473 0 : muse::async::Notification EngravingConfiguration::debuggingOptionsChanged() const
474 : {
475 0 : return m_debuggingOptions.notification;
476 : }
477 :
478 0 : bool EngravingConfiguration::allowReadingImagesFromOutsideMscz() const
479 : {
480 0 : return false;
481 : }
482 :
483 9517 : bool EngravingConfiguration::guitarProImportExperimental() const
484 : {
485 9517 : return guitarProConfiguration() ? guitarProConfiguration()->experimental() : false;
486 : }
487 :
488 4731 : bool EngravingConfiguration::negativeFretsAllowed() const
489 : {
490 4731 : return guitarProImportExperimental();
491 : }
492 :
493 221 : void EngravingConfiguration::setGuitarProMultivoiceEnabled(bool multiVoice)
494 : {
495 221 : m_multiVoice = multiVoice;
496 221 : }
497 :
498 0 : bool EngravingConfiguration::guitarProMultivoiceEnabled() const
499 : {
500 0 : return m_multiVoice;
501 : }
502 :
503 0 : bool EngravingConfiguration::minDistanceForPartialSkylineCalculated() const
504 : {
505 0 : return guitarProImportExperimental();
506 : }
507 :
508 403 : bool EngravingConfiguration::specificSlursLayoutWorkaround() const
509 : {
510 403 : return guitarProImportExperimental();
511 : }
512 :
513 1160 : bool EngravingConfiguration::preferSameStringForTranspose() const
514 : {
515 1160 : return false;
516 : }
517 :
518 0 : void EngravingConfiguration::setPreferSameStringForTranspose(bool /*preferSameString*/)
519 : {
520 0 : }
521 :
522 2147 : bool EngravingConfiguration::keepDeadNotesUnchangedOnTranspose() const
523 : {
524 2147 : return false;
525 : }
|