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 "tremolosinglechord.h"
24 :
25 : #include "draw/types/transform.h"
26 :
27 : #include "types/typesconv.h"
28 :
29 : #include "style/style.h"
30 :
31 : #include "rendering/score/beamtremololayout.h"
32 :
33 : #include "beam.h"
34 : #include "chord.h"
35 : #include "stem.h"
36 : #include "system.h"
37 : #include "stafftype.h"
38 :
39 : #include "log.h"
40 :
41 : using namespace mu;
42 : using namespace muse::draw;
43 : using namespace mu::engraving;
44 :
45 : namespace mu::engraving {
46 164 : TremoloSingleChord::TremoloSingleChord(DummyParentOr<Chord> parent)
47 164 : : EngravingItem(ElementType::TREMOLO_SINGLECHORD, parent, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
48 : {
49 164 : }
50 :
51 3 : TremoloSingleChord::TremoloSingleChord(const TremoloSingleChord& t)
52 3 : : EngravingItem(t)
53 : {
54 3 : setTremoloType(t.tremoloType());
55 3 : m_durationType = t.m_durationType;
56 3 : }
57 :
58 276 : TremoloSingleChord::~TremoloSingleChord()
59 : {
60 : //
61 : // delete all references from chords
62 : //
63 138 : if (chord() && chord()->tremoloSingleChord() == this) {
64 0 : chord()->setTremoloSingleChord(nullptr);
65 : }
66 276 : }
67 :
68 3248 : double TremoloSingleChord::chordMag() const
69 : {
70 3248 : return chord() ? chord()->intrinsicMag() : 1.0;
71 : }
72 :
73 1152 : double TremoloSingleChord::minHeight() const
74 : {
75 1152 : const double sw = style().styleS(Sid::tremoloLineWidth).val() * chordMag();
76 1152 : const double td = style().styleS(Sid::tremoloDistance).val() * chordMag();
77 1152 : return (lines() - 1) * td + sw;
78 : }
79 :
80 : //---------------------------------------------------------
81 : // drag
82 : //---------------------------------------------------------
83 :
84 0 : RectF TremoloSingleChord::drag(EditData& ed)
85 : {
86 0 : return EngravingItem::drag(ed);
87 : }
88 :
89 : //---------------------------------------------------------
90 : // setTremoloType
91 : //---------------------------------------------------------
92 :
93 166 : void TremoloSingleChord::setTremoloType(TremoloType t)
94 : {
95 166 : m_tremoloType = t;
96 166 : switch (tremoloType()) {
97 31 : case TremoloType::R16:
98 : case TremoloType::C16:
99 31 : m_lines = 2;
100 31 : break;
101 36 : case TremoloType::R32:
102 : case TremoloType::C32:
103 36 : m_lines = 3;
104 36 : break;
105 14 : case TremoloType::R64:
106 : case TremoloType::C64:
107 14 : m_lines = 4;
108 14 : break;
109 0 : case TremoloType::R128:
110 : case TremoloType::C128:
111 0 : m_lines = 5;
112 0 : break;
113 0 : case TremoloType::R256:
114 : case TremoloType::C256:
115 0 : m_lines = 6;
116 0 : break;
117 85 : default:
118 85 : m_lines = 1;
119 85 : break;
120 : }
121 :
122 166 : styleChanged();
123 166 : }
124 :
125 : //---------------------------------------------------------
126 : // spatiumChanged
127 : //---------------------------------------------------------
128 :
129 0 : void TremoloSingleChord::spatiumChanged(double oldValue, double newValue)
130 : {
131 0 : EngravingItem::spatiumChanged(oldValue, newValue);
132 0 : computeShape();
133 0 : }
134 :
135 : //---------------------------------------------------------
136 : // localSpatiumChanged
137 : // the scale of a staff changed
138 : //---------------------------------------------------------
139 :
140 0 : void TremoloSingleChord::localSpatiumChanged(double oldValue, double newValue)
141 : {
142 0 : EngravingItem::localSpatiumChanged(oldValue, newValue);
143 0 : computeShape();
144 0 : }
145 :
146 : //---------------------------------------------------------
147 : // styleChanged
148 : // the scale of a staff changed
149 : //---------------------------------------------------------
150 :
151 274 : void TremoloSingleChord::styleChanged()
152 : {
153 274 : EngravingItem::styleChanged();
154 274 : computeShape();
155 274 : }
156 :
157 65 : staff_idx_t TremoloSingleChord::vStaffIdx() const
158 : {
159 65 : return chord() ? chord()->vStaffIdx() : EngravingItem::vStaffIdx();
160 : }
161 :
162 : //---------------------------------------------------------
163 : // basePath
164 : //---------------------------------------------------------
165 :
166 1008 : PainterPath TremoloSingleChord::basePath(double /*stretch*/) const
167 : {
168 1008 : if (isBuzzRoll()) {
169 64 : return PainterPath();
170 : }
171 :
172 944 : const double sp = spatium() * chordMag();
173 :
174 944 : double w2 = sp * style().styleS(Sid::tremoloWidth).val() * .5;
175 944 : double lw = sp * style().styleS(Sid::tremoloLineWidth).val();
176 944 : double td = sp * style().styleS(Sid::tremoloDistance).val();
177 :
178 944 : PainterPath ppath;
179 :
180 : // first line
181 944 : ppath.addRect(-w2, 0.0, 2.0 * w2, lw);
182 944 : double ty = td;
183 :
184 : // other lines
185 1921 : for (int i = 1; i < m_lines; i++) {
186 977 : ppath.addRect(-w2, ty, 2.0 * w2, lw);
187 977 : ty += td;
188 : }
189 :
190 944 : Transform shearTransform;
191 944 : shearTransform.shear(0.0, -(lw / 2.0) / w2);
192 944 : ppath = shearTransform.map(ppath);
193 :
194 944 : return ppath;
195 944 : }
196 :
197 686 : void TremoloSingleChord::computeShape()
198 : {
199 686 : if (isBuzzRoll()) {
200 90 : setbbox(symBbox(SymId::buzzRoll));
201 : } else {
202 596 : m_path = basePath();
203 596 : setbbox(m_path.boundingRect());
204 : }
205 686 : }
206 :
207 0 : TDuration TremoloSingleChord::durationType() const
208 : {
209 0 : return m_durationType;
210 : }
211 :
212 89 : void TremoloSingleChord::setDurationType(TDuration d)
213 : {
214 89 : if (m_durationType == d) {
215 0 : return;
216 : }
217 :
218 89 : m_durationType = d;
219 89 : styleChanged();
220 : }
221 :
222 : //---------------------------------------------------------
223 : // tremoloLen
224 : //---------------------------------------------------------
225 :
226 0 : Fraction TremoloSingleChord::tremoloLen() const
227 : {
228 0 : Fraction f;
229 0 : switch (lines()) {
230 0 : case 1: f.set(1, 8);
231 0 : break;
232 0 : case 2: f.set(1, 16);
233 0 : break;
234 0 : case 3: f.set(1, 32);
235 0 : break;
236 0 : case 4: f.set(1, 64);
237 0 : break;
238 0 : case 5: f.set(1, 128);
239 0 : break;
240 0 : case 6: f.set(1, 256);
241 0 : break;
242 : }
243 0 : return f;
244 : }
245 :
246 : //---------------------------------------------------------
247 : // subtypeName
248 : //---------------------------------------------------------
249 :
250 1 : TranslatableString TremoloSingleChord::subtypeUserName() const
251 : {
252 1 : return TConv::userName(tremoloType());
253 : }
254 :
255 : //---------------------------------------------------------
256 : // accessibleInfo
257 : //---------------------------------------------------------
258 :
259 0 : String TremoloSingleChord::accessibleInfo() const
260 : {
261 0 : return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), translatedSubtypeUserName());
262 : }
263 :
264 : //---------------------------------------------------------
265 : // getProperty
266 : //---------------------------------------------------------
267 :
268 1211 : PropertyValue TremoloSingleChord::getProperty(Pid propertyId) const
269 : {
270 1211 : switch (propertyId) {
271 110 : case Pid::TREMOLO_TYPE:
272 110 : return int(m_tremoloType);
273 110 : case Pid::PLAY:
274 110 : return m_playTremolo;
275 991 : default:
276 991 : break;
277 : }
278 991 : return EngravingItem::getProperty(propertyId);
279 : }
280 :
281 : //---------------------------------------------------------
282 : // setProperty
283 : //---------------------------------------------------------
284 :
285 1 : bool TremoloSingleChord::setProperty(Pid propertyId, const PropertyValue& val)
286 : {
287 1 : switch (propertyId) {
288 0 : case Pid::TREMOLO_TYPE:
289 0 : setTremoloType(TremoloType(val.toInt()));
290 0 : break;
291 0 : case Pid::PLAY:
292 0 : setPlayTremolo(val.toBool());
293 0 : break;
294 1 : default:
295 1 : return EngravingItem::setProperty(propertyId, val);
296 : }
297 0 : triggerLayout();
298 0 : return true;
299 : }
300 :
301 : //---------------------------------------------------------
302 : // propertyDefault
303 : //---------------------------------------------------------
304 :
305 1210 : PropertyValue TremoloSingleChord::propertyDefault(Pid propertyId) const
306 : {
307 1210 : switch (propertyId) {
308 110 : case Pid::PLAY:
309 110 : return true;
310 1100 : default:
311 1100 : return EngravingItem::propertyDefault(propertyId);
312 : }
313 : }
314 :
315 : //---------------------------------------------------------
316 : // scanElements
317 : //---------------------------------------------------------
318 :
319 0 : void TremoloSingleChord::scanElements(std::function<void(EngravingItem*)> func)
320 : {
321 0 : if (chord() && chord()->tremoloChordType() == TremoloChordType::TremoloSecondChord) {
322 0 : return;
323 : }
324 0 : EngravingItem::scanElements(func);
325 : }
326 : }
|