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 "fermata.h"
24 :
25 : #include "types/symnames.h"
26 : #include "types/translatablestring.h"
27 :
28 : #include "chord.h"
29 : #include "chordrest.h"
30 : #include "measure.h"
31 : #include "note.h"
32 : #include "page.h"
33 : #include "score.h"
34 : #include "staff.h"
35 : #include "stafftype.h"
36 : #include "system.h"
37 :
38 : #include "log.h"
39 :
40 : using namespace mu;
41 : using namespace mu::engraving;
42 :
43 : namespace mu::engraving {
44 : //---------------------------------------------------------
45 : // fermataStyle
46 : //---------------------------------------------------------
47 :
48 : static const ElementStyle fermataStyle {
49 : { Sid::fermataMinDistance, Pid::MIN_DISTANCE },
50 : };
51 :
52 : //---------------------------------------------------------
53 : // Fermata
54 : //---------------------------------------------------------
55 :
56 203 : Fermata::Fermata(EngravingObject* parent)
57 203 : : EngravingItem(ElementType::FERMATA, parent, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
58 : {
59 203 : setPlacement(PlacementV::ABOVE);
60 203 : m_symId = SymId::noSym;
61 203 : setPlay(true);
62 203 : initElementStyle(&fermataStyle);
63 203 : }
64 :
65 : //---------------------------------------------------------
66 : // subtype
67 : //---------------------------------------------------------
68 :
69 0 : int Fermata::subtype() const
70 : {
71 0 : String s = String::fromAscii(SymNames::nameForSymId(m_symId).ascii());
72 0 : if (s.endsWith(u"Below")) {
73 0 : return int(SymNames::symIdByName(s.left(s.size() - 5) + u"Above"));
74 : } else {
75 0 : return int(m_symId);
76 : }
77 0 : }
78 :
79 : //---------------------------------------------------------
80 : // subtypeUserName
81 : //---------------------------------------------------------
82 :
83 0 : muse::TranslatableString Fermata::subtypeUserName() const
84 : {
85 0 : return SymNames::userNameForSymId(symId());
86 : }
87 :
88 : //---------------------------------------------------------
89 : // measure
90 : //---------------------------------------------------------
91 :
92 0 : Measure* Fermata::measure() const
93 : {
94 0 : Segment* s = segment();
95 0 : return toMeasure(s ? s->ownershipParent() : 0);
96 : }
97 :
98 : //---------------------------------------------------------
99 : // system
100 : //---------------------------------------------------------
101 :
102 0 : System* Fermata::system() const
103 : {
104 0 : Measure* m = measure();
105 0 : return m ? m->system() : nullptr;
106 : }
107 :
108 : //---------------------------------------------------------
109 : // page
110 : //---------------------------------------------------------
111 :
112 0 : Page* Fermata::page() const
113 : {
114 0 : System* s = system();
115 0 : return s ? s->page() : nullptr;
116 : }
117 :
118 : //---------------------------------------------------------
119 : // dragAnchorLines
120 : //---------------------------------------------------------
121 :
122 0 : std::vector<LineF> Fermata::dragAnchorLines() const
123 : {
124 0 : std::vector<LineF> result;
125 0 : result.push_back(LineF(canvasPos(), layoutParent()->canvasPos()));
126 0 : return result;
127 0 : }
128 :
129 : //---------------------------------------------------------
130 : // getProperty
131 : //---------------------------------------------------------
132 :
133 1552 : PropertyValue Fermata::getProperty(Pid propertyId) const
134 : {
135 1552 : switch (propertyId) {
136 0 : case Pid::SYMBOL:
137 0 : return PropertyValue::fromValue(m_symId);
138 141 : case Pid::TIME_STRETCH:
139 141 : return timeStretch();
140 141 : case Pid::PLAY:
141 141 : return play();
142 1270 : default:
143 1270 : return EngravingItem::getProperty(propertyId);
144 : }
145 : }
146 :
147 : //---------------------------------------------------------
148 : // setProperty
149 : //---------------------------------------------------------
150 :
151 272 : bool Fermata::setProperty(Pid propertyId, const PropertyValue& v)
152 : {
153 272 : switch (propertyId) {
154 0 : case Pid::SYMBOL:
155 0 : setSymIdAndTimeStretch(v.value<SymId>());
156 0 : break;
157 22 : case Pid::PLACEMENT: {
158 22 : PlacementV p = v.value<PlacementV>();
159 22 : if (p != placement()) {
160 4 : String s = String::fromAscii(SymNames::nameForSymId(m_symId).ascii());
161 4 : bool up = placeAbove();
162 4 : if (s.endsWith(up ? u"Above" : u"Below")) {
163 4 : String s2 = s.left(s.size() - 5) + (up ? u"Below" : u"Above");
164 4 : m_symId = SymNames::symIdByName(s2);
165 4 : }
166 4 : setPlacement(p);
167 4 : }
168 : }
169 22 : break;
170 0 : case Pid::PLAY:
171 0 : setPlay(v.toBool());
172 0 : break;
173 2 : case Pid::TIME_STRETCH:
174 2 : setTimeStretch(v.toDouble());
175 2 : break;
176 248 : default:
177 248 : return EngravingItem::setProperty(propertyId, v);
178 : }
179 24 : triggerLayout();
180 24 : return true;
181 : }
182 :
183 : //---------------------------------------------------------
184 : // propertyDefault
185 : //---------------------------------------------------------
186 :
187 1753 : PropertyValue Fermata::propertyDefault(Pid propertyId) const
188 : {
189 1753 : switch (propertyId) {
190 151 : case Pid::PLACEMENT:
191 151 : return track() & 1 ? PlacementV::BELOW : PlacementV::ABOVE;
192 297 : case Pid::TIME_STRETCH:
193 297 : switch (fermataType()) {
194 1 : case FermataType::VeryShort:
195 1 : return 1.25;
196 38 : case FermataType::Short:
197 : case FermataType::ShortHenze:
198 38 : return 1.5;
199 216 : case FermataType::Normal:
200 : case FermataType::Undefined:
201 216 : return 2.0;
202 24 : case FermataType::Long:
203 : case FermataType::LongHenze:
204 24 : return 3.0;
205 18 : case FermataType::VeryLong:
206 18 : return 4.0;
207 : }
208 0 : break;
209 141 : case Pid::PLAY:
210 141 : return true;
211 1164 : default:
212 1164 : break;
213 : }
214 1164 : return EngravingItem::propertyDefault(propertyId);
215 : }
216 :
217 : //---------------------------------------------------------
218 : // resetProperty
219 : //---------------------------------------------------------
220 :
221 35 : void Fermata::resetProperty(Pid id)
222 : {
223 35 : switch (id) {
224 0 : case Pid::TIME_STRETCH:
225 0 : setProperty(id, propertyDefault(id));
226 0 : return;
227 :
228 35 : default:
229 35 : break;
230 : }
231 35 : EngravingItem::resetProperty(id);
232 : }
233 :
234 : //---------------------------------------------------------
235 : // mag
236 : //---------------------------------------------------------
237 :
238 9745 : double Fermata::mag() const
239 : {
240 9745 : double m = staff() ? staff()->staffMag(tick()) * style().styleD(Sid::articulationMag) : 1.0;
241 9745 : if (segment() && segment()->isChordRestType() && segment()->element(track())) {
242 9215 : m *= toChordRest(segment()->element(track()))->intrinsicMag();
243 : }
244 9745 : return m;
245 : }
246 :
247 156 : void Fermata::setSymIdAndTimeStretch(SymId id)
248 : {
249 156 : m_symId = id;
250 156 : m_timeStretch = m_timeStretch == -1 ? propertyDefault(Pid::TIME_STRETCH).value<double>() : -1;
251 156 : }
252 :
253 308 : FermataType Fermata::fermataType() const
254 : {
255 : static const std::unordered_map<SymId, FermataType> FERMATA_TYPES = {
256 : { SymId::fermataAbove, FermataType::Normal },
257 : { SymId::fermataBelow, FermataType::Normal },
258 : { SymId::fermataLongAbove, FermataType::Long },
259 : { SymId::fermataLongBelow, FermataType::Long },
260 : { SymId::fermataLongHenzeAbove, FermataType::LongHenze },
261 : { SymId::fermataLongHenzeBelow, FermataType::LongHenze },
262 : { SymId::fermataVeryLongAbove, FermataType::VeryLong },
263 : { SymId::fermataVeryLongBelow, FermataType::VeryLong },
264 : { SymId::fermataShortHenzeAbove, FermataType::ShortHenze },
265 : { SymId::fermataShortHenzeBelow, FermataType::ShortHenze },
266 : { SymId::fermataVeryShortAbove, FermataType::VeryShort },
267 : { SymId::fermataVeryShortBelow, FermataType::VeryShort },
268 : { SymId::fermataShortAbove, FermataType::Short },
269 : { SymId::fermataShortBelow, FermataType::Short },
270 320 : };
271 :
272 308 : auto search = FERMATA_TYPES.find(symId());
273 :
274 308 : if (search != FERMATA_TYPES.cend()) {
275 308 : return search->second;
276 : }
277 :
278 0 : return FermataType::Undefined;
279 : }
280 :
281 : //---------------------------------------------------------
282 : // accessibleInfo
283 : //---------------------------------------------------------
284 :
285 0 : String Fermata::accessibleInfo() const
286 : {
287 0 : return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), SymNames::translatedUserNameForSymId(symId()));
288 : }
289 :
290 618 : Sid Fermata::defaultPosSid() const
291 : {
292 618 : return placeAbove() ? Sid::fermataPosAbove : Sid::fermataPosBelow;
293 : }
294 : }
|