1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2011 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "trill.h"
14 #include "style.h"
15 #include "system.h"
16 #include "measure.h"
17 #include "xml.h"
18 #include "utils.h"
19 #include "sym.h"
20 #include "score.h"
21 #include "accidental.h"
22 #include "segment.h"
23 #include "staff.h"
24
25 namespace Ms {
26
27
28 //---------------------------------------------------------
29 // trillTable
30 // must be in sync with Trill::Type
31 //---------------------------------------------------------
32
33 const TrillTableItem trillTable[] = {
34 { Trill::Type::TRILL_LINE, "trill", QT_TRANSLATE_NOOP("trillType", "Trill line") },
35 { Trill::Type::UPPRALL_LINE, "upprall", QT_TRANSLATE_NOOP("trillType", "Upprall line") },
36 { Trill::Type::DOWNPRALL_LINE, "downprall", QT_TRANSLATE_NOOP("trillType", "Downprall line") },
37 { Trill::Type::PRALLPRALL_LINE, "prallprall", QT_TRANSLATE_NOOP("trillType", "Prallprall line") }
38 };
39
trillTableSize()40 int trillTableSize() {
41 return sizeof(trillTable)/sizeof(TrillTableItem);
42 }
43
44 //---------------------------------------------------------
45 // trillStyle
46 //---------------------------------------------------------
47
48 static const ElementStyle trillStyle {
49 { Sid::trillPlacement, Pid::PLACEMENT },
50 { Sid::trillPosAbove, Pid::OFFSET },
51 };
52
53 //---------------------------------------------------------
54 // draw
55 //---------------------------------------------------------
56
draw(QPainter * painter) const57 void TrillSegment::draw(QPainter* painter) const
58 {
59 painter->setPen(spanner()->curColor());
60 drawSymbols(_symbols, painter);
61 }
62
63 //---------------------------------------------------------
64 // add
65 //---------------------------------------------------------
66
add(Element * e)67 void TrillSegment::add(Element* e)
68 {
69 e->setParent(this);
70 if (e->type() == ElementType::ACCIDENTAL) {
71 // accidental is part of trill
72 trill()->setAccidental(toAccidental(e));
73 }
74 }
75
76 //---------------------------------------------------------
77 // remove
78 //---------------------------------------------------------
79
remove(Element * e)80 void TrillSegment::remove(Element* e)
81 {
82 if (trill()->accidental() == e) {
83 // accidental is part of trill
84 trill()->setAccidental(0);
85 }
86 }
87
88 //---------------------------------------------------------
89 // symbolLine
90 //---------------------------------------------------------
91
symbolLine(SymId start,SymId fill)92 void TrillSegment::symbolLine(SymId start, SymId fill)
93 {
94 qreal x1 = 0;
95 qreal x2 = pos2().x();
96 qreal w = x2 - x1;
97 qreal mag = magS();
98 ScoreFont* f = score()->scoreFont();
99
100 _symbols.clear();
101 _symbols.push_back(start);
102 qreal w1 = f->advance(start, mag);
103 qreal w2 = f->advance(fill, mag);
104 int n = lrint((w - w1) / w2);
105 for (int i = 0; i < n; ++i)
106 _symbols.push_back(fill);
107 QRectF r(f->bbox(_symbols, mag));
108 setbbox(r);
109 }
110
symbolLine(SymId start,SymId fill,SymId end)111 void TrillSegment::symbolLine(SymId start, SymId fill, SymId end)
112 {
113 qreal x1 = 0;
114 qreal x2 = pos2().x();
115 qreal w = x2 - x1;
116 qreal mag = magS();
117 ScoreFont* f = score()->scoreFont();
118
119 _symbols.clear();
120 _symbols.push_back(start);
121 qreal w1 = f->advance(start, mag);
122 qreal w2 = f->advance(fill, mag);
123 qreal w3 = f->advance(end, mag);
124 int n = lrint((w - w1 - w3) / w2);
125 for (int i = 0; i < n; ++i)
126 _symbols.push_back(fill);
127 _symbols.push_back(end);
128 QRectF r(f->bbox(_symbols, mag));
129 setbbox(r);
130 }
131
132 //---------------------------------------------------------
133 // layout
134 //---------------------------------------------------------
135
layout()136 void TrillSegment::layout()
137 {
138 if (staff())
139 setMag(staff()->mag(tick()));
140 if (spanner()->placeBelow())
141 rypos() = staff() ? staff()->height() : 0.0;
142
143 if (isSingleType() || isBeginType()) {
144 Accidental* a = trill()->accidental();
145 if (a) {
146 a->layout();
147 a->setMag(a->mag() * .6);
148 qreal _spatium = spatium();
149 a->setPos(_spatium * 1.3, -2.2 * _spatium);
150 a->setParent(this);
151 }
152 switch (trill()->trillType()) {
153 case Trill::Type::TRILL_LINE:
154 symbolLine(SymId::ornamentTrill, SymId::wiggleTrill);
155 break;
156 case Trill::Type::PRALLPRALL_LINE:
157 symbolLine(SymId::wiggleTrill, SymId::wiggleTrill);
158 break;
159 case Trill::Type::UPPRALL_LINE:
160 symbolLine(SymId::ornamentBottomLeftConcaveStroke,
161 SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd);
162 break;
163 case Trill::Type::DOWNPRALL_LINE:
164 symbolLine(SymId::ornamentLeftVerticalStroke,
165 SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd);
166 break;
167 }
168 }
169 else
170 symbolLine(SymId::wiggleTrill, SymId::wiggleTrill);
171 if (isStyled(Pid::OFFSET))
172 roffset() = trill()->propertyDefault(Pid::OFFSET).toPointF();
173
174 autoplaceSpannerSegment();
175 }
176
177 //---------------------------------------------------------
178 // shape
179 //---------------------------------------------------------
180
shape() const181 Shape TrillSegment::shape() const
182 {
183 return Shape(bbox());
184 }
185
186 //---------------------------------------------------------
187 // acceptDrop
188 //---------------------------------------------------------
189
acceptDrop(EditData & data) const190 bool TrillSegment::acceptDrop(EditData& data) const
191 {
192 if (data.dropElement->isAccidental())
193 return true;
194 return false;
195 }
196
197 //---------------------------------------------------------
198 // drop
199 //---------------------------------------------------------
200
drop(EditData & data)201 Element* TrillSegment::drop(EditData& data)
202 {
203 Element* e = data.dropElement;
204 switch (e->type()) {
205 case ElementType::ACCIDENTAL:
206 e->setParent(trill());
207 score()->undoAddElement(e);
208 break;
209
210 default:
211 delete e;
212 e = 0;
213 break;
214 }
215 return e;
216 }
217
218 //---------------------------------------------------------
219 // propertyDelegate
220 //---------------------------------------------------------
221
propertyDelegate(Pid pid)222 Element* TrillSegment::propertyDelegate(Pid pid)
223 {
224 if (pid == Pid::TRILL_TYPE || pid == Pid::ORNAMENT_STYLE || pid == Pid::PLACEMENT || pid == Pid::PLAY)
225 return spanner();
226 return LineSegment::propertyDelegate(pid);
227 }
228
229 //---------------------------------------------------------
230 // scanElements
231 //---------------------------------------------------------
232
scanElements(void * data,void (* func)(void *,Element *),bool)233 void TrillSegment::scanElements(void* data, void (*func)(void*, Element*), bool /*all*/)
234 {
235 func(data, this);
236 if (isSingleType() || isBeginType()) {
237 Accidental* a = trill()->accidental();
238 if (a)
239 func(data, a);
240 }
241 }
242
243 //---------------------------------------------------------
244 // getPropertyStyle
245 //---------------------------------------------------------
246
getPropertyStyle(Pid pid) const247 Sid TrillSegment::getPropertyStyle(Pid pid) const
248 {
249 if (pid == Pid::OFFSET)
250 return spanner()->placeAbove() ? Sid::trillPosAbove : Sid::trillPosBelow;
251 return LineSegment::getPropertyStyle(pid);
252 }
253
getPropertyStyle(Pid pid) const254 Sid Trill::getPropertyStyle(Pid pid) const
255 {
256 if (pid == Pid::OFFSET)
257 return placeAbove() ? Sid::trillPosAbove : Sid::trillPosBelow;
258 return SLine::getPropertyStyle(pid);
259 }
260
261 //---------------------------------------------------------
262 // Trill
263 //---------------------------------------------------------
264
Trill(Score * s)265 Trill::Trill(Score* s)
266 : SLine(s)
267 {
268 _trillType = Type::TRILL_LINE;
269 _accidental = 0;
270 _ornamentStyle = MScore::OrnamentStyle::DEFAULT;
271 setPlayArticulation(true);
272 initElementStyle(&trillStyle);
273 }
274
~Trill()275 Trill::~Trill()
276 {
277 delete _accidental;
278 }
279
280 //---------------------------------------------------------
281 // add
282 //---------------------------------------------------------
283
add(Element * e)284 void Trill::add(Element* e)
285 {
286 if (e->type() == ElementType::ACCIDENTAL) {
287 e->setParent(this);
288 _accidental = toAccidental(e);
289 }
290 else
291 SLine::add(e);
292 }
293
294 //---------------------------------------------------------
295 // remove
296 //---------------------------------------------------------
297
remove(Element * e)298 void Trill::remove(Element* e)
299 {
300 if (e == _accidental)
301 _accidental = 0;
302 }
303
304 //---------------------------------------------------------
305 // layout
306 //---------------------------------------------------------
307
layout()308 void Trill::layout()
309 {
310 SLine::layout();
311 if (score() == gscore)
312 return;
313 if (spannerSegments().empty())
314 return;
315 TrillSegment* ls = toTrillSegment(frontSegment());
316 if (spannerSegments().empty())
317 qDebug("Trill: no segments");
318 if (_accidental)
319 _accidental->setParent(ls);
320 }
321
322 //---------------------------------------------------------
323 // createLineSegment
324 //---------------------------------------------------------
325
326 static const ElementStyle trillSegmentStyle {
327 { Sid::trillPosAbove, Pid::OFFSET },
328 { Sid::trillMinDistance, Pid::MIN_DISTANCE },
329 };
330
createLineSegment()331 LineSegment* Trill::createLineSegment()
332 {
333 TrillSegment* seg = new TrillSegment(this, score());
334 seg->setTrack(track());
335 seg->setColor(color());
336 seg->initElementStyle(&trillSegmentStyle);
337 return seg;
338 }
339
340 //---------------------------------------------------------
341 // Trill::write
342 //---------------------------------------------------------
343
write(XmlWriter & xml) const344 void Trill::write(XmlWriter& xml) const
345 {
346 if (!xml.canWrite(this))
347 return;
348 xml.stag(this);
349 xml.tag("subtype", trillTypeName());
350 writeProperty(xml, Pid::PLAY);
351 writeProperty(xml, Pid::ORNAMENT_STYLE);
352 writeProperty(xml, Pid::PLACEMENT);
353 SLine::writeProperties(xml);
354 if (_accidental)
355 _accidental->write(xml);
356 xml.etag();
357 }
358
359 //---------------------------------------------------------
360 // Trill::read
361 //---------------------------------------------------------
362
read(XmlReader & e)363 void Trill::read(XmlReader& e)
364 {
365 eraseSpannerSegments();
366
367 while (e.readNextStartElement()) {
368 const QStringRef& tag(e.name());
369 if (tag == "subtype")
370 setTrillType(e.readElementText());
371 else if (tag == "Accidental") {
372 _accidental = new Accidental(score());
373 _accidental->read(e);
374 _accidental->setParent(this);
375 }
376 else if ( tag == "ornamentStyle")
377 readProperty(e, Pid::ORNAMENT_STYLE);
378 else if ( tag == "play")
379 setPlayArticulation(e.readBool());
380 else if (!SLine::readProperties(e))
381 e.unknown();
382 }
383 }
384
385 //---------------------------------------------------------
386 // setTrillType
387 //---------------------------------------------------------
388
setTrillType(const QString & s)389 void Trill::setTrillType(const QString& s)
390 {
391 if (s == "0") {
392 _trillType = Type::TRILL_LINE;
393 return;
394 }
395 if (s == "pure") {
396 _trillType = Type::PRALLPRALL_LINE; // obsolete, compatibility only
397 return;
398 }
399 for (TrillTableItem i : trillTable) {
400 if (s.compare(i.name) == 0) {
401 _trillType = i.type;
402 return;
403 }
404 }
405 qDebug("Trill::setSubtype: unknown <%s>", qPrintable(s));
406 }
407
408 //---------------------------------------------------------
409 // type2name
410 //---------------------------------------------------------
411
type2name(Trill::Type t)412 QString Trill::type2name(Trill::Type t)
413 {
414 for (TrillTableItem i : trillTable) {
415 if (i.type == t)
416 return i.name;
417 }
418 qDebug("unknown Trill subtype %d", int(t));
419 return "?";
420 }
421
422 //---------------------------------------------------------
423 // trillTypeName
424 //---------------------------------------------------------
425
trillTypeName() const426 QString Trill::trillTypeName() const
427 {
428 return type2name(trillType());
429 }
430
431 //---------------------------------------------------------
432 // trillTypeName
433 //---------------------------------------------------------
434
trillTypeUserName() const435 QString Trill::trillTypeUserName() const
436 {
437 return qApp->translate("trillType", trillTable[static_cast<int>(trillType())].userName.toUtf8().constData());
438 }
439
440 //---------------------------------------------------------
441 // scanElements
442 //---------------------------------------------------------
443
scanElements(void * data,void (* func)(void *,Element *),bool all)444 void Trill::scanElements(void* data, void (*func)(void*, Element*), bool all)
445 {
446 if (_accidental)
447 _accidental->scanElements(data, func, all);
448 func(data, this); // ?
449 SLine::scanElements(data, func, all);
450 }
451
452 //---------------------------------------------------------
453 // getProperty
454 //---------------------------------------------------------
455
getProperty(Pid propertyId) const456 QVariant Trill::getProperty(Pid propertyId) const
457 {
458 switch(propertyId) {
459 case Pid::TRILL_TYPE:
460 return int(trillType());
461 case Pid::ORNAMENT_STYLE:
462 return int(ornamentStyle());
463 case Pid::PLAY:
464 return bool(playArticulation());
465 default:
466 break;
467 }
468 return SLine::getProperty(propertyId);
469 }
470
471 //---------------------------------------------------------
472 // setProperty
473 //---------------------------------------------------------
474
setProperty(Pid propertyId,const QVariant & val)475 bool Trill::setProperty(Pid propertyId, const QVariant& val)
476 {
477 switch(propertyId) {
478 case Pid::TRILL_TYPE:
479 setTrillType(Type(val.toInt()));
480 break;
481 case Pid::PLAY:
482 setPlayArticulation(val.toBool());
483 break;
484 case Pid::ORNAMENT_STYLE:
485 setOrnamentStyle(MScore::OrnamentStyle(val.toInt()));
486 break;
487 default:
488 if (!SLine::setProperty(propertyId, val))
489 return false;
490 break;
491 }
492 triggerLayoutAll();
493 return true;
494 }
495
496 //---------------------------------------------------------
497 // propertyDefault
498 //---------------------------------------------------------
499
propertyDefault(Pid propertyId) const500 QVariant Trill::propertyDefault(Pid propertyId) const
501 {
502 switch (propertyId) {
503 case Pid::TRILL_TYPE:
504 return 0;
505 case Pid::ORNAMENT_STYLE:
506 //return int(score()->style()->ornamentStyle(_ornamentStyle));
507 return int(MScore::OrnamentStyle::DEFAULT);
508 case Pid::PLAY:
509 return true;
510 case Pid::PLACEMENT:
511 return score()->styleV(Sid::trillPlacement);
512
513 default:
514 return SLine::propertyDefault(propertyId);
515 }
516 }
517
518 //---------------------------------------------------------
519 // propertyId
520 //---------------------------------------------------------
521
propertyId(const QStringRef & name) const522 Pid Trill::propertyId(const QStringRef& name) const
523 {
524 if (name == "subtype")
525 return Pid::TRILL_TYPE;
526 return SLine::propertyId(name);
527 }
528
529 //---------------------------------------------------------
530 // accessibleInfo
531 //---------------------------------------------------------
532
accessibleInfo() const533 QString Trill::accessibleInfo() const
534 {
535 return QString("%1: %2").arg(Element::accessibleInfo(), trillTypeUserName());
536 }
537 }
538
539