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 "connectorinfowriter.h"
23 :
24 : #include "../../dom/engravingitem.h"
25 : #include "../../dom/spanner.h"
26 : #include "../../dom/measurebase.h"
27 : #include "../../dom/measure.h"
28 : #include "../../dom/score.h"
29 :
30 : #include "../xmlwriter.h"
31 :
32 : #include "twrite.h"
33 :
34 : #include "log.h"
35 :
36 : using namespace mu::engraving;
37 : using namespace mu::engraving::write;
38 :
39 0 : ConnectorInfoWriter::ConnectorInfoWriter(XmlWriter& xml, WriteContext* ctx, const EngravingItem* current,
40 : const EngravingItem* connector,
41 : int track,
42 0 : Fraction frac)
43 0 : : ConnectorInfo(current, track, frac), _connector(connector), m_xml(&xml), m_ctx(ctx)
44 : {
45 0 : IF_ASSERT_FAILED(current) {
46 0 : return;
47 : }
48 0 : m_type = connector->type();
49 0 : updateCurrentInfo(m_ctx->clipboardmode());
50 0 : }
51 :
52 0 : void ConnectorInfoWriter::write()
53 : {
54 0 : XmlWriter& xml = *m_xml;
55 0 : WriteContext& ctx = *m_ctx;
56 0 : if (!ctx.canWrite(_connector)) {
57 0 : return;
58 : }
59 0 : xml.startElement(tagName(), { { "type", _connector->typeName() } });
60 0 : if (isStart()) {
61 0 : TWrite::writeItem(_connector, xml, ctx);
62 : }
63 0 : if (hasPrevious()) {
64 0 : xml.startElement("prev");
65 0 : m_prevLoc.toRelative(m_currentLoc);
66 0 : TWrite::write(&m_prevLoc, xml, ctx);
67 0 : xml.endElement();
68 : }
69 0 : if (hasNext()) {
70 0 : xml.startElement("next");
71 0 : m_nextLoc.toRelative(m_currentLoc);
72 0 : TWrite::write(&m_nextLoc, xml, ctx);
73 0 : xml.endElement();
74 : }
75 0 : xml.endElement();
76 0 : }
77 :
78 : //---------------------------------------------------------
79 : // SpannerWriter::fillSpannerPosition
80 : //---------------------------------------------------------
81 :
82 0 : void SpannerWriter::fillSpannerPosition(Location& l, const MeasureBase* m, const Fraction& tick, bool clipboardmode)
83 : {
84 0 : if (clipboardmode) {
85 0 : l.setMeasure(0);
86 0 : l.setFrac(tick);
87 : } else {
88 0 : if (!m) {
89 0 : LOGW("fillSpannerPosition: couldn't find spanner's endpoint's measure");
90 0 : l.setMeasure(0);
91 0 : l.setFrac(tick);
92 0 : return;
93 : }
94 0 : l.setMeasure(m->measureIndex());
95 0 : l.setFrac(tick - m->tick());
96 : }
97 : }
98 :
99 : //---------------------------------------------------------
100 : // SpannerWriter::SpannerWriter
101 : //---------------------------------------------------------
102 :
103 0 : SpannerWriter::SpannerWriter(XmlWriter& xml, WriteContext* ctx, const EngravingItem* current, const Spanner* sp, int track, Fraction frac,
104 0 : bool start)
105 0 : : ConnectorInfoWriter(xml, ctx, current, sp, track, frac)
106 : {
107 0 : const bool clipboardmode = ctx->clipboardmode();
108 0 : if ((!sp->startElement() || !sp->endElement())
109 0 : && (sp->anchor() == Spanner::Anchor::CHORDREST || sp->anchor() == Spanner::Anchor::NOTE)) {
110 0 : LOGW("SpannerWriter: spanner (%s) doesn't have an endpoint!", sp->typeName());
111 0 : return;
112 : }
113 0 : if (current->isMeasure() || current->isSegment() || !sp->startElement() || !sp->endElement()
114 0 : || (sp->startElement()->type() != current->type())) {
115 : // (The latter is the hairpins' case, for example, though they are
116 : // covered by the other checks too.)
117 : // We cannot determine position of the spanner from its start/end
118 : // elements and will try to obtain this info from the spanner itself.
119 0 : if (!start) {
120 0 : m_prevLoc.setTrack(static_cast<int>(sp->track()));
121 0 : Measure* m = sp->score()->tick2measure(sp->tick());
122 0 : fillSpannerPosition(m_prevLoc, m, sp->tick(), clipboardmode);
123 : } else {
124 0 : const track_idx_t track2 = (sp->track2() != muse::nidx) ? sp->track2() : sp->track();
125 0 : m_nextLoc.setTrack(static_cast<int>(track2));
126 0 : Measure* m = sp->score()->tick2measure(sp->tick2());
127 0 : fillSpannerPosition(m_nextLoc, m, sp->tick2(), clipboardmode);
128 : }
129 : } else {
130 : // We can obtain the spanner position info from its start/end
131 : // elements and will prefer this source of information.
132 : // Reason: some spanners contain no or wrong information (e.g. Ties).
133 0 : if (!start) {
134 0 : updateLocation(sp->startElement(), m_prevLoc, clipboardmode);
135 : } else {
136 0 : updateLocation(sp->endElement(), m_nextLoc, clipboardmode);
137 : }
138 : }
139 0 : }
|