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