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