1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2002-2016 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 "accidental.h"
14 #include "barline.h"
15 #include "beam.h"
16 #include "box.h"
17 #include "chord.h"
18 #include "clef.h"
19 #include "element.h"
20 #include "fingering.h"
21 #include "glissando.h"
22 #include "harmony.h"
23 #include "key.h"
24 #include "keysig.h"
25 #include "layoutbreak.h"
26 #include "layout.h"
27 #include "lyrics.h"
28 #include "marker.h"
29 #include "measure.h"
30 #include "mscore.h"
31 #include "notedot.h"
32 #include "note.h"
33 #include "ottava.h"
34 #include "page.h"
35 #include "part.h"
36 #include "repeat.h"
37 #include "score.h"
38 #include "segment.h"
39 #include "sig.h"
40 #include "slur.h"
41 #include "staff.h"
42 #include "stem.h"
43 #include "stemslash.h"
44 #include "sticking.h"
45 #include "style.h"
46 #include "sym.h"
47 #include "system.h"
48 #include "text.h"
49 #include "tie.h"
50 #include "timesig.h"
51 #include "tremolo.h"
52 #include "tuplet.h"
53 #include "undo.h"
54 #include "utils.h"
55 #include "volta.h"
56 #include "breath.h"
57 #include "tempotext.h"
58 #include "systemdivider.h"
59 #include "hook.h"
60 #include "ambitus.h"
61 #include "hairpin.h"
62 #include "stafflines.h"
63 #include "articulation.h"
64 #include "bracket.h"
65 #include "spacer.h"
66 #include "fermata.h"
67 #include "measurenumber.h"
68 
69 namespace Ms {
70 
71 // #define PAGE_DEBUG
72 
73 #ifdef PAGE_DEBUG
74 #define PAGEDBG(...)  qDebug(__VA_ARGS__)
75 #else
76 #define PAGEDBG(...)  ;
77 #endif
78 
79 //---------------------------------------------------------
80 //   rebuildBspTree
81 //---------------------------------------------------------
82 
rebuildBspTree()83 void Score::rebuildBspTree()
84       {
85       for (Page* page : pages())
86             page->rebuildBspTree();
87       }
88 
89 //---------------------------------------------------------
90 //   layoutSegmentElements
91 //---------------------------------------------------------
92 
layoutSegmentElements(Segment * segment,int startTrack,int endTrack)93 static void layoutSegmentElements(Segment* segment, int startTrack, int endTrack)
94       {
95       for (int track = startTrack; track < endTrack; ++track) {
96             if (Element* e = segment->element(track))
97                   e->layout();
98             }
99       }
100 
101 #if 0
102 //---------------------------------------------------------
103 //   vUp
104 //    reurns true if chord should be treated as up
105 //    for purpose of setting horizontal position
106 //    for most chords, this is just chord->up()
107 //    but for notes on cross-staff beams, we take care to produce more consistent results
108 //    since the initial guess for up() may change during layout
109 //---------------------------------------------------------
110 static bool vUp(Chord* chord)
111       {
112       if (!chord)
113             return true;
114       else if (!chord->beam() || !chord->beam()->cross()) {
115             return chord->up();
116             }
117       else {
118             // cross-staff beam: we cannot know the actual direction of this chord until the beam layout,
119             // but that's too late - it won't work to lay out as if the chord is up on pass one but then down on pass two
120             // so just assign a logical direction based on attributes that won't change
121             // so chords can be laid out consistently on both passes
122             bool up;
123             if (chord->stemDirection() != Direction::AUTO)
124                   up = chord->stemDirection() == Direction::UP;
125             else if (chord->staffMove())
126                   up = chord->staffMove() > 0;
127             else if (chord->track() < chord->beam()->track())
128                   up = false;
129             else if (chord->track() > chord->beam()->track())
130                   up = true;
131             else if (chord->measure()->hasVoices(chord->staffIdx(), chord->tick(), chord->actualTicks()))
132                   up = !(chord->track() % 2);
133             else
134                   up = !chord->staff()->isTop();
135             return up;
136             }
137       }
138 #endif
139 
140 //---------------------------------------------------------
141 //   layoutChords1
142 //    - layout upstem and downstem chords
143 //    - offset as necessary to avoid conflict
144 //---------------------------------------------------------
145 
layoutChords1(Segment * segment,int staffIdx)146 void Score::layoutChords1(Segment* segment, int staffIdx)
147       {
148       const Staff* staff = Score::staff(staffIdx);
149       const int startTrack = staffIdx * VOICES;
150       const int endTrack   = startTrack + VOICES;
151       const Fraction tick = segment->tick();
152 
153       if (staff->isTabStaff(tick)) {
154             layoutSegmentElements(segment, startTrack, endTrack);
155             return;
156             }
157 
158       bool crossBeamFound = false;
159       std::vector<Note*> upStemNotes;
160       std::vector<Note*> downStemNotes;
161       int upVoices       = 0;
162       int downVoices     = 0;
163       qreal nominalWidth = noteHeadWidth() * staff->mag(tick);
164       qreal maxUpWidth   = 0.0;
165       qreal maxDownWidth = 0.0;
166       qreal maxUpMag     = 0.0;
167       qreal maxDownMag   = 0.0;
168 
169       // dots and hooks can affect layout of notes as well as vice versa
170       int upDots         = 0;
171       int downDots       = 0;
172       bool upHooks       = false;
173       bool downHooks     = false;
174 
175       // also check for grace notes
176       bool upGrace       = false;
177       bool downGrace     = false;
178 
179       for (int track = startTrack; track < endTrack; ++track) {
180             Element* e = segment->element(track);
181             if (e && e->isChord()) {
182                   Chord* chord = toChord(e);
183                   if (chord->beam() && chord->beam()->cross())
184                         crossBeamFound = true;
185                   bool hasGraceBefore = false;
186                   for (Chord* c : chord->graceNotes()) {
187                         if (c->isGraceBefore())
188                               hasGraceBefore = true;
189                         layoutChords2(c->notes(), c->up());       // layout grace note noteheads
190                         layoutChords3(c->notes(), staff, 0);      // layout grace note chords
191                         }
192                   if (chord->up()) {
193                         ++upVoices;
194                         upStemNotes.insert(upStemNotes.end(), chord->notes().begin(), chord->notes().end());
195                         upDots   = qMax(upDots, chord->dots());
196                         maxUpMag = qMax(maxUpMag, chord->mag());
197                         if (!upHooks)
198                               upHooks = chord->hook();
199                         if (hasGraceBefore)
200                               upGrace = true;
201                         }
202                   else {
203                         ++downVoices;
204                         downStemNotes.insert(downStemNotes.end(), chord->notes().begin(), chord->notes().end());
205                         downDots = qMax(downDots, chord->dots());
206                         maxDownMag = qMax(maxDownMag, chord->mag());
207                         if (!downHooks)
208                               downHooks = chord->hook();
209                         if (hasGraceBefore)
210                               downGrace = true;
211                         }
212                   }
213             }
214 
215       if (upVoices + downVoices) {
216             // TODO: use track as secondary sort criteria?
217             // otherwise there might be issues with unisons between voices
218             // in some corner cases
219 
220             maxUpWidth   = nominalWidth * maxUpMag;
221             maxDownWidth = nominalWidth * maxDownMag;
222 
223             // layout upstem noteheads
224             if (upVoices > 1) {
225                   std::sort(upStemNotes.begin(), upStemNotes.end(),
226                      [](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
227                   }
228             if (upVoices) {
229                   qreal hw = layoutChords2(upStemNotes, true);
230                   maxUpWidth = qMax(maxUpWidth, hw);
231                   }
232 
233             // layout downstem noteheads
234             if (downVoices > 1) {
235                   std::sort(downStemNotes.begin(), downStemNotes.end(),
236                      [](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
237                   }
238             if (downVoices) {
239                   qreal hw = layoutChords2(downStemNotes, false);
240                   maxDownWidth = qMax(maxDownWidth, hw);
241                   }
242 
243             qreal sp                 = staff->spatium(tick);
244             qreal upOffset           = 0.0;      // offset to apply to upstem chords
245             qreal downOffset         = 0.0;      // offset to apply to downstem chords
246             qreal dotAdjust          = 0.0;      // additional chord offset to account for dots
247             qreal dotAdjustThreshold = 0.0;      // if it exceeds this amount
248 
249             // centering adjustments for whole note, breve, and small chords
250             qreal centerUp          = 0.0;      // offset to apply in order to center upstem chords
251             qreal oversizeUp        = 0.0;      // adjustment to oversized upstem chord needed if laid out to the right
252             qreal centerDown        = 0.0;      // offset to apply in order to center downstem chords
253             qreal centerAdjustUp    = 0.0;      // adjustment to upstem chord needed after centering donwstem chord
254             qreal centerAdjustDown  = 0.0;      // adjustment to downstem chord needed after centering upstem chord
255 
256             // only center chords if they differ from nominal by at least this amount
257             // this avoids unnecessary centering on differences due only to floating point roundoff
258             // it also allows for the possibility of disabling centering
259             // for notes only "slightly" larger than nominal, like half notes
260             // but this will result in them not being aligned with each other between voices
261             // unless you change to left alignment as described in the comments below
262             qreal centerThreshold   = 0.01 * sp;
263 
264             // amount by which actual width exceeds nominal, adjusted for staff mag() only
265             qreal headDiff = maxUpWidth - nominalWidth;
266             // amount by which actual width exceeds nominal, adjusted for staff & chord/note mag()
267             qreal headDiff2 = maxUpWidth - nominalWidth * (maxUpMag / staff->mag(tick));
268             if (headDiff > centerThreshold) {
269                   // larger than nominal
270                   centerUp = headDiff * -0.5;
271                   // maxUpWidth is true width, but we no longer will care about that
272                   // instead, we care only about portion to right of origin
273                   maxUpWidth += centerUp;
274                   // to left align rather than center, delete both of the above
275                   if (headDiff2 > centerThreshold) {
276                         // if max notehead is wider than nominal with chord/note mag() applied
277                         // then noteheads extend to left of origin
278                         // because stemPosX() is based on nominal width
279                         // so we need to correct for that too
280                         centerUp += headDiff2;
281                         oversizeUp = headDiff2;
282                         }
283                   }
284             else if (-headDiff > centerThreshold) {
285                   // smaller than nominal
286                   centerUp = -headDiff * 0.5;
287                   if (headDiff2 > centerThreshold) {
288                         // max notehead is wider than nominal with chord/note mag() applied
289                         // perform same adjustment as above
290                         centerUp += headDiff2;
291                         oversizeUp = headDiff2;
292                         }
293                   centerAdjustDown = centerUp;
294                   }
295 
296             headDiff = maxDownWidth - nominalWidth;
297             if (headDiff > centerThreshold) {
298                   // larger than nominal
299                   centerDown = headDiff * -0.5;
300                   // to left align rather than center, change the above to
301                   //centerAdjustUp = headDiff;
302                   maxDownWidth = nominalWidth - centerDown;
303                   }
304             else if (-headDiff > centerThreshold) {
305                   // smaller than nominal
306                   centerDown = -headDiff * 0.5;
307                   centerAdjustUp = centerDown;
308                   }
309 
310             // handle conflict between upstem and downstem chords
311 
312             if (upVoices && downVoices) {
313                   Note* bottomUpNote = upStemNotes.front();
314                   Note* topDownNote  = downStemNotes.back();
315                   int separation;
316                   // TODO: handle conflicts for cross-staff notes and notes on cross-staff beams
317                   // for now we simply treat these as though there is no conflict
318                   if (bottomUpNote->chord()->staffMove() == topDownNote->chord()->staffMove() && !crossBeamFound)
319                         separation = topDownNote->line() - bottomUpNote->line();
320                   else
321                         separation = 2;   // no conflict
322                   QVector<Note*> overlapNotes;
323                   overlapNotes.reserve(8);
324 
325                   if (separation == 1) {
326                         // second
327                         downOffset = maxUpWidth;
328                         // align stems if present, leave extra room if not
329                         if (topDownNote->chord()->stem() && bottomUpNote->chord()->stem())
330                               downOffset -= topDownNote->chord()->stem()->lineWidth();
331                         else
332                               downOffset += 0.1 * sp;
333                         }
334 
335                   else if (separation < 1) {
336 
337                         // overlap (possibly unison)
338 
339                         // build list of overlapping notes
340                         for (size_t i = 0, n = upStemNotes.size(); i < n; ++i) {
341                               if (upStemNotes[i]->line() >= topDownNote->line() - 1)
342                                     overlapNotes.append(upStemNotes[i]);
343                               else
344                                     break;
345                               }
346                         for (size_t i = downStemNotes.size(); i > 0; --i) { // loop most probably needs to be in this reverse order
347                               if (downStemNotes[i-1]->line() <= bottomUpNote->line() + 1)
348                                     overlapNotes.append(downStemNotes[i-1]);
349                               else
350                                     break;
351                               }
352                         std::sort(overlapNotes.begin(), overlapNotes.end(),
353                            [](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
354 
355                         // determine nature of overlap
356                         bool shareHeads = true;       // can all overlapping notes share heads?
357                         bool matchPending = false;    // looking for a unison match
358                         bool conflictUnison = false;  // unison found
359                         bool conflictSecondUpHigher = false;      // second found
360                         bool conflictSecondDownHigher = false;    // second found
361                         int lastLine = 1000;
362                         Note* p = overlapNotes[0];
363                         for (int i = 0, count = overlapNotes.size(); i < count; ++i) {
364                               Note* n = overlapNotes[i];
365                               NoteHead::Type nHeadType;
366                               NoteHead::Type pHeadType;
367                               Chord* nchord = n->chord();
368                               Chord* pchord = p->chord();
369                               if (n->mirror()) {
370                                     if (separation < 0) {
371                                           // don't try to share heads if there is any mirroring
372                                           shareHeads = false;
373                                           // don't worry about conflicts involving mirrored notes
374                                           continue;
375                                           }
376                                     }
377                               int line = n->line();
378                               int d = lastLine - line;
379                               switch (d) {
380                                     case 0:
381                                           // unison
382                                           conflictUnison = true;
383                                           matchPending = false;
384                                           nHeadType = (n->headType() == NoteHead::Type::HEAD_AUTO) ? n->chord()->durationType().headType() : n->headType();
385                                           pHeadType = (p->headType() == NoteHead::Type::HEAD_AUTO) ? p->chord()->durationType().headType() : p->headType();
386                                           // the most important rules for sharing noteheads on unisons between voices are
387                                           // that notes must be one same line with same tpc
388                                           // noteheads must be unmirrored and of same group
389                                           // and chords must be same size (or else sharing code won't work)
390                                           if (n->headGroup() != p->headGroup() || n->tpc() != p->tpc() || n->mirror() || p->mirror() || nchord->small() != pchord->small()) {
391                                                 shareHeads = false;
392                                                 }
393                                           else {
394                                                 // noteheads are potentially shareable
395                                                 // it is more subjective at this point
396                                                 // current default is to require *either* of the following:
397                                                 //    1) both chords have same number of dots, both have stems, and both noteheads are same type and are full size (automatic match)
398                                                 // or 2) one or more of the noteheads is not of type AUTO, but is explicitly set to match the other (user-forced match)
399                                                 // or 3) exactly one of the noteheads is invisible (user-forced match)
400                                                 // thus user can force notes to be shared despite differing number of dots or either being stemless
401                                                 // by setting one of the notehead types to match the other or by making one notehead invisible
402                                                 // TODO: consider adding a style option, staff properties, or note property to control sharing
403                                                 if ((nchord->dots() != pchord->dots() || !nchord->stem() || !pchord->stem() || nHeadType != pHeadType || n->small() || p->small()) &&
404                                                     ((n->headType() == NoteHead::Type::HEAD_AUTO && p->headType() == NoteHead::Type::HEAD_AUTO) || nHeadType != pHeadType) &&
405                                                     (n->visible() == p->visible())) {
406                                                       shareHeads = false;
407                                                       }
408                                                 }
409                                           break;
410                                     case 1:
411                                           // second
412                                           // trust that this won't be a problem for single unison
413                                           if (separation < 0) {
414                                                 if (n->chord()->up())
415                                                       conflictSecondUpHigher = true;
416                                                 else
417                                                       conflictSecondDownHigher = true;
418                                                 shareHeads = false;
419                                                 }
420                                           break;
421                                     default:
422                                           // no conflict
423                                           if (matchPending)
424                                                 shareHeads = false;
425                                           matchPending = true;
426                                     }
427                               p = n;
428                               lastLine = line;
429                               }
430                         if (matchPending)
431                               shareHeads = false;
432 
433                         // calculate offsets
434                         if (shareHeads) {
435                               for (int i = overlapNotes.size() - 1; i >= 1; i -= 2) {
436                                     Note* previousNote = overlapNotes[i-1];
437                                     Note* n = overlapNotes[i];
438                                     if (!(previousNote->chord()->isNudged() || n->chord()->isNudged())) {
439                                           if (previousNote->chord()->dots() == n->chord()->dots()) {
440                                                 // hide one set dots
441                                                 bool onLine = !(previousNote->line() & 1);
442                                                 if (onLine) {
443                                                       // hide dots for lower voice
444                                                       if (previousNote->voice() & 1)
445                                                             previousNote->setDotsHidden(true);
446                                                       else
447                                                             n->setDotsHidden(true);
448                                                       }
449                                                 else {
450                                                       // hide dots for upper voice
451                                                       if (!(previousNote->voice() & 1))
452                                                             previousNote->setDotsHidden(true);
453                                                       else
454                                                             n->setDotsHidden(true);
455                                                       }
456                                                 }
457                                           // formerly we hid noteheads in an effort to fix playback
458                                           // but this doesn't work for cases where noteheads cannot be shared
459                                           // so better to solve the problem elsewhere
460                                           }
461                                     }
462                               }
463                         else if (conflictUnison && separation == 0 && (!downGrace || upGrace))
464                               downOffset = maxUpWidth + 0.3 * sp;
465                         else if (conflictUnison)
466                               upOffset = maxDownWidth + 0.3 * sp;
467                         else if (conflictSecondUpHigher)
468                               upOffset = maxDownWidth + 0.2 * sp;
469                         else if ((downHooks && !upHooks) && !(upDots && !downDots))
470                               downOffset = maxUpWidth + 0.3 * sp;
471                         else if (conflictSecondDownHigher) {
472                               if (downDots && !upDots)
473                                     downOffset = maxUpWidth + 0.3 * sp;
474                               else {
475                                     upOffset = maxDownWidth - 0.2 * sp;
476                                     if (downHooks)
477                                           upOffset += 0.3 * sp;
478                                     }
479                               }
480                         else {
481                               // no direct conflict, so parts can overlap (downstem on left)
482                               // just be sure that stems clear opposing noteheads
483                               qreal clearLeft = 0.0, clearRight = 0.0;
484                               if (topDownNote->chord()->stem())
485                                     clearLeft = topDownNote->chord()->stem()->lineWidth() + 0.3 * sp;
486                               if (bottomUpNote->chord()->stem())
487                                     clearRight = bottomUpNote->chord()->stem()->lineWidth() + qMax(maxDownWidth - maxUpWidth, 0.0) + 0.3 * sp;
488                               else
489                                     downDots = 0; // no need to adjust for dots in this case
490                               upOffset = qMax(clearLeft, clearRight);
491                               if (downHooks) {
492                                     // we will need more space to avoid collision with hook
493                                     // but we won't need as much dot adjustment
494                                     upOffset = qMax(upOffset, maxDownWidth + 0.1 * sp);
495                                     dotAdjustThreshold = maxUpWidth - 0.3 * sp;
496                                     }
497                               // if downstem chord is small, don't center
498                               // and we might not need as much dot adjustment either
499                               if (centerDown > 0.0) {
500                                     centerDown = 0.0;
501                                     centerAdjustUp = 0.0;
502                                     dotAdjustThreshold = (upOffset - maxDownWidth) + maxUpWidth - 0.3 * sp;
503                                     }
504                               }
505 
506                         }
507 
508                   // adjust for dots
509                   if ((upDots && !downDots) || (downDots && !upDots)) {
510                         // only one sets of dots
511                         // place between chords
512                         int dots;
513                         qreal mag;
514                         if (upDots) {
515                               dots = upDots;
516                               mag = maxUpMag;
517                               }
518                         else {
519                               dots = downDots;
520                               mag = maxDownMag;
521                               }
522                         qreal dotWidth = segment->symWidth(SymId::augmentationDot);
523                         // first dot
524                         dotAdjust = styleP(Sid::dotNoteDistance) + dotWidth;
525                         // additional dots
526                         if (dots > 1)
527                               dotAdjust += styleP(Sid::dotDotDistance) * (dots - 1);
528                         dotAdjust *= mag;
529                         // only by amount over threshold
530                         dotAdjust = qMax(dotAdjust - dotAdjustThreshold, 0.0);
531                         }
532                   if (separation == 1)
533                         dotAdjust += 0.1 * sp;
534 
535                   }
536 
537             // apply chord offsets
538             for (int track = startTrack; track < endTrack; ++track) {
539                   Element* e = segment->element(track);
540                   if (e && e->isChord()) {
541                         Chord* chord = toChord(e);
542                         if (chord->up()) {
543                               if (upOffset != 0.0) {
544                                     chord->rxpos() += upOffset + centerAdjustUp + oversizeUp;
545                                     if (downDots && !upDots)
546                                           chord->rxpos() += dotAdjust;
547                                     }
548                               else
549                                     chord->rxpos() += centerUp;
550                               }
551                         else {
552                               if (downOffset != 0.0) {
553                                     chord->rxpos() += downOffset + centerAdjustDown;
554                                     if (upDots && !downDots)
555                                           chord->rxpos() += dotAdjust;
556                                     }
557                               else
558                                     chord->rxpos() += centerDown;
559                               }
560                         }
561                   }
562 
563             // layout chords
564             std::vector<Note*> notes;
565             if (upVoices)
566                   notes.insert(notes.end(), upStemNotes.begin(), upStemNotes.end());
567             if (downVoices)
568                   notes.insert(notes.end(), downStemNotes.begin(), downStemNotes.end());
569             if (upVoices + downVoices > 1)
570                   std::sort(notes.begin(), notes.end(),
571                      [](Note* n1, const Note* n2) ->bool {return n1->line() > n2->line(); } );
572             layoutChords3(notes, staff, segment);
573             }
574 
575       layoutSegmentElements(segment, startTrack, endTrack);
576       }
577 
578 //---------------------------------------------------------
579 //   layoutChords2
580 //    - determine which notes need mirroring
581 //    - this is called once for each stem direction
582 //      eg, once for voices 1&3, once for 2&4
583 //      with all notes combined and sorted to resemble one chord
584 //    - return maximum non-mirrored notehead width
585 //---------------------------------------------------------
586 
layoutChords2(std::vector<Note * > & notes,bool up)587 qreal Score::layoutChords2(std::vector<Note*>& notes, bool up)
588       {
589       int startIdx, endIdx, incIdx;
590       qreal maxWidth = 0.0;
591 
592       // loop in correct direction so that first encountered notehead wins conflict
593       if (up) {
594             // loop bottom up
595             startIdx = 0;
596             endIdx = int(notes.size());
597             incIdx = 1;
598             }
599       else {
600             // loop top down
601             startIdx = int(notes.size()) - 1;
602             endIdx = -1;
603             incIdx = -1;
604             }
605 
606       int ll        = 1000;         // line of previous notehead
607                                     // hack: start high so first note won't show as conflict
608       bool lvisible = false;        // was last note visible?
609       bool mirror   = false;        // should current notehead be mirrored?
610                                     // value is retained and may be used on next iteration
611                                     // to track mirror status of previous note
612       bool isLeft   = notes[startIdx]->chord()->up();             // is notehead on left?
613       int lmove     = notes[startIdx]->chord()->staffMove();      // staff offset of last note (for cross-staff beaming)
614 
615       for (int idx = startIdx; idx != endIdx; idx += incIdx) {
616             Note* note    = notes[idx];                     // current note
617             int line      = note->line();                   // line of current note
618             Chord* chord  = note->chord();
619             int move      = chord->staffMove();             // staff offset of current note
620 
621             // there is a conflict
622             // if this is same or adjacent line as previous note (and chords are on same staff!)
623             // but no need to do anything about it if either note is invisible
624             bool conflict = (qAbs(ll - line) < 2) && (lmove == move) && note->visible() && lvisible;
625 
626             // this note is on opposite side of stem as previous note
627             // if there is a conflict
628             // or if this the first note *after* a conflict
629             if (conflict || (chord->up() != isLeft))
630                   isLeft = !isLeft;
631 
632             // determine if we would need to mirror current note
633             // to get it to the correct side
634             // this would be needed to get a note to left or downstem or right of upstem
635             // whether or not we actually do this is determined later (based on user mirror property)
636             bool nmirror = (chord->up() != isLeft);
637 
638             // by default, notes and dots are not hidden
639             // this may be changed later to allow unisons to share noteheads
640             note->setHidden(false);
641             note->setDotsHidden(false);
642 
643             // be sure chord position is initialized
644             // chord may be moved to the right later
645             // if there are conflicts between voices
646             chord->rxpos() = 0.0;
647 
648             // let user mirror property override the default we calculated
649             if (note->userMirror() == MScore::DirectionH::AUTO) {
650                   mirror = nmirror;
651                   }
652             else {
653                   mirror = note->chord()->up();
654                   if (note->userMirror() == MScore::DirectionH::LEFT)
655                         mirror = !mirror;
656                   }
657             note->setMirror(mirror);
658 
659             // accumulate return value
660             if (!mirror)
661                   maxWidth = qMax(maxWidth, note->bboxRightPos());
662 
663             // prepare for next iteration
664             lvisible = note->visible();
665             lmove    = move;
666             ll       = line;
667             }
668 
669       return maxWidth;
670       }
671 
672 //---------------------------------------------------------
673 //   AcEl
674 //---------------------------------------------------------
675 
676 struct AcEl {
677       Note* note;
678       qreal x;          // actual x position of this accidental relative to origin
679       qreal top;        // top of accidental bbox relative to staff
680       qreal bottom;     // bottom of accidental bbox relative to staff
681       int line;         // line of note
682       int next;         // index of next accidental of same pitch class (ascending list)
683       qreal width;      // width of accidental
684       qreal ascent;     // amount (in sp) vertical strokes extend above body
685       qreal descent;    // amount (in sp) vertical strokes extend below body
686       qreal rightClear; // amount (in sp) to right of last vertical stroke above body
687       qreal leftClear;  // amount (in sp) to left of last vertical stroke below body
688       };
689 
690 //---------------------------------------------------------
691 //   resolveAccidentals
692 //    lx = calculated position of rightmost edge of left accidental relative to origin
693 //---------------------------------------------------------
694 
resolveAccidentals(AcEl * left,AcEl * right,qreal & lx,qreal pd,qreal sp)695 static bool resolveAccidentals(AcEl* left, AcEl* right, qreal& lx, qreal pd, qreal sp)
696       {
697       AcEl* upper;
698       AcEl* lower;
699       if (left->line >= right->line) {
700             upper = right;
701             lower = left;
702             }
703       else {
704             upper = left;
705             lower = right;
706             }
707 
708       qreal gap = lower->top - upper->bottom;
709 
710       // no conflict at all if there is sufficient vertical gap between accidentals
711       // the arrangement of accidentals into columns assumes accidentals an octave apart *do* clear
712       if (gap >= pd || lower->line - upper->line >= 7)
713             return false;
714 
715       qreal allowableOverlap = qMax(upper->descent, lower->ascent) - pd;
716 
717       // accidentals that are "close" (small gap or even slight overlap)
718       if (qAbs(gap) <= 0.33 * sp) {
719             // acceptable with slight offset
720             // if one of the accidentals can subsume the overlap
721             // and both accidentals allow it
722             if (-gap <= allowableOverlap && qMin(upper->descent, lower->ascent) > 0.0) {
723                   qreal align = qMin(left->width, right->width);
724                   lx = qMin(lx, right->x + align - pd);
725                   return true;
726                   }
727             }
728 
729       // amount by which overlapping accidentals will be separated
730       // for example, the vertical stems of two flat signs
731       // these need more space than we would need between non-overlapping accidentals
732       qreal overlapShift = pd * 1.41;
733 
734       // accidentals with more significant overlap
735       // acceptable if one accidental can subsume overlap
736       if (left == lower && -gap <= allowableOverlap) {
737             qreal offset = qMax(left->rightClear, right->leftClear);
738             offset = qMin(offset, left->width) - overlapShift;
739             lx = qMin(lx, right->x + offset);
740             return true;
741             }
742 
743       // accidentals with even more overlap
744       // can work if both accidentals can subsume overlap
745       if (left == lower && -gap <= upper->descent + lower->ascent - pd) {
746             qreal offset = qMin(left->rightClear, right->leftClear) - overlapShift;
747             if (offset > 0.0) {
748                   lx = qMin(lx, right->x + offset);
749                   return true;
750                   }
751             }
752 
753       // otherwise, there is real conflict
754       lx = qMin(lx, right->x - pd);
755       return true;
756       }
757 
758 //---------------------------------------------------------
759 //   layoutAccidental
760 //---------------------------------------------------------
761 
layoutAccidental(AcEl * me,AcEl * above,AcEl * below,qreal colOffset,QVector<Note * > & leftNotes,qreal pnd,qreal pd,qreal sp)762 static QPair<qreal, qreal> layoutAccidental(AcEl* me, AcEl* above, AcEl* below, qreal colOffset, QVector<Note*>& leftNotes, qreal pnd, qreal pd, qreal sp)
763       {
764       qreal lx = colOffset;
765       Accidental* acc = me->note->accidental();
766       qreal mag = acc->mag();
767       pnd *= mag;
768       pd *= mag;
769 
770       Chord* chord = me->note->chord();
771       Staff* staff = chord->staff();
772       Fraction tick = chord->tick();
773 
774       // extra space for ledger lines
775       qreal ledgerAdjust = 0.0;
776       qreal ledgerVerticalClear = 0.0;
777       bool ledgerAbove = chord->upNote()->line() <= -2;
778       bool ledgerBelow = chord->downNote()->line() >= staff->lines(tick) * 2;
779       if (ledgerAbove || ledgerBelow) {
780             // ledger lines are present
781             // check for collision with lines above & below staff
782             // note that on 1-line staff, both collisions are possible at once
783             // TODO: account for cutouts in accidental
784             qreal lds = staff->lineDistance(tick) * sp;
785             if ((ledgerAbove && me->top + lds <= pnd) || (ledgerBelow && staff->lines(tick) * lds - me->bottom <= pnd)) {
786                   ledgerAdjust = -acc->score()->styleS(Sid::ledgerLineLength).val() * sp;
787                   ledgerVerticalClear = acc->score()->styleS(Sid::ledgerLineWidth).val() * 0.5 * sp;
788                   lx = qMin(lx, ledgerAdjust);
789                   }
790             }
791 
792       // clear left notes
793       int lns = leftNotes.size();
794       for (int i = 0; i < lns; ++i) {
795             Note* ln = leftNotes[i];
796             int lnLine = ln->line();
797             qreal lnTop = (lnLine - 1) * 0.5 * sp;
798             qreal lnBottom = lnTop + sp;
799             if (me->top - lnBottom <= pnd && lnTop - me->bottom <= pnd) {
800                   qreal lnLedgerAdjust = 0.0;
801                   if (lnLine <= -2 || lnLine >= staff->lines(tick) * 2) {
802                         // left note has a ledger line we probably need to clear horizontally as well
803                         // except for accidentals that clear the last extended ledger line vertically
804                         // in these cases, the accidental may tuck closer
805                         Note* lastLnNote = lnLine < 0  ? leftNotes[0] : leftNotes[lns - 1];
806                         int lastLnLine = lastLnNote->line();
807                         qreal ledgerY = (lastLnLine / 2) * sp;
808                         if (me->line < 0 && ledgerY - me->bottom < ledgerVerticalClear)
809                               lnLedgerAdjust = ledgerAdjust;
810                         else if (me->line > 0 && me->top - ledgerY < ledgerVerticalClear)
811                               lnLedgerAdjust = ledgerAdjust;
812                         }
813                   // undercut note above if possible
814                   if (lnBottom - me->top <= me->ascent - pnd)
815                         lx = qMin(lx, ln->x() + ln->chord()->x() + lnLedgerAdjust + me->rightClear);
816                   else
817                         lx = qMin(lx, ln->x() + ln->chord()->x() + lnLedgerAdjust);
818                   }
819             else if (lnTop > me->bottom)
820                   break;
821             }
822 
823       // clear other accidentals
824       bool conflictAbove = false;
825       bool conflictBelow = false;
826 
827       if (above)
828             conflictAbove = resolveAccidentals(me, above, lx, pd, sp);
829       if (below)
830             conflictBelow = resolveAccidentals(me, below, lx, pd, sp);
831       if (conflictAbove || conflictBelow)
832             me->x = lx - acc->width() - acc->bbox().x();
833       else if (colOffset != 0.0)
834             me->x = lx - pd - acc->width() - acc->bbox().x();
835       else
836             me->x = lx - pnd - acc->width() - acc->bbox().x();
837 
838       return QPair<qreal, qreal> (me->x, me->x + me->width);
839       }
840 
841 //---------------------------------------------------------
842 //   layoutChords3
843 //    - calculate positions of notes, accidentals, dots
844 //---------------------------------------------------------
845 
layoutChords3(std::vector<Note * > & notes,const Staff * staff,Segment * segment)846 void Score::layoutChords3(std::vector<Note*>& notes, const Staff* staff, Segment* segment)
847       {
848       //---------------------------------------------------
849       //    layout accidentals
850       //    find column for dots
851       //---------------------------------------------------
852 
853       QVector<Note*> leftNotes; // notes to left of origin
854       leftNotes.reserve(8);
855       QVector<AcEl> aclist;       // accidentals
856       aclist.reserve(8);
857 
858       // track columns of octave-separated accidentals
859       int columnBottom[7] = { -1, -1, -1, -1, -1, -1, -1 };
860 
861       Fraction tick      =  notes.front()->chord()->segment()->tick();
862       qreal sp           = staff->spatium(tick);
863       qreal stepDistance = sp * staff->lineDistance(tick) * .5;
864       int stepOffset     = staff->staffType(tick)->stepOffset();
865 
866       qreal lx           = 10000.0;  // leftmost notehead position
867       qreal upDotPosX    = 0.0;
868       qreal downDotPosX  = 0.0;
869 
870       int nNotes = int(notes.size());
871       int nAcc = 0;
872       for (int i = nNotes-1; i >= 0; --i) {
873             Note* note     = notes[i];
874             Accidental* ac = note->accidental();
875             if (ac && !note->fixed()) {
876                   ac->layout();
877                   if (!ac->visible()) {
878                         ac->setPos(ac->bbox().x() - ac->width(), 0.0);
879                         }
880                   else {
881                         AcEl acel;
882                         acel.note   = note;
883                         int line    = note->line();
884                         acel.line   = line;
885                         acel.x      = 0.0;
886                         acel.top    = line * 0.5 * sp + ac->bbox().top();
887                         acel.bottom = line * 0.5 * sp + ac->bbox().bottom();
888                         acel.width  = ac->width();
889                         QPointF bboxNE = ac->symBbox(ac->symbol()).topRight();
890                         QPointF bboxSW = ac->symBbox(ac->symbol()).bottomLeft();
891                         QPointF cutOutNE = ac->symCutOutNE(ac->symbol());
892                         QPointF cutOutSW = ac->symCutOutSW(ac->symbol());
893                         if (!cutOutNE.isNull()) {
894                               acel.ascent     = cutOutNE.y() - bboxNE.y();
895                               acel.rightClear = bboxNE.x() - cutOutNE.x();
896                               }
897                         else {
898                               acel.ascent     = 0.0;
899                               acel.rightClear = 0.0;
900                               }
901                         if (!cutOutSW.isNull()) {
902                               acel.descent   = bboxSW.y() - cutOutSW.y();
903                               acel.leftClear = cutOutSW.x() - bboxSW.x();
904                               }
905                         else {
906                               acel.descent   = 0.0;
907                               acel.leftClear = 0.0;
908                               }
909                         int pitchClass = (line + 700) % 7;
910                         acel.next = columnBottom[pitchClass];
911                         columnBottom[pitchClass] = nAcc;
912                         aclist.append(acel);
913                         ++nAcc;
914                         }
915                   }
916 
917             Chord* chord = note->chord();
918             bool _up     = chord->up();
919 
920             if (chord->stemSlash())
921                   chord->stemSlash()->layout();
922 
923             qreal overlapMirror;
924             Stem* stem = chord->stem();
925             if (stem)
926                   overlapMirror = stem->lineWidth();
927             else if (chord->durationType().headType() == NoteHead::Type::HEAD_WHOLE)
928                   overlapMirror = styleP(Sid::stemWidth) * chord->mag();
929             else
930                   overlapMirror = 0.0;
931 
932             qreal x = 0.0;
933             if (note->mirror())
934                   if (_up)
935                         x = chord->stemPosX() - overlapMirror;
936                   else
937                         x = -note->headBodyWidth() + overlapMirror;
938             else if (_up)
939                   x = chord->stemPosX() - note->headBodyWidth();
940 
941             qreal ny = (note->line() + stepOffset) * stepDistance;
942             if (note->rypos() != ny) {
943                   note->rypos() = ny;
944                   if (chord->stem()) {
945                         chord->stem()->layout();
946                         if (chord->hook())
947                               chord->hook()->rypos() = chord->stem()->hookPos().y();
948                         }
949                   }
950             note->rxpos()  = x;
951 
952             // find leftmost non-mirrored note to set as X origin for accidental layout
953             // a mirrored note that extends to left of segment X origin
954             // will displace accidentals only if there is conflict
955             qreal sx = x + chord->x(); // segment-relative X position of note
956             if (note->mirror() && !chord->up() && sx < 0.0)
957                   leftNotes.append(note);
958             else if (sx < lx)
959                   lx = sx;
960 
961             qreal xx = x + note->headBodyWidth() + chord->pos().x();
962 
963             Direction dotPosition = note->userDotPosition();
964             if (chord->dots()) {
965                   if (chord->up())
966                         upDotPosX = qMax(upDotPosX, xx);
967                   else {
968                         downDotPosX = qMax(downDotPosX, xx);
969                         }
970 
971                   if (dotPosition == Direction::AUTO && nNotes > 1 && note->visible() && !note->dotsHidden()) {
972                         // resolve dot conflicts
973                         int line = note->line();
974                         Note* above = (i < nNotes - 1) ? notes[i+1] : 0;
975                         if (above && (!above->visible() || above->dotsHidden()))
976                               above = 0;
977                         int intervalAbove = above ? line - above->line() : 1000;
978                         Note* below = (i > 0) ? notes[i-1] : 0;
979                         if (below && (!below->visible() || below->dotsHidden()))
980                               below = 0;
981                         int intervalBelow = below ? below->line() - line : 1000;
982                         if ((line & 1) == 0) {
983                               // line
984                               if (intervalAbove == 1 && intervalBelow != 1)
985                                     dotPosition = Direction::DOWN;
986                               else if (intervalBelow == 1 && intervalAbove != 1)
987                                     dotPosition = Direction::UP;
988                               else if (intervalAbove == 0 && above->chord()->dots()) {
989                                     // unison
990                                     if (((above->voice() & 1) == (note->voice() & 1))) {
991                                           above->setDotY(Direction::UP);
992                                           dotPosition = Direction::DOWN;
993                                           }
994                                     }
995                               }
996                         else {
997                               // space
998                               if (intervalAbove == 0 && above->chord()->dots()) {
999                                     // unison
1000                                     if (!(note->voice() & 1))
1001                                           dotPosition = Direction::UP;
1002                                     else {
1003                                           if (!(above->voice() & 1))
1004                                                 above->setDotY(Direction::UP);
1005                                           else
1006                                                 dotPosition = Direction::DOWN;
1007                                           }
1008                                     }
1009                               }
1010                         }
1011                   }
1012             note->setDotY(dotPosition);  // also removes invalid dots
1013             }
1014 
1015       // if there are no non-mirrored notes in a downstem chord,
1016       // then use the stem X position as X origin for accidental layout
1017       if (nNotes && leftNotes.size() == nNotes)
1018             lx = notes.front()->chord()->stemPosX();
1019 
1020       if (segment) {
1021             // align all dots for segment/staff
1022             // it would be possible to dots for up & down chords separately
1023             // this would require space to have been allocated previously
1024             // when calculating chord offsets
1025             segment->setDotPosX(staff->idx(), qMax(upDotPosX, downDotPosX));
1026             }
1027 
1028       if (nAcc == 0)
1029             return;
1030 
1031       QVector<int> umi;
1032       qreal pd  = styleP(Sid::accidentalDistance);
1033       qreal pnd = styleP(Sid::accidentalNoteDistance);
1034       qreal colOffset = 0.0;
1035 
1036       if (nAcc >= 2 && aclist[nAcc-1].line - aclist[0].line >= 7) {
1037 
1038             // accidentals spread over an octave or more
1039             // set up columns for accidentals with octave matches
1040             // these will start at right and work to the left
1041             // unmatched accidentals will use zig zag approach (see below)
1042             // starting to the left of the octave columns
1043 
1044             int columnTop[7] = { -1, -1, -1, -1, -1, -1, -1 };
1045 
1046             // find columns of octaves
1047             for (int pc = 0; pc < 7; ++pc) {
1048                   if (columnBottom[pc] == -1)
1049                         continue;
1050                   // calculate column height
1051                   for (int j = columnBottom[pc]; j != -1; j = aclist[j].next)
1052                         columnTop[pc] = j;
1053                   }
1054 
1055             // compute reasonable column order
1056             // use zig zag
1057             QVector<int> column;
1058             QVector<int> unmatched;
1059             int n = nAcc - 1;
1060             for (int i = 0; i <= n; ++i, --n) {
1061                   int pc = (aclist[i].line + 700) % 7;
1062                   if (aclist[columnTop[pc]].line != aclist[columnBottom[pc]].line) {
1063                         if (!column.contains(pc))
1064                               column.append(pc);
1065                         }
1066                   else
1067                         unmatched.append(i);
1068                   if (i == n)
1069                         break;
1070                   pc = (aclist[n].line + 700) % 7;
1071                   if (aclist[columnTop[pc]].line != aclist[columnBottom[pc]].line) {
1072                         if (!column.contains(pc))
1073                               column.append(pc);
1074                         }
1075                   else
1076                         unmatched.append(n);
1077                   }
1078             int nColumns = column.size();
1079             int nUnmatched = unmatched.size();
1080 
1081             // handle unmatched accidentals
1082             for (int i = 0; i < nUnmatched; ++i) {
1083                   // first try to slot it into an existing column
1084                   AcEl* me = &aclist[unmatched[i]];
1085                   // find column
1086                   bool found = false;
1087                   for (int j = 0; j < nColumns; ++j) {
1088                         int pc = column[j];
1089                         int above = -1;
1090                         int below = -1;
1091                         // find slot within column
1092                         for (int k = columnBottom[pc]; k != -1; k = aclist[k].next) {
1093                               if (aclist[k].line < me->line) {
1094                                     above = k;
1095                                     break;
1096                                     }
1097                               below = k;
1098                               }
1099                         // check to see if accidental can fit in slot
1100                         qreal myPd = pd * me->note->accidental()->mag();
1101                         bool conflict = false;
1102                         if (above != -1 && me->top - aclist[above].bottom < myPd)
1103                               conflict = true;
1104                         else if (below != -1 && aclist[below].top - me->bottom < myPd)
1105                               conflict = true;
1106                         if (!conflict) {
1107                               // insert into column
1108                               found = true;
1109                               me->next = above;
1110                               if (above == -1)
1111                                     columnTop[pc] = unmatched[i];
1112                               if (below != -1)
1113                                     aclist[below].next = unmatched[i];
1114                               else
1115                                     columnBottom[pc] = unmatched[i];
1116                               break;
1117                               }
1118                         }
1119                   // if no slot found, then add to list of unmatched accidental indices
1120                   if (!found)
1121                         umi.push_back(unmatched[i]);
1122                   }
1123             nAcc = umi.size();
1124             if (nAcc > 1)
1125                   std::sort(umi.begin(), umi.end());
1126 
1127             bool alignLeft = score()->styleB(Sid::alignAccidentalsLeft);
1128 
1129             // through columns
1130             for (int i = 0; i < nColumns; ++i) {
1131                   // column index
1132                   const int pc = column[i];
1133 
1134                   qreal minX = 0.0;
1135                   qreal maxX = 0.0;
1136 
1137                   AcEl* below = 0;
1138                   // through accidentals in this column
1139                   for (int j = columnBottom[pc]; j != -1; j = aclist[j].next) {
1140                         QPair<qreal, qreal> x = layoutAccidental(&aclist[j], 0, below, colOffset, leftNotes, pnd, pd, sp);
1141                         minX = qMin(minX, x.first);
1142                         maxX = qMin(maxX, x.second);
1143                         below = &aclist[j];
1144                         }
1145 
1146                   // align
1147                   int next = -1;
1148                   for (int j = columnBottom[pc]; j != -1; j = next) {
1149                         AcEl* current = &aclist[j];
1150                         next = current->next;
1151                         if (next != -1 && current->line == aclist[next].line)
1152                                 continue;
1153 
1154                         if (alignLeft)
1155                                 current->x = minX;
1156                         else
1157                               current->x = maxX - current->width;
1158                         }
1159                   colOffset = minX;
1160                   }
1161             }
1162 
1163       else {
1164             for (int i = 0; i < nAcc; ++i)
1165                   umi.push_back(i);
1166             }
1167 
1168       if (nAcc) {
1169             // for accidentals with no octave matches, use zig zag approach
1170             // layout right to left in pairs, (next) highest then lowest
1171 
1172             AcEl* me = &aclist[umi[0]];
1173             AcEl* above = 0;
1174             AcEl* below = 0;
1175 
1176             // layout top accidental
1177             layoutAccidental(me, above, below, colOffset, leftNotes, pnd, pd, sp);
1178 
1179             // layout bottom accidental
1180             int n = nAcc - 1;
1181             if (n > 0) {
1182                   above = me;
1183                   me = &aclist[umi[n]];
1184                   layoutAccidental(me, above, below, colOffset, leftNotes, pnd, pd, sp);
1185                   }
1186 
1187             // layout middle accidentals
1188             if (n > 1) {
1189                   for (int i = 1; i < n; ++i, --n) {
1190                         // next highest
1191                         below = me;
1192                         me = &aclist[umi[i]];
1193                         layoutAccidental(me, above, below, colOffset, leftNotes, pnd, pd, sp);
1194                         if (i == n - 1)
1195                               break;
1196                         // next lowest
1197                         above = me;
1198                         me = &aclist[umi[n-1]];
1199                         layoutAccidental(me, above, below, colOffset, leftNotes, pnd, pd, sp);
1200                         }
1201                   }
1202             }
1203 
1204       for (const AcEl& e : qAsConst(aclist)) {
1205             // even though we initially calculate accidental position relative to segment
1206             // we must record pos for accidental relative to note,
1207             // since pos is always interpreted relative to parent
1208             Note* note = e.note;
1209             qreal x    = e.x + lx - (note->x() + note->chord()->x());
1210             note->accidental()->setPos(x, 0);
1211             }
1212       }
1213 
1214 #define beamModeMid(a) (a == Beam::Mode::MID || a == Beam::Mode::BEGIN32 || a == Beam::Mode::BEGIN64)
1215 
beamNoContinue(Beam::Mode mode)1216 bool beamNoContinue(Beam::Mode mode)
1217       {
1218       return mode == Beam::Mode::END || mode == Beam::Mode::NONE || mode == Beam::Mode::INVALID;
1219       }
1220 
1221 //---------------------------------------------------------
1222 //   beamGraceNotes
1223 //---------------------------------------------------------
1224 
beamGraceNotes(Chord * mainNote,bool after)1225 void Score::beamGraceNotes(Chord* mainNote, bool after)
1226       {
1227       ChordRest* a1    = 0;      // start of (potential) beam
1228       Beam* beam       = 0;      // current beam
1229       Beam::Mode bm = Beam::Mode::AUTO;
1230       QVector<Chord*> graceNotes = after ? mainNote->graceNotesAfter() : mainNote->graceNotesBefore();
1231 
1232       for (ChordRest* cr : qAsConst(graceNotes)) {
1233             bm = Groups::endBeam(cr);
1234             if ((cr->durationType().type() <= TDuration::DurationType::V_QUARTER) || (bm == Beam::Mode::NONE)) {
1235                   if (beam) {
1236                         beam->layoutGraceNotes();
1237                         beam = 0;
1238                         }
1239                   if (a1) {
1240                         a1->removeDeleteBeam(false);
1241                         a1 = 0;
1242                         }
1243                   cr->removeDeleteBeam(false);
1244                   continue;
1245                   }
1246             if (beam) {
1247                   bool beamEnd = bm == Beam::Mode::BEGIN;
1248                   if (!beamEnd) {
1249                         cr->replaceBeam(beam);
1250                         cr = 0;
1251                         beamEnd = (bm == Beam::Mode::END);
1252                         }
1253                   if (beamEnd) {
1254                         beam->layoutGraceNotes();
1255                         beam = 0;
1256                         }
1257                   }
1258             if (!cr)
1259                   continue;
1260             if (a1 == 0)
1261                   a1 = cr;
1262             else {
1263                   if (!beamModeMid(bm) && (bm == Beam::Mode::BEGIN)) {
1264                         a1->removeDeleteBeam(false);
1265                         a1 = cr;
1266                         }
1267                   else {
1268                         beam = a1->beam();
1269                         if (beam == 0 || beam->elements().front() != a1) {
1270                               beam = new Beam(this);
1271                               beam->setGenerated(true);
1272                               beam->setTrack(mainNote->track());
1273                               a1->replaceBeam(beam);
1274                               }
1275                         cr->replaceBeam(beam);
1276                         a1 = 0;
1277                         }
1278                   }
1279             }
1280       if (beam)
1281             beam->layoutGraceNotes();
1282       else if (a1)
1283             a1->removeDeleteBeam(false);
1284       }
1285 
1286 #if 0 // unused
1287 //---------------------------------------------------------
1288 //   layoutSpanner
1289 //    called after dragging a staff
1290 //---------------------------------------------------------
1291 
1292 void Score::layoutSpanner()
1293       {
1294       int tracks = ntracks();
1295       for (int track = 0; track < tracks; ++track) {
1296             for (Segment* segment = firstSegment(SegmentType::All); segment; segment = segment->next1()) {
1297                   if (track == tracks-1) {
1298                         size_t n = segment->annotations().size();
1299                         for (size_t i = 0; i < n; ++i)
1300                               segment->annotations().at(i)->layout();
1301                         }
1302                   Element* e = segment->element(track);
1303                   if (e && e->isChord()) {
1304                         Chord* c = toChord(segment->element(track));
1305                         c->layoutStem();
1306                         for (Note* n : c->notes()) {
1307                               Tie* tie = n->tieFor();
1308                               if (tie)
1309                                     tie->layout();
1310                               for (Spanner* sp : n->spannerFor())
1311                                     sp->layout();
1312                               }
1313                         }
1314                   }
1315             }
1316       rebuildBspTree();
1317       }
1318 #endif
1319 
1320 //---------------------------------------------------------
1321 //   hideEmptyStaves
1322 //---------------------------------------------------------
1323 
hideEmptyStaves(System * system,bool isFirstSystem)1324 void Score::hideEmptyStaves(System* system, bool isFirstSystem)
1325       {
1326       int staves   = _staves.size();
1327       int staffIdx = 0;
1328       bool systemIsEmpty = true;
1329 
1330       for (Staff* staff : qAsConst(_staves)) {
1331             SysStaff* ss  = system->staff(staffIdx);
1332 
1333             Staff::HideMode hideMode = staff->hideWhenEmpty();
1334 
1335             if (hideMode == Staff::HideMode::ALWAYS
1336                 || (styleB(Sid::hideEmptyStaves)
1337                     && (staves > 1)
1338                     && !(isFirstSystem && styleB(Sid::dontHideStavesInFirstSystem))
1339                     && hideMode != Staff::HideMode::NEVER)) {
1340                   bool hideStaff = true;
1341                   for (MeasureBase* m : system->measures()) {
1342                         if (!m->isMeasure())
1343                               continue;
1344                         Measure* measure = toMeasure(m);
1345                         if (!measure->isEmpty(staffIdx)) {
1346                               hideStaff = false;
1347                               break;
1348                               }
1349                         }
1350                   // check if notes moved into this staff
1351                   Part* part = staff->part();
1352                   int n = part->nstaves();
1353                   if (hideStaff && (n > 1)) {
1354                         int idx = part->staves()->front()->idx();
1355                         for (int i = 0; i < part->nstaves(); ++i) {
1356                               int st = idx + i;
1357 
1358                               for (MeasureBase* mb : system->measures()) {
1359                                     if (!mb->isMeasure())
1360                                           continue;
1361                                     Measure* m = toMeasure(mb);
1362                                     if (staff->hideWhenEmpty() == Staff::HideMode::INSTRUMENT && !m->isEmpty(st)) {
1363                                           hideStaff = false;
1364                                           break;
1365                                           }
1366                                     for (Segment* s = m->first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
1367                                           for (int voice = 0; voice < VOICES; ++voice) {
1368                                                 ChordRest* cr = s->cr(st * VOICES + voice);
1369                                                 if (cr == 0 || cr->isRest())
1370                                                       continue;
1371                                                 int staffMove = cr->staffMove();
1372                                                 if (staffIdx == st + staffMove) {
1373                                                       hideStaff = false;
1374                                                       break;
1375                                                       }
1376                                                 }
1377                                           }
1378                                     if (!hideStaff)
1379                                           break;
1380                                     }
1381                               if (!hideStaff)
1382                                     break;
1383                               }
1384                         }
1385                   ss->setShow(hideStaff ? false : staff->show());
1386                   if (ss->show())
1387                         systemIsEmpty = false;
1388                   }
1389             else if (!staff->show()) {
1390                   // TODO: OK to check this first and not bother with checking if empty?
1391                   ss->setShow(false);
1392                   }
1393             else {
1394                   systemIsEmpty = false;
1395                   ss->setShow(true);
1396                   }
1397 
1398             ++staffIdx;
1399             }
1400       Staff* firstVisible = nullptr;
1401       if (systemIsEmpty) {
1402             for (Staff* staff : qAsConst(_staves)) {
1403                   SysStaff* ss  = system->staff(staff->idx());
1404                   if (staff->showIfEmpty() && !ss->show()) {
1405                         ss->setShow(true);
1406                         systemIsEmpty = false;
1407                         }
1408                   else if (!firstVisible && staff->show()) {
1409                         firstVisible = staff;
1410                         }
1411                   }
1412             }
1413       // don’t allow a complete empty system
1414       if (systemIsEmpty) {
1415             Staff* staff = firstVisible ? firstVisible : _staves.front();
1416             SysStaff* ss = system->staff(staff->idx());
1417             ss->setShow(true);
1418             }
1419       }
1420 
1421 //---------------------------------------------------------
1422 //   connectTies
1423 ///   Rebuild tie connections.
1424 //---------------------------------------------------------
1425 
connectTies(bool silent)1426 void Score::connectTies(bool silent)
1427       {
1428       int tracks = nstaves() * VOICES;
1429       Measure* m = firstMeasure();
1430       if (!m)
1431             return;
1432 
1433       SegmentType st = SegmentType::ChordRest;
1434       for (Segment* s = m->first(st); s; s = s->next1(st)) {
1435             for (int i = 0; i < tracks; ++i) {
1436                   Element* e = s->element(i);
1437                   if (e == 0 || !e->isChord())
1438                         continue;
1439                   Chord* c = toChord(e);
1440                   for (Note* n : c->notes()) {
1441                         // connect a tie without end note
1442                         Tie* tie = n->tieFor();
1443                         if (tie && !tie->endNote()) {
1444                               Note* nnote;
1445                               if (_mscVersion <= 114)
1446                                     nnote = searchTieNote114(n);
1447                               else
1448                                     nnote = searchTieNote(n);
1449                               if (nnote == 0) {
1450                                     if (!silent) {
1451                                           qDebug("next note at %d track %d for tie not found (version %d)", s->tick().ticks(), i, _mscVersion);
1452                                           delete tie;
1453                                           n->setTieFor(0);
1454                                           }
1455                                     }
1456                               else {
1457                                     tie->setEndNote(nnote);
1458                                     nnote->setTieBack(tie);
1459                                     }
1460                               }
1461                         // connect a glissando without initial note (old glissando format)
1462                         for (Spanner* spanner : n->spannerBack()) {
1463                               if (spanner->isGlissando() && !spanner->startElement()) {
1464                                     Note* initialNote = Glissando::guessInitialNote(n->chord());
1465                                     n->removeSpannerBack(spanner);
1466                                     if (initialNote) {
1467                                           spanner->setStartElement(initialNote);
1468                                           spanner->setEndElement(n);
1469                                           spanner->setTick(initialNote->chord()->tick());
1470                                           spanner->setTick2(n->chord()->tick());
1471                                           spanner->setTrack(n->track());
1472                                           spanner->setTrack2(n->track());
1473                                           spanner->setParent(initialNote);
1474                                           initialNote->add(spanner);
1475                                           }
1476                                     else {
1477                                           delete spanner;
1478                                           }
1479                                     }
1480                               }
1481                         // spanner with no end element can happen during copy/paste
1482                         for (Spanner* spanner : n->spannerFor()) {
1483                               if (spanner->endElement() == nullptr) {
1484                                     n->removeSpannerFor(spanner);
1485                                     delete spanner;
1486                                     }
1487                               }
1488                         }
1489 #if 0    // chords are set in tremolo->layout()
1490                   // connect two note tremolos
1491                   Tremolo* tremolo = c->tremolo();
1492                   if (tremolo && tremolo->twoNotes() && !tremolo->chord2()) {
1493                         for (Segment* ls = s->next1(st); ls; ls = ls->next1(st)) {
1494                               Element* element = ls->element(i);
1495                               if (!element)
1496                                     continue;
1497                               if (!element->isChord())
1498                                     qDebug("cannot connect tremolo");
1499                               else {
1500                                     Chord* nc = toChord(element);
1501                                     nc->setTremolo(tremolo);
1502                                     tremolo->setChords(c, nc);
1503                                     // cross-measure tremolos are not supported
1504                                     // but can accidentally result from copy & paste
1505                                     // remove them now
1506                                     if (c->measure() != nc->measure())
1507                                           c->remove(tremolo);
1508                                     }
1509                               break;
1510                               }
1511                         }
1512 #endif
1513                   }
1514             }
1515       }
1516 
1517 //---------------------------------------------------------
1518 //   checkDivider
1519 //---------------------------------------------------------
1520 
checkDivider(bool left,System * s,qreal yOffset,bool remove=false)1521 static void checkDivider(bool left, System* s, qreal yOffset, bool remove = false)
1522       {
1523       SystemDivider* divider = left ? s->systemDividerLeft() : s->systemDividerRight();
1524       if ((s->score()->styleB(left ? Sid::dividerLeft : Sid::dividerRight)) && !remove) {
1525             if (!divider) {
1526                   divider = new SystemDivider(s->score());
1527                   divider->setDividerType(left ? SystemDivider::Type::LEFT : SystemDivider::Type::RIGHT);
1528                   divider->setGenerated(true);
1529                   s->add(divider);
1530                   }
1531             divider->layout();
1532             divider->rypos() = divider->height() * .5 + yOffset;
1533             if (left) {
1534                   divider->rypos() += s->score()->styleD(Sid::dividerLeftY) * SPATIUM20;
1535                   divider->rxpos() =  s->score()->styleD(Sid::dividerLeftX) * SPATIUM20;
1536                   }
1537             else {
1538                   divider->rypos() += s->score()->styleD(Sid::dividerRightY) * SPATIUM20;
1539                   divider->rxpos() =  s->score()->styleD(Sid::pagePrintableWidth) * DPI - divider->width();
1540                   divider->rxpos() += s->score()->styleD(Sid::dividerRightX) * SPATIUM20;
1541                   }
1542             }
1543       else if (divider) {
1544             if (divider->generated()) {
1545                   s->remove(divider);
1546                   delete divider;
1547                   }
1548             else
1549                   s->score()->undoRemoveElement(divider);
1550             }
1551       }
1552 
1553 //---------------------------------------------------------
1554 //   almostZero
1555 //---------------------------------------------------------
1556 
almostZero(qreal value)1557 bool inline almostZero(qreal value)
1558       {
1559       // 1e-3 is close enough to zero to see it as zero.
1560       return value > -1e-3 && value < 1e-3;
1561       }
1562 
1563 //---------------------------------------------------------
1564 //   distributeStaves
1565 //---------------------------------------------------------
1566 
distributeStaves(Page * page)1567 static void distributeStaves(Page* page)
1568       {
1569       Score* score { page->score() };
1570       VerticalGapDataList vgdl;
1571 
1572       // Find and classify all gaps between staves.
1573       int    ngaps { 0 };
1574       qreal  prevYBottom  { page->tm() };
1575       qreal  yBottom      { 0.0        };
1576       bool   vbox         { false      };
1577       Spacer* fixedSpacer { nullptr    };
1578       bool transferNormalBracket { false };
1579       bool transferCurlyBracket  { false };
1580       for (System* system : page->systems()) {
1581             if (system->vbox()) {
1582                   VerticalGapData* vgd = new VerticalGapData(!ngaps++, system, nullptr, nullptr, nullptr, prevYBottom);
1583                   vgd->addSpaceAroundVBox(true);
1584                   prevYBottom = system->y();
1585                   yBottom     = system->y() + system->height();
1586                   vbox        = true;
1587                   vgdl.append(vgd);
1588                   transferNormalBracket = false;
1589                   transferCurlyBracket  = false;
1590                   }
1591             else {
1592                   bool newSystem       { true };
1593                   bool addSpaceAroundNormalBracket { false };
1594                   bool addSpaceAroundCurlyBracket  { false };
1595                   int endNormalBracket { -1   };
1596                   int endCurlyBracket  { -1   };
1597                   int staffNr { -1 };
1598                   for (SysStaff* sysStaff : *system->staves()) {
1599                         Staff* staff { score->staff(++staffNr)};
1600                         addSpaceAroundNormalBracket |= endNormalBracket == staffNr;
1601                         addSpaceAroundCurlyBracket  |= endCurlyBracket == staffNr;
1602                         for (const BracketItem* bi : staff->brackets()) {
1603                               if  (bi->bracketType() == BracketType::NORMAL) {
1604                                     addSpaceAroundNormalBracket |= staff->idx() > (endNormalBracket - 1);
1605                                     endNormalBracket = qMax(endNormalBracket, staff->idx() + bi->bracketSpan());
1606                                     }
1607                               else if(bi->bracketType() == BracketType::BRACE) {
1608                                     addSpaceAroundCurlyBracket |= staff->idx() > (endCurlyBracket - 1);
1609                                     endCurlyBracket = qMax(endCurlyBracket, staff->idx() + bi->bracketSpan());
1610                                     }
1611                               }
1612 
1613                         if (!sysStaff->show())
1614                               continue;
1615 
1616                         VerticalGapData* vgd = new VerticalGapData(!ngaps++, system, staff, sysStaff, fixedSpacer, prevYBottom);
1617                         fixedSpacer = nullptr;
1618 
1619                         if (newSystem) {
1620                               vgd->addSpaceBetweenSections();
1621                               newSystem = false;
1622                               }
1623                         if (addSpaceAroundNormalBracket || transferNormalBracket) {
1624                               vgd->addSpaceAroundNormalBracket();
1625                               addSpaceAroundNormalBracket = false;
1626                               transferNormalBracket = false;
1627                               }
1628                         if (addSpaceAroundCurlyBracket || transferCurlyBracket) {
1629                               vgd->addSpaceAroundCurlyBracket();
1630                               addSpaceAroundCurlyBracket = false;
1631                               transferCurlyBracket = false;
1632                               }
1633                         else if (staffNr < endCurlyBracket) {
1634                               vgd->insideCurlyBracket();
1635                               }
1636 
1637                         if (vbox) {
1638                               vgd->addSpaceAroundVBox(false);
1639                               vbox = false;
1640                               }
1641 
1642                         prevYBottom = system->y() + sysStaff->y() + sysStaff->bbox().height();
1643                         yBottom     = system->y() + sysStaff->y() + sysStaff->skyline().south().max();
1644                         vgdl.append(vgd);
1645                         }
1646                   transferNormalBracket = endNormalBracket >= 0;
1647                   transferCurlyBracket  = endCurlyBracket >= 0;
1648                   }
1649             fixedSpacer = system->getFixedSpacer();
1650             }
1651       --ngaps;
1652 
1653       qreal spaceLeft { page->height() - page->bm() - score->styleP(Sid::staffLowerBorder) - yBottom };
1654       if (spaceLeft <= 0.0)
1655             return;
1656 
1657       // Try to make the gaps equal, taking the spread factors and maximum spacing into account.
1658       static const int maxPasses { 20 };   // Saveguard to prevent endless loops.
1659       int pass { 0 };
1660       while (!almostZero(spaceLeft) && (ngaps > 0) && (++pass < maxPasses)) {
1661             ngaps = 0;
1662             qreal smallest     { vgdl.smallest()         };
1663             qreal nextSmallest { vgdl.smallest(smallest) };
1664             if (almostZero(smallest) || almostZero(nextSmallest))
1665                   break;
1666 
1667             if ((nextSmallest - smallest) * vgdl.sumStretchFactor() > spaceLeft)
1668                   nextSmallest = smallest + spaceLeft/vgdl.sumStretchFactor();
1669 
1670             qreal addedSpace { 0.0 };
1671             VerticalGapDataList modified;
1672             for (VerticalGapData* vgd : vgdl) {
1673                   if (!almostZero(vgd->spacing() - smallest))
1674                         continue;
1675                   qreal step { nextSmallest - vgd->spacing() };
1676                   if (step < 0.0)
1677                         continue;
1678                   step = vgd->addSpacing(step);
1679                   if (!almostZero(step)) {
1680                         addedSpace += step * vgd->factor();
1681                         modified.append(vgd);
1682                         ++ngaps;
1683                         }
1684                   if ((spaceLeft - addedSpace) <= 0.0)
1685                         break;
1686                   }
1687             if ((spaceLeft - addedSpace) <= 0.0)
1688                   {
1689                   for (VerticalGapData* vgd : modified)
1690                         vgd->undoLastAddSpacing();
1691                   ngaps = 0;
1692                   }
1693             else {
1694                   spaceLeft -= addedSpace;
1695                   }
1696             }
1697 
1698       // If there is still space left, distribute the space of the staves.
1699       const qreal maxPageFill { score->styleP(Sid::maxPageFillSpread) };
1700       pass = 0;
1701       ngaps = 1;
1702       while (!almostZero(spaceLeft) && !almostZero(maxPageFill) && (ngaps > 0) && (++pass < maxPasses)) {
1703             ngaps = 0;
1704             qreal addedSpace { 0.0 };
1705             for (VerticalGapData* vgd : vgdl) {
1706                   qreal step = spaceLeft / vgdl.sumStretchFactor();
1707                   step = vgd->addFillSpacing(step, maxPageFill);
1708                   if (!almostZero(step)) {
1709                         addedSpace += step * vgd->factor();
1710                         ++ngaps;
1711                         }
1712                   }
1713             spaceLeft -= addedSpace;
1714             }
1715 
1716       QSet<System*> systems;
1717       qreal systemShift { 0.0 };
1718       qreal staffShift  { 0.0 };
1719       System* prvSystem { nullptr };
1720       for (VerticalGapData* vgd : vgdl) {
1721             if (vgd->sysStaff)
1722                   systems.insert(vgd->system);
1723             systemShift += vgd->actualAddedSpace();
1724             if (prvSystem == vgd->system) {
1725                   staffShift += vgd->actualAddedSpace();
1726                   }
1727             else {
1728                   vgd->system->rypos() += systemShift;
1729                   if (prvSystem) {
1730                         prvSystem->setDistance(vgd->system->y() - prvSystem->y());
1731                         prvSystem->setHeight(prvSystem->height() + staffShift);
1732                         }
1733                   staffShift = 0.0;
1734                   }
1735 
1736             if (vgd->sysStaff)
1737                   vgd->sysStaff->bbox().translate(0.0, staffShift);
1738 
1739             prvSystem = vgd->system;
1740             }
1741       if (prvSystem) {
1742             prvSystem->setHeight(prvSystem->height() + staffShift);
1743             }
1744 
1745       for (System* system : systems) {
1746             system->setMeasureHeight(system->height());
1747             system->layoutBracketsVertical();
1748             system->layoutInstrumentNames();
1749             }
1750       vgdl.deleteAll();
1751       }
1752 
1753 //---------------------------------------------------------
1754 //   layoutPage
1755 //    restHeight - vertical space which has to be distributed
1756 //                 between systems
1757 //    The algorithm tries to produce most equally spaced
1758 //    systems.
1759 //---------------------------------------------------------
1760 
layoutPage(Page * page,qreal restHeight)1761 static void layoutPage(Page* page, qreal restHeight)
1762       {
1763       if (restHeight < 0.0) {
1764             qDebug("restHeight < 0.0: %f\n", restHeight);
1765             restHeight = 0;
1766             }
1767 
1768       Score* score = page->score();
1769       int gaps     = page->systems().size() - 1;
1770 
1771       QList<System*> sList;
1772 
1773       // build list of systems (excluding last)
1774       // set initial distance for each to the unstretched minimum distance to next
1775       for (int i = 0; i < gaps; ++i) {
1776             System* s1 = page->systems().at(i);
1777             System* s2 = page->systems().at(i+1);
1778             s1->setDistance(s2->y() - s1->y());
1779             if (s1->vbox() || s2->vbox() || s1->getFixedSpacer()) {
1780                   if (s2->vbox()) {
1781                         checkDivider(true, s1, 0.0, true);      // remove
1782                         checkDivider(false, s1, 0.0, true);     // remove
1783                         checkDivider(true, s2, 0.0, true);      // remove
1784                         checkDivider(false, s2, 0.0, true);     // remove
1785                         }
1786                   continue;
1787                   }
1788             sList.push_back(s1);
1789             }
1790 
1791       // last system needs no divider
1792       System* lastSystem = page->systems().back();
1793       checkDivider(true, lastSystem, 0.0, true);      // remove
1794       checkDivider(false, lastSystem, 0.0, true);     // remove
1795 
1796       if (sList.empty() || MScore::noVerticalStretch || score->enableVerticalSpread() || score->layoutMode() == LayoutMode::SYSTEM) {
1797             if (score->layoutMode() == LayoutMode::FLOAT) {
1798                   qreal y = restHeight * .5;
1799                   for (System* system : page->systems())
1800                         system->move(QPointF(0.0, y));
1801                   }
1802             else if ((score->layoutMode() != LayoutMode::SYSTEM) && score->enableVerticalSpread())
1803                   distributeStaves(page);
1804 
1805             // system dividers
1806             for (int i = 0; i < gaps; ++i) {
1807                   System* s1 = page->systems().at(i);
1808                   System* s2 = page->systems().at(i+1);
1809                   if (!(s1->vbox() || s2->vbox())) {
1810                         qreal yOffset = s1->height() + (s1->distance()-s1->height()) * .5;
1811                         checkDivider(true,  s1, yOffset);
1812                         checkDivider(false, s1, yOffset);
1813                         }
1814                   }
1815             return;
1816             }
1817 
1818       qreal maxDist = score->maxSystemDistance();
1819 
1820       // allocate space as needed to normalize system distance (bottom of one system to top of next)
1821       std::sort(sList.begin(), sList.end(), [](System* a, System* b) { return a->distance() - a->height() < b->distance() - b->height(); });
1822       System* s0 = sList[0];
1823       qreal dist = s0->distance() - s0->height();           // distance for shortest system
1824       for (int i = 1; i < sList.size(); ++i) {
1825             System* si = sList[i];
1826             qreal ndist = si->distance() - si->height();    // next taller system
1827             qreal fill  = ndist - dist;                     // amount by which this system distance exceeds next shorter
1828             if (fill > 0.0) {
1829                   qreal totalFill = fill * i;               // space required to add this amount to all shorter systems
1830                   if (totalFill > restHeight) {
1831                         totalFill = restHeight;             // too much; adjust amount
1832                         fill = restHeight / i;
1833                         }
1834                   for (int k = 0; k < i; ++k) {             // add amount to all shorter systems
1835                         System* s = sList[k];
1836                         qreal d = s->distance() + fill;
1837                         if ((d - s->height()) > maxDist)    // but don't exceed max system distance
1838                               d = qMax(maxDist + s->height(), s->distance());
1839                         s->setDistance(d);
1840                         }
1841                   restHeight -= totalFill;                  // reduce available space for next iteration
1842                   if (restHeight <= 0)
1843                         break;                              // no space left
1844                   }
1845             dist = ndist;                                   // set up for next iteration
1846             }
1847 
1848       if (restHeight > 0.0) {                               // space left?
1849             qreal fill = restHeight / sList.size();
1850             for (System* s : qAsConst(sList)) {                       // allocate it to systems equally
1851                   qreal d = s->distance() + fill;
1852                   if ((d - s->height()) > maxDist)          // but don't exceed max system distance
1853                         d = qMax(maxDist + s->height(), s->distance());
1854                   s->setDistance(d);
1855                   }
1856             }
1857 
1858       qreal y = page->systems().at(0)->y();
1859       for (int i = 0; i < gaps; ++i) {
1860             System* s1  = page->systems().at(i);
1861             System* s2  = page->systems().at(i+1);
1862             s1->rypos() = y;
1863             y          += s1->distance();
1864 
1865             if (!(s1->vbox() || s2->vbox())) {
1866                   qreal yOffset = s1->height() + (s1->distance()-s1->height()) * .5;
1867                   checkDivider(true,  s1, yOffset);
1868                   checkDivider(false, s1, yOffset);
1869                   }
1870             }
1871       page->systems().back()->rypos() = y;
1872       }
1873 
1874 //---------------------------------------------------------
1875 //   Spring
1876 //---------------------------------------------------------
1877 
1878 struct Spring {
1879       int seg;
1880       qreal stretch;
1881       qreal fix;
SpringMs::Spring1882       Spring(int i, qreal s, qreal f) : seg(i), stretch(s), fix(f) {}
1883       };
1884 
1885 typedef std::multimap<qreal, Spring, std::less<qreal> > SpringMap;
1886 
1887 //---------------------------------------------------------
1888 //   sff2
1889 //    compute 1/Force for a given Extend
1890 //---------------------------------------------------------
1891 
sff2(qreal width,qreal xMin,const SpringMap & springs)1892 static qreal sff2(qreal width, qreal xMin, const SpringMap& springs)
1893       {
1894       if (width <= xMin)
1895             return 0.0;
1896       auto i = springs.begin();
1897       qreal c  = i->second.stretch;
1898       if (c == 0.0)           //DEBUG
1899             c = 1.1;
1900       qreal f = 0.0;
1901       for (; i != springs.end();) {
1902             xMin -= i->second.fix;
1903             f = (width - xMin) / c;
1904             ++i;
1905             if (i == springs.end() || f <= i->first)
1906                   break;
1907             c += i->second.stretch;
1908             }
1909       return f;
1910       }
1911 
1912 //---------------------------------------------------------
1913 //   respace
1914 //---------------------------------------------------------
1915 
respace(std::vector<ChordRest * > * elements)1916 void Score::respace(std::vector<ChordRest*>* elements)
1917       {
1918       ChordRest* cr1 = elements->front();
1919       ChordRest* cr2 = elements->back();
1920       int n          = int(elements->size());
1921       qreal x1       = cr1->segment()->pos().x();
1922       qreal x2       = cr2->segment()->pos().x();
1923 
1924 #if (!defined (_MSCVER) && !defined (_MSC_VER))
1925       qreal width[n-1];
1926       int ticksList[n-1];
1927 #else
1928       // MSVC does not support VLA. Replace with std::vector. If profiling determines that the
1929       //    heap allocation is slow, an optimization might be used.
1930       std::vector<qreal> width(n-1);
1931       std::vector<int> ticksList(n-1);
1932 #endif
1933       int minTick = 100000;
1934 
1935       for (int i = 0; i < n-1; ++i) {
1936             ChordRest* cr  = (*elements)[i];
1937             ChordRest* ncr  = (*elements)[i+1];
1938             width[i]       = cr->shape().minHorizontalDistance(ncr->shape());
1939             ticksList[i]   = cr->ticks().ticks();
1940             minTick = qMin(ticksList[i], minTick);
1941             }
1942 
1943       //---------------------------------------------------
1944       // compute stretches
1945       //---------------------------------------------------
1946 
1947       SpringMap springs;
1948       qreal minimum = 0.0;
1949       for (int i = 0; i < n-1; ++i) {
1950             qreal w   = width[i];
1951             int t     = ticksList[i];
1952             qreal str = 1.0 + 0.865617 * log(qreal(t) / qreal(minTick));
1953             qreal d   = w / str;
1954 
1955             springs.insert(std::pair<qreal, Spring>(d, Spring(i, str, w)));
1956             minimum += w;
1957             }
1958 
1959       //---------------------------------------------------
1960       //    distribute stretch to elements
1961       //---------------------------------------------------
1962 
1963       qreal force = sff2(x2 - x1, minimum, springs);
1964       for (auto i = springs.begin(); i != springs.end(); ++i) {
1965             qreal stretch = force * i->second.stretch;
1966             if (stretch < i->second.fix)
1967                   stretch = i->second.fix;
1968             width[i->second.seg] = stretch;
1969             }
1970       qreal x = x1;
1971       for (int i = 1; i < n-1; ++i) {
1972             x += width[i-1];
1973             ChordRest* cr = (*elements)[i];
1974             qreal dx = x - cr->segment()->pos().x();
1975             cr->rxpos() += dx;
1976             }
1977       }
1978 
1979 //---------------------------------------------------------
1980 //   getNextPage
1981 //---------------------------------------------------------
1982 
getNextPage()1983 void LayoutContext::getNextPage()
1984       {
1985       if (!page || curPage >= score->npages()) {
1986             page = new Page(score);
1987             score->pages().push_back(page);
1988             prevSystem = nullptr;
1989             pageOldMeasure = nullptr;
1990             }
1991       else {
1992             page = score->pages()[curPage];
1993             QList<System*>& systems = page->systems();
1994             pageOldMeasure = systems.isEmpty() ? nullptr : systems.back()->measures().back();
1995             const int i = systems.indexOf(curSystem);
1996             if (i > 0 && systems[i-1]->page() == page) {
1997                   // Current and previous systems are on the current page.
1998                   // Erase only the current and the following systems
1999                   // as the previous one will not participate in layout.
2000                   systems.erase(systems.begin() + i, systems.end());
2001                   }
2002             else // system is not on the current page (or will be the first one)
2003                   systems.clear();
2004             prevSystem = systems.empty() ? nullptr : systems.back();
2005             }
2006       page->bbox().setRect(0.0, 0.0, score->loWidth(), score->loHeight());
2007       page->setNo(curPage);
2008       qreal x = 0.0;
2009       qreal y = 0.0;
2010       if (curPage) {
2011             Page* prevPage = score->pages()[curPage - 1];
2012             if (MScore::verticalOrientation())
2013                   y = prevPage->pos().y() + page->height() + MScore::verticalPageGap;
2014             else {
2015                   qreal gap = (curPage + score->pageNumberOffset()) & 1 ? MScore::horizontalPageGapOdd : MScore::horizontalPageGapEven;
2016                   x = prevPage->pos().x() + page->width() + gap;
2017                   }
2018             }
2019       ++curPage;
2020       page->setPos(x, y);
2021       }
2022 
2023 //---------------------------------------------------------
2024 //   getNextSystem
2025 //---------------------------------------------------------
2026 
getNextSystem(LayoutContext & lc)2027 System* Score::getNextSystem(LayoutContext& lc)
2028       {
2029       bool isVBox = lc.curMeasure->isVBox();
2030       System* system;
2031       if (lc.systemList.empty()) {
2032             system = new System(this);
2033             lc.systemOldMeasure = 0;
2034             }
2035       else {
2036             system = lc.systemList.takeFirst();
2037             lc.systemOldMeasure = system->measures().empty() ? 0 : system->measures().back();
2038             system->clear();   // remove measures from system
2039             }
2040       _systems.append(system);
2041       if (!isVBox) {
2042             int nstaves = Score::nstaves();
2043             system->adjustStavesNumber(nstaves);
2044             }
2045       return system;
2046       }
2047 
2048 //---------------------------------------------------------
2049 //   createMMRest
2050 //    create a multi measure rest from m to lm (inclusive)
2051 //---------------------------------------------------------
2052 
createMMRest(Measure * m,Measure * lm,const Fraction & len)2053 void Score::createMMRest(Measure* m, Measure* lm, const Fraction& len)
2054       {
2055       int n = 1;
2056       if (m != lm) {
2057             for (Measure* mm = m->nextMeasure(); mm; mm = mm->nextMeasure()) {
2058                   ++n;
2059                   mm->setMMRestCount(-1);
2060                   if (mm->mmRest())
2061                         undo(new ChangeMMRest(mm, 0));
2062                   if (mm == lm)
2063                         break;
2064                   }
2065             }
2066 
2067       Measure* mmr = m->mmRest();
2068       if (mmr) {
2069             // reuse existing mmrest
2070             if (mmr->ticks() != len) {
2071                   Segment* s = mmr->findSegmentR(SegmentType::EndBarLine, mmr->ticks());
2072                   // adjust length
2073                   mmr->setTicks(len);
2074                   // move existing end barline
2075                   if (s)
2076                         s->setRtick(len);
2077                   }
2078             mmr->removeSystemTrailer();
2079             }
2080       else {
2081             mmr = new Measure(this);
2082             mmr->setTicks(len);
2083             mmr->setTick(m->tick());
2084             undo(new ChangeMMRest(m, mmr));
2085             }
2086       mmr->setTimesig(m->timesig());
2087       mmr->setPageBreak(lm->pageBreak());
2088       mmr->setLineBreak(lm->lineBreak());
2089       mmr->setMMRestCount(n);
2090       mmr->setNo(m->no());
2091 
2092       Segment* ss = lm->findSegmentR(SegmentType::EndBarLine, lm->ticks());
2093       if (ss) {
2094             Segment* ds = mmr->undoGetSegmentR(SegmentType::EndBarLine, mmr->ticks());
2095             for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
2096                   Element* e = ss->element(staffIdx * VOICES);
2097                   if (e) {
2098                         bool generated = e->generated();
2099                         if (!ds->element(staffIdx * VOICES)) {
2100                               Element* ee = generated ? e->clone() : e->linkedClone();
2101                               ee->setGenerated(generated);
2102                               ee->setParent(ds);
2103                               undoAddElement(ee);
2104                               }
2105                         else {
2106                               BarLine* bd = toBarLine(ds->element(staffIdx * VOICES));
2107                               BarLine* bs = toBarLine(e);
2108                               if (!generated && !bd->links())
2109                                     undo(new Link(bd, bs));
2110                               if (bd->barLineType() != bs->barLineType()) {
2111                                     // change directly when generating mmrests, do not change underlying measures or follow links
2112                                     undo(new ChangeProperty(bd, Pid::BARLINE_TYPE, QVariant::fromValue(bs->barLineType()), PropertyFlags::NOSTYLE));
2113                                     undo(new ChangeProperty(bd, Pid::GENERATED, generated, PropertyFlags::NOSTYLE));
2114                                     }
2115                               }
2116                         }
2117                   }
2118             }
2119 
2120       Segment* clefSeg = lm->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, lm->ticks());
2121       if (clefSeg) {
2122             Segment* mmrClefSeg = mmr->undoGetSegment(clefSeg->segmentType(), lm->endTick());
2123             for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
2124                   const int track = staff2track(staffIdx);
2125                   Element* e = clefSeg->element(track);
2126                   if (e && e->isClef()) {
2127                         Clef* clef = toClef(e);
2128                         if (!mmrClefSeg->element(track)) {
2129                               Clef* mmrClef = clef->generated() ? clef->clone() : toClef(clef->linkedClone());
2130                               mmrClef->setParent(mmrClefSeg);
2131                               undoAddElement(mmrClef);
2132                               }
2133                         else {
2134                               Clef* mmrClef = toClef(mmrClefSeg->element(track));
2135                               mmrClef->setClefType(clef->clefType());
2136                               mmrClef->setShowCourtesy(clef->showCourtesy());
2137                               }
2138                         }
2139                   }
2140             }
2141 
2142       mmr->setRepeatStart(m->repeatStart() || lm->repeatStart());
2143       mmr->setRepeatEnd(m->repeatEnd() || lm->repeatEnd());
2144       mmr->setSectionBreak(lm->sectionBreak());
2145 
2146       ElementList oldList = mmr->takeElements();
2147       ElementList newList = lm->el();
2148 
2149       for (Element* e : m->el()) {
2150             if (e->isMarker())
2151                   newList.push_back(e);
2152             }
2153       for (Element* e : newList) {
2154             bool found = false;
2155             for (Element* ee : oldList) {
2156                   if (ee->type() == e->type() && ee->subtype() == e->subtype()) {
2157                         mmr->add(ee);
2158                         auto i = std::find(oldList.begin(), oldList.end(), ee);
2159                         if (i != oldList.end())
2160                               oldList.erase(i);
2161                         found = true;
2162                         break;
2163                         }
2164                   }
2165             if (!found)
2166                   mmr->add(e->clone());
2167             }
2168       for (Element* e : oldList)
2169             delete e;
2170       Segment* s = mmr->undoGetSegmentR(SegmentType::ChordRest, Fraction(0,1));
2171       for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
2172             int track = staffIdx * VOICES;
2173             if (s->element(track) == 0) {
2174                   Rest* r = new Rest(this);
2175                   r->setDurationType(TDuration::DurationType::V_MEASURE);
2176                   r->setTicks(mmr->ticks());
2177                   r->setTrack(track);
2178                   r->setParent(s);
2179                   undo(new AddElement(r));
2180                   }
2181             }
2182 
2183       //
2184       // check for clefs
2185       //
2186       Segment* cs = lm->findSegmentR(SegmentType::Clef, lm->ticks());
2187       Segment* ns = mmr->findSegment(SegmentType::Clef, lm->endTick());
2188       if (cs) {
2189             if (ns == 0)
2190                   ns = mmr->undoGetSegmentR(SegmentType::Clef, lm->ticks());
2191             ns->setEnabled(cs->enabled());
2192             ns->setTrailer(cs->trailer());
2193             for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
2194                   int track = staffIdx * VOICES;
2195                   Clef* clef = toClef(cs->element(track));
2196                   if (clef) {
2197                         if (ns->element(track) == 0)
2198                               ns->add(clef->clone());
2199                         else {
2200                               //TODO: check if same clef
2201                               }
2202                         }
2203                   }
2204             }
2205       else if (ns) {
2206             // TODO: remove elements from ns?
2207             undo(new RemoveElement(ns));
2208             }
2209 
2210       //
2211       // check for time signature
2212       //
2213       cs = m->findSegmentR(SegmentType::TimeSig, Fraction(0,1));
2214       ns = mmr->findSegment(SegmentType::TimeSig, m->tick());
2215       if (cs) {
2216             if (ns == 0)
2217                   ns = mmr->undoGetSegmentR(SegmentType::TimeSig, Fraction(0,1));
2218             ns->setEnabled(cs->enabled());
2219             ns->setHeader(cs->header());
2220             for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
2221                   int track = staffIdx * VOICES;
2222                   TimeSig* ts = toTimeSig(cs->element(track));
2223                   if (ts) {
2224                         TimeSig* nts = toTimeSig(ns->element(track));
2225                         if (!nts) {
2226                               nts = ts->generated() ? ts->clone() : toTimeSig(ts->linkedClone());
2227                               nts->setParent(ns);
2228                               undo(new AddElement(nts));
2229                               }
2230                         else {
2231                               nts->setSig(ts->sig(), ts->timeSigType());
2232                               nts->layout();
2233                               }
2234                         }
2235                   }
2236             }
2237       else if (ns) {
2238             // TODO: remove elements from ns?
2239             undo(new RemoveElement(ns));
2240             }
2241 
2242       //
2243       // check for ambitus
2244       //
2245       cs = m->findSegmentR(SegmentType::Ambitus, Fraction(0,1));
2246       ns = mmr->findSegment(SegmentType::Ambitus, m->tick());
2247       if (cs) {
2248             if (ns == 0)
2249                   ns = mmr->undoGetSegmentR(SegmentType::Ambitus, Fraction(0,1));
2250             for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
2251                   int track = staffIdx * VOICES;
2252                   Ambitus* a = toAmbitus(cs->element(track));
2253                   if (a) {
2254                         Ambitus* na = toAmbitus(ns->element(track));
2255                         if (!na) {
2256                               na = a->clone();
2257                               na->setParent(ns);
2258                               undo(new AddElement(na));
2259                               }
2260                         else {
2261                               na->initFrom(a);
2262                               na->layout();
2263                               }
2264                         }
2265                   }
2266             }
2267       else if (ns) {
2268             // TODO: remove elements from ns?
2269             undo(new RemoveElement(ns));
2270             }
2271 
2272       //
2273       // check for key signature
2274       //
2275       cs = m->findSegmentR(SegmentType::KeySig, Fraction(0,1));
2276       ns = mmr->findSegmentR(SegmentType::KeySig, Fraction(0,1));
2277       if (cs) {
2278             if (ns == 0)
2279                   ns = mmr->undoGetSegmentR(SegmentType::KeySig, Fraction(0,1));
2280             ns->setEnabled(cs->enabled());
2281             ns->setHeader(cs->header());
2282             for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
2283                   int track = staffIdx * VOICES;
2284                   KeySig* ks  = toKeySig(cs->element(track));
2285                   if (ks) {
2286                         KeySig* nks = toKeySig(ns->element(track));
2287                         if (!nks) {
2288                               nks = ks->generated() ? ks->clone() : toKeySig(ks->linkedClone());
2289                               nks->setParent(ns);
2290                               nks->setGenerated(true);
2291                               undo(new AddElement(nks));
2292                               }
2293                         else {
2294                               if (!(nks->keySigEvent() == ks->keySigEvent())) {
2295                                     bool addKey = ks->isChange();
2296                                     undo(new ChangeKeySig(nks, ks->keySigEvent(), nks->showCourtesy(), addKey));
2297                                     }
2298                               }
2299                         }
2300                   }
2301             }
2302       else if (ns) {
2303             ns->setEnabled(false);
2304             // TODO: remove elements from ns, then delete ns
2305             // previously we removed the segment if not empty,
2306             // but this resulted in "stale" keysig in mmrest after removed from underlying measure
2307             //undo(new RemoveElement(ns));
2308             }
2309 
2310       mmr->checkHeader();
2311       mmr->checkTrailer();
2312 
2313       //
2314       // check for rehearsal mark etc.
2315       //
2316       cs = m->findSegmentR(SegmentType::ChordRest, Fraction(0,1));
2317       if (cs) {
2318             // clone elements from underlying measure to mmr
2319             for (Element* e : cs->annotations()) {
2320                   // look at elements in underlying measure
2321                   if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() || e->isInstrumentChange()))
2322                         continue;
2323                   // try to find a match in mmr
2324                   bool found = false;
2325                   for (Element* ee : s->annotations()) {
2326                         if (e->linkList().contains(ee)) {
2327                               found = true;
2328                               break;
2329                               }
2330                         }
2331                   // add to mmr if no match found
2332                   if (!found) {
2333                         Element* ne = e->linkedClone();
2334                         ne->setParent(s);
2335                         undo(new AddElement(ne));
2336                         }
2337                   }
2338 
2339             // remove stray elements (possibly leftover from a previous layout of this mmr)
2340             // this should not happen since the elements are linked?
2341             for (Element* e : s->annotations()) {
2342                   // look at elements in mmr
2343                   if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() || e->isInstrumentChange()))
2344                         continue;
2345                   // try to find a match in underlying measure
2346                   bool found = false;
2347                   for (Element* ee : cs->annotations()) {
2348                         if (e->linkList().contains(ee)) {
2349                               found = true;
2350                               break;
2351                               }
2352                         }
2353                   // remove from mmr if no match found
2354                   if (!found)
2355                         undo(new RemoveElement(e));
2356                   }
2357             }
2358       MeasureBase* nm = _showVBox ? lm->next() : lm->nextMeasure();
2359       mmr->setNext(nm);
2360       mmr->setPrev(m->prev());
2361       }
2362 
2363 //---------------------------------------------------------
2364 // validMMRestMeasure
2365 //    return true if this might be a measure in a
2366 //    multi measure rest
2367 //---------------------------------------------------------
2368 
validMMRestMeasure(Measure * m)2369 static bool validMMRestMeasure(Measure* m)
2370       {
2371       if (m->irregular())
2372             return false;
2373 
2374       int n = 0;
2375       for (Segment* s = m->first(); s; s = s->next()) {
2376             for (Element* e : s->annotations()) {
2377                   if (!(e->isRehearsalMark() || e->isTempoText() || e->isHarmony() || e->isStaffText() || e->isSystemText() || e->isInstrumentChange()))
2378                         return false;
2379                   }
2380             if (s->isChordRestType()) {
2381                   bool restFound = false;
2382                   int tracks = m->score()->ntracks();
2383                   for (int track = 0; track < tracks; ++track) {
2384                         if ((track % VOICES) == 0 && !m->score()->staff(track/VOICES)->show()) {
2385                               track += VOICES-1;
2386                               continue;
2387                               }
2388                         if (s->element(track))  {
2389                               if (!s->element(track)->isRest())
2390                                     return false;
2391                               restFound = true;
2392                               }
2393                         }
2394                   for (Element* e : s->annotations()) {
2395                         if (e->isFermata())
2396                               return false;
2397                         }
2398                   if (restFound)
2399                         ++n;
2400                   // measure is not empty if there is more than one rest
2401                   if (n > 1)
2402                         return false;
2403                   }
2404             }
2405       return true;
2406       }
2407 
2408 //---------------------------------------------------------
2409 //  breakMultiMeasureRest
2410 //    return true if this measure should start a new
2411 //    multi measure rest
2412 //---------------------------------------------------------
2413 
breakMultiMeasureRest(Measure * m)2414 static bool breakMultiMeasureRest(Measure* m)
2415       {
2416       if (m->breakMultiMeasureRest())
2417             return true;
2418 
2419       if (m->repeatStart()
2420          || (m->prevMeasure() && m->prevMeasure()->repeatEnd())
2421          || (m->isIrregular())
2422          || (m->prevMeasure() && m->prevMeasure()->isIrregular())
2423          || (m->prevMeasure() && (m->prevMeasure()->sectionBreak())))
2424             return true;
2425 
2426       auto sl = m->score()->spannerMap().findOverlapping(m->tick().ticks(), m->endTick().ticks());
2427       for (auto i : sl) {
2428             Spanner* s = i.value;
2429             // break for first measure of volta or textline and first measure *after* volta
2430             if ((s->isVolta() || s->isTextLine()) && (s->tick() == m->tick() || s->tick2() == m->tick()))
2431                   return true;
2432             }
2433 
2434       // break for marker in this measure
2435       for (Element* e : m->el()) {
2436             if (e->isMarker()) {
2437                   Marker* mark = toMarker(e);
2438                   if (!(mark->align() & Align::RIGHT))
2439                         return true;
2440                   }
2441             }
2442 
2443       // break for marker & jump in previous measure
2444       Measure* pm = m->prevMeasure();
2445       if (pm) {
2446             for (Element* e : pm->el()) {
2447                   if (e->isJump())
2448                         return true;
2449                   else if (e->isMarker()) {
2450                         Marker* mark = toMarker(e);
2451                         if (mark->align() & Align::RIGHT)
2452                               return true;
2453                         }
2454                   }
2455             }
2456 
2457       for (Segment* s = m->first(); s; s = s->next()) {
2458             for (Element* e : s->annotations()) {
2459                   if (!e->visible())
2460                         continue;
2461                   if (e->isRehearsalMark() ||
2462                       e->isTempoText() ||
2463                       ((e->isHarmony() || e->isStaffText() || e->isSystemText() || e->isInstrumentChange()) && (e->systemFlag() || m->score()->staff(e->staffIdx())->show())))
2464                         return true;
2465                   }
2466             for (int staffIdx = 0; staffIdx < m->score()->nstaves(); ++staffIdx) {
2467                   if (!m->score()->staff(staffIdx)->show())
2468                         continue;
2469                   Element* e = s->element(staffIdx * VOICES);
2470                   if (!e || e->generated())
2471                         continue;
2472                   if (s->isStartRepeatBarLineType())
2473                         return true;
2474                   if (s->isType(SegmentType::KeySig | SegmentType::TimeSig) && m->tick().isNotZero())
2475                         return true;
2476                   if (s->isClefType()) {
2477                         if (s->tick() != m->endTick() && m->tick().isNotZero())
2478                               return true;
2479                         }
2480                   }
2481             }
2482       if (pm) {
2483             Segment* s = pm->findSegmentR(SegmentType::EndBarLine, pm->ticks());
2484             if (s) {
2485                   for (int staffIdx = 0; staffIdx < s->score()->nstaves(); ++staffIdx) {
2486                         BarLine* bl = toBarLine(s->element(staffIdx * VOICES));
2487                         if (bl) {
2488                               BarLineType t = bl->barLineType();
2489                               if (t != BarLineType::NORMAL && t != BarLineType::BROKEN && t != BarLineType::DOTTED && !bl->generated())
2490                                     return true;
2491                               else
2492                                     break;
2493                               }
2494                         }
2495                   }
2496             if (pm->findSegment(SegmentType::Clef, m->tick()))
2497                   return true;
2498             }
2499       return false;
2500       }
2501 
2502 //---------------------------------------------------------
2503 //   adjustMeasureNo
2504 //---------------------------------------------------------
2505 
adjustMeasureNo(MeasureBase * m)2506 int LayoutContext::adjustMeasureNo(MeasureBase* m)
2507       {
2508       measureNo += m->noOffset();
2509       m->setNo(measureNo);
2510       if (!m->irregular())          // don’t count measure
2511             ++measureNo;
2512       if (m->sectionBreakElement() && m->sectionBreakElement()->startWithMeasureOne())
2513             measureNo = 0;
2514       return measureNo;
2515       }
2516 
2517 //---------------------------------------------------------
2518 //   createBeams
2519 //    helper function
2520 //---------------------------------------------------------
2521 
createBeams(LayoutContext & lc,Measure * measure)2522 void Score::createBeams(LayoutContext& lc, Measure* measure)
2523       {
2524       bool crossMeasure = styleB(Sid::crossMeasureValues);
2525 
2526       for (int track = 0; track < ntracks(); ++track) {
2527             Staff* stf = staff(track2staff(track));
2528 
2529             // don’t compute beams for invisible staves and tablature without stems
2530             if (!stf->show() || (stf->isTabStaff(measure->tick()) && stf->staffType(measure->tick())->stemless()))
2531                   continue;
2532 
2533             ChordRest* a1    = 0;      // start of (potential) beam
2534             bool firstCR     = true;
2535             Beam* beam       = 0;      // current beam
2536             Beam::Mode bm    = Beam::Mode::AUTO;
2537             ChordRest* prev  = 0;
2538             bool checkBeats  = false;
2539             Fraction stretch = Fraction(1,1);
2540             QHash<int, TDuration> beatSubdivision;
2541 
2542             // if this measure is simple meter (actually X/4),
2543             // then perform a prepass to determine the subdivision of each beat
2544 
2545             beatSubdivision.clear();
2546             TimeSig* ts = stf->timeSig(measure->tick());
2547             checkBeats  = false;
2548             stretch     = ts ? ts->stretch() : Fraction(1,1);
2549 
2550             const SegmentType st = SegmentType::ChordRest;
2551             if (ts && ts->denominator() == 4) {
2552                   checkBeats = true;
2553                   for (Segment* s = measure->first(st); s; s = s->next(st)) {
2554                         ChordRest* mcr = toChordRest(s->element(track));
2555                         if (mcr == 0)
2556                               continue;
2557                         int beat = (mcr->rtick() * stretch).ticks() / MScore::division;
2558                         if (beatSubdivision.contains(beat))
2559                               beatSubdivision[beat] = qMin(beatSubdivision[beat], mcr->durationType());
2560                         else
2561                               beatSubdivision[beat] = mcr->durationType();
2562                         }
2563                   }
2564 
2565             for (Segment* segment = measure->first(st); segment; segment = segment->next(st)) {
2566                   ChordRest* cr = segment->cr(track);
2567                   if (cr == 0)
2568                         continue;
2569 
2570                   if (firstCR) {
2571                         firstCR = false;
2572                         // Handle cross-measure beams
2573                         Beam::Mode mode = cr->beamMode();
2574                         if (mode == Beam::Mode::MID || mode == Beam::Mode::END) {
2575                               ChordRest* prevCR = findCR(measure->tick() - Fraction::fromTicks(1), track);
2576                               if (prevCR) {
2577                                     const Measure* pm = prevCR->measure();
2578                                     if (!beamNoContinue(prevCR->beamMode())
2579                                         && !pm->lineBreak() && !pm->pageBreak() && !pm->sectionBreak()
2580                                         && lc.prevMeasure
2581                                         && prevCR->durationType().type() >= TDuration::DurationType::V_EIGHTH
2582                                         && prevCR->durationType().type() <= TDuration::DurationType::V_1024TH) {
2583                                           beam = prevCR->beam();
2584                                           //a1 = beam ? beam->elements().front() : prevCR;
2585                                           a1 = beam ? nullptr : prevCR; // when beam is found, a1 is no longer required.
2586                                           }
2587                                     }
2588                               }
2589                         }
2590 #if 0
2591                   for (Lyrics* l : cr->lyrics()) {
2592                         if (l)
2593                               l->layout();
2594                         }
2595 #endif
2596                   // handle grace notes and cross-measure beaming
2597                   // (tied chords?)
2598                   if (cr->isChord()) {
2599                         Chord* chord = toChord(cr);
2600                         beamGraceNotes(chord, false); // grace before
2601                         beamGraceNotes(chord, true);  // grace after
2602                         // set up for cross-measure values as soon as possible
2603                         // to have all computations (stems, hooks, ...) consistent with it
2604                         if (!chord->isGrace())
2605                               chord->crossMeasureSetup(crossMeasure);
2606                         }
2607 
2608                   if (cr->isRest() && cr->beamMode() == Beam::Mode::AUTO)
2609                         bm = Beam::Mode::NONE;           // do not beam rests set to Beam::Mode::AUTO
2610                   else
2611                         bm = Groups::endBeam(cr, prev);  // get defaults from time signature properties
2612 
2613                   // perform additional context-dependent checks
2614                   if (bm == Beam::Mode::AUTO) {
2615                         // check if we need to break beams according to minimum duration in current / previous beat
2616                         if (checkBeats && cr->rtick().isNotZero()) {
2617                               Fraction tick = cr->rtick() * stretch;
2618                               // check if on the beat
2619                               if ((tick.ticks() % MScore::division) == 0) {
2620                                     int beat = tick.ticks() / MScore::division;
2621                                     // get minimum duration for this & previous beat
2622                                     TDuration minDuration = qMin(beatSubdivision[beat], beatSubdivision[beat - 1]);
2623                                     // re-calculate beam as if this were the duration of current chordrest
2624                                     TDuration saveDuration        = cr->actualDurationType();
2625                                     TDuration saveCMDuration      = cr->crossMeasureDurationType();
2626                                     CrossMeasure saveCrossMeasVal = cr->crossMeasure();
2627                                     cr->setDurationType(minDuration);
2628                                     bm = Groups::endBeam(cr, prev);
2629                                     cr->setDurationType(saveDuration);
2630                                     cr->setCrossMeasure(saveCrossMeasVal);
2631                                     cr->setCrossMeasureDurationType(saveCMDuration);
2632                                     }
2633                               }
2634                         }
2635 
2636                   prev = cr;
2637 
2638                   // if chord has hooks and is 2nd element of a cross-measure value
2639                   // set beam mode to NONE (do not combine with following chord beam/hook, if any)
2640 
2641                   if (cr->durationType().hooks() > 0 && cr->crossMeasure() == CrossMeasure::SECOND)
2642                         bm = Beam::Mode::NONE;
2643 
2644                   if ((cr->durationType().type() <= TDuration::DurationType::V_QUARTER) || (bm == Beam::Mode::NONE)) {
2645                         bool removeBeam = true;
2646                         if (beam) {
2647                               beam->layout1();
2648                               removeBeam = (beam->elements().size() <= 1);
2649                               beam = 0;
2650                               }
2651                         if (a1) {
2652                               if (removeBeam)
2653                                     a1->removeDeleteBeam(false);
2654                               a1 = 0;
2655                               }
2656                         cr->removeDeleteBeam(false);
2657                         continue;
2658                         }
2659 
2660                   if (beam) {
2661                         bool beamEnd = (bm == Beam::Mode::BEGIN);
2662                         if (!beamEnd) {
2663                               cr->replaceBeam(beam);
2664                               cr = 0;
2665                               beamEnd = (bm == Beam::Mode::END);
2666                               }
2667                         if (beamEnd) {
2668                               beam->layout1();
2669                               beam = 0;
2670                               }
2671                         }
2672                   if (!cr)
2673                         continue;
2674 
2675                   if (a1 == 0)
2676                         a1 = cr;
2677                   else {
2678                         if (!beamModeMid(bm)
2679                            &&
2680                            (bm == Beam::Mode::BEGIN
2681                               || (a1->segment()->segmentType() != cr->segment()->segmentType())
2682                               || (a1->tick() + a1->actualTicks() < cr->tick())
2683                               )
2684                            )
2685                               {
2686                               a1->removeDeleteBeam(false);
2687                               a1 = cr;
2688                               }
2689                         else {
2690                               beam = a1->beam();
2691                               if (beam == 0 || beam->elements().front() != a1) {
2692                                     beam = new Beam(this);
2693                                     beam->setGenerated(true);
2694                                     beam->setTrack(track);
2695                                     a1->replaceBeam(beam);
2696                                     }
2697                               cr->replaceBeam(beam);
2698                               a1 = 0;
2699                               }
2700                         }
2701                   }
2702             if (beam)
2703                   beam->layout1();
2704             else if (a1) {
2705                   Fraction nextTick = a1->tick() + a1->actualTicks();
2706                   Measure* m = (nextTick >= measure->endTick() ? measure->nextMeasure() : measure);
2707                   ChordRest* nextCR = (m ? m->findChordRest(nextTick, track) : nullptr);
2708                   Beam* b = a1->beam();
2709                   if (!(b && b->elements().startsWith(a1) && nextCR && beamModeMid(nextCR->beamMode())))
2710                         a1->removeDeleteBeam(false);
2711                   }
2712             }
2713       }
2714 
2715 //---------------------------------------------------------
2716 //   breakCrossMeasureBeams
2717 //---------------------------------------------------------
2718 
breakCrossMeasureBeams(Measure * measure)2719 static void breakCrossMeasureBeams(Measure* measure)
2720       {
2721       MeasureBase* mbNext = measure->next();
2722       if (!mbNext || !mbNext->isMeasure())
2723             return;
2724 
2725       Measure* next = toMeasure(mbNext);
2726       Score* score = measure->score();
2727       const int ntracks = score->ntracks();
2728       Segment* fstSeg = next->first(SegmentType::ChordRest);
2729       if (!fstSeg)
2730             return;
2731 
2732       for (int track = 0; track < ntracks; ++track) {
2733             Staff* stf = score->staff(track2staff(track));
2734 
2735             // don’t compute beams for invisible staves and tablature without stems
2736             if (!stf->show() || (stf->isTabStaff(measure->tick()) && stf->staffType(measure->tick())->stemless()))
2737                   continue;
2738 
2739             Element* e = fstSeg->element(track);
2740             if (!e || !e->isChordRest())
2741                   continue;
2742 
2743             ChordRest* cr = toChordRest(e);
2744             Beam* beam = cr->beam();
2745             if (!beam || beam->elements().front()->measure() == next) // no beam or not cross-measure beam
2746                   continue;
2747 
2748             std::vector<ChordRest*> mElements;
2749             std::vector<ChordRest*> nextElements;
2750 
2751             for (ChordRest* beamCR : beam->elements()) {
2752                   if (beamCR->measure() == measure)
2753                         mElements.push_back(beamCR);
2754                   else
2755                         nextElements.push_back(beamCR);
2756                   }
2757 
2758             if (mElements.size() == 1)
2759                   mElements[0]->removeDeleteBeam(false);
2760 
2761             Beam* newBeam = nullptr;
2762             if (nextElements.size() > 1) {
2763                   newBeam = new Beam(score);
2764                   newBeam->setGenerated(true);
2765                   newBeam->setTrack(track);
2766                   }
2767 
2768             const bool nextBeamed = bool(newBeam);
2769             for (ChordRest* nextCR : nextElements) {
2770                   nextCR->removeDeleteBeam(nextBeamed);
2771                   if (newBeam)
2772                         newBeam->add(nextCR);
2773                   }
2774 
2775             if (newBeam)
2776                   newBeam->layout1();
2777             }
2778       }
2779 
2780 //---------------------------------------------------------
2781 //   layoutDrumsetChord
2782 //---------------------------------------------------------
2783 
layoutDrumsetChord(Chord * c,const Drumset * drumset,const StaffType * st,qreal spatium)2784 void layoutDrumsetChord(Chord* c, const Drumset* drumset, const StaffType* st, qreal spatium)
2785       {
2786       for (Note* note : c->notes()) {
2787             int pitch = note->pitch();
2788             if (!drumset->isValid(pitch)) {
2789                   // qDebug("unmapped drum note %d", pitch);
2790                   }
2791             else if (!note->fixed()) {
2792                   note->undoChangeProperty(Pid::HEAD_GROUP, int(drumset->noteHead(pitch)));
2793                   int line = drumset->line(pitch);
2794                   note->setLine(line);
2795 
2796                   int off  = st->stepOffset();
2797                   qreal ld = st->lineDistance().val();
2798                   note->rypos()  = (line + off * 2.0) * spatium * .5 * ld;
2799                   }
2800             }
2801       }
2802 
2803 //---------------------------------------------------------
2804 //   extendedStemLenWithTwoNotesTremolo
2805 //    Goal: To extend stem of one of the chords to make the tremolo less steep
2806 //    Returns a modified pair of stem lengths of two chords
2807 //---------------------------------------------------------
2808 
extendedStemLenWithTwoNoteTremolo(Tremolo * tremolo,qreal stemLen1,qreal stemLen2)2809 std::pair<qreal, qreal> extendedStemLenWithTwoNoteTremolo(Tremolo* tremolo, qreal stemLen1, qreal stemLen2)
2810       {
2811       const qreal spatium = tremolo->spatium();
2812       Chord* c1 = tremolo->chord1();
2813       Chord* c2 = tremolo->chord2();
2814       Stem*  s1 = c1->stem();
2815       Stem*  s2 = c2->stem();
2816       const qreal sgn1 = c1->up() ? -1.0 : 1.0;
2817       const qreal sgn2 = c2->up() ? -1.0 : 1.0;
2818       const qreal stemTipDistance = (s1 && s2) ? (s2->pagePos().y() + stemLen2) - (s1->pagePos().y() + stemLen1)
2819          : (c2->stemPos().y() + stemLen2) - (c1->stemPos().y() + stemLen1);
2820 
2821       // same staff & same direction: extend one of the stems
2822       if (c1->staffMove() == c2->staffMove() && c1->up() == c2->up()) {
2823             const bool stem1Higher = stemTipDistance > 0.0;
2824             if (std::abs(stemTipDistance) > 1.0 * spatium) {
2825                   if ((c1->up() && !stem1Higher) || (!c1->up() && stem1Higher))
2826                         return { stemLen1 + sgn1 * (std::abs(stemTipDistance) - 1.0 * spatium), stemLen2 };
2827                   else /* if ((c1->up() && stem1Higher) || (!c1->up() && !stem1Higher)) */
2828                         return { stemLen1, stemLen2 + sgn2 * (std::abs(stemTipDistance) - 1.0 * spatium) };
2829                   }
2830             }
2831 
2832 // TODO: cross-staff two-note tremolo. Currently doesn't generate the right result in some cases.
2833 #if 0
2834       // cross-staff & beam between staves: extend both stems by the same length
2835       else if (tremolo->crossStaffBeamBetween()) {
2836             const qreal sw = tremolo->score()->styleS(Sid::tremoloStrokeWidth).val();
2837             const qreal td = tremolo->score()->styleS(Sid::tremoloDistance).val();
2838             const qreal tremoloMinHeight = ((tremolo->lines() - 1) * td + sw) * spatium;
2839             const qreal dy = c1->up() ? tremoloMinHeight - stemTipDistance : tremoloMinHeight + stemTipDistance;
2840             const bool tooShort = dy > 1.0 * spatium;
2841             const bool tooLong = dy < -1.0 * spatium;
2842             const qreal idealDistance = 1.0 * spatium - tremoloMinHeight;
2843 
2844             if (tooShort)
2845                   return { stemLen1 + sgn1 * (std::abs(stemTipDistance) - idealDistance) / 2.0,
2846                            stemLen2 + sgn2 * (std::abs(stemTipDistance) - idealDistance) / 2.0 };
2847             else if (tooLong)
2848                   return { stemLen1 - sgn1 * (std::abs(stemTipDistance) + idealDistance) / 2.0,
2849                            stemLen2 - sgn2 * (std::abs(stemTipDistance) + idealDistance) / 2.0 };
2850             }
2851 #endif
2852 
2853       return { stemLen1, stemLen2 };
2854       }
2855 
2856 //---------------------------------------------------------
2857 //   getNextMeasure
2858 //---------------------------------------------------------
2859 
getNextMeasure(LayoutContext & lc)2860 void Score::getNextMeasure(LayoutContext& lc)
2861       {
2862       lc.prevMeasure = lc.curMeasure;
2863       lc.curMeasure  = lc.nextMeasure;
2864       if (!lc.curMeasure)
2865             lc.nextMeasure = _showVBox ? first() : firstMeasure();
2866       else
2867             lc.nextMeasure = _showVBox ? lc.curMeasure->next() : lc.curMeasure->nextMeasure();
2868       if (!lc.curMeasure)
2869             return;
2870 
2871       int mno = lc.adjustMeasureNo(lc.curMeasure);
2872 
2873       if (lc.curMeasure->isMeasure()) {
2874             if (score()->styleB(Sid::createMultiMeasureRests)) {
2875                   Measure* m = toMeasure(lc.curMeasure);
2876                   Measure* nm = m;
2877                   Measure* lm = nm;
2878                   int n       = 0;
2879                   Fraction len;
2880 
2881                   while (validMMRestMeasure(nm)) {
2882                         MeasureBase* mb = _showVBox ? nm->next() : nm->nextMeasure();
2883                         if (breakMultiMeasureRest(nm) && n)
2884                               break;
2885                         if (nm != m)
2886                               lc.adjustMeasureNo(nm);
2887                         ++n;
2888                         len += nm->ticks();
2889                         lm = nm;
2890                         if (!(mb && mb->isMeasure()))
2891                               break;
2892                         nm = toMeasure(mb);
2893                         }
2894                   if (n >= styleI(Sid::minEmptyMeasures)) {
2895                         createMMRest(m, lm, len);
2896                         lc.curMeasure  = m->mmRest();
2897                         lc.nextMeasure = _showVBox ?  lm->next() : lm->nextMeasure();
2898                         }
2899                   else {
2900                         if (m->mmRest())
2901                               undo(new ChangeMMRest(m, 0));
2902                         m->setMMRestCount(0);
2903                         lc.measureNo = mno;
2904                         }
2905                   }
2906             else if (toMeasure(lc.curMeasure)->isMMRest()) {
2907                   qDebug("mmrest: no %d += %d", lc.measureNo, toMeasure(lc.curMeasure)->mmRestCount());
2908                   lc.measureNo += toMeasure(lc.curMeasure)->mmRestCount() - 1;
2909                   }
2910             }
2911       if (!lc.curMeasure->isMeasure()) {
2912             lc.curMeasure->setTick(lc.tick);
2913             return;
2914             }
2915 
2916       //-----------------------------------------
2917       //    process one measure
2918       //-----------------------------------------
2919 
2920       Measure* measure = toMeasure(lc.curMeasure);
2921       measure->moveTicks(lc.tick - measure->tick());
2922 
2923       if (lineMode() && (measure->tick() < lc.startTick || measure->tick() > lc.endTick)) {
2924             // needed to reset segment widths if they can change after measure width is computed
2925             //for (Segment& s : measure->segments())
2926             //      s.createShapes();
2927             lc.tick += measure->ticks();
2928             return;
2929             }
2930 
2931       measure->connectTremolo();
2932 
2933       //
2934       // calculate accidentals and note lines,
2935       // create stem and set stem direction
2936       //
2937       for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
2938             const Staff* staff     = Score::staff(staffIdx);
2939             const Drumset* drumset = staff->part()->instrument(measure->tick())->useDrumset() ? staff->part()->instrument(measure->tick())->drumset() : 0;
2940             AccidentalState as;      // list of already set accidentals for this measure
2941             as.init(staff->keySigEvent(measure->tick()), staff->clef(measure->tick()));
2942 
2943             for (Segment& segment : measure->segments()) {
2944                   // TODO? maybe we do need to process it here to make it possible to enable later
2945                   //if (!segment.enabled())
2946                   //      continue;
2947                   if (segment.isKeySigType()) {
2948                         KeySig* ks = toKeySig(segment.element(staffIdx * VOICES));
2949                         if (!ks)
2950                               continue;
2951                         Fraction tick = segment.tick();
2952                         as.init(staff->keySigEvent(tick), staff->clef(tick));
2953                         ks->layout();
2954                         }
2955                   else if (segment.isChordRestType()) {
2956                         const StaffType* st = staff->staffTypeForElement(&segment);
2957                         int track     = staffIdx * VOICES;
2958                         int endTrack  = track + VOICES;
2959 
2960                         for (int t = track; t < endTrack; ++t) {
2961                               ChordRest* cr = segment.cr(t);
2962                               if (!cr)
2963                                     continue;
2964                               qreal m = staff->mag(&segment);
2965                               if (cr->small())
2966                                     m *= score()->styleD(Sid::smallNoteMag);
2967 
2968                               if (cr->isChord()) {
2969                                     Chord* chord = toChord(cr);
2970                                     chord->cmdUpdateNotes(&as);
2971                                     for (Chord* c : chord->graceNotes()) {
2972                                           c->setMag(m * score()->styleD(Sid::graceNoteMag));
2973                                           c->computeUp();
2974                                           if (c->stemDirection() != Direction::AUTO)
2975                                                 c->setUp(c->stemDirection() == Direction::UP);
2976                                           else
2977                                                 c->setUp(!(t % 2));
2978                                           if (drumset)
2979                                                 layoutDrumsetChord(c, drumset, st, spatium());
2980                                           c->layoutStem1();
2981                                           }
2982                                     if (drumset)
2983                                           layoutDrumsetChord(chord, drumset, st, spatium());
2984                                     chord->computeUp();
2985                                     chord->layoutStem1();   // create stems needed to calculate spacing
2986                                                             // stem direction can change later during beam processing
2987 
2988                                     // if there is a two-note tremolo attached, and it is too steep,
2989                                     // extend stem of one of the chords (if not cross-staff)
2990                                     // or extend both stems (if cross-staff)
2991                                     // this should be done after the stem lengths of two notes are both calculated
2992                                     if (chord->tremolo() && chord == chord->tremolo()->chord2()) {
2993                                           Stem* stem1 = chord->tremolo()->chord1()->stem();
2994                                           Stem* stem2 = chord->tremolo()->chord2()->stem();
2995                                           if (stem1 && stem2) {
2996                                                 std::pair<qreal, qreal> extendedLen = extendedStemLenWithTwoNoteTremolo(chord->tremolo(),
2997                                                    stem1->p2().y(), stem2->p2().y());
2998                                                 stem1->setLen(extendedLen.first);
2999                                                 stem2->setLen(extendedLen.second);
3000                                                 }
3001                                           }
3002                                     }
3003                               cr->setMag(m);
3004                               }
3005                         }
3006                   else if (segment.isClefType()) {
3007                         Element* e = segment.element(staffIdx * VOICES);
3008                         if (e) {
3009                               toClef(e)->setSmall(true);
3010                               e->layout();
3011                               }
3012                         }
3013                   else if (segment.isType(SegmentType::TimeSig | SegmentType::Ambitus | SegmentType::HeaderClef)) {
3014                         Element* e = segment.element(staffIdx * VOICES);
3015                         if (e)
3016                               e->layout();
3017                         }
3018                   }
3019             }
3020 
3021       createBeams(lc, measure);
3022 
3023       for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
3024             for (Segment& segment : measure->segments()) {
3025                   if (segment.isChordRestType()) {
3026                         layoutChords1(&segment, staffIdx);
3027                         for (int voice = 0; voice < VOICES; ++voice) {
3028                               ChordRest* cr = segment.cr(staffIdx * VOICES + voice);
3029                               if (cr) {
3030                                     for (Lyrics* l : cr->lyrics()) {
3031                                           if (l)
3032                                                 l->layout();
3033                                           }
3034                                     }
3035                               }
3036                         }
3037                   }
3038             }
3039 
3040       measure->computeTicks();
3041 
3042       for (Segment& segment : measure->segments()) {
3043             if (segment.isBreathType()) {
3044                   for (Element* e : segment.elist()) {
3045                         if (e && e->isBreath())
3046                               e->layout();
3047                         }
3048                   }
3049             else if (segment.isChordRestType()) {
3050                   for (Element* e : segment.annotations()) {
3051                         if (e->isSymbol())
3052                               e->layout();
3053                         }
3054                   }
3055             }
3056 
3057       rebuildTempoAndTimeSigMaps(measure);
3058 
3059       Segment* seg = measure->findSegmentR(SegmentType::StartRepeatBarLine, Fraction(0,1));
3060       if (measure->repeatStart()) {
3061             if (!seg)
3062                   seg = measure->getSegmentR(SegmentType::StartRepeatBarLine, Fraction(0,1));
3063             measure->barLinesSetSpan(seg);      // this also creates necessary barlines
3064             for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
3065                   BarLine* b = toBarLine(seg->element(staffIdx * VOICES));
3066                   if (b) {
3067                         b->setBarLineType(BarLineType::START_REPEAT);
3068                         b->layout();
3069                         }
3070                   }
3071             }
3072       else if (seg)
3073             score()->undoRemoveElement(seg);
3074 
3075       for (Segment& s : measure->segments()) {
3076             // TODO? maybe we do need to process it here to make it possible to enable later
3077             //if (!s.enabled())
3078             //      continue;
3079             // DEBUG: relayout grace notes as beaming/flags may have changed
3080             if (s.isChordRestType()) {
3081                   for (Element* e : s.elist()) {
3082                         if (e && e->isChord()) {
3083                               Chord* chord = toChord(e);
3084                               chord->layout();
3085 //                              if (chord->tremolo())            // debug
3086 //                                    chord->tremolo()->layout();
3087                               }
3088                         }
3089                   }
3090             else if (s.isEndBarLineType())
3091                   continue;
3092             s.createShapes();
3093             }
3094 
3095       lc.tick += measure->ticks();
3096       }
3097 
3098 //---------------------------------------------------------
3099 //   isTopBeam
3100 //    returns true for the first CR of a beam that is not cross-staff
3101 //---------------------------------------------------------
3102 
isTopBeam(ChordRest * cr)3103 bool isTopBeam(ChordRest* cr)
3104       {
3105       Beam* b = cr->beam();
3106       if (b && b->elements().front() == cr) {
3107             // beam already considered cross?
3108             if (b->cross())
3109                   return false;
3110 
3111             // for beams not already considered cross,
3112             // consider them so here if any elements were moved up
3113             for (ChordRest* cr1 : b->elements()) {
3114                   // some element moved up?
3115                   if (cr1->staffMove() < 0)
3116                         return false;
3117                   }
3118 
3119             // not cross
3120             return true;
3121             }
3122 
3123       // no beam or not first element
3124       return false;
3125       }
3126 
3127 //---------------------------------------------------------
3128 //   notTopBeam
3129 //    returns true for the first CR of a beam that is cross-staff
3130 //---------------------------------------------------------
3131 
notTopBeam(ChordRest * cr)3132 bool notTopBeam(ChordRest* cr)
3133       {
3134       Beam* b = cr->beam();
3135       if (b && b->elements().front() == cr) {
3136             // beam already considered cross?
3137             if (b->cross())
3138                   return true;
3139 
3140             // for beams not already considered cross,
3141             // consider them so here if any elements were moved up
3142             for (ChordRest* cr1 : b->elements()) {
3143                   // some element moved up?
3144                   if (cr1->staffMove() < 0)
3145                         return true;
3146                   }
3147 
3148             // not cross
3149             return false;
3150             }
3151 
3152       // no beam or not first element
3153       return false;
3154       }
3155 
3156 //---------------------------------------------------------
3157 //   isTopTuplet
3158 //    returns true for the first CR of a tuplet that is not cross-staff
3159 //---------------------------------------------------------
3160 
isTopTuplet(ChordRest * cr)3161 bool isTopTuplet(ChordRest* cr)
3162       {
3163       Tuplet* t = cr->tuplet();
3164       if (t && t->elements().front() == cr) {
3165             // find top level tuplet
3166             while (t->tuplet())
3167                   t = t->tuplet();
3168             // consider tuplet cross if anything moved within it
3169             if (t->cross())
3170                   return false;
3171             else
3172                   return true;
3173             }
3174 
3175       // no tuplet or not first element
3176       return false;
3177       }
3178 
3179 //---------------------------------------------------------
3180 //   notTopTuplet
3181 //    returns true for the first CR of a tuplet that is cross-staff
3182 //---------------------------------------------------------
3183 
notTopTuplet(ChordRest * cr)3184 bool notTopTuplet(ChordRest* cr)
3185       {
3186       Tuplet* t = cr->tuplet();
3187       if (t && t->elements().front() == cr) {
3188             // find top level tuplet
3189             while (t->tuplet())
3190                   t = t->tuplet();
3191             // consider tuplet cross if anything moved within it
3192             if (t->cross())
3193                   return true;
3194             else
3195                   return false;
3196             }
3197 
3198       // no tuplet or not first element
3199       return false;
3200       }
3201 
3202 
3203 //---------------------------------------------------------
3204 //   findLyricsMaxY
3205 //---------------------------------------------------------
3206 
findLyricsMaxY(Segment & s,int staffIdx)3207 static qreal findLyricsMaxY(Segment& s, int staffIdx)
3208       {
3209       qreal yMax = 0.0;
3210       if (!s.isChordRestType())
3211             return yMax;
3212 
3213       qreal lyricsMinTopDistance = s.score()->styleP(Sid::lyricsMinTopDistance);
3214 
3215       for (int voice = 0; voice < VOICES; ++voice) {
3216             ChordRest* cr = s.cr(staffIdx * VOICES + voice);
3217             if (cr && !cr->lyrics().empty()) {
3218                   SkylineLine sk(true);
3219 
3220                   for (Lyrics* l : cr->lyrics()) {
3221                         if (l->autoplace() && l->placeBelow()) {
3222                               qreal yOff = l->offset().y();
3223                               QPointF offset = l->pos() + cr->pos() + s.pos() + s.measure()->pos();
3224                               QRectF r = l->bbox().translated(offset);
3225                               r.translate(0.0, -yOff);
3226                               sk.add(r.x(), r.top(), r.width());
3227                               }
3228                         }
3229                   SysStaff* ss = s.measure()->system()->staff(staffIdx);
3230                   for (Lyrics* l : cr->lyrics()) {
3231                         if (l->autoplace() && l->placeBelow()) {
3232                               qreal y = ss->skyline().south().minDistance(sk);
3233                               if (y > -lyricsMinTopDistance)
3234                                     yMax = qMax(yMax, y + lyricsMinTopDistance);
3235                               }
3236                         }
3237                   }
3238             }
3239       return yMax;
3240       }
3241 
3242 //---------------------------------------------------------
3243 //   findLyricsMinY
3244 //---------------------------------------------------------
3245 
findLyricsMinY(Segment & s,int staffIdx)3246 static qreal findLyricsMinY(Segment& s, int staffIdx)
3247       {
3248       qreal yMin = 0.0;
3249       if (!s.isChordRestType())
3250             return yMin;
3251       qreal lyricsMinTopDistance = s.score()->styleP(Sid::lyricsMinTopDistance);
3252       for (int voice = 0; voice < VOICES; ++voice) {
3253             ChordRest* cr = s.cr(staffIdx * VOICES + voice);
3254             if (cr && !cr->lyrics().empty()) {
3255                   SkylineLine sk(false);
3256 
3257                   for (Lyrics* l : cr->lyrics()) {
3258                         if (l->autoplace() && l->placeAbove()) {
3259                               qreal yOff = l->offset().y();
3260                               QRectF r = l->bbox().translated(l->pos() + cr->pos() + s.pos() + s.measure()->pos());
3261                               r.translate(0.0, -yOff);
3262                               sk.add(r.x(), r.bottom(), r.width());
3263                               }
3264                         }
3265                   SysStaff* ss = s.measure()->system()->staff(staffIdx);
3266                   for (Lyrics* l : cr->lyrics()) {
3267                         if (l->autoplace() && l->placeAbove()) {
3268                               qreal y = sk.minDistance(ss->skyline().north());
3269                               if (y > -lyricsMinTopDistance)
3270                                     yMin = qMin(yMin, -y - lyricsMinTopDistance);
3271                               }
3272                         }
3273                   }
3274             }
3275       return yMin;
3276       }
3277 
findLyricsMaxY(Measure * m,int staffIdx)3278 static qreal findLyricsMaxY(Measure* m, int staffIdx)
3279       {
3280       qreal yMax = 0.0;
3281       for (Segment& s : m->segments())
3282             yMax = qMax(yMax, findLyricsMaxY(s, staffIdx));
3283       return yMax;
3284       }
3285 
findLyricsMinY(Measure * m,int staffIdx)3286 static qreal findLyricsMinY(Measure* m, int staffIdx)
3287       {
3288       qreal yMin = 0.0;
3289       for (Segment& s : m->segments())
3290             yMin = qMin(yMin, findLyricsMinY(s, staffIdx));
3291       return yMin;
3292       }
3293 
3294 //---------------------------------------------------------
3295 //   applyLyricsMax
3296 //---------------------------------------------------------
3297 
applyLyricsMax(Segment & s,int staffIdx,qreal yMax)3298 static void applyLyricsMax(Segment& s, int staffIdx, qreal yMax)
3299       {
3300       if (!s.isChordRestType())
3301             return;
3302       Skyline& sk = s.measure()->system()->staff(staffIdx)->skyline();
3303       for (int voice = 0; voice < VOICES; ++voice) {
3304             ChordRest* cr = s.cr(staffIdx * VOICES + voice);
3305             if (cr && !cr->lyrics().empty()) {
3306                   qreal lyricsMinBottomDistance = s.score()->styleP(Sid::lyricsMinBottomDistance);
3307                   for (Lyrics* l : cr->lyrics()) {
3308                         if (l->autoplace() && l->placeBelow()) {
3309                               l->rypos() += yMax - l->propertyDefault(Pid::OFFSET).toPointF().y();
3310                               if (l->addToSkyline()) {
3311                                     QPointF offset = l->pos() + cr->pos() + s.pos() + s.measure()->pos();
3312                                     sk.add(l->bbox().translated(offset).adjusted(0.0, 0.0, 0.0, lyricsMinBottomDistance));
3313                                     }
3314                               }
3315                         }
3316                   }
3317             }
3318       }
3319 
applyLyricsMax(Measure * m,int staffIdx,qreal yMax)3320 static void applyLyricsMax(Measure* m, int staffIdx, qreal yMax)
3321       {
3322       for (Segment& s : m->segments())
3323             applyLyricsMax(s, staffIdx, yMax);
3324       }
3325 
3326 //---------------------------------------------------------
3327 //   applyLyricsMin
3328 //---------------------------------------------------------
3329 
applyLyricsMin(ChordRest * cr,int staffIdx,qreal yMin)3330 static void applyLyricsMin(ChordRest* cr, int staffIdx, qreal yMin)
3331       {
3332       Skyline& sk = cr->measure()->system()->staff(staffIdx)->skyline();
3333       for (Lyrics* l : cr->lyrics()) {
3334             if (l->autoplace() && l->placeAbove()) {
3335                   l->rypos() += yMin - l->propertyDefault(Pid::OFFSET).toPointF().y();
3336                   if (l->addToSkyline()) {
3337                         QPointF offset = l->pos() + cr->pos() + cr->segment()->pos() + cr->segment()->measure()->pos();
3338                         sk.add(l->bbox().translated(offset));
3339                         }
3340                   }
3341             }
3342       }
3343 
applyLyricsMin(Measure * m,int staffIdx,qreal yMin)3344 static void applyLyricsMin(Measure* m, int staffIdx, qreal yMin)
3345       {
3346       for (Segment& s : m->segments()) {
3347             if (s.isChordRestType()) {
3348                   for (int voice = 0; voice < VOICES; ++voice) {
3349                         ChordRest* cr = s.cr(staffIdx * VOICES + voice);
3350                         if (cr)
3351                               applyLyricsMin(cr, staffIdx, yMin);
3352                         }
3353                   }
3354             }
3355       }
3356 
3357 //---------------------------------------------------------
3358 //   restoreBeams
3359 //---------------------------------------------------------
3360 
restoreBeams(Measure * m)3361 static void restoreBeams(Measure* m)
3362       {
3363       for (Segment* s = m->first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
3364             for (Element* e : s->elist()) {
3365                   if (e && e->isChordRest()) {
3366                         ChordRest* cr = toChordRest(e);
3367                         if (isTopBeam(cr)) {
3368                               Beam* b = cr->beam();
3369                               b->layout();
3370                               b->addSkyline(m->system()->staff(b->staffIdx())->skyline());
3371                               }
3372                         }
3373                   }
3374             }
3375       }
3376 
3377 //---------------------------------------------------------
3378 //   layoutLyrics
3379 //
3380 //    vertical align lyrics
3381 //
3382 //---------------------------------------------------------
3383 
layoutLyrics(System * system)3384 void Score::layoutLyrics(System* system)
3385       {
3386       std::vector<int> visibleStaves;
3387       for (int staffIdx = system->firstVisibleStaff(); staffIdx < nstaves(); staffIdx = system->nextVisibleStaff(staffIdx))
3388             visibleStaves.push_back(staffIdx);
3389 
3390       //int nAbove[nstaves()];
3391       std::vector<int> VnAbove(nstaves());
3392 
3393       for (int staffIdx : visibleStaves) {
3394             VnAbove[staffIdx] = 0;
3395             for (MeasureBase* mb : system->measures()) {
3396                   if (!mb->isMeasure())
3397                         continue;
3398                   Measure* m = toMeasure(mb);
3399                   for (Segment& s : m->segments()) {
3400                         if (s.isChordRestType()) {
3401                               for (int voice = 0; voice < VOICES; ++voice) {
3402                                     ChordRest* cr = s.cr(staffIdx * VOICES + voice);
3403                                     if (cr) {
3404                                           int nA = 0;
3405                                           for (Lyrics* l : cr->lyrics()) {
3406                                                 // user adjusted offset can possibly change placement
3407                                                 if (l->offsetChanged() != OffsetChange::NONE) {
3408                                                       Placement p = l->placement();
3409                                                       l->rebaseOffset();
3410                                                       if (l->placement() != p) {
3411                                                             l->undoResetProperty(Pid::AUTOPLACE);
3412                                                             //l->undoResetProperty(Pid::OFFSET);
3413                                                             //l->layout();
3414                                                             }
3415                                                       }
3416                                                 l->setOffsetChanged(false);
3417                                                 if (l->placeAbove())
3418                                                       ++nA;
3419                                                 }
3420                                           VnAbove[staffIdx] = qMax(VnAbove[staffIdx], nA);
3421                                           }
3422                                     }
3423                               }
3424                         }
3425                   }
3426             }
3427 
3428       for (int staffIdx : visibleStaves) {
3429             for (MeasureBase* mb : system->measures()) {
3430                   if (!mb->isMeasure())
3431                         continue;
3432                   Measure* m = toMeasure(mb);
3433                   for (Segment& s : m->segments()) {
3434                         if (s.isChordRestType()) {
3435                               for (int voice = 0; voice < VOICES; ++voice) {
3436                                     ChordRest* cr = s.cr(staffIdx * VOICES + voice);
3437                                     if (cr) {
3438                                           for (Lyrics* l : cr->lyrics())
3439                                                 l->layout2(VnAbove[staffIdx]);
3440                                           }
3441                                     }
3442                               }
3443                         }
3444                   }
3445             }
3446 
3447       VerticalAlignRange ar = VerticalAlignRange(styleI(Sid::autoplaceVerticalAlignRange));
3448 
3449       switch (ar) {
3450             case VerticalAlignRange::MEASURE:
3451                   for (MeasureBase* mb : system->measures()) {
3452                         if (!mb->isMeasure())
3453                               continue;
3454                         Measure* m = toMeasure(mb);
3455                         for (int staffIdx : visibleStaves) {
3456                               qreal yMax = findLyricsMaxY(m, staffIdx);
3457                               applyLyricsMax(m, staffIdx, yMax);
3458                               }
3459                         }
3460                   break;
3461             case VerticalAlignRange::SYSTEM:
3462                   for (int staffIdx : visibleStaves) {
3463                         qreal yMax = 0.0;
3464                         qreal yMin = 0.0;
3465                         for (MeasureBase* mb : system->measures()) {
3466                               if (!mb->isMeasure())
3467                                     continue;
3468                               yMax = qMax<qreal>(yMax, findLyricsMaxY(toMeasure(mb), staffIdx));
3469                               yMin = qMin(yMin, findLyricsMinY(toMeasure(mb), staffIdx));
3470                               }
3471                         for (MeasureBase* mb : system->measures()) {
3472                               if (!mb->isMeasure())
3473                                     continue;
3474                               applyLyricsMax(toMeasure(mb), staffIdx, yMax);
3475                               applyLyricsMin(toMeasure(mb), staffIdx, yMin);
3476                               }
3477                         }
3478                   break;
3479             case VerticalAlignRange::SEGMENT:
3480                   for (MeasureBase* mb : system->measures()) {
3481                         if (!mb->isMeasure())
3482                               continue;
3483                         Measure* m = toMeasure(mb);
3484                         for (int staffIdx : visibleStaves) {
3485                               for (Segment& s : m->segments()) {
3486                                     qreal yMax = findLyricsMaxY(s, staffIdx);
3487                                     applyLyricsMax(s, staffIdx, yMax);
3488                                     }
3489                               }
3490                         }
3491                   break;
3492             }
3493       }
3494 
3495 //---------------------------------------------------------
3496 //   layoutTies
3497 //---------------------------------------------------------
3498 
layoutTies(Chord * ch,System * system,const Fraction & stick)3499 void layoutTies(Chord* ch, System* system, const Fraction& stick)
3500       {
3501       SysStaff* staff = system->staff(ch->staffIdx());
3502       if (!staff->show())
3503             return;
3504       for (Note* note : ch->notes()) {
3505             Tie* t = note->tieFor();
3506             if (t) {
3507                   TieSegment* ts = t->layoutFor(system);
3508                   if (ts && ts->addToSkyline())
3509                         staff->skyline().add(ts->shape().translated(ts->pos()));
3510                   }
3511             t = note->tieBack();
3512             if (t) {
3513                   if (t->startNote()->tick() < stick) {
3514                         TieSegment* ts = t->layoutBack(system);
3515                         if (ts && ts->addToSkyline())
3516                               staff->skyline().add(ts->shape().translated(ts->pos()));
3517                         }
3518                   }
3519             }
3520       }
3521 
3522 //---------------------------------------------------------
3523 //   layoutHarmonies
3524 //---------------------------------------------------------
3525 
layoutHarmonies(const std::vector<Segment * > & sl)3526 void layoutHarmonies(const std::vector<Segment*>& sl)
3527       {
3528       for (const Segment* s : sl) {
3529             for (Element* e : s->annotations()) {
3530                   if (e->isHarmony()) {
3531                         Harmony* h = toHarmony(e);
3532                         // For chord symbols that coincide with a chord or rest,
3533                         // a partial layout can also happen (if needed) during ChordRest layout
3534                         // in order to calculate a bbox and allocate its shape to the ChordRest.
3535                         // But that layout (if it happens at all) does not do autoplace,
3536                         // so we need the full layout here.
3537                         h->layout();
3538                         h->autoplaceSegmentElement();
3539                         }
3540                   }
3541             }
3542       }
3543 
3544 //---------------------------------------------------------
3545 //   alignHarmonies
3546 //---------------------------------------------------------
3547 
alignHarmonies(const System * system,const std::vector<Segment * > & sl,bool harmony,const qreal maxShiftAbove,const qreal maxShiftBelow)3548 void alignHarmonies(const System* system, const std::vector<Segment*>& sl, bool harmony, const qreal maxShiftAbove, const qreal maxShiftBelow)
3549       {
3550 
3551       // Help class.
3552       // Contains harmonies/fretboard per segment.
3553       class HarmonyList : public QList<Element*> {
3554             QMap<const Segment*, QList<Element*>> elements;
3555             QList<Element*> modified;
3556 
3557             Element* getReferenceElement(const Segment* s, bool above, bool visible) const
3558                   {
3559                   // Returns the reference element for aligning.
3560                   // When a segments contains multiple harmonies/fretboard, the lowest placed
3561                   // element (for placement above, otherwise the highest placed element) is
3562                   // used for alignment.
3563                   Element* element { nullptr };
3564                   for (Element* e : elements[s]) {
3565                         // Only chord symbols have styled offset, fretboards don't.
3566                         if (!e->autoplace() || (e->isHarmony() && !e->isStyled(Pid::OFFSET)) || (visible && !e->visible()))
3567                               continue;
3568                         if (!element) {
3569                               element = e;
3570                               }
3571                         else {
3572                               if ((e->placeAbove() &&  above && (element->y() < e->y())) ||
3573                                   (e->placeBelow() && !above && (element->y() > e->y())))
3574                                     element = e;
3575                               }
3576                          }
3577                   return element;
3578                   }
3579 
3580          public:
3581             HarmonyList()
3582                   {
3583                   elements.clear();
3584                   modified.clear();
3585                   }
3586 
3587             void append(const Segment* s, Element* e)
3588                   {
3589                   elements[s].append(e);
3590                   }
3591 
3592             qreal getReferenceHeight(bool above) const
3593                   {
3594                   // The reference height is the height of
3595                   //    the lowest element if placed above
3596                   // or
3597                   //    the highest element if placed below.
3598                   bool first { true };
3599                   qreal ref { 0.0 };
3600                   for (auto s : elements.keys()) {
3601                         Element* e { getReferenceElement(s, above, true) };
3602                         if (!e)
3603                               continue;
3604                         if (e->placeAbove() && above) {
3605                               ref = first ? e->y() : qMin(ref, e->y());
3606                               first = false;
3607                               }
3608                         else if (e->placeBelow() && !above) {
3609                               ref = first ? e->y() : qMax(ref, e->y());
3610                               first = false;
3611                               }
3612                         }
3613                   return ref;
3614                   }
3615 
3616             bool align(bool above, qreal reference, qreal maxShift)
3617                   {
3618                   // Align the elements. If a segment contains multiple elements,
3619                   // only the reference elements is used in the algorithm. All other
3620                   // elements will remain their original placement with respect to
3621                   // the reference element.
3622                   bool moved { false };
3623                   if (almostZero(reference))
3624                         return moved;
3625 
3626                   for (auto s : elements.keys()) {
3627                         QList<Element*> handled;
3628                         Element* be = getReferenceElement(s, above, false);
3629                         if (!be)
3630                               // If there are only invisible elements, we have to use an invisible
3631                               // element for alignment reference.
3632                               be = getReferenceElement(s, above, true);
3633                         if (be && ((above && (be->y() < (reference + maxShift))) || ((!above && (be->y() > (reference - maxShift)))))) {
3634                               qreal shift = be->rypos();
3635                               be->rypos() = reference - be->ryoffset();
3636                               shift -= be->rypos();
3637                               for (Element* e : elements[s]) {
3638                                     if ((above && e->placeBelow()) || (!above && e->placeAbove()))
3639                                           continue;
3640                                     modified.append(e);
3641                                     handled.append(e);
3642                                     moved = true;
3643                                     if (e != be)
3644                                           e->rypos() -= shift;
3645                                     }
3646                               for (auto e : handled)
3647                                     elements[s].removeOne(e);
3648                               }
3649                         }
3650                   return moved;
3651                   }
3652 
3653             void addToSkyline(const System* system)
3654                   {
3655                   for (Element* e : qAsConst(modified)) {
3656                         const Segment* s = toSegment(e->parent());
3657                         const MeasureBase* m = toMeasureBase(s->parent());
3658                         system->staff(e->staffIdx())->skyline().add(e->shape().translated(e->pos() + s->pos() + m->pos()));
3659                         if (e->isFretDiagram()) {
3660                               FretDiagram* fd = toFretDiagram(e);
3661                               Harmony* h = fd->harmony();
3662                               if (h)
3663                                     system->staff(e->staffIdx())->skyline().add(h->shape().translated(h->pos() + fd->pos() + s->pos() + m->pos()));
3664                               else
3665                                     system->staff(e->staffIdx())->skyline().add(fd->shape().translated(fd->pos() + s->pos() + m->pos()));
3666                               }
3667                         }
3668                   }
3669             };
3670 
3671       if (almostZero(maxShiftAbove) && almostZero(maxShiftBelow))
3672             return;
3673 
3674       // Collect all fret diagrams and chord symbol and store them per staff.
3675       // In the same pass, the maximum height is collected.
3676       QMap<int, HarmonyList> staves;
3677       for (const Segment* s : sl) {
3678             for (Element* e : s->annotations()) {
3679                   if ((harmony && e->isHarmony()) || (!harmony && e->isFretDiagram()))
3680                         staves[e->staffIdx()].append(s, e);
3681                   }
3682             }
3683 
3684       for (int idx: staves.keys()) {
3685             // Align the objects.
3686             // Algorithm:
3687             //    - Find highest placed harmony/fretdiagram.
3688             //    - Align all harmony/fretdiagram objects placed between height and height-maxShiftAbove.
3689             //    - Repeat for all harmony/fretdiagram objects below heigt-maxShiftAbove.
3690             bool moved { true };
3691             int pass { 0 };
3692             while (moved && (pass++ < 10)) {
3693                   moved = false;
3694                   moved |= staves[idx].align(true, staves[idx].getReferenceHeight(true), maxShiftAbove);
3695                   moved |= staves[idx].align(false, staves[idx].getReferenceHeight(false), maxShiftBelow);
3696                   }
3697 
3698             // Add all aligned objects to the sky line.
3699             staves[idx].addToSkyline(system);
3700             }
3701       }
3702 
3703 //---------------------------------------------------------
3704 //   processLines
3705 //---------------------------------------------------------
3706 
processLines(System * system,std::vector<Spanner * > lines,bool align)3707 static void processLines(System* system, std::vector<Spanner*> lines, bool align)
3708       {
3709       std::vector<SpannerSegment*> segments;
3710       for (Spanner* sp : lines) {
3711             SpannerSegment* ss = sp->layoutSystem(system);     // create/layout spanner segment for this system
3712             if (ss->autoplace())
3713                   segments.push_back(ss);
3714             }
3715 
3716       if (align && segments.size() > 1) {
3717             const int nstaves = system->staves()->size();
3718             constexpr qreal minY = -1000000.0;
3719             const qreal defaultY = segments[0]->rypos();
3720             std::vector<qreal> y(nstaves, minY);
3721 
3722             for (SpannerSegment* ss : segments) {
3723                   if (ss->visible()) {
3724                         qreal& staffY = y[ss->staffIdx()];
3725                         staffY = qMax(staffY, ss->rypos());
3726                         }
3727                   }
3728             for (SpannerSegment* ss : segments) {
3729                   if (!ss->isStyled(Pid::OFFSET))
3730                         continue;
3731                   const qreal staffY = y[ss->staffIdx()];
3732                   if (staffY > minY)
3733                         ss->rypos() = staffY;
3734                   else
3735                         ss->rypos() = defaultY;
3736                   }
3737             }
3738 
3739       //
3740       // add shapes to skyline
3741       //
3742       for (SpannerSegment* ss : segments) {
3743             if (ss->addToSkyline())
3744                   system->staff(ss->staffIdx())->skyline().add(ss->shape().translated(ss->pos()));
3745             }
3746       }
3747 
3748 //---------------------------------------------------------
3749 //   collectSystem
3750 //---------------------------------------------------------
3751 
collectSystem(LayoutContext & lc)3752 System* Score::collectSystem(LayoutContext& lc)
3753       {
3754       if (!lc.curMeasure)
3755             return 0;
3756       const MeasureBase* measure  = _systems.empty() ? 0 : _systems.back()->measures().back();
3757       if (measure)
3758             measure = measure->findPotentialSectionBreak();
3759       if (measure) {
3760             lc.firstSystem        = measure->sectionBreak() && _layoutMode != LayoutMode::FLOAT;
3761             lc.firstSystemIndent  = lc.firstSystem && measure->sectionBreakElement()->firstSystemIdentation() && styleB(Sid::enableIndentationOnFirstSystem);
3762             lc.startWithLongNames = lc.firstSystem && measure->sectionBreakElement()->startWithLongNames();
3763             }
3764       System* system = getNextSystem(lc);
3765       Fraction lcmTick = lc.curMeasure->tick();
3766       system->setInstrumentNames(lc.startWithLongNames, lcmTick);
3767 
3768       qreal minWidth    = 0;
3769       qreal layoutSystemMinWidth = 0;
3770       bool firstMeasure = true;
3771       bool createHeader = false;
3772       qreal systemWidth = styleD(Sid::pagePrintableWidth) * DPI;
3773       system->setWidth(systemWidth);
3774 
3775       // save state of measure
3776       qreal curWidth = lc.curMeasure->width();
3777       bool curHeader = lc.curMeasure->header();
3778       bool curTrailer = lc.curMeasure->trailer();
3779 
3780       while (lc.curMeasure) {    // collect measure for system
3781             System* oldSystem = lc.curMeasure->system();
3782             system->appendMeasure(lc.curMeasure);
3783 
3784             qreal ww  = 0;      // width of current measure
3785 
3786             if (lc.curMeasure->isMeasure()) {
3787                   Measure* m = toMeasure(lc.curMeasure);
3788                   if (firstMeasure) {
3789                         layoutSystemMinWidth = minWidth;
3790                         system->layoutSystem(minWidth, lc.firstSystem, lc.firstSystemIndent);
3791                         minWidth += system->leftMargin();
3792                         if (m->repeatStart()) {
3793                               Segment* s = m->findSegmentR(SegmentType::StartRepeatBarLine, Fraction(0,1));
3794                               if (!s->enabled())
3795                                     s->setEnabled(true);
3796                               }
3797                         m->addSystemHeader(lc.firstSystem);
3798                         firstMeasure = false;
3799                         createHeader = false;
3800                         }
3801                   else {
3802                         if (createHeader) {
3803                               m->addSystemHeader(false);
3804                               createHeader = false;
3805                               }
3806                         else if (m->header())
3807                               m->removeSystemHeader();
3808                         }
3809 
3810                   m->createEndBarLines(true);
3811                   m->addSystemTrailer(m->nextMeasure());
3812                   m->computeMinWidth();
3813                   ww = m->width();
3814                   }
3815             else if (lc.curMeasure->isHBox()) {
3816                   lc.curMeasure->computeMinWidth();
3817                   ww = lc.curMeasure->width();
3818                   createHeader = toHBox(lc.curMeasure)->createSystemHeader();
3819                   }
3820             else {
3821                   // vbox:
3822                   getNextMeasure(lc);
3823                   system->layout2();   // compute staff distances
3824                   return system;
3825                   }
3826             // check if lc.curMeasure fits, remove if not
3827             // collect at least one measure and the break
3828 
3829             bool doBreak = (system->measures().size() > 1) && ((minWidth + ww) > systemWidth);
3830             if (doBreak) {
3831                   if (lc.prevMeasure->noBreak() && system->measures().size() > 2) {
3832                         // remove last two measures
3833                         // TODO: check more measures for noBreak()
3834                         system->removeLastMeasure();
3835                         system->removeLastMeasure();
3836                         lc.curMeasure->setSystem(oldSystem);
3837                         lc.prevMeasure->setSystem(oldSystem);
3838                         lc.nextMeasure = lc.curMeasure;
3839                         lc.curMeasure  = lc.prevMeasure;
3840                         lc.prevMeasure = lc.curMeasure->prevMeasure();
3841                         break;
3842                         }
3843                   else if (!lc.prevMeasure->noBreak()) {
3844                         // remove last measure
3845                         system->removeLastMeasure();
3846                         lc.curMeasure->setSystem(oldSystem);
3847                         break;
3848                         }
3849                   }
3850 
3851             if (lc.prevMeasure && lc.prevMeasure->isMeasure() && lc.prevMeasure->system() == system) {
3852                   //
3853                   // now we know that the previous measure is not the last
3854                   // measure in the system and we finally can create the end barline for it
3855 
3856                   Measure* m = toMeasure(lc.prevMeasure);
3857                   // TODO: if lc.curMeasure is a frame, removing the trailer may be premature
3858                   // but merely skipping this code isn't good enough,
3859                   // we need to find the right time to re-enable the trailer,
3860                   // since it seems to be disabled somewhere else
3861                   if (m->trailer()) {
3862                         qreal ow = m->width();
3863                         m->removeSystemTrailer();
3864                         minWidth += m->width() - ow;
3865                         }
3866                   // if the prev measure is an end repeat and the cur measure
3867                   // is an repeat, the createEndBarLines() created an start-end repeat barline
3868                   // and we can remove the start repeat barline of the current barline
3869 
3870                   if (lc.curMeasure->isMeasure()) {
3871                         Measure* m1 = toMeasure(lc.curMeasure);
3872                         if (m1->repeatStart()) {
3873                               Segment* s = m1->findSegmentR(SegmentType::StartRepeatBarLine, Fraction(0,1));
3874                               if (!s->enabled()) {
3875                                     s->setEnabled(true);
3876                                     m1->computeMinWidth();
3877                                     ww = m1->width();
3878                                     }
3879                               }
3880                         }
3881                   // TODO: we actually still don't know for sure
3882                   // if this will be the last true measure of the system or not
3883                   // since the lc.curMeasure may be a frame
3884                   // but at this point we have no choice but to assume it isn't
3885                   // since we don't know yet if another true measure will fit
3886                   // worst that happens is we don't get the automatic double bar before a courtesy key signature
3887                   minWidth += m->createEndBarLines(false);    // create final barLine
3888                   }
3889 
3890             MeasureBase* mb = lc.curMeasure;
3891             bool lineBreak  = false;
3892             switch (_layoutMode) {
3893                   case LayoutMode::PAGE:
3894                   case LayoutMode::SYSTEM:
3895                         lineBreak = mb->pageBreak() || mb->lineBreak() || mb->sectionBreak();
3896                         break;
3897                   case LayoutMode::FLOAT:
3898                   case LayoutMode::LINE:
3899                         lineBreak = false;
3900                         break;
3901                   }
3902 
3903             // preserve state of next measure (which is about to become current measure)
3904             if (lc.nextMeasure) {
3905                   MeasureBase* nmb = lc.nextMeasure;
3906                   if (nmb->isMeasure() && styleB(Sid::createMultiMeasureRests)) {
3907                         Measure* nm = toMeasure(nmb);
3908                         if (nm->hasMMRest())
3909                               nmb = nm->mmRest();
3910                         }
3911                   curWidth = nmb->width();
3912                   curHeader = nmb->header();
3913                   curTrailer = nmb->trailer();
3914                   }
3915 
3916             getNextMeasure(lc);
3917 
3918             minWidth += ww;
3919 
3920             // ElementType nt = lc.curMeasure ? lc.curMeasure->type() : ElementType::INVALID;
3921             mb = lc.curMeasure;
3922             bool tooWide = false; // minWidth + minMeasureWidth > systemWidth;  // TODO: noBreak
3923             if (lineBreak || !mb || mb->isVBox() || mb->isTBox() || mb->isFBox() || tooWide)
3924                   break;
3925             }
3926 
3927       if (lc.endTick < lc.prevMeasure->tick()) {
3928             // we've processed the entire range
3929             // but we need to continue layout until we reach a system whose last measure is the same as previous layout
3930             if (lc.prevMeasure == lc.systemOldMeasure) {
3931                   // this system ends in the same place as the previous layout
3932                   // ok to stop
3933                   if (lc.curMeasure && lc.curMeasure->isMeasure()) {
3934                         // we may have previously processed first measure of next system
3935                         // so now we must restore it to its original state
3936                         Measure* m = toMeasure(lc.curMeasure);
3937                         if (m->repeatStart()) {
3938                               Segment* s = m->findSegmentR(SegmentType::StartRepeatBarLine, Fraction(0,1));
3939                               if (!s->enabled())
3940                                     s->setEnabled(true);
3941                               }
3942                         // TODO: use findPotentialSectionBreak here to handle breaks on frames correctly?
3943                         bool firstSystem = lc.prevMeasure->sectionBreak() && _layoutMode != LayoutMode::FLOAT;
3944                         if (curHeader)
3945                               m->addSystemHeader(firstSystem);
3946                         else
3947                               m->removeSystemHeader();
3948                         if (curTrailer)
3949                               m->addSystemTrailer(m->nextMeasure());
3950                         else
3951                               m->removeSystemTrailer();
3952                         m->computeMinWidth();
3953                         m->stretchMeasure(curWidth);
3954                         restoreBeams(m);
3955                         }
3956                   lc.rangeDone = true;
3957                   }
3958             }
3959 
3960       //
3961       // now we have a complete set of measures for this system
3962       //
3963       // prevMeasure is the last measure in the system
3964       if (lc.prevMeasure && lc.prevMeasure->isMeasure()) {
3965             breakCrossMeasureBeams(toMeasure(lc.prevMeasure));
3966             qreal w = toMeasure(lc.prevMeasure)->createEndBarLines(true);
3967             minWidth += w;
3968             }
3969 
3970       hideEmptyStaves(system, lc.firstSystem);
3971       // Relayout system decorations to reuse space properly for
3972       // hidden staves' instrument names or other hidden elements.
3973       minWidth -= system->leftMargin();
3974       system->layoutSystem(layoutSystemMinWidth, lc.firstSystem, lc.firstSystemIndent);
3975       minWidth += system->leftMargin();
3976 
3977       //-------------------------------------------------------
3978       //    add system trailer if needed
3979       //    (cautionary time/key signatures etc)
3980       //-------------------------------------------------------
3981 
3982       Measure* lm  = system->lastMeasure();
3983       if (lm) {
3984             Measure* nm = lm->nextMeasure();
3985             if (nm) {
3986                   qreal w = lm->width();
3987                   lm->addSystemTrailer(nm);
3988                   if (lm->trailer())
3989                         lm->computeMinWidth();
3990                   minWidth += lm->width() - w;
3991                   }
3992             }
3993 
3994       //
3995       // stretch incomplete row
3996       //
3997       qreal rest;
3998       if (MScore::noHorizontalStretch)
3999             rest = 0;
4000       else {
4001             qreal mw          = system->leftMargin();      // DEBUG
4002             qreal totalWeight = 0.0;
4003 
4004             for (MeasureBase* mb : system->measures()) {
4005                   if (mb->isHBox()) {
4006                         mw += mb->width();
4007                         }
4008                   else if (mb->isMeasure()) {
4009                         Measure* m  = toMeasure(mb);
4010                         mw          += m->width();               // measures are stretched already with basicStretch()
4011                         int weight   = m->layoutWeight();
4012                         totalWeight += weight * m->basicStretch();
4013                         }
4014                   }
4015 
4016 #ifndef NDEBUG
4017             if (!qFuzzyCompare(mw, minWidth))
4018                   qDebug("==layoutSystem %6d old %.1f new %.1f", system->measures().front()->tick().ticks(), minWidth, mw);
4019 #endif
4020             rest = systemWidth - minWidth;
4021             //
4022             // don’t stretch last system row, if accumulated minWidth is <= lastSystemFillLimit
4023             //
4024             if (lc.curMeasure == 0 && ((minWidth / systemWidth) <= styleD(Sid::lastSystemFillLimit))) {
4025                   if (minWidth > rest)
4026                         rest = rest * .5;
4027                   else
4028                         rest = minWidth;
4029                   }
4030             rest /= totalWeight;
4031             }
4032 
4033       QPointF pos;
4034       firstMeasure = true;
4035       bool createBrackets = false;
4036       for (MeasureBase* mb : system->measures()) {
4037             qreal ww = mb->width();
4038             if (mb->isMeasure()) {
4039                   if (firstMeasure) {
4040                         pos.rx() += system->leftMargin();
4041                         firstMeasure = false;
4042                         }
4043                   mb->setPos(pos);
4044                   Measure* m = toMeasure(mb);
4045                   qreal stretch = m->basicStretch();
4046                   int weight = m->layoutWeight();
4047                   ww  += rest * weight * stretch;
4048                   m->stretchMeasure(ww);
4049                   m->layoutStaffLines();
4050                   if (createBrackets) {
4051                         system->addBrackets(toMeasure(mb));
4052                         createBrackets = false;
4053                         }
4054                   }
4055             else if (mb->isHBox()) {
4056                   mb->setPos(pos + QPointF(toHBox(mb)->topGap(), 0.0));
4057                   mb->layout();
4058                   createBrackets = toHBox(mb)->createSystemHeader();
4059                   }
4060             else if (mb->isVBox())
4061                   mb->setPos(pos);
4062             pos.rx() += ww;
4063             }
4064       system->setWidth(pos.x());
4065 
4066       layoutSystemElements(system, lc);
4067       system->layout2();   // compute staff distances
4068       // TODO: now that the code at the top of this function does this same backwards search,
4069       // we might be able to eliminate this block
4070       // but, lc might be used elsewhere so we need to be careful
4071 #if 1
4072       measure = system->measures().back();
4073       if (measure)
4074             measure = measure->findPotentialSectionBreak();
4075       if (measure) {
4076             lc.firstSystem        = measure->sectionBreak() && _layoutMode != LayoutMode::FLOAT;
4077             lc.firstSystemIndent  = lc.firstSystem && measure->sectionBreakElement()->firstSystemIdentation() && styleB(Sid::enableIndentationOnFirstSystem);
4078             lc.startWithLongNames = lc.firstSystem && measure->sectionBreakElement()->startWithLongNames();
4079             }
4080 #endif
4081       return system;
4082       }
4083 
4084 //---------------------------------------------------------
4085 //   layoutSystemElements
4086 //---------------------------------------------------------
4087 
layoutSystemElements(System * system,LayoutContext & lc)4088 void Score::layoutSystemElements(System* system, LayoutContext& lc)
4089       {
4090       //-------------------------------------------------------------
4091       //    create cr segment list to speed up computations
4092       //-------------------------------------------------------------
4093 
4094       std::vector<Segment*> sl;
4095       for (MeasureBase* mb : system->measures()) {
4096             if (!mb->isMeasure())
4097                   continue;
4098             Measure* m = toMeasure(mb);
4099             m->layoutMeasureNumber();
4100             m->layoutMMRestRange();
4101 
4102             // in continuous view, entire score is one system
4103             // but we only need to process the range
4104             if (lineMode() && (m->tick() < lc.startTick || m->tick() > lc.endTick))
4105                   continue;
4106             for (Segment* s = m->first(); s; s = s->next()) {
4107                   if (s->isChordRestType() || !s->annotations().empty())
4108                         sl.push_back(s);
4109                   }
4110             }
4111 
4112       //-------------------------------------------------------------
4113       // layout beams
4114       //  Needs to be done before creating skylines as stem lengths
4115       //  may change.
4116       //-------------------------------------------------------------
4117 
4118       for (Segment* s : sl) {
4119             for (Element* e : s->elist()) {
4120                   if (!e || !e->isChordRest() || !score()->staff(e->staffIdx())->show()) {
4121                         // the beam and its system may still be referenced when selecting all,
4122                         // even if the staff is invisible. The old system is invalid and does cause problems in #284012
4123                         if (e && e->isChordRest() && !score()->staff(e->staffIdx())->show() && toChordRest(e)->beam())
4124                               toChordRest(e)->beam()->setParent(nullptr);
4125                         continue;
4126                         }
4127                   ChordRest* cr = toChordRest(e);
4128 
4129                   // layout beam
4130                   if (isTopBeam(cr)) {
4131                         Beam* b = cr->beam();
4132                         b->layout();
4133                         }
4134                   }
4135             }
4136 
4137       //-------------------------------------------------------------
4138       //    create skylines
4139       //-------------------------------------------------------------
4140 
4141       for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
4142             SysStaff* ss = system->staff(staffIdx);
4143             Skyline& skyline = ss->skyline();
4144             skyline.clear();
4145             for (MeasureBase* mb : system->measures()) {
4146                   if (!mb->isMeasure())
4147                         continue;
4148                   Measure* m = toMeasure(mb);
4149                   MeasureNumber* mno = m->noText(staffIdx);
4150                   // no need to build skyline outside of range in continuous view
4151                   if (lineMode() && (m->tick() < lc.startTick || m->tick() > lc.endTick))
4152                         continue;
4153                   if (mno && mno->addToSkyline())
4154                         ss->skyline().add(mno->bbox().translated(m->pos() + mno->pos()));
4155                   if (m->staffLines(staffIdx)->addToSkyline())
4156                         ss->skyline().add(m->staffLines(staffIdx)->bbox().translated(m->pos()));
4157                   for (Segment& s : m->segments()) {
4158                         if (!s.enabled() || s.isTimeSigType())       // hack: ignore time signatures
4159                               continue;
4160                         QPointF p(s.pos() + m->pos());
4161                         if (s.segmentType() & (SegmentType::BarLine | SegmentType::EndBarLine | SegmentType::StartRepeatBarLine | SegmentType::BeginBarLine)) {
4162                               BarLine* bl = toBarLine(s.element(staffIdx * VOICES));
4163                               if (bl && bl->addToSkyline()) {
4164                                     QRectF r = bl->layoutRect();
4165                                     skyline.add(r.translated(bl->pos() + p));
4166                                     }
4167                               }
4168                         else {
4169                               int strack = staffIdx * VOICES;
4170                               int etrack = strack + VOICES;
4171                               for (Element* e : s.elist()) {
4172                                     if (!e)
4173                                           continue;
4174                                     int effectiveTrack = e->vStaffIdx() * VOICES + e->voice();
4175                                     if (effectiveTrack < strack || effectiveTrack >= etrack)
4176                                           continue;
4177 
4178                                     // clear layout for chord-based fingerings
4179                                     // do this before adding chord to skyline
4180                                     if (e->isChord()) {
4181                                           Chord* c = toChord(e);
4182                                           std::list<Note*> notes;
4183                                           for (auto gc : c->graceNotes()) {
4184                                                 for (auto n : gc->notes())
4185                                                       notes.push_back(n);
4186                                                 }
4187                                           for (auto n : c->notes())
4188                                                 notes.push_back(n);
4189                                           for (Note* note : notes) {
4190                                                 for (Element* en : note->el()) {
4191                                                       if (en->isFingering()) {
4192                                                             Fingering* f = toFingering(en);
4193                                                             if (f->layoutType() == ElementType::CHORD) {
4194                                                                   f->setPos(QPointF());
4195                                                                   f->setbbox(QRectF());
4196                                                                   }
4197                                                             }
4198                                                       }
4199                                                 }
4200                                           }
4201 
4202                                     // add element to skyline
4203                                     if (e->addToSkyline())
4204                                           skyline.add(e->shape().translated(e->pos() + p));
4205 
4206                                     // add tremolo to skyline
4207                                     if (e->isChord() && toChord(e)->tremolo()) {
4208                                           Tremolo* t = toChord(e)->tremolo();
4209                                           Chord* c1 = t->chord1();
4210                                           Chord* c2 = t->chord2();
4211                                           if (!t->twoNotes() || (c1 && !c1->staffMove() && c2 && !c2->staffMove())) {
4212                                                 if (t->chord() == e && t->addToSkyline())
4213                                                       skyline.add(t->shape().translated(t->pos() + e->pos() + p));
4214                                                 }
4215                                           }
4216                                     }
4217                               }
4218                         }
4219                   }
4220             }
4221 
4222       //-------------------------------------------------------------
4223       // layout fingerings, add beams to skylines
4224       //-------------------------------------------------------------
4225 
4226       for (Segment* s : sl) {
4227             std::set<int> recreateShapes;
4228             for (Element* e : s->elist()) {
4229                   if (!e || !e->isChordRest() || !score()->staff(e->staffIdx())->show())
4230                         continue;
4231                   ChordRest* cr = toChordRest(e);
4232 
4233                   // add beam to skyline
4234                   if (isTopBeam(cr)) {
4235                         Beam* b = cr->beam();
4236                         b->addSkyline(system->staff(b->staffIdx())->skyline());
4237                         }
4238 
4239                   // layout chord-based fingerings
4240                   if (e->isChord()) {
4241                         Chord* c = toChord(e);
4242                         std::list<Note*> notes;
4243                         for (auto gc : c->graceNotes()) {
4244                               for (auto n : gc->notes())
4245                                     notes.push_back(n);
4246                               }
4247                         for (auto n : c->notes())
4248                               notes.push_back(n);
4249                         std::list<Fingering*> fingerings;
4250                         for (Note* note : notes) {
4251                               for (Element* el : note->el()) {
4252                                     if (el->isFingering()) {
4253                                           Fingering* f = toFingering(el);
4254                                           if (f->layoutType() == ElementType::CHORD) {
4255                                                 if (f->placeAbove())
4256                                                       fingerings.push_back(f);
4257                                                 else
4258                                                       fingerings.push_front(f);
4259                                                 }
4260                                           }
4261                                     }
4262                               }
4263                         for (Fingering* f : fingerings) {
4264                               f->layout();
4265                               if (f->addToSkyline()) {
4266                                     Note* n = f->note();
4267                                     QRectF r = f->bbox().translated(f->pos() + n->pos() + n->chord()->pos() + s->pos() + s->measure()->pos());
4268                                     system->staff(f->note()->chord()->vStaffIdx())->skyline().add(r);
4269                                     }
4270                               recreateShapes.insert(f->staffIdx());
4271                               }
4272                         }
4273                   }
4274             for (auto staffIdx : recreateShapes)
4275                   s->createShape(staffIdx);
4276             }
4277 
4278       //-------------------------------------------------------------
4279       // layout articulations
4280       //-------------------------------------------------------------
4281 
4282       for (Segment* s : sl) {
4283             for (Element* e : s->elist()) {
4284                   if (!e || !e->isChordRest() || !score()->staff(e->staffIdx())->show())
4285                         continue;
4286                   ChordRest* cr = toChordRest(e);
4287                   // articulations
4288                   if (cr->isChord()) {
4289                         Chord* c = toChord(cr);
4290                         c->layoutArticulations();
4291                         c->layoutArticulations2();
4292                         }
4293                   }
4294             }
4295 
4296       //-------------------------------------------------------------
4297       // layout tuplets
4298       //-------------------------------------------------------------
4299 
4300       for (Segment* s : sl) {
4301             for (Element* e : s->elist()) {
4302                   if (!e || !e->isChordRest() || !score()->staff(e->staffIdx())->show())
4303                         continue;
4304                   ChordRest* cr = toChordRest(e);
4305                   if (!isTopTuplet(cr))
4306                         continue;
4307                   DurationElement* de = cr;
4308                   while (de->tuplet() && de->tuplet()->elements().front() == de) {
4309                         Tuplet* t = de->tuplet();
4310                         t->layout();
4311                         de = t;
4312                         }
4313                   }
4314             }
4315 
4316       //-------------------------------------------------------------
4317       // Drumline sticking
4318       //-------------------------------------------------------------
4319 
4320       for (const Segment* s : sl) {
4321             for (Element* e : s->annotations()) {
4322                   if (e->isSticking())
4323                         e->layout();
4324                   }
4325             }
4326 
4327       //-------------------------------------------------------------
4328       // layout slurs
4329       //-------------------------------------------------------------
4330 
4331       bool useRange = false;  // TODO: lineMode();
4332       Fraction stick = useRange ? lc.startTick : system->measures().front()->tick();
4333       Fraction etick = useRange ? lc.endTick : system->measures().back()->endTick();
4334       auto spanners = score()->spannerMap().findOverlapping(stick.ticks(), etick.ticks());
4335 
4336       std::vector<Spanner*> spanner;
4337       for (auto interval : spanners) {
4338             Spanner* sp = interval.value;
4339             sp->computeStartElement();
4340             sp->computeEndElement();
4341             lc.processedSpanners.insert(sp);
4342             if (sp->tick() < etick && sp->tick2() >= stick) {
4343                   if (sp->isSlur()) {
4344                         // skip cross-staff slurs
4345                         ChordRest* scr = sp->startCR();
4346                         ChordRest* ecr = sp->endCR();
4347                         int idx = sp->vStaffIdx();
4348                         if (scr && ecr && (scr->vStaffIdx() != idx || ecr->vStaffIdx() != idx))
4349                               continue;
4350                         spanner.push_back(sp);
4351                         }
4352                   }
4353             }
4354       processLines(system, spanner, false);
4355       for (auto s : spanner) {
4356             Slur* slur = toSlur(s);
4357             ChordRest* scr = s->startCR();
4358             ChordRest* ecr = s->endCR();
4359             if (scr && scr->isChord())
4360                   toChord(scr)->layoutArticulations3(slur);
4361             if (ecr && ecr->isChord())
4362                   toChord(ecr)->layoutArticulations3(slur);
4363             }
4364 
4365       std::vector<Dynamic*> dynamics;
4366       for (Segment* s : sl) {
4367             for (Element* e : s->elist()) {
4368                   if (!e)
4369                         continue;
4370                   if (e->isChord()) {
4371                         Chord* c = toChord(e);
4372                         for (Chord* ch : c->graceNotes())
4373                               layoutTies(ch, system, stick);
4374                         layoutTies(c, system, stick);
4375                         }
4376                   }
4377             for (Element* e : s->annotations()) {
4378                   if (e->isDynamic()) {
4379                         Dynamic* d = toDynamic(e);
4380                         d->layout();
4381 
4382                         if (d->autoplace()) {
4383                               d->autoplaceSegmentElement(false);
4384                               dynamics.push_back(d);
4385                               }
4386                         }
4387                   else if (e->isFiguredBass()) {
4388                         e->layout();
4389                         e->autoplaceSegmentElement();
4390                         }
4391                   }
4392             }
4393 
4394       // add dynamics shape to skyline
4395 
4396       for (Dynamic* d : dynamics) {
4397             if (!d->addToSkyline())
4398                   continue;
4399             int si = d->staffIdx();
4400             Segment* s = d->segment();
4401             Measure* m = s->measure();
4402             system->staff(si)->skyline().add(d->shape().translated(d->pos() + s->pos() + m->pos()));
4403             }
4404 
4405       //-------------------------------------------------------------
4406       // layout SpannerSegments for current system
4407       // ottavas, pedals, voltas are collected here, but layouted later
4408       //-------------------------------------------------------------
4409 
4410       spanner.clear();
4411       std::vector<Spanner*> hairpins;
4412       std::vector<Spanner*> ottavas;
4413       std::vector<Spanner*> pedal;
4414       std::vector<Spanner*> voltas;
4415 
4416       for (auto interval : spanners) {
4417             Spanner* sp = interval.value;
4418             if (sp->tick() < etick && sp->tick2() > stick) {
4419                   if (sp->isOttava())
4420                         ottavas.push_back(sp);
4421                   else if (sp->isPedal())
4422                         pedal.push_back(sp);
4423                   else if (sp->isVolta())
4424                         voltas.push_back(sp);
4425                   else if (sp->isHairpin())
4426                         hairpins.push_back(sp);
4427                   else if (!sp->isSlur() && !sp->isVolta())    // slurs are already
4428                         spanner.push_back(sp);
4429                   }
4430             }
4431       processLines(system, hairpins, false);
4432       processLines(system, spanner, false);
4433 
4434       //-------------------------------------------------------------
4435       // Fermata, TremoloBar
4436       //-------------------------------------------------------------
4437 
4438       for (const Segment* s : sl) {
4439             for (Element* e : s->annotations()) {
4440                   if (e->isFermata() || e->isTremoloBar())
4441                         e->layout();
4442                   }
4443             }
4444 
4445       //-------------------------------------------------------------
4446       // Ottava, Pedal
4447       //-------------------------------------------------------------
4448 
4449       processLines(system, ottavas, false);
4450       processLines(system, pedal,   true);
4451 
4452       //-------------------------------------------------------------
4453       // Lyric
4454       //-------------------------------------------------------------
4455 
4456       layoutLyrics(system);
4457 
4458       // here are lyrics dashes and melisma
4459       for (Spanner* sp : _unmanagedSpanner) {
4460             if (sp->tick() >= etick || sp->tick2() <= stick)
4461                   continue;
4462             sp->layoutSystem(system);
4463             }
4464 
4465       //
4466       // We need to known if we have FretDiagrams in the system to decide when to layout the Harmonies
4467       //
4468 
4469       bool hasFretDiagram = false;
4470       for (const Segment* s : sl) {
4471             for (Element* e : s->annotations()) {
4472                   if (e->isFretDiagram()) {
4473                         hasFretDiagram = true;
4474                         break;
4475                         }
4476                   }
4477 
4478             if (hasFretDiagram)
4479                   break;
4480             }
4481 
4482       //-------------------------------------------------------------
4483       // Harmony, 1st place
4484       // If we have FretDiagrams, we want the Harmony above this and
4485       // above the volta, therefore we delay the layout.
4486       //-------------------------------------------------------------
4487 
4488       if (!hasFretDiagram) {
4489             layoutHarmonies(sl);
4490             alignHarmonies(system, sl, true, styleP(Sid::maxChordShiftAbove), styleP(Sid::maxChordShiftBelow));
4491             }
4492 
4493       //-------------------------------------------------------------
4494       // StaffText, InstrumentChange
4495       //-------------------------------------------------------------
4496 
4497       for (const Segment* s : sl) {
4498             for (Element* e : s->annotations()) {
4499                   if (e->isStaffText() || e->isSystemText() || e->isInstrumentChange())
4500                         e->layout();
4501                   }
4502             }
4503 
4504       //-------------------------------------------------------------
4505       // Jump, Marker
4506       //-------------------------------------------------------------
4507 
4508       for (MeasureBase* mb : system->measures()) {
4509             if (!mb->isMeasure())
4510                   continue;
4511             Measure* m = toMeasure(mb);
4512             for (Element* e : m->el()) {
4513                   if (e->isJump() || e->isMarker())
4514                         e->layout();
4515                   }
4516             }
4517 
4518       //-------------------------------------------------------------
4519       // TempoText
4520       //-------------------------------------------------------------
4521 
4522       for (const Segment* s : sl) {
4523             for (Element* e : s->annotations()) {
4524                   if (e->isTempoText())
4525                         e->layout();
4526                   }
4527             }
4528 
4529       //-------------------------------------------------------------
4530       // layout Voltas for current system
4531       //-------------------------------------------------------------
4532 
4533       processLines(system, voltas, false);
4534 
4535       //
4536       // vertical align volta segments
4537       //
4538       for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
4539             std::vector<SpannerSegment*> voltaSegments;
4540             for (SpannerSegment* ss : system->spannerSegments()) {
4541                   if (ss->isVoltaSegment() && ss->staffIdx() == staffIdx)
4542                         voltaSegments.push_back(ss);
4543                   }
4544             while (!voltaSegments.empty()) {
4545                   // we assume voltas are sorted left to right (by tick values)
4546                   qreal y = 0;
4547                   int idx = 0;
4548                   Volta* prevVolta = 0;
4549                   for (SpannerSegment* ss : voltaSegments) {
4550                         Volta* volta = toVolta(ss->spanner());
4551                         if (prevVolta && prevVolta != volta) {
4552                               // check if volta is adjacent to prevVolta
4553                               if (prevVolta->tick2() != volta->tick())
4554                                     break;
4555                               }
4556                         y = qMin(y, ss->rypos());
4557                         ++idx;
4558                         prevVolta = volta;
4559                         }
4560 
4561                   for (int i = 0; i < idx; ++i) {
4562                         SpannerSegment* ss = voltaSegments[i];
4563                         if (ss->autoplace() && ss->isStyled(Pid::OFFSET))
4564                               ss->rypos() = y;
4565                         if (ss->addToSkyline())
4566                               system->staff(staffIdx)->skyline().add(ss->shape().translated(ss->pos()));
4567                         }
4568 
4569                   voltaSegments.erase(voltaSegments.begin(), voltaSegments.begin() + idx);
4570                   }
4571             }
4572 
4573       //-------------------------------------------------------------
4574       // FretDiagram
4575       //-------------------------------------------------------------
4576 
4577       if (hasFretDiagram) {
4578             for (const Segment* s : sl) {
4579                   for (Element* e : s->annotations()) {
4580                         if (e->isFretDiagram())
4581                               e->layout();
4582                         }
4583                   }
4584 
4585             //-------------------------------------------------------------
4586             // Harmony, 2nd place
4587             // We have FretDiagrams, we want the Harmony above this and
4588             // above the volta.
4589             //-------------------------------------------------------------
4590 
4591             layoutHarmonies(sl);
4592             alignHarmonies(system, sl, false, styleP(Sid::maxFretShiftAbove), styleP(Sid::maxFretShiftBelow));
4593             }
4594 
4595       //-------------------------------------------------------------
4596       // RehearsalMark
4597       //-------------------------------------------------------------
4598 
4599       for (const Segment* s : sl) {
4600             for (Element* e : s->annotations()) {
4601                   if (e->isRehearsalMark())
4602                         e->layout();
4603                   }
4604             }
4605 
4606       //-------------------------------------------------------------
4607       // Image
4608       //-------------------------------------------------------------
4609 
4610       for (const Segment* s : sl) {
4611             for (Element* e : s->annotations()) {
4612                   if (e->isImage())
4613                         e->layout();
4614                   }
4615             }
4616 
4617       }
4618 
4619 //---------------------------------------------------------
4620 //   collectPage
4621 //---------------------------------------------------------
4622 
collectPage()4623 void LayoutContext::collectPage()
4624       {
4625       const qreal slb = score->styleP(Sid::staffLowerBorder);
4626       bool breakPages = score->layoutMode() != LayoutMode::SYSTEM;
4627       qreal ey        = page->height() - page->bm();
4628       qreal y         = 0.0;
4629 
4630       System* nextSystem = 0;
4631       int systemIdx = -1;
4632 
4633       // re-calculate positions for systems before current
4634       // (they may have been filled on previous layout)
4635       int pSystems = page->systems().size();
4636       if (pSystems > 0) {
4637             page->system(0)->restoreLayout2();
4638             y = page->system(0)->y() + page->system(0)->height();
4639             }
4640       else {
4641              y = page->tm();
4642             }
4643       for (int i = 1; i < pSystems; ++i) {
4644             System* cs = page->system(i);
4645             System* ps = page->system(i - 1);
4646             qreal distance = ps->minDistance(cs);
4647             y += distance;
4648             cs->setPos(page->lm(), y);
4649             cs->restoreLayout2();
4650             y += cs->height();
4651             }
4652 
4653       for (int k = 0;;++k) {
4654             //
4655             // calculate distance to previous system
4656             //
4657             qreal distance;
4658             if (prevSystem)
4659                   distance = prevSystem->minDistance(curSystem);
4660             else {
4661                   // this is the first system on page
4662                   if (curSystem->vbox())
4663                         distance = 0.0;
4664                   else {
4665                         distance = score->styleP(Sid::staffUpperBorder);
4666                         bool fixedDistance = false;
4667                         // TODO: curSystem->spacerDistance(true)
4668                         for (MeasureBase* mb : curSystem->measures()) {
4669                               if (mb->isMeasure()) {
4670                                     Measure* m = toMeasure(mb);
4671                                     Spacer* sp = m->vspacerUp(0);       // TODO: first visible?
4672                                     if (sp) {
4673                                           if (sp->spacerType() == SpacerType::FIXED) {
4674                                                 distance = sp->gap();
4675                                                 fixedDistance = true;
4676                                                 break;
4677                                                 }
4678                                           else
4679                                                 distance = qMax(distance, sp->gap());
4680                                           }
4681 //TODO::ws                                    distance = qMax(distance, -m->staffShape(0).top());
4682                                     }
4683                               }
4684                         if (!fixedDistance)
4685                               distance = qMax(distance, curSystem->minTop());
4686                         }
4687                   }
4688 //TODO-ws ??
4689 //          distance += score->staves().front()->userDist();
4690 
4691             y += distance;
4692             curSystem->setPos(page->lm(), y);
4693             curSystem->restoreLayout2();
4694             page->appendSystem(curSystem);
4695             y += curSystem->height();
4696 
4697             //
4698             //  check for page break or if next system will fit on page
4699             //
4700             bool collected = false;
4701             if (rangeDone) {
4702                   // take next system unchanged
4703                   if (systemIdx > 0) {
4704                         nextSystem = score->systems().value(systemIdx++);
4705                         if (!nextSystem) {
4706                               // TODO: handle next movement
4707                               }
4708                         }
4709                   else {
4710                         nextSystem = systemList.empty() ? 0 : systemList.takeFirst();
4711                         if (nextSystem)
4712                               score->systems().append(nextSystem);
4713                         else if (score->isMaster()) {
4714                               MasterScore* ms = static_cast<MasterScore*>(score)->next();
4715                               if (ms) {
4716                                     score     = ms;
4717                                     systemIdx = 0;
4718                                     nextSystem = score->systems().value(systemIdx++);
4719                                     }
4720                               }
4721                         }
4722                   }
4723             else {
4724                   nextSystem = score->collectSystem(*this);
4725                   if (nextSystem)
4726                         collected = true;
4727                   if (!nextSystem && score->isMaster()) {
4728                         MasterScore* ms = static_cast<MasterScore*>(score)->next();
4729                         if (ms) {
4730                               score = ms;
4731                               QList<System*>& systems = ms->systems();
4732                               if (systems.empty() || systems.front()->measures().empty()) {
4733                                     systemList         = systems;
4734                                     systems.clear();
4735                                     measureNo          = 0;
4736                                     startWithLongNames = true;
4737                                     firstSystem        = true;
4738                                     tick               = Fraction(0,1);
4739                                     prevMeasure        = 0;
4740                                     curMeasure         = 0;
4741                                     nextMeasure        = ms->measures()->first();
4742                                     ms->getNextMeasure(*this);
4743                                     nextSystem         = ms->collectSystem(*this);
4744                                     ms->setScoreFont(ScoreFont::fontFactory(ms->styleSt(Sid::MusicalSymbolFont)));
4745                                     ms->setNoteHeadWidth(ms->scoreFont()->width(SymId::noteheadBlack, ms->spatium() / SPATIUM20));
4746                                     }
4747                               else {
4748                                     rangeDone = true;
4749                                     systemIdx = 0;
4750                                     nextSystem = score->systems().value(systemIdx++);
4751                                     }
4752                               }
4753                         }
4754                   }
4755             prevSystem = curSystem;
4756             Q_ASSERT(curSystem != nextSystem);
4757             curSystem  = nextSystem;
4758 
4759             bool breakPage = !curSystem || (breakPages && prevSystem->pageBreak());
4760 
4761             if (!breakPage) {
4762                   qreal dist = prevSystem->minDistance(curSystem) + curSystem->height();
4763                   Box* vbox = curSystem->vbox();
4764                   if (vbox) {
4765                         dist += vbox->bottomGap();
4766                         }
4767                   else if (!prevSystem->getFixedSpacer()) {
4768                         qreal margin = qMax(curSystem->minBottom(), curSystem->spacerDistance(false));
4769                         dist += qMax(margin, slb);
4770                         }
4771                   breakPage = (y + dist) >= ey && breakPages;
4772                   }
4773             if (breakPage) {
4774                   qreal dist = qMax(prevSystem->minBottom(), prevSystem->spacerDistance(false));
4775                   dist = qMax(dist, slb);
4776                   layoutPage(page, ey - (y + dist));
4777                   // if we collected a system we cannot fit onto this page,
4778                   // we need to collect next page in order to correctly set system positions
4779                   if (collected)
4780                         pageOldMeasure = nullptr;
4781                   break;
4782                   }
4783             }
4784 
4785       Fraction stick = Fraction(-1,1);
4786       for (System* s : page->systems()) {
4787             Score* currentScore = s->score();
4788             for (MeasureBase* mb : s->measures()) {
4789                   if (!mb->isMeasure())
4790                         continue;
4791                   Measure* m = toMeasure(mb);
4792                   if (stick == Fraction(-1,1))
4793                         stick = m->tick();
4794 
4795                   for (int track = 0; track < currentScore->ntracks(); ++track) {
4796                         for (Segment* segment = m->first(); segment; segment = segment->next()) {
4797                               Element* e = segment->element(track);
4798                               if (!e)
4799                                     continue;
4800                               if (e->isChordRest()) {
4801                                     if (!currentScore->staff(track2staff(track))->show())
4802                                           continue;
4803                                     ChordRest* cr = toChordRest(e);
4804                                     if (notTopBeam(cr))                 // layout cross staff beams
4805                                           cr->beam()->layout();
4806                                     if (notTopTuplet(cr)) {
4807                                           // fix layout of tuplets
4808                                           DurationElement* de = cr;
4809                                           while (de->tuplet() && de->tuplet()->elements().front() == de) {
4810                                                 Tuplet* t = de->tuplet();
4811                                                 t->layout();
4812                                                 de = t;
4813                                                 }
4814                                           }
4815 
4816                                     if (cr->isChord()) {
4817                                           Chord* c = toChord(cr);
4818                                           for (Chord* cc : c->graceNotes()) {
4819                                                 if (cc->beam() && cc->beam()->elements().front() == cc)
4820                                                       cc->beam()->layout();
4821                                                 cc->layoutSpanners();
4822                                                 for (Element* element : cc->el()) {
4823                                                       if (element->isSlur())
4824                                                             element->layout();
4825                                                       }
4826                                                 }
4827                                           c->layoutArpeggio2();
4828                                           c->layoutSpanners();
4829                                           if (c->tremolo()) {
4830                                                 Tremolo* t = c->tremolo();
4831                                                 Chord* c1 = t->chord1();
4832                                                 Chord* c2 = t->chord2();
4833                                                 if (t->twoNotes() && c1 && c2 && (c1->staffMove() || c2->staffMove()))
4834                                                       t->layout();
4835                                                 }
4836                                           }
4837                                     }
4838                               else if (e->isBarLine())
4839                                     toBarLine(e)->layout2();
4840                               }
4841                         }
4842                   m->layout2();
4843                   }
4844             }
4845 
4846       if (score->systemMode()) {
4847             System* s = page->systems().last();
4848             qreal height = s ? s->pos().y() + s->height() + s->minBottom() : page->tm();
4849             page->bbox().setRect(0.0, 0.0, score->loWidth(), height + page->bm());
4850             }
4851 
4852       page->rebuildBspTree();
4853       }
4854 
4855 //---------------------------------------------------------
4856 //   doLayout
4857 //    do a complete (re-) layout
4858 //---------------------------------------------------------
4859 
doLayout()4860 void Score::doLayout()
4861       {
4862       doLayoutRange(Fraction(0,1), Fraction(-1,1));
4863       }
4864 
4865 //---------------------------------------------------------
4866 //   CmdStateLocker
4867 //---------------------------------------------------------
4868 
4869 class CmdStateLocker {
4870       Score* score;
4871    public:
CmdStateLocker(Score * s)4872       CmdStateLocker(Score* s) : score(s) { score->cmdState().lock(); }
~CmdStateLocker()4873       ~CmdStateLocker() { score->cmdState().unlock(); }
4874       };
4875 
4876 //---------------------------------------------------------
4877 //   doLayoutRange
4878 //---------------------------------------------------------
4879 
doLayoutRange(const Fraction & st,const Fraction & et)4880 void Score::doLayoutRange(const Fraction& st, const Fraction& et)
4881       {
4882       CmdStateLocker cmdStateLocker(this);
4883       LayoutContext lc(this);
4884 
4885       Fraction stick(st);
4886       Fraction etick(et);
4887       Q_ASSERT(!(stick == Fraction(-1,1) && etick == Fraction(-1,1)));
4888 
4889       if (!last() || (lineMode() && !firstMeasure())) {
4890             qDebug("empty score");
4891             qDeleteAll(_systems);
4892             _systems.clear();
4893             qDeleteAll(pages());
4894             pages().clear();
4895             lc.getNextPage();
4896             return;
4897             }
4898 //      if (!_systems.isEmpty())
4899 //            return;
4900       bool layoutAll = stick <= Fraction(0,1) && (etick < Fraction(0,1) || etick >= masterScore()->last()->endTick());
4901       if (stick < Fraction(0,1))
4902             stick = Fraction(0,1);
4903       if (etick < Fraction(0,1))
4904             etick = last()->endTick();
4905 
4906       lc.endTick     = etick;
4907       _scoreFont     = ScoreFont::fontFactory(style().value(Sid::MusicalSymbolFont).toString());
4908       _noteHeadWidth = _scoreFont->width(SymId::noteheadBlack, spatium() / SPATIUM20);
4909 
4910       if (cmdState().layoutFlags & LayoutFlag::REBUILD_MIDI_MAPPING) {
4911             if (isMaster())
4912                   masterScore()->rebuildMidiMapping();
4913             }
4914       if (cmdState().layoutFlags & LayoutFlag::FIX_PITCH_VELO)
4915             updateVelo();
4916 #if 0 // TODO: needed? It was introduced in ab9774ec4098512068b8ef708167d9aa6e702c50
4917       if (cmdState().layoutFlags & LayoutFlag::PLAY_EVENTS)
4918             createPlayEvents();
4919 #endif
4920 
4921       //---------------------------------------------------
4922       //    initialize layout context lc
4923       //---------------------------------------------------
4924 
4925       MeasureBase* m = tick2measure(stick);
4926       if (m == 0)
4927             m = first();
4928       // start layout one measure earlier to handle clefs and cautionary elements
4929       if (m->prevMeasureMM())
4930             m = m->prevMeasureMM();
4931       else if (m->prev())
4932             m = m->prev();
4933       while (!m->isMeasure() && m->prev())
4934             m = m->prev();
4935 
4936       // if the first measure of the score is part of a multi measure rest
4937       // m->system() will return a nullptr. We need to find the multi measure
4938       // rest which replaces the measure range
4939 
4940       if (!m->system() && m->isMeasure() && toMeasure(m)->hasMMRest()) {
4941             qDebug("  don’t start with mmrest");
4942             m = toMeasure(m)->mmRest();
4943             }
4944 
4945 //      qDebug("start <%s> tick %d, system %p", m->name(), m->tick(), m->system());
4946 
4947       if (lineMode()) {
4948             lc.prevMeasure = 0;
4949             lc.nextMeasure = m;     //_showVBox ? first() : firstMeasure();
4950             lc.startTick   = m->tick();
4951             layoutLinear(layoutAll, lc);
4952             return;
4953             }
4954       if (!layoutAll && m->system()) {
4955             System* system  = m->system();
4956             int systemIndex = _systems.indexOf(system);
4957             lc.page         = system->page();
4958             lc.curPage      = pageIdx(lc.page);
4959             if (lc.curPage == -1)
4960                   lc.curPage = 0;
4961             lc.curSystem   = system;
4962             lc.systemList  = _systems.mid(systemIndex);
4963 
4964             if (systemIndex == 0)
4965                   lc.nextMeasure = _showVBox ? first() : firstMeasure();
4966             else {
4967                   System* prevSystem = _systems[systemIndex-1];
4968                   lc.nextMeasure = prevSystem->measures().back()->next();
4969                   }
4970 
4971             _systems.erase(_systems.begin() + systemIndex, _systems.end());
4972             if (!lc.nextMeasure->prevMeasure()) {
4973                   lc.measureNo = 0;
4974                   lc.tick      = Fraction(0,1);
4975                   }
4976             else {
4977                   const MeasureBase* mb = lc.nextMeasure->prev();
4978                   if (mb)
4979                         mb->findPotentialSectionBreak();
4980                   LayoutBreak* sectionBreak = mb->sectionBreakElement();
4981                   // TODO: also use mb in else clause here?
4982                   // probably not, only actual measures have meaningful numbers
4983                   if (sectionBreak && sectionBreak->startWithMeasureOne())
4984                         lc.measureNo = 0;
4985                   else
4986                         lc.measureNo = lc.nextMeasure->prevMeasure()->no()                     // will be adjusted later with respect
4987                                        + (lc.nextMeasure->prevMeasure()->irregular() ? 0 : 1); // to the user-defined offset.
4988                   lc.tick      = lc.nextMeasure->tick();
4989                   }
4990             }
4991       else {
4992 //  qDebug("layoutAll, systems %p %d", &_systems, int(_systems.size()));
4993             //lc.measureNo   = 0;
4994             //lc.tick        = 0;
4995             // qDeleteAll(_systems);
4996             // _systems.clear();
4997                   // lc.systemList  = _systems;
4998                   // _systems.clear();
4999 
5000             for (System* s : qAsConst(_systems)) {
5001                   for (Bracket* b : s->brackets()) {
5002                         if (b->selected()) {
5003                               _selection.remove(b);
5004                               setSelectionChanged(true);
5005                               }
5006                         }
5007 //                  for (SpannerSegment* ss : s->spannerSegments())
5008 //                        ss->setParent(0);
5009                   s->setParent(nullptr);
5010                   }
5011             for (MeasureBase* mb = first(); mb; mb = mb->next()) {
5012                   mb->setSystem(0);
5013                   if (mb->isMeasure() && toMeasure(mb)->mmRest())
5014                         toMeasure(mb)->mmRest()->setSystem(0);
5015                   }
5016             qDeleteAll(_systems);
5017             _systems.clear();
5018 
5019             qDeleteAll(pages());
5020             pages().clear();
5021 
5022             lc.nextMeasure = _showVBox ? first() : firstMeasure();
5023             }
5024 
5025       lc.prevMeasure = 0;
5026 
5027       getNextMeasure(lc);
5028       lc.curSystem = collectSystem(lc);
5029 
5030       lc.layout();
5031       }
5032 
5033 //---------------------------------------------------------
5034 //   layout
5035 //---------------------------------------------------------
5036 
layout()5037 void LayoutContext::layout()
5038       {
5039       MeasureBase* lmb;
5040       do {
5041             getNextPage();
5042             collectPage();
5043 
5044             if (page && !page->systems().isEmpty())
5045                   lmb = page->systems().back()->measures().back();
5046             else
5047                   lmb = nullptr;
5048 
5049             // we can stop collecting pages when:
5050             // 1) we reach the end of score (curSystem is nullptr)
5051             // or
5052             // 2) we have fully processed the range and reached a point of stability:
5053             //    a) we have completed layout for the range (rangeDone is true)
5054             //    b) we haven't collected a system that will need to go on the next page
5055             //    c) this page ends with the same measure as the previous layout
5056             //    pageOldMeasure will be last measure from previous layout if range was completed on or before this page
5057             //    it will be nullptr if this page was never laid out or if we collected a system for next page
5058             } while (curSystem && !(rangeDone && lmb == pageOldMeasure));
5059             // && page->system(0)->measures().back()->tick() > endTick // FIXME: perhaps the first measure was meant? Or last system?
5060 
5061       if (!curSystem) {
5062             // The end of the score. The remaining systems are not needed...
5063             qDeleteAll(systemList);
5064             systemList.clear();
5065             // ...and the remaining pages too
5066             while (score->npages() > curPage)
5067                   delete score->pages().takeLast();
5068             }
5069       else {
5070             Page* p = curSystem->page();
5071             if (p && (p != page))
5072                   p->rebuildBspTree();
5073             }
5074       score->systems().append(systemList);     // TODO
5075       }
5076 
5077 //---------------------------------------------------------
5078 //   LayoutContext::LayoutContext
5079 //---------------------------------------------------------
5080 
LayoutContext(Score * s)5081 LayoutContext::LayoutContext(Score* s)
5082       : score(s)
5083       {
5084       firstSystemIndent = score && score->styleB(Sid::enableIndentationOnFirstSystem);
5085       }
5086 
5087 //---------------------------------------------------------
5088 //   LayoutContext::~LayoutContext
5089 //---------------------------------------------------------
5090 
~LayoutContext()5091 LayoutContext::~LayoutContext()
5092       {
5093       for (Spanner* s : processedSpanners)
5094             s->layoutSystemsDone();
5095 
5096       for (MuseScoreView* v : score->getViewer())
5097             v->layoutChanged();
5098       }
5099 
5100 //---------------------------------------------------------
5101 //   VerticalStretchData
5102 //---------------------------------------------------------
5103 
VerticalGapData(bool first,System * sys,Staff * st,SysStaff * sst,const Spacer * spacer,qreal y)5104 VerticalGapData::VerticalGapData(bool first, System *sys, Staff *st, SysStaff *sst, const Spacer* spacer, qreal y)
5105       : _fixedHeight(first), system(sys), sysStaff(sst), staff(st)
5106       {
5107       if (_fixedHeight) {
5108             _normalisedSpacing = system->score()->styleP(Sid::staffUpperBorder);
5109             _maxActualSpacing = _normalisedSpacing;
5110             }
5111       else {
5112             if (spacer) {
5113                   _fixedHeight = true;
5114                   _normalisedSpacing = spacer->gap();
5115                   _maxActualSpacing = _normalisedSpacing;
5116                   }
5117             else {
5118                   _normalisedSpacing = system->y() + (sysStaff ? sysStaff->y() : 0.0) - y;
5119                   _maxActualSpacing = system->score()->styleP(Sid::maxStaffSpread);
5120                   }
5121             }
5122       }
5123 
5124 //---------------------------------------------------------
5125 //   updateFactor
5126 //---------------------------------------------------------
5127 
updateFactor(qreal factor)5128 void VerticalGapData::updateFactor(qreal factor)
5129       {
5130       if (_fixedHeight)
5131             return;
5132       qreal f = qMax(factor, _factor);
5133       _normalisedSpacing *= _factor / f;
5134       _factor = f;
5135       }
5136 
5137 //---------------------------------------------------------
5138 //   addSpaceBetweenSections
5139 //---------------------------------------------------------
5140 
addSpaceBetweenSections()5141 void VerticalGapData::addSpaceBetweenSections()
5142       {
5143       updateFactor(system->score()->styleD(Sid::spreadSystem));
5144       if (!_fixedHeight)
5145             _maxActualSpacing = qMax(_maxActualSpacing, system->score()->styleP(Sid::maxSystemSpread));
5146       }
5147 
5148 //---------------------------------------------------------
5149 //   addSpaceAroundVBox
5150 //---------------------------------------------------------
5151 
addSpaceAroundVBox(bool above)5152 void VerticalGapData::addSpaceAroundVBox(bool above)
5153       {
5154       _fixedHeight = true;
5155       _factor = 1.0;
5156       const Score* score { system->score() };
5157       _normalisedSpacing = above ? score->styleP(Sid::frameSystemDistance) : score->styleP(Sid::systemFrameDistance);
5158       _maxActualSpacing = _normalisedSpacing;
5159       }
5160 
5161 //---------------------------------------------------------
5162 //   addSpaceAroundNormalBracket
5163 //---------------------------------------------------------
5164 
addSpaceAroundNormalBracket()5165 void VerticalGapData::addSpaceAroundNormalBracket()
5166       {
5167       updateFactor(system->score()->styleD(Sid::spreadSquareBracket));
5168       }
5169 
5170 //---------------------------------------------------------
5171 //   addSpaceAroundCurlyBracket
5172 //---------------------------------------------------------
5173 
addSpaceAroundCurlyBracket()5174 void VerticalGapData::addSpaceAroundCurlyBracket()
5175       {
5176       updateFactor(system->score()->styleD(Sid::spreadCurlyBracket));
5177       }
5178 
5179 //---------------------------------------------------------
5180 //   insideCurlyBracket
5181 //---------------------------------------------------------
5182 
insideCurlyBracket()5183 void VerticalGapData::insideCurlyBracket()
5184       {
5185       _maxActualSpacing = system->score()->styleP(Sid::maxAkkoladeDistance);
5186       }
5187 
5188 //---------------------------------------------------------
5189 //   factor
5190 //---------------------------------------------------------
5191 
factor() const5192 qreal VerticalGapData::factor() const
5193       {
5194       return _factor;
5195       }
5196 
5197 //---------------------------------------------------------
5198 //   spacing
5199 //    return normalised spacing
5200 //---------------------------------------------------------
5201 
spacing() const5202 qreal VerticalGapData::spacing() const
5203       {
5204       return _normalisedSpacing + _addedNormalisedSpace;
5205       }
5206 
5207 //---------------------------------------------------------
5208 //   addedSpace
5209 //---------------------------------------------------------
5210 
actualAddedSpace() const5211 qreal VerticalGapData::actualAddedSpace() const
5212       {
5213       return _addedNormalisedSpace * factor();
5214       }
5215 
5216 //---------------------------------------------------------
5217 //   addSpacing
5218 //---------------------------------------------------------
5219 
addSpacing(qreal step)5220 qreal VerticalGapData::addSpacing(qreal step)
5221       {
5222       if (_fixedHeight)
5223             return 0.0;
5224       if ((_normalisedSpacing >= _maxActualSpacing)) {
5225             _normalisedSpacing = _maxActualSpacing;
5226             step = 0.0;
5227             }
5228       else {
5229             qreal newSpacing { _normalisedSpacing + _addedNormalisedSpace + step };
5230             if ((newSpacing >= _maxActualSpacing))
5231                   step = _maxActualSpacing - _normalisedSpacing - _addedNormalisedSpace;
5232             }
5233       _addedNormalisedSpace += step;
5234       _lastStep = step;
5235       return step;
5236       }
5237 
5238 //---------------------------------------------------------
5239 //   isFixedHeight
5240 //---------------------------------------------------------
5241 
isFixedHeight() const5242 bool VerticalGapData::isFixedHeight() const
5243       {
5244       return _fixedHeight;
5245       }
5246 
5247 //---------------------------------------------------------
5248 //   undoLastAddSpacing
5249 //---------------------------------------------------------
5250 
undoLastAddSpacing()5251 void VerticalGapData::undoLastAddSpacing()
5252       {
5253       _addedNormalisedSpace -= _lastStep;
5254       _lastStep = 0.0;
5255       }
5256 
5257 //---------------------------------------------------------
5258 //   addFillSpacing
5259 //---------------------------------------------------------
5260 
addFillSpacing(qreal step,qreal maxFill)5261 qreal VerticalGapData::addFillSpacing(qreal step, qreal maxFill)
5262       {
5263       qreal res = addSpacing(qMin(maxFill - _fillSpacing, step));
5264       _fillSpacing += res;
5265       return res;
5266       }
5267 
5268 //---------------------------------------------------------
5269 //   deleteAll
5270 //---------------------------------------------------------
5271 
deleteAll()5272 void VerticalGapDataList::deleteAll()
5273       {
5274       for (auto vsd : *this)
5275             delete vsd;
5276       }
5277 
5278 //---------------------------------------------------------
5279 //   sumStretchFactor
5280 //---------------------------------------------------------
5281 
sumStretchFactor() const5282 qreal VerticalGapDataList::sumStretchFactor() const
5283       {
5284       qreal sum { 0.0 };
5285       for (VerticalGapData* vsd : *this)
5286             sum += vsd->factor();
5287       return sum;
5288       }
5289 
5290 //---------------------------------------------------------
5291 //   smallest
5292 //---------------------------------------------------------
5293 
smallest(qreal limit) const5294 qreal VerticalGapDataList::smallest(qreal limit) const
5295       {
5296       VerticalGapData* vdp { nullptr };
5297       for (VerticalGapData* vgd : *this) {
5298             if (vgd->isFixedHeight())
5299                   continue;
5300             if ((qCeil(limit) == qCeil(vgd->spacing())))
5301                   continue;
5302             if (!vdp || (vgd->spacing() <  vdp->spacing()))
5303                   vdp = vgd;
5304             }
5305       return vdp ? vdp->spacing() : 0.0;
5306       }
5307 
5308 }
5309