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 :
23 : #include "style.h"
24 :
25 : #include "global/modularity/ioc.h"
26 :
27 : #include "iengravingfontsprovider.h"
28 :
29 : #include "types/constants.h"
30 : #include "compat/pageformat.h"
31 : #include "rw/compat/readchordlisthook.h"
32 : #include "rw/compat/compatutils.h"
33 : #include "rw/xmlreader.h"
34 : #include "rw/xmlwriter.h"
35 : #include "types/typesconv.h"
36 :
37 : #include "dom/mscore.h"
38 : #include "dom/pedal.h"
39 :
40 : #include "defaultstyle.h"
41 :
42 : #include "log.h"
43 :
44 : using namespace mu;
45 : using namespace muse::io;
46 : using namespace mu::engraving;
47 :
48 25413103 : const PropertyValue& MStyle::value(Sid idx) const
49 : {
50 25413103 : if (idx == Sid::NOSTYLE) {
51 0 : static PropertyValue dummy;
52 0 : return dummy;
53 : }
54 :
55 25413103 : const PropertyValue& val = m_values[size_t(idx)];
56 25413103 : if (val.isValid()) {
57 8377044 : return val;
58 : }
59 :
60 17036059 : return StyleDef::styleValues[size_t(idx)].defaultValue;
61 : }
62 :
63 2317822 : double MStyle::valueAbsolute(Sid idx) const
64 : {
65 2317822 : if (idx == Sid::NOSTYLE) {
66 0 : return 0.0;
67 : }
68 :
69 2317822 : return m_precomputedValues[size_t(idx)];
70 : }
71 :
72 271932 : void MStyle::set(const Sid t, const PropertyValue& val)
73 : {
74 271932 : if (t == Sid::NOSTYLE) {
75 0 : return;
76 : }
77 :
78 271932 : const size_t idx = size_t(t);
79 271932 : m_values[idx] = val;
80 271932 : if (t == Sid::spatium) {
81 1168 : precomputeValues();
82 : } else {
83 270764 : if (StyleDef::styleValues[idx].valueType() == P_TYPE::SPATIUM) {
84 36166 : double _spatium = value(Sid::spatium).toReal();
85 36166 : m_precomputedValues[idx] = m_values[idx].value<Spatium>().val() * _spatium;
86 : }
87 : }
88 : }
89 :
90 2349078 : double MStyle::defaultSpatium() const
91 : {
92 2349078 : return StyleDef::styleValues[static_cast<size_t>(Sid::spatium)].defaultValue.toDouble();
93 : }
94 :
95 1365 : void MStyle::precomputeValues()
96 : {
97 1365 : double _spatium = value(Sid::spatium).toReal();
98 2805075 : for (const StyleDef::StyleValue& t : StyleDef::styleValues) {
99 2803710 : if (t.valueType() == P_TYPE::SPATIUM) {
100 700245 : m_precomputedValues[t.idx()] = value(t.sid).value<Spatium>().val() * _spatium;
101 : }
102 : }
103 1365 : }
104 :
105 2250099 : bool MStyle::isDefault(Sid idx) const
106 : {
107 2250099 : return value(idx) == DefaultStyle::resolveStyleDefaults(defaultStyleVersion()).value(idx);
108 : }
109 :
110 581 : void MStyle::setDefaultStyleVersion(const int defaultsVersion)
111 : {
112 581 : set(Sid::defaultsVersion, defaultsVersion);
113 581 : }
114 :
115 2250207 : int MStyle::defaultStyleVersion() const
116 : {
117 2250207 : return styleI(Sid::defaultsVersion);
118 : }
119 :
120 113542 : bool MStyle::readProperties(XmlReader& e)
121 : {
122 113542 : const AsciiStringView tag(e.name());
123 :
124 108690762 : for (const StyleDef::StyleValue& t : StyleDef::styleValues) {
125 108690564 : Sid idx = t.sid;
126 108690564 : if (t.xmlName == tag) {
127 113344 : P_TYPE type = t.valueType();
128 113344 : switch (type) {
129 25801 : case P_TYPE::SPATIUM:
130 25801 : set(idx, Spatium(e.readDouble()));
131 25801 : break;
132 15483 : case P_TYPE::REAL:
133 15483 : set(idx, e.readDouble());
134 15483 : break;
135 14424 : case P_TYPE::BOOL:
136 14424 : set(idx, bool(e.readInt()));
137 14424 : break;
138 14260 : case P_TYPE::INT:
139 14260 : set(idx, e.readInt());
140 14260 : break;
141 109 : case P_TYPE::DIRECTION_V:
142 109 : set(idx, DirectionV(e.readInt()));
143 109 : break;
144 10965 : case P_TYPE::STRING:
145 10965 : set(idx, e.readText());
146 10965 : break;
147 4596 : case P_TYPE::ALIGN: {
148 4596 : Align align = TConv::fromXml(e.readText(), Align());
149 4596 : set(idx, align);
150 4596 : } break;
151 733 : case P_TYPE::ALIGN_H: {
152 733 : AlignH align = TConv::fromXml(e.readAsciiText(), AlignH::HCENTER);
153 733 : set(idx, align);
154 733 : } break;
155 7742 : case P_TYPE::POINT: {
156 7742 : double x = e.doubleAttribute("x", 0.0);
157 7742 : double y = e.doubleAttribute("y", 0.0);
158 7742 : set(idx, PointF(x, y));
159 7742 : e.readText();
160 7742 : } break;
161 0 : case P_TYPE::SIZE: {
162 0 : double x = e.doubleAttribute("w", 0.0);
163 0 : double y = e.doubleAttribute("h", 0.0);
164 0 : set(idx, SizeF(x, y));
165 0 : e.readText();
166 0 : } break;
167 63 : case P_TYPE::SCALE: {
168 63 : double sx = e.doubleAttribute("w", 0.0);
169 63 : double sy = e.doubleAttribute("h", 0.0);
170 63 : set(idx, ScaleF(sx, sy));
171 63 : e.readText();
172 63 : } break;
173 15170 : case P_TYPE::COLOR: {
174 15170 : Color c;
175 15170 : c.setRed(e.intAttribute("r"));
176 15170 : c.setGreen(e.intAttribute("g"));
177 15170 : c.setBlue(e.intAttribute("b"));
178 15170 : c.setAlpha(e.intAttribute("a", 255));
179 15170 : set(idx, c);
180 15170 : e.readText();
181 15170 : } break;
182 2744 : case P_TYPE::PLACEMENT_V:
183 2744 : set(idx, PlacementV(e.readText().toInt()));
184 2744 : break;
185 0 : case P_TYPE::PLACEMENT_H:
186 0 : set(idx, PlacementH(e.readText().toInt()));
187 0 : break;
188 6 : case P_TYPE::DIRECTION_H:
189 6 : set(idx, DirectionH(e.readText().toInt()));
190 6 : break;
191 6 : case P_TYPE::ORIENTATION:
192 6 : set(idx, TConv::fromXml(e.readAsciiText(), Orientation::HORIZONTAL));
193 6 : break;
194 2 : case P_TYPE::SHARED_LABEL_ORIENTATION:
195 2 : set(idx, TConv::fromXml(e.readAsciiText(), SharedLabelOrientation::HORIZONTAL));
196 2 : break;
197 175 : case P_TYPE::HOOK_TYPE:
198 175 : set(idx, HookType(e.readText().toInt()));
199 175 : break;
200 647 : case P_TYPE::LINE_TYPE:
201 647 : set(idx, TConv::fromXml(e.readAsciiText(), LineType::SOLID));
202 647 : break;
203 0 : case P_TYPE::CLEF_TO_BARLINE_POS:
204 0 : set(idx, ClefToBarlinePosition(e.readInt()));
205 0 : break;
206 61 : case P_TYPE::TIE_PLACEMENT:
207 61 : set(idx, TConv::fromXml(e.readAsciiText(), TiePlacement::AUTO));
208 61 : break;
209 21 : case P_TYPE::TIE_DOTS_PLACEMENT:
210 21 : set(idx, TConv::fromXml(e.readAsciiText(), TieDotsPlacement::AUTO));
211 21 : break;
212 56 : case P_TYPE::GLISS_STYLE:
213 56 : set(idx, GlissandoStyle(e.readText().toInt()));
214 56 : break;
215 21 : case P_TYPE::GLISS_TYPE:
216 21 : set(idx, GlissandoType(e.readText().toInt()));
217 21 : break;
218 21 : case P_TYPE::TIMESIG_PLACEMENT:
219 21 : set(idx, TConv::fromXml(e.readAsciiText(), TimeSigPlacement::NORMAL));
220 21 : break;
221 63 : case P_TYPE::TIMESIG_STYLE:
222 63 : set(idx, TConv::fromXml(e.readAsciiText(), TimeSigStyle::NORMAL));
223 63 : break;
224 42 : case P_TYPE::TIMESIG_MARGIN:
225 42 : set(idx, TConv::fromXml(e.readAsciiText(), TimeSigVSMargin::RIGHT_ALIGN_TO_BARLINE));
226 42 : break;
227 10 : case P_TYPE::NOTE_SPELLING_TYPE:
228 10 : set(idx, TConv::fromXml(e.readAsciiText(), NoteSpellingType::STANDARD));
229 10 : break;
230 17 : case P_TYPE::CHORD_PRESET_TYPE:
231 17 : set(idx, TConv::fromXml(e.readAsciiText(), ChordStylePreset::STANDARD));
232 17 : break;
233 0 : case P_TYPE::PARENTHESES_MODE:
234 0 : set(idx, TConv::fromXml(e.readAsciiText(), ParenthesesMode::NONE));
235 0 : break;
236 20 : case P_TYPE::LH_TAPPING_SYMBOL:
237 20 : set(idx, TConv::fromXml(e.readAsciiText(), LHTappingSymbol::DOT));
238 20 : break;
239 20 : case P_TYPE::RH_TAPPING_SYMBOL:
240 20 : set(idx, TConv::fromXml(e.readAsciiText(), RHTappingSymbol::T));
241 20 : break;
242 20 : case P_TYPE::TEXT_STYLE:
243 20 : set(idx, TConv::fromXml(e.readAsciiText(), TextStyleType::DEFAULT));
244 20 : break;
245 10 : case P_TYPE::PLAY_COUNT_PRESET:
246 10 : set(idx, TConv::fromXml(e.readAsciiText(), RepeatPlayCountPreset::X_N));
247 10 : break;
248 10 : case P_TYPE::MEASURE_NUMBER_PLACEMENT:
249 10 : set(idx, TConv::fromXml(e.readAsciiText(), MeasureNumberPlacement::ABOVE_SYSTEM));
250 10 : break;
251 12 : case P_TYPE::INSTRUMENT_NAMES_ALIGN:
252 12 : set(idx, TConv::fromXml(e.readAsciiText(), InstrumentNamesAlign::RIGHT_RIGHT));
253 12 : break;
254 12 : case P_TYPE::INSTRUMENT_NAMES_FORMAT:
255 12 : set(idx, TConv::fromXml(e.readAsciiText(), InstrumentNamesFormat::NAME_IN_TRANSP_NUM));
256 12 : break;
257 2 : case P_TYPE::AUTO_ON_OFF:
258 2 : set(idx, TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
259 2 : break;
260 0 : default:
261 0 : ASSERT_X(u"unhandled type " + String::number(int(type)));
262 : }
263 113344 : return true;
264 : }
265 : }
266 198 : if (readStyleValCompat(e)) {
267 8 : return true;
268 : }
269 190 : return false;
270 : }
271 :
272 : //---------------------------------------------------------
273 : // readStyleValCompat
274 : // Read obsolete style values which may appear in files
275 : // produced by older versions of MuseScore.
276 : //---------------------------------------------------------
277 :
278 198 : bool MStyle::readStyleValCompat(XmlReader& e)
279 : {
280 198 : const AsciiStringView tag(e.name());
281 198 : if (tag == "tempoOffset") { // pre-3.0-beta
282 0 : const double x = e.doubleAttribute("x", 0.0);
283 0 : const double y = e.doubleAttribute("y", 0.0);
284 0 : const PointF val(x, y);
285 0 : set(Sid::tempoPosAbove, val);
286 0 : set(Sid::tempoPosBelow, val);
287 0 : e.readText();
288 0 : return true;
289 : }
290 198 : if (readTextStyleValCompat(e)) {
291 8 : return true;
292 : }
293 190 : return false;
294 : }
295 :
296 : //---------------------------------------------------------
297 : // readTextStyleValCompat
298 : // Handle transition from separate bold, underline, strike
299 : // and italic style properties to the single *FontStyle
300 : // property set.
301 : //---------------------------------------------------------
302 :
303 198 : bool MStyle::readTextStyleValCompat(XmlReader& e)
304 : {
305 : static const std::array<std::pair<String, FontStyle>, 4> styleNamesEndings { {
306 0 : { u"FontBold", FontStyle::Bold },
307 0 : { u"FontItalic", FontStyle::Italic },
308 0 : { u"FontUnderline", FontStyle::Underline },
309 6 : { u"FontStrike", FontStyle::Strike }
310 198 : } };
311 :
312 198 : const String tag = String::fromAscii(e.name().ascii());
313 198 : FontStyle readFontStyle = FontStyle::Normal;
314 198 : String typeName;
315 966 : for (auto& fontStyle : styleNamesEndings) {
316 776 : if (tag.endsWith(fontStyle.first)) {
317 8 : readFontStyle = fontStyle.second;
318 8 : typeName = tag.mid(0, tag.size() - fontStyle.first.size());
319 8 : break;
320 : }
321 : }
322 198 : if (readFontStyle == FontStyle::Normal) {
323 190 : return false;
324 : }
325 :
326 8 : const String newFontStyleName = typeName + u"FontStyle";
327 8 : const Sid sid = MStyle::styleIdx(newFontStyleName);
328 8 : if (sid == Sid::NOSTYLE) {
329 0 : LOGW() << "readFontStyleValCompat: couldn't read text readFontStyle value:" << tag;
330 0 : return false;
331 : }
332 :
333 8 : const bool readVal = bool(e.readText().toInt());
334 8 : const PropertyValue& val = value(sid);
335 8 : FontStyle newFontStyle = val.isValid() ? FontStyle(val.toInt()) : FontStyle::Normal;
336 8 : if (readVal) {
337 0 : newFontStyle = newFontStyle + readFontStyle;
338 : } else {
339 8 : newFontStyle = newFontStyle - readFontStyle;
340 : }
341 :
342 8 : set(sid, int(newFontStyle));
343 8 : return true;
344 198 : }
345 :
346 832 : void MStyle::applyCompatStyleVals(int mscVersion)
347 : {
348 832 : if (mscVersion < 500) {
349 621 : set(Sid::windsNameByGroup, false);
350 621 : set(Sid::vocalsNameByGroup, false);
351 621 : set(Sid::maskSlurs, false);
352 621 : set(Sid::maskTies, false);
353 621 : set(Sid::dashBarWidth, value(Sid::barWidth));
354 621 : set(Sid::lyricsStackingOrder, int(LyricsStackingOrder::LYRICS_AFTER_PEDALS));
355 : }
356 :
357 832 : if (mscVersion < 470) {
358 615 : set(Sid::dividerLeftAlignToSystemBarline, false);
359 615 : set(Sid::dividerRightAlignToSystemBarline, false);
360 :
361 : // Musical symbol size
362 615 : compat::CompatUtils::setMusicSymbolSize470(*this);
363 :
364 : // Make sure new position styles are initially the same as align values
365 : // Exclude text styles which had align & position separated in 4.6
366 1230 : compat::CompatUtils::setPositionStylesFromAlign(this, { Sid::chordSymbolAAlign, Sid::chordSymbolBAlign, Sid::romanNumeralAlign,
367 : Sid::nashvilleNumberAlign, Sid::repeatLeftAlign, Sid::repeatRightAlign });
368 :
369 615 : if (value(Sid::chordStyle).value<ChordStylePreset>() == ChordStylePreset::JAZZ) {
370 0 : set(Sid::harmonyParenUseSmuflSym, true);
371 : }
372 : }
373 :
374 832 : if (mscVersion < 460) {
375 578 : bool verticalChordAlign = value(Sid::maxChordShiftAbove).value<Spatium>() != 0.0_sp
376 578 : || value(Sid::maxChordShiftBelow).value<Spatium>() != 0.0_sp
377 578 : || value(Sid::maxFretShiftAbove).value<Spatium>() != 0.0_sp
378 1156 : || value(Sid::maxFretShiftBelow).value<Spatium>() != 0.0_sp;
379 578 : set(Sid::verticallyAlignChordSymbols, verticalChordAlign);
380 : // Make sure new position styles are initially the same as align values
381 578 : compat::CompatUtils::setPositionStylesFromAlign(this);
382 :
383 578 : if (value(Sid::measureNumberPosition).value<AlignH>() == AlignH::HCENTER) {
384 432 : set(Sid::measureNumberHPlacement, AlignH::HCENTER);
385 : }
386 :
387 578 : if (value(Sid::pedalPlacement).value<PlacementV>() == PlacementV::BELOW
388 578 : && value(Sid::pedalHookHeight).value<Spatium>().val() < 0) {
389 71 : set(Sid::pedalHookHeight, -value(Sid::pedalHookHeight).value<Spatium>());
390 : }
391 578 : if (value(Sid::ottavaHookBelow).value<Spatium>().val() < 0) {
392 71 : set(Sid::ottavaHookBelow, -value(Sid::ottavaHookBelow).value<Spatium>());
393 : }
394 578 : set(Sid::repeatPlayCountShow, false);
395 :
396 578 : set(Sid::harmonyHarmonyDistance, value(Sid::minHarmonyDistance));
397 : }
398 :
399 832 : if (mscVersion == 450) {
400 : // 450 spacing was a bit narrower
401 14 : set(Sid::spacingDensity, 1.30);
402 : }
403 :
404 832 : if (mscVersion < 450) {
405 : // Didn't exist before 4.5. Default to false for compatibility.
406 564 : set(Sid::scaleRythmicSpacingForSmallNotes, false);
407 564 : set(Sid::maskBarlinesForText, false);
408 564 : set(Sid::showCourtesiesRepeats, false);
409 564 : set(Sid::showCourtesiesOtherJumps, false);
410 564 : set(Sid::showCourtesiesAfterCancellingRepeats, false);
411 564 : set(Sid::showCourtesiesAfterCancellingOtherJumps, false);
412 564 : set(Sid::changesBeforeBarlineRepeats, false);
413 564 : set(Sid::changesBeforeBarlineOtherJumps, false);
414 : }
415 :
416 832 : if (mscVersion < 420 && !MScore::testMode) {
417 : // This style didn't exist before version 4.2. For files older than 4.2, defaults
418 : // to INSIDE for compatibility. For files 4.2 and newer, defaults to OUTSIDE.
419 0 : set(Sid::tiePlacementChord, TiePlacement::INSIDE);
420 : }
421 832 : }
422 :
423 83 : bool MStyle::read(IODevice* device, bool ign)
424 : {
425 : UNUSED(ign);
426 83 : XmlReader e(device);
427 249 : while (e.readNextStartElement()) {
428 83 : if (e.name() == "museScore") {
429 83 : const String versionTag = e.attribute("version").remove(u'.');
430 83 : const int mscVersion = versionTag.toInt();
431 166 : while (e.readNextStartElement()) {
432 83 : if (e.name() == "Style") {
433 83 : read(e, nullptr, mscVersion);
434 : } else {
435 0 : e.unknown();
436 : }
437 : }
438 83 : }
439 : }
440 83 : return true;
441 83 : }
442 :
443 0 : bool MStyle::isValid(IODevice* device)
444 : {
445 0 : XmlReader e(device);
446 0 : while (!e.isError() && e.readNextStartElement()) {
447 0 : if (e.name() == "museScore") {
448 0 : while (e.readNextStartElement()) {
449 0 : if (e.name() == "Style") {
450 0 : return true;
451 : }
452 : }
453 : }
454 : }
455 0 : return false;
456 0 : }
457 :
458 832 : void MStyle::read(XmlReader& e, compat::ReadChordListHook* readChordListHook, int mscVersion)
459 : {
460 832 : TRACEFUNC;
461 :
462 123728 : while (e.readNextStartElement()) {
463 122896 : const AsciiStringView tag(e.name());
464 :
465 122896 : if (tag == "TextStyle") {
466 : //readTextStyle206(this, e); // obsolete
467 0 : e.readText();
468 122896 : } else if (tag == "ottavaHook") { // obsolete, for 3.0dev bw. compatibility, should be removed in final release
469 0 : double y = std::abs(e.readDouble());
470 0 : set(Sid::ottavaHookAbove, y);
471 0 : set(Sid::ottavaHookBelow, -y);
472 122896 : } else if (tag == "Spatium" || tag == "spatium") {
473 827 : set(Sid::spatium, e.readDouble() * DPMM);
474 122069 : } else if (tag == "page-layout") { // obsolete
475 0 : compat::readPageFormat206(this, e);
476 122069 : } else if (tag == "displayInConcertPitch") {
477 0 : set(Sid::concertPitch, e.readBool());
478 122069 : } else if (tag == "ChordList") {
479 1 : if (readChordListHook) {
480 1 : readChordListHook->read(e);
481 : }
482 122068 : } else if (tag == "lyricsDashMaxLegth") { // pre-3.6 typo
483 9 : set(Sid::lyricsDashMaxLength, Spatium(e.readDouble()));
484 122059 : } else if (tag == "dontHidStavesInFirstSystm") { // pre-3.6.3/4.0 typo
485 11 : set(Sid::dontHideStavesInFirstSystem, e.readBool());
486 122048 : } else if (tag == "minSpreadSpread") { // pre-4.4 typo
487 48 : set(Sid::minStaffSpread, Spatium(e.readDouble()));
488 122000 : } else if (tag == "maxSpreadSpread") { // pre-4.4 typo
489 48 : set(Sid::maxStaffSpread, Spatium(e.readDouble()));
490 121952 : } else if (tag == "beamDistance") { // beamDistance maps to useWideBeams in 4.0
491 19 : set(Sid::useWideBeams, e.readDouble() > 0.75);
492 121933 : } else if (tag == "hairpinWidth") { // pre-4.4 typo
493 58 : set(Sid::hairpinLineWidth, Spatium(e.readDouble()));
494 121875 : } else if (tag == "chordSymbolPosAbove") { // pre-4.4 typo
495 57 : set(Sid::chordSymbolAPosAbove, e.readPoint());
496 121818 : } else if (tag == "chordSymbolPosBelow") { // pre-4.4 typo
497 57 : set(Sid::chordSymbolAPosBelow, e.readPoint());
498 121761 : } else if (tag == "dontHidStavesInFirstSystm") { // pre-3.6.3/4.0 typo
499 0 : set(Sid::dontHideStavesInFirstSystem, e.readBool());
500 121761 : } else if (tag == "firstSystemInsNameVisibility") { // pre-4.4 typo
501 0 : set(Sid::firstSystemInstNameVisibility, e.readInt());
502 121761 : } else if ((tag == "articulationMinDistance"
503 121678 : || tag == "propertyDistanceHead"
504 121595 : || tag == "propertyDistanceStem"
505 121511 : || tag == "propertyDistance"
506 121428 : || tag == "bracketDistance")
507 243439 : && mscVersion < 400) {
508 : // Ignoring pre-4.0 articulation style and brackets distance settings. Using the new defaults instead
509 60 : e.skipCurrentElement();
510 121701 : } else if (tag == "pedalListStyle") { // pre-3.6.3/4.0 typo
511 52 : set(Sid::pedalLineStyle, TConv::fromXml(e.readAsciiText(), LineType::SOLID));
512 121649 : } else if (tag == "chordlineThickness" && mscVersion < 410) {
513 : // Ignoring pre-4.1 value as it was wrong (it wasn't user-editable anyway)
514 4 : e.skipCurrentElement();
515 121645 : } else if (tag == "pedalText" && mscVersion < 420) {
516 : // Ignore old default
517 1 : String pedText = e.readText();
518 1 : if (!pedText.empty()) {
519 0 : set(Sid::pedalText, pedText);
520 : }
521 121645 : } else if (tag == "pedalContinueText" && mscVersion < 420) {
522 : // Ignore old default
523 1 : String pedContText = e.readText();
524 1 : if (!pedContText.empty()) {
525 0 : set(Sid::pedalText, pedContText);
526 : }
527 121644 : } else if (tag == "ArpeggioNoteDistance") { // pre-4.4 typo
528 57 : set(Sid::arpeggioNoteDistance, Spatium(e.readDouble()));
529 121586 : } else if (tag == "ArpeggioAccidentalDistance") { // pre-4.4 typo
530 46 : set(Sid::arpeggioAccidentalDistance, Spatium(e.readDouble()));
531 121540 : } else if (tag == "ArpeggioAccidentalDistanceMin") { // pre-4.4 typo
532 46 : set(Sid::arpeggioAccidentalDistanceMin, Spatium(e.readDouble()));
533 121494 : } else if (tag == "ArpeggioLineWidth") { // pre-x.4 typo
534 57 : set(Sid::arpeggioLineWidth, Spatium(e.readDouble()));
535 121437 : } else if (tag == "ArpeggioHookLen") { // pre-x.4 typo
536 57 : set(Sid::arpeggioHookLen, Spatium(e.readDouble()));
537 121380 : } else if (tag == "ArpeggioHiddenInStdIfTab") { // pre-x.4 typo
538 57 : set(Sid::arpeggioHiddenInStdIfTab, e.readBool());
539 121323 : } else if ((tag == "slurEndWidth"
540 121236 : || tag == "slurMidWidth"
541 121148 : || tag == "slurDottedWidth"
542 121065 : || tag == "slurMinDistance")
543 242559 : && mscVersion < 430) {
544 : // Pre-4.3 scores used identical style values for slurs and ties.
545 : // When opening older scores, use the same values for both.
546 229 : double _val = e.readDouble();
547 229 : if (tag == "slurEndWidth") {
548 57 : set(Sid::tieEndWidth, Spatium(_val));
549 57 : set(Sid::slurEndWidth, Spatium(_val));
550 172 : } else if (tag == "slurMidWidth") {
551 58 : set(Sid::tieMidWidth, Spatium(_val));
552 58 : set(Sid::slurMidWidth, Spatium(_val));
553 114 : } else if (tag == "slurDottedWidth") {
554 57 : set(Sid::tieDottedWidth, Spatium(_val));
555 57 : set(Sid::slurDottedWidth, Spatium(_val));
556 57 : } else if (tag == "slurMinDistance") {
557 57 : set(Sid::tieMinDistance, Spatium(_val));
558 57 : set(Sid::slurMinDistance, Spatium(_val));
559 : }
560 121094 : } else if (tag == "measureNumberOffset" && mscVersion < 440) { // pre-4.4 typo
561 57 : set(Sid::measureNumberPosAbove, PointF(e.readPoint()));
562 121037 : } else if (tag == "measureNumberPosAbove" && mscVersion < 440) { // pre-4.4 typo
563 48 : set(Sid::mmRestRangePosAbove, PointF(e.readPoint()));
564 120989 : } else if (tag == "ottavaTextAlign") {
565 : // Pre-x.x (?) scores used identical style values for Above and Below
566 : // apparently the old default was "VCENTER",
567 : // so better ignore and take the new defaults
568 39 : e.skipCurrentElement(); // obsolete
569 120950 : } else if (tag == "tremoloStrokeStyle") { // pre-4.4 typo
570 57 : set(Sid::tremoloStyle, e.readInt());
571 120893 : } else if (tag == "systemFontFace") { // pre-4.4 typo
572 58 : set(Sid::systemTextFontFace, e.readText());
573 120835 : } else if (tag == "systemFontSize") { // pre-4.4 typo
574 57 : set(Sid::systemTextFontSize, e.readDouble());
575 120778 : } else if (tag == "systemFontSpatiumDependent") { // pre-4.4 typo
576 57 : set(Sid::systemTextFontSpatiumDependent, bool(e.readInt()));
577 120721 : } else if (tag == "systemFontStyle") { // pre-4.4 typo
578 57 : set(Sid::systemTextFontStyle, e.readInt());
579 120664 : } else if (tag == "systemAlign") { // pre-4.4 typo
580 48 : set(Sid::systemTextAlign, TConv::fromXml(e.readText(), Align()));
581 120616 : } else if (tag == "systemOffsetType") { // pre-4.4 typo
582 114 : set(Sid::systemTextOffsetType, e.readInt());
583 120502 : } else if (tag == "systemPlacement") { // pre-4.4 typo
584 57 : set(Sid::systemTextPlacement, PlacementV(e.readText().toInt()));
585 120445 : } else if (tag == "systemPosAbove") { // pre-4.4 typo
586 57 : set(Sid::systemTextPosAbove, PointF(e.readPoint()));
587 120388 : } else if (tag == "systemPosBelow") { // pre-4.4 typo
588 57 : set(Sid::systemTextPosBelow, PointF(e.readPoint()));
589 120331 : } else if (tag == "systemMinDistance") { // pre-4.4 typo
590 57 : set(Sid::systemTextMinDistance, Spatium(e.readDouble()));
591 120274 : } else if (tag == "systemFrameType") { // pre-4.4 typo
592 57 : set(Sid::systemTextFrameType, e.readInt());
593 120217 : } else if (tag == "systemFramePadding") { // pre-4.4 typo
594 59 : set(Sid::systemTextFramePadding, e.readDouble());
595 120158 : } else if (tag == "systemFrameWidth") { // pre-4.4 typo
596 59 : set(Sid::systemTextFrameWidth, e.readDouble());
597 120099 : } else if (tag == "systemFrameRound") { // pre-4.4 typo
598 59 : set(Sid::systemTextFrameRound, e.readDouble());
599 120040 : } else if (tag == "systemFrameFgColor") { // pre-4.4 typo
600 57 : set(Sid::systemTextFrameFgColor, e.readColor());
601 119983 : } else if (tag == "systemFrameBgColor") { // pre-4.4 typo
602 57 : set(Sid::systemTextFrameBgColor, e.readColor());
603 119926 : } else if (tag == "staffFontFace") { // pre-4.4 typo
604 58 : set(Sid::staffTextFontFace, e.readText());
605 119868 : } else if (tag == "staffFontSize") { // pre-4.4 typo
606 57 : set(Sid::staffTextFontSize, e.readDouble());
607 119811 : } else if (tag == "staffFontSpatiumDependent") { // pre-4.4 typo
608 57 : set(Sid::staffTextFontSpatiumDependent, e.readBool());
609 119754 : } else if (tag == "staffFontStyle") { // pre-4.4 typo
610 57 : set(Sid::staffTextFontStyle, e.readInt());
611 119697 : } else if (tag == "staffAlign") { // pre-4.4 typo
612 50 : set(Sid::staffTextAlign, TConv::fromXml(e.readText(), Align()));
613 119647 : } else if (tag == "staffOffsetType") { // pre-4.4 typo
614 0 : set(Sid::staffTextOffsetType, e.readInt());
615 119647 : } else if (tag == "staffPlacement") { // pre-4.4 typo
616 57 : set(Sid::staffTextPlacement, PlacementV(e.readText().toInt()));
617 119590 : } else if (tag == "staffTextPosAbove" // pre-4.4 typo, certainly before 3.6, even before 3.5
618 119590 : && mscVersion <= 410) { // so we might test for < 302, however m_version seems set to 410 here?!?
619 0 : double staffTextPosAboveY = e.readDouble();
620 0 : set(Sid::staffTextPosAbove, PointF(0.0, staffTextPosAboveY));
621 119590 : } else if (tag == "staffPosAbove") { // pre-4.4 typo
622 57 : set(Sid::staffTextPosAbove, e.readPoint());
623 119533 : } else if (tag == "staffPosBelow") { // pre-4.4 typo
624 57 : set(Sid::staffTextPosBelow, e.readPoint());
625 119476 : } else if (tag == "staffTextMinDistance" // pre-4.4 typo, certainly before 3.6, even before 3.5
626 119476 : && mscVersion <= 410) { // so we might test for < 302, however m_version seems set to 410 here?!?
627 0 : set(Sid::staffTextMinDistance, Spatium(e.readDouble()));
628 119476 : } else if (tag == "staffMinDistance") { // pre-4.4 typo
629 57 : set(Sid::staffTextMinDistance, Spatium(e.readDouble()));
630 119419 : } else if (tag == "staffFrameType") { // pre-4.4 typo
631 57 : set(Sid::staffTextFrameType, e.readInt());
632 119362 : } else if (tag == "staffFramePadding") { // pre-4.4 typo
633 59 : set(Sid::staffTextFramePadding, e.readDouble());
634 119303 : } else if (tag == "staffFrameWidth") { // pre-4.4 typo
635 59 : set(Sid::staffTextFrameWidth, e.readDouble());
636 119244 : } else if (tag == "staffFrameRound") { // pre-4.4 typo
637 59 : set(Sid::staffTextFrameRound, e.readDouble());
638 119185 : } else if (tag == "staffFrameFgColor") { // pre-4.4 typo
639 57 : set(Sid::staffTextFrameFgColor, e.readColor());
640 119128 : } else if (tag == "staffFrameBgColor") { // pre-4.4 typo
641 57 : set(Sid::staffTextFrameBgColor, e.readColor());
642 119071 : } else if (tag == "dymanicsShowTabCommon") { // pre-4.4 typo in gp-style.mss
643 0 : set(Sid::dynamicsShowTabCommon, bool(e.readInt()));
644 119071 : } else if (tag == "tupletOufOfStaff") {
645 63 : set(Sid::tupletOutOfStaff, bool(e.readInt()));
646 119008 : } else if (tag == "pedalBeginTextOffset"
647 118960 : || tag == "letRingBeginTextOffset"
648 118912 : || tag == "palmMuteBeginTextOffset"
649 118864 : || tag == "defaultFontSpatiumDependent"
650 237968 : || tag == "usePre_3_6_defaults") {
651 229 : e.skipCurrentElement(); // obsolete
652 118779 : } else if (tag == "articulationAnchorDefault" && mscVersion < 410) {
653 52 : set(Sid::articulationAnchorDefault, (int)compat::CompatUtils::translateToNewArticulationAnchor(e.readInt()));
654 118727 : } else if (tag == "articulationAnchorLuteFingering" && mscVersion < 410) {
655 52 : set(Sid::articulationAnchorLuteFingering, (int)compat::CompatUtils::translateToNewArticulationAnchor(e.readInt()));
656 118675 : } else if (tag == "articulationAnchorOther" && mscVersion < 410) {
657 52 : set(Sid::articulationAnchorOther, (int)compat::CompatUtils::translateToNewArticulationAnchor(e.readInt()));
658 118623 : } else if (tag == "lineEndToSystemEndDistance") { // renamed in 4.5
659 0 : set(Sid::lineEndToBarlineDistance, Spatium(e.readDouble()));
660 118623 : } else if (tag == "useStandardNoteNames") { // These settings were collapsed into one enum in 4.6
661 76 : if (e.readBool()) {
662 72 : set(Sid::chordSymbolSpelling, NoteSpellingType::STANDARD);
663 : }
664 118547 : } else if (tag == "useGermanNoteNames") {
665 73 : if (e.readBool()) {
666 0 : set(Sid::chordSymbolSpelling, NoteSpellingType::GERMAN);
667 : }
668 118474 : } else if (tag == "useFullGermanNoteNames") {
669 73 : if (e.readBool()) {
670 0 : set(Sid::chordSymbolSpelling, NoteSpellingType::GERMAN_PURE);
671 : }
672 118401 : } else if (tag == "useSolfeggioNoteNames") {
673 73 : if (e.readBool()) {
674 0 : set(Sid::chordSymbolSpelling, NoteSpellingType::SOLFEGGIO);
675 : }
676 118328 : } else if (tag == "useFrenchNoteNames") {
677 73 : if (e.readBool()) {
678 0 : set(Sid::chordSymbolSpelling, NoteSpellingType::FRENCH);
679 : }
680 118255 : } else if (tag == "chordModifierAdjust" && mscVersion < 460) {
681 71 : set(Sid::chordModifierAdjust, compat::CompatUtils::convertChordExtModUnits(e.readDouble()));
682 118184 : } else if (tag == "chordExtensionAdjust" && mscVersion < 460) {
683 71 : set(Sid::chordExtensionAdjust, compat::CompatUtils::convertChordExtModUnits(e.readDouble()));
684 118113 : } else if (tag == "chordDescriptionFile" && mscVersion < 460) {
685 72 : AsciiStringView val = e.readAsciiText();
686 72 : if (val == "chords_std.xml") {
687 60 : set(Sid::chordDescriptionFile, String(u"chords_legacy.xml"));
688 : } else {
689 12 : set(Sid::chordDescriptionFile, String::fromAscii(val.ascii()));
690 : }
691 118041 : } else if (tag == "chordStyle" && mscVersion < 460) {
692 72 : AsciiStringView val = e.readAsciiText();
693 72 : if (val == "std") {
694 60 : set(Sid::chordStyle, ChordStylePreset::LEGACY);
695 : } else {
696 12 : set(Sid::chordStyle, TConv::fromXml(val, ChordStylePreset::STANDARD));
697 : }
698 117969 : } else if (tag == "fretFrets" && mscVersion < 460) {
699 71 : e.skipCurrentElement();
700 117898 : } else if (tag == "measureNumberHPlacement" && mscVersion < 460) {
701 : // Before 460 PlacementH was used instead of AlignH, and was written as integer.
702 : // We can't directly map the integer to AlignH because it's enumerated differently.
703 71 : PlacementH hPlacement = PlacementH(e.readInt());
704 71 : AlignH hAlign = hPlacement == PlacementH::LEFT ? AlignH::LEFT
705 0 : : hPlacement == PlacementH::CENTER ? AlignH::HCENTER : AlignH::RIGHT;
706 71 : set(Sid::measureNumberHPlacement, hAlign);
707 :
708 71 : if (value(Sid::measureNumberHPlacement).value<AlignH>() != AlignH::LEFT) {
709 : // In this case it was assumed to be centered on the measure
710 0 : set(Sid::measureNumberAlignToBarline, false);
711 : }
712 117827 : } else if (tag == "mmRestRangeHPlacement" && mscVersion < 460) {
713 : // Before 460 PlacementH was used instead of AlignH, and was written as integer.
714 : // We can't directly map the integer to AlignH because it's enumerated differently.
715 62 : PlacementH hPlacement = PlacementH(e.readInt());
716 124 : AlignH hAlign = hPlacement == PlacementH::LEFT ? AlignH::LEFT
717 62 : : hPlacement == PlacementH::CENTER ? AlignH::HCENTER : AlignH::RIGHT;
718 62 : set(Sid::mmRestRangeHPlacement, hAlign);
719 117765 : } else if (tag == "measureNumberAllStaves" || tag == "measureNumberAllStaffs" /*old typo*/) {
720 73 : bool allStaves = e.readBool();
721 73 : set(Sid::measureNumberPlacementMode, allStaves ? MeasureNumberPlacement::ON_ALL_STAVES : MeasureNumberPlacement::ABOVE_SYSTEM);
722 117692 : } else if (String sTag = String::fromAscii(tag.ascii()); mscVersion < 470 && sTag.contains(u"FrameRound")) {
723 4360 : auto i = std::find_if(StyleDef::styleValues.begin(), StyleDef::styleValues.end(), [&](const StyleDef::StyleValue& s) {
724 4863771 : return s.xmlName == tag;
725 : });
726 4360 : if (i != StyleDef::styleValues.end()) {
727 4360 : const StyleDef::StyleValue& s = *i;
728 4360 : set(s.sid, compat::CompatUtils::convertPre470FrameRadius(e.readDouble()));
729 : }
730 113332 : } else if (!readProperties(e)) {
731 141 : e.unknown();
732 117692 : }
733 : }
734 :
735 832 : applyCompatStyleVals(mscVersion);
736 :
737 832 : if (readChordListHook) {
738 749 : readChordListHook->validate();
739 : }
740 832 : }
741 :
742 3 : bool MStyle::write(IODevice* device)
743 : {
744 3 : XmlWriter xml(device);
745 3 : xml.startDocument();
746 9 : xml.startElement("museScore", { { "version", Constants::MSC_VERSION_STR } });
747 3 : save(xml, false);
748 3 : xml.endElement();
749 3 : return true;
750 6 : }
751 :
752 1099 : void MStyle::save(XmlWriter& xml, bool optimize)
753 : {
754 1099 : xml.startElement("Style");
755 :
756 2258445 : for (const StyleDef::StyleValue& st : StyleDef::styleValues) {
757 2257346 : Sid idx = st.sid;
758 2257346 : if (idx == Sid::spatium) { // special handling for spatium
759 1099 : continue;
760 : }
761 2256247 : if (optimize && isDefault(idx)) {
762 2241473 : continue;
763 : }
764 14774 : P_TYPE type = st.valueType();
765 14774 : if (P_TYPE::SPATIUM == type) {
766 2555 : xml.tag(st.xmlName, value(idx).value<Spatium>().val());
767 12219 : } else if (P_TYPE::DIRECTION_V == type) {
768 6 : xml.tag(st.xmlName, int(value(idx).value<DirectionV>()));
769 12213 : } else if (P_TYPE::ORIENTATION == type) {
770 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<Orientation>()));
771 12210 : } else if (P_TYPE::SHARED_LABEL_ORIENTATION == type) {
772 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<SharedLabelOrientation>()));
773 12207 : } else if (P_TYPE::ALIGN == type) {
774 301 : Align a = value(idx).value<Align>();
775 : // Don't write if it's the default value
776 301 : if (optimize && a == st.defaultValue.value<Align>()) {
777 21 : continue;
778 : }
779 280 : xml.tag(st.xmlName, TConv::toXml(a));
780 11906 : } else if (P_TYPE::ALIGN_H == type) {
781 262 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<AlignH>()));
782 11644 : } else if (P_TYPE::LINE_TYPE == type) {
783 39 : xml.tagProperty(st.xmlName, value(idx));
784 11605 : } else if (P_TYPE::TIE_PLACEMENT == type) {
785 8 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<TiePlacement>()));
786 11597 : } else if (P_TYPE::TIE_DOTS_PLACEMENT == type) {
787 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<TieDotsPlacement>()));
788 11594 : } else if (P_TYPE::TIMESIG_PLACEMENT == type) {
789 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<TimeSigPlacement>()));
790 11591 : } else if (P_TYPE::TIMESIG_STYLE == type) {
791 9 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<TimeSigStyle>()));
792 11582 : } else if (P_TYPE::TIMESIG_MARGIN == type) {
793 6 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<TimeSigVSMargin>()));
794 11576 : } else if (P_TYPE::CHORD_PRESET_TYPE == type) {
795 9 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<ChordStylePreset>()));
796 11567 : } else if (P_TYPE::NOTE_SPELLING_TYPE == type) {
797 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<NoteSpellingType>()));
798 11564 : } else if (P_TYPE::LH_TAPPING_SYMBOL == type) {
799 6 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<LHTappingSymbol>()));
800 11558 : } else if (P_TYPE::RH_TAPPING_SYMBOL == type) {
801 6 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<RHTappingSymbol>()));
802 11552 : } else if (P_TYPE::TEXT_STYLE == type) {
803 6 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<TextStyleType>()));
804 11546 : } else if (P_TYPE::PARENTHESES_MODE == type) {
805 0 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<ParenthesesMode>()));
806 11546 : } else if (P_TYPE::PLAY_COUNT_PRESET == type) {
807 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<RepeatPlayCountPreset>()));
808 11543 : } else if (P_TYPE::MEASURE_NUMBER_PLACEMENT == type) {
809 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<MeasureNumberPlacement>()));
810 11540 : } else if (P_TYPE::INSTRUMENT_NAMES_ALIGN == type) {
811 6 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<InstrumentNamesAlign>()));
812 11534 : } else if (P_TYPE::INSTRUMENT_NAMES_FORMAT == type) {
813 6 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<InstrumentNamesFormat>()));
814 11528 : } else if (P_TYPE::AUTO_ON_OFF == type) {
815 3 : xml.tag(st.xmlName, TConv::toXml(value(idx).value<AutoOnOff>()));
816 : } else {
817 11525 : PropertyValue val = value(idx);
818 : //! NOTE for compatibility
819 11525 : if (val.isEnum()) {
820 148 : val = val.value<int>();
821 : }
822 11525 : xml.tagProperty(st.xmlName, val);
823 11525 : }
824 : }
825 :
826 1099 : xml.tag("spatium", value(Sid::spatium).toReal() / DPMM);
827 1099 : xml.endElement();
828 1099 : }
829 :
830 : // ====================================================
831 : // Static
832 : // ====================================================
833 :
834 17458298 : P_TYPE MStyle::valueType(const Sid i)
835 : {
836 17458298 : return StyleDef::styleValues[size_t(i)].valueType();
837 : }
838 :
839 0 : const char* MStyle::valueName(const Sid i)
840 : {
841 0 : if (i == Sid::NOSTYLE) {
842 : static const char* no_style = "no style";
843 0 : return no_style;
844 : }
845 0 : return StyleDef::styleValues[size_t(i)].xmlName.ascii();
846 : }
847 :
848 8 : Sid MStyle::styleIdx(const String& name)
849 : {
850 8 : muse::ByteArray ba = name.toAscii();
851 8368 : for (const StyleDef::StyleValue& st : StyleDef::styleValues) {
852 8368 : if (st.xmlName == ba.constChar()) {
853 8 : return st.sid;
854 : }
855 : }
856 0 : return Sid::NOSTYLE;
857 8 : }
|