1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2013 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 "chord.h"
14 #include "note.h"
15 #include "xml.h"
16 #include "style.h"
17 #include "segment.h"
18 #include "text.h"
19 #include "measure.h"
20 #include "system.h"
21 #include "tuplet.h"
22 #include "hook.h"
23 #include "tie.h"
24 #include "arpeggio.h"
25 #include "score.h"
26 #include "tremolo.h"
27 #include "glissando.h"
28 #include "staff.h"
29 #include "part.h"
30 #include "utils.h"
31 #include "articulation.h"
32 #include "undo.h"
33 #include "chordline.h"
34 #include "lyrics.h"
35 #include "navigate.h"
36 #include "stafftype.h"
37 #include "stem.h"
38 #include "mscore.h"
39 #include "accidental.h"
40 #include "noteevent.h"
41 #include "pitchspelling.h"
42 #include "stemslash.h"
43 #include "ledgerline.h"
44 #include "drumset.h"
45 #include "key.h"
46 #include "sym.h"
47 #include "stringdata.h"
48 #include "beam.h"
49 #include "slur.h"
50 #include "fingering.h"
51
52 namespace Ms {
53
54 //---------------------------------------------------------
55 // LedgerLineData
56 //---------------------------------------------------------
57
58 struct LedgerLineData {
59 int line;
60 qreal minX, maxX;
61 bool visible;
62 bool accidental;
63 };
64
65 //---------------------------------------------------------
66 // upNote
67 //---------------------------------------------------------
68
upNote() const69 Note* Chord::upNote() const
70 {
71 Q_ASSERT(!_notes.empty());
72
73 Note* result = _notes.back();
74 const Staff* stf = staff();
75 if (!stf)
76 return result;
77
78 const StaffType* st = stf->staffTypeForElement(this);
79 if (st->isDrumStaff()) {
80 for (Note* n : _notes) {
81 if (n->line() < result->line()) {
82 result = n;
83 }
84 }
85 }
86 else if (st->isTabStaff()) {
87 int line = st->lines() - 1; // start at bottom line
88 int noteLine;
89 // scan each note: if TAB strings are not in sequential order,
90 // visual order of notes might not correspond to pitch order
91 for (Note* n : _notes) {
92 noteLine = st->physStringToVisual(n->string());
93 if (noteLine < line) {
94 line = noteLine;
95 result = n;
96 }
97 }
98 }
99 return result;
100 }
101
102 //---------------------------------------------------------
103 // downNote
104 //---------------------------------------------------------
105
downNote() const106 Note* Chord::downNote() const
107 {
108 Q_ASSERT(!_notes.empty());
109
110 Note* result = _notes.front();
111 const Staff* stf = staff();
112 if (!stf)
113 return result;
114
115 const StaffType* st = stf->staffTypeForElement(this);
116 if (st->isDrumStaff()) {
117 for (Note* n : _notes) {
118 if (n->line() > result->line()) {
119 result = n;
120 }
121 }
122 }
123 else if (st->isTabStaff()) {
124 int line = 0; // start at top line
125 int noteLine;
126 // scan each note: if TAB strings are not in sequential order,
127 // visual order of notes might not correspond to pitch order
128 for (Note* n : _notes) {
129 noteLine = st->physStringToVisual(n->string());
130 if (noteLine > line) {
131 line = noteLine;
132 result = n;
133 }
134 }
135 }
136 return result;
137 }
138
139 //---------------------------------------------------------
140 // upLine / downLine
141 //---------------------------------------------------------
142
upLine() const143 int Chord::upLine() const
144 {
145 return onTabStaff() ? upString()*2 : upNote()->line();
146 }
147
downLine() const148 int Chord::downLine() const
149 {
150 return onTabStaff() ? downString()*2 : downNote()->line();
151 }
152
153 //---------------------------------------------------------
154 // upString / downString
155 //
156 // return the topmost / bottommost string used by chord
157 // Top and bottom refer to the DRAWN position, not the position in the instrument
158 // (i.e., upside-down TAB are taken into account)
159 //
160 // If no staff, always return 0
161 // If staf is not a TAB, always returns TOP and BOTTOM staff lines
162 //---------------------------------------------------------
163
upString() const164 int Chord::upString() const
165 {
166 // if no staff or staff not a TAB, return 0 (=topmost line)
167 const Staff* st = staff();
168 if (!st)
169 return 0;
170
171 const StaffType* tab = st->staffTypeForElement(this);
172 if (!tab->isTabStaff())
173 return 0;
174
175 int line = tab->lines() - 1; // start at bottom line
176 int noteLine;
177 // scan each note: if TAB strings are not in sequential order,
178 // visual order of notes might not correspond to pitch order
179 size_t n = _notes.size();
180 for (size_t i = 0; i < n; ++i) {
181 noteLine = tab->physStringToVisual(_notes.at(i)->string());
182 if (noteLine < line)
183 line = noteLine;
184 }
185 return line;
186 }
187
downString() const188 int Chord::downString() const
189 {
190 const Staff* st = staff();
191 if (!st) // if no staff, return 0
192 return 0;
193
194 const StaffType* tab = st->staffTypeForElement(this);
195 if (!tab->isTabStaff()) // if staff not a TAB, return bottom line
196 return st->lines(tick())-1;
197
198 int line = 0; // start at top line
199 int noteLine;
200 size_t n = _notes.size();
201 for (size_t i = 0; i < n; ++i) {
202 noteLine = tab->physStringToVisual(_notes.at(i)->string());
203 if (noteLine > line)
204 line = noteLine;
205 }
206 return line;
207 }
208
209 //---------------------------------------------------------
210 // Chord
211 //---------------------------------------------------------
212
Chord(Score * s)213 Chord::Chord(Score* s)
214 : ChordRest(s)
215 {
216 _ledgerLines = 0;
217 _stem = 0;
218 _hook = 0;
219 _stemDirection = Direction::AUTO;
220 _arpeggio = 0;
221 _tremolo = 0;
222 _endsGlissando = false;
223 _noteType = NoteType::NORMAL;
224 _stemSlash = 0;
225 _noStem = false;
226 _playEventType = PlayEventType::Auto;
227 _spaceLw = 0.;
228 _spaceRw = 0.;
229 _crossMeasure = CrossMeasure::UNKNOWN;
230 _graceIndex = 0;
231 }
232
Chord(const Chord & c,bool link)233 Chord::Chord(const Chord& c, bool link)
234 : ChordRest(c, link)
235 {
236 if (link)
237 score()->undo(new Link(this, const_cast<Chord*>(&c)));
238 _ledgerLines = 0;
239
240 for (Note* onote : c._notes) {
241 Note* nnote = new Note(*onote, link);
242 add(nnote);
243 }
244 for (Chord* gn : c.graceNotes()) {
245 Chord* nc = new Chord(*gn, link);
246 add(nc);
247 }
248 for (Articulation* a : c._articulations) { // make deep copy
249 Articulation* na = new Articulation(*a);
250 if (link)
251 na->linkTo(a);
252 na->setParent(this);
253 na->setTrack(track());
254 _articulations.append(na);
255 }
256 _stem = 0;
257 _hook = 0;
258 _endsGlissando = false;
259 _arpeggio = 0;
260 _stemSlash = 0;
261 _tremolo = 0;
262
263 _graceIndex = c._graceIndex;
264 _noStem = c._noStem;
265 _playEventType = c._playEventType;
266 _stemDirection = c._stemDirection;
267 _noteType = c._noteType;
268 _crossMeasure = CrossMeasure::UNKNOWN;
269
270 if (c._stem)
271 add(new Stem(*(c._stem)));
272 if (c._hook)
273 add(new Hook(*(c._hook)));
274 if (c._stemSlash)
275 add(new StemSlash(*(c._stemSlash)));
276 if (c._arpeggio) {
277 Arpeggio* a = new Arpeggio(*(c._arpeggio));
278 add(a);
279 if (link)
280 score()->undo(new Link(a, const_cast<Arpeggio*>(c._arpeggio)));
281 }
282 if (c._tremolo) {
283 Tremolo* t = new Tremolo(*(c._tremolo));
284 if (link)
285 score()->undo(new Link(t, const_cast<Tremolo*>(c._tremolo)));
286 if (c._tremolo->twoNotes()) {
287 if (c._tremolo->chord1() == &c)
288 t->setChords(this, nullptr);
289 else
290 t->setChords(nullptr, this);
291 }
292 add(t);
293 }
294
295 for (Element* e : c.el()) {
296 if (e->isChordLine()) {
297 ChordLine* cl = toChordLine(e);
298 ChordLine* ncl = new ChordLine(*cl);
299 add(ncl);
300 if (link)
301 score()->undo(new Link(ncl, cl));
302 }
303 }
304 }
305
306 //---------------------------------------------------------
307 // undoUnlink
308 //---------------------------------------------------------
309
undoUnlink()310 void Chord::undoUnlink()
311 {
312 ChordRest::undoUnlink();
313 for (Note* n : _notes)
314 n->undoUnlink();
315 for (Chord* gn : graceNotes())
316 gn->undoUnlink();
317 for (Articulation* a : qAsConst(_articulations))
318 a->undoUnlink();
319 /* if (_glissando)
320 _glissando->undoUnlink(); */
321 if (_arpeggio)
322 _arpeggio->undoUnlink();
323 if (_tremolo && !_tremolo->twoNotes())
324 _tremolo->undoUnlink();
325
326 for (Element* e : el()) {
327 if (e->type() == ElementType::CHORDLINE)
328 e->undoUnlink();
329 }
330 }
331
332 //---------------------------------------------------------
333 // ~Chord
334 //---------------------------------------------------------
335
~Chord()336 Chord::~Chord()
337 {
338 qDeleteAll(_articulations);
339 delete _arpeggio;
340 if (_tremolo) {
341 if (_tremolo->chord1() == this) {
342 Tremolo* tremoloPointer = _tremolo; // setTremolo(0) loses reference to the current pointer
343 if (_tremolo->chord2())
344 _tremolo->chord2()->setTremolo(0);
345 delete tremoloPointer;
346 }
347 else if (!(_tremolo->chord1())) // delete orphaned tremolo
348 delete _tremolo;
349 }
350 delete _stemSlash;
351 delete _stem;
352 delete _hook;
353 for (LedgerLine* ll = _ledgerLines; ll;) {
354 LedgerLine* llNext = ll->next();
355 delete ll;
356 ll = llNext;
357 }
358 qDeleteAll(_graceNotes);
359 qDeleteAll(_notes);
360 }
361
362 //---------------------------------------------------------
363 // noteHeadWidth
364 //---------------------------------------------------------
365
noteHeadWidth() const366 qreal Chord::noteHeadWidth() const
367 {
368 qreal nhw = score()->noteHeadWidth();
369 if (_noteType != NoteType::NORMAL)
370 nhw *= score()->styleD(Sid::graceNoteMag);
371 return nhw * mag();
372 }
373
374 //---------------------------------------------------------
375 // stemPosX
376 // return Chord coordinates. Based on nominal notehead
377 //---------------------------------------------------------
378
stemPosX() const379 qreal Chord::stemPosX() const
380 {
381 const Staff* stf = staff();
382 const StaffType* st = stf ? stf->staffTypeForElement(this) : 0;
383 if (st && st->isTabStaff())
384 return st->chordStemPosX(this) * spatium();
385 return _up ? noteHeadWidth() : 0.0;
386 }
387
388 //---------------------------------------------------------
389 // stemPos
390 // return page coordinates
391 //---------------------------------------------------------
392
stemPos() const393 QPointF Chord::stemPos() const
394 {
395 QPointF p(pagePos());
396
397 const Staff* stf = staff();
398 const StaffType* st = stf ? stf->staffTypeForElement(this) : 0;
399 if (st && st->isTabStaff())
400 return st->chordStemPos(this) * spatium() + p;
401
402 if (_up) {
403 qreal nhw = _notes.size() == 1 ? downNote()->bboxRightPos() : noteHeadWidth();
404 p.rx() += nhw;
405 p.ry() += downNote()->pos().y();
406 }
407 else
408 p.ry() += upNote()->pos().y();
409 return p;
410 }
411
412 //---------------------------------------------------------
413 // stemPosBeam
414 // return stem position of note on beam side
415 // return page coordinates
416 //---------------------------------------------------------
417
stemPosBeam() const418 QPointF Chord::stemPosBeam() const
419 {
420 qreal _spatium = spatium();
421 QPointF p(pagePos());
422
423 const Staff* stf = staff();
424 const StaffType* st = stf ? stf->staffTypeForElement(this) : 0;
425
426 if (st && st->isTabStaff())
427 return st->chordStemPosBeam(this) * _spatium + p;
428
429 if (_up) {
430 qreal nhw = noteHeadWidth();
431 p.rx() += nhw;
432 p.ry() += upNote()->pos().y();
433 }
434 else
435 p.ry() += downNote()->pos().y();
436
437 return p;
438 }
439
440 //---------------------------------------------------------
441 // rightEdge
442 //---------------------------------------------------------
443
rightEdge() const444 qreal Chord::rightEdge() const
445 {
446 qreal right = 0.0;
447 for (Note* n : notes())
448 right = qMax(right, x() + n->x() + n->bboxRightPos());
449 return right;
450 }
451
452 //---------------------------------------------------------
453 // setTremolo
454 //---------------------------------------------------------
455
setTremolo(Tremolo * tr)456 void Chord::setTremolo(Tremolo* tr)
457 {
458 if (_tremolo && tr && tr == _tremolo)
459 return;
460
461 if (_tremolo) {
462 if (_tremolo->twoNotes()) {
463 TDuration d;
464 const Fraction f = ticks();
465 if (f.numerator() > 0)
466 d = TDuration(f);
467 else {
468 d = _tremolo->durationType();
469 const int dots = d.dots();
470 d = d.shift(1);
471 d.setDots(dots);
472 }
473
474 setDurationType(d);
475 Chord* other = _tremolo->chord1() == this ? _tremolo->chord2() : _tremolo->chord1();
476 _tremolo = nullptr;
477 if (other)
478 other->setTremolo(nullptr);
479 }
480 else
481 _tremolo = nullptr;
482 }
483
484 if (tr) {
485 if (tr->twoNotes()) {
486 TDuration d = tr->durationType();
487 if (!d.isValid()) {
488 d = durationType();
489 const int dots = d.dots();
490 d = d.shift(-1);
491 d.setDots(dots);
492 tr->setDurationType(d);
493 }
494
495 setDurationType(d);
496 Chord* other = tr->chord1() == this ? tr->chord2() : tr->chord1();
497 _tremolo = tr;
498 if (other)
499 other->setTremolo(tr);
500 }
501 else
502 _tremolo = tr;
503 }
504 else {
505 _tremolo = nullptr;
506 }
507 }
508
509 //---------------------------------------------------------
510 // add
511 //---------------------------------------------------------
512
add(Element * e)513 void Chord::add(Element* e)
514 {
515 e->setParent(this);
516 e->setTrack(track());
517 switch(e->type()) {
518 case ElementType::NOTE:
519 {
520 Note* note = toNote(e);
521 bool found = false;
522
523 // _notes should be sorted by line position,
524 // but it's often not yet possible since line is unknown
525 // use pitch instead, and line as a second sort criteria.
526
527 for (unsigned idx = 0; idx < _notes.size(); ++idx) {
528 if (note->pitch() <= _notes[idx]->pitch()) {
529 if (note->pitch() == _notes[idx]->pitch() && note->line() >= _notes[idx]->line())
530 _notes.insert(_notes.begin()+idx+1, note);
531 else
532 _notes.insert(_notes.begin()+idx, note);
533 found = true;
534 break;
535 }
536 }
537 if (!found)
538 _notes.push_back(note);
539 note->connectTiedNotes();
540 if (voice() && measure() && note->visible())
541 measure()->setHasVoices(staffIdx(), true);
542 }
543 score()->setPlaylistDirty();
544 break;
545 case ElementType::ARPEGGIO:
546 _arpeggio = toArpeggio(e);
547 break;
548 case ElementType::TREMOLO:
549 setTremolo(toTremolo(e));
550 break;
551 case ElementType::GLISSANDO:
552 _endsGlissando = true;
553 break;
554 case ElementType::STEM:
555 Q_ASSERT(!_stem);
556 _stem = toStem(e);
557 break;
558 case ElementType::HOOK:
559 _hook = toHook(e);
560 break;
561 case ElementType::CHORDLINE:
562 el().push_back(e);
563 break;
564 case ElementType::STEM_SLASH:
565 Q_ASSERT(!_stemSlash);
566 _stemSlash = toStemSlash(e);
567 break;
568 case ElementType::CHORD:
569 {
570 Chord* gc = toChord(e);
571 Q_ASSERT(gc->noteType() != NoteType::NORMAL);
572 int idx = gc->graceIndex();
573 gc->setFlag(ElementFlag::MOVABLE, true);
574 _graceNotes.insert(_graceNotes.begin() + idx, gc);
575 }
576 break;
577 case ElementType::LEDGER_LINE:
578 qFatal("Chord::add ledgerline");
579 break;
580 case ElementType::ARTICULATION:
581 {
582 Articulation* a = toArticulation(e);
583 if (a->layoutCloseToNote()) {
584 auto i = _articulations.begin();
585 while (i != _articulations.end() && (*i)->layoutCloseToNote())
586 i++;
587 _articulations.insert(i, a);
588 }
589 else
590 _articulations.push_back(a);
591 }
592 break;
593 default:
594 ChordRest::add(e);
595 break;
596 }
597 }
598
599 //---------------------------------------------------------
600 // remove
601 //---------------------------------------------------------
602
remove(Element * e)603 void Chord::remove(Element* e)
604 {
605 if (!e)
606 return;
607
608 switch (e->type()) {
609 case ElementType::NOTE:
610 {
611 Note* note = toNote(e);
612 auto i = std::find(_notes.begin(), _notes.end(), note);
613 if (i != _notes.end()) {
614 _notes.erase(i);
615 note->disconnectTiedNotes();
616 for (Spanner* s : note->spannerBack())
617 note->removeSpannerBack(s);
618 for (Spanner* s : note->spannerFor())
619 note->removeSpannerFor(s);
620 }
621 else
622 qDebug("Chord::remove() note %p not found!", e);
623 if (voice() && measure() && note->visible())
624 measure()->checkMultiVoices(staffIdx());
625 score()->setPlaylistDirty();
626 }
627 break;
628
629 case ElementType::ARPEGGIO:
630 _arpeggio = 0;
631 break;
632 case ElementType::TREMOLO:
633 setTremolo(nullptr);
634 break;
635 case ElementType::GLISSANDO:
636 _endsGlissando = false;
637 break;
638 case ElementType::STEM:
639 _stem = 0;
640 break;
641 case ElementType::HOOK:
642 _hook = 0;
643 break;
644 case ElementType::STEM_SLASH:
645 Q_ASSERT(_stemSlash);
646 if (_stemSlash->selected() && score())
647 score()->deselect(_stemSlash);
648 _stemSlash = 0;
649 break;
650 case ElementType::CHORDLINE:
651 el().remove(e);
652 break;
653 case ElementType::CHORD:
654 {
655 auto i = std::find(_graceNotes.begin(), _graceNotes.end(), toChord(e));
656 Chord* grace = *i;
657 grace->setGraceIndex(i - _graceNotes.begin());
658 _graceNotes.erase(i);
659 }
660 break;
661 case ElementType::ARTICULATION:
662 {
663 Articulation* a = toArticulation(e);
664 if (!_articulations.removeOne(a))
665 qDebug("ChordRest::remove(): articulation not found");
666 }
667 break;
668 default:
669 ChordRest::remove(e);
670 break;
671 }
672 }
673
674 //---------------------------------------------------------
675 // maxHeadWidth
676 //---------------------------------------------------------
677
maxHeadWidth() const678 qreal Chord::maxHeadWidth() const
679 {
680 // determine max head width in chord
681 qreal hw = 0;
682 for (const Note* n : _notes) {
683 qreal t = n->headWidth();
684 if (t > hw)
685 hw = t;
686 }
687 return hw;
688 }
689
690 //---------------------------------------------------------
691 // addLedgerLines
692 //---------------------------------------------------------
693
addLedgerLines()694 void Chord::addLedgerLines()
695 {
696 // initialize for palette
697 int track = 0; // the track lines belong to
698 // the line pos corresponding to the bottom line of the staff
699 int lineBelow = 8; // assuming 5-lined "staff"
700 qreal lineDistance = 1;
701 qreal mag = 1;
702 bool staffVisible = true;
703 int stepOffset = 0; // for staff type changes with a step offset
704
705 if (segment()) { //not palette
706 Fraction tick = segment()->tick();
707 int idx = staffIdx() + staffMove();
708 track = staff2track(idx);
709 Staff* st = score()->staff(idx);
710 lineBelow = (st->lines(tick) - 1) * 2;
711 lineDistance = st->lineDistance(tick);
712 mag = staff()->mag(tick);
713 staffVisible = !staff()->invisible(tick);
714 stepOffset = st->staffType(tick)->stepOffset();
715 }
716
717 // need ledger lines?
718 if (downLine() + stepOffset <= lineBelow + 1 && upLine() + stepOffset >= -1)
719 return;
720
721 // the extra length of a ledger line with respect to notehead (half of it on each side)
722 qreal extraLen = score()->styleP(Sid::ledgerLineLength) * mag;
723 qreal hw;
724 qreal minX, maxX; // note extrema in raster units
725 int minLine, maxLine;
726 bool visible = false;
727 qreal x;
728
729 // scan chord notes, collecting visibility and x and y extrema
730 // NOTE: notes are sorted from bottom to top (line no. decreasing)
731 // notes are scanned twice from outside (bottom or top) toward the staff
732 // each pass stops at the first note without ledger lines
733 size_t n = _notes.size();
734 for (size_t j = 0; j < 2; j++) { // notes are scanned twice...
735 int from, delta;
736 std::vector<LedgerLineData> vecLines;
737 hw = 0.0;
738 minX = maxX = 0;
739 minLine = 0;
740 maxLine = lineBelow;
741 if (j == 0) { // ...once from lowest up...
742 from = 0;
743 delta = +1;
744 }
745 else {
746 from = int(n)-1; // ...once from highest down
747 delta = -1;
748 }
749 for (int i = from; i < int(n) && i >= 0 ; i += delta) {
750 Note* note = _notes.at(i);
751 int l = note->line() + stepOffset;
752
753 // if 1st pass and note not below staff or 2nd pass and note not above staff
754 if ((!j && l <= lineBelow + 1) || (j && l >= -1))
755 break; // stop this pass
756 // round line number to even number toward 0
757 if (l < 0)
758 l = (l + 1) & ~ 1;
759 else
760 l = l & ~ 1;
761
762 if (note->visible()) // if one note is visible,
763 visible = true; // all lines between it and the staff are visible
764 hw = qMax(hw, note->headWidth());
765
766 //
767 // Experimental:
768 // shorten ledger line to avoid collisions with accidentals
769 //
770 // bool accid = (note->accidental() && note->line() >= (l-1) && note->line() <= (l+1) );
771 //
772 // TODO : do something with this accid flag in the following code!
773 //
774
775 // check if note horiz. pos. is outside current range
776 // if more length on the right, increase range
777 // note->layout();
778
779 //ledger lines need the leftmost point of the notehead with a respect of bbox
780 x = note->pos().x() + note->bboxXShift();
781 if (x - extraLen < minX) {
782 minX = x - extraLen;
783 // increase width of all lines between this one and the staff
784 for (auto& d : vecLines) {
785 if (!d.accidental && ((l < 0 && d.line >= l) || (l > 0 && d.line <= l)) )
786 d.minX = minX ;
787 }
788 }
789 // same for left side
790 if (x + hw + extraLen > maxX) {
791 maxX = x + hw + extraLen;
792 for (auto& d : vecLines)
793 if ( (l < 0 && d.line >= l) || (l > 0 && d.line <= l) )
794 d.maxX = maxX;
795 }
796
797 LedgerLineData lld;
798 // check if note vert. pos. is outside current range
799 // and, if so, add data for new line(s)
800 if (l < minLine) {
801 for (int i1 = l; i1 < minLine; i1 += 2) {
802 lld.line = i1;
803 lld.minX = minX;
804 lld.maxX = maxX;
805 lld.visible = visible;
806 lld.accidental = false;
807 vecLines.push_back(lld);
808 }
809 minLine = l;
810 }
811 if (l > maxLine) {
812 for (int i1 = maxLine+2; i1 <= l; i1 += 2) {
813 lld.line = i1;
814 lld.minX = minX;
815 lld.maxX = maxX;
816 lld.visible = visible;
817 lld.accidental = false;
818 vecLines.push_back(lld);
819 }
820 maxLine = l;
821 }
822 }
823 if (minLine < 0 || maxLine > lineBelow) {
824 qreal _spatium = spatium();
825 qreal stepDistance = lineDistance * 0.5;
826 for (auto lld : vecLines) {
827 LedgerLine* h = new LedgerLine(score());
828 h->setParent(this);
829 h->setTrack(track);
830 h->setVisible(lld.visible && staffVisible);
831 h->setLen(lld.maxX - lld.minX);
832 h->setPos(lld.minX, lld.line * _spatium * stepDistance);
833 h->setNext(_ledgerLines);
834 _ledgerLines = h;
835 }
836 }
837 }
838 for (LedgerLine* ll = _ledgerLines; ll; ll = ll->next())
839 ll->layout();
840 }
841
842 //-----------------------------------------------------------------------------
843 // computeUp
844 // rules:
845 // single note:
846 // All notes beneath the middle line: upward stems
847 // All notes on or above the middle line: downward stems
848 // two notes:
849 // If the interval above the middle line is greater than the interval
850 // below the middle line: downward stems
851 // If the interval below the middle line is greater than the interval
852 // above the middle line: upward stems
853 // If the two notes are the same distance from the middle line:
854 // stem can go in either direction. but most engravers prefer
855 // downward stems
856 // > two notes:
857 // If the interval of the highest note above the middle line is greater
858 // than the interval of the lowest note below the middle line:
859 // downward stems
860 // If the interval of the lowest note below the middle line is greater
861 // than the interval of the highest note above the middle line:
862 // upward stem
863 // If the highest and the lowest notes are the same distance from
864 // the middle line:, use these rules to determine stem direction:
865 // - If the majority of the notes are above the middle:
866 // downward stems
867 // - If the majority of the notes are below the middle:
868 // upward stems
869 // TABlatures:
870 // stems beside staves:
871 // All stems are up / down according to TAB::stemsDown() setting
872 // stems through staves:
873 // Same rules as per pitched staves
874 //-----------------------------------------------------------------------------
875
computeUp()876 void Chord::computeUp()
877 {
878 Q_ASSERT(!_notes.empty());
879 const Staff* st = staff();
880 const StaffType* tab = st ? st->staffTypeForElement(this) : 0;
881 bool tabStaff = tab && tab->isTabStaff();
882 // TAB STAVES
883 if (tabStaff) {
884 // if no stems or stem beside staves
885 if (tab->stemless() || !tab->stemThrough()) {
886 // if measure has voices, set stem direction according to voice
887 if (measure()->hasVoices(staffIdx(), tick(), actualTicks()))
888 _up = !(track() % 2);
889 else // if only voice 1,
890 // unconditionally set to down if not stems or according to TAB stem direction otherwise
891 // (even with no stems, stem direction controls position of slurs and ties)
892 _up = tab->stemless() ? false : !tab->stemsDown();
893 return;
894 }
895 // if TAB has stems through staves, chain into standard processing
896 }
897
898 // PITCHED STAVES (or TAB with stems through staves)
899 if (_stemDirection != Direction::AUTO)
900 _up = _stemDirection == Direction::UP;
901 else if (!parent())
902 // hack for palette and drumset editor
903 _up = upNote()->line() > 4;
904 else if (_noteType != NoteType::NORMAL) {
905 //
906 // stem direction for grace notes
907 //
908 if (measure()->hasVoices(staffIdx(), tick(), actualTicks()))
909 _up = !(track() % 2);
910 else
911 _up = true;
912 }
913 else if (staffMove())
914 _up = staffMove() > 0;
915 else if (measure()->hasVoices(staffIdx(), tick(), actualTicks()))
916 _up = !(track() % 2);
917 else {
918 int dnMaxLine = staff()->middleLine(tick());
919 int ud = (tabStaff ? upString() * 2 : upNote()->line() ) - dnMaxLine;
920 // standard case: if only 1 note or cross beaming
921 if (_notes.size() == 1 || staffMove()) {
922 if (staffMove() > 0)
923 _up = true;
924 else if (staffMove() < 0)
925 _up = false;
926 else
927 _up = ud > 0;
928 }
929 // if more than 1 note, compare extrema (topmost and bottommost notes)
930 else {
931 int dd = (tabStaff ? downString() * 2 : downNote()->line() ) - dnMaxLine;
932 // if extrema symmetrical, average directions of intermediate notes
933 if (-ud == dd) {
934 int up = 0;
935 size_t n = _notes.size();
936 for (size_t i = 0; i < n; ++i) {
937 const Note* currentNote = _notes.at(i);
938 int l = tabStaff ? currentNote->string() * 2 : currentNote->line();
939 if (l <= dnMaxLine)
940 --up;
941 else
942 ++up;
943 }
944 _up = up > 0;
945 }
946 // if extrema not symmetrical, set _up to prevailing
947 else
948 _up = dd > -ud;
949 }
950 }
951 }
952
953 //---------------------------------------------------------
954 // selectedNote
955 //---------------------------------------------------------
956
selectedNote() const957 Note* Chord::selectedNote() const
958 {
959 Note* note = 0;
960 size_t n = _notes.size();
961 for (size_t i = 0; i < n; ++i) {
962 Note* currentNote = _notes.at(i);
963 if (currentNote->selected()) {
964 if (note)
965 return 0;
966 note = currentNote;
967 }
968 }
969 return note;
970 }
971
972 //---------------------------------------------------------
973 // Chord::write
974 //---------------------------------------------------------
975
write(XmlWriter & xml) const976 void Chord::write(XmlWriter& xml) const
977 {
978 for (Chord* c : _graceNotes) {
979 c->write(xml);
980 }
981 writeBeam(xml);
982 xml.stag(this);
983 ChordRest::writeProperties(xml);
984 for (const Articulation* a : _articulations)
985 a->write(xml);
986 switch (_noteType) {
987 case NoteType::NORMAL:
988 break;
989 case NoteType::ACCIACCATURA:
990 xml.tagE("acciaccatura");
991 break;
992 case NoteType::APPOGGIATURA:
993 xml.tagE("appoggiatura");
994 break;
995 case NoteType::GRACE4:
996 xml.tagE("grace4");
997 break;
998 case NoteType::GRACE16:
999 xml.tagE("grace16");
1000 break;
1001 case NoteType::GRACE32:
1002 xml.tagE("grace32");
1003 break;
1004 case NoteType::GRACE8_AFTER:
1005 xml.tagE("grace8after");
1006 break;
1007 case NoteType::GRACE16_AFTER:
1008 xml.tagE("grace16after");
1009 break;
1010 case NoteType::GRACE32_AFTER:
1011 xml.tagE("grace32after");
1012 break;
1013 default:
1014 break;
1015 }
1016
1017 if (_noStem)
1018 xml.tag("noStem", _noStem);
1019 else if (_stem && (_stem->isUserModified() || (_stem->userLen() != 0.0)))
1020 _stem->write(xml);
1021 if (_hook && _hook->isUserModified())
1022 _hook->write(xml);
1023 if (_stemSlash && _stemSlash->isUserModified())
1024 _stemSlash->write(xml);
1025 writeProperty(xml, Pid::STEM_DIRECTION);
1026 for (Note* n : _notes)
1027 n->write(xml);
1028 if (_arpeggio)
1029 _arpeggio->write(xml);
1030 if (_tremolo && tremoloChordType() != TremoloChordType::TremoloSecondNote)
1031 _tremolo->write(xml);
1032 for (Element* e : el())
1033 e->write(xml);
1034 xml.etag();
1035 }
1036
1037 //---------------------------------------------------------
1038 // Chord::read
1039 //---------------------------------------------------------
1040
read(XmlReader & e)1041 void Chord::read(XmlReader& e)
1042 {
1043 while (e.readNextStartElement()) {
1044 if (readProperties(e))
1045 ;
1046 else
1047 e.unknown();
1048 }
1049 }
1050
1051 //---------------------------------------------------------
1052 // readProperties
1053 //---------------------------------------------------------
1054
readProperties(XmlReader & e)1055 bool Chord::readProperties(XmlReader& e)
1056 {
1057 const QStringRef& tag(e.name());
1058
1059 if (tag == "Note") {
1060 Note* note = new Note(score());
1061 // the note needs to know the properties of the track it belongs to
1062 note->setTrack(track());
1063 note->setChord(this);
1064 note->read(e);
1065 add(note);
1066 }
1067 else if (ChordRest::readProperties(e))
1068 ;
1069 else if (tag == "Stem") {
1070 Stem* s = new Stem(score());
1071 s->read(e);
1072 add(s);
1073 }
1074 else if (tag == "Hook") {
1075 _hook = new Hook(score());
1076 _hook->read(e);
1077 add(_hook);
1078 }
1079 else if (tag == "appoggiatura") {
1080 _noteType = NoteType::APPOGGIATURA;
1081 e.readNext();
1082 }
1083 else if (tag == "acciaccatura") {
1084 _noteType = NoteType::ACCIACCATURA;
1085 e.readNext();
1086 }
1087 else if (tag == "grace4") {
1088 _noteType = NoteType::GRACE4;
1089 e.readNext();
1090 }
1091 else if (tag == "grace16") {
1092 _noteType = NoteType::GRACE16;
1093 e.readNext();
1094 }
1095 else if (tag == "grace32") {
1096 _noteType = NoteType::GRACE32;
1097 e.readNext();
1098 }
1099 else if (tag == "grace8after") {
1100 _noteType = NoteType::GRACE8_AFTER;
1101 e.readNext();
1102 }
1103 else if (tag == "grace16after") {
1104 _noteType = NoteType::GRACE16_AFTER;
1105 e.readNext();
1106 }
1107 else if (tag == "grace32after") {
1108 _noteType = NoteType::GRACE32_AFTER;
1109 e.readNext();
1110 }
1111 else if (tag == "StemSlash") {
1112 StemSlash* ss = new StemSlash(score());
1113 ss->read(e);
1114 add(ss);
1115 }
1116 else if (readProperty(tag, e, Pid::STEM_DIRECTION))
1117 ;
1118 else if (tag == "noStem")
1119 _noStem = e.readInt();
1120 else if (tag == "Arpeggio") {
1121 _arpeggio = new Arpeggio(score());
1122 _arpeggio->setTrack(track());
1123 _arpeggio->read(e);
1124 _arpeggio->setParent(this);
1125 }
1126 else if (tag == "Tremolo") {
1127 _tremolo = new Tremolo(score());
1128 _tremolo->setTrack(track());
1129 _tremolo->read(e);
1130 _tremolo->setParent(this);
1131 _tremolo->setDurationType(durationType());
1132 }
1133 else if (tag == "tickOffset") // obsolete
1134 ;
1135 else if (tag == "ChordLine") {
1136 ChordLine* cl = new ChordLine(score());
1137 cl->read(e);
1138 add(cl);
1139 }
1140 else
1141 return false;
1142 return true;
1143 }
1144
1145 //---------------------------------------------------------
1146 // upPos
1147 //---------------------------------------------------------
1148
upPos() const1149 qreal Chord::upPos() const
1150 {
1151 return upNote()->pos().y();
1152 }
1153
1154 //---------------------------------------------------------
1155 // downPos
1156 //---------------------------------------------------------
1157
downPos() const1158 qreal Chord::downPos() const
1159 {
1160 return downNote()->pos().y();
1161 }
1162
1163 //---------------------------------------------------------
1164 // centerX
1165 // return x position for attributes
1166 //---------------------------------------------------------
1167
centerX() const1168 qreal Chord::centerX() const
1169 {
1170 // TAB 'notes' are always centered on the stem
1171 const Staff* st = staff();
1172 const StaffType* stt = st->staffTypeForElement(this);
1173 if (stt->isTabStaff())
1174 return stt->chordStemPosX(this) * spatium();
1175
1176 const Note* note = up() ? upNote() : downNote();
1177 qreal x = note->pos().x() + note->noteheadCenterX();
1178 if (note->mirror())
1179 x += (note->headBodyWidth()) * (up() ? -1.0 : 1.0);
1180 return x;
1181 }
1182
1183 //---------------------------------------------------------
1184 // scanElements
1185 //---------------------------------------------------------
1186
scanElements(void * data,void (* func)(void *,Element *),bool all)1187 void Chord::scanElements(void* data, void (*func)(void*, Element*), bool all)
1188 {
1189 for (Articulation* a : qAsConst(_articulations))
1190 func(data, a);
1191 if (_hook)
1192 func(data, _hook );
1193 if (_stem)
1194 func(data, _stem);
1195 if (_stemSlash)
1196 func(data, _stemSlash);
1197 if (_arpeggio)
1198 func(data, _arpeggio);
1199 if (_tremolo && (tremoloChordType() != TremoloChordType::TremoloSecondNote))
1200 func(data, _tremolo);
1201 const Staff* st = staff();
1202 if ((st && st->showLedgerLines(tick())) || !st) // also for palette
1203 for (LedgerLine* ll = _ledgerLines; ll; ll = ll->next())
1204 func(data, ll);
1205 size_t n = _notes.size();
1206 for (size_t i = 0; i < n; ++i)
1207 _notes.at(i)->scanElements(data, func, all);
1208 for (Chord* chord : qAsConst(_graceNotes))
1209 chord->scanElements(data, func, all);
1210 for (Element* e : el())
1211 e->scanElements(data, func, all);
1212 ChordRest::scanElements(data, func, all);
1213 }
1214
1215 //---------------------------------------------------------
1216 // processSiblings
1217 //---------------------------------------------------------
1218
processSiblings(std::function<void (Element *)> func) const1219 void Chord::processSiblings(std::function<void(Element*)> func) const
1220 {
1221 if (_hook)
1222 func(_hook);
1223 if (_stem)
1224 func(_stem);
1225 if (_stemSlash)
1226 func(_stemSlash);
1227 if (_arpeggio)
1228 func(_arpeggio);
1229 if (_tremolo)
1230 func(_tremolo);
1231 for (LedgerLine* ll = _ledgerLines; ll; ll = ll->next())
1232 func(ll);
1233 for (Articulation* a : _articulations)
1234 func(a);
1235 for (Note* note : _notes)
1236 func(note);
1237 for (Element* e : el())
1238 func(e);
1239 for (Chord* chord : _graceNotes) // process grace notes last, needed for correct shape calculation
1240 func(chord);
1241 }
1242
1243 //---------------------------------------------------------
1244 // setTrack
1245 //---------------------------------------------------------
1246
setTrack(int val)1247 void Chord::setTrack(int val)
1248 {
1249 ChordRest::setTrack(val);
1250 processSiblings([val] (Element* e) { e->setTrack(val); } );
1251 }
1252
1253 //---------------------------------------------------------
1254 // setScore
1255 //---------------------------------------------------------
1256
setScore(Score * s)1257 void Chord::setScore(Score* s)
1258 {
1259 ChordRest::setScore(s);
1260 processSiblings([s] (Element* e) { e->setScore(s); } );
1261 }
1262
1263 //-----------------------------------------------------------------------------
1264 // hookAdjustment
1265 // Adjustment to the length of the stem in order to accommodate hooks
1266 // This function replaces this bit of code:
1267 // switch (hookIdx) {
1268 // case 3: normalStemLen += small() ? .5 : 0.75; break; //32nd notes
1269 // case 4: normalStemLen += small() ? 1.0 : 1.5; break; //64th notes
1270 // case 5: normalStemLen += small() ? 1.5 : 2.25; break; //128th notes
1271 // }
1272 // which was not sufficient for two reasons:
1273 // 1. It only lengthened the stem for 3, 4, or 5 hooks.
1274 // 2. It was too general to produce good results for all combinations of factors.
1275 // This provides a way to take a number of factors into account. Further tweaking may be in order.
1276 //-----------------------------------------------------------------------------
1277
hookAdjustment(QString font,int hooks,bool up,bool small)1278 qreal hookAdjustment(QString font, int hooks, bool up, bool small)
1279 {
1280 bool fallback = MScore::useFallbackFont && (hooks > 5);
1281
1282 if (font == "Emmentaler" && !fallback) {
1283 if (up) {
1284 if (hooks > 2)
1285 return (hooks - 2) * (small ? .75 : 1);
1286 }
1287 else {
1288 if (hooks == 3)
1289 return (small ? .75 : 1);
1290 else if (hooks > 3)
1291 return (hooks - 2) * (small ? .5 : .75);
1292 }
1293 }
1294 else if (font == "Gonville" && !fallback) {
1295 if (up) {
1296 if (hooks > 2)
1297 return (hooks - 2) * (small ? .5 : .75);
1298 }
1299 else {
1300 if (hooks > 1)
1301 return (hooks - 1) * (small ? .5 : .75);
1302 }
1303 }
1304 else if (font == "MuseJazz") {
1305 if (hooks > 2)
1306 return (hooks - 2) * (small ? .75 : 1);
1307 }
1308 else {
1309 if (hooks > 2)
1310 return (hooks - 2) * (small ? .5 : .75);
1311 }
1312 return 0;
1313 }
1314
1315 //-----------------------------------------------------------------------------
1316 // defaultStemLength
1317 /// Get the default stem length for this chord
1318 //-----------------------------------------------------------------------------
1319
defaultStemLength() const1320 qreal Chord::defaultStemLength() const
1321 {
1322 Note* downnote;
1323 qreal stemLen;
1324 qreal _spatium = spatium();
1325 int hookIdx = durationType().hooks();
1326 downnote = downNote();
1327 int ul = upLine();
1328 int dl = downLine();
1329 const Staff* st = staff();
1330 qreal lineDistance = st ? st->lineDistance(tick()) : 1.0;
1331
1332 const StaffType* stt = st ? st->staffTypeForElement(this) : nullptr;
1333 const StaffType* tab = (stt && stt->isTabStaff()) ? stt : nullptr;
1334 if (tab) {
1335 // require stems only if TAB is not stemless and this chord has a stem
1336 if (!tab->stemless() && _stem) {
1337 // if stems are beside staff, apply special formatting
1338 if (!tab->stemThrough()) {
1339 // process stem:
1340 return tab->chordStemLength(this) * _spatium;
1341 }
1342 }
1343 }
1344 else if (lineDistance != 1.0) {
1345 // convert to actual distance from top of staff in sp
1346 // ul *= lineDistance;
1347 // dl *= lineDistance;
1348 }
1349
1350 if (tab && !tab->onLines()) { // if TAB and frets above strings, move 1 position up
1351 --ul;
1352 --dl;
1353 }
1354 bool shortenStem = score()->styleB(Sid::shortenStem);
1355 if (hookIdx >= 2 || _tremolo)
1356 shortenStem = false;
1357
1358 Spatium progression = score()->styleS(Sid::shortStemProgression);
1359 qreal shortest = score()->styleS(Sid::shortestStem).val();
1360 if (hookIdx) {
1361 if (up())
1362 shortest = qMax(shortest, small() ? 2.0 : 3.0);
1363 else
1364 shortest = qMax(shortest, small() ? 2.25 : 3.5);
1365 }
1366
1367 qreal normalStemLen = small() ? 2.5 : 3.5;
1368 if (hookIdx && tab == 0) {
1369 if (up() && durationType().dots()) {
1370 //
1371 // avoid collision of dot with hook
1372 //
1373 if (!(ul & 1))
1374 normalStemLen += .5;
1375 shortenStem = false;
1376 }
1377 }
1378
1379 if (isGrace()) {
1380 // grace notes stems are not subject to normal
1381 // stem rules
1382 stemLen = qAbs(ul - dl) * .5;
1383 stemLen += normalStemLen * score()->styleD(Sid::graceNoteMag);
1384 if (up())
1385 stemLen *= -1;
1386 }
1387 else {
1388 // normal note (not grace)
1389 qreal staffHeight = st ? st->lines(tick()) - 1 : 4;
1390 if (!tab)
1391 staffHeight *= lineDistance;
1392 qreal staffHlfHgt = staffHeight * 0.5;
1393 if (up()) { // stem up
1394 qreal dy = dl * .5; // note-side vert. pos.
1395 qreal sel = ul * .5 - normalStemLen; // stem end vert. pos
1396
1397 // if stem ends above top line (with some exceptions), shorten it
1398 if (shortenStem && (sel < 0.0) && (hookIdx == 0 || tab || !downnote->mirror()))
1399 sel -= sel * progression.val();
1400 if (sel > staffHlfHgt) // if stem ends below ('>') staff mid position,
1401 sel = staffHlfHgt; // stretch it to mid position
1402 stemLen = sel - dy; // actual stem length
1403 qreal exposedLen = sel - ul * .5; // portion extending above top note of chord
1404 if (-exposedLen < shortest) { // if stem too short,
1405 qreal diff = shortest + exposedLen;
1406 stemLen -= diff; // lengthen it to shortest possible length
1407 }
1408 }
1409 else { // stem down
1410 qreal uy = ul * .5; // note-side vert. pos.
1411 qreal sel = dl * .5 + normalStemLen; // stem end vert. pos.
1412
1413 // if stem ends below bottom line (with some exceptions), shorten it
1414 if (shortenStem && (sel > staffHeight) && (hookIdx == 0 || tab || downnote->mirror()))
1415 sel -= (sel - staffHeight) * progression.val();
1416 if (sel < staffHlfHgt) // if stem ends above ('<') staff mid position,
1417 sel = staffHlfHgt; // stretch it to mid position
1418 stemLen = sel - uy; // actual stem length
1419 qreal exposedLen = sel - dl * .5; // portion extending below bottom note of chord
1420 if (exposedLen < shortest) { // if stem too short,
1421 qreal diff = shortest - exposedLen;
1422 stemLen += diff; // lengthen it to shortest possible length
1423 }
1424 }
1425 }
1426
1427 if (tab)
1428 stemLen *= lineDistance;
1429
1430 const qreal sgn = up() ? -1.0 : 1.0;
1431 qreal stemLenPoints = point(Spatium(stemLen));
1432 const qreal minAbsStemLen = minAbsStemLength();
1433 if (sgn * stemLenPoints < minAbsStemLen)
1434 stemLenPoints = sgn * minAbsStemLen;
1435
1436 return stemLenPoints;
1437 }
1438
1439 //---------------------------------------------------------
1440 // minAbsStemLength
1441 // get minimum stem length with tremolo
1442 //---------------------------------------------------------
1443
minAbsStemLength() const1444 qreal Chord::minAbsStemLength() const
1445 {
1446 if (!_tremolo)
1447 return 0.0;
1448
1449 const qreal sw = score()->styleS(Sid::tremoloStrokeWidth).val() * chordMag();
1450 const qreal td = score()->styleS(Sid::tremoloDistance).val() * chordMag();
1451 int beamLvl = beams();
1452 const qreal beamDist = beam() ? beam()->beamDist() : (sw * spatium());
1453
1454 // single-note tremolo
1455 if (!_tremolo->twoNotes()) {
1456 _tremolo->layout(); // guarantee right "height value"
1457
1458 // distance between tremolo stroke(s) and chord
1459 // choose the furthest/nearest note to calculate for unbeamed/beamed chords
1460 // this is due to special layout mechanisms regarding beamed chords
1461 // may be changed if beam layout code is improved/rewritten
1462 qreal height = 0.0;
1463 if (up())
1464 height = (beam() ? upPos() : downPos()) - _tremolo->pos().y();
1465 else
1466 height = _tremolo->pos().y() + _tremolo->minHeight() * spatium() - (beam() ? downPos() : upPos());
1467 const bool hasHook = beamLvl && !beam();
1468 if (hasHook)
1469 beamLvl += (up() ? 3 : 2); // reserve more space for stem with both hook and tremolo
1470
1471 const qreal addHeight1 = beamLvl ? 0 : sw * spatium();
1472 // buzz roll needs to have additional space so as not to collide with the beam/hook
1473 const qreal addHeight2 = (_tremolo->isBuzzRoll() && beamLvl) ? sw * spatium() : 0;
1474
1475 return height + beamLvl * beamDist + addHeight1 + addHeight2;
1476 }
1477
1478 // two-note tremolo
1479 else {
1480 if (_tremolo->chord2() && _tremolo->chord1()->up() == _tremolo->chord2()->up()) {
1481 const qreal tremoloMinHeight = _tremolo->minHeight() * spatium();
1482 return tremoloMinHeight + beamLvl * beamDist + 2 * td * spatium();
1483 }
1484 return 0.0;
1485 }
1486 }
1487
1488 //---------------------------------------------------------
1489 // layoutStem1
1490 /// Layout _stem and _stemSlash
1491 //
1492 // Called before layout spacing of notes.
1493 // Create stem if necessary.
1494 //---------------------------------------------------------
1495
layoutStem1()1496 void Chord::layoutStem1()
1497 {
1498 const Staff* stf = staff();
1499 const StaffType* st = stf ? stf->staffTypeForElement(this) : 0;
1500 if (durationType().hasStem() && !(_noStem || (measure() && measure()->stemless(staffIdx())) || (st && st->isTabStaff() && st->stemless()))) {
1501 if (!_stem) {
1502 Stem* stem = new Stem(score());
1503 stem->setParent(this);
1504 stem->setGenerated(true);
1505 score()->undoAddElement(stem);
1506 }
1507 if ((_noteType == NoteType::ACCIACCATURA) && !(beam() && beam()->elements().front() != this)) {
1508 if (!_stemSlash)
1509 add(new StemSlash(score()));
1510 }
1511 else if (_stemSlash)
1512 remove(_stemSlash);
1513
1514 qreal stemWidth5 = _stem->lineWidth() * .5 * mag();
1515 _stem->rxpos() = stemPosX() + (up() ? -stemWidth5 : +stemWidth5);
1516 _stem->setLen(defaultStemLength());
1517 }
1518 else {
1519 if (_stem)
1520 score()->undoRemoveElement(_stem);
1521 if (_stemSlash)
1522 score()->undoRemoveElement(_stemSlash);
1523 }
1524 }
1525
1526 //-----------------------------------------------------------------------------
1527 // layoutStem
1528 /// Layout chord tremolo stem and hook.
1529 //
1530 // hook: sets position
1531 //-----------------------------------------------------------------------------
1532
layoutStem()1533 void Chord::layoutStem()
1534 {
1535 for (Chord* c : qAsConst(_graceNotes))
1536 c->layoutStem();
1537 if (_beam)
1538 return;
1539
1540 // create hooks for unbeamed chords
1541
1542 int hookIdx = durationType().hooks();
1543
1544 if (hookIdx && !(noStem() || measure()->stemless(staffIdx()))) {
1545 if (!hook()) {
1546 Hook* hook = new Hook(score());
1547 hook->setParent(this);
1548 hook->setGenerated(true);
1549 score()->undoAddElement(hook);
1550 }
1551 hook()->setHookType(up() ? hookIdx : -hookIdx);
1552 }
1553 else if (hook())
1554 score()->undoRemoveElement(hook());
1555
1556 //
1557 // TAB
1558 //
1559 const Staff* st = staff();
1560 const StaffType* tab = st ? st->staffTypeForElement(this) : 0;
1561 if (tab && tab->isTabStaff()) {
1562 // if stemless TAB
1563 if (tab->stemless()) {
1564 // if 'grid' duration symbol of MEDIALFINAL type, it is time to compute its width
1565 if (_tabDur != nullptr && _tabDur->beamGrid() == TabBeamGrid::MEDIALFINAL)
1566 _tabDur->layout2();
1567 // in all other stemless cases, do nothing
1568 return;
1569 }
1570 // not a stemless TAB; if stems are beside staff, apply special formatting
1571 if (!tab->stemThrough()) {
1572 if (_stem) { // (duplicate code with defaultStemLength())
1573 // process stem:
1574 _stem->setLen(tab->chordStemLength(this) * spatium());
1575 // process hook
1576 hookIdx = durationType().hooks();
1577 if (!up())
1578 hookIdx = -hookIdx;
1579 if (hookIdx && _hook) {
1580 _hook->setHookType(hookIdx);
1581 #if 0
1582 _hook->layout();
1583 QPointF p(_stem->hookPos());
1584 if (up()) {
1585 p.ry() -= _hook->bbox().top();
1586 p.rx() -= _stem->width();
1587 }
1588 else {
1589 p.ry() -= _hook->bbox().bottom();
1590 p.rx() -= _stem->width();
1591 }
1592 _hook->setPos(p);
1593 #endif
1594 }
1595 }
1596 return;
1597 }
1598 // if stems are through staff, use standard formatting
1599 }
1600
1601 //
1602 // NON-TAB (or TAB with stems through staff)
1603 //
1604 if (_stem) {
1605 if (_hook) {
1606 _hook->layout();
1607 QPointF p(_stem->hookPos());
1608 if (up()) {
1609 p.rx() -= _stem->width();
1610 }
1611 else {
1612 p.rx() -= _stem->width();
1613 }
1614 _hook->setPos(p);
1615 }
1616 if (_stemSlash)
1617 _stemSlash->layout();
1618 }
1619
1620 //-----------------------------------------
1621 // process tremolo
1622 //-----------------------------------------
1623
1624 // if (_tremolo)
1625 // _tremolo->layout();
1626 }
1627
1628 //---------------------------------------------------------
1629 // underBeam: true, if grace note is placed under a beam.
1630 //---------------------------------------------------------
1631
underBeam() const1632 bool Chord::underBeam() const
1633 {
1634 if (_noteType == NoteType::NORMAL)
1635 return false;
1636 const Chord* cr = toChord(parent());
1637 Beam* beam = cr->beam();
1638 if(!beam || !cr->beam()->up())
1639 return false;
1640 int s = beam->elements().count();
1641 if (isGraceBefore()){
1642 if (beam->elements()[0] != cr)
1643 return true;
1644 }
1645 if (isGraceAfter()){
1646 if (beam->elements()[s - 1] != cr)
1647 return true;
1648 }
1649 return false;
1650 }
1651
1652 //---------------------------------------------------------
1653 // layout2
1654 // Called after horizontal positions of all elements
1655 // are fixed.
1656 //---------------------------------------------------------
1657
layout2()1658 void Chord::layout2()
1659 {
1660 for (Chord* c : qAsConst(_graceNotes))
1661 c->layout2();
1662
1663 const qreal mag = staff()->mag(this);
1664
1665 //
1666 // position after-chord grace notes
1667 // room for them has been reserved in Chord::layout()
1668 //
1669
1670 QVector<Chord*> gna = graceNotesAfter();
1671 if (!gna.empty()) {
1672 qreal minNoteDist = score()->styleP(Sid::minNoteDistance) * mag * score()->styleD(Sid::graceNoteMag);
1673 // position grace notes from the rightmost to the leftmost
1674 // get segment (of whatever type) at the end of this chord; if none, get measure last segment
1675 Segment* s = measure()->tick2segment(segment()->tick() + actualTicks(), SegmentType::All);
1676 if (s == nullptr)
1677 s = measure()->last();
1678 if (s == segment()) // if our segment is the last, no adjacent segment found
1679 s = nullptr;
1680 // start from the right (if next segment found, x of it relative to this chord;
1681 // chord right space otherwise)
1682 Chord* last = gna.last();
1683 qreal xOff = s ? (s->pos().x() - s->staffShape(last->vStaffIdx()).left()) - (segment()->pos().x() + pos().x()) : _spaceRw;
1684 // final distance: if near to another chord, leave minNoteDist at right of last grace
1685 // else leave note-to-barline distance;
1686 xOff -= (s != nullptr && s->segmentType() != SegmentType::ChordRest)
1687 ? score()->styleP(Sid::noteBarDistance) * mag
1688 : minNoteDist;
1689 // scan grace note list from the end
1690 int n = gna.size();
1691 for (int i = n-1; i >= 0; i--) {
1692 Chord* g = gna.value(i);
1693 xOff -= g->_spaceRw; // move to left by grace note left space (incl. grace own width)
1694 g->rxpos() = xOff;
1695 xOff -= minNoteDist + g->_spaceLw; // move to left by grace note right space and inter-grace distance
1696 }
1697 }
1698 if (_tabDur)
1699 _tabDur->layout2();
1700 }
1701
1702 //---------------------------------------------------------
1703 // updatePercussionNotes
1704 //---------------------------------------------------------
1705
updatePercussionNotes(Chord * c,const Drumset * drumset)1706 static void updatePercussionNotes(Chord* c, const Drumset* drumset)
1707 {
1708 for (Chord* ch : c->graceNotes())
1709 updatePercussionNotes(ch, drumset);
1710 std::vector<Note*> lnotes(c->notes()); // we need a copy!
1711 for (Note* note : lnotes) {
1712 if (!drumset)
1713 note->setLine(0);
1714 else {
1715 int pitch = note->pitch();
1716 if (!drumset->isValid(pitch)) {
1717 note->setLine(0);
1718 qWarning("unmapped drum note %d", pitch);
1719 }
1720 else if (!note->fixed()) {
1721 note->undoChangeProperty(Pid::HEAD_GROUP, int(drumset->noteHead(pitch)));
1722 note->setLine(drumset->line(pitch));
1723 }
1724 }
1725 }
1726 }
1727
1728 //---------------------------------------------------------
1729 // cmdUpdateNotes
1730 //---------------------------------------------------------
1731
cmdUpdateNotes(AccidentalState * as)1732 void Chord::cmdUpdateNotes(AccidentalState* as)
1733 {
1734 // TAB_STAFF is different, as each note has to be fretted
1735 // in the context of the all of the chords of the whole segment
1736
1737 const Staff* st = staff();
1738 StaffGroup staffGroup = st->staffTypeForElement(this)->group();
1739 if (staffGroup == StaffGroup::TAB) {
1740 const Instrument* instrument = part()->instrument(this->tick());
1741 for (Chord* ch : graceNotes())
1742 instrument->stringData()->fretChords(ch);
1743 instrument->stringData()->fretChords(this);
1744 return;
1745 }
1746 else {
1747 // if not tablature, use instrument->useDrumset to set staffGroup (to allow pitched to unpitched in same staff)
1748 staffGroup = st->part()->instrument(this->tick())->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
1749 }
1750
1751 // PITCHED_ and PERCUSSION_STAFF can go note by note
1752
1753 if (staffGroup == StaffGroup::STANDARD) {
1754 const QVector<Chord*> gnb(graceNotesBefore());
1755 for (Chord* ch : gnb) {
1756 std::vector<Note*> notes(ch->notes()); // we need a copy!
1757 for (Note* note : notes)
1758 note->updateAccidental(as);
1759 ch->sortNotes();
1760 }
1761 std::vector<Note*> lnotes(notes()); // we need a copy!
1762 for (Note* note : lnotes) {
1763 if (note->tieBack() && note->tpc() == note->tieBack()->startNote()->tpc()) {
1764 // same pitch
1765 if (note->accidental() && note->accidental()->role() == AccidentalRole::AUTO) {
1766 // not courtesy
1767 // TODO: remove accidental only if note is not
1768 // on new system
1769 score()->undoRemoveElement(note->accidental());
1770 }
1771 }
1772 note->updateAccidental(as);
1773 }
1774 const QVector<Chord*> gna(graceNotesAfter());
1775 for (Chord* ch : gna) {
1776 std::vector<Note*> notes(ch->notes()); // we need a copy!
1777 for (Note* note : notes)
1778 note->updateAccidental(as);
1779 ch->sortNotes();
1780 }
1781 }
1782 else if (staffGroup == StaffGroup::PERCUSSION) {
1783 const Instrument* instrument = part()->instrument(this->tick());
1784 const Drumset* drumset = instrument->drumset();
1785 if (!drumset)
1786 qWarning("no drumset");
1787 updatePercussionNotes(this, drumset);
1788 }
1789
1790 sortNotes();
1791 }
1792
1793 //---------------------------------------------------------
1794 // pagePos
1795 //---------------------------------------------------------
1796
pagePos() const1797 QPointF Chord::pagePos() const
1798 {
1799 if (isGrace()) {
1800 QPointF p(pos());
1801 if (parent() == 0)
1802 return p;
1803 p.rx() = pageX();
1804
1805 const Chord* pc = static_cast<const Chord*>(parent());
1806 System* system = pc->segment()->system();
1807 if (!system)
1808 return p;
1809 qreal staffYOffset = staff() ? staff()->staffType(tick())->yoffset().val() * spatium() : 0.0;
1810 p.ry() += system->staffYpage(vStaffIdx()) + staffYOffset;
1811 return p;
1812 }
1813 return Element::pagePos();
1814 }
1815
1816 //---------------------------------------------------------
1817 // layout
1818 //---------------------------------------------------------
1819
layout()1820 void Chord::layout()
1821 {
1822 if (_notes.empty())
1823 return;
1824 if (onTabStaff())
1825 layoutTablature();
1826 else
1827 layoutPitched();
1828 }
1829
1830 //---------------------------------------------------------
1831 // layoutPitched
1832 //---------------------------------------------------------
1833
layoutPitched()1834 void Chord::layoutPitched()
1835 {
1836 int gi = 0;
1837 for (Chord* c : qAsConst(_graceNotes)) {
1838 // HACK: graceIndex is not well-maintained on add & remove
1839 // so rebuild now
1840 c->setGraceIndex(gi++);
1841 if (c->isGraceBefore())
1842 c->layoutPitched();
1843 }
1844 const QVector<Chord*> graceNotesBefore = Chord::graceNotesBefore();
1845 const int gnb = graceNotesBefore.size();
1846
1847 // lay out grace notes after separately so they are processed left to right
1848 // (they are normally stored right to left)
1849
1850 const QVector<Chord*> gna = graceNotesAfter();
1851 for (Chord* c : gna)
1852 c->layoutPitched();
1853
1854 qreal _spatium = spatium();
1855 qreal mag_ = staff() ? staff()->mag(this) : 1.0; // palette elements do not have a staff
1856 qreal dotNoteDistance = score()->styleP(Sid::dotNoteDistance) * mag_;
1857 qreal minNoteDistance = score()->styleP(Sid::minNoteDistance) * mag_;
1858 qreal minTieLength = score()->styleP(Sid::MinTieLength) * mag_;
1859
1860 qreal graceMag = score()->styleD(Sid::graceNoteMag);
1861 qreal chordX = (_noteType == NoteType::NORMAL) ? ipos().x() : 0.0;
1862
1863 while (_ledgerLines) {
1864 LedgerLine* l = _ledgerLines->next();
1865 delete _ledgerLines;
1866 _ledgerLines = l;
1867 }
1868
1869 qreal lll = 0.0; // space to leave at left of chord
1870 qreal rrr = 0.0; // space to leave at right of chord
1871 qreal lhead = 0.0; // amount of notehead to left of chord origin
1872 Note* upnote = upNote();
1873
1874 delete _tabDur; // no TAB? no duration symbol! (may happen when converting a TAB into PITCHED)
1875 _tabDur = 0;
1876
1877 if (!segment()) {
1878 //
1879 // hack for use in palette
1880 //
1881 size_t n = _notes.size();
1882 for (size_t i = 0; i < n; i++) {
1883 Note* note = _notes.at(i);
1884 note->layout();
1885 qreal x = 0.0;
1886 qreal y = note->line() * _spatium * .5;
1887 note->setPos(x, y);
1888 }
1889 computeUp();
1890 layoutStem1();
1891 if (_stem) { //false when dragging notes from drum palette
1892 qreal stemWidth5 = _stem->lineWidth() * .5;
1893 _stem->rxpos() = up() ? (upNote()->headBodyWidth() - stemWidth5) : stemWidth5;
1894 }
1895 addLedgerLines();
1896 return;
1897 }
1898
1899 //-----------------------------------------
1900 // process notes
1901 //-----------------------------------------
1902
1903 for (Note* note : _notes) {
1904 note->layout();
1905
1906 qreal x1 = note->pos().x() + chordX;
1907 qreal x2 = x1 + note->headWidth();
1908 lll = qMax(lll, -x1);
1909 rrr = qMax(rrr, x2);
1910 // track amount of space due to notehead only
1911 lhead = qMax(lhead, -x1);
1912
1913 Accidental* accidental = note->accidental();
1914 if (accidental && accidental->addToSkyline() && !note->fixed()) {
1915 // convert x position of accidental to segment coordinate system
1916 qreal x = accidental->pos().x() + note->pos().x() + chordX;
1917 // distance from accidental to note already taken into account
1918 // but here perhaps we create more padding in *front* of accidental?
1919 x -= score()->styleP(Sid::accidentalDistance) * mag_;
1920 lll = qMax(lll, -x);
1921 }
1922
1923 // allow extra space for shortened ties
1924 // this code must be kept synchronized
1925 // with the tie positioning code in Tie::slurPos()
1926 // but the allocation of space needs to be performed here
1927 Tie* tie;
1928 tie = note->tieBack();
1929 if (tie) {
1930 tie->calculateDirection();
1931 qreal overlap = 0.0;
1932 bool shortStart = false;
1933 Note* sn = tie->startNote();
1934 Chord* sc = sn->chord();
1935 if (sc && sc->measure() == measure() && sc == prevChordRest(this)) {
1936 if (sc->notes().size() > 1 || (sc->stem() && sc->up() == tie->up())) {
1937 shortStart = true;
1938 if (sc->width() > sn->width()) {
1939 // chord with second?
1940 // account for noteheads further to right
1941 qreal snEnd = sn->x() + sn->bboxRightPos();
1942 qreal scEnd = snEnd;
1943 for (unsigned i = 0; i < sc->notes().size(); ++i)
1944 scEnd = qMax(scEnd, sc->notes().at(i)->x() + sc->notes().at(i)->bboxRightPos());
1945 overlap += scEnd - snEnd;
1946 }
1947 else
1948 overlap -= sn->headWidth() * 0.12;
1949 }
1950 else
1951 overlap += sn->headWidth() * 0.35;
1952 if (notes().size() > 1 || (stem() && !up() && !tie->up())) {
1953 // for positive offset:
1954 // use available space
1955 // for negative x offset:
1956 // space is allocated elsewhere, so don't re-allocate here
1957 if (note->ipos().x() != 0.0)
1958 overlap += qAbs(note->ipos().x());
1959 else
1960 overlap -= note->headWidth() * 0.12;
1961 }
1962 else {
1963 if (shortStart)
1964 overlap += note->headWidth() * 0.15;
1965 else
1966 overlap += note->headWidth() * 0.35;
1967 }
1968 qreal d = qMax(minTieLength - overlap, 0.0);
1969 lll = qMax(lll, d);
1970 }
1971 }
1972
1973 // clear layout for note-based fingerings
1974 for (Element* e : note->el()) {
1975 if (e->isFingering()) {
1976 Fingering* f = toFingering(e);
1977 if (f->layoutType() == ElementType::NOTE) {
1978 f->setPos(QPointF());
1979 f->setbbox(QRectF());
1980 }
1981 }
1982 }
1983
1984 }
1985
1986 //-----------------------------------------
1987 // create ledger lines
1988 //-----------------------------------------
1989
1990 addLedgerLines();
1991
1992 if (_arpeggio) {
1993 qreal arpeggioDistance = score()->styleP(Sid::ArpeggioNoteDistance) * mag_;
1994 _arpeggio->layout(); // only for width() !
1995 _arpeggio->setHeight(0.0);
1996 qreal extraX = _arpeggio->width() + arpeggioDistance + chordX;
1997 qreal y1 = upnote->pos().y() - upnote->headHeight() * .5;
1998 _arpeggio->setPos(-(lll + extraX), y1);
1999 if (_arpeggio->visible())
2000 lll += extraX;
2001 // _arpeggio->layout() called in layoutArpeggio2()
2002
2003 // handle the special case of _arpeggio->span() > 1
2004 // in layoutArpeggio2() after page layout has done so we
2005 // know the y position of the next staves
2006 }
2007
2008 // allocate enough room for glissandi
2009 if (_endsGlissando) {
2010 for (const Note* note : notes()) {
2011 for (const Spanner* sp : note->spannerBack()) {
2012 if (sp->isGlissando()) {
2013 if (toGlissando(sp)->visible()) {
2014 if (!rtick().isZero() // if not at beginning of measure
2015 || graceNotesBefore.size() > 0) { // or there are graces before
2016 lll += _spatium * 0.5 + minTieLength;
2017 break;
2018 }
2019 }
2020 }
2021 }
2022 }
2023 // special case of system-initial glissando final note is handled in Glissando::layout() itself
2024 }
2025
2026 if (dots()) {
2027 qreal x = dotPosX() + dotNoteDistance
2028 + (dots()-1) * score()->styleP(Sid::dotDotDistance) * mag_;
2029 x += symWidth(SymId::augmentationDot);
2030 rrr = qMax(rrr, x);
2031 }
2032
2033 if (_hook) {
2034 if (beam())
2035 score()->undoRemoveElement(_hook);
2036 else {
2037 _hook->layout();
2038 if (up() && stem()) {
2039 // hook position is not set yet
2040 qreal x = _hook->bbox().right() + stem()->hookPos().x() + chordX;
2041 rrr = qMax(rrr, x);
2042 }
2043 }
2044 }
2045
2046 #if 0
2047 if (!_articulations.isEmpty()) {
2048 // TODO: allocate space to avoid "staircase" effect
2049 // but we would need to determine direction in order to get correct symid & bbox
2050 // another alternative is to limit the width contribution of the articulation in layoutArticulations2()
2051 //qreal aWidth = 0.0;
2052 for (Articulation* a : articulations())
2053 a->layout(); // aWidth = qMax(aWidth, a->width());
2054 //qreal w = width();
2055 //qreal aExtra = (qMax(aWidth, w) - w) * 0.5;
2056 //lll = qMax(lll, aExtra);
2057 //rrr = qMax(rrr, aExtra);
2058 }
2059 #endif
2060
2061 _spaceLw = lll;
2062 _spaceRw = rrr;
2063
2064 if (gnb) {
2065 qreal xl = -(_spaceLw + minNoteDistance) - chordX;
2066 for (int i = gnb-1; i >= 0; --i) {
2067 Chord* g = graceNotesBefore.value(i);
2068 xl -= g->_spaceRw/* * 1.2*/;
2069 g->setPos(xl, 0);
2070 xl -= g->_spaceLw + minNoteDistance * graceMag;
2071 }
2072 if (-xl > _spaceLw)
2073 _spaceLw = -xl;
2074 }
2075 if (!gna.empty()) {
2076 qreal xr = _spaceRw;
2077 int n = gna.size();
2078 for (int i = 0; i <= n - 1; i++) {
2079 Chord* g = gna.value(i);
2080 xr += g->_spaceLw + g->_spaceRw + minNoteDistance * graceMag;
2081 }
2082 if (xr > _spaceRw)
2083 _spaceRw = xr;
2084 }
2085
2086 for (Element* e : el()) {
2087 if (e->type() == ElementType::SLUR) // we cannot at this time as chordpositions are not fixed
2088 continue;
2089 e->layout();
2090 if (e->type() == ElementType::CHORDLINE) {
2091 QRectF tbbox = e->bbox().translated(e->pos());
2092 qreal lx = tbbox.left() + chordX;
2093 qreal rx = tbbox.right() + chordX;
2094 if (-lx > _spaceLw)
2095 _spaceLw = -lx;
2096 if (rx > _spaceRw)
2097 _spaceRw = rx;
2098 }
2099 }
2100
2101 for (Note* note : _notes)
2102 note->layout2();
2103
2104 // align note-based fingerings
2105 std::vector<Fingering*> alignNote;
2106 qreal xNote = 10000.0;
2107 for (Note* note : _notes) {
2108 bool leftFound = false;
2109 for (Element* e : note->el()) {
2110 if (e->isFingering() && e->autoplace()) {
2111 Fingering* f = toFingering(e);
2112 if (f->layoutType() == ElementType::NOTE && f->tid() == Tid::LH_GUITAR_FINGERING) {
2113 alignNote.push_back(f);
2114 if (!leftFound) {
2115 leftFound = true;
2116 qreal xf = f->ipos().x();
2117 xNote = qMin(xNote, xf);
2118 }
2119 }
2120 }
2121 }
2122 }
2123 for (Fingering* f : alignNote)
2124 f->rxpos() = xNote;
2125 }
2126
2127 //---------------------------------------------------------
2128 // layoutTablature
2129 //---------------------------------------------------------
2130
layoutTablature()2131 void Chord::layoutTablature()
2132 {
2133 qreal _spatium = spatium();
2134 qreal dotNoteDistance = score()->styleP(Sid::dotNoteDistance);
2135 qreal minNoteDistance = score()->styleP(Sid::minNoteDistance);
2136 qreal minTieLength = score()->styleP(Sid::MinTieLength);
2137
2138 for (Chord* c : qAsConst(_graceNotes))
2139 c->layoutTablature();
2140
2141 while (_ledgerLines) {
2142 LedgerLine* l = _ledgerLines->next();
2143 delete _ledgerLines;
2144 _ledgerLines = l;
2145 }
2146
2147 qreal lll = 0.0; // space to leave at left of chord
2148 qreal rrr = 0.0; // space to leave at right of chord
2149 Note* upnote = upNote();
2150 qreal headWidth = symWidth(SymId::noteheadBlack);
2151 const Staff* st = staff();
2152 const StaffType* tab = st->staffTypeForElement(this);
2153 qreal lineDist = tab->lineDistance().val() *_spatium;
2154 qreal stemX = tab->chordStemPosX(this) *_spatium;
2155 int ledgerLines = 0;
2156 qreal llY = 0.0;
2157
2158 size_t numOfNotes = _notes.size();
2159 qreal minY = 1000.0; // just a very large value
2160 for (size_t i = 0; i < numOfNotes; ++i) {
2161 Note* note = _notes.at(i);
2162 note->layout();
2163 // set headWidth to max fret text width
2164 qreal fretWidth = note->bbox().width();
2165 if (headWidth < fretWidth)
2166 headWidth = fretWidth;
2167 // centre fret string on stem
2168 qreal x = stemX - fretWidth*0.5;
2169 qreal y = note->fixed() ? note->line() * lineDist / 2 : tab->physStringToYOffset(note->string()) * _spatium;
2170 note->setPos(x, y);
2171 if (y < minY)
2172 minY = y;
2173 int currLedgerLines = tab->numOfTabLedgerLines(note->string());
2174 if (currLedgerLines > ledgerLines) {
2175 ledgerLines = currLedgerLines;
2176 llY = y;
2177 }
2178
2179 // allow extra space for shortened ties; this code must be kept synchronized
2180 // with the tie positioning code in Tie::slurPos()
2181 // but the allocation of space needs to be performed here
2182 Tie* tie;
2183 tie = note->tieBack();
2184 if (tie) {
2185 tie->calculateDirection();
2186 qreal overlap = 0.0; // how much tie can overlap start and end notes
2187 bool shortStart = false; // whether tie should clear start note or not
2188 Note* startNote = tie->startNote();
2189 Chord* startChord = startNote->chord();
2190 if (startChord && startChord->measure() == measure() && startChord == prevChordRest(this)) {
2191 qreal startNoteWidth = startNote->width();
2192 // overlap into start chord?
2193 // if in start chord, there are several notes or stem and tie in same direction
2194 if (startChord->notes().size() > 1 || (startChord->stem() && startChord->up() == tie->up())) {
2195 // clear start note (1/8 of fret mark width)
2196 shortStart = true;
2197 overlap -= startNoteWidth * 0.125;
2198 }
2199 else // overlap start note (by ca. 1/3 of fret mark width)
2200 overlap += startNoteWidth * 0.35;
2201 // overlap into end chord (this)?
2202 // if several notes or neither stem or tie are up
2203 if (notes().size() > 1 || (stem() && !up() && !tie->up())) {
2204 // for positive offset:
2205 // use available space
2206 // for negative x offset:
2207 // space is allocated elsewhere, so don't re-allocate here
2208 if (note->ipos().x() != 0.0) // this probably does not work for TAB, as
2209 overlap += qAbs(note->ipos().x()); // _pos is used to centre the fret on the stem
2210 else
2211 overlap -= fretWidth * 0.125;
2212 }
2213 else {
2214 if (shortStart)
2215 overlap += fretWidth * 0.15;
2216 else
2217 overlap += fretWidth * 0.35;
2218 }
2219 qreal d = qMax(minTieLength - overlap, 0.0);
2220 lll = qMax(lll, d);
2221 }
2222 }
2223 }
2224
2225 // create ledger lines, if required (in some historic styles)
2226 if (ledgerLines > 0) {
2227 // there seems to be no need for widening 'ledger lines' beyond fret mark widths; more 'on the field'
2228 // tests and usage will show if this depends on the metrics of the specific fonts used or not.
2229 // qreal extraLen = score()->styleS(Sid::ledgerLineLength).val() * _spatium;
2230 qreal extraLen = 0;
2231 qreal llX = stemX - (headWidth + extraLen) * 0.5;
2232 for (int i = 0; i < ledgerLines; i++) {
2233 LedgerLine* ldgLin = new LedgerLine(score());
2234 ldgLin->setParent(this);
2235 ldgLin->setTrack(track());
2236 ldgLin->setVisible(visible());
2237 ldgLin->setLen(headWidth + extraLen);
2238 ldgLin->setPos(llX, llY);
2239 ldgLin->setNext(_ledgerLines);
2240 _ledgerLines = ldgLin;
2241 ldgLin->layout();
2242 llY += lineDist / ledgerLines;
2243 }
2244 headWidth += extraLen; // include ledger lines extra width in chord width
2245 }
2246
2247 // horiz. spacing: leave half width at each side of the (potential) stem
2248 qreal halfHeadWidth = headWidth * 0.5;
2249 if (lll < stemX - halfHeadWidth)
2250 lll = stemX - halfHeadWidth;
2251 if (rrr < stemX + halfHeadWidth)
2252 rrr = stemX + halfHeadWidth;
2253 // align dots to the widest fret mark (not needed in all TAB styles, but harmless anyway)
2254 if (segment())
2255 segment()->setDotPosX(staffIdx(), headWidth);
2256 // if tab type is stemless or chord is stemless (possible when imported from MusicXML)
2257 // or measure is stemless
2258 // or duration longer than half (if halves have stems) or duration longer than crochet
2259 // remove stems
2260 if (tab->stemless() || _noStem || measure()->stemless(staffIdx()) || durationType().type() <
2261 (tab->minimStyle() != TablatureMinimStyle::NONE ? TDuration::DurationType::V_HALF : TDuration::DurationType::V_QUARTER) ) {
2262 if (_stem)
2263 score()->undo(new RemoveElement(_stem));
2264 if (_hook)
2265 score()->undo(new RemoveElement(_hook));
2266 if (_beam)
2267 score()->undo(new RemoveElement(_beam));
2268 }
2269 // if stem is required but missing, add it;
2270 // set stem position (stem length is set in Chord:layoutStem() )
2271 else {
2272 if (_stem == 0) {
2273 Stem* stem = new Stem(score());
2274 stem->setParent(this);
2275 score()->undo(new AddElement(stem));
2276 }
2277 _stem->setPos(tab->chordStemPos(this) * _spatium);
2278 if (_hook) {
2279 if (beam())
2280 score()->undoRemoveElement(_hook);
2281 else {
2282 _hook->layout();
2283 if (rrr < stemX + _hook->width())
2284 rrr = stemX + _hook->width();
2285
2286 QPointF p(_stem->hookPos());
2287 if (up()) {
2288 p.ry() -= _hook->bbox().top();
2289 p.rx() -= _stem->width();
2290 }
2291 else {
2292 p.ry() -= _hook->bbox().bottom();
2293 p.rx() -= _stem->width();
2294 }
2295 _hook->setPos(p);
2296 }
2297 }
2298 }
2299 if (!tab->genDurations() // if tab is not set for duration symbols
2300 || track2voice(track()) // or not in first voice
2301 || (isGrace() // no tab duration symbols if grace notes
2302 && beamMode() == Beam::Mode::AUTO)) { // and beammode == AUTO
2303 //
2304 delete _tabDur; // delete an existing duration symbol
2305 _tabDur = 0;
2306 }
2307 else {
2308 //
2309 // tab duration symbols
2310 //
2311 // if no previous CR
2312 // OR symbol repeat set to ALWAYS
2313 // OR symbol repeat condition is triggered
2314 // OR duration type and/or number of dots is different from current CR
2315 // OR chord beam mode not AUTO
2316 // OR previous CR is a rest
2317 // AND no not-stem
2318 // set a duration symbol (trying to re-use existing symbols where existing to minimize
2319 // symbol creation and deletion)
2320 bool needTabDur = false;
2321 bool repeat = false;
2322 if (!noStem()) {
2323 // check duration of prev. CR segm
2324 ChordRest * prevCR = prevChordRest(this);
2325 if (prevCR == 0)
2326 needTabDur = true;
2327 else if (beamMode() != Beam::Mode::AUTO
2328 || prevCR->durationType().type() != durationType().type()
2329 || prevCR->dots() != dots()
2330 || prevCR->tuplet() != tuplet()
2331 || prevCR->type() == ElementType::REST)
2332 needTabDur = true;
2333 else if (tab->symRepeat() == TablatureSymbolRepeat::ALWAYS
2334 || ((tab->symRepeat() == TablatureSymbolRepeat::MEASURE ||
2335 tab->symRepeat() == TablatureSymbolRepeat::SYSTEM)
2336 && measure() != prevCR->measure())) {
2337 needTabDur = true;
2338 repeat = true;
2339 }
2340 }
2341 if (needTabDur) {
2342 // symbol needed; if not exist, create; if exists, update duration
2343 if (!_tabDur)
2344 _tabDur = new TabDurationSymbol(score(), tab, durationType().type(), dots());
2345 else
2346 _tabDur->setDuration(durationType().type(), dots(), tab);
2347 _tabDur->setParent(this);
2348 _tabDur->setRepeat(repeat);
2349 // _tabDur->setMag(mag()); // useless to set grace mag: graces have no dur. symbol
2350 _tabDur->layout();
2351 if (minY < 0) { // if some fret extends above tab body (like bass strings)
2352 _tabDur->rypos() += minY; // raise duration symbol
2353 _tabDur->bbox().translate(0, minY);
2354 }
2355 }
2356 else { // symbol not needed: if exists, delete
2357 delete _tabDur;
2358 _tabDur = 0;
2359 }
2360 } // end of if(duration_symbols)
2361
2362 if (_arpeggio) {
2363 qreal headHeight = upnote->headHeight();
2364 _arpeggio->layout();
2365 lll += _arpeggio->width() + _spatium * .5;
2366 qreal y = upNote()->pos().y() - headHeight * .5;
2367 qreal h = downNote()->pos().y() + downNote()->headHeight() - y;
2368 _arpeggio->setHeight(h);
2369 _arpeggio->setPos(-lll, y);
2370
2371 // handle the special case of _arpeggio->span() > 1
2372 // in layoutArpeggio2() after page layout has done so we
2373 // know the y position of the next staves
2374 }
2375
2376 // allocate enough room for glissandi
2377 if (_endsGlissando) {
2378 if (!rtick().isZero()) // if not at beginning of measure
2379 lll += (0.5 + score()->styleS(Sid::MinTieLength).val()) * _spatium;
2380 // special case of system-initial glissando final note is handled in Glissando::layout() itself
2381 }
2382
2383 if (_hook) {
2384 if (beam())
2385 score()->undoRemoveElement(_hook);
2386 else if(tab == 0) {
2387 _hook->layout();
2388 if (up()) {
2389 // hook position is not set yet
2390 qreal x = _hook->bbox().right() + stem()->hookPos().x();
2391 rrr = qMax(rrr, x);
2392 }
2393 }
2394 }
2395
2396 if (dots()) {
2397 qreal x = 0.0;
2398 // if stems are beside staff, dots are placed near to stem
2399 if (!tab->stemThrough()) {
2400 // if there is an unbeamed hook, dots should start after the hook
2401 if (_hook && !beam())
2402 x = _hook->width() + dotNoteDistance;
2403 // if not, dots should start at a fixed distance right after the stem
2404 else
2405 x = STAFFTYPE_TAB_DEFAULTDOTDIST_X * _spatium;
2406 if (segment())
2407 segment()->setDotPosX(staffIdx(), x);
2408 }
2409 // if stems are through staff, use dot position computed above on fret mark widths
2410 else
2411 x = dotPosX() + dotNoteDistance
2412 + (dots()-1) * score()->styleS(Sid::dotDotDistance).val() * _spatium;
2413 x += symWidth(SymId::augmentationDot);
2414 rrr = qMax(rrr, x);
2415 }
2416
2417 #if 0
2418 if (!_articulations.isEmpty()) {
2419 // TODO: allocate space? see layoutPitched()
2420 for (Articulation* a : articulations())
2421 a->layout();
2422 }
2423 #endif
2424
2425 _spaceLw = lll;
2426 _spaceRw = rrr;
2427
2428 qreal graceMag = score()->styleD(Sid::graceNoteMag);
2429
2430 QVector<Chord*> graceNotesBefore = Chord::graceNotesBefore();
2431 int nb = graceNotesBefore.size();
2432 if (nb) {
2433 qreal xl = -(_spaceLw + minNoteDistance);
2434 for (int i = nb-1; i >= 0; --i) {
2435 Chord* c = graceNotesBefore.value(i);
2436 xl -= c->_spaceRw/* * 1.2*/;
2437 c->setPos(xl, 0);
2438 xl -= c->_spaceLw + minNoteDistance * graceMag;
2439 }
2440 if (-xl > _spaceLw)
2441 _spaceLw = -xl;
2442 }
2443 QVector<Chord*> gna = graceNotesAfter();
2444 int na = gna.size();
2445 if (na) {
2446 // get factor for start distance after main note. Values found by testing.
2447 qreal fc;
2448 switch (durationType().type()) {
2449 case TDuration::DurationType::V_LONG: fc = 3.8; break;
2450 case TDuration::DurationType::V_BREVE: fc = 3.8; break;
2451 case TDuration::DurationType::V_WHOLE: fc = 3.8; break;
2452 case TDuration::DurationType::V_HALF: fc = 3.6; break;
2453 case TDuration::DurationType::V_QUARTER: fc = 2.1; break;
2454 case TDuration::DurationType::V_EIGHTH: fc = 1.4; break;
2455 case TDuration::DurationType::V_16TH: fc = 1.2; break;
2456 default: fc = 1;
2457 }
2458 qreal xr = fc * (_spaceRw + minNoteDistance);
2459 for (int i = 0; i <= na - 1; i++) {
2460 Chord* c = gna.value(i);
2461 xr += c->_spaceLw * (i == 0 ? 1.3 : 1);
2462 c->setPos(xr, 0);
2463 xr += c->_spaceRw + minNoteDistance * graceMag;
2464 }
2465 if (xr > _spaceRw)
2466 _spaceRw = xr;
2467 }
2468 for (Element* e : el()) {
2469 e->layout();
2470 if (e->type() == ElementType::CHORDLINE) {
2471 QRectF tbbox = e->bbox().translated(e->pos());
2472 qreal lx = tbbox.left();
2473 qreal rx = tbbox.right();
2474 if (-lx > _spaceLw)
2475 _spaceLw = -lx;
2476 if (rx > _spaceRw)
2477 _spaceRw = rx;
2478 }
2479 }
2480
2481 for (size_t i = 0; i < numOfNotes; ++i)
2482 _notes.at(i)->layout2();
2483 QRectF bb;
2484 processSiblings([&bb] (Element* e) { bb |= e->bbox().translated(e->pos()); } );
2485 if (_tabDur)
2486 bb |= _tabDur->bbox().translated(_tabDur->pos());
2487 setbbox(bb);
2488 }
2489
2490 //---------------------------------------------------------
2491 // crossMeasureSetup
2492 //---------------------------------------------------------
2493
crossMeasureSetup(bool on)2494 void Chord::crossMeasureSetup(bool on)
2495 {
2496 if (!on) {
2497 if (_crossMeasure != CrossMeasure::UNKNOWN) {
2498 _crossMeasure = CrossMeasure::UNKNOWN;
2499 layoutStem1();
2500 }
2501 return;
2502 }
2503 if (_crossMeasure == CrossMeasure::UNKNOWN) {
2504 CrossMeasure tempCross = CrossMeasure::NONE; // assume no cross-measure modification
2505 // if chord has only one note and note is tied forward
2506 if (notes().size() == 1 && _notes[0]->tieFor()) {
2507 Chord* tiedChord = _notes[0]->tieFor()->endNote()->chord();
2508 // if tied note belongs to another measure and to a single-note chord
2509 if (tiedChord->measure() != measure() && tiedChord->notes().size() == 1) {
2510 // get total duration
2511 std::vector<TDuration> durList = toDurationList(
2512 actualDurationType().fraction() +
2513 tiedChord->actualDurationType().fraction(), true);
2514 // if duration can be expressed as a single duration
2515 // apply cross-measure modification
2516 if (durList.size() == 1) {
2517 _crossMeasure = tempCross = CrossMeasure::FIRST;
2518 _crossMeasureTDur = durList[0];
2519 layoutStem1();
2520 }
2521 }
2522 _crossMeasure = tempCross;
2523 tiedChord->setCrossMeasure(tempCross == CrossMeasure::FIRST ?
2524 CrossMeasure::SECOND : CrossMeasure::NONE);
2525 }
2526 }
2527 }
2528
2529 //---------------------------------------------------------
2530 // layoutArpeggio2
2531 // called after layout of page
2532 //---------------------------------------------------------
2533
layoutArpeggio2()2534 void Chord::layoutArpeggio2()
2535 {
2536 if (!_arpeggio)
2537 return;
2538 qreal y = upNote()->pagePos().y() - upNote()->headHeight() * .5;
2539 int span = _arpeggio->span();
2540 int btrack = track() + (span - 1) * VOICES;
2541
2542 Element* element = segment()->element(btrack);
2543 ChordRest* bchord = element ? toChordRest(element) : nullptr;
2544 Note* dnote = (bchord && bchord->type() == ElementType::CHORD) ? toChord(bchord)->downNote() : downNote();
2545
2546 qreal h = dnote->pagePos().y() + dnote->headHeight() * .5 - y;
2547 _arpeggio->setHeight(h);
2548 _arpeggio->layout();
2549
2550 #if 0 // collect notes for arpeggio
2551 QList<Note*> notes;
2552 int n = _notes.size();
2553 for (int j = n - 1; j >= 0; --j) {
2554 Note* note = _notes[j];
2555 if (note->tieBack())
2556 continue;
2557 notes.prepend(note);
2558 }
2559
2560 for (int i = 1; i < span; ++i) {
2561 ChordRest* c = toChordRest(segment()->element(track() + i * VOICES));
2562 if (c && c->type() == CHORD) {
2563 QList<Note*> nl = toChord(c)->notes();
2564 int n = nl.size();
2565 for (int j = n - 1; j >= 0; --j) {
2566 Note* note = nl[j];
2567 if (note->tieBack())
2568 continue;
2569 notes.prepend(note);
2570 }
2571 }
2572 }
2573 #endif
2574 }
2575
2576 //---------------------------------------------------------
2577 // layoutNotesSpanners
2578 //---------------------------------------------------------
2579
layoutSpanners()2580 void Chord::layoutSpanners()
2581 {
2582 for (const Note* n : notes()) {
2583 Tie* tie = n->tieFor();
2584 if (tie)
2585 tie->layout();
2586 for (Spanner* sp : n->spannerBack())
2587 sp->layout();
2588 }
2589 }
2590
layoutSpanners(System * system,const Fraction & stick)2591 void Chord::layoutSpanners(System* system, const Fraction& stick)
2592 {
2593 //! REVIEW Needs explanation
2594 for (const Note* note : notes()) {
2595 Tie* t = note->tieFor();
2596 if (t)
2597 t->layoutFor(system);
2598 t = note->tieBack();
2599 if (t) {
2600 if (t->startNote()->tick() < stick)
2601 t->layoutBack(system);
2602 }
2603 for (Spanner* sp : note->spannerBack())
2604 sp->layout();
2605 }
2606 }
2607
2608 //---------------------------------------------------------
2609 // findNote
2610 //---------------------------------------------------------
2611
findNote(int pitch,int skip) const2612 Note* Chord::findNote(int pitch, int skip) const
2613 {
2614 size_t ns = _notes.size();
2615 for (size_t i = 0; i < ns; ++i) {
2616 Note* n = _notes.at(i);
2617 if (n->pitch() == pitch) {
2618 if (skip == 0)
2619 return n;
2620 else
2621 --skip;
2622 }
2623 }
2624 return 0;
2625 }
2626
2627 //---------------------------------------------------------
2628 // drop
2629 //---------------------------------------------------------
2630
drop(EditData & data)2631 Element* Chord::drop(EditData& data)
2632 {
2633 Element* e = data.dropElement;
2634 switch (e->type()) {
2635 case ElementType::ARTICULATION:
2636 {
2637 Articulation* atr = toArticulation(e);
2638 Articulation* oa = hasArticulation(atr);
2639 if (oa) {
2640 delete atr;
2641 atr = 0;
2642 // if attribute is already there, remove
2643 // score()->cmdRemove(oa); // unexpected behaviour?
2644 score()->select(oa, SelectType::SINGLE, 0);
2645 }
2646 else {
2647 atr->setParent(this);
2648 atr->setTrack(track());
2649 score()->undoAddElement(atr);
2650 }
2651 return atr;
2652 }
2653
2654 case ElementType::CHORDLINE:
2655 e->setParent(this);
2656 e->setTrack(track());
2657 score()->undoAddElement(e);
2658 break;
2659
2660 case ElementType::TREMOLO:
2661 {
2662 Tremolo* t = toTremolo(e);
2663 if (t->twoNotes()) {
2664 Segment* s = segment()->next();
2665 while (s) {
2666 if (s->element(track()) && s->element(track())->isChord())
2667 break;
2668 s = s->next();
2669 }
2670 if (s == 0) {
2671 qDebug("no segment for second note of tremolo found");
2672 delete e;
2673 return 0;
2674 }
2675 Chord* ch2 = toChord(s->element(track()));
2676 if (ch2->ticks() != ticks()) {
2677 qDebug("no matching chord for second note of tremolo found");
2678 delete e;
2679 return 0;
2680 }
2681 t->setChords(this, ch2);
2682 }
2683 }
2684 if (tremolo())
2685 score()->undoRemoveElement(tremolo());
2686 e->setParent(this);
2687 e->setTrack(track());
2688 score()->undoAddElement(e);
2689 break;
2690
2691 case ElementType::ARPEGGIO:
2692 {
2693 Arpeggio* a = toArpeggio(e);
2694 if (arpeggio())
2695 score()->undoRemoveElement(arpeggio());
2696 a->setTrack(track());
2697 a->setParent(this);
2698 a->setHeight(spatium() * 5); //DEBUG
2699 score()->undoAddElement(a);
2700 }
2701 return e;
2702
2703 default:
2704 return ChordRest::drop(data);
2705 }
2706 return 0;
2707 }
2708
2709 //---------------------------------------------------------
2710 // dotPosX
2711 //---------------------------------------------------------
2712
dotPosX() const2713 qreal Chord::dotPosX() const
2714 {
2715 if (parent())
2716 return segment()->dotPosX(staffIdx());
2717 return -1000.0;
2718 }
2719
2720 //---------------------------------------------------------
2721 // localSpatiumChanged
2722 //---------------------------------------------------------
2723
localSpatiumChanged(qreal oldValue,qreal newValue)2724 void Chord::localSpatiumChanged(qreal oldValue, qreal newValue)
2725 {
2726 ChordRest::localSpatiumChanged(oldValue, newValue);
2727 for (Element* e : graceNotes())
2728 e->localSpatiumChanged(oldValue, newValue);
2729 if (_hook)
2730 _hook->localSpatiumChanged(oldValue, newValue);
2731 if (_stem)
2732 _stem->localSpatiumChanged(oldValue, newValue);
2733 if (_stemSlash)
2734 _stemSlash->localSpatiumChanged(oldValue, newValue);
2735 if (arpeggio())
2736 arpeggio()->localSpatiumChanged(oldValue, newValue);
2737 if (_tremolo && (tremoloChordType() != TremoloChordType::TremoloSecondNote))
2738 _tremolo->localSpatiumChanged(oldValue, newValue);
2739 for (Element* e : articulations())
2740 e->localSpatiumChanged(oldValue, newValue);
2741 for (Note* note : notes())
2742 note->localSpatiumChanged(oldValue, newValue);
2743 }
2744
2745 //---------------------------------------------------------
2746 // getProperty
2747 //---------------------------------------------------------
2748
getProperty(Pid propertyId) const2749 QVariant Chord::getProperty(Pid propertyId) const
2750 {
2751 switch (propertyId) {
2752 case Pid::NO_STEM: return noStem();
2753 case Pid::SMALL: return small();
2754 case Pid::STEM_DIRECTION: return QVariant::fromValue<Direction>(stemDirection());
2755 default:
2756 return ChordRest::getProperty(propertyId);
2757 }
2758 }
2759
2760 //---------------------------------------------------------
2761 // propertyDefault
2762 //---------------------------------------------------------
2763
propertyDefault(Pid propertyId) const2764 QVariant Chord::propertyDefault(Pid propertyId) const
2765 {
2766 switch (propertyId) {
2767 case Pid::NO_STEM: return false;
2768 case Pid::SMALL: return false;
2769 case Pid::STEM_DIRECTION: return QVariant::fromValue<Direction>(Direction::AUTO);
2770 default:
2771 return ChordRest::propertyDefault(propertyId);
2772 }
2773 }
2774
2775 //---------------------------------------------------------
2776 // setProperty
2777 //---------------------------------------------------------
2778
setProperty(Pid propertyId,const QVariant & v)2779 bool Chord::setProperty(Pid propertyId, const QVariant& v)
2780 {
2781 switch (propertyId) {
2782 case Pid::NO_STEM:
2783 setNoStem(v.toBool());
2784 break;
2785 case Pid::SMALL:
2786 setSmall(v.toBool());
2787 break;
2788 case Pid::STEM_DIRECTION:
2789 setStemDirection(v.value<Direction>());
2790 break;
2791 default:
2792 return ChordRest::setProperty(propertyId, v);
2793 }
2794 triggerLayout();
2795 return true;
2796 }
2797
2798 //---------------------------------------------------------
2799 // hasArticulation
2800 //---------------------------------------------------------
2801
hasArticulation(const Articulation * aa)2802 Articulation* Chord::hasArticulation(const Articulation* aa)
2803 {
2804 for (Articulation* a : qAsConst(_articulations)) {
2805 if (a->subtype() == aa->subtype())
2806 return a;
2807 }
2808 return 0;
2809 }
2810
2811 //---------------------------------------------------------
2812 // reset
2813 //---------------------------------------------------------
2814
reset()2815 void Chord::reset()
2816 {
2817 undoChangeProperty(Pid::STEM_DIRECTION, QVariant::fromValue<Direction>(Direction::AUTO));
2818 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::AUTO));
2819 score()->createPlayEvents(this);
2820 ChordRest::reset();
2821 }
2822
2823 //---------------------------------------------------------
2824 // slash
2825 //---------------------------------------------------------
2826
slash()2827 bool Chord::slash()
2828 {
2829 Note* n = upNote();
2830 return n->fixed();
2831 }
2832
2833 //---------------------------------------------------------
2834 // setSlash
2835 //---------------------------------------------------------
2836
setSlash(bool flag,bool stemless)2837 void Chord::setSlash(bool flag, bool stemless)
2838 {
2839 int line = 0;
2840 NoteHead::Group head = NoteHead::Group::HEAD_SLASH;
2841
2842 if (!flag) {
2843 // restore to normal
2844 undoChangeProperty(Pid::NO_STEM, false);
2845 undoChangeProperty(Pid::SMALL, false);
2846 undoChangeProperty(Pid::OFFSET, QPointF());
2847 for (Note* n : _notes) {
2848 n->undoChangeProperty(Pid::HEAD_GROUP, int(NoteHead::Group::HEAD_NORMAL));
2849 n->undoChangeProperty(Pid::FIXED, false);
2850 n->undoChangeProperty(Pid::FIXED_LINE, 0);
2851 n->undoChangeProperty(Pid::PLAY, true);
2852 n->undoChangeProperty(Pid::VISIBLE, true);
2853 if (staff()->isDrumStaff(tick())) {
2854 const Drumset* ds = part()->instrument(tick())->drumset();
2855 int pitch = n->pitch();
2856 if (ds && ds->isValid(pitch)) {
2857 undoChangeProperty(Pid::STEM_DIRECTION, QVariant::fromValue<Direction>(ds->stemDirection(pitch)));
2858 n->undoChangeProperty(Pid::HEAD_GROUP, int(ds->noteHead(pitch)));
2859 }
2860 }
2861 }
2862 return;
2863 }
2864
2865 // set stem to auto (mostly important for rhythmic notation on drum staves)
2866 undoChangeProperty(Pid::STEM_DIRECTION, QVariant::fromValue<Direction>(Direction::AUTO));
2867
2868 // make stemless if asked
2869 if (stemless) {
2870 undoChangeProperty(Pid::NO_STEM, true);
2871 undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::NONE));
2872 }
2873
2874 // voice-dependent attributes - line, size, offset, head
2875 if (track() % VOICES < 2) {
2876 // use middle line
2877 line = staff()->middleLine(tick());
2878 }
2879 else {
2880 // set small
2881 undoChangeProperty(Pid::SMALL, true);
2882 // set outside the staff
2883 qreal y = 0.0;
2884 if (track() % 2) {
2885 line = staff()->bottomLine(tick()) + 1;
2886 y = 0.5 * spatium();
2887 }
2888 else {
2889 line = -1;
2890 if (!staff()->isDrumStaff(tick()))
2891 y = -0.5 * spatium();
2892 }
2893 // for non-drum staves, add an additional offset
2894 // for drum staves, no offset, but use normal head
2895 if (!staff()->isDrumStaff(tick()))
2896 // undoChangeProperty(Pid::OFFSET, QPointF(0.0, y));
2897 rypos() += y;
2898 else
2899 head = NoteHead::Group::HEAD_NORMAL;
2900 }
2901
2902 size_t ns = _notes.size();
2903 for (size_t i = 0; i < ns; ++i) {
2904 Note* n = _notes[i];
2905 n->undoChangeProperty(Pid::HEAD_GROUP, static_cast<int>(head));
2906 n->undoChangeProperty(Pid::FIXED, true);
2907 n->undoChangeProperty(Pid::FIXED_LINE, line);
2908 n->undoChangeProperty(Pid::PLAY, false);
2909 // hide all but first notehead
2910 if (i)
2911 n->undoChangeProperty(Pid::VISIBLE, false);
2912 }
2913 }
2914
2915 //---------------------------------------------------------
2916 // updateEndsGlissando
2917 // sets/resets the chord _endsGlissando according any glissando (or more)
2918 // end into this chord or no.
2919 //---------------------------------------------------------
2920
updateEndsGlissando()2921 void Chord::updateEndsGlissando()
2922 {
2923 _endsGlissando = false; // assume no glissando ends here
2924 // scan all chord notes for glissandi ending on this chord
2925 for (Note* note : notes()) {
2926 for (Spanner* sp : note->spannerBack())
2927 if (sp->type() == ElementType::GLISSANDO) {
2928 _endsGlissando = true;
2929 return;
2930 }
2931 }
2932 }
2933
2934 //---------------------------------------------------------
2935 // removeMarkings
2936 // - this is normally called after cloning a chord to tie a note over the barline
2937 // - there is no special undo handling; the assumption is that undo will simply remove the cloned chord
2938 // - two note tremolos are converted into simple notes
2939 // - single note tremolos are optionally retained
2940 //---------------------------------------------------------
2941
removeMarkings(bool keepTremolo)2942 void Chord::removeMarkings(bool keepTremolo)
2943 {
2944 if (tremolo() && !keepTremolo)
2945 remove(tremolo());
2946 if (arpeggio())
2947 remove(arpeggio());
2948 qDeleteAll(graceNotes());
2949 graceNotes().clear();
2950 qDeleteAll(articulations());
2951 articulations().clear();
2952 for (Note* n : notes()) {
2953 for (Element* e : n->el())
2954 n->remove(e);
2955 }
2956 ChordRest::removeMarkings(keepTremolo);
2957 }
2958
2959 //---------------------------------------------------------
2960 // chordMag
2961 //---------------------------------------------------------
2962
chordMag() const2963 qreal Chord::chordMag() const
2964 {
2965 qreal m = 1.0;
2966 if (small())
2967 m *= score()->styleD(Sid::smallNoteMag);
2968 if (_noteType != NoteType::NORMAL)
2969 m *= score()->styleD(Sid::graceNoteMag);
2970 return m;
2971 }
2972
2973 //---------------------------------------------------------
2974 // mag
2975 //---------------------------------------------------------
2976
mag() const2977 qreal Chord::mag() const
2978 {
2979 const Staff* st = staff();
2980 return (st ? st->mag(this) : 1.0) * chordMag();
2981 }
2982
2983 //---------------------------------------------------------
2984 // segment
2985 //---------------------------------------------------------
2986
segment() const2987 Segment* Chord::segment() const
2988 {
2989 Element* e = parent();
2990 for (; e && e->type() != ElementType::SEGMENT; e = e->parent())
2991 ;
2992 return toSegment(e);
2993 }
2994
2995 //---------------------------------------------------------
2996 // measure
2997 //---------------------------------------------------------
2998
measure() const2999 Measure* Chord::measure() const
3000 {
3001 Element* e = parent();
3002 for (; e && e->type() != ElementType::MEASURE; e = e->parent())
3003 ;
3004 return toMeasure(e);
3005 }
3006
3007 //---------------------------------------------------------
3008 // graceNotesBefore
3009 //---------------------------------------------------------
3010
graceNotesBefore() const3011 QVector<Chord*> Chord::graceNotesBefore() const
3012 {
3013 QVector<Chord*> cl;
3014 for (Chord* c : _graceNotes) {
3015 Q_ASSERT(c->noteType() != NoteType::NORMAL && c->noteType() != NoteType::INVALID);
3016 if (c->noteType() & (
3017 NoteType::ACCIACCATURA
3018 | NoteType::APPOGGIATURA
3019 | NoteType::GRACE4
3020 | NoteType::GRACE16
3021 | NoteType::GRACE32)) {
3022 cl.push_back(c);
3023 }
3024 }
3025 return cl;
3026 }
3027
3028 //---------------------------------------------------------
3029 // graceNotesAfter
3030 //---------------------------------------------------------
3031
graceNotesAfter() const3032 QVector<Chord*> Chord::graceNotesAfter() const
3033 {
3034 QVector<Chord*> cl;
3035 for (int i = _graceNotes.size() - 1; i >= 0; i--) {
3036 Chord* c = _graceNotes[i];
3037 Q_ASSERT(c->noteType() != NoteType::NORMAL && c->noteType() != NoteType::INVALID);
3038 if (c->noteType() & (NoteType::GRACE8_AFTER | NoteType::GRACE16_AFTER | NoteType::GRACE32_AFTER))
3039 cl.push_back(c);
3040 }
3041 return cl;
3042 }
3043
3044 //---------------------------------------------------------
3045 // sortNotes
3046 //---------------------------------------------------------
3047
noteIsBefore(const Note * n1,const Note * n2)3048 static bool noteIsBefore(const Note* n1, const Note* n2)
3049 {
3050 const int l1 = n1->line();
3051 const int l2 = n2->line();
3052 if (l1 != l2)
3053 return l1 > l2;
3054
3055 const int p1 = n1->pitch();
3056 const int p2 = n2->pitch();
3057 if (p1 != p2)
3058 return p1 < p2;
3059
3060 if (n1->tieBack()) {
3061 if (n2->tieBack()) {
3062 const Note* sn1 = n1->tieBack()->startNote();
3063 const Note* sn2 = n2->tieBack()->startNote();
3064 if (sn1->chord() == sn2->chord())
3065 return sn1->unisonIndex() < sn2->unisonIndex();
3066 return sn1->chord()->isBefore(sn2->chord());
3067 }
3068 else
3069 return true; // place tied notes before
3070 }
3071
3072 return false;
3073 }
3074
sortNotes()3075 void Chord::sortNotes()
3076 {
3077 std::sort(notes().begin(), notes().end(), noteIsBefore);
3078 }
3079
3080 //---------------------------------------------------------
3081 // nextTiedChord
3082 // Return next chord if all notes in this chord are tied to it.
3083 // Set backwards=true to return the previous chord instead.
3084 //
3085 // Note: the next chord might have extra notes that are not tied
3086 // back to this one. Set sameSize=true to return 0 in this case.
3087 //---------------------------------------------------------
3088
nextTiedChord(bool backwards,bool sameSize)3089 Chord* Chord::nextTiedChord(bool backwards, bool sameSize)
3090 {
3091 Segment* nextSeg = backwards ? segment()->prev1(SegmentType::ChordRest) : segment()->next1(SegmentType::ChordRest);
3092 if (!nextSeg)
3093 return 0;
3094 ChordRest* nextCR = nextSeg->nextChordRest(track(), backwards);
3095 if (!nextCR || !nextCR->isChord())
3096 return 0;
3097 Chord* next = toChord(nextCR);
3098 if (sameSize && notes().size() != next->notes().size())
3099 return 0; // sizes don't match so some notes can't be tied
3100 if (tuplet() != next->tuplet())
3101 return 0; // next chord belongs to a different tuplet
3102 for (Note* n : _notes) {
3103 Tie* tie = backwards ? n->tieBack() : n->tieFor();
3104 if (!tie)
3105 return 0; // not tied
3106 Note* nn = backwards ? tie->startNote() : tie->endNote();
3107 if (!nn || nn->chord() != next)
3108 return 0; // tied to note in wrong voice, or tied over rest
3109 }
3110 return next; // all notes in this chord are tied to notes in next chord
3111 }
3112
3113 //---------------------------------------------------------
3114 // toGraceAfter
3115 //---------------------------------------------------------
3116
toGraceAfter()3117 void Chord::toGraceAfter()
3118 {
3119 switch (noteType()) {
3120 case NoteType::APPOGGIATURA: setNoteType(NoteType::GRACE8_AFTER); break;
3121 case NoteType::GRACE16: setNoteType(NoteType::GRACE16_AFTER); break;
3122 case NoteType::GRACE32: setNoteType(NoteType::GRACE32_AFTER); break;
3123 default: break;
3124 }
3125 }
3126
3127 //---------------------------------------------------------
3128 // tremoloChordType
3129 //---------------------------------------------------------
3130
tremoloChordType() const3131 TremoloChordType Chord::tremoloChordType() const
3132 {
3133 if (_tremolo && _tremolo->twoNotes()) {
3134 if (_tremolo->chord1() == this)
3135 return TremoloChordType::TremoloFirstNote;
3136 else if (_tremolo->chord2() == this)
3137 return TremoloChordType::TremoloSecondNote;
3138 else
3139 qFatal("Chord::tremoloChordType(): inconsistency %p - %p, this is %p", _tremolo->chord1(), _tremolo->chord2(), this);
3140 }
3141 return TremoloChordType::TremoloSingle;
3142 }
3143
3144 //---------------------------------------------------------
3145 // nextElement
3146 //---------------------------------------------------------
3147
nextElement()3148 Element* Chord::nextElement()
3149 {
3150 Element* e = score()->selection().element();
3151 if (!e && !score()->selection().elements().isEmpty())
3152 e = score()->selection().elements().first();
3153
3154 switch(e->type()) {
3155 case ElementType::SYMBOL:
3156 case ElementType::IMAGE:
3157 case ElementType::FINGERING:
3158 case ElementType::TEXT:
3159 case ElementType::BEND: {
3160 Note* n = toNote(e->parent());
3161 if(n == _notes.front()) {
3162 if (_arpeggio)
3163 return _arpeggio;
3164 else if (_tremolo)
3165 return _tremolo;
3166 break;
3167 }
3168 for (auto &i : _notes) {
3169 if (i == n) {
3170 return *(&i-1);
3171 }
3172 }
3173 break;
3174 }
3175
3176 case ElementType::GLISSANDO_SEGMENT:
3177 case ElementType::TIE_SEGMENT: {
3178 SpannerSegment* s = toSpannerSegment(e);
3179 Spanner* sp = s->spanner();
3180 Element* elSt = sp->startElement();
3181 Q_ASSERT(elSt->type() == ElementType::NOTE);
3182 Note* n = toNote(elSt);
3183 Q_ASSERT(n != NULL);
3184 if (n == _notes.front()) {
3185 if (_arpeggio)
3186 return _arpeggio;
3187 else if (_tremolo)
3188 return _tremolo;
3189 break;
3190 }
3191 for (auto &i : _notes) {
3192 if (i == n) {
3193 return *(&i-1);
3194 }
3195 }
3196 break;
3197 }
3198 case ElementType::ARPEGGIO:
3199 if (_tremolo)
3200 return _tremolo;
3201 break;
3202
3203 case ElementType::ACCIDENTAL:
3204 e = e->parent();
3205 // fall through
3206
3207 case ElementType::NOTE: {
3208 if (e == _notes.front()) {
3209 if (_arpeggio)
3210 return _arpeggio;
3211 else if (_tremolo)
3212 return _tremolo;
3213 break;
3214 }
3215 for (auto &i : _notes) {
3216 if (i == e)
3217 return *(&i -1);
3218 }
3219 }
3220 break;
3221
3222 case ElementType::CHORD:
3223 return _notes.back();
3224
3225 default:
3226 break;
3227 }
3228
3229 return ChordRest::nextElement();
3230 }
3231
3232 //---------------------------------------------------------
3233 // prevElement
3234 //---------------------------------------------------------
3235
prevElement()3236 Element* Chord::prevElement()
3237 {
3238 Element* e = score()->selection().element();
3239 if (!e && !score()->selection().elements().isEmpty())
3240 e = score()->selection().elements().last();
3241 switch (e->type()) {
3242 case ElementType::NOTE: {
3243 if (e == _notes.back())
3244 break;
3245 Note* prevNote = nullptr;
3246 for (auto &i : _notes) {
3247 if (i == e) {
3248 prevNote = *(&i+1);
3249 }
3250 }
3251 Element* next = prevNote->lastElementBeforeSegment();
3252 return next;
3253 }
3254
3255 case ElementType::CHORD:
3256 return _notes.front();
3257
3258 case ElementType::TREMOLO:
3259 if (_arpeggio)
3260 return _arpeggio;
3261 // fall through
3262
3263 case ElementType::ARPEGGIO: {
3264 Note* n = _notes.front();
3265 Element* elN = n->lastElementBeforeSegment();
3266 Q_ASSERT(elN != NULL);
3267 return elN;
3268 }
3269
3270 default:
3271 break;
3272 }
3273 return ChordRest::prevElement();
3274 }
3275
3276 //---------------------------------------------------------
3277 // lastElementBeforeSegment
3278 //---------------------------------------------------------
3279
lastElementBeforeSegment()3280 Element* Chord::lastElementBeforeSegment()
3281 {
3282 if (_tremolo) {
3283 return _tremolo;
3284 }
3285 else if (_arpeggio) {
3286 return _arpeggio;
3287 }
3288 else {
3289 Note* n = _notes.front();
3290 Element* elN = n->lastElementBeforeSegment();
3291 Q_ASSERT(elN != NULL);
3292 return elN;
3293 }
3294 }
3295
3296 //---------------------------------------------------------
3297 // nextSegmentElement
3298 //---------------------------------------------------------
3299
nextSegmentElement()3300 Element* Chord::nextSegmentElement()
3301 {
3302 for (int v = track() + 1; staffIdx() == v/VOICES; ++v) {
3303 Element* e = segment()->element(v);
3304 if (e) {
3305 if (e->type() == ElementType::CHORD)
3306 return toChord(e)->notes().back();
3307
3308 return e;
3309 }
3310 }
3311
3312 return ChordRest::nextSegmentElement();
3313 }
3314
3315 //---------------------------------------------------------
3316 // prevSegmentElement
3317 //---------------------------------------------------------
3318
prevSegmentElement()3319 Element* Chord::prevSegmentElement()
3320 {
3321 Element* el = score()->selection().element();
3322 if (!el && !score()->selection().elements().isEmpty() )
3323 el = score()->selection().elements().first();
3324 Element* e = segment()->lastInPrevSegments(el->staffIdx());
3325 if (e) {
3326 if (e->isChord())
3327 return toChord(e)->notes().front();
3328 return e;
3329 }
3330
3331 return ChordRest::prevSegmentElement();
3332 }
3333
3334 //---------------------------------------------------------
3335 // accessibleExtraInfo
3336 //---------------------------------------------------------
3337
accessibleExtraInfo() const3338 QString Chord::accessibleExtraInfo() const
3339 {
3340 QString rez = "";
3341
3342 for (const Chord* c : graceNotes()) {
3343 if (!score()->selectionFilter().canSelect(c))
3344 continue;
3345 for (const Note* n : c->notes())
3346 rez = QString("%1 %2").arg(rez, n->screenReaderInfo());
3347 }
3348
3349 for (Articulation* a : articulations()) {
3350 if (!score()->selectionFilter().canSelect(a))
3351 continue;
3352 rez = QString("%1 %2").arg(rez, a->screenReaderInfo());
3353 }
3354
3355 if (arpeggio() && score()->selectionFilter().canSelect(arpeggio()))
3356 rez = QString("%1 %2").arg(rez, arpeggio()->screenReaderInfo());
3357
3358 if (tremolo() && score()->selectionFilter().canSelect(tremolo()))
3359 rez = QString("%1 %2").arg(rez, tremolo()->screenReaderInfo());
3360
3361 foreach (Element* e, el()) {
3362 if (!score()->selectionFilter().canSelect(e))
3363 continue;
3364 rez = QString("%1 %2").arg(rez, e->screenReaderInfo());
3365 }
3366
3367 return QString("%1 %2").arg(rez, ChordRest::accessibleExtraInfo());
3368 }
3369
3370 //---------------------------------------------------------
3371 // shape
3372 // does not contain articulations
3373 //---------------------------------------------------------
3374
shape() const3375 Shape Chord::shape() const
3376 {
3377 Shape shape;
3378 if (_hook && _hook->addToSkyline())
3379 shape.add(_hook->shape().translated(_hook->pos()));
3380 if (_stem && _stem->addToSkyline()) {
3381 // stem direction is not known soon enough for cross staff beamed notes
3382 if (!(beam() && (staffMove() || beam()->cross())))
3383 shape.add(_stem->shape().translated(_stem->pos()));
3384 }
3385 if (_stemSlash && _stemSlash->addToSkyline())
3386 shape.add(_stemSlash->shape().translated(_stemSlash->pos()));
3387 if (_arpeggio && _arpeggio->addToSkyline())
3388 shape.add(_arpeggio->shape().translated(_arpeggio->pos()));
3389 // if (_tremolo)
3390 // shape.add(_tremolo->shape().translated(_tremolo->pos()));
3391 for (Note* note : _notes) {
3392 shape.add(note->shape().translated(note->pos()));
3393 for (Element* e : note->el()) {
3394 if (!e->addToSkyline())
3395 continue;
3396 if (e->isFingering() && toFingering(e)->layoutType() == ElementType::CHORD && e->bbox().isValid())
3397 shape.add(e->bbox().translated(e->pos() + note->pos()));
3398 }
3399 }
3400 for (Element* e : el()) {
3401 if (e->addToSkyline())
3402 shape.add(e->shape().translated(e->pos()));
3403 }
3404 for (Chord* chord : _graceNotes) // process grace notes last, needed for correct shape calculation
3405 shape.add(chord->shape().translated(chord->pos()));
3406 shape.add(ChordRest::shape()); // add lyrics
3407 for (LedgerLine* l = _ledgerLines; l; l = l->next())
3408 shape.add(l->shape().translated(l->pos()));
3409 if (_spaceLw || _spaceRw)
3410 shape.addHorizontalSpacing(Shape::SPACING_GENERAL, -_spaceLw, _spaceRw);
3411 return shape;
3412 }
3413
3414 //---------------------------------------------------------
3415 // layoutArticulations
3416 // layout tenuto and staccato
3417 // called before layouting slurs
3418 //---------------------------------------------------------
3419
layoutArticulations()3420 void Chord::layoutArticulations()
3421 {
3422 for (Chord* gc : graceNotes())
3423 gc->layoutArticulations();
3424
3425 if (_articulations.empty())
3426 return;
3427 const Staff* st = staff();
3428 const StaffType* staffType = st->staffTypeForElement(this);
3429 qreal mag = (staffType->small() ? score()->styleD(Sid::smallStaffMag) : 1.0) * staffType->userMag();
3430 qreal _spatium = score()->spatium() * mag;
3431 qreal _spStaff = _spatium * staffType->lineDistance().val();
3432
3433 //
3434 // determine direction
3435 // place tenuto and staccato
3436 //
3437
3438 Articulation* prevArticulation = nullptr;
3439 for (Articulation* a : qAsConst(_articulations)) {
3440 if (a->anchor() == ArticulationAnchor::CHORD) {
3441 if (measure()->hasVoices(a->staffIdx(), tick(), actualTicks()))
3442 a->setUp(up()); // if there are voices place articulation at stem
3443 else if (a->symId() >= SymId::articMarcatoAbove && a->symId() <= SymId::articMarcatoTenutoBelow)
3444 a->setUp(true); // Gould, p. 117: strong accents above staff
3445 else if (isGrace() && up() && !a->layoutCloseToNote() && downNote()->line() < 6)
3446 a->setUp(true); // keep articulation close to grace note
3447 else
3448 a->setUp(!up()); // place articulation at note head
3449 }
3450 else
3451 a->setUp(a->anchor() == ArticulationAnchor::TOP_STAFF || a->anchor() == ArticulationAnchor::TOP_CHORD);
3452
3453 if (!a->layoutCloseToNote())
3454 continue;
3455
3456 bool bottom = !a->up(); // true: articulation is below chord; false: articulation is above chord
3457 a->layout(); // must be done after assigning direction, or else symId is not reliable
3458
3459 bool headSide = bottom == up();
3460 qreal x = centerX();
3461 qreal y = 0.0;
3462
3463 if (bottom) {
3464 if (!headSide && stem()) {
3465 y = upPos() + stem()->stemLen();
3466 if (beam())
3467 y += score()->styleS(Sid::beamWidth).val() * _spatium * .5;
3468 int line = lrint((y + 0.5 * _spStaff) / _spStaff);
3469 if (line < staffType->lines()) // align between staff lines
3470 y = line * _spStaff + _spatium * .5;
3471 else
3472 y += _spatium;
3473 if (a->isStaccato() && articulations().size() == 1) {
3474 if (_up)
3475 x = downNote()->bboxRightPos() - stem()->width() * .5;
3476 else
3477 x = stem()->width() * .5;
3478 }
3479 }
3480 else {
3481 int line = downLine();
3482 int lines = (staffType->lines() - 1) * 2;
3483 if (line < lines)
3484 y = ((line & ~1) + 3) * _spStaff;
3485 else
3486 y = line * _spStaff + 2 * _spatium;
3487 y *= .5;
3488 }
3489 if (prevArticulation && (prevArticulation->up() == a->up()))
3490 y += _spatium;
3491 y -= a->height() * .5; // center symbol
3492 }
3493 else {
3494 if (!headSide && stem()) {
3495 y = downPos() + stem()->stemLen();
3496 if (beam())
3497 y -= score()->styleS(Sid::beamWidth).val() * _spatium * .5;
3498 int line = lrint((y-0.5*_spStaff) / _spStaff);
3499 if (line >= 0) // align between staff lines
3500 y = line * _spStaff - _spatium * .5;
3501 else
3502 y -= _spatium;
3503 if (a->isStaccato() && articulations().size() == 1) {
3504 if (_up)
3505 x = downNote()->bboxRightPos() - stem()->width() * .5;
3506 else
3507 x = stem()->width() * .5;
3508 }
3509 }
3510 else {
3511 int line = upLine();
3512 if (line > 0)
3513 y = (((line+1) & ~1) - 3) * _spStaff;
3514 else
3515 y = line * _spStaff - 2 * _spatium;
3516 y *= .5;
3517 }
3518 if (prevArticulation && (prevArticulation->up() == a->up()))
3519 y -= _spatium;
3520 y += a->height() * .5; // center symbol
3521 }
3522 a->setPos(x, y);
3523 prevArticulation = a;
3524 // measure()->system()->staff(a->staffIdx())->skyline().add(a->shape().translated(a->pos() + segment()->pos() + measure()->pos()));
3525 }
3526 }
3527
3528 //---------------------------------------------------------
3529 // layoutArticulations2
3530 // Called after layouting systems
3531 // Tentatively layout all articulations
3532 // To be finished after laying out slurs
3533 //---------------------------------------------------------
3534
layoutArticulations2()3535 void Chord::layoutArticulations2()
3536 {
3537 for (Chord* gc : graceNotes())
3538 gc->layoutArticulations2();
3539
3540 if (_articulations.empty())
3541 return;
3542 qreal _spatium = spatium();
3543 qreal x = centerX();
3544 qreal distance0 = score()->styleP(Sid::propertyDistance);
3545 qreal distance2 = score()->styleP(Sid::propertyDistanceStem);
3546
3547 qreal chordTopY = upPos(); // note position of highest note
3548 qreal chordBotY = downPos(); // note position of lowest note
3549
3550 qreal staffTopY = -distance2;
3551 qreal staffBotY = staff()->height() + distance2;
3552
3553 // avoid collisions of staff articulations with chord notes:
3554 // gap between note and staff articulation is distance0 + 0.5 spatium
3555
3556 if (stem()) {
3557 qreal y = stem()->pos().y() + pos().y() + stem()->stemLen();
3558 if (beam()) {
3559 qreal bw = score()->styleS(Sid::beamWidth).val() * _spatium;
3560 y += up() ? -bw : bw;
3561 }
3562 if (up())
3563 chordTopY = y;
3564 else
3565 chordBotY = y;
3566 }
3567
3568 //
3569 // place all articulations with anchor at chord/rest
3570 //
3571 qreal distance1 = score()->styleP(Sid::propertyDistanceHead);
3572 chordTopY -= up() ? 0.5 * _spatium : distance1;
3573 chordBotY += up() ? distance1 : 0.5 * _spatium;
3574 for (Articulation* a : qAsConst(_articulations)) {
3575 ArticulationAnchor aa = a->anchor();
3576 if (aa != ArticulationAnchor::CHORD && aa != ArticulationAnchor::TOP_CHORD && aa != ArticulationAnchor::BOTTOM_CHORD)
3577 continue;
3578
3579 if (a->up()) {
3580 if (!a->layoutCloseToNote()) {
3581 a->layout();
3582 a->setPos(x, chordTopY);
3583 a->doAutoplace();
3584 }
3585 if (a->visible())
3586 chordTopY = a->y() - a->height() - 0.5 * _spatium;
3587 }
3588 else {
3589 if (!a->layoutCloseToNote()) {
3590 a->layout();
3591 a->setPos(x, chordBotY);
3592 a->doAutoplace();
3593 }
3594 if (a->visible())
3595 chordBotY = a->y() + a->height() + 0.5 * _spatium;
3596 }
3597 }
3598 //
3599 // now place all articulations with staff top or bottom anchor
3600 //
3601
3602 staffTopY = qMin(staffTopY, chordTopY - distance0 - 0.5 * _spatium);
3603 staffBotY = qMax(staffBotY, chordBotY + distance0 + 0.5 * _spatium);
3604 for (Articulation* a : qAsConst(_articulations)) {
3605 ArticulationAnchor aa = a->anchor();
3606 if (aa == ArticulationAnchor::TOP_STAFF || aa == ArticulationAnchor::BOTTOM_STAFF) {
3607 a->layout();
3608 if (a->up()) {
3609 a->setPos(x, staffTopY);
3610 if (a->visible())
3611 staffTopY -= distance0;
3612 }
3613 else {
3614 a->setPos(x, staffBotY);
3615 if (a->visible())
3616 staffBotY += distance0;
3617 }
3618 a->doAutoplace();
3619 }
3620 }
3621 for (Articulation* a : qAsConst(_articulations)) {
3622 if (a->addToSkyline()) {
3623 // the segment shape has already been calculated
3624 // so measure width and spacing is already determined
3625 // in line mode, we cannot add to segment shape without throwing this off
3626 // but adding to skyline is always good
3627 Segment* s = segment();
3628 Measure* m = s->measure();
3629 QRectF r = a->bbox().translated(a->pos() + pos());
3630 // TODO: limit to width of chord
3631 // this avoids "staircase" effect due to space not having been allocated already
3632 // ANOTHER alternative is to allocate the space in layoutPitched() / layoutTablature()
3633 //qreal w = qMin(r.width(), width());
3634 //r.translate((r.width() - w) * 0.5, 0.0);
3635 //r.setWidth(w);
3636 if (!score()->lineMode())
3637 s->staffShape(staffIdx()).add(r);
3638 r.translate(s->pos() + m->pos());
3639 m->system()->staff(vStaffIdx())->skyline().add(r);
3640 }
3641 }
3642 }
3643
3644 //---------------------------------------------------------
3645 // layoutArticulations3
3646 // Called after layouting slurs
3647 // Fix up articulations that need to go outside the slur
3648 //---------------------------------------------------------
3649
layoutArticulations3(Slur * slur)3650 void Chord::layoutArticulations3(Slur* slur)
3651 {
3652 SlurSegment* ss;
3653 if (this == slur->startCR())
3654 ss = slur->frontSegment();
3655 else if (this == slur->endCR())
3656 ss = slur->backSegment();
3657 else
3658 return;
3659 Segment* s = segment();
3660 Measure* m = measure();
3661 SysStaff* sstaff = m->system() ? m->system()->staff(vStaffIdx()) : nullptr;
3662 for (Articulation* a : qAsConst(_articulations)) {
3663 if (a->layoutCloseToNote() || !a->autoplace() || !slur->addToSkyline())
3664 continue;
3665 Shape aShape = a->shape().translated(a->pos() + pos() + s->pos() + m->pos());
3666 Shape sShape = ss->shape().translated(ss->pos());
3667 if (aShape.intersects(sShape)) {
3668 qreal d = score()->styleS(Sid::articulationMinDistance).val() * spatium();
3669 if (slur->up()) {
3670 d += qMax(aShape.minVerticalDistance(sShape), 0.0);
3671 a->rypos() -= d;
3672 aShape.translateY(-d);
3673 }
3674 else {
3675 d += qMax(sShape.minVerticalDistance(aShape), 0.0);
3676 a->rypos() += d;
3677 aShape.translateY(d);
3678 }
3679 if (sstaff && a->addToSkyline())
3680 sstaff->skyline().add(aShape);
3681 }
3682 }
3683 }
3684
3685 //---------------------------------------------------------
3686 // getNoteEventLists
3687 // Get contents of all NoteEventLists for all notes in
3688 // the chord.
3689 //---------------------------------------------------------
3690
getNoteEventLists()3691 QList<NoteEventList> Chord::getNoteEventLists()
3692 {
3693 QList<NoteEventList> ell;
3694 if (notes().empty())
3695 return ell;
3696 for (size_t i = 0; i < notes().size(); ++i) {
3697 ell.append(NoteEventList(notes()[i]->playEvents()));
3698 }
3699 return ell;
3700 }
3701
3702 //---------------------------------------------------------
3703 // setNoteEventLists
3704 // Set contents of all NoteEventLists for all notes in
3705 // the chord.
3706 //---------------------------------------------------------
3707
setNoteEventLists(QList<NoteEventList> & ell)3708 void Chord::setNoteEventLists(QList<NoteEventList>& ell)
3709 {
3710 if (notes().empty())
3711 return;
3712 Q_ASSERT(ell.size() == int(notes().size()));
3713 for (size_t i = 0; int(i) < ell.size(); i++) {
3714 notes()[i]->setPlayEvents(ell[int(i)]);
3715 }
3716
3717 }
3718
3719 }
3720