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 "marker.h"
24 :
25 : #include "dom/staff.h"
26 : #include "dom/system.h"
27 : #include "types/typesconv.h"
28 :
29 : #include "measure.h"
30 : #include "score.h"
31 :
32 : #include "log.h"
33 :
34 : using namespace mu;
35 : using namespace mu::engraving;
36 :
37 : namespace mu::engraving {
38 : //---------------------------------------------------------
39 : // markerStyle
40 : //---------------------------------------------------------
41 :
42 : static const ElementStyle markerStyle {
43 : { Sid::repeatLeftPlacement, Pid::PLACEMENT },
44 : { Sid::repeatMinDistance, Pid::MIN_DISTANCE },
45 : };
46 :
47 : //---------------------------------------------------------
48 : // MarkerTypeTable
49 : //---------------------------------------------------------
50 :
51 : const std::vector<MarkerTypeTableItem> markerTypeTable {
52 : { MarkerType::SEGNO, "<sym>segno</sym>", "segno", false },
53 : { MarkerType::VARSEGNO, "<sym>segnoSerpent1</sym>", "varsegno", false },
54 : { MarkerType::CODA, "<sym>coda</sym>", "codab", false },
55 : { MarkerType::VARCODA, "<sym>codaSquare</sym>", "varcoda", false },
56 : { MarkerType::CODETTA, "<sym>coda</sym><sym>coda</sym>", "codetta", false },
57 : { MarkerType::FINE, "Fine", "fine", true },
58 : { MarkerType::TOCODA, "To Coda", "coda", true },
59 : { MarkerType::TOCODASYM, "To <sym>coda</sym>", "coda", true },
60 : { MarkerType::DA_CODA, "Da Coda", "coda", true },
61 : { MarkerType::DA_DBLCODA, "Da Doppia Coda", "coda", true },
62 : };
63 :
64 : //---------------------------------------------------------
65 : // Marker
66 : //---------------------------------------------------------
67 :
68 220 : Marker::Marker(DummyParentOr<EngravingItem> parent)
69 220 : : Marker(parent, TextStyleType::REPEAT_LEFT)
70 : {
71 220 : resetProperty(Pid::MUSIC_SYMBOL_SIZE);
72 220 : }
73 :
74 230 : Marker::Marker(DummyParentOr<EngravingItem> parent, TextStyleType tid)
75 230 : : TextBase(ElementType::MARKER, parent, tid, ElementFlag::MOVABLE | ElementFlag::ON_STAFF | ElementFlag::SYSTEM)
76 : {
77 230 : initElementStyle(&markerStyle);
78 230 : resetProperty(Pid::MUSIC_SYMBOL_SIZE);
79 230 : m_markerType = MarkerType::FINE;
80 230 : }
81 :
82 : //---------------------------------------------------------
83 : // setMarkerType
84 : //---------------------------------------------------------
85 :
86 234 : void Marker::setMarkerType(MarkerType t)
87 : {
88 234 : bool changeLabel = getProperty(Pid::LABEL) == propertyDefault(Pid::LABEL);
89 234 : m_markerType = t;
90 987 : for (const MarkerTypeTableItem& p : markerTypeTable) {
91 972 : if (p.type == t) {
92 219 : if (empty()) {
93 69 : setXmlText(String::fromAscii(p.text.ascii()));
94 : }
95 219 : if (changeLabel) {
96 79 : setLabel(String::fromAscii(p.label.ascii()));
97 : }
98 219 : TextStyleType ts = p.rightAligned ? TextStyleType::REPEAT_RIGHT : TextStyleType::REPEAT_LEFT;
99 219 : if (textStyleType() != ts) {
100 17 : initTextStyleType(ts);
101 : }
102 :
103 219 : break;
104 : }
105 : }
106 234 : }
107 :
108 : //---------------------------------------------------------
109 : // markerTypeUserName
110 : //---------------------------------------------------------
111 :
112 0 : String Marker::markerTypeUserName() const
113 : {
114 0 : return TConv::translatedUserName(m_markerType);
115 : }
116 :
117 : //---------------------------------------------------------
118 : // getProperty
119 : //---------------------------------------------------------
120 :
121 2286 : PropertyValue Marker::getProperty(Pid propertyId) const
122 : {
123 2286 : switch (propertyId) {
124 234 : case Pid::LABEL:
125 234 : return label();
126 75 : case Pid::MARKER_TYPE:
127 75 : return markerType();
128 75 : case Pid::MARKER_CENTER_ON_SYMBOL:
129 75 : return centerOnSymbol();
130 1902 : default:
131 1902 : break;
132 : }
133 1902 : return TextBase::getProperty(propertyId);
134 : }
135 :
136 : //---------------------------------------------------------
137 : // setProperty
138 : //---------------------------------------------------------
139 :
140 7830 : bool Marker::setProperty(Pid propertyId, const PropertyValue& v)
141 : {
142 7830 : switch (propertyId) {
143 31 : case Pid::LABEL:
144 31 : setLabel(v.value<String>());
145 31 : break;
146 40 : case Pid::MARKER_TYPE:
147 40 : setMarkerType(v.value<MarkerType>());
148 40 : break;
149 0 : case Pid::MARKER_CENTER_ON_SYMBOL:
150 0 : setCenterOnSymbol(v.toBool());
151 0 : break;
152 7759 : default:
153 7759 : if (!TextBase::setProperty(propertyId, v)) {
154 0 : return false;
155 : }
156 7759 : break;
157 : }
158 7830 : triggerLayout();
159 7830 : return true;
160 : }
161 :
162 : //---------------------------------------------------------
163 : // propertyDefault
164 : //---------------------------------------------------------
165 :
166 1787 : PropertyValue Marker::propertyDefault(Pid propertyId) const
167 : {
168 1787 : switch (propertyId) {
169 291 : case Pid::LABEL:
170 1619 : for (const MarkerTypeTableItem& p : markerTypeTable) {
171 1619 : if (m_markerType == p.type) {
172 291 : return String::fromAscii(p.label.ascii());
173 : }
174 : }
175 0 : return String();
176 75 : case Pid::MARKER_TYPE:
177 150 : return MarkerType::FINE;
178 2 : case Pid::PLACEMENT:
179 2 : return PlacementV::ABOVE;
180 75 : case Pid::MARKER_CENTER_ON_SYMBOL:
181 75 : return true;
182 450 : case Pid::MUSIC_SYMBOL_SIZE:
183 450 : return 18.0;
184 894 : default:
185 894 : break;
186 : }
187 894 : return TextBase::propertyDefault(propertyId);
188 : }
189 :
190 : //---------------------------------------------------------
191 : // nextSegmentElement
192 : //---------------------------------------------------------
193 :
194 0 : EngravingItem* Marker::nextSegmentElement()
195 : {
196 : Segment* seg;
197 0 : if (markerType() == MarkerType::FINE) {
198 0 : seg = measure()->last();
199 0 : return seg->firstElementForNavigation(staffIdx());
200 : }
201 0 : Measure* prevMeasure = measure()->prevMeasureMM();
202 0 : if (prevMeasure) {
203 0 : seg = prevMeasure->last();
204 0 : return seg->firstElementForNavigation(staffIdx());
205 : }
206 0 : return EngravingItem::nextSegmentElement();
207 : }
208 :
209 : //---------------------------------------------------------
210 : // prevSegmentElement
211 : //---------------------------------------------------------
212 :
213 0 : EngravingItem* Marker::prevSegmentElement()
214 : {
215 : //it's the same barline
216 0 : return nextSegmentElement();
217 : }
218 :
219 : //---------------------------------------------------------
220 : // accessibleInfo
221 : //---------------------------------------------------------
222 :
223 0 : String Marker::accessibleInfo() const
224 : {
225 0 : return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), markerTypeUserName());
226 : }
227 :
228 0 : std::vector<LineF> Marker::dragAnchorLines() const
229 : {
230 0 : Measure* m = measure();
231 :
232 0 : std::vector<LineF> lines(TextBase::dragAnchorLines());
233 :
234 0 : if (!m || !isRightMarker()) {
235 0 : return lines;
236 : }
237 :
238 0 : for (LineF& l : lines) {
239 0 : l.setP1(l.p1() + PointF(m->width(), 0.0));
240 : }
241 :
242 0 : return lines;
243 0 : }
244 :
245 652 : String Marker::symbolString() const
246 : {
247 : // Returns the coda/segno symbol if present
248 : const static std::array REPEAT_SYMBOL_NAMES {
249 : String(u"<sym>coda</sym>"),
250 : String(u"<sym>codaSquare</sym>"),
251 : String(u"<sym>codaJapanes</sym>"),
252 : String(u"<sym>segno</sym>"),
253 : String(u"<sym>segnoSerpent1</sym>"),
254 : String(u"<sym>segnoSerpent2</sym>"),
255 : String(u"<sym>segnoJapanese</sym>"),
256 652 : };
257 :
258 2600 : for (const String& sym : REPEAT_SYMBOL_NAMES) {
259 2408 : if (xmlText().contains(sym)) {
260 460 : return sym;
261 : }
262 : }
263 :
264 192 : return String();
265 : }
266 :
267 : //---------------------------------------------------------
268 : // subtypeUserName
269 : //---------------------------------------------------------
270 :
271 0 : muse::TranslatableString Marker::subtypeUserName() const
272 : {
273 0 : return TConv::userName(m_markerType);
274 : }
275 : }
|