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 "vibrato.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 //   vibratoTable
29 //    must be in sync with Vibrato::Type
30 //---------------------------------------------------------
31 
32 const VibratoTableItem vibratoTable[] = {
33       { Vibrato::Type::GUITAR_VIBRATO,        "guitarVibrato",       QT_TRANSLATE_NOOP("vibratoType", "Guitar vibrato")        },
34       { Vibrato::Type::GUITAR_VIBRATO_WIDE,   "guitarVibratoWide",   QT_TRANSLATE_NOOP("vibratoType", "Guitar vibrato wide")   },
35       { Vibrato::Type::VIBRATO_SAWTOOTH,      "vibratoSawtooth",     QT_TRANSLATE_NOOP("vibratoType", "Vibrato sawtooth")      },
36       { Vibrato::Type::VIBRATO_SAWTOOTH_WIDE, "vibratoSawtoothWide", QT_TRANSLATE_NOOP("vibratoType", "Tremolo sawtooth wide") }
37       };
38 
vibratoTableSize()39 int vibratoTableSize() {
40       return sizeof(vibratoTable)/sizeof(VibratoTableItem);
41       }
42 
43 //---------------------------------------------------------
44 //   draw
45 //---------------------------------------------------------
46 
draw(QPainter * painter) const47 void VibratoSegment::draw(QPainter* painter) const
48       {
49       painter->setPen(spanner()->curColor());
50       drawSymbols(_symbols, painter);
51       }
52 
53 //---------------------------------------------------------
54 //   symbolLine
55 //---------------------------------------------------------
56 
symbolLine(SymId start,SymId fill)57 void VibratoSegment::symbolLine(SymId start, SymId fill)
58       {
59       qreal x1 = 0;
60       qreal x2 = pos2().x();
61       qreal w   = x2 - x1;
62       qreal mag = magS();
63       ScoreFont* f = score()->scoreFont();
64 
65       _symbols.clear();
66       _symbols.push_back(start);
67       qreal w1 = f->advance(start, mag);
68       qreal w2 = f->advance(fill, mag);
69       int n    = lrint((w - w1) / w2);
70       for (int i = 0; i < n; ++i)
71            _symbols.push_back(fill);
72       QRectF r(f->bbox(_symbols, mag));
73       setbbox(r);
74       }
75 
symbolLine(SymId start,SymId fill,SymId end)76 void VibratoSegment::symbolLine(SymId start, SymId fill, SymId end)
77       {
78       qreal x1 = 0;
79       qreal x2 = pos2().x();
80       qreal w   = x2 - x1;
81       qreal mag = magS();
82       ScoreFont* f = score()->scoreFont();
83 
84       _symbols.clear();
85       _symbols.push_back(start);
86       qreal w1 = f->bbox(start, mag).width();
87       qreal w2 = f->width(fill, mag);
88       qreal w3 = f->width(end, mag);
89       int n    = lrint((w - w1 - w3) / w2);
90       for (int i = 0; i < n; ++i)
91            _symbols.push_back(fill);
92       _symbols.push_back(end);
93       QRectF r(f->bbox(_symbols, mag));
94       setbbox(r);
95       }
96 
97 //---------------------------------------------------------
98 //   layout
99 //---------------------------------------------------------
100 
layout()101 void VibratoSegment::layout()
102       {
103       if (staff())
104             setMag(staff()->mag(tick()));
105       if (spanner()->placeBelow())
106             rypos() = staff() ? staff()->height() : 0.0;
107 
108       if (isSingleType() || isBeginType()) {
109             switch (vibrato()->vibratoType()) {
110                   case Vibrato::Type::GUITAR_VIBRATO:
111                         symbolLine(SymId::guitarVibratoStroke, SymId::guitarVibratoStroke);
112                         break;
113                   case Vibrato::Type::GUITAR_VIBRATO_WIDE:
114                         symbolLine(SymId::guitarWideVibratoStroke, SymId::guitarWideVibratoStroke);
115                         break;
116                   case Vibrato::Type::VIBRATO_SAWTOOTH:
117                         symbolLine(SymId::wiggleSawtooth, SymId::wiggleSawtooth);
118                         break;
119                   case Vibrato::Type::VIBRATO_SAWTOOTH_WIDE:
120                         symbolLine(SymId::wiggleSawtoothWide, SymId::wiggleSawtoothWide);
121                         break;
122                   }
123             }
124       else
125             symbolLine(SymId::wiggleVibrato, SymId::wiggleVibrato);
126       if (isStyled(Pid::OFFSET))
127             roffset() = vibrato()->propertyDefault(Pid::OFFSET).toPointF();
128 
129       autoplaceSpannerSegment();
130       }
131 
132 //---------------------------------------------------------
133 //   shape
134 //---------------------------------------------------------
135 
shape() const136 Shape VibratoSegment::shape() const
137       {
138       return Shape(bbox());
139       }
140 
141 //---------------------------------------------------------
142 //   propertyDelegate
143 //---------------------------------------------------------
144 
propertyDelegate(Pid pid)145 Element* VibratoSegment::propertyDelegate(Pid pid)
146       {
147       if (pid == Pid::VIBRATO_TYPE || pid == Pid::PLACEMENT || pid == Pid::PLAY)
148             return spanner();
149       return LineSegment::propertyDelegate(pid);
150       }
151 
152 //---------------------------------------------------------
153 //   vibratoStyle
154 //---------------------------------------------------------
155 
156 static const ElementStyle vibratoStyle {
157       { Sid::vibratoPlacement,      Pid::PLACEMENT    },
158       { Sid::vibratoPosAbove,       Pid::OFFSET       },
159       };
160 
161 //---------------------------------------------------------
162 //   Vibrato
163 //---------------------------------------------------------
164 
Vibrato(Score * s)165 Vibrato::Vibrato(Score* s)
166   : SLine(s)
167       {
168       initElementStyle(&vibratoStyle);
169       _vibratoType = Type::GUITAR_VIBRATO;
170       setPlayArticulation(true);
171       }
172 
~Vibrato()173 Vibrato::~Vibrato()
174       {
175       }
176 
177 //---------------------------------------------------------
178 //   layout
179 //---------------------------------------------------------
180 
layout()181 void Vibrato::layout()
182       {
183       SLine::layout();
184       if (score() == gscore)
185             return;
186       if (spannerSegments().empty()) {
187             qDebug("Vibrato: no segments");
188             return;
189             }
190       }
191 
192 static const ElementStyle vibratoSegmentStyle {
193       { Sid::vibratoPosAbove,       Pid::OFFSET       },
194       { Sid::vibratoMinDistance,    Pid::MIN_DISTANCE },
195       };
196 
197 //---------------------------------------------------------
198 //   createLineSegment
199 //---------------------------------------------------------
200 
createLineSegment()201 LineSegment* Vibrato::createLineSegment()
202       {
203       VibratoSegment* seg = new VibratoSegment(this, score());
204       seg->setTrack(track());
205       seg->setColor(color());
206       seg->initElementStyle(&vibratoSegmentStyle);
207       return seg;
208       }
209 
210 //---------------------------------------------------------
211 //   Vibrato::write
212 //---------------------------------------------------------
213 
write(XmlWriter & xml) const214 void Vibrato::write(XmlWriter& xml) const
215       {
216       if (!xml.canWrite(this))
217             return;
218       xml.stag(this);
219       xml.tag("subtype", vibratoTypeName());
220       writeProperty(xml, Pid::PLAY);
221       for (const StyledProperty& spp : *styledProperties())
222             writeProperty(xml, spp.pid);
223       SLine::writeProperties(xml);
224       xml.etag();
225       }
226 
227 //---------------------------------------------------------
228 //   Vibrato::read
229 //---------------------------------------------------------
230 
read(XmlReader & e)231 void Vibrato::read(XmlReader& e)
232       {
233       eraseSpannerSegments();
234 
235       while (e.readNextStartElement()) {
236             const QStringRef& tag(e.name());
237             if (tag == "subtype")
238                   setVibratoType(e.readElementText());
239             else if ( tag == "play")
240                   setPlayArticulation(e.readBool());
241             else if (!SLine::readProperties(e))
242                   e.unknown();
243             }
244       }
245 
246 //---------------------------------------------------------
247 //   setVibratoType
248 //---------------------------------------------------------
249 
setVibratoType(const QString & s)250 void Vibrato::setVibratoType(const QString& s)
251       {
252       for (VibratoTableItem i : vibratoTable) {
253             if (s.compare(i.name) == 0) {
254                   _vibratoType = i.type;
255                   return;
256                   }
257             }
258       qDebug("Vibrato::setSubtype: unknown <%s>", qPrintable(s));
259       }
260 
261 //---------------------------------------------------------
262 //   type2name
263 //---------------------------------------------------------
264 
type2name(Vibrato::Type t)265 QString Vibrato::type2name(Vibrato::Type t)
266       {
267       for (VibratoTableItem i : vibratoTable) {
268             if (i.type == t)
269                   return i.name;
270             }
271       qDebug("unknown Vibrato subtype %d", int(t));
272             return "?";
273       }
274 
275 //---------------------------------------------------------
276 //   vibratoTypeName
277 //---------------------------------------------------------
278 
vibratoTypeName() const279 QString Vibrato::vibratoTypeName() const
280       {
281       return type2name(vibratoType());
282       }
283 
284 //---------------------------------------------------------
285 //   vibratoTypeName
286 //---------------------------------------------------------
287 
vibratoTypeUserName() const288 QString Vibrato::vibratoTypeUserName() const
289       {
290       return qApp->translate("vibratoType", vibratoTable[static_cast<int>(vibratoType())].userName.toUtf8().constData());
291       }
292 
293 //---------------------------------------------------------
294 //   getPropertyStyle
295 //---------------------------------------------------------
296 
getPropertyStyle(Pid pid) const297 Sid VibratoSegment::getPropertyStyle(Pid pid) const
298       {
299       if (pid == Pid::OFFSET)
300             return spanner()->placeAbove() ? Sid::vibratoPosAbove : Sid::vibratoPosBelow;
301       return LineSegment::getPropertyStyle(pid);
302       }
303 
getPropertyStyle(Pid pid) const304 Sid Vibrato::getPropertyStyle(Pid pid) const
305       {
306       if (pid == Pid::OFFSET)
307             return placeAbove() ? Sid::vibratoPosAbove : Sid::vibratoPosBelow;
308       return SLine::getPropertyStyle(pid);
309       }
310 
311 //---------------------------------------------------------
312 //   getProperty
313 //---------------------------------------------------------
314 
getProperty(Pid propertyId) const315 QVariant Vibrato::getProperty(Pid propertyId) const
316       {
317       switch(propertyId) {
318             case Pid::VIBRATO_TYPE:
319                   return int(vibratoType());
320             case Pid::PLAY:
321                   return bool(playArticulation());
322             default:
323                   break;
324             }
325       return SLine::getProperty(propertyId);
326       }
327 
328 //---------------------------------------------------------
329 //   setProperty
330 //---------------------------------------------------------
331 
setProperty(Pid propertyId,const QVariant & val)332 bool Vibrato::setProperty(Pid propertyId, const QVariant& val)
333       {
334       switch(propertyId) {
335             case Pid::VIBRATO_TYPE:
336                   setVibratoType(Type(val.toInt()));
337                   break;
338             case Pid::PLAY:
339                   setPlayArticulation(val.toBool());
340                   break;
341             default:
342                   if (!SLine::setProperty(propertyId, val))
343                         return false;
344                   break;
345             }
346       triggerLayoutAll();
347       return true;
348       }
349 
350 //---------------------------------------------------------
351 //   propertyDefault
352 //---------------------------------------------------------
353 
propertyDefault(Pid propertyId) const354 QVariant Vibrato::propertyDefault(Pid propertyId) const
355       {
356       switch(propertyId) {
357             case Pid::VIBRATO_TYPE:
358                   return 0;
359             case Pid::PLAY:
360                   return true;
361             case Pid::PLACEMENT:
362                   return score()->styleV(Sid::vibratoPlacement);
363             default:
364                   return SLine::propertyDefault(propertyId);
365             }
366       }
367 
368 //---------------------------------------------------------
369 //   propertyId
370 //---------------------------------------------------------
371 
propertyId(const QStringRef & name) const372 Pid Vibrato::propertyId(const QStringRef& name) const
373       {
374       if (name == "subtype")
375             return Pid::VIBRATO_TYPE;
376       return SLine::propertyId(name);
377       }
378 
379 //---------------------------------------------------------
380 //   undoSetVibratoType
381 //---------------------------------------------------------
382 
undoSetVibratoType(Type val)383 void Vibrato::undoSetVibratoType(Type val)
384       {
385       undoChangeProperty(Pid::VIBRATO_TYPE, int(val));
386       }
387 
388 //---------------------------------------------------------
389 //   accessibleInfo
390 //---------------------------------------------------------
391 
accessibleInfo() const392 QString Vibrato::accessibleInfo() const
393       {
394       return QString("%1: %2").arg(Element::accessibleInfo(), vibratoTypeUserName());
395       }
396 }
397 
398