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 "chordrest.h"
14 #include "chord.h"
15 #include "xml.h"
16 #include "style.h"
17 #include "system.h"
18 #include "measure.h"
19 #include "staff.h"
20 #include "tuplet.h"
21 #include "score.h"
22 #include "sym.h"
23 #include "slur.h"
24 #include "beam.h"
25 #include "breath.h"
26 #include "barline.h"
27 #include "articulation.h"
28 #include "tempo.h"
29 #include "tempotext.h"
30 #include "note.h"
31 #include "arpeggio.h"
32 #include "dynamic.h"
33 #include "stafftext.h"
34 #include "sig.h"
35 #include "clef.h"
36 #include "lyrics.h"
37 #include "segment.h"
38 #include "stafftype.h"
39 #include "undo.h"
40 #include "stem.h"
41 #include "harmony.h"
42 #include "hairpin.h"
43 #include "figuredbass.h"
44 #include "icon.h"
45 #include "utils.h"
46 #include "keysig.h"
47 #include "page.h"
48 #include "hook.h"
49 #include "rehearsalmark.h"
50 #include "instrchange.h"
51
52 namespace Ms {
53
54 //---------------------------------------------------------
55 // ChordRest
56 //---------------------------------------------------------
57
ChordRest(Score * s)58 ChordRest::ChordRest(Score* s)
59 : DurationElement(s)
60 {
61 _staffMove = 0;
62 _beam = 0;
63 _tabDur = 0;
64 _up = true;
65 _beamMode = Beam::Mode::AUTO;
66 _small = false;
67 _melismaEnd = false;
68 _crossMeasure = CrossMeasure::UNKNOWN;
69 }
70
ChordRest(const ChordRest & cr,bool link)71 ChordRest::ChordRest(const ChordRest& cr, bool link)
72 : DurationElement(cr)
73 {
74 _durationType = cr._durationType;
75 _staffMove = cr._staffMove;
76 _beam = 0;
77 _tabDur = 0; // tab sur. symb. depends upon context: can't be
78 // simply copied from another CR
79
80 _beamMode = cr._beamMode;
81 _up = cr._up;
82 _small = cr._small;
83 _melismaEnd = cr._melismaEnd;
84 _crossMeasure = cr._crossMeasure;
85
86 for (Lyrics* l : cr._lyrics) { // make deep copy
87 Lyrics* nl = new Lyrics(*l);
88 if (link)
89 nl->linkTo(l);
90 nl->setParent(this);
91 nl->setTrack(track());
92 _lyrics.push_back(nl);
93 }
94 }
95
96 //---------------------------------------------------------
97 // undoUnlink
98 //---------------------------------------------------------
99
undoUnlink()100 void ChordRest::undoUnlink()
101 {
102 DurationElement::undoUnlink();
103 for (Lyrics* l : _lyrics)
104 l->undoUnlink();
105 }
106
107 //---------------------------------------------------------
108 // ChordRest
109 //---------------------------------------------------------
110
~ChordRest()111 ChordRest::~ChordRest()
112 {
113 qDeleteAll(_lyrics);
114 qDeleteAll(_el);
115 delete _tabDur;
116 if (_beam && _beam->contains(this))
117 delete _beam; // Beam destructor removes references to the deleted object
118 }
119
120 //---------------------------------------------------------
121 // scanElements
122 //---------------------------------------------------------
123
scanElements(void * data,void (* func)(void *,Element *),bool all)124 void ChordRest::scanElements(void* data, void (*func)(void*, Element*), bool all)
125 {
126 if (_beam && (_beam->elements().front() == this)
127 && !measure()->stemless(staffIdx()))
128 _beam->scanElements(data, func, all);
129 for (Lyrics* l : _lyrics)
130 l->scanElements(data, func, all);
131 DurationElement* de = this;
132 while (de->tuplet() && de->tuplet()->elements().front() == de) {
133 de->tuplet()->scanElements(data, func, all);
134 de = de->tuplet();
135 }
136 if (_tabDur)
137 func(data, _tabDur);
138 }
139
140 //---------------------------------------------------------
141 // writeProperties
142 //---------------------------------------------------------
143
writeProperties(XmlWriter & xml) const144 void ChordRest::writeProperties(XmlWriter& xml) const
145 {
146 DurationElement::writeProperties(xml);
147
148 //
149 // Beam::Mode default:
150 // REST - Beam::Mode::NONE
151 // CHORD - Beam::Mode::AUTO
152 //
153 if ((isRest() && _beamMode != Beam::Mode::NONE) || (isChord() && _beamMode != Beam::Mode::AUTO)) {
154 QString s;
155 switch(_beamMode) {
156 case Beam::Mode::AUTO: s = "auto"; break;
157 case Beam::Mode::BEGIN: s = "begin"; break;
158 case Beam::Mode::MID: s = "mid"; break;
159 case Beam::Mode::END: s = "end"; break;
160 case Beam::Mode::NONE: s = "no"; break;
161 case Beam::Mode::BEGIN32: s = "begin32"; break;
162 case Beam::Mode::BEGIN64: s = "begin64"; break;
163 case Beam::Mode::INVALID: s = "?"; break;
164 }
165 xml.tag("BeamMode", s);
166 }
167 writeProperty(xml, Pid::SMALL);
168 if (actualDurationType().dots())
169 xml.tag("dots", actualDurationType().dots());
170 writeProperty(xml, Pid::STAFF_MOVE);
171
172 if (actualDurationType().isValid())
173 xml.tag("durationType", actualDurationType().name());
174
175 if (!ticks().isZero() && (!actualDurationType().fraction().isValid()
176 || (actualDurationType().fraction() != ticks()))) {
177 xml.tag("duration", ticks());
178 //xml.tagE("duration z=\"%d\" n=\"%d\"", ticks().numerator(), ticks().denominator());
179 }
180
181 for (Lyrics* lyrics : _lyrics)
182 lyrics->write(xml);
183
184 const int curTick = xml.curTick().ticks();
185
186 if (!isGrace()) {
187 Fraction t(globalTicks());
188 if (staff())
189 t /= staff()->timeStretch(xml.curTick());
190 xml.incCurTick(t);
191 }
192
193 for (auto i : score()->spannerMap().findOverlapping(curTick - 1, curTick + 1)) {
194 Spanner* s = i.value;
195 if (s->generated() || !s->isSlur() || toSlur(s)->broken() || !xml.canWrite(s))
196 continue;
197
198 if (s->startElement() == this)
199 s->writeSpannerStart(xml, this, track());
200 else if (s->endElement() == this)
201 s->writeSpannerEnd(xml, this, track());
202 }
203 }
204
205 //---------------------------------------------------------
206 // readProperties
207 //---------------------------------------------------------
208
readProperties(XmlReader & e)209 bool ChordRest::readProperties(XmlReader& e)
210 {
211 const QStringRef& tag(e.name());
212
213 if (tag == "durationType") {
214 setDurationType(e.readElementText());
215 if (actualDurationType().type() != TDuration::DurationType::V_MEASURE) {
216 if (score()->mscVersion() < 112 && (type() == ElementType::REST) &&
217 // for backward compatibility, convert V_WHOLE rests to V_MEASURE
218 // if long enough to fill a measure.
219 // OTOH, freshly created (un-initialized) rests have numerator == 0 (< 4/4)
220 // (see Fraction() constructor in fraction.h; this happens for instance
221 // when pasting selection from clipboard): they should not be converted
222 ticks().numerator() != 0 &&
223 // rest durations are initialized to full measure duration when
224 // created upon reading the <Rest> tag (see Measure::read() )
225 // so a V_WHOLE rest in a measure of 4/4 or less => V_MEASURE
226 (actualDurationType()==TDuration::DurationType::V_WHOLE && ticks() <= Fraction(4, 4)) ) {
227 // old pre 2.0 scores: convert
228 setDurationType(TDuration::DurationType::V_MEASURE);
229 }
230 else // not from old score: set duration fraction from duration type
231 setTicks(actualDurationType().fraction());
232 }
233 else {
234 if (score()->mscVersion() <= 114) {
235 SigEvent event = score()->sigmap()->timesig(e.tick());
236 setTicks(event.timesig());
237 }
238 }
239 }
240 else if (tag == "BeamMode") {
241 QString val(e.readElementText());
242 Beam::Mode bm = Beam::Mode::AUTO;
243 if (val == "auto")
244 bm = Beam::Mode::AUTO;
245 else if (val == "begin")
246 bm = Beam::Mode::BEGIN;
247 else if (val == "mid")
248 bm = Beam::Mode::MID;
249 else if (val == "end")
250 bm = Beam::Mode::END;
251 else if (val == "no")
252 bm = Beam::Mode::NONE;
253 else if (val == "begin32")
254 bm = Beam::Mode::BEGIN32;
255 else if (val == "begin64")
256 bm = Beam::Mode::BEGIN64;
257 else
258 bm = Beam::Mode(val.toInt());
259 _beamMode = Beam::Mode(bm);
260 }
261 else if (tag == "Articulation") {
262 Articulation* atr = new Articulation(score());
263 atr->setTrack(track());
264 atr->read(e);
265 add(atr);
266 }
267 else if (tag == "leadingSpace" || tag == "trailingSpace") {
268 qDebug("ChordRest: %s obsolete", tag.toLocal8Bit().data());
269 e.skipCurrentElement();
270 }
271 else if (tag == "small")
272 _small = e.readInt();
273 else if (tag == "duration")
274 setTicks(e.readFraction());
275 else if (tag == "ticklen") { // obsolete (version < 1.12)
276 int mticks = score()->sigmap()->timesig(e.tick()).timesig().ticks();
277 int i = e.readInt();
278 if (i == 0)
279 i = mticks;
280 if ((type() == ElementType::REST) && (mticks == i)) {
281 setDurationType(TDuration::DurationType::V_MEASURE);
282 setTicks(Fraction::fromTicks(i));
283 }
284 else {
285 Fraction f = Fraction::fromTicks(i);
286 setTicks(f);
287 setDurationType(TDuration(f));
288 }
289 }
290 else if (tag == "dots")
291 setDots(e.readInt());
292 else if (tag == "staffMove") {
293 _staffMove = e.readInt();
294 if (vStaffIdx() < part()->staves()->first()->idx() || vStaffIdx() > part()->staves()->last()->idx())
295 _staffMove = 0;
296 }
297 else if (tag == "Spanner")
298 Spanner::readSpanner(e, this, track());
299 else if (tag == "Lyrics") {
300 Element* element = new Lyrics(score());
301 element->setTrack(e.track());
302 element->read(e);
303 add(element);
304 }
305 else if (tag == "pos") {
306 QPointF pt = e.readPoint();
307 setOffset(pt * spatium());
308 }
309 // else if (tag == "offset")
310 // DurationElement::readProperties(e);
311 else if (!DurationElement::readProperties(e))
312 return false;
313 return true;
314 }
315
316 //---------------------------------------------------------
317 // ChordRest::readAddConnector
318 //---------------------------------------------------------
319
readAddConnector(ConnectorInfoReader * info,bool pasteMode)320 void ChordRest::readAddConnector(ConnectorInfoReader* info, bool pasteMode)
321 {
322 const ElementType type = info->type();
323 switch (type) {
324 case ElementType::SLUR:
325 {
326 Spanner* spanner = toSpanner(info->connector());
327 const Location& l = info->location();
328
329 if (info->isStart()) {
330 spanner->setTrack(l.track());
331 spanner->setTick(tick());
332 spanner->setStartElement(this);
333 if (pasteMode) {
334 score()->undoAddElement(spanner);
335 for (ScoreElement* ee : spanner->linkList()) {
336 if (ee == spanner)
337 continue;
338 Spanner* ls = toSpanner(ee);
339 ls->setTick(spanner->tick());
340 for (ScoreElement* eee : linkList()) {
341 ChordRest* cr = toChordRest(eee);
342 if (cr->score() == eee->score() && cr->staffIdx() == ls->staffIdx()) {
343 ls->setTrack(cr->track());
344 if (ls->isSlur())
345 ls->setStartElement(cr);
346 break;
347 }
348 }
349 }
350 }
351 else
352 score()->addSpanner(spanner);
353 }
354 else if (info->isEnd()) {
355 spanner->setTrack2(l.track());
356 spanner->setTick2(tick());
357 spanner->setEndElement(this);
358 if (pasteMode) {
359 for (ScoreElement* ee : spanner->linkList()) {
360 if (ee == spanner)
361 continue;
362 Spanner* ls = static_cast<Spanner*>(ee);
363 ls->setTick2(spanner->tick2());
364 for (ScoreElement* eee : linkList()) {
365 ChordRest* cr = toChordRest(eee);
366 if (cr->score() == eee->score() && cr->staffIdx() == ls->staffIdx()) {
367 ls->setTrack2(cr->track());
368 if (ls->type() == ElementType::SLUR)
369 ls->setEndElement(cr);
370 break;
371 }
372 }
373 }
374 }
375 }
376 else
377 qDebug("ChordRest::readAddConnector(): Slur end is neither start nor end");
378 }
379 break;
380 default:
381 break;
382 }
383 }
384
385 //---------------------------------------------------------
386 // setSmall
387 //---------------------------------------------------------
388
setSmall(bool val)389 void ChordRest::setSmall(bool val)
390 {
391 _small = val;
392 }
393
394 //---------------------------------------------------------
395 // undoSetSmall
396 //---------------------------------------------------------
397
undoSetSmall(bool val)398 void ChordRest::undoSetSmall(bool val)
399 {
400 undoChangeProperty(Pid::SMALL, val);
401 }
402
403 //---------------------------------------------------------
404 // drop
405 //---------------------------------------------------------
406
drop(EditData & data)407 Element* ChordRest::drop(EditData& data)
408 {
409 Element* e = data.dropElement;
410 Measure* m = measure();
411 bool fromPalette = (e->track() == -1);
412 switch (e->type()) {
413 case ElementType::BREATH:
414 {
415 Breath* b = toBreath(e);
416 b->setPos(QPointF());
417 // allow breath marks in voice > 1
418 b->setTrack(this->track());
419 b->setPlacement(b->track() & 1 ? Placement::BELOW : Placement::ABOVE);
420 Fraction bt = tick() + actualTicks();
421
422 bt = tick() + actualTicks();
423 // TODO: insert automatically in all staves?
424
425 Segment* seg = m->undoGetSegment(SegmentType::Breath, bt);
426 b->setParent(seg);
427 score()->undoAddElement(b);
428 }
429 return e;
430
431 case ElementType::BAR_LINE:
432 if (data.control())
433 score()->splitMeasure(segment());
434 else {
435 BarLine* bl = toBarLine(e);
436 bl->setPos(QPointF());
437 bl->setTrack(staffIdx() * VOICES);
438 bl->setGenerated(false);
439
440 if (tick() == m->tick())
441 return m->drop(data);
442
443 BarLine* obl = 0;
444 for (Staff* st : staff()->staffList()) {
445 Score* score = st->score();
446 Measure* measure = score->tick2measure(m->tick());
447 Segment* seg = measure->undoGetSegmentR(SegmentType::BarLine, rtick());
448 BarLine* l;
449 if (obl == 0)
450 obl = l = bl->clone();
451 else
452 l = toBarLine(obl->linkedClone());
453 l->setTrack(st->idx() * VOICES);
454 l->setScore(score);
455 l->setParent(seg);
456 score->undoAddElement(l);
457 l->layout();
458 }
459 }
460 delete e;
461 return 0;
462
463 case ElementType::CLEF:
464 score()->cmdInsertClef(toClef(e), this);
465 break;
466
467 case ElementType::TIMESIG:
468 if (measure()->system()) {
469 EditData ndd = data;
470 // adding from palette sets pos, but normal paste does not
471 if (!fromPalette)
472 ndd.pos = pagePos();
473 // convert page-relative pos to score-relative
474 ndd.pos += measure()->system()->page()->pos();
475 return measure()->drop(ndd);
476 }
477 else {
478 delete e;
479 return 0;
480 }
481
482 case ElementType::FERMATA:
483 e->setPlacement(track() & 1 ? Placement::BELOW : Placement::ABOVE);
484 for (Element* el: segment()->annotations())
485 if (el->isFermata() && (el->track() == track())) {
486 if (el->subtype() == e->subtype()) {
487 delete e;
488 return el;
489 }
490 else {
491 e->setPlacement(el->placement());
492 e->setTrack(track());
493 e->setParent(segment());
494 score()->undoChangeElement(el, e);
495 return e;
496 }
497 }
498 // fall through
499 case ElementType::TEMPO_TEXT:
500 case ElementType::DYNAMIC:
501 case ElementType::FRET_DIAGRAM:
502 case ElementType::TREMOLOBAR:
503 case ElementType::SYMBOL:
504 e->setTrack(track());
505 e->setParent(segment());
506 score()->undoAddElement(e);
507 return e;
508
509 case ElementType::NOTE: {
510 Note* note = toNote(e);
511 NoteVal nval;
512 nval.pitch = note->pitch();
513 nval.tpc1 = note->tpc1();
514 nval.headGroup = note->headGroup();
515 nval.fret = note->fret();
516 nval.string = note->string();
517 score()->setNoteRest(segment(), track(), nval, ticks(), Direction::AUTO);
518 delete e;
519 }
520 break;
521
522 case ElementType::HARMONY:
523 {
524 // transpose
525 Harmony* harmony = toHarmony(e);
526 Interval interval = staff()->part()->instrument(tick())->transpose();
527 if (!score()->styleB(Sid::concertPitch) && !interval.isZero()) {
528 interval.flip();
529 int rootTpc = transposeTpc(harmony->rootTpc(), interval, true);
530 int baseTpc = transposeTpc(harmony->baseTpc(), interval, true);
531 score()->undoTransposeHarmony(harmony, rootTpc, baseTpc);
532 }
533 // render
534 harmony->render();
535 }
536 // fall through
537 case ElementType::TEXT:
538 case ElementType::STAFF_TEXT:
539 case ElementType::SYSTEM_TEXT:
540 case ElementType::STICKING:
541 case ElementType::STAFF_STATE:
542 // fall through
543 case ElementType::REHEARSAL_MARK:
544 {
545 e->setParent(segment());
546 e->setTrack((track() / VOICES) * VOICES);
547 if (e->isRehearsalMark()) {
548 RehearsalMark* r = toRehearsalMark(e);
549 if (fromPalette)
550 r->setXmlText(score()->createRehearsalMarkText(r));
551 }
552 score()->undoAddElement(e);
553 return e;
554 }
555 case ElementType::INSTRUMENT_CHANGE:
556 if (part()->instruments()->find(tick().ticks()) != part()->instruments()->end()) {
557 qDebug() << "InstrumentChange already exists at tick = " << tick().ticks();
558 delete e;
559 return 0;
560 }
561 else {
562 InstrumentChange* ic = toInstrumentChange(e);
563 ic->setParent(segment());
564 ic->setTrack((track() / VOICES) * VOICES);
565 Instrument* instr = ic->instrument();
566 Instrument* prevInstr = part()->instrument(tick());
567 if (instr && instr->isDifferentInstrument(*prevInstr))
568 ic->setupInstrument(instr);
569 score()->undoAddElement(ic);
570 return e;
571 }
572 case ElementType::FIGURED_BASS:
573 {
574 bool bNew;
575 FiguredBass * fb = toFiguredBass(e);
576 fb->setParent( segment() );
577 fb->setTrack( (track() / VOICES) * VOICES );
578 fb->setTicks(ticks() );
579 fb->setOnNote(true);
580 FiguredBass::addFiguredBassToSegment(segment(), fb->track(), fb->ticks(), &bNew);
581 if (bNew)
582 score()->undoAddElement(e);
583 return e;
584 }
585
586 case ElementType::IMAGE:
587 e->setParent(segment());
588 score()->undoAddElement(e);
589 return e;
590
591 case ElementType::ICON:
592 {
593 switch (toIcon(e)->iconType()) {
594 case IconType::SBEAM:
595 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::BEGIN));
596 break;
597 case IconType::MBEAM:
598 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::MID));
599 break;
600 case IconType::NBEAM:
601 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::NONE));
602 break;
603 case IconType::BEAM32:
604 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::BEGIN32));
605 break;
606 case IconType::BEAM64:
607 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::BEGIN64));
608 break;
609 case IconType::AUTOBEAM:
610 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::AUTO));
611 break;
612 default:
613 break;
614 }
615 }
616 delete e;
617 break;
618
619 case ElementType::KEYSIG:
620 {
621 KeySig* ks = toKeySig(e);
622 KeySigEvent k = ks->keySigEvent();
623 delete ks;
624
625 // apply only to this stave
626 score()->undoChangeKeySig(staff(), tick(), k);
627 }
628 break;
629
630 case ElementType::HAIRPIN:
631 {
632 Hairpin* hairpin = toHairpin(e);
633 hairpin->setTick(tick());
634 hairpin->setTrack(track());
635 hairpin->setTrack2(track());
636 score()->undoAddElement(hairpin);
637 }
638 return e;
639
640 default:
641 qDebug("cannot drop %s", e->name());
642 delete e;
643 return 0;
644 }
645 return 0;
646 }
647
648 //---------------------------------------------------------
649 // setBeam
650 //---------------------------------------------------------
651
setBeam(Beam * b)652 void ChordRest::setBeam(Beam* b)
653 {
654 _beam = b;
655 }
656
657 //---------------------------------------------------------
658 // setDurationType
659 //---------------------------------------------------------
660
setDurationType(TDuration::DurationType t)661 void ChordRest::setDurationType(TDuration::DurationType t)
662 {
663 _durationType.setType(t);
664 _crossMeasure = CrossMeasure::UNKNOWN;
665 }
666
setDurationType(const QString & s)667 void ChordRest::setDurationType(const QString& s)
668 {
669 _durationType.setType(s);
670 _crossMeasure = CrossMeasure::UNKNOWN;
671 }
672
setDurationType(const Fraction & ticks)673 void ChordRest::setDurationType(const Fraction& ticks)
674 {
675 _durationType.setVal(ticks.ticks());
676 _crossMeasure = CrossMeasure::UNKNOWN;
677 }
678
setDurationType(TDuration v)679 void ChordRest::setDurationType(TDuration v)
680 {
681 _durationType = v;
682 _crossMeasure = CrossMeasure::UNKNOWN;
683 }
684
685 //---------------------------------------------------------
686 // durationUserName
687 //---------------------------------------------------------
688
durationUserName() const689 QString ChordRest::durationUserName() const
690 {
691 QString tupletType = "";
692 if (tuplet()) {
693 switch (tuplet()->ratio().numerator()) {
694 case 2:
695 tupletType = QObject::tr("Duplet");
696 break;
697 case 3:
698 tupletType = QObject::tr("Triplet");
699 break;
700 case 4:
701 tupletType = QObject::tr("Quadruplet");
702 break;
703 case 5:
704 tupletType = QObject::tr("Quintuplet");
705 break;
706 case 6:
707 tupletType = QObject::tr("Sextuplet");
708 break;
709 case 7:
710 tupletType = QObject::tr("Septuplet");
711 break;
712 case 8:
713 tupletType = QObject::tr("Octuplet");
714 break;
715 case 9:
716 tupletType = QObject::tr("Nonuplet");
717 break;
718 default:
719 tupletType = QObject::tr("Custom tuplet");
720 }
721 }
722 QString dotString = "";
723 if(!tupletType.isEmpty())
724 dotString += " ";
725
726 switch (dots()) {
727 case 1:
728 dotString += QObject::tr("Dotted %1").arg(durationType().durationTypeUserName()).trimmed();
729 break;
730 case 2:
731 dotString += QObject::tr("Double dotted %1").arg(durationType().durationTypeUserName()).trimmed();
732 break;
733 case 3:
734 dotString += QObject::tr("Triple dotted %1").arg(durationType().durationTypeUserName()).trimmed();
735 break;
736 case 4:
737 dotString += QObject::tr("Quadruple dotted %1").arg(durationType().durationTypeUserName()).trimmed();
738 break;
739 default:
740 dotString += durationType().durationTypeUserName();
741 }
742 return QString("%1%2").arg(tupletType, dotString);
743 }
744
745 //---------------------------------------------------------
746 // add
747 //---------------------------------------------------------
748
add(Element * e)749 void ChordRest::add(Element* e)
750 {
751 e->setParent(this);
752 e->setTrack(track());
753 switch (e->type()) {
754 case ElementType::ARTICULATION: // for backward compatibility
755 qDebug("ChordRest::add: unknown element %s", e->name());
756 break;
757 case ElementType::LYRICS:
758 if (e->isStyled(Pid::OFFSET))
759 e->setOffset(e->propertyDefault(Pid::OFFSET).toPointF());
760 _lyrics.push_back(toLyrics(e));
761 break;
762 default:
763 qFatal("ChordRest::add: unknown element %s", e->name());
764 break;
765 }
766 }
767
768 //---------------------------------------------------------
769 // remove
770 //---------------------------------------------------------
771
remove(Element * e)772 void ChordRest::remove(Element* e)
773 {
774 switch (e->type()) {
775 case ElementType::LYRICS: {
776 toLyrics(e)->removeFromScore();
777 auto i = std::find(_lyrics.begin(), _lyrics.end(), toLyrics(e));
778 if (i != _lyrics.end())
779 _lyrics.erase(i);
780 else
781 qDebug("ChordRest::remove: %s %p not found", e->name(), e);
782 }
783 break;
784 default:
785 qFatal("ChordRest::remove: unknown element <%s>", e->name());
786 }
787 }
788
789 //---------------------------------------------------------
790 // removeDeleteBeam
791 /// Remove ChordRest from beam, delete beam if empty.
792 /// \param beamed - if the chordrest is beamed (will get
793 /// a (new) beam)
794 //---------------------------------------------------------
795
removeDeleteBeam(bool beamed)796 void ChordRest::removeDeleteBeam(bool beamed)
797 {
798 if (_beam) {
799 Beam* b = _beam;
800 _beam->remove(this);
801 if (b->empty())
802 score()->undoRemoveElement(b);
803 else
804 b->layout1();
805 }
806 if (!beamed && isChord())
807 toChord(this)->layoutStem();
808 }
809
810 //---------------------------------------------------------
811 // replaceBeam
812 //---------------------------------------------------------
813
replaceBeam(Beam * newBeam)814 void ChordRest::replaceBeam(Beam* newBeam)
815 {
816 if (_beam == newBeam)
817 return;
818 removeDeleteBeam(true);
819 newBeam->add(this);
820 }
821
822 //---------------------------------------------------------
823 // undoSetBeamMode
824 //---------------------------------------------------------
825
undoSetBeamMode(Beam::Mode mode)826 void ChordRest::undoSetBeamMode(Beam::Mode mode)
827 {
828 undoChangeProperty(Pid::BEAM_MODE, int(mode));
829 }
830
831 //---------------------------------------------------------
832 // localSpatiumChanged
833 //---------------------------------------------------------
834
localSpatiumChanged(qreal oldValue,qreal newValue)835 void ChordRest::localSpatiumChanged(qreal oldValue, qreal newValue)
836 {
837 DurationElement::localSpatiumChanged(oldValue, newValue);
838 for (Element* e : lyrics())
839 e->localSpatiumChanged(oldValue, newValue);
840 for (Element* e : el())
841 e->localSpatiumChanged(oldValue, newValue);
842 }
843
844 //---------------------------------------------------------
845 // getProperty
846 //---------------------------------------------------------
847
getProperty(Pid propertyId) const848 QVariant ChordRest::getProperty(Pid propertyId) const
849 {
850 switch (propertyId) {
851 case Pid::SMALL: return QVariant(small());
852 case Pid::BEAM_MODE: return int(beamMode());
853 case Pid::STAFF_MOVE: return staffMove();
854 case Pid::DURATION_TYPE: return QVariant::fromValue(actualDurationType());
855 default: return DurationElement::getProperty(propertyId);
856 }
857 }
858
859 //---------------------------------------------------------
860 // setProperty
861 //---------------------------------------------------------
862
setProperty(Pid propertyId,const QVariant & v)863 bool ChordRest::setProperty(Pid propertyId, const QVariant& v)
864 {
865 switch (propertyId) {
866 case Pid::SMALL:
867 setSmall(v.toBool());
868 break;
869 case Pid::BEAM_MODE:
870 setBeamMode(Beam::Mode(v.toInt()));
871 break;
872 case Pid::STAFF_MOVE:
873 setStaffMove(v.toInt());
874 break;
875 case Pid::VISIBLE:
876 setVisible(v.toBool());
877 measure()->checkMultiVoices(staffIdx());
878 break;
879 case Pid::DURATION_TYPE:
880 setDurationType(v.value<TDuration>());
881 break;
882 default:
883 return DurationElement::setProperty(propertyId, v);
884 }
885 triggerLayout();
886 return true;
887 }
888
889 //---------------------------------------------------------
890 // propertyDefault
891 //---------------------------------------------------------
892
propertyDefault(Pid propertyId) const893 QVariant ChordRest::propertyDefault(Pid propertyId) const
894 {
895 switch (propertyId) {
896 case Pid::SMALL:
897 return false;
898 case Pid::BEAM_MODE:
899 return int(Beam::Mode::AUTO);
900 case Pid::STAFF_MOVE:
901 return 0;
902 default:
903 return DurationElement::propertyDefault(propertyId);
904 }
905 // Prevent unreachable code warning
906 // triggerLayout();
907 }
908
909 //---------------------------------------------------------
910 // isGrace
911 //---------------------------------------------------------
912
isGrace() const913 bool ChordRest::isGrace() const
914 {
915 return isChord() && toChord(this)->isGrace();
916 }
917
918 //---------------------------------------------------------
919 // isGraceBefore
920 //---------------------------------------------------------
921
isGraceBefore() const922 bool ChordRest::isGraceBefore() const
923 {
924 return isChord()
925 && (toChord(this)->noteType() & (
926 NoteType::ACCIACCATURA | NoteType::APPOGGIATURA | NoteType::GRACE4 | NoteType::GRACE16 | NoteType::GRACE32
927 ));
928 }
929
930 //---------------------------------------------------------
931 // isGraceAfter
932 //---------------------------------------------------------
933
isGraceAfter() const934 bool ChordRest::isGraceAfter() const
935 {
936 return isChord()
937 && (toChord(this)->noteType() & (NoteType::GRACE8_AFTER | NoteType::GRACE16_AFTER | NoteType::GRACE32_AFTER));
938 }
939
940 //---------------------------------------------------------
941 // hasBreathMark - determine if chordrest has breath-mark
942 //---------------------------------------------------------
hasBreathMark() const943 Breath* ChordRest::hasBreathMark() const
944 {
945 Fraction end = tick() + actualTicks();
946 Segment* s = measure()->findSegment(SegmentType::Breath, end);
947 return s ? toBreath(s->element(track())) : 0;
948 }
949
950 //---------------------------------------------------------
951 // writeBeam
952 //---------------------------------------------------------
953
writeBeam(XmlWriter & xml) const954 void ChordRest::writeBeam(XmlWriter& xml) const
955 {
956 Beam* b = beam();
957 if (b && b->elements().front() == this && (MScore::testMode || !b->generated())) {
958 b->write(xml);
959 }
960 }
961
962 //---------------------------------------------------------
963 // nextSegmentAfterCR
964 // returns first segment at tick CR->tick + CR->actualTicks
965 // of given types
966 //---------------------------------------------------------
967
nextSegmentAfterCR(SegmentType types) const968 Segment* ChordRest::nextSegmentAfterCR(SegmentType types) const
969 {
970 Fraction end = tick() + actualTicks();
971 for (Segment* s = segment()->next1MM(types); s; s = s->next1MM(types)) {
972 // chordrest ends at afrac+actualFraction
973 // we return the segment at or after the end of the chordrest
974 // Segment::afrac() is based on ticks; use DurationElement::afrac() if possible
975 Element* e = s;
976 if (s->isChordRestType()) {
977 // Find the first non-NULL element in the segment
978 for (Element* ee : s->elist()) {
979 if (ee) {
980 e = ee;
981 break;
982 }
983 }
984 }
985 if (e->tick() >= end)
986 return s;
987 }
988 return 0;
989 }
990
991 //---------------------------------------------------------
992 // setTrack
993 //---------------------------------------------------------
994
setTrack(int val)995 void ChordRest::setTrack(int val)
996 {
997 Element::setTrack(val);
998 processSiblings([val] (Element* e) { e->setTrack(val); } );
999 }
1000
1001 //---------------------------------------------------------
1002 // setScore
1003 //---------------------------------------------------------
1004
setScore(Score * s)1005 void ChordRest::setScore(Score* s)
1006 {
1007 Element::setScore(s);
1008 processSiblings([s] (Element* e) { e->setScore(s); } );
1009 }
1010
1011 //---------------------------------------------------------
1012 // processSiblings
1013 //---------------------------------------------------------
1014
processSiblings(std::function<void (Element *)> func)1015 void ChordRest::processSiblings(std::function<void(Element*)> func)
1016 {
1017 if (_beam)
1018 func(_beam);
1019 if (_tabDur)
1020 func(_tabDur);
1021 for (Lyrics* l : _lyrics)
1022 func(l);
1023 if (tuplet())
1024 func(tuplet());
1025 }
1026
1027 //---------------------------------------------------------
1028 // nextArticulationOrLyric
1029 //---------------------------------------------------------
1030
nextArticulationOrLyric(Element * e)1031 Element* ChordRest::nextArticulationOrLyric(Element* e)
1032 {
1033 if (isChord() && e->isArticulation()) {
1034 Chord* c = toChord(this);
1035 auto i = std::find(c->articulations().begin(), c->articulations().end(), e);
1036 if (i != c->articulations().end()) {
1037 if (i != c->articulations().end() - 1) {
1038 return *(i+1);
1039 }
1040 else {
1041 if (!_lyrics.empty())
1042 return _lyrics[0];
1043 else
1044 return nullptr;
1045 }
1046 }
1047 }
1048 else {
1049 auto i = std::find(_lyrics.begin(), _lyrics.end(), e);
1050 if (i != _lyrics.end()) {
1051 if (i != _lyrics.end()-1)
1052 return *(i+1);
1053 }
1054 }
1055 return 0;
1056 }
1057
1058 //---------------------------------------------------------
1059 // prevArticulationOrLyric
1060 //---------------------------------------------------------
1061
prevArticulationOrLyric(Element * e)1062 Element* ChordRest::prevArticulationOrLyric(Element* e)
1063 {
1064 auto i = std::find(_lyrics.begin(), _lyrics.end(), e);
1065 if (i != _lyrics.end()) {
1066 if (i != _lyrics.begin()) {
1067 return *(i-1);
1068 }
1069 else {
1070 if (isChord() && !toChord(this)->articulations().empty())
1071 return toChord(this)->articulations().back();
1072 else
1073 return nullptr;
1074 }
1075 }
1076 else if (isChord() && e->isArticulation()) {
1077 Chord* c = toChord(this);
1078 auto j = std::find(c->articulations().begin(), c->articulations().end(), e);
1079 if (j != c->articulations().end()) {
1080 if (j != c->articulations().begin())
1081 return *(j-1);
1082 }
1083 }
1084 return 0;
1085 }
1086
1087 //---------------------------------------------------------
1088 // nextElement
1089 //---------------------------------------------------------
1090
nextElement()1091 Element* ChordRest::nextElement()
1092 {
1093 Element* e = score()->selection().element();
1094 if (!e && !score()->selection().elements().isEmpty())
1095 e = score()->selection().elements().first();
1096 switch (e->type()) {
1097 case ElementType::ARTICULATION:
1098 case ElementType::LYRICS: {
1099 Element* next = nextArticulationOrLyric(e);
1100 if (next)
1101 return next;
1102 else
1103 break;
1104 }
1105 default: {
1106 if (isChord() && !toChord(this)->articulations().empty())
1107 return toChord(this)->articulations()[0];
1108 else if (!_lyrics.empty())
1109 return _lyrics[0];
1110 else
1111 break;
1112 }
1113 }
1114 int staffId = e->staffIdx();
1115 return segment()->nextElement(staffId);
1116 }
1117
1118 //---------------------------------------------------------
1119 // prevElement
1120 //---------------------------------------------------------
1121
prevElement()1122 Element* ChordRest::prevElement()
1123 {
1124 Element* e = score()->selection().element();
1125 if (!e && !score()->selection().elements().isEmpty())
1126 e = score()->selection().elements().last();
1127 switch (e->type()) {
1128 case ElementType::ARTICULATION:
1129 case ElementType::LYRICS: {
1130 Element* prev = prevArticulationOrLyric(e);
1131 if (prev)
1132 return prev;
1133 else {
1134 if (isChord())
1135 return toChord(this)->lastElementBeforeSegment();
1136 }
1137 // fall through
1138 }
1139 default: {
1140 break;
1141 }
1142 }
1143 int staffId = e->staffIdx();
1144 return segment()->prevElement(staffId);
1145 }
1146
1147 //---------------------------------------------------------
1148 // lastElementBeforeSegment
1149 //---------------------------------------------------------
1150
lastElementBeforeSegment()1151 Element* ChordRest::lastElementBeforeSegment()
1152 {
1153 if (!_lyrics.empty())
1154 return _lyrics.back();
1155 // else if (!_articulations.empty()) { // TODO:fermata
1156 // return _articulations.back();
1157 // }
1158 else
1159 return 0;
1160 }
1161
1162 //---------------------------------------------------------
1163 // nextSegmentElement
1164 //---------------------------------------------------------
1165
nextSegmentElement()1166 Element* ChordRest::nextSegmentElement()
1167 {
1168 return segment()->firstInNextSegments(staffIdx());
1169 }
1170
1171 //---------------------------------------------------------
1172 // prevSegmentElement
1173 //---------------------------------------------------------
1174
prevSegmentElement()1175 Element* ChordRest::prevSegmentElement()
1176 {
1177 return segment()->lastInPrevSegments(staffIdx());
1178 }
1179
accessibleExtraInfo() const1180 QString ChordRest::accessibleExtraInfo() const
1181 {
1182 QString rez = "";
1183 for (Element* l : lyrics()) {
1184 if (!score()->selectionFilter().canSelect(l))
1185 continue;
1186 rez = QString("%1 %2").arg(rez, l->screenReaderInfo());
1187 }
1188
1189 if (segment()) {
1190 for (Element* e : segment()->annotations()) {
1191 if (!score()->selectionFilter().canSelect(e))
1192 continue;
1193 if (e->track() == track())
1194 rez = QString("%1 %2").arg(rez, e->screenReaderInfo());
1195 }
1196
1197 SpannerMap& smap = score()->spannerMap();
1198 auto spanners = smap.findOverlapping(tick().ticks(), tick().ticks());
1199 for (auto interval : spanners) {
1200 Spanner* s = interval.value;
1201 if (!score()->selectionFilter().canSelect(s))
1202 continue;
1203 if (s->type() == ElementType::VOLTA || //voltas are added for barlines
1204 s->type() == ElementType::TIE ) //ties are added in notes
1205 continue;
1206
1207 if (s->type() == ElementType::SLUR) {
1208 if (s->tick() == tick() && s->track() == track())
1209 rez = QObject::tr("%1 Start of %2").arg(rez, s->screenReaderInfo());
1210 if (s->tick2() == tick() && s->track2() == track())
1211 rez = QObject::tr("%1 End of %2").arg(rez, s->screenReaderInfo());
1212 }
1213 else if (s->staffIdx() == staffIdx()) {
1214 bool start = s->tick() == tick();
1215 bool end = s->tick2() == tick() + ticks();
1216 if (start && end)
1217 rez = QObject::tr("%1 Start and end of %2").arg(rez, s->screenReaderInfo());
1218 else if (start)
1219 rez = QObject::tr("%1 Start of %2").arg(rez, s->screenReaderInfo());
1220 else if (end)
1221 rez = QObject::tr("%1 End of %2").arg(rez, s->screenReaderInfo());
1222 }
1223 }
1224 }
1225 return rez;
1226 }
1227
1228 //---------------------------------------------------------
1229 // isMelismaEnd
1230 // returns true if chordrest represents the end of a melisma
1231 //---------------------------------------------------------
1232
isMelismaEnd() const1233 bool ChordRest::isMelismaEnd() const
1234 {
1235 return _melismaEnd;
1236 }
1237
1238 //---------------------------------------------------------
1239 // setMelismaEnd
1240 //---------------------------------------------------------
1241
setMelismaEnd(bool v)1242 void ChordRest::setMelismaEnd(bool v)
1243 {
1244 _melismaEnd = v;
1245 // TODO: don't take "false" at face value
1246 // check to see if some other melisma ends here,
1247 // in which case we can leave this set to true
1248 // for now, rely on the fact that we'll generate the value correctly on layout
1249 }
1250
1251 //---------------------------------------------------------
1252 // shape
1253 //---------------------------------------------------------
1254
shape() const1255 Shape ChordRest::shape() const
1256 {
1257 Shape shape;
1258 {
1259 qreal x1 = 1000000.0;
1260 qreal x2 = -1000000.0;
1261 bool adjustWidth = false;
1262 for (Lyrics* l : _lyrics) {
1263 if (!l || !l->addToSkyline())
1264 continue;
1265 qreal lmargin = score()->styleS(Sid::lyricsMinDistance).val() * spatium() * 0.5;
1266 qreal rmargin = lmargin;
1267 Lyrics::Syllabic syl = l->syllabic();
1268 if ((syl == Lyrics::Syllabic::BEGIN || syl == Lyrics::Syllabic::MIDDLE) && score()->styleB(Sid::lyricsDashForce))
1269 rmargin = qMax(rmargin, styleP(Sid::lyricsDashMinLength));
1270 // for horizontal spacing we only need the lyrics width:
1271 x1 = qMin(x1, l->bbox().x() - lmargin + l->pos().x());
1272 x2 = qMax(x2, l->bbox().x() + l->bbox().width() + rmargin + l->pos().x());
1273 if (l->ticks() == Fraction::fromTicks(Lyrics::TEMP_MELISMA_TICKS))
1274 x2 += spatium();
1275 adjustWidth = true;
1276 }
1277 if (adjustWidth)
1278 shape.addHorizontalSpacing(Shape::SPACING_LYRICS, x1, x2);
1279 }
1280
1281 {
1282 qreal x1 = 1000000.0;
1283 qreal x2 = -1000000.0;
1284 bool adjustWidth = false;
1285 for (Element* e : segment()->annotations()) {
1286 if (!e || !e->addToSkyline())
1287 continue;
1288 if (e->isHarmony() && e->staffIdx() == staffIdx()) {
1289 Harmony* h = toHarmony(e);
1290 // calculate bbox only (do not reset position)
1291 h->layout1();
1292 const qreal margin = styleP(Sid::minHarmonyDistance) * 0.5;
1293 x1 = qMin(x1, e->bbox().x() - margin + e->pos().x());
1294 x2 = qMax(x2, e->bbox().x() + e->bbox().width() + margin + e->pos().x());
1295 adjustWidth = true;
1296 }
1297 }
1298 if (adjustWidth)
1299 shape.addHorizontalSpacing(Shape::SPACING_HARMONY, x1, x2);
1300 }
1301
1302 if (isMelismaEnd()) {
1303 qreal right = rightEdge();
1304 shape.addHorizontalSpacing(Shape::SPACING_LYRICS, right, right);
1305 }
1306
1307 return shape;
1308 }
1309
1310 //---------------------------------------------------------
1311 // lyrics
1312 //---------------------------------------------------------
1313
lyrics(int no,Placement p) const1314 Lyrics* ChordRest::lyrics(int no, Placement p) const
1315 {
1316 for (Lyrics* l : _lyrics) {
1317 if (l->placement() == p && l->no() == no)
1318 return l;
1319 }
1320 return 0;
1321 }
1322
1323 //---------------------------------------------------------
1324 // lastVerse
1325 // return last verse number (starting from 0)
1326 // return -1 if there are no lyrics;
1327 //---------------------------------------------------------
1328
lastVerse(Placement p) const1329 int ChordRest::lastVerse(Placement p) const
1330 {
1331 int lastVerse = -1;
1332
1333 for (Lyrics* l : _lyrics) {
1334 if (l->placement() == p && l->no() > lastVerse)
1335 lastVerse = l->no();
1336 }
1337
1338 return lastVerse;
1339 }
1340
1341 //---------------------------------------------------------
1342 // removeMarkings
1343 // - this is normally called after cloning a chord to tie a note over the barline
1344 // - there is no special undo handling; the assumption is that undo will simply remove the cloned chord
1345 // - two note tremolos are converted into simple notes
1346 // - single note tremolos are optionally retained
1347 //---------------------------------------------------------
1348
removeMarkings(bool)1349 void ChordRest::removeMarkings(bool /* keepTremolo */)
1350 {
1351 qDeleteAll(el());
1352 el().clear();
1353 qDeleteAll(lyrics());
1354 lyrics().clear();
1355 }
1356
1357 //---------------------------------------------------------
1358 // isBefore
1359 //---------------------------------------------------------
1360
isBefore(const ChordRest * o) const1361 bool ChordRest::isBefore(const ChordRest* o) const
1362 {
1363 if (!o || this == o)
1364 return true;
1365 int otick = o->tick().ticks();
1366 int t = tick().ticks();
1367 if (t == otick) { // At least one of the chord is a grace, order the grace notes
1368 bool oGraceAfter = o->isGraceAfter();
1369 bool graceAfter = isGraceAfter();
1370 bool oGrace = o->isGrace();
1371 bool grace = isGrace();
1372 // normal note are initialized at graceIndex 0 and graceIndex is 0 based
1373 int oGraceIndex = oGrace ? toChord(o)->graceIndex() + 1 : 0;
1374 int graceIndex = grace ? toChord(this)->graceIndex() + 1 : 0;
1375 if (oGrace)
1376 oGraceIndex = toChord(o->parent())->graceNotes().size() - oGraceIndex;
1377 if (grace)
1378 graceIndex = toChord(parent())->graceNotes().size() - graceIndex;
1379 otick = otick + (oGraceAfter ? 1 : -1) * oGraceIndex;
1380 t = t + (graceAfter ? 1 : -1) * graceIndex;
1381 }
1382 return t < otick;
1383 }
1384
1385 //---------------------------------------------------------
1386 // undoAddAnnotation
1387 //---------------------------------------------------------
1388
undoAddAnnotation(Element * a)1389 void ChordRest::undoAddAnnotation(Element* a)
1390 {
1391 Segment* seg = segment();
1392 Measure* m = measure();
1393 if (m && m->isMMRest())
1394 seg = m->mmRestFirst()->findSegmentR(SegmentType::ChordRest, Fraction(0,1));
1395
1396 a->setTrack(a->systemFlag() ? 0 : track());
1397 a->setParent(seg);
1398 score()->undoAddElement(a);
1399 }
1400
1401 }
1402
1403